diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-13 15:05:29 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-13 15:05:29 -0800 | 
| commit | a70210f41566131f88d31583f96e36cb7f5d2ad0 (patch) | |
| tree | ab9a0efc97432547d97455b9cc1b17a9fa49d267 /arch/x86/kernel/cpu/intel.c | |
| parent | 3ef3ace4e2ecf4aa4c8ddff1d35683671a09b05e (diff) | |
| parent | be1b670f61443aa5d0d01782e9b8ea0ee825d018 (diff) | |
Merge tag 'x86_microcode_for_v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 microcode and IFS updates from Borislav Petkov:
 "The IFS (In-Field Scan) stuff goes through tip because the IFS driver
  uses the same structures and similar functionality as the microcode
  loader and it made sense to route it all through this branch so that
  there are no conflicts.
   - Add support for multiple testing sequences to the Intel In-Field
     Scan driver in order to be able to run multiple different test
     patterns. Rework things and remove the BROKEN dependency so that
     the driver can be enabled (Jithu Joseph)
   - Remove the subsys interface usage in the microcode loader because
     it is not really needed
   - A couple of smaller fixes and cleanups"
* tag 'x86_microcode_for_v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
  x86/microcode/intel: Do not retry microcode reloading on the APs
  x86/microcode/intel: Do not print microcode revision and processor flags
  platform/x86/intel/ifs: Add missing kernel-doc entry
  Revert "platform/x86/intel/ifs: Mark as BROKEN"
  Documentation/ABI: Update IFS ABI doc
  platform/x86/intel/ifs: Add current_batch sysfs entry
  platform/x86/intel/ifs: Remove reload sysfs entry
  platform/x86/intel/ifs: Add metadata validation
  platform/x86/intel/ifs: Use generic microcode headers and functions
  platform/x86/intel/ifs: Add metadata support
  x86/microcode/intel: Use a reserved field for metasize
  x86/microcode/intel: Add hdr_type to intel_microcode_sanity_check()
  x86/microcode/intel: Reuse microcode_sanity_check()
  x86/microcode/intel: Use appropriate type in microcode_sanity_check()
  x86/microcode/intel: Reuse find_matching_signature()
  platform/x86/intel/ifs: Remove memory allocation from load path
  platform/x86/intel/ifs: Remove image loading during init
  platform/x86/intel/ifs: Return a more appropriate error code
  platform/x86/intel/ifs: Remove unused selection
  x86/microcode: Drop struct ucode_cpu_info.valid
  ...
Diffstat (limited to 'arch/x86/kernel/cpu/intel.c')
| -rw-r--r-- | arch/x86/kernel/cpu/intel.c | 144 | 
1 files changed, 143 insertions, 1 deletions
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 427899650483..291d4167fab8 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -210,12 +210,154 @@ int intel_cpu_collect_info(struct ucode_cpu_info *uci)  	csig.rev = intel_get_microcode_revision();  	uci->cpu_sig = csig; -	uci->valid = 1;  	return 0;  }  EXPORT_SYMBOL_GPL(intel_cpu_collect_info); +/* + * Returns 1 if update has been found, 0 otherwise. + */ +int intel_find_matching_signature(void *mc, unsigned int csig, int cpf) +{ +	struct microcode_header_intel *mc_hdr = mc; +	struct extended_sigtable *ext_hdr; +	struct extended_signature *ext_sig; +	int i; + +	if (intel_cpu_signatures_match(csig, cpf, mc_hdr->sig, mc_hdr->pf)) +		return 1; + +	/* Look for ext. headers: */ +	if (get_totalsize(mc_hdr) <= get_datasize(mc_hdr) + MC_HEADER_SIZE) +		return 0; + +	ext_hdr = mc + get_datasize(mc_hdr) + MC_HEADER_SIZE; +	ext_sig = (void *)ext_hdr + EXT_HEADER_SIZE; + +	for (i = 0; i < ext_hdr->count; i++) { +		if (intel_cpu_signatures_match(csig, cpf, ext_sig->sig, ext_sig->pf)) +			return 1; +		ext_sig++; +	} +	return 0; +} +EXPORT_SYMBOL_GPL(intel_find_matching_signature); + +/** + * intel_microcode_sanity_check() - Sanity check microcode file. + * @mc: Pointer to the microcode file contents. + * @print_err: Display failure reason if true, silent if false. + * @hdr_type: Type of file, i.e. normal microcode file or In Field Scan file. + *            Validate if the microcode header type matches with the type + *            specified here. + * + * Validate certain header fields and verify if computed checksum matches + * with the one specified in the header. + * + * Return: 0 if the file passes all the checks, -EINVAL if any of the checks + * fail. + */ +int intel_microcode_sanity_check(void *mc, bool print_err, int hdr_type) +{ +	unsigned long total_size, data_size, ext_table_size; +	struct microcode_header_intel *mc_header = mc; +	struct extended_sigtable *ext_header = NULL; +	u32 sum, orig_sum, ext_sigcount = 0, i; +	struct extended_signature *ext_sig; + +	total_size = get_totalsize(mc_header); +	data_size = get_datasize(mc_header); + +	if (data_size + MC_HEADER_SIZE > total_size) { +		if (print_err) +			pr_err("Error: bad microcode data file size.\n"); +		return -EINVAL; +	} + +	if (mc_header->ldrver != 1 || mc_header->hdrver != hdr_type) { +		if (print_err) +			pr_err("Error: invalid/unknown microcode update format. Header type %d\n", +			       mc_header->hdrver); +		return -EINVAL; +	} + +	ext_table_size = total_size - (MC_HEADER_SIZE + data_size); +	if (ext_table_size) { +		u32 ext_table_sum = 0; +		u32 *ext_tablep; + +		if (ext_table_size < EXT_HEADER_SIZE || +		    ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) { +			if (print_err) +				pr_err("Error: truncated extended signature table.\n"); +			return -EINVAL; +		} + +		ext_header = mc + MC_HEADER_SIZE + data_size; +		if (ext_table_size != exttable_size(ext_header)) { +			if (print_err) +				pr_err("Error: extended signature table size mismatch.\n"); +			return -EFAULT; +		} + +		ext_sigcount = ext_header->count; + +		/* +		 * Check extended table checksum: the sum of all dwords that +		 * comprise a valid table must be 0. +		 */ +		ext_tablep = (u32 *)ext_header; + +		i = ext_table_size / sizeof(u32); +		while (i--) +			ext_table_sum += ext_tablep[i]; + +		if (ext_table_sum) { +			if (print_err) +				pr_warn("Bad extended signature table checksum, aborting.\n"); +			return -EINVAL; +		} +	} + +	/* +	 * Calculate the checksum of update data and header. The checksum of +	 * valid update data and header including the extended signature table +	 * must be 0. +	 */ +	orig_sum = 0; +	i = (MC_HEADER_SIZE + data_size) / sizeof(u32); +	while (i--) +		orig_sum += ((u32 *)mc)[i]; + +	if (orig_sum) { +		if (print_err) +			pr_err("Bad microcode data checksum, aborting.\n"); +		return -EINVAL; +	} + +	if (!ext_table_size) +		return 0; + +	/* +	 * Check extended signature checksum: 0 => valid. +	 */ +	for (i = 0; i < ext_sigcount; i++) { +		ext_sig = (void *)ext_header + EXT_HEADER_SIZE + +			  EXT_SIGNATURE_SIZE * i; + +		sum = (mc_header->sig + mc_header->pf + mc_header->cksum) - +		      (ext_sig->sig + ext_sig->pf + ext_sig->cksum); +		if (sum) { +			if (print_err) +				pr_err("Bad extended signature checksum, aborting.\n"); +			return -EINVAL; +		} +	} +	return 0; +} +EXPORT_SYMBOL_GPL(intel_microcode_sanity_check); +  static void early_init_intel(struct cpuinfo_x86 *c)  {  	u64 misc_enable;  | 
