- Add new cvs code to cvs
[coreboot.git] / src / cpu / intel / microcode / microcode.c
1 /* microcode.c: Microcode update for PIII and later CPUS
2  */
3
4 #include <stdint.h>
5 #include <console/console.h>
6 #include <cpu/cpu.h>
7 #include <cpu/x86/msr.h>
8 #include <cpu/intel/microcode.h>
9
10 struct microcode {
11         uint32_t hdrver;
12         uint32_t rev;
13         uint32_t date;
14         uint32_t sig;
15
16         uint32_t cksum;
17         uint32_t ldrver;
18         uint32_t pf;
19
20         uint32_t data_size;
21         uint32_t total_size;
22
23         uint32_t reserved[3];
24         uint32_t bits[1012];
25 };
26
27
28 static inline uint32_t read_microcode_rev(void)
29 {
30         /* Some Intel Cpus can be very finicky about the
31          * cpuid sequence used.  So this is implemented in
32          * assembly so that it works reliably.
33          */
34         msr_t msr;
35         __asm__ volatile (
36                 "wrmsr\n\t"
37                 "xorl %%eax, %%eax\n\t"
38                 "xorl %%edx, %%edx\n\t"
39                 "movl $0x8b, %%ecx\n\t"
40                 "wrmsr\n\t"
41                 "movl $0x01, %%eax\n\t"
42                 "cpuid\n\t"
43                 "movl $0x08b, %%ecx\n\t"
44                 "rdmsr \n\t"
45                 : /* outputs */
46                 "=a" (msr.lo), "=d" (msr.hi)
47                 : /* inputs */
48                 : /* trashed */
49                  "ecx"
50                 );
51         return msr.hi;
52 }
53
54 void intel_update_microcode(void *microcode_updates)
55 {
56         unsigned int eax;
57         unsigned int pf, rev, sig;
58         unsigned int x86_model, x86_family;
59         struct microcode *m;
60         char *c;
61         msr_t msr;
62         
63         /* cpuid sets msr 0x8B iff a microcode update has been loaded. */
64         msr.lo = 0;
65         msr.hi = 0;
66         wrmsr(0x8B, msr);
67         eax = cpuid_eax(1);
68         msr = rdmsr(0x8B);
69         rev = msr.hi;
70         x86_model = (eax >>4) & 0x0f;
71         x86_family = (eax >>8) & 0x0f;
72         sig = eax;
73
74         pf = 0;
75         if ((x86_model >= 5)||(x86_family>6)) {
76                 msr = rdmsr(0x17);
77                 pf = 1 << ((msr.hi >> 18) & 7);
78         }
79         print_debug("microcode_info: sig = 0x");
80         print_debug_hex32(sig);
81         print_debug(" pf=0x");
82         print_debug_hex32(pf);
83         print_debug(" rev = 0x");
84         print_debug_hex32(rev);
85         print_debug("\r\n");
86
87         m = microcode_updates;
88         for(c = microcode_updates; m->hdrver;  m = (struct microcode *)c) {
89                 if ((m->sig == sig) && (m->pf & pf)) {
90                         unsigned int new_rev;
91                         msr.lo = (unsigned long)(&m->bits) & 0xffffffff;
92                         msr.hi = 0;
93                         wrmsr(0x79, msr);
94
95                         /* Read back the new microcode version */
96                         new_rev = read_microcode_rev();
97
98                         print_debug("microcode updated to revision: ");
99                         print_debug_hex32(new_rev);
100                         print_debug(" from revision ");
101                         print_debug_hex32(rev);
102                         print_debug("\r\n");
103                         break;
104                 }
105                 if (m->total_size) {
106                         c += m->total_size;
107                 } else {
108                         c += 2048;
109                 }
110         }
111 }