coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
microcode.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /* Microcode update for Intel PIII and later CPUs */
4 
5 #include <stdint.h>
6 #include <stddef.h>
7 #include <cbfs.h>
8 #include <arch/cpu.h>
9 #include <console/console.h>
10 #include <cpu/x86/msr.h>
11 #include <cpu/intel/microcode.h>
12 #include <smp/spinlock.h>
13 
14 DECLARE_SPIN_LOCK(microcode_lock)
15 
16 struct microcode {
17  u32 hdrver; /* Header Version */
18  u32 rev; /* Update Revision */
19  u32 date; /* Date */
20  u32 sig; /* Processor Signature */
21 
22  u32 cksum; /* Checksum */
23  u32 ldrver; /* Loader Revision */
24  u32 pf; /* Processor Flags */
25 
26  u32 data_size; /* Data Size */
27  u32 total_size; /* Total Size */
28 
30 };
31 
32 struct ext_sig_table {
35  u32 res[3];
36 };
37 
38 struct ext_sig_entry {
42 };
43 
44 static inline u32 read_microcode_rev(void)
45 {
46  /* Some Intel CPUs can be very finicky about the
47  * CPUID sequence used. So this is implemented in
48  * assembly so that it works reliably.
49  */
50  msr_t msr;
51  asm volatile (
52  "xorl %%eax, %%eax\n\t"
53  "xorl %%edx, %%edx\n\t"
54  "movl $0x8b, %%ecx\n\t"
55  "wrmsr\n\t"
56  "movl $0x01, %%eax\n\t"
57  "cpuid\n\t"
58  "movl $0x08b, %%ecx\n\t"
59  "rdmsr\n\t"
60  : /* outputs */
61  "=a" (msr.lo), "=d" (msr.hi)
62  : /* inputs */
63  : /* trashed */
64  "ebx", "ecx"
65  );
66  return msr.hi;
67 }
68 
69 #define MICROCODE_CBFS_FILE "cpu_microcode_blob.bin"
70 
72 {
73  u32 current_rev;
74  msr_t msr;
75  const struct microcode *m = microcode_patch;
76 
77  if (!m)
78  return;
79 
80  current_rev = read_microcode_rev();
81 
82  /* No use loading the same revision. */
83  if (current_rev == m->rev) {
84  printk(BIOS_INFO, "microcode: Update skipped, already up-to-date\n");
85  return;
86  }
87 
88 #if ENV_RAMSTAGE
89  /*SoC specific check to update microcode*/
90  if (soc_skip_ucode_update(current_rev, m->rev)) {
91  printk(BIOS_DEBUG, "Skip microcode update\n");
92  return;
93  }
94 #endif
95 
96  msr.lo = (unsigned long)m + sizeof(struct microcode);
97  msr.hi = 0;
99 
100  current_rev = read_microcode_rev();
101  if (current_rev == m->rev) {
102  printk(BIOS_INFO, "microcode: updated to revision "
103  "0x%x date=%04x-%02x-%02x\n", read_microcode_rev(),
104  m->date & 0xffff, (m->date >> 24) & 0xff,
105  (m->date >> 16) & 0xff);
106  return;
107  }
108 
109  printk(BIOS_INFO, "microcode: Update failed\n");
110 }
111 
113 {
114  return read_microcode_rev();
115 }
116 
118 {
119  return ((struct microcode *)microcode)->rev;
120 }
121 
123 {
124  return ((struct microcode *)microcode)->total_size;
125 }
126 
128 {
129  return ((struct microcode *)microcode)->cksum;
130 }
131 
132 
133 static struct ext_sig_table *ucode_get_ext_sig_table(const struct microcode *ucode)
134 {
135  struct ext_sig_table *ext_tbl;
136  /* header + ucode data blob size */
137  u32 size = ucode->data_size + sizeof(struct microcode);
138 
139  ssize_t ext_tbl_len = ucode->total_size - size;
140 
141  if (ext_tbl_len < (ssize_t)sizeof(struct ext_sig_table))
142  return NULL;
143 
144  ext_tbl = (struct ext_sig_table *)((uintptr_t)ucode + size);
145 
146  if (ext_tbl_len < (sizeof(struct ext_sig_table) +
147  ext_tbl->ext_sig_cnt * sizeof(struct ext_sig_entry)))
148  return NULL;
149 
150  return ext_tbl;
151 }
152 
153 static const void *find_cbfs_microcode(void)
154 {
155  const struct microcode *ucode_updates;
156  struct ext_sig_table *ext_tbl;
157  size_t microcode_len;
158  u32 eax;
159  u32 pf, rev, sig, update_size;
160  msr_t msr;
161  struct cpuinfo_x86 c;
162 
163  ucode_updates = cbfs_map(MICROCODE_CBFS_FILE, &microcode_len);
164  if (ucode_updates == NULL)
165  return NULL;
166 
167  rev = read_microcode_rev();
168  eax = cpuid_eax(1);
169  get_fms(&c, eax);
170  sig = eax;
171 
172  pf = 0;
173  if ((c.x86_model >= 5) || (c.x86 > 6)) {
174  msr = rdmsr(IA32_PLATFORM_ID);
175  pf = 1 << ((msr.hi >> 18) & 7);
176  }
177 
178  printk(BIOS_DEBUG, "microcode: sig=0x%x pf=0x%x revision=0x%x\n",
179  sig, pf, rev);
180 
181  while (microcode_len >= sizeof(*ucode_updates)) {
182  /* Newer microcode updates include a size field, whereas older
183  * containers set it at 0 and are exactly 2048 bytes long */
184  if (ucode_updates->total_size) {
185  update_size = ucode_updates->total_size;
186  } else {
187  printk(BIOS_SPEW, "Microcode size field is 0\n");
188  update_size = 2048;
189  }
190 
191  /* Checkpoint 1: The microcode update falls within CBFS */
192  if (update_size > microcode_len) {
193  printk(BIOS_WARNING, "Microcode header corrupted!\n");
194  break;
195  }
196 
197  if ((ucode_updates->sig == sig) && (ucode_updates->pf & pf))
198  return ucode_updates;
199 
200 
201  /* Check if there is extended signature table */
202  ext_tbl = ucode_get_ext_sig_table(ucode_updates);
203 
204  if (ext_tbl != NULL) {
205  int i;
206  struct ext_sig_entry *entry = (struct ext_sig_entry *)(ext_tbl + 1);
207 
208  for (i = 0; i < ext_tbl->ext_sig_cnt; i++, entry++) {
209 
210  if ((sig == entry->sig) && (pf & entry->pf)) {
211  return ucode_updates;
212  }
213  }
214  }
215 
216  ucode_updates = (void *)((char *)ucode_updates + update_size);
217  microcode_len -= update_size;
218  }
219 
220  return NULL;
221 }
222 
223 const void *intel_microcode_find(void)
224 {
225  static bool microcode_checked;
226  static const void *ucode_update;
227 
228  if (microcode_checked)
229  return ucode_update;
230 
231  /*
232  * Since this function caches the found microcode (NULL or a valid
233  * microcode pointer), it is expected to be run from BSP before starting
234  * any other APs. This sequence is not multithread safe otherwise.
235  */
236  ucode_update = find_cbfs_microcode();
237  microcode_checked = true;
238 
239  return ucode_update;
240 }
241 
243 {
244  const void *patch = intel_microcode_find();
245 
246  spin_lock(&microcode_lock);
247 
249 
250  spin_unlock(&microcode_lock);
251 }
252 
253 #if ENV_RAMSTAGE
254 __weak int soc_skip_ucode_update(u32 current_patch_id,
255  u32 new_patch_id)
256 {
257  return 0;
258 }
259 #endif
static unsigned int cpuid_eax(unsigned int op)
Definition: cpu.h:79
static void get_fms(struct cpuinfo_x86 *c, uint32_t tfms)
Definition: cpu.h:278
#define DECLARE_SPIN_LOCK(x)
Definition: spinlock.h:18
static void * cbfs_map(const char *name, size_t *size_out)
Definition: cbfs.h:246
#define printk(level,...)
Definition: stdlib.h:16
static const void * microcode_patch
Definition: haswell_init.c:567
static __always_inline msr_t rdmsr(unsigned int index)
Definition: msr.h:146
#define IA32_BIOS_UPDT_TRIG
Definition: msr.h:31
static __always_inline void wrmsr(unsigned int index, msr_t msr)
Definition: msr.h:157
#define IA32_PLATFORM_ID
Definition: msr.h:18
#define spin_lock(lock)
Definition: spinlock.h:11
#define spin_unlock(lock)
Definition: spinlock.h:12
int soc_skip_ucode_update(u32 current_patch_id, u32 new_patch_id)
Definition: cpu.c:206
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_SPEW
BIOS_SPEW - Excessively verbose output.
Definition: loglevel.h:142
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
static const void * find_cbfs_microcode(void)
Definition: microcode.c:153
void intel_microcode_load_unlocked(const void *microcode_patch)
Definition: microcode.c:71
static u32 read_microcode_rev(void)
Definition: microcode.c:44
uint32_t get_microcode_size(const void *microcode)
Definition: microcode.c:122
uint32_t get_microcode_checksum(const void *microcode)
Definition: microcode.c:127
#define MICROCODE_CBFS_FILE
Definition: microcode.c:69
uint32_t get_microcode_rev(const void *microcode)
Definition: microcode.c:117
void intel_update_microcode_from_cbfs(void)
Definition: microcode.c:242
uint32_t get_current_microcode_rev(void)
Definition: microcode.c:112
const void * intel_microcode_find(void)
Definition: microcode.c:223
static struct ext_sig_table * ucode_get_ext_sig_table(const struct microcode *ucode)
Definition: microcode.c:133
const struct smm_save_state_ops *legacy_ops __weak
Definition: save_state.c:8
#define NULL
Definition: stddef.h:19
__SIZE_TYPE__ ssize_t
Definition: stddef.h:13
unsigned int uint32_t
Definition: stdint.h:14
uint32_t u32
Definition: stdint.h:51
unsigned long uintptr_t
Definition: stdint.h:21
Definition: microcode.c:38
u32 pf
Definition: microcode.c:40
u32 chksm
Definition: microcode.c:41
u32 sig
Definition: microcode.c:39
u32 res[3]
Definition: microcode.c:35
u32 ext_tbl_chksm
Definition: microcode.c:34
u32 ext_sig_cnt
Definition: microcode.c:33
u32 sig
Definition: microcode.c:20
u32 date
Definition: microcode.c:19
u32 pf
Definition: microcode.c:24
u32 hdrver
Definition: microcode.c:17
u32 rev
Definition: microcode.c:18
u32 ldrver
Definition: microcode.c:23
u32 total_size
Definition: microcode.c:27
u32 reserved[3]
Definition: microcode.c:29
u32 data_size
Definition: microcode.c:26
u32 cksum
Definition: microcode.c:22
unsigned int hi
Definition: msr.h:112
unsigned int lo
Definition: msr.h:111
#define m(clkreg, src_bits, pmcreg, dst_bits)
#define c(value, pmcreg, dst_bits)