1 /* $OpenBSD: ucode.c,v 1.6 2023/09/10 09:32:31 jsg Exp $ */
2 /*
3 * Copyright (c) 2018 Stefan Fritsch <fritsch@genua.de>
4 * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/mutex.h>
22 #include <sys/malloc.h>
23
24 #include <uvm/uvm_extern.h>
25
26 #include <machine/cpu.h>
27 #include <machine/cpufunc.h>
28 #include <machine/specialreg.h>
29 #include <machine/biosvar.h>
30
31 /* #define UCODE_DEBUG */
32 #ifdef UCODE_DEBUG
33 #define DPRINTF(x) do { if (cpu_ucode_debug > 0) printf x; } while (0)
34 #define DPRINTFN(n, x) do { if (cpu_ucode_debug >= (n)) printf x; } while (0)
35 int cpu_ucode_debug = 1;
36 #else
37 #define DPRINTF(x) do { ; } while (0)
38 #define DPRINTFN(n, x) do { ; } while (0)
39 #endif
40
41 struct intel_ucode_header {
42 uint32_t header_version;
43 uint32_t update_revision;
44 uint32_t date;
45 uint32_t processor_sig;
46 uint32_t checksum;
47 uint32_t loader_rev;
48 uint32_t processor_flags;
49 uint32_t data_size;
50 uint32_t total_size;
51 uint32_t reserved[3];
52 };
53
54 struct intel_ucode_ext_sig_header {
55 uint32_t ext_sig_count;
56 uint32_t checksum;
57 uint32_t reserved[3];
58 };
59
60 struct intel_ucode_ext_sig {
61 uint32_t processor_sig;
62 uint32_t processor_flags;
63 uint32_t checksum;
64 };
65
66 #define INTEL_UCODE_DEFAULT_DATA_SIZE 2000
67
68 /* Generic */
69 char * cpu_ucode_data;
70 size_t cpu_ucode_size;
71
72 void cpu_ucode_setup(void);
73 void cpu_ucode_apply(struct cpu_info *);
74
75 struct mutex cpu_ucode_mtx = MUTEX_INITIALIZER(IPL_HIGH);
76
77 /* Intel */
78 void cpu_ucode_intel_apply(struct cpu_info *);
79 struct intel_ucode_header *
80 cpu_ucode_intel_find(char *, size_t, uint32_t);
81 int cpu_ucode_intel_verify(struct intel_ucode_header *);
82 int cpu_ucode_intel_match(struct intel_ucode_header *, uint32_t, uint32_t,
83 uint32_t);
84 uint32_t cpu_ucode_intel_rev(void);
85
86 struct intel_ucode_header *cpu_ucode_intel_applied;
87
88 void cpu_ucode_amd_apply(struct cpu_info *);
89
90 void
cpu_ucode_setup(void)91 cpu_ucode_setup(void)
92 {
93 vaddr_t va;
94 paddr_t pa;
95 int i, npages;
96 size_t size;
97
98 if (bios_ucode == NULL)
99 return;
100
101 if (!bios_ucode->uc_addr || !bios_ucode->uc_size)
102 return;
103
104 cpu_ucode_size = bios_ucode->uc_size;
105 size = round_page(bios_ucode->uc_size);
106 npages = size / PAGE_SIZE;
107
108 va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, &kd_nowait);
109 if (va == 0)
110 return;
111 for (i = 0; i < npages; i++) {
112 pa = bios_ucode->uc_addr + (i * PAGE_SIZE);
113 pmap_enter(pmap_kernel(), va + (i * PAGE_SIZE), pa,
114 PROT_READ,
115 PROT_READ | PMAP_WIRED);
116 pmap_update(pmap_kernel());
117 }
118
119 cpu_ucode_data = malloc(cpu_ucode_size, M_DEVBUF, M_WAITOK);
120
121 memcpy((void *)cpu_ucode_data, (void *)va, cpu_ucode_size);
122
123 pmap_remove(pmap_kernel(), va, va + size);
124 pmap_update(pmap_kernel());
125 km_free((void *)va, size, &kv_any, &kp_none);
126 }
127
128 /*
129 * Called per-CPU.
130 */
131 void
cpu_ucode_apply(struct cpu_info * ci)132 cpu_ucode_apply(struct cpu_info *ci)
133 {
134 if (strcmp(cpu_vendor, "GenuineIntel") == 0)
135 cpu_ucode_intel_apply(ci);
136 else if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
137 cpu_ucode_amd_apply(ci);
138 }
139
140 #define AMD_MAGIC 0x00414d44
141
142 struct amd_equiv {
143 uint32_t id;
144 uint32_t a;
145 uint32_t b;
146 uint16_t eid;
147 uint16_t c;
148 } __packed;
149
150 struct amd_patch {
151 uint32_t type;
152 uint32_t len;
153 uint32_t a;
154 uint32_t level;
155 uint8_t c[16];
156 uint16_t eid;
157 } __packed;
158
159 void
cpu_ucode_amd_apply(struct cpu_info * ci)160 cpu_ucode_amd_apply(struct cpu_info *ci)
161 {
162 uint64_t level;
163 uint32_t magic, tlen, i;
164 uint16_t eid = 0;
165 uint32_t sig, ebx, ecx, edx;
166 uint64_t start = 0;
167 uint32_t patch_len = 0;
168
169 if (cpu_ucode_data == NULL || cpu_ucode_size == 0) {
170 DPRINTF(("%s: no microcode provided\n", __func__));
171 return;
172 }
173
174 /*
175 * Grab a mutex, because we are not allowed to run updates
176 * simultaneously on HT siblings.
177 */
178 mtx_enter(&cpu_ucode_mtx);
179
180 CPUID(1, sig, ebx, ecx, edx);
181
182 level = rdmsr(MSR_PATCH_LEVEL);
183 DPRINTF(("%s: cur patch level 0x%llx\n", __func__, level));
184
185 memcpy(&magic, cpu_ucode_data, 4);
186 if (magic != AMD_MAGIC) {
187 DPRINTF(("%s: bad magic %x\n", __func__, magic));
188 goto out;
189 }
190
191 memcpy(&tlen, &cpu_ucode_data[8], 4);
192
193 /* find equivalence id matching our cpu signature */
194 for (i = 12; i < 12 + tlen;) {
195 struct amd_equiv ae;
196 if (i + sizeof(ae) > cpu_ucode_size) {
197 DPRINTF(("%s: truncated etable\n", __func__));
198 goto out;
199 }
200 memcpy(&ae, &cpu_ucode_data[i], sizeof(ae));
201 i += sizeof(ae);
202 if (ae.id == sig)
203 eid = ae.eid;
204 }
205
206 /* look for newer patch with the equivalence id */
207 while (i < cpu_ucode_size) {
208 struct amd_patch ap;
209 if (i + sizeof(ap) > cpu_ucode_size) {
210 DPRINTF(("%s: truncated ptable\n", __func__));
211 goto out;
212 }
213 memcpy(&ap, &cpu_ucode_data[i], sizeof(ap));
214 if (ap.type == 1 && ap.eid == eid && ap.level > level) {
215 start = (uint64_t)&cpu_ucode_data[i + 8];
216 patch_len = ap.len;
217 }
218 if (i + ap.len + 8 > cpu_ucode_size) {
219 DPRINTF(("%s: truncated patch\n", __func__));
220 goto out;
221 }
222 i += ap.len + 8;
223 }
224
225 if (start != 0) {
226 /* alignment required on fam 15h */
227 uint8_t *p = malloc(patch_len, M_TEMP, M_NOWAIT);
228 if (p == NULL)
229 goto out;
230 memcpy(p, (uint8_t *)start, patch_len);
231 start = (uint64_t)p;
232 wrmsr(MSR_PATCH_LOADER, start);
233 level = rdmsr(MSR_PATCH_LEVEL);
234 DPRINTF(("%s: new patch level 0x%llx\n", __func__, level));
235 free(p, M_TEMP, patch_len);
236 }
237 out:
238 mtx_leave(&cpu_ucode_mtx);
239 }
240
241 void
cpu_ucode_intel_apply(struct cpu_info * ci)242 cpu_ucode_intel_apply(struct cpu_info *ci)
243 {
244 struct intel_ucode_header *update;
245 uint32_t old_rev, new_rev;
246 paddr_t data;
247
248 if (cpu_ucode_data == NULL || cpu_ucode_size == 0) {
249 DPRINTF(("%s: no microcode provided\n", __func__));
250 return;
251 }
252
253 /*
254 * Grab a mutex, because we are not allowed to run updates
255 * simultaneously on HT siblings.
256 */
257 mtx_enter(&cpu_ucode_mtx);
258
259 old_rev = cpu_ucode_intel_rev();
260 update = cpu_ucode_intel_applied;
261 if (update == NULL)
262 update = cpu_ucode_intel_find(cpu_ucode_data,
263 cpu_ucode_size, old_rev);
264 if (update == NULL) {
265 DPRINTF(("%s: no microcode update found\n", __func__));
266 goto out;
267 }
268 if (update->update_revision == old_rev) {
269 DPRINTF(("%s: microcode already up-to-date\n", __func__));
270 goto out;
271 }
272
273 /* Apply microcode. */
274 data = (paddr_t)update;
275 data += sizeof(struct intel_ucode_header);
276 wbinvd();
277 wrmsr(MSR_BIOS_UPDT_TRIG, data);
278
279 new_rev = cpu_ucode_intel_rev();
280 if (new_rev != old_rev) {
281 DPRINTF(("%s: microcode updated cpu %ld rev %#x->%#x (%x)\n",
282 __func__, ci->ci_cpuid, old_rev, new_rev, update->date));
283 if (cpu_ucode_intel_applied == NULL)
284 cpu_ucode_intel_applied = update;
285 } else {
286 DPRINTF(("%s: microcode update failed cpu %ld rev %#x->%#x != %#x\n",
287 __func__, ci->ci_cpuid, old_rev, update->update_revision, new_rev));
288 }
289
290 out:
291 mtx_leave(&cpu_ucode_mtx);
292 }
293
294 struct intel_ucode_header *
cpu_ucode_intel_find(char * data,size_t left,uint32_t current)295 cpu_ucode_intel_find(char *data, size_t left, uint32_t current)
296 {
297 uint64_t platform_id = (rdmsr(MSR_PLATFORM_ID) >> 50) & 7;
298 uint32_t sig, dummy1, dummy2, dummy3;
299 uint32_t mask = 1UL << platform_id;
300 struct intel_ucode_header *hdr;
301 uint32_t total_size;
302 int n = 0;
303
304 CPUID(1, sig, dummy1, dummy2, dummy3);
305
306 while (left > 0) {
307 hdr = (struct intel_ucode_header *)data;
308 if (left < sizeof(struct intel_ucode_header)) {
309 DPRINTF(("%s:%d: not enough data for header (%zd)\n",
310 __func__, n, left));
311 break;
312 }
313 /*
314 * Older microcode has an empty length. In that case we
315 * have to use the default length of 2000.
316 */
317 if (hdr->data_size)
318 total_size = hdr->total_size;
319 else
320 total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
321 sizeof(struct intel_ucode_header);
322 if (total_size > left) {
323 DPRINTF(("%s:%d: size %u out of range (%zd)\n",
324 __func__, n, total_size, left));
325 break;
326 }
327 if (cpu_ucode_intel_verify(hdr)) {
328 DPRINTF(("%s:%d: broken data\n", __func__, n));
329 break;
330 }
331 if (cpu_ucode_intel_match(hdr, sig, mask, current))
332 return hdr;
333 n++;
334 left -= total_size;
335 data += total_size;
336 }
337 DPRINTF(("%s: no update found\n", __func__));
338 return NULL;
339 }
340
341 int
cpu_ucode_intel_verify(struct intel_ucode_header * hdr)342 cpu_ucode_intel_verify(struct intel_ucode_header *hdr)
343 {
344 uint32_t *data = (uint32_t *)hdr;
345 size_t total_size;
346 uint32_t sum;
347 int i;
348
349 CTASSERT(sizeof(struct intel_ucode_header) == 48);
350
351 if ((paddr_t)data % 16 != 0) {
352 DPRINTF(("%s: misaligned microcode update\n", __func__));
353 return 1;
354 }
355 if (hdr->loader_rev != 1) {
356 DPRINTF(("%s: unsupported loader rev\n", __func__));
357 return 1;
358 }
359
360 if (hdr->data_size)
361 total_size = hdr->total_size;
362 else
363 total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
364 sizeof(struct intel_ucode_header);
365 if (total_size % 4 != 0) {
366 DPRINTF(("%s: inconsistent size\n", __func__));
367 return 1;
368 }
369
370 sum = 0;
371 for (i = 0; i < total_size / 4; i++)
372 sum += data[i];
373 if (sum != 0) {
374 DPRINTF(("%s: wrong checksum (%#x)\n", __func__, sum));
375 return 1;
376 }
377
378 return 0;
379 }
380
381 int
cpu_ucode_intel_match(struct intel_ucode_header * hdr,uint32_t processor_sig,uint32_t processor_mask,uint32_t ucode_revision)382 cpu_ucode_intel_match(struct intel_ucode_header *hdr,
383 uint32_t processor_sig, uint32_t processor_mask,
384 uint32_t ucode_revision)
385 {
386 struct intel_ucode_ext_sig_header *ehdr;
387 struct intel_ucode_ext_sig *esig;
388 uint32_t data_size, total_size;
389 unsigned i;
390
391 data_size = hdr->data_size;
392 total_size = hdr->total_size;
393
394 /*
395 * Older microcode has an empty length. In that case we
396 * have to use the default length of 2000.
397 */
398 if (!data_size) {
399 data_size = INTEL_UCODE_DEFAULT_DATA_SIZE;
400 total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
401 sizeof(struct intel_ucode_header);
402 }
403
404 if (ucode_revision > hdr->update_revision)
405 return 0;
406 if (hdr->processor_sig == processor_sig &&
407 (hdr->processor_flags & processor_mask))
408 return 1;
409 if (total_size <= sizeof(struct intel_ucode_header) +
410 data_size + sizeof(struct intel_ucode_ext_sig_header))
411 return 0;
412
413 ehdr = (void *)((char *)hdr + sizeof(struct intel_ucode_header) +
414 data_size);
415 esig = (void *)&ehdr[1];
416 for (i = 0; i < ehdr->ext_sig_count; i++) {
417 if (esig[i].processor_sig == processor_sig &&
418 (esig[i].processor_flags & processor_mask))
419 return 1;
420 }
421
422 return 0;
423 }
424
425 uint32_t
cpu_ucode_intel_rev(void)426 cpu_ucode_intel_rev(void)
427 {
428 uint32_t eax, ebx, ecx, edx;
429 uint64_t rev;
430
431 wrmsr(MSR_BIOS_SIGN, 0);
432 CPUID(1, eax, ebx, ecx, edx);
433 rev = rdmsr(MSR_BIOS_SIGN);
434 return rev >> 32;
435 }
436