- The first, cleanup part of the microcode loader reorg tglx has been
working on. This part makes the loader core code as it is practically enabled on pretty much every baremetal machine so there's no need to have the Kconfig items. In addition, there are cleanups which prepare for future feature enablement. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmTskfcACgkQEsHwGGHe VUo/hBAAiqVqdc0WASHgVYoO9mD1M2T3oHFz8ceX2pGKf/raZ5UJyit7ybWEZEWG rWXFORRlqOKoKImQm6JhyJsu29Xmi9sTb1WNwEyT8YMdhx8v57hOch3alX7sm2BF 9eOl/77hxt7Pt8keN6gY5w5cydEgBvi8bVe8sfU3hJMwieAMH0q5syRx7fDizcVd qoTicHRjfj5Q8BL5NXtdPEMENYPyV89DVjnUM1HVPpCkoHxmOujewgjs4gY7PsGp qAGB1+IG3aqOWHM9SDIJp5U9tNX2huhqRTcZsNEe8qHTXCv8F8zRzK0J8giM1wed 5aAGC4AfMh/gjryXeMj1nnwoAf5TQw4dK+y+BYXIykdQDV1up+HdDtjrBmJ5Kslf n/8uGLdLLqMQVEE2hT3r1Ft1RqVf3UwWOxzc+KASjKCj0F5djt+F2JDNGoN0sMD9 JDj3Dtvo2e1+aZlcvXWSmMCVMT0By1mbFqirEXT3i1sYwHDx23s+KwY71CdT8gx8 nbEWsaADPRynNbTAI5Z5TFq0Cohs9AUNuotRHYCc0Et5NBlzoN8yAKNW39twUDEt a/Knq1Vnybrp18pE/rDphm+p/K261OuEXfFFVTASSlvgMnVM0UAZZZka7A0DmN+g mvZ2A9hByFk6sELm3QeNrOdex8djeichyY7+EQ13K25wMd/YsX0= =QXDh -----END PGP SIGNATURE----- Merge tag 'x86_microcode_for_v6.6_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull x86 microcode loading updates from Borislav Petkov: "The first, cleanup part of the microcode loader reorg tglx has been working on. The other part wasn't fully ready in time so it will follow on later. This part makes the loader core code as it is practically enabled on pretty much every baremetal machine so there's no need to have the Kconfig items. In addition, there are cleanups which prepare for future feature enablement" * tag 'x86_microcode_for_v6.6_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/microcode: Remove remaining references to CONFIG_MICROCODE_AMD x86/microcode/intel: Remove pointless mutex x86/microcode/intel: Remove debug code x86/microcode: Move core specific defines to local header x86/microcode/intel: Rename get_datasize() since its used externally x86/microcode: Make reload_early_microcode() static x86/microcode: Include vendor headers into microcode.h x86/microcode/intel: Move microcode functions out of cpu/intel.c x86/microcode: Hide the config knob x86/mm: Remove unused microcode.h include x86/microcode: Remove microcode_mutex x86/microcode/AMD: Rip out static buffers
This commit is contained in:
commit
42a7f6e3ff
@ -1308,44 +1308,8 @@ config X86_REBOOTFIXUPS
|
||||
Say N otherwise.
|
||||
|
||||
config MICROCODE
|
||||
bool "CPU microcode loading support"
|
||||
default y
|
||||
def_bool y
|
||||
depends on CPU_SUP_AMD || CPU_SUP_INTEL
|
||||
help
|
||||
If you say Y here, you will be able to update the microcode on
|
||||
Intel and AMD processors. The Intel support is for the IA32 family,
|
||||
e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4, Xeon etc. The
|
||||
AMD support is for families 0x10 and later. You will obviously need
|
||||
the actual microcode binary data itself which is not shipped with
|
||||
the Linux kernel.
|
||||
|
||||
The preferred method to load microcode from a detached initrd is described
|
||||
in Documentation/arch/x86/microcode.rst. For that you need to enable
|
||||
CONFIG_BLK_DEV_INITRD in order for the loader to be able to scan the
|
||||
initrd for microcode blobs.
|
||||
|
||||
In addition, you can build the microcode into the kernel. For that you
|
||||
need to add the vendor-supplied microcode to the CONFIG_EXTRA_FIRMWARE
|
||||
config option.
|
||||
|
||||
config MICROCODE_INTEL
|
||||
bool "Intel microcode loading support"
|
||||
depends on CPU_SUP_INTEL && MICROCODE
|
||||
default MICROCODE
|
||||
help
|
||||
This options enables microcode patch loading support for Intel
|
||||
processors.
|
||||
|
||||
For the current Intel microcode data package go to
|
||||
<https://downloadcenter.intel.com> and search for
|
||||
'Linux Processor Microcode Data File'.
|
||||
|
||||
config MICROCODE_AMD
|
||||
bool "AMD microcode loading support"
|
||||
depends on CPU_SUP_AMD && MICROCODE
|
||||
help
|
||||
If you select this option, microcode patch loading support for AMD
|
||||
processors will be enabled.
|
||||
|
||||
config MICROCODE_LATE_LOADING
|
||||
bool "Late microcode loading (DANGEROUS)"
|
||||
|
@ -33,7 +33,6 @@ CONFIG_HYPERVISOR_GUEST=y
|
||||
CONFIG_PARAVIRT=y
|
||||
CONFIG_NR_CPUS=8
|
||||
CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
|
||||
CONFIG_MICROCODE_AMD=y
|
||||
CONFIG_X86_MSR=y
|
||||
CONFIG_X86_CPUID=y
|
||||
CONFIG_X86_CHECK_BIOS_CORRUPTION=y
|
||||
|
@ -31,7 +31,6 @@ CONFIG_SMP=y
|
||||
CONFIG_HYPERVISOR_GUEST=y
|
||||
CONFIG_PARAVIRT=y
|
||||
CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
|
||||
CONFIG_MICROCODE_AMD=y
|
||||
CONFIG_X86_MSR=y
|
||||
CONFIG_X86_CPUID=y
|
||||
CONFIG_NUMA=y
|
||||
|
@ -2,138 +2,83 @@
|
||||
#ifndef _ASM_X86_MICROCODE_H
|
||||
#define _ASM_X86_MICROCODE_H
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <linux/earlycpio.h>
|
||||
#include <linux/initrd.h>
|
||||
#include <asm/microcode_amd.h>
|
||||
|
||||
struct ucode_patch {
|
||||
struct list_head plist;
|
||||
void *data; /* Intel uses only this one */
|
||||
unsigned int size;
|
||||
u32 patch_id;
|
||||
u16 equiv_cpu;
|
||||
};
|
||||
|
||||
extern struct list_head microcode_cache;
|
||||
|
||||
struct cpu_signature {
|
||||
unsigned int sig;
|
||||
unsigned int pf;
|
||||
unsigned int rev;
|
||||
};
|
||||
|
||||
struct device;
|
||||
|
||||
enum ucode_state {
|
||||
UCODE_OK = 0,
|
||||
UCODE_NEW,
|
||||
UCODE_UPDATED,
|
||||
UCODE_NFOUND,
|
||||
UCODE_ERROR,
|
||||
};
|
||||
|
||||
struct microcode_ops {
|
||||
enum ucode_state (*request_microcode_fw) (int cpu, struct device *);
|
||||
|
||||
void (*microcode_fini_cpu) (int cpu);
|
||||
|
||||
/*
|
||||
* The generic 'microcode_core' part guarantees that
|
||||
* the callbacks below run on a target cpu when they
|
||||
* are being called.
|
||||
* See also the "Synchronization" section in microcode_core.c.
|
||||
*/
|
||||
enum ucode_state (*apply_microcode) (int cpu);
|
||||
int (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
|
||||
};
|
||||
|
||||
struct ucode_cpu_info {
|
||||
struct cpu_signature cpu_sig;
|
||||
void *mc;
|
||||
};
|
||||
extern struct ucode_cpu_info ucode_cpu_info[];
|
||||
struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa);
|
||||
|
||||
#ifdef CONFIG_MICROCODE_INTEL
|
||||
extern struct microcode_ops * __init init_intel_microcode(void);
|
||||
#else
|
||||
static inline struct microcode_ops * __init init_intel_microcode(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_MICROCODE_INTEL */
|
||||
|
||||
#ifdef CONFIG_MICROCODE_AMD
|
||||
extern struct microcode_ops * __init init_amd_microcode(void);
|
||||
extern void __exit exit_amd_microcode(void);
|
||||
#else
|
||||
static inline struct microcode_ops * __init init_amd_microcode(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void __exit exit_amd_microcode(void) {}
|
||||
#endif
|
||||
|
||||
#define MAX_UCODE_COUNT 128
|
||||
|
||||
#define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
|
||||
#define CPUID_INTEL1 QCHAR('G', 'e', 'n', 'u')
|
||||
#define CPUID_INTEL2 QCHAR('i', 'n', 'e', 'I')
|
||||
#define CPUID_INTEL3 QCHAR('n', 't', 'e', 'l')
|
||||
#define CPUID_AMD1 QCHAR('A', 'u', 't', 'h')
|
||||
#define CPUID_AMD2 QCHAR('e', 'n', 't', 'i')
|
||||
#define CPUID_AMD3 QCHAR('c', 'A', 'M', 'D')
|
||||
|
||||
#define CPUID_IS(a, b, c, ebx, ecx, edx) \
|
||||
(!((ebx ^ (a))|(edx ^ (b))|(ecx ^ (c))))
|
||||
|
||||
/*
|
||||
* In early loading microcode phase on BSP, boot_cpu_data is not set up yet.
|
||||
* x86_cpuid_vendor() gets vendor id for BSP.
|
||||
*
|
||||
* In 32 bit AP case, accessing boot_cpu_data needs linear address. To simplify
|
||||
* coding, we still use x86_cpuid_vendor() to get vendor id for AP.
|
||||
*
|
||||
* x86_cpuid_vendor() gets vendor information directly from CPUID.
|
||||
*/
|
||||
static inline int x86_cpuid_vendor(void)
|
||||
{
|
||||
u32 eax = 0x00000000;
|
||||
u32 ebx, ecx = 0, edx;
|
||||
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
if (CPUID_IS(CPUID_INTEL1, CPUID_INTEL2, CPUID_INTEL3, ebx, ecx, edx))
|
||||
return X86_VENDOR_INTEL;
|
||||
|
||||
if (CPUID_IS(CPUID_AMD1, CPUID_AMD2, CPUID_AMD3, ebx, ecx, edx))
|
||||
return X86_VENDOR_AMD;
|
||||
|
||||
return X86_VENDOR_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline unsigned int x86_cpuid_family(void)
|
||||
{
|
||||
u32 eax = 0x00000001;
|
||||
u32 ebx, ecx = 0, edx;
|
||||
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
return x86_family(eax);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MICROCODE
|
||||
extern void __init load_ucode_bsp(void);
|
||||
extern void load_ucode_ap(void);
|
||||
void reload_early_microcode(unsigned int cpu);
|
||||
extern bool initrd_gone;
|
||||
void load_ucode_bsp(void);
|
||||
void load_ucode_ap(void);
|
||||
void microcode_bsp_resume(void);
|
||||
#else
|
||||
static inline void __init load_ucode_bsp(void) { }
|
||||
static inline void load_ucode_ap(void) { }
|
||||
static inline void reload_early_microcode(unsigned int cpu) { }
|
||||
static inline void microcode_bsp_resume(void) { }
|
||||
static inline void load_ucode_bsp(void) { }
|
||||
static inline void load_ucode_ap(void) { }
|
||||
static inline void microcode_bsp_resume(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_SUP_INTEL
|
||||
/* Intel specific microcode defines. Public for IFS */
|
||||
struct microcode_header_intel {
|
||||
unsigned int hdrver;
|
||||
unsigned int rev;
|
||||
unsigned int date;
|
||||
unsigned int sig;
|
||||
unsigned int cksum;
|
||||
unsigned int ldrver;
|
||||
unsigned int pf;
|
||||
unsigned int datasize;
|
||||
unsigned int totalsize;
|
||||
unsigned int metasize;
|
||||
unsigned int reserved[2];
|
||||
};
|
||||
|
||||
struct microcode_intel {
|
||||
struct microcode_header_intel hdr;
|
||||
unsigned int bits[];
|
||||
};
|
||||
|
||||
#define DEFAULT_UCODE_DATASIZE (2000)
|
||||
#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
|
||||
#define MC_HEADER_TYPE_MICROCODE 1
|
||||
#define MC_HEADER_TYPE_IFS 2
|
||||
|
||||
static inline int intel_microcode_get_datasize(struct microcode_header_intel *hdr)
|
||||
{
|
||||
return hdr->datasize ? : DEFAULT_UCODE_DATASIZE;
|
||||
}
|
||||
|
||||
static inline u32 intel_get_microcode_revision(void)
|
||||
{
|
||||
u32 rev, dummy;
|
||||
|
||||
native_wrmsrl(MSR_IA32_UCODE_REV, 0);
|
||||
|
||||
/* As documented in the SDM: Do a CPUID 1 here */
|
||||
native_cpuid_eax(1);
|
||||
|
||||
/* get the current revision from MSR 0x8B */
|
||||
native_rdmsr(MSR_IA32_UCODE_REV, dummy, rev);
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
void show_ucode_info_early(void);
|
||||
|
||||
#else /* CONFIG_CPU_SUP_INTEL */
|
||||
static inline void show_ucode_info_early(void) { }
|
||||
#endif /* !CONFIG_CPU_SUP_INTEL */
|
||||
|
||||
#ifdef CONFIG_CPU_SUP_AMD
|
||||
void amd_check_microcode(void);
|
||||
#else /* CONFIG_CPU_SUP_AMD */
|
||||
static inline void amd_check_microcode(void) {}
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_MICROCODE_H */
|
||||
|
@ -1,60 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_MICROCODE_AMD_H
|
||||
#define _ASM_X86_MICROCODE_AMD_H
|
||||
|
||||
#include <asm/microcode.h>
|
||||
|
||||
#define UCODE_MAGIC 0x00414d44
|
||||
#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
|
||||
#define UCODE_UCODE_TYPE 0x00000001
|
||||
|
||||
#define SECTION_HDR_SIZE 8
|
||||
#define CONTAINER_HDR_SZ 12
|
||||
|
||||
struct equiv_cpu_entry {
|
||||
u32 installed_cpu;
|
||||
u32 fixed_errata_mask;
|
||||
u32 fixed_errata_compare;
|
||||
u16 equiv_cpu;
|
||||
u16 res;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct microcode_header_amd {
|
||||
u32 data_code;
|
||||
u32 patch_id;
|
||||
u16 mc_patch_data_id;
|
||||
u8 mc_patch_data_len;
|
||||
u8 init_flag;
|
||||
u32 mc_patch_data_checksum;
|
||||
u32 nb_dev_id;
|
||||
u32 sb_dev_id;
|
||||
u16 processor_rev_id;
|
||||
u8 nb_rev_id;
|
||||
u8 sb_rev_id;
|
||||
u8 bios_api_rev;
|
||||
u8 reserved1[3];
|
||||
u32 match_reg[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct microcode_amd {
|
||||
struct microcode_header_amd hdr;
|
||||
unsigned int mpb[];
|
||||
};
|
||||
|
||||
#define PATCH_MAX_SIZE (3 * PAGE_SIZE)
|
||||
|
||||
#ifdef CONFIG_MICROCODE_AMD
|
||||
extern void __init load_ucode_amd_bsp(unsigned int family);
|
||||
extern void load_ucode_amd_ap(unsigned int family);
|
||||
extern int __init save_microcode_in_initrd_amd(unsigned int family);
|
||||
void reload_ucode_amd(unsigned int cpu);
|
||||
extern void amd_check_microcode(void);
|
||||
#else
|
||||
static inline void __init load_ucode_amd_bsp(unsigned int family) {}
|
||||
static inline void load_ucode_amd_ap(unsigned int family) {}
|
||||
static inline int __init
|
||||
save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
|
||||
static inline void reload_ucode_amd(unsigned int cpu) {}
|
||||
static inline void amd_check_microcode(void) {}
|
||||
#endif
|
||||
#endif /* _ASM_X86_MICROCODE_AMD_H */
|
@ -1,88 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_MICROCODE_INTEL_H
|
||||
#define _ASM_X86_MICROCODE_INTEL_H
|
||||
|
||||
#include <asm/microcode.h>
|
||||
|
||||
struct microcode_header_intel {
|
||||
unsigned int hdrver;
|
||||
unsigned int rev;
|
||||
unsigned int date;
|
||||
unsigned int sig;
|
||||
unsigned int cksum;
|
||||
unsigned int ldrver;
|
||||
unsigned int pf;
|
||||
unsigned int datasize;
|
||||
unsigned int totalsize;
|
||||
unsigned int metasize;
|
||||
unsigned int reserved[2];
|
||||
};
|
||||
|
||||
struct microcode_intel {
|
||||
struct microcode_header_intel hdr;
|
||||
unsigned int bits[];
|
||||
};
|
||||
|
||||
/* microcode format is extended from prescott processors */
|
||||
struct extended_signature {
|
||||
unsigned int sig;
|
||||
unsigned int pf;
|
||||
unsigned int cksum;
|
||||
};
|
||||
|
||||
struct extended_sigtable {
|
||||
unsigned int count;
|
||||
unsigned int cksum;
|
||||
unsigned int reserved[3];
|
||||
struct extended_signature sigs[];
|
||||
};
|
||||
|
||||
#define DEFAULT_UCODE_DATASIZE (2000)
|
||||
#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
|
||||
#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
|
||||
#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
|
||||
#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
|
||||
#define MC_HEADER_TYPE_MICROCODE 1
|
||||
#define MC_HEADER_TYPE_IFS 2
|
||||
|
||||
#define get_totalsize(mc) \
|
||||
(((struct microcode_intel *)mc)->hdr.datasize ? \
|
||||
((struct microcode_intel *)mc)->hdr.totalsize : \
|
||||
DEFAULT_UCODE_TOTALSIZE)
|
||||
|
||||
#define get_datasize(mc) \
|
||||
(((struct microcode_intel *)mc)->hdr.datasize ? \
|
||||
((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
|
||||
|
||||
#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
|
||||
|
||||
static inline u32 intel_get_microcode_revision(void)
|
||||
{
|
||||
u32 rev, dummy;
|
||||
|
||||
native_wrmsrl(MSR_IA32_UCODE_REV, 0);
|
||||
|
||||
/* As documented in the SDM: Do a CPUID 1 here */
|
||||
native_cpuid_eax(1);
|
||||
|
||||
/* get the current revision from MSR 0x8B */
|
||||
native_rdmsr(MSR_IA32_UCODE_REV, dummy, rev);
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MICROCODE_INTEL
|
||||
extern void __init load_ucode_intel_bsp(void);
|
||||
extern void load_ucode_intel_ap(void);
|
||||
extern void show_ucode_info_early(void);
|
||||
extern int __init save_microcode_in_initrd_intel(void);
|
||||
void reload_ucode_intel(void);
|
||||
#else
|
||||
static inline __init void load_ucode_intel_bsp(void) {}
|
||||
static inline void load_ucode_intel_ap(void) {}
|
||||
static inline void show_ucode_info_early(void) {}
|
||||
static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; }
|
||||
static inline void reload_ucode_intel(void) {}
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_MICROCODE_INTEL_H */
|
@ -59,7 +59,6 @@
|
||||
#include <asm/cacheinfo.h>
|
||||
#include <asm/memtype.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/microcode_intel.h>
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/uv/uv.h>
|
||||
@ -2300,8 +2299,7 @@ void store_cpu_caps(struct cpuinfo_x86 *curr_info)
|
||||
* @prev_info: CPU capabilities stored before an update.
|
||||
*
|
||||
* The microcode loader calls this upon late microcode load to recheck features,
|
||||
* only when microcode has been updated. Caller holds microcode_mutex and CPU
|
||||
* hotplug lock.
|
||||
* only when microcode has been updated. Caller holds and CPU hotplug lock.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <asm/bugs.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/microcode_intel.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/hwcap2.h>
|
||||
#include <asm/elf.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
@ -184,180 +184,6 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c)
|
||||
return false;
|
||||
}
|
||||
|
||||
int intel_cpu_collect_info(struct ucode_cpu_info *uci)
|
||||
{
|
||||
unsigned int val[2];
|
||||
unsigned int family, model;
|
||||
struct cpu_signature csig = { 0 };
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
|
||||
memset(uci, 0, sizeof(*uci));
|
||||
|
||||
eax = 0x00000001;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
csig.sig = eax;
|
||||
|
||||
family = x86_family(eax);
|
||||
model = x86_model(eax);
|
||||
|
||||
if (model >= 5 || family > 6) {
|
||||
/* get processor flags from MSR 0x17 */
|
||||
native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
|
||||
csig.pf = 1 << ((val[1] >> 18) & 7);
|
||||
}
|
||||
|
||||
csig.rev = intel_get_microcode_revision();
|
||||
|
||||
uci->cpu_sig = csig;
|
||||
|
||||
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;
|
||||
|
@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
microcode-y := core.o
|
||||
obj-$(CONFIG_MICROCODE) += microcode.o
|
||||
microcode-$(CONFIG_MICROCODE_INTEL) += intel.o
|
||||
microcode-$(CONFIG_MICROCODE_AMD) += amd.o
|
||||
microcode-$(CONFIG_CPU_SUP_INTEL) += intel.o
|
||||
microcode-$(CONFIG_CPU_SUP_AMD) += amd.o
|
||||
|
@ -29,13 +29,53 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/microcode_amd.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define UCODE_MAGIC 0x00414d44
|
||||
#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
|
||||
#define UCODE_UCODE_TYPE 0x00000001
|
||||
|
||||
#define SECTION_HDR_SIZE 8
|
||||
#define CONTAINER_HDR_SZ 12
|
||||
|
||||
struct equiv_cpu_entry {
|
||||
u32 installed_cpu;
|
||||
u32 fixed_errata_mask;
|
||||
u32 fixed_errata_compare;
|
||||
u16 equiv_cpu;
|
||||
u16 res;
|
||||
} __packed;
|
||||
|
||||
struct microcode_header_amd {
|
||||
u32 data_code;
|
||||
u32 patch_id;
|
||||
u16 mc_patch_data_id;
|
||||
u8 mc_patch_data_len;
|
||||
u8 init_flag;
|
||||
u32 mc_patch_data_checksum;
|
||||
u32 nb_dev_id;
|
||||
u32 sb_dev_id;
|
||||
u16 processor_rev_id;
|
||||
u8 nb_rev_id;
|
||||
u8 sb_rev_id;
|
||||
u8 bios_api_rev;
|
||||
u8 reserved1[3];
|
||||
u32 match_reg[8];
|
||||
} __packed;
|
||||
|
||||
struct microcode_amd {
|
||||
struct microcode_header_amd hdr;
|
||||
unsigned int mpb[];
|
||||
};
|
||||
|
||||
#define PATCH_MAX_SIZE (3 * PAGE_SIZE)
|
||||
|
||||
static struct equiv_cpu_table {
|
||||
unsigned int num_entries;
|
||||
struct equiv_cpu_entry *entry;
|
||||
@ -56,9 +96,6 @@ struct cont_desc {
|
||||
|
||||
static u32 ucode_new_rev;
|
||||
|
||||
/* One blob per node. */
|
||||
static u8 amd_ucode_patch[MAX_NUMNODES][PATCH_MAX_SIZE];
|
||||
|
||||
/*
|
||||
* Microcode patch container file is prepended to the initrd in cpio
|
||||
* format. See Documentation/arch/x86/microcode.rst
|
||||
@ -415,20 +452,17 @@ static int __apply_microcode_amd(struct microcode_amd *mc)
|
||||
*
|
||||
* Returns true if container found (sets @desc), false otherwise.
|
||||
*/
|
||||
static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch)
|
||||
static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size)
|
||||
{
|
||||
struct cont_desc desc = { 0 };
|
||||
u8 (*patch)[PATCH_MAX_SIZE];
|
||||
struct microcode_amd *mc;
|
||||
u32 rev, dummy, *new_rev;
|
||||
bool ret = false;
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
|
||||
patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch);
|
||||
#else
|
||||
new_rev = &ucode_new_rev;
|
||||
patch = &amd_ucode_patch[0];
|
||||
#endif
|
||||
|
||||
desc.cpuid_1_eax = cpuid_1_eax;
|
||||
@ -452,9 +486,6 @@ static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, boo
|
||||
if (!__apply_microcode_amd(mc)) {
|
||||
*new_rev = mc->hdr.patch_id;
|
||||
ret = true;
|
||||
|
||||
if (save_patch)
|
||||
memcpy(patch, mc, min_t(u32, desc.psize, PATCH_MAX_SIZE));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -507,7 +538,7 @@ static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data
|
||||
*ret = cp;
|
||||
}
|
||||
|
||||
void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax)
|
||||
static void apply_ucode_from_containers(unsigned int cpuid_1_eax)
|
||||
{
|
||||
struct cpio_data cp = { };
|
||||
|
||||
@ -515,42 +546,12 @@ void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax)
|
||||
if (!(cp.data && cp.size))
|
||||
return;
|
||||
|
||||
early_apply_microcode(cpuid_1_eax, cp.data, cp.size, true);
|
||||
early_apply_microcode(cpuid_1_eax, cp.data, cp.size);
|
||||
}
|
||||
|
||||
void load_ucode_amd_ap(unsigned int cpuid_1_eax)
|
||||
void load_ucode_amd_early(unsigned int cpuid_1_eax)
|
||||
{
|
||||
struct microcode_amd *mc;
|
||||
struct cpio_data cp;
|
||||
u32 *new_rev, rev, dummy;
|
||||
|
||||
if (IS_ENABLED(CONFIG_X86_32)) {
|
||||
mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch);
|
||||
new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
|
||||
} else {
|
||||
mc = (struct microcode_amd *)amd_ucode_patch;
|
||||
new_rev = &ucode_new_rev;
|
||||
}
|
||||
|
||||
native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
|
||||
|
||||
/*
|
||||
* Check whether a new patch has been saved already. Also, allow application of
|
||||
* the same revision in order to pick up SMT-thread-specific configuration even
|
||||
* if the sibling SMT thread already has an up-to-date revision.
|
||||
*/
|
||||
if (*new_rev && rev <= mc->hdr.patch_id) {
|
||||
if (!__apply_microcode_amd(mc)) {
|
||||
*new_rev = mc->hdr.patch_id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
find_blobs_in_containers(cpuid_1_eax, &cp);
|
||||
if (!(cp.data && cp.size))
|
||||
return;
|
||||
|
||||
early_apply_microcode(cpuid_1_eax, cp.data, cp.size, false);
|
||||
return apply_ucode_from_containers(cpuid_1_eax);
|
||||
}
|
||||
|
||||
static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);
|
||||
@ -578,23 +579,6 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reload_ucode_amd(unsigned int cpu)
|
||||
{
|
||||
u32 rev, dummy __always_unused;
|
||||
struct microcode_amd *mc;
|
||||
|
||||
mc = (struct microcode_amd *)amd_ucode_patch[cpu_to_node(cpu)];
|
||||
|
||||
rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
|
||||
|
||||
if (rev < mc->hdr.patch_id) {
|
||||
if (!__apply_microcode_amd(mc)) {
|
||||
ucode_new_rev = mc->hdr.patch_id;
|
||||
pr_info("reload patch_level=0x%08x\n", ucode_new_rev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* a small, trivial cache of per-family ucode patches
|
||||
*/
|
||||
@ -655,6 +639,28 @@ static struct ucode_patch *find_patch(unsigned int cpu)
|
||||
return cache_find_patch(equiv_id);
|
||||
}
|
||||
|
||||
void reload_ucode_amd(unsigned int cpu)
|
||||
{
|
||||
u32 rev, dummy __always_unused;
|
||||
struct microcode_amd *mc;
|
||||
struct ucode_patch *p;
|
||||
|
||||
p = find_patch(cpu);
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
mc = p->data;
|
||||
|
||||
rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
|
||||
|
||||
if (rev < mc->hdr.patch_id) {
|
||||
if (!__apply_microcode_amd(mc)) {
|
||||
ucode_new_rev = mc->hdr.patch_id;
|
||||
pr_info("reload patch_level=0x%08x\n", ucode_new_rev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||
@ -875,9 +881,6 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz
|
||||
continue;
|
||||
|
||||
ret = UCODE_NEW;
|
||||
|
||||
memset(&amd_ucode_patch[nid], 0, PATCH_MAX_SIZE);
|
||||
memcpy(&amd_ucode_patch[nid], p->data, min_t(u32, p->size, PATCH_MAX_SIZE));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -31,15 +31,14 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/microcode_intel.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/microcode_amd.h>
|
||||
#include <asm/perf_event.h>
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/cmdline.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define DRIVER_VERSION "2.2"
|
||||
|
||||
static struct microcode_ops *microcode_ops;
|
||||
@ -54,15 +53,12 @@ LIST_HEAD(microcode_cache);
|
||||
*
|
||||
* All non cpu-hotplug-callback call sites use:
|
||||
*
|
||||
* - microcode_mutex to synchronize with each other;
|
||||
* - cpus_read_lock/unlock() to synchronize with
|
||||
* the cpu-hotplug-callback call sites.
|
||||
*
|
||||
* We guarantee that only a single cpu is being
|
||||
* updated at any particular moment of time.
|
||||
*/
|
||||
static DEFINE_MUTEX(microcode_mutex);
|
||||
|
||||
struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
|
||||
|
||||
struct cpu_info_ctx {
|
||||
@ -172,7 +168,7 @@ void __init load_ucode_bsp(void)
|
||||
if (intel)
|
||||
load_ucode_intel_bsp();
|
||||
else
|
||||
load_ucode_amd_bsp(cpuid_1_eax);
|
||||
load_ucode_amd_early(cpuid_1_eax);
|
||||
}
|
||||
|
||||
static bool check_loader_disabled_ap(void)
|
||||
@ -200,7 +196,7 @@ void load_ucode_ap(void)
|
||||
break;
|
||||
case X86_VENDOR_AMD:
|
||||
if (x86_family(cpuid_1_eax) >= 0x10)
|
||||
load_ucode_amd_ap(cpuid_1_eax);
|
||||
load_ucode_amd_early(cpuid_1_eax);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -298,7 +294,7 @@ struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa)
|
||||
#endif
|
||||
}
|
||||
|
||||
void reload_early_microcode(unsigned int cpu)
|
||||
static void reload_early_microcode(unsigned int cpu)
|
||||
{
|
||||
int vendor, family;
|
||||
|
||||
@ -488,10 +484,7 @@ static ssize_t reload_store(struct device *dev,
|
||||
if (tmp_ret != UCODE_NEW)
|
||||
goto put;
|
||||
|
||||
mutex_lock(µcode_mutex);
|
||||
ret = microcode_reload_late();
|
||||
mutex_unlock(µcode_mutex);
|
||||
|
||||
put:
|
||||
cpus_read_unlock();
|
||||
|
||||
|
@ -10,15 +10,7 @@
|
||||
* Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com>
|
||||
* H Peter Anvin" <hpa@zytor.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This needs to be before all headers so that pr_debug in printk.h doesn't turn
|
||||
* printk calls into no_printk().
|
||||
*
|
||||
*#define DEBUG
|
||||
*/
|
||||
#define pr_fmt(fmt) "microcode: " fmt
|
||||
|
||||
#include <linux/earlycpio.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/uaccess.h>
|
||||
@ -30,13 +22,14 @@
|
||||
#include <linux/uio.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/microcode_intel.h>
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/msr.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
|
||||
|
||||
/* Current microcode patch used in early patching on the APs. */
|
||||
@ -45,6 +38,208 @@ static struct microcode_intel *intel_ucode_patch;
|
||||
/* last level cache size per core */
|
||||
static int llc_size_per_core;
|
||||
|
||||
/* microcode format is extended from prescott processors */
|
||||
struct extended_signature {
|
||||
unsigned int sig;
|
||||
unsigned int pf;
|
||||
unsigned int cksum;
|
||||
};
|
||||
|
||||
struct extended_sigtable {
|
||||
unsigned int count;
|
||||
unsigned int cksum;
|
||||
unsigned int reserved[3];
|
||||
struct extended_signature sigs[];
|
||||
};
|
||||
|
||||
#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
|
||||
#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))
|
||||
#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))
|
||||
|
||||
static inline unsigned int get_totalsize(struct microcode_header_intel *hdr)
|
||||
{
|
||||
return hdr->datasize ? hdr->totalsize : DEFAULT_UCODE_TOTALSIZE;
|
||||
}
|
||||
|
||||
static inline unsigned int exttable_size(struct extended_sigtable *et)
|
||||
{
|
||||
return et->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE;
|
||||
}
|
||||
|
||||
int intel_cpu_collect_info(struct ucode_cpu_info *uci)
|
||||
{
|
||||
unsigned int val[2];
|
||||
unsigned int family, model;
|
||||
struct cpu_signature csig = { 0 };
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
|
||||
memset(uci, 0, sizeof(*uci));
|
||||
|
||||
eax = 0x00000001;
|
||||
ecx = 0;
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
csig.sig = eax;
|
||||
|
||||
family = x86_family(eax);
|
||||
model = x86_model(eax);
|
||||
|
||||
if (model >= 5 || family > 6) {
|
||||
/* get processor flags from MSR 0x17 */
|
||||
native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
|
||||
csig.pf = 1 << ((val[1] >> 18) & 7);
|
||||
}
|
||||
|
||||
csig.rev = intel_get_microcode_revision();
|
||||
|
||||
uci->cpu_sig = csig;
|
||||
|
||||
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) <= intel_microcode_get_datasize(mc_hdr) + MC_HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
ext_hdr = mc + intel_microcode_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 = intel_microcode_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);
|
||||
|
||||
/*
|
||||
* Returns 1 if update has been found, 0 otherwise.
|
||||
*/
|
||||
@ -202,86 +397,6 @@ next:
|
||||
return patch;
|
||||
}
|
||||
|
||||
static void show_saved_mc(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
int i = 0, j;
|
||||
unsigned int sig, pf, rev, total_size, data_size, date;
|
||||
struct ucode_cpu_info uci;
|
||||
struct ucode_patch *p;
|
||||
|
||||
if (list_empty(µcode_cache)) {
|
||||
pr_debug("no microcode data saved.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
intel_cpu_collect_info(&uci);
|
||||
|
||||
sig = uci.cpu_sig.sig;
|
||||
pf = uci.cpu_sig.pf;
|
||||
rev = uci.cpu_sig.rev;
|
||||
pr_debug("CPU: sig=0x%x, pf=0x%x, rev=0x%x\n", sig, pf, rev);
|
||||
|
||||
list_for_each_entry(p, µcode_cache, plist) {
|
||||
struct microcode_header_intel *mc_saved_header;
|
||||
struct extended_sigtable *ext_header;
|
||||
struct extended_signature *ext_sig;
|
||||
int ext_sigcount;
|
||||
|
||||
mc_saved_header = (struct microcode_header_intel *)p->data;
|
||||
|
||||
sig = mc_saved_header->sig;
|
||||
pf = mc_saved_header->pf;
|
||||
rev = mc_saved_header->rev;
|
||||
date = mc_saved_header->date;
|
||||
|
||||
total_size = get_totalsize(mc_saved_header);
|
||||
data_size = get_datasize(mc_saved_header);
|
||||
|
||||
pr_debug("mc_saved[%d]: sig=0x%x, pf=0x%x, rev=0x%x, total size=0x%x, date = %04x-%02x-%02x\n",
|
||||
i++, sig, pf, rev, total_size,
|
||||
date & 0xffff,
|
||||
date >> 24,
|
||||
(date >> 16) & 0xff);
|
||||
|
||||
/* Look for ext. headers: */
|
||||
if (total_size <= data_size + MC_HEADER_SIZE)
|
||||
continue;
|
||||
|
||||
ext_header = (void *)mc_saved_header + data_size + MC_HEADER_SIZE;
|
||||
ext_sigcount = ext_header->count;
|
||||
ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
|
||||
|
||||
for (j = 0; j < ext_sigcount; j++) {
|
||||
sig = ext_sig->sig;
|
||||
pf = ext_sig->pf;
|
||||
|
||||
pr_debug("\tExtended[%d]: sig=0x%x, pf=0x%x\n",
|
||||
j, sig, pf);
|
||||
|
||||
ext_sig++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Save this microcode patch. It will be loaded early when a CPU is
|
||||
* hot-added or resumes.
|
||||
*/
|
||||
static void save_mc_for_early(struct ucode_cpu_info *uci, u8 *mc, unsigned int size)
|
||||
{
|
||||
/* Synchronization during CPU hotplug. */
|
||||
static DEFINE_MUTEX(x86_cpu_microcode_mutex);
|
||||
|
||||
mutex_lock(&x86_cpu_microcode_mutex);
|
||||
|
||||
save_microcode_patch(uci, mc, size);
|
||||
show_saved_mc();
|
||||
|
||||
mutex_unlock(&x86_cpu_microcode_mutex);
|
||||
}
|
||||
|
||||
static bool load_builtin_intel_microcode(struct cpio_data *cp)
|
||||
{
|
||||
unsigned int eax = 1, ebx, ecx = 0, edx;
|
||||
@ -428,9 +543,6 @@ int __init save_microcode_in_initrd_intel(void)
|
||||
intel_cpu_collect_info(&uci);
|
||||
|
||||
scan_microcode(cp.data, cp.size, &uci, true);
|
||||
|
||||
show_saved_mc();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -701,12 +813,8 @@ static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter)
|
||||
vfree(uci->mc);
|
||||
uci->mc = (struct microcode_intel *)new_mc;
|
||||
|
||||
/*
|
||||
* If early loading microcode is supported, save this mc into
|
||||
* permanent memory. So it will be loaded early when a CPU is hot added
|
||||
* or resumes.
|
||||
*/
|
||||
save_mc_for_early(uci, new_mc, new_mc_size);
|
||||
/* Save for CPU hotplug */
|
||||
save_microcode_patch(uci, new_mc, new_mc_size);
|
||||
|
||||
pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
|
||||
cpu, new_rev, uci->cpu_sig.rev);
|
||||
|
131
arch/x86/kernel/cpu/microcode/internal.h
Normal file
131
arch/x86/kernel/cpu/microcode/internal.h
Normal file
@ -0,0 +1,131 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _X86_MICROCODE_INTERNAL_H
|
||||
#define _X86_MICROCODE_INTERNAL_H
|
||||
|
||||
#include <linux/earlycpio.h>
|
||||
#include <linux/initrd.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/microcode.h>
|
||||
|
||||
struct ucode_patch {
|
||||
struct list_head plist;
|
||||
void *data; /* Intel uses only this one */
|
||||
unsigned int size;
|
||||
u32 patch_id;
|
||||
u16 equiv_cpu;
|
||||
};
|
||||
|
||||
extern struct list_head microcode_cache;
|
||||
|
||||
struct device;
|
||||
|
||||
enum ucode_state {
|
||||
UCODE_OK = 0,
|
||||
UCODE_NEW,
|
||||
UCODE_UPDATED,
|
||||
UCODE_NFOUND,
|
||||
UCODE_ERROR,
|
||||
};
|
||||
|
||||
struct microcode_ops {
|
||||
enum ucode_state (*request_microcode_fw)(int cpu, struct device *dev);
|
||||
|
||||
void (*microcode_fini_cpu)(int cpu);
|
||||
|
||||
/*
|
||||
* The generic 'microcode_core' part guarantees that
|
||||
* the callbacks below run on a target cpu when they
|
||||
* are being called.
|
||||
* See also the "Synchronization" section in microcode_core.c.
|
||||
*/
|
||||
enum ucode_state (*apply_microcode)(int cpu);
|
||||
int (*collect_cpu_info)(int cpu, struct cpu_signature *csig);
|
||||
};
|
||||
|
||||
extern struct ucode_cpu_info ucode_cpu_info[];
|
||||
struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa);
|
||||
|
||||
#define MAX_UCODE_COUNT 128
|
||||
|
||||
#define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
|
||||
#define CPUID_INTEL1 QCHAR('G', 'e', 'n', 'u')
|
||||
#define CPUID_INTEL2 QCHAR('i', 'n', 'e', 'I')
|
||||
#define CPUID_INTEL3 QCHAR('n', 't', 'e', 'l')
|
||||
#define CPUID_AMD1 QCHAR('A', 'u', 't', 'h')
|
||||
#define CPUID_AMD2 QCHAR('e', 'n', 't', 'i')
|
||||
#define CPUID_AMD3 QCHAR('c', 'A', 'M', 'D')
|
||||
|
||||
#define CPUID_IS(a, b, c, ebx, ecx, edx) \
|
||||
(!(((ebx) ^ (a)) | ((edx) ^ (b)) | ((ecx) ^ (c))))
|
||||
|
||||
/*
|
||||
* In early loading microcode phase on BSP, boot_cpu_data is not set up yet.
|
||||
* x86_cpuid_vendor() gets vendor id for BSP.
|
||||
*
|
||||
* In 32 bit AP case, accessing boot_cpu_data needs linear address. To simplify
|
||||
* coding, we still use x86_cpuid_vendor() to get vendor id for AP.
|
||||
*
|
||||
* x86_cpuid_vendor() gets vendor information directly from CPUID.
|
||||
*/
|
||||
static inline int x86_cpuid_vendor(void)
|
||||
{
|
||||
u32 eax = 0x00000000;
|
||||
u32 ebx, ecx = 0, edx;
|
||||
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
if (CPUID_IS(CPUID_INTEL1, CPUID_INTEL2, CPUID_INTEL3, ebx, ecx, edx))
|
||||
return X86_VENDOR_INTEL;
|
||||
|
||||
if (CPUID_IS(CPUID_AMD1, CPUID_AMD2, CPUID_AMD3, ebx, ecx, edx))
|
||||
return X86_VENDOR_AMD;
|
||||
|
||||
return X86_VENDOR_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline unsigned int x86_cpuid_family(void)
|
||||
{
|
||||
u32 eax = 0x00000001;
|
||||
u32 ebx, ecx = 0, edx;
|
||||
|
||||
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||
|
||||
return x86_family(eax);
|
||||
}
|
||||
|
||||
extern bool initrd_gone;
|
||||
|
||||
#ifdef CONFIG_CPU_SUP_AMD
|
||||
void load_ucode_amd_bsp(unsigned int family);
|
||||
void load_ucode_amd_ap(unsigned int family);
|
||||
void load_ucode_amd_early(unsigned int cpuid_1_eax);
|
||||
int save_microcode_in_initrd_amd(unsigned int family);
|
||||
void reload_ucode_amd(unsigned int cpu);
|
||||
struct microcode_ops *init_amd_microcode(void);
|
||||
void exit_amd_microcode(void);
|
||||
#else /* CONFIG_CPU_SUP_AMD */
|
||||
static inline void load_ucode_amd_bsp(unsigned int family) { }
|
||||
static inline void load_ucode_amd_ap(unsigned int family) { }
|
||||
static inline void load_ucode_amd_early(unsigned int family) { }
|
||||
static inline int save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
|
||||
static inline void reload_ucode_amd(unsigned int cpu) { }
|
||||
static inline struct microcode_ops *init_amd_microcode(void) { return NULL; }
|
||||
static inline void exit_amd_microcode(void) { }
|
||||
#endif /* !CONFIG_CPU_SUP_AMD */
|
||||
|
||||
#ifdef CONFIG_CPU_SUP_INTEL
|
||||
void load_ucode_intel_bsp(void);
|
||||
void load_ucode_intel_ap(void);
|
||||
int save_microcode_in_initrd_intel(void);
|
||||
void reload_ucode_intel(void);
|
||||
struct microcode_ops *init_intel_microcode(void);
|
||||
#else /* CONFIG_CPU_SUP_INTEL */
|
||||
static inline void load_ucode_intel_bsp(void) { }
|
||||
static inline void load_ucode_intel_ap(void) { }
|
||||
static inline int save_microcode_in_initrd_intel(void) { return -EINVAL; }
|
||||
static inline void reload_ucode_intel(void) { }
|
||||
static inline struct microcode_ops *init_intel_microcode(void) { return NULL; }
|
||||
#endif /* !CONFIG_CPU_SUP_INTEL */
|
||||
|
||||
#endif /* _X86_MICROCODE_INTERNAL_H */
|
@ -20,7 +20,6 @@
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/proto.h>
|
||||
#include <asm/dma.h> /* for MAX_DMA_PFN */
|
||||
#include <asm/microcode.h>
|
||||
#include <asm/kaslr.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm/cpufeature.h>
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/microcode_intel.h>
|
||||
#include <asm/microcode.h>
|
||||
|
||||
#include "ifs.h"
|
||||
|
||||
@ -56,12 +56,13 @@ struct metadata_header {
|
||||
|
||||
static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_type)
|
||||
{
|
||||
struct microcode_header_intel *hdr = &((struct microcode_intel *)ucode)->hdr;
|
||||
struct metadata_header *meta_header;
|
||||
unsigned long data_size, total_meta;
|
||||
unsigned long meta_size = 0;
|
||||
|
||||
data_size = get_datasize(ucode);
|
||||
total_meta = ((struct microcode_intel *)ucode)->hdr.metasize;
|
||||
data_size = intel_microcode_get_datasize(hdr);
|
||||
total_meta = hdr->metasize;
|
||||
if (!total_meta)
|
||||
return NULL;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user