diff options
author | Eric Biederman <ebiederm@xmission.com> | 2004-10-14 19:29:29 +0000 |
---|---|---|
committer | Eric Biederman <ebiederm@xmission.com> | 2004-10-14 19:29:29 +0000 |
commit | fcd5ace00b333ce31b11b02a2243dfbf39307f10 (patch) | |
tree | d686d752ccea9b185b0008c70d8523749b26e2dd /src/cpu/intel/microcode | |
parent | 98e619b1cefcb9871185f4cc3db85fa430dcdbce (diff) | |
download | coreboot-fcd5ace00b333ce31b11b02a2243dfbf39307f10.tar.xz |
- Add new cvs code to cvs
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1657 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/cpu/intel/microcode')
-rw-r--r-- | src/cpu/intel/microcode/Config.lb | 1 | ||||
-rw-r--r-- | src/cpu/intel/microcode/microcode.c | 111 |
2 files changed, 112 insertions, 0 deletions
diff --git a/src/cpu/intel/microcode/Config.lb b/src/cpu/intel/microcode/Config.lb new file mode 100644 index 0000000000..f19d210a58 --- /dev/null +++ b/src/cpu/intel/microcode/Config.lb @@ -0,0 +1 @@ +object microcode.o
\ No newline at end of file diff --git a/src/cpu/intel/microcode/microcode.c b/src/cpu/intel/microcode/microcode.c new file mode 100644 index 0000000000..38739babe6 --- /dev/null +++ b/src/cpu/intel/microcode/microcode.c @@ -0,0 +1,111 @@ +/* microcode.c: Microcode update for PIII and later CPUS + */ + +#include <stdint.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <cpu/x86/msr.h> +#include <cpu/intel/microcode.h> + +struct microcode { + uint32_t hdrver; + uint32_t rev; + uint32_t date; + uint32_t sig; + + uint32_t cksum; + uint32_t ldrver; + uint32_t pf; + + uint32_t data_size; + uint32_t total_size; + + uint32_t reserved[3]; + uint32_t bits[1012]; +}; + + +static inline uint32_t read_microcode_rev(void) +{ + /* Some Intel Cpus can be very finicky about the + * cpuid sequence used. So this is implemented in + * assembly so that it works reliably. + */ + msr_t msr; + __asm__ volatile ( + "wrmsr\n\t" + "xorl %%eax, %%eax\n\t" + "xorl %%edx, %%edx\n\t" + "movl $0x8b, %%ecx\n\t" + "wrmsr\n\t" + "movl $0x01, %%eax\n\t" + "cpuid\n\t" + "movl $0x08b, %%ecx\n\t" + "rdmsr \n\t" + : /* outputs */ + "=a" (msr.lo), "=d" (msr.hi) + : /* inputs */ + : /* trashed */ + "ecx" + ); + return msr.hi; +} + +void intel_update_microcode(void *microcode_updates) +{ + unsigned int eax; + unsigned int pf, rev, sig; + unsigned int x86_model, x86_family; + struct microcode *m; + char *c; + msr_t msr; + + /* 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); + } + print_debug("microcode_info: sig = 0x"); + print_debug_hex32(sig); + print_debug(" pf=0x"); + print_debug_hex32(pf); + print_debug(" rev = 0x"); + print_debug_hex32(rev); + print_debug("\r\n"); + + m = microcode_updates; + for(c = microcode_updates; m->hdrver; m = (struct microcode *)c) { + if ((m->sig == sig) && (m->pf & pf)) { + unsigned int new_rev; + msr.lo = (unsigned long)(&m->bits) & 0xffffffff; + msr.hi = 0; + wrmsr(0x79, msr); + + /* Read back the new microcode version */ + new_rev = read_microcode_rev(); + + print_debug("microcode updated to revision: "); + print_debug_hex32(new_rev); + print_debug(" from revision "); + print_debug_hex32(rev); + print_debug("\r\n"); + break; + } + if (m->total_size) { + c += m->total_size; + } else { + c += 2048; + } + } +} |