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