diff options
Diffstat (limited to 'src/cpu')
-rw-r--r-- | src/cpu/intel/microcode/microcode.c | 128 |
1 files changed, 110 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 |