Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1/*
  2 *	Intel CPU Microcode Update Driver for Linux
  3 *
  4 *	Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com>
  5 *			   H Peter Anvin" <hpa@zytor.com>
  6 *
  7 *	This driver allows to upgrade microcode on Intel processors
  8 *	belonging to IA-32 family - PentiumPro, Pentium II,
  9 *	Pentium III, Xeon, Pentium 4, etc.
 10 *
 11 *	Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
 12 *	Software Developer's Manual
 13 *	Order Number 253668 or free download from:
 14 *
 15 *	http://developer.intel.com/Assets/PDF/manual/253668.pdf
 16 *
 17 *	For more information, go to http://www.urbanmyth.org/microcode
 18 *
 19 *	This program is free software; you can redistribute it and/or
 20 *	modify it under the terms of the GNU General Public License
 21 *	as published by the Free Software Foundation; either version
 22 *	2 of the License, or (at your option) any later version.
 23 *
 24 */
 25#include <linux/firmware.h>
 26#include <linux/uaccess.h>
 27#include <linux/kernel.h>
 28
 29#include <asm/microcode_intel.h>
 30#include <asm/processor.h>
 31#include <asm/msr.h>
 32
 33static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1,
 34					unsigned int s2, unsigned int p2)
 35{
 36	if (s1 != s2)
 37		return false;
 38
 39	/* Processor flags are either both 0 ... */
 40	if (!p1 && !p2)
 41		return true;
 42
 43	/* ... or they intersect. */
 44	return p1 & p2;
 45}
 46
 47int microcode_sanity_check(void *mc, int print_err)
 48{
 49	unsigned long total_size, data_size, ext_table_size;
 50	struct microcode_header_intel *mc_header = mc;
 51	struct extended_sigtable *ext_header = NULL;
 52	u32 sum, orig_sum, ext_sigcount = 0, i;
 53	struct extended_signature *ext_sig;
 54
 55	total_size = get_totalsize(mc_header);
 56	data_size = get_datasize(mc_header);
 57
 58	if (data_size + MC_HEADER_SIZE > total_size) {
 59		if (print_err)
 60			pr_err("Error: bad microcode data file size.\n");
 61		return -EINVAL;
 62	}
 63
 64	if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
 65		if (print_err)
 66			pr_err("Error: invalid/unknown microcode update format.\n");
 67		return -EINVAL;
 68	}
 69
 70	ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
 71	if (ext_table_size) {
 72		u32 ext_table_sum = 0;
 73		u32 *ext_tablep;
 74
 75		if ((ext_table_size < EXT_HEADER_SIZE)
 76		 || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
 77			if (print_err)
 78				pr_err("Error: truncated extended signature table.\n");
 79			return -EINVAL;
 80		}
 81
 82		ext_header = mc + MC_HEADER_SIZE + data_size;
 83		if (ext_table_size != exttable_size(ext_header)) {
 84			if (print_err)
 85				pr_err("Error: extended signature table size mismatch.\n");
 86			return -EFAULT;
 87		}
 88
 89		ext_sigcount = ext_header->count;
 90
 91		/*
 92		 * Check extended table checksum: the sum of all dwords that
 93		 * comprise a valid table must be 0.
 94		 */
 95		ext_tablep = (u32 *)ext_header;
 96
 97		i = ext_table_size / sizeof(u32);
 98		while (i--)
 99			ext_table_sum += ext_tablep[i];
100
101		if (ext_table_sum) {
102			if (print_err)
103				pr_warn("Bad extended signature table checksum, aborting.\n");
104			return -EINVAL;
105		}
106	}
107
108	/*
109	 * Calculate the checksum of update data and header. The checksum of
110	 * valid update data and header including the extended signature table
111	 * must be 0.
112	 */
113	orig_sum = 0;
114	i = (MC_HEADER_SIZE + data_size) / sizeof(u32);
115	while (i--)
116		orig_sum += ((u32 *)mc)[i];
117
118	if (orig_sum) {
119		if (print_err)
120			pr_err("Bad microcode data checksum, aborting.\n");
121		return -EINVAL;
122	}
123
124	if (!ext_table_size)
125		return 0;
126
127	/*
128	 * Check extended signature checksum: 0 => valid.
129	 */
130	for (i = 0; i < ext_sigcount; i++) {
131		ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
132			  EXT_SIGNATURE_SIZE * i;
133
134		sum = (mc_header->sig + mc_header->pf + mc_header->cksum) -
135		      (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
136		if (sum) {
137			if (print_err)
138				pr_err("Bad extended signature checksum, aborting.\n");
139			return -EINVAL;
140		}
141	}
142	return 0;
143}
144EXPORT_SYMBOL_GPL(microcode_sanity_check);
145
146/*
147 * Returns 1 if update has been found, 0 otherwise.
148 */
149int find_matching_signature(void *mc, unsigned int csig, int cpf)
150{
151	struct microcode_header_intel *mc_hdr = mc;
152	struct extended_sigtable *ext_hdr;
153	struct extended_signature *ext_sig;
154	int i;
155
156	if (cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf))
157		return 1;
158
159	/* Look for ext. headers: */
160	if (get_totalsize(mc_hdr) <= get_datasize(mc_hdr) + MC_HEADER_SIZE)
161		return 0;
162
163	ext_hdr = mc + get_datasize(mc_hdr) + MC_HEADER_SIZE;
164	ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE;
165
166	for (i = 0; i < ext_hdr->count; i++) {
167		if (cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf))
168			return 1;
169		ext_sig++;
170	}
171	return 0;
172}
173
174/*
175 * Returns 1 if update has been found, 0 otherwise.
176 */
177int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev)
178{
179	struct microcode_header_intel *mc_hdr = mc;
180
181	if (mc_hdr->rev <= new_rev)
182		return 0;
183
184	return find_matching_signature(mc, csig, cpf);
185}
186EXPORT_SYMBOL_GPL(has_newer_microcode);