Stefan Reinauer (stefan.reinauer@coreboot.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2778
-gerrit
commit 2007453797a6db1927dc3fd2f415008306ba24eb Author: Aaron Durbin adurbin@chromium.org Date: Tue Jan 15 15:15:32 2013 -0600
intel microcode: split up microcode loading stages
This patch only applies to CONFIG_MICROCODE_IN_CBFS. The intel microcode update routine would always walk the CBFS for the microcode file. Then it would loop through the whole file looking for a match then load the microcode. This process was maintained for intel_update_microcode_from_cbfs(), however 2 new functions were exported: 1. const void *intel_microcode_find(void) 2. void intel_microcode_load_unlocked(const void *microcode_patch)
The first locates a matching microcode while the second loads that mircocode. These new functions can then be used to cache the found microcode blob w/o having to re-walk the CBFS.
Booted baskingridge board to Linux and noted that all microcode revisions match on all the CPUs.
Change-Id: Ifde3f3e5c100911c4f984dd56d36664a8acdf7d5 Signed-off-by: Aaron Durbin adurbin@chromium.org --- src/cpu/intel/microcode/microcode.c | 128 +++++++++++++++++++++++++++++++----- src/include/cpu/intel/microcode.h | 7 ++ 2 files changed, 117 insertions(+), 18 deletions(-)
diff --git a/src/cpu/intel/microcode/microcode.c b/src/cpu/intel/microcode/microcode.c index 713a6df..d908c25 100644 --- a/src/cpu/intel/microcode/microcode.c +++ b/src/cpu/intel/microcode/microcode.c @@ -82,8 +82,117 @@ static inline u32 read_microcode_rev(void) }
#if CONFIG_CPU_MICROCODE_IN_CBFS -static + +#define MICROCODE_CBFS_FILE "cpu_microcode_blob.bin" + +void intel_microcode_load_unlocked(const void *microcode_patch) +{ + u32 current_rev; + msr_t msr; + const struct microcode *m = microcode_patch; + + if (!m) + return; + + current_rev = read_microcode_rev(); + + /* No use loading the same revision. */ + if (current_rev == m->rev) + return; + + msr.lo = (unsigned long)m + sizeof(struct microcode); + msr.hi = 0; + wrmsr(0x79, msr); + +#if !defined(__ROMCC__) + printk(BIOS_DEBUG, "microcode: updated to revision " + "0x%x date=%04x-%02x-%02x\n", read_microcode_rev(), + m->date & 0xffff, (m->date >> 24) & 0xff, + (m->date >> 16) & 0xff); +#endif +} + +const void *intel_microcode_find(void) +{ + void *microcode_updates; + u32 eax; + u32 pf, rev, sig; + unsigned int x86_model, x86_family; + const struct microcode *m; + const char *c; + msr_t msr; + +#ifdef __PRE_RAM__ + microcode_updates = walkcbfs((char *) MICROCODE_CBFS_FILE); +#else + microcode_updates = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, + MICROCODE_CBFS_FILE, + CBFS_TYPE_MICROCODE); #endif + + if (!microcode_updates) + return microcode_updates; + + /* CPUID sets MSR 0x8B iff a microcode update has been loaded. */ + msr.lo = 0; + msr.hi = 0; + wrmsr(0x8B, msr); + eax = cpuid_eax(1); + msr = rdmsr(0x8B); + rev = msr.hi; + x86_model = (eax >>4) & 0x0f; + x86_family = (eax >>8) & 0x0f; + sig = eax; + + pf = 0; + if ((x86_model >= 5)||(x86_family>6)) { + msr = rdmsr(0x17); + pf = 1 << ((msr.hi >> 18) & 7); + } +#if !defined(__ROMCC__) + /* If this code is compiled with ROMCC we're probably in + * the bootblock and don't have console output yet. + */ + printk(BIOS_DEBUG, "microcode: sig=0x%x pf=0x%x revision=0x%x\n", + sig, pf, rev); +#endif + + m = microcode_updates; + for(c = microcode_updates; m->hdrver; m = (const struct microcode *)c) { + if ((m->sig == sig) && (m->pf & pf)) + return m; + + if (m->total_size) { + c += m->total_size; + } else { +#if !defined(__ROMCC__) + printk(BIOS_WARNING, "Microcode has no valid size field!\n"); +#endif + c += 2048; + } + } + + /* ROMCC doesn't like NULL. */ + return (void *)0; +} + +void intel_update_microcode_from_cbfs(void) +{ + const void *patch = intel_microcode_find(); + +#if !defined(__ROMCC__) && !defined(__PRE_RAM__) + spin_lock(µcode_lock); +#endif + + intel_microcode_load_unlocked(patch); + +#if !defined(__ROMCC__) && !defined(__PRE_RAM__) + spin_unlock(µcode_lock); +#endif +} + +#else /* !CONFIG_CPU_MICROCODE_IN_CBFS */ + void intel_update_microcode(const void *microcode_updates) { u32 eax; @@ -155,21 +264,4 @@ void intel_update_microcode(const void *microcode_updates) #endif }
-#if CONFIG_CPU_MICROCODE_IN_CBFS - -#define MICROCODE_CBFS_FILE "cpu_microcode_blob.bin" - -void intel_update_microcode_from_cbfs(void) -{ - void *microcode_blob; - -#ifdef __PRE_RAM__ - microcode_blob = walkcbfs((char *) MICROCODE_CBFS_FILE); -#else - microcode_blob = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, - MICROCODE_CBFS_FILE, - CBFS_TYPE_MICROCODE); -#endif - intel_update_microcode(microcode_blob); -} #endif diff --git a/src/include/cpu/intel/microcode.h b/src/include/cpu/intel/microcode.h index e9c13f9..7a291e2 100644 --- a/src/include/cpu/intel/microcode.h +++ b/src/include/cpu/intel/microcode.h @@ -23,6 +23,13 @@ #ifndef __PRE_RAM__ #if CONFIG_CPU_MICROCODE_IN_CBFS void intel_update_microcode_from_cbfs(void); +/* Find a microcode that matches the revision and platform family returning + * NULL if none found. */ +const void *intel_microcode_find(void); +/* It is up to the caller to determine if parallel loading is possible as + * well as ensuring the micrcode matches the family and revision (i.e. with + * intel_microcode_find()). */ +void intel_microcode_load_unlocked(const void *microcode_patch); #else void intel_update_microcode(const void *microcode_updates); #endif