diff options
author | Aaron Durbin <adurbin@chromium.org> | 2013-01-15 15:15:32 -0600 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2013-03-19 05:11:50 +0100 |
commit | 98ffb426f40593f930388c006f8058c199defff4 (patch) | |
tree | 2cf6b6e95ceede3a8c8773f80bb2be48d4046c31 /src | |
parent | 3c734bb355b6cf15e61e3bc8755f622d4117e7c2 (diff) |
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>
Reviewed-on: http://review.coreboot.org/2778
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/cpu/intel/microcode/microcode.c | 128 | ||||
-rw-r--r-- | 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 713a6df19b..d908c25ec0 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 e9c13f978c..7a291e2f27 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 |