提交 0ad5c6b3 编写于 作者: L Linus Torvalds

Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 microcode changes from Ingo Molnar:
 "Microcode driver updates: mostly cleanups but also some fixes
  (Borislav Petkov)"

* 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/microcode/amd: Drop the pci_ids.h dependency
  x86/microcode/intel: Fix printing of microcode blobs in show_saved_mc()
  x86/microcode/intel: Check scan_microcode()'s retval
  x86/microcode/intel: Sanitize microcode_pointer()
  x86/microcode/intel: Move mc arg last in get_matching_{microcode|sig}
  x86/microcode/intel: Simplify generic_load_microcode_early()
  x86/microcode: Consolidate family,model, ... code
  x86/microcode/intel: Rename update_match_revision()
  x86/microcode/intel: Sanitize _save_mc()
  x86/microcode/intel: Make _save_mc() return the updated saved count
  x86/microcode/intel: Simplify load_ucode_intel_bsp()
  x86/microcode/intel: Get rid of last arg to load_ucode_intel_bsp()
  x86/microcode/intel: Do the mc_saved_src NULL check first
  x86/microcode/intel: Check if microcode was found before applying
  x86/microcode/intel: Fix out of bounds memory access to the extended header
...@@ -75,6 +75,79 @@ static inline void __exit exit_amd_microcode(void) {} ...@@ -75,6 +75,79 @@ static inline void __exit exit_amd_microcode(void) {}
#ifdef CONFIG_MICROCODE_EARLY #ifdef CONFIG_MICROCODE_EARLY
#define MAX_UCODE_COUNT 128 #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_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_vendor() to get vendor id for AP.
*
* x86_vendor() gets vendor information directly from CPUID.
*/
static inline int x86_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_family(unsigned int sig)
{
unsigned int x86;
x86 = (sig >> 8) & 0xf;
if (x86 == 0xf)
x86 += (sig >> 20) & 0xff;
return x86;
}
static inline unsigned int x86_family(void)
{
u32 eax = 0x00000001;
u32 ebx, ecx = 0, edx;
native_cpuid(&eax, &ebx, &ecx, &edx);
return __x86_family(eax);
}
static inline unsigned int x86_model(unsigned int sig)
{
unsigned int x86, model;
x86 = __x86_family(sig);
model = (sig >> 4) & 0xf;
if (x86 == 0x6 || x86 == 0xf)
model += ((sig >> 16) & 0xf) << 4;
return model;
}
extern void __init load_ucode_bsp(void); extern void __init load_ucode_bsp(void);
extern void load_ucode_ap(void); extern void load_ucode_ap(void);
extern int __init save_microcode_in_initrd(void); extern int __init save_microcode_in_initrd(void);
......
...@@ -56,12 +56,15 @@ struct extended_sigtable { ...@@ -56,12 +56,15 @@ struct extended_sigtable {
#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE) #define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
extern int extern int get_matching_microcode(unsigned int csig, int cpf, int rev, void *mc);
get_matching_microcode(unsigned int csig, int cpf, void *mc, int rev);
extern int microcode_sanity_check(void *mc, int print_err); extern int microcode_sanity_check(void *mc, int print_err);
extern int get_matching_sig(unsigned int csig, int cpf, void *mc, int rev); extern int get_matching_sig(unsigned int csig, int cpf, int rev, void *mc);
extern int
update_match_revision(struct microcode_header_intel *mc_header, int rev); static inline int
revision_is_newer(struct microcode_header_intel *mc_header, int rev)
{
return (mc_header->rev <= rev) ? 0 : 1;
}
#ifdef CONFIG_MICROCODE_INTEL_EARLY #ifdef CONFIG_MICROCODE_INTEL_EARLY
extern void __init load_ucode_intel_bsp(void); extern void __init load_ucode_intel_bsp(void);
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/pci_ids.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/kernel.h> #include <linux/kernel.h>
......
...@@ -23,57 +23,6 @@ ...@@ -23,57 +23,6 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/cmdline.h> #include <asm/cmdline.h>
#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_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_vendor() to get vendor id for AP.
*
* x86_vendor() gets vendor information directly through cpuid.
*/
static int x86_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 int x86_family(void)
{
u32 eax = 0x00000001;
u32 ebx, ecx = 0, edx;
int x86;
native_cpuid(&eax, &ebx, &ecx, &edx);
x86 = (eax >> 8) & 0xf;
if (x86 == 15)
x86 += (eax >> 20) & 0xff;
return x86;
}
static bool __init check_loader_disabled_bsp(void) static bool __init check_loader_disabled_bsp(void)
{ {
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
...@@ -96,7 +45,7 @@ static bool __init check_loader_disabled_bsp(void) ...@@ -96,7 +45,7 @@ static bool __init check_loader_disabled_bsp(void)
void __init load_ucode_bsp(void) void __init load_ucode_bsp(void)
{ {
int vendor, x86; int vendor, family;
if (check_loader_disabled_bsp()) if (check_loader_disabled_bsp())
return; return;
...@@ -105,15 +54,15 @@ void __init load_ucode_bsp(void) ...@@ -105,15 +54,15 @@ void __init load_ucode_bsp(void)
return; return;
vendor = x86_vendor(); vendor = x86_vendor();
x86 = x86_family(); family = x86_family();
switch (vendor) { switch (vendor) {
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
if (x86 >= 6) if (family >= 6)
load_ucode_intel_bsp(); load_ucode_intel_bsp();
break; break;
case X86_VENDOR_AMD: case X86_VENDOR_AMD:
if (x86 >= 0x10) if (family >= 0x10)
load_ucode_amd_bsp(); load_ucode_amd_bsp();
break; break;
default: default:
...@@ -132,7 +81,7 @@ static bool check_loader_disabled_ap(void) ...@@ -132,7 +81,7 @@ static bool check_loader_disabled_ap(void)
void load_ucode_ap(void) void load_ucode_ap(void)
{ {
int vendor, x86; int vendor, family;
if (check_loader_disabled_ap()) if (check_loader_disabled_ap())
return; return;
...@@ -141,15 +90,15 @@ void load_ucode_ap(void) ...@@ -141,15 +90,15 @@ void load_ucode_ap(void)
return; return;
vendor = x86_vendor(); vendor = x86_vendor();
x86 = x86_family(); family = x86_family();
switch (vendor) { switch (vendor) {
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
if (x86 >= 6) if (family >= 6)
load_ucode_intel_ap(); load_ucode_intel_ap();
break; break;
case X86_VENDOR_AMD: case X86_VENDOR_AMD:
if (x86 >= 0x10) if (family >= 0x10)
load_ucode_amd_ap(); load_ucode_amd_ap();
break; break;
default: default:
...@@ -179,18 +128,18 @@ int __init save_microcode_in_initrd(void) ...@@ -179,18 +128,18 @@ int __init save_microcode_in_initrd(void)
void reload_early_microcode(void) void reload_early_microcode(void)
{ {
int vendor, x86; int vendor, family;
vendor = x86_vendor(); vendor = x86_vendor();
x86 = x86_family(); family = x86_family();
switch (vendor) { switch (vendor) {
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
if (x86 >= 6) if (family >= 6)
reload_ucode_intel(); reload_ucode_intel();
break; break;
case X86_VENDOR_AMD: case X86_VENDOR_AMD:
if (x86 >= 0x10) if (family >= 0x10)
reload_ucode_amd(); reload_ucode_amd();
break; break;
default: default:
......
...@@ -124,7 +124,7 @@ static int get_matching_mc(struct microcode_intel *mc_intel, int cpu) ...@@ -124,7 +124,7 @@ static int get_matching_mc(struct microcode_intel *mc_intel, int cpu)
cpf = cpu_sig.pf; cpf = cpu_sig.pf;
crev = cpu_sig.rev; crev = cpu_sig.rev;
return get_matching_microcode(csig, cpf, mc_intel, crev); return get_matching_microcode(csig, cpf, crev, mc_intel);
} }
static int apply_microcode_intel(int cpu) static int apply_microcode_intel(int cpu)
...@@ -226,7 +226,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, ...@@ -226,7 +226,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
csig = uci->cpu_sig.sig; csig = uci->cpu_sig.sig;
cpf = uci->cpu_sig.pf; cpf = uci->cpu_sig.pf;
if (get_matching_microcode(csig, cpf, mc, new_rev)) { if (get_matching_microcode(csig, cpf, new_rev, mc)) {
vfree(new_mc); vfree(new_mc);
new_rev = mc_header.rev; new_rev = mc_header.rev;
new_mc = mc; new_mc = mc;
......
...@@ -16,6 +16,14 @@ ...@@ -16,6 +16,14 @@
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
/*
* This needs to be before all headers so that pr_debug in printk.h doesn't turn
* printk calls into no_printk().
*
*#define DEBUG
*/
#include <linux/module.h> #include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -28,6 +36,9 @@ ...@@ -28,6 +36,9 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/setup.h> #include <asm/setup.h>
#undef pr_fmt
#define pr_fmt(fmt) "microcode: " fmt
static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT]; static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT];
static struct mc_saved_data { static struct mc_saved_data {
unsigned int mc_saved_count; unsigned int mc_saved_count;
...@@ -35,50 +46,45 @@ static struct mc_saved_data { ...@@ -35,50 +46,45 @@ static struct mc_saved_data {
} mc_saved_data; } mc_saved_data;
static enum ucode_state static enum ucode_state
generic_load_microcode_early(struct microcode_intel **mc_saved_p, load_microcode_early(struct microcode_intel **saved,
unsigned int mc_saved_count, unsigned int num_saved, struct ucode_cpu_info *uci)
struct ucode_cpu_info *uci)
{ {
struct microcode_intel *ucode_ptr, *new_mc = NULL; struct microcode_intel *ucode_ptr, *new_mc = NULL;
int new_rev = uci->cpu_sig.rev; struct microcode_header_intel *mc_hdr;
enum ucode_state state = UCODE_OK; int new_rev, ret, i;
unsigned int mc_size;
struct microcode_header_intel *mc_header;
unsigned int csig = uci->cpu_sig.sig;
unsigned int cpf = uci->cpu_sig.pf;
int i;
for (i = 0; i < mc_saved_count; i++) { new_rev = uci->cpu_sig.rev;
ucode_ptr = mc_saved_p[i];
mc_header = (struct microcode_header_intel *)ucode_ptr; for (i = 0; i < num_saved; i++) {
mc_size = get_totalsize(mc_header); ucode_ptr = saved[i];
if (get_matching_microcode(csig, cpf, ucode_ptr, new_rev)) { mc_hdr = (struct microcode_header_intel *)ucode_ptr;
new_rev = mc_header->rev;
ret = get_matching_microcode(uci->cpu_sig.sig,
uci->cpu_sig.pf,
new_rev,
ucode_ptr);
if (!ret)
continue;
new_rev = mc_hdr->rev;
new_mc = ucode_ptr; new_mc = ucode_ptr;
} }
}
if (!new_mc) { if (!new_mc)
state = UCODE_NFOUND; return UCODE_NFOUND;
goto out;
}
uci->mc = (struct microcode_intel *)new_mc; uci->mc = (struct microcode_intel *)new_mc;
out: return UCODE_OK;
return state;
} }
static void static inline void
microcode_pointer(struct microcode_intel **mc_saved, copy_initrd_ptrs(struct microcode_intel **mc_saved, unsigned long *initrd,
unsigned long *mc_saved_in_initrd, unsigned long off, int num_saved)
unsigned long initrd_start, int mc_saved_count)
{ {
int i; int i;
for (i = 0; i < mc_saved_count; i++) for (i = 0; i < num_saved; i++)
mc_saved[i] = (struct microcode_intel *) mc_saved[i] = (struct microcode_intel *)(initrd[i] + off);
(mc_saved_in_initrd[i] + initrd_start);
} }
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
...@@ -102,55 +108,27 @@ microcode_phys(struct microcode_intel **mc_saved_tmp, ...@@ -102,55 +108,27 @@ microcode_phys(struct microcode_intel **mc_saved_tmp,
#endif #endif
static enum ucode_state static enum ucode_state
load_microcode(struct mc_saved_data *mc_saved_data, load_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd,
unsigned long *mc_saved_in_initrd, unsigned long initrd_start, struct ucode_cpu_info *uci)
unsigned long initrd_start,
struct ucode_cpu_info *uci)
{ {
struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT]; struct microcode_intel *mc_saved_tmp[MAX_UCODE_COUNT];
unsigned int count = mc_saved_data->mc_saved_count; unsigned int count = mc_saved_data->mc_saved_count;
if (!mc_saved_data->mc_saved) { if (!mc_saved_data->mc_saved) {
microcode_pointer(mc_saved_tmp, mc_saved_in_initrd, copy_initrd_ptrs(mc_saved_tmp, initrd, initrd_start, count);
initrd_start, count);
return generic_load_microcode_early(mc_saved_tmp, count, uci); return load_microcode_early(mc_saved_tmp, count, uci);
} else { } else {
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
microcode_phys(mc_saved_tmp, mc_saved_data); microcode_phys(mc_saved_tmp, mc_saved_data);
return generic_load_microcode_early(mc_saved_tmp, count, uci); return load_microcode_early(mc_saved_tmp, count, uci);
#else #else
return generic_load_microcode_early(mc_saved_data->mc_saved, return load_microcode_early(mc_saved_data->mc_saved,
count, uci); count, uci);
#endif #endif
} }
} }
static u8 get_x86_family(unsigned long sig)
{
u8 x86;
x86 = (sig >> 8) & 0xf;
if (x86 == 0xf)
x86 += (sig >> 20) & 0xff;
return x86;
}
static u8 get_x86_model(unsigned long sig)
{
u8 x86, x86_model;
x86 = get_x86_family(sig);
x86_model = (sig >> 4) & 0xf;
if (x86 == 0x6 || x86 == 0xf)
x86_model += ((sig >> 16) & 0xf) << 4;
return x86_model;
}
/* /*
* Given CPU signature and a microcode patch, this function finds if the * Given CPU signature and a microcode patch, this function finds if the
* microcode patch has matching family and model with the CPU. * microcode patch has matching family and model with the CPU.
...@@ -159,42 +137,40 @@ static enum ucode_state ...@@ -159,42 +137,40 @@ static enum ucode_state
matching_model_microcode(struct microcode_header_intel *mc_header, matching_model_microcode(struct microcode_header_intel *mc_header,
unsigned long sig) unsigned long sig)
{ {
u8 x86, x86_model; unsigned int fam, model;
u8 x86_ucode, x86_model_ucode; unsigned int fam_ucode, model_ucode;
struct extended_sigtable *ext_header; struct extended_sigtable *ext_header;
unsigned long total_size = get_totalsize(mc_header); unsigned long total_size = get_totalsize(mc_header);
unsigned long data_size = get_datasize(mc_header); unsigned long data_size = get_datasize(mc_header);
int ext_sigcount, i; int ext_sigcount, i;
struct extended_signature *ext_sig; struct extended_signature *ext_sig;
x86 = get_x86_family(sig); fam = __x86_family(sig);
x86_model = get_x86_model(sig); model = x86_model(sig);
x86_ucode = get_x86_family(mc_header->sig); fam_ucode = __x86_family(mc_header->sig);
x86_model_ucode = get_x86_model(mc_header->sig); model_ucode = x86_model(mc_header->sig);
if (x86 == x86_ucode && x86_model == x86_model_ucode) if (fam == fam_ucode && model == model_ucode)
return UCODE_OK; return UCODE_OK;
/* Look for ext. headers: */ /* Look for ext. headers: */
if (total_size <= data_size + MC_HEADER_SIZE) if (total_size <= data_size + MC_HEADER_SIZE)
return UCODE_NFOUND; return UCODE_NFOUND;
ext_header = (struct extended_sigtable *) ext_header = (void *) mc_header + data_size + MC_HEADER_SIZE;
mc_header + data_size + MC_HEADER_SIZE;
ext_sigcount = ext_header->count;
ext_sig = (void *)ext_header + EXT_HEADER_SIZE; ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
ext_sigcount = ext_header->count;
for (i = 0; i < ext_sigcount; i++) { for (i = 0; i < ext_sigcount; i++) {
x86_ucode = get_x86_family(ext_sig->sig); fam_ucode = __x86_family(ext_sig->sig);
x86_model_ucode = get_x86_model(ext_sig->sig); model_ucode = x86_model(ext_sig->sig);
if (x86 == x86_ucode && x86_model == x86_model_ucode) if (fam == fam_ucode && model == model_ucode)
return UCODE_OK; return UCODE_OK;
ext_sig++; ext_sig++;
} }
return UCODE_NFOUND; return UCODE_NFOUND;
} }
...@@ -204,7 +180,7 @@ save_microcode(struct mc_saved_data *mc_saved_data, ...@@ -204,7 +180,7 @@ save_microcode(struct mc_saved_data *mc_saved_data,
unsigned int mc_saved_count) unsigned int mc_saved_count)
{ {
int i, j; int i, j;
struct microcode_intel **mc_saved_p; struct microcode_intel **saved_ptr;
int ret; int ret;
if (!mc_saved_count) if (!mc_saved_count)
...@@ -213,39 +189,45 @@ save_microcode(struct mc_saved_data *mc_saved_data, ...@@ -213,39 +189,45 @@ save_microcode(struct mc_saved_data *mc_saved_data,
/* /*
* Copy new microcode data. * Copy new microcode data.
*/ */
mc_saved_p = kmalloc(mc_saved_count*sizeof(struct microcode_intel *), saved_ptr = kcalloc(mc_saved_count, sizeof(struct microcode_intel *), GFP_KERNEL);
GFP_KERNEL); if (!saved_ptr)
if (!mc_saved_p)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < mc_saved_count; i++) { for (i = 0; i < mc_saved_count; i++) {
struct microcode_intel *mc = mc_saved_src[i]; struct microcode_header_intel *mc_hdr;
struct microcode_header_intel *mc_header = &mc->hdr; struct microcode_intel *mc;
unsigned long mc_size = get_totalsize(mc_header); unsigned long size;
mc_saved_p[i] = kmalloc(mc_size, GFP_KERNEL);
if (!mc_saved_p[i]) {
ret = -ENOMEM;
goto err;
}
if (!mc_saved_src[i]) { if (!mc_saved_src[i]) {
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;
} }
memcpy(mc_saved_p[i], mc, mc_size);
mc = mc_saved_src[i];
mc_hdr = &mc->hdr;
size = get_totalsize(mc_hdr);
saved_ptr[i] = kmalloc(size, GFP_KERNEL);
if (!saved_ptr[i]) {
ret = -ENOMEM;
goto err;
}
memcpy(saved_ptr[i], mc, size);
} }
/* /*
* Point to newly saved microcode. * Point to newly saved microcode.
*/ */
mc_saved_data->mc_saved = mc_saved_p; mc_saved_data->mc_saved = saved_ptr;
mc_saved_data->mc_saved_count = mc_saved_count; mc_saved_data->mc_saved_count = mc_saved_count;
return 0; return 0;
err: err:
for (j = 0; j <= i; j++) for (j = 0; j <= i; j++)
kfree(mc_saved_p[j]); kfree(saved_ptr[j]);
kfree(mc_saved_p); kfree(saved_ptr);
return ret; return ret;
} }
...@@ -257,48 +239,45 @@ save_microcode(struct mc_saved_data *mc_saved_data, ...@@ -257,48 +239,45 @@ save_microcode(struct mc_saved_data *mc_saved_data,
* - or if it is a newly discovered microcode patch. * - or if it is a newly discovered microcode patch.
* *
* The microcode patch should have matching model with CPU. * The microcode patch should have matching model with CPU.
*
* Returns: The updated number @num_saved of saved microcode patches.
*/ */
static void _save_mc(struct microcode_intel **mc_saved, u8 *ucode_ptr, static unsigned int _save_mc(struct microcode_intel **mc_saved,
unsigned int *mc_saved_count_p) u8 *ucode_ptr, unsigned int num_saved)
{ {
int i; struct microcode_header_intel *mc_hdr, *mc_saved_hdr;
int found = 0; unsigned int sig, pf, new_rev;
unsigned int mc_saved_count = *mc_saved_count_p; int found = 0, i;
struct microcode_header_intel *mc_header;
mc_header = (struct microcode_header_intel *)ucode_ptr; mc_hdr = (struct microcode_header_intel *)ucode_ptr;
for (i = 0; i < mc_saved_count; i++) {
unsigned int sig, pf; for (i = 0; i < num_saved; i++) {
unsigned int new_rev; mc_saved_hdr = (struct microcode_header_intel *)mc_saved[i];
struct microcode_header_intel *mc_saved_header = sig = mc_saved_hdr->sig;
(struct microcode_header_intel *)mc_saved[i]; pf = mc_saved_hdr->pf;
sig = mc_saved_header->sig; new_rev = mc_hdr->rev;
pf = mc_saved_header->pf;
new_rev = mc_header->rev; if (!get_matching_sig(sig, pf, new_rev, ucode_ptr))
continue;
if (get_matching_sig(sig, pf, ucode_ptr, new_rev)) {
found = 1; found = 1;
if (update_match_revision(mc_header, new_rev)) {
if (!revision_is_newer(mc_hdr, new_rev))
continue;
/* /*
* Found an older ucode saved before. * Found an older ucode saved earlier. Replace it with
* Replace the older one with this newer * this newer one.
* one.
*/ */
mc_saved[i] = mc_saved[i] = (struct microcode_intel *)ucode_ptr;
(struct microcode_intel *)ucode_ptr;
break; break;
} }
}
}
if (i >= mc_saved_count && !found)
/*
* This ucode is first time discovered in ucode file.
* Save it to memory.
*/
mc_saved[mc_saved_count++] =
(struct microcode_intel *)ucode_ptr;
*mc_saved_count_p = mc_saved_count; /* Newly detected microcode, save it to memory. */
if (i >= num_saved && !found)
mc_saved[num_saved++] = (struct microcode_intel *)ucode_ptr;
return num_saved;
} }
/* /*
...@@ -346,7 +325,7 @@ get_matching_model_microcode(int cpu, unsigned long start, ...@@ -346,7 +325,7 @@ get_matching_model_microcode(int cpu, unsigned long start,
continue; continue;
} }
_save_mc(mc_saved_tmp, ucode_ptr, &mc_saved_count); mc_saved_count = _save_mc(mc_saved_tmp, ucode_ptr, mc_saved_count);
ucode_ptr += mc_size; ucode_ptr += mc_size;
} }
...@@ -372,7 +351,7 @@ get_matching_model_microcode(int cpu, unsigned long start, ...@@ -372,7 +351,7 @@ get_matching_model_microcode(int cpu, unsigned long start,
static int collect_cpu_info_early(struct ucode_cpu_info *uci) static int collect_cpu_info_early(struct ucode_cpu_info *uci)
{ {
unsigned int val[2]; unsigned int val[2];
u8 x86, x86_model; unsigned int family, model;
struct cpu_signature csig; struct cpu_signature csig;
unsigned int eax, ebx, ecx, edx; unsigned int eax, ebx, ecx, edx;
...@@ -387,10 +366,10 @@ static int collect_cpu_info_early(struct ucode_cpu_info *uci) ...@@ -387,10 +366,10 @@ static int collect_cpu_info_early(struct ucode_cpu_info *uci)
native_cpuid(&eax, &ebx, &ecx, &edx); native_cpuid(&eax, &ebx, &ecx, &edx);
csig.sig = eax; csig.sig = eax;
x86 = get_x86_family(csig.sig); family = __x86_family(csig.sig);
x86_model = get_x86_model(csig.sig); model = x86_model(csig.sig);
if ((x86_model >= 5) || (x86 > 6)) { if ((model >= 5) || (family > 6)) {
/* get processor flags from MSR 0x17 */ /* get processor flags from MSR 0x17 */
native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
csig.pf = 1 << ((val[1] >> 18) & 7); csig.pf = 1 << ((val[1] >> 18) & 7);
...@@ -429,8 +408,7 @@ static void __ref show_saved_mc(void) ...@@ -429,8 +408,7 @@ static void __ref show_saved_mc(void)
sig = uci.cpu_sig.sig; sig = uci.cpu_sig.sig;
pf = uci.cpu_sig.pf; pf = uci.cpu_sig.pf;
rev = uci.cpu_sig.rev; rev = uci.cpu_sig.rev;
pr_debug("CPU%d: sig=0x%x, pf=0x%x, rev=0x%x\n", pr_debug("CPU: sig=0x%x, pf=0x%x, rev=0x%x\n", sig, pf, rev);
smp_processor_id(), sig, pf, rev);
for (i = 0; i < mc_saved_data.mc_saved_count; i++) { for (i = 0; i < mc_saved_data.mc_saved_count; i++) {
struct microcode_header_intel *mc_saved_header; struct microcode_header_intel *mc_saved_header;
...@@ -457,8 +435,7 @@ static void __ref show_saved_mc(void) ...@@ -457,8 +435,7 @@ static void __ref show_saved_mc(void)
if (total_size <= data_size + MC_HEADER_SIZE) if (total_size <= data_size + MC_HEADER_SIZE)
continue; continue;
ext_header = (struct extended_sigtable *) ext_header = (void *) mc_saved_header + data_size + MC_HEADER_SIZE;
mc_saved_header + data_size + MC_HEADER_SIZE;
ext_sigcount = ext_header->count; ext_sigcount = ext_header->count;
ext_sig = (void *)ext_header + EXT_HEADER_SIZE; ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
...@@ -515,8 +492,7 @@ int save_mc_for_early(u8 *mc) ...@@ -515,8 +492,7 @@ int save_mc_for_early(u8 *mc)
* Save the microcode patch mc in mc_save_tmp structure if it's a newer * Save the microcode patch mc in mc_save_tmp structure if it's a newer
* version. * version.
*/ */
mc_saved_count = _save_mc(mc_saved_tmp, mc, mc_saved_count);
_save_mc(mc_saved_tmp, mc, &mc_saved_count);
/* /*
* Save the mc_save_tmp in global mc_saved_data. * Save the mc_save_tmp in global mc_saved_data.
...@@ -548,12 +524,10 @@ EXPORT_SYMBOL_GPL(save_mc_for_early); ...@@ -548,12 +524,10 @@ EXPORT_SYMBOL_GPL(save_mc_for_early);
static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin"; static __initdata char ucode_name[] = "kernel/x86/microcode/GenuineIntel.bin";
static __init enum ucode_state static __init enum ucode_state
scan_microcode(unsigned long start, unsigned long end, scan_microcode(struct mc_saved_data *mc_saved_data, unsigned long *initrd,
struct mc_saved_data *mc_saved_data, unsigned long start, unsigned long size,
unsigned long *mc_saved_in_initrd,
struct ucode_cpu_info *uci) struct ucode_cpu_info *uci)
{ {
unsigned int size = end - start + 1;
struct cpio_data cd; struct cpio_data cd;
long offset = 0; long offset = 0;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
...@@ -569,10 +543,8 @@ scan_microcode(unsigned long start, unsigned long end, ...@@ -569,10 +543,8 @@ scan_microcode(unsigned long start, unsigned long end,
if (!cd.data) if (!cd.data)
return UCODE_ERROR; return UCODE_ERROR;
return get_matching_model_microcode(0, start, cd.data, cd.size, return get_matching_model_microcode(0, start, cd.data, cd.size,
mc_saved_data, mc_saved_in_initrd, mc_saved_data, initrd, uci);
uci);
} }
/* /*
...@@ -704,7 +676,7 @@ int __init save_microcode_in_initrd_intel(void) ...@@ -704,7 +676,7 @@ int __init save_microcode_in_initrd_intel(void)
if (count == 0) if (count == 0)
return ret; return ret;
microcode_pointer(mc_saved, mc_saved_in_initrd, initrd_start, count); copy_initrd_ptrs(mc_saved, mc_saved_in_initrd, initrd_start, count);
ret = save_microcode(&mc_saved_data, mc_saved, count); ret = save_microcode(&mc_saved_data, mc_saved, count);
if (ret) if (ret)
pr_err("Cannot save microcode patches from initrd.\n"); pr_err("Cannot save microcode patches from initrd.\n");
...@@ -716,52 +688,44 @@ int __init save_microcode_in_initrd_intel(void) ...@@ -716,52 +688,44 @@ int __init save_microcode_in_initrd_intel(void)
static void __init static void __init
_load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data, _load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data,
unsigned long *mc_saved_in_initrd, unsigned long *initrd,
unsigned long initrd_start_early, unsigned long start, unsigned long size)
unsigned long initrd_end_early,
struct ucode_cpu_info *uci)
{ {
struct ucode_cpu_info uci;
enum ucode_state ret; enum ucode_state ret;
collect_cpu_info_early(uci); collect_cpu_info_early(&uci);
scan_microcode(initrd_start_early, initrd_end_early, mc_saved_data,
mc_saved_in_initrd, uci);
ret = load_microcode(mc_saved_data, mc_saved_in_initrd, ret = scan_microcode(mc_saved_data, initrd, start, size, &uci);
initrd_start_early, uci); if (ret != UCODE_OK)
return;
if (ret == UCODE_OK) ret = load_microcode(mc_saved_data, initrd, start, &uci);
apply_microcode_early(uci, true); if (ret != UCODE_OK)
return;
apply_microcode_early(&uci, true);
} }
void __init void __init load_ucode_intel_bsp(void)
load_ucode_intel_bsp(void)
{ {
u64 ramdisk_image, ramdisk_size; u64 start, size;
unsigned long initrd_start_early, initrd_end_early;
struct ucode_cpu_info uci;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
struct boot_params *boot_params_p; struct boot_params *p;
boot_params_p = (struct boot_params *)__pa_nodebug(&boot_params); p = (struct boot_params *)__pa_nodebug(&boot_params);
ramdisk_image = boot_params_p->hdr.ramdisk_image; start = p->hdr.ramdisk_image;
ramdisk_size = boot_params_p->hdr.ramdisk_size; size = p->hdr.ramdisk_size;
initrd_start_early = ramdisk_image;
initrd_end_early = initrd_start_early + ramdisk_size;
_load_ucode_intel_bsp( _load_ucode_intel_bsp(
(struct mc_saved_data *)__pa_nodebug(&mc_saved_data), (struct mc_saved_data *)__pa_nodebug(&mc_saved_data),
(unsigned long *)__pa_nodebug(&mc_saved_in_initrd), (unsigned long *)__pa_nodebug(&mc_saved_in_initrd),
initrd_start_early, initrd_end_early, &uci); start, size);
#else #else
ramdisk_image = boot_params.hdr.ramdisk_image; start = boot_params.hdr.ramdisk_image + PAGE_OFFSET;
ramdisk_size = boot_params.hdr.ramdisk_size; size = boot_params.hdr.ramdisk_size;
initrd_start_early = ramdisk_image + PAGE_OFFSET;
initrd_end_early = initrd_start_early + ramdisk_size; _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, start, size);
_load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd,
initrd_start_early, initrd_end_early,
&uci);
#endif #endif
} }
...@@ -771,6 +735,7 @@ void load_ucode_intel_ap(void) ...@@ -771,6 +735,7 @@ void load_ucode_intel_ap(void)
struct ucode_cpu_info uci; struct ucode_cpu_info uci;
unsigned long *mc_saved_in_initrd_p; unsigned long *mc_saved_in_initrd_p;
unsigned long initrd_start_addr; unsigned long initrd_start_addr;
enum ucode_state ret;
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
unsigned long *initrd_start_p; unsigned long *initrd_start_p;
...@@ -793,8 +758,12 @@ void load_ucode_intel_ap(void) ...@@ -793,8 +758,12 @@ void load_ucode_intel_ap(void)
return; return;
collect_cpu_info_early(&uci); collect_cpu_info_early(&uci);
load_microcode(mc_saved_data_p, mc_saved_in_initrd_p, ret = load_microcode(mc_saved_data_p, mc_saved_in_initrd_p,
initrd_start_addr, &uci); initrd_start_addr, &uci);
if (ret != UCODE_OK)
return;
apply_microcode_early(&uci, true); apply_microcode_early(&uci, true);
} }
...@@ -808,7 +777,7 @@ void reload_ucode_intel(void) ...@@ -808,7 +777,7 @@ void reload_ucode_intel(void)
collect_cpu_info_early(&uci); collect_cpu_info_early(&uci);
ret = generic_load_microcode_early(mc_saved_data.mc_saved, ret = load_microcode_early(mc_saved_data.mc_saved,
mc_saved_data.mc_saved_count, &uci); mc_saved_data.mc_saved_count, &uci);
if (ret != UCODE_OK) if (ret != UCODE_OK)
return; return;
......
...@@ -38,12 +38,6 @@ update_match_cpu(unsigned int csig, unsigned int cpf, ...@@ -38,12 +38,6 @@ update_match_cpu(unsigned int csig, unsigned int cpf,
return (!sigmatch(sig, csig, pf, cpf)) ? 0 : 1; return (!sigmatch(sig, csig, pf, cpf)) ? 0 : 1;
} }
int
update_match_revision(struct microcode_header_intel *mc_header, int rev)
{
return (mc_header->rev <= rev) ? 0 : 1;
}
int microcode_sanity_check(void *mc, int print_err) int microcode_sanity_check(void *mc, int print_err)
{ {
unsigned long total_size, data_size, ext_table_size; unsigned long total_size, data_size, ext_table_size;
...@@ -128,10 +122,9 @@ int microcode_sanity_check(void *mc, int print_err) ...@@ -128,10 +122,9 @@ int microcode_sanity_check(void *mc, int print_err)
EXPORT_SYMBOL_GPL(microcode_sanity_check); EXPORT_SYMBOL_GPL(microcode_sanity_check);
/* /*
* return 0 - no update found * Returns 1 if update has been found, 0 otherwise.
* return 1 - found update
*/ */
int get_matching_sig(unsigned int csig, int cpf, void *mc, int rev) int get_matching_sig(unsigned int csig, int cpf, int rev, void *mc)
{ {
struct microcode_header_intel *mc_header = mc; struct microcode_header_intel *mc_header = mc;
struct extended_sigtable *ext_header; struct extended_sigtable *ext_header;
...@@ -159,16 +152,15 @@ int get_matching_sig(unsigned int csig, int cpf, void *mc, int rev) ...@@ -159,16 +152,15 @@ int get_matching_sig(unsigned int csig, int cpf, void *mc, int rev)
} }
/* /*
* return 0 - no update found * Returns 1 if update has been found, 0 otherwise.
* return 1 - found update
*/ */
int get_matching_microcode(unsigned int csig, int cpf, void *mc, int rev) int get_matching_microcode(unsigned int csig, int cpf, int rev, void *mc)
{ {
struct microcode_header_intel *mc_header = mc; struct microcode_header_intel *mc_hdr = mc;
if (!update_match_revision(mc_header, rev)) if (!revision_is_newer(mc_hdr, rev))
return 0; return 0;
return get_matching_sig(csig, cpf, mc, rev); return get_matching_sig(csig, cpf, rev, mc);
} }
EXPORT_SYMBOL_GPL(get_matching_microcode); EXPORT_SYMBOL_GPL(get_matching_microcode);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册