iPXE
ucode.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26/** @file
27 *
28 * Microcode updates
29 *
30 */
31
32#include <stdlib.h>
33#include <stdio.h>
34#include <string.h>
35#include <assert.h>
36#include <errno.h>
37#include <ipxe/uaccess.h>
38#include <ipxe/umalloc.h>
39#include <ipxe/image.h>
40#include <ipxe/cpuid.h>
41#include <ipxe/msr.h>
42#include <ipxe/mp.h>
43#include <ipxe/timer.h>
44#include <ipxe/ucode.h>
45
46/**
47 * Maximum number of hyperthread siblings
48 *
49 * Microcode updates must not be performed on hyperthread siblings at
50 * the same time, since they share microcode storage.
51 *
52 * Hyperthread siblings are always the lowest level of the CPU
53 * topology and correspond to the least significant bits of the APIC
54 * ID. We may therefore avoid collisions by performing the microcode
55 * updates in batches, with each batch targeting just one value for
56 * the least significant N bits of the APIC ID.
57 *
58 * We assume that no CPUs exist with more than this number of
59 * hyperthread siblings. (This must be a power of two.)
60 */
61#define UCODE_MAX_HT 8
62
63/** Time to wait for a microcode update to complete */
64#define UCODE_WAIT_MS 10
65
66/** A CPU vendor string */
68 /** CPUID registers */
70 /** Human-readable string */
71 uint8_t string[12];
72};
73
74/** A CPU vendor */
76 /** Vendor string */
78 /** Microcode load trigger MSR */
80 /** Microcode version requires manual clear */
82 /** Microcode version is reported via high dword */
84};
85
86/** A microcode update */
88 /** CPU vendor, if known */
90 /** Boot processor CPU signature */
92 /** Platform ID */
94 /** Number of potentially relevant signatures found */
95 unsigned int count;
96 /** Update descriptors (if being populated) */
98};
99
100/** A microcode update summary */
102 /** Number of CPUs processed */
103 unsigned int count;
104 /** Lowest observed microcode version */
106 /** Highest observed microcode version */
108};
109
110/** Intel CPU vendor */
111static struct ucode_vendor ucode_intel = {
112 .id = { .string = "GenuineIntel" },
113 .ver_clear = 1,
114 .ver_high = 1,
115 .trigger_msr = MSR_UCODE_TRIGGER_INTEL,
116};
117
118/** AMD CPU vendor */
119static struct ucode_vendor ucode_amd = {
120 .id = { .string = "AuthenticAMD" },
121 .trigger_msr = MSR_UCODE_TRIGGER_AMD,
122};
123
124/** List of known CPU vendors */
125static struct ucode_vendor *ucode_vendors[] = {
127 &ucode_amd,
128};
129
130/**
131 * Get CPU vendor name (for debugging)
132 *
133 * @v vendor CPU vendor
134 * @ret name Name
135 */
136static const char * ucode_vendor_name ( const union ucode_vendor_id *vendor ) {
137 static union {
139 char text[ sizeof ( *vendor ) + 1 /* NUL */ ];
140 } u;
141
142 /* Construct name */
143 memcpy ( &u.vendor, vendor, sizeof ( u.vendor ) );
144 u.text[ sizeof ( u.text ) - 1 ] = '\0';
145 return u.text;
146}
147
148/**
149 * Check status report
150 *
151 * @v update Microcode update
152 * @v control Microcode update control
153 * @v status Microcode update status
154 * @v summary Microcode update summary
155 * @v id APIC ID
156 * @v optional Status report is optional
157 * @ret rc Return status code
158 */
159static int ucode_status ( const struct ucode_update *update,
160 const struct ucode_control *control,
161 const struct ucode_status *status,
162 struct ucode_summary *summary,
163 unsigned int id, int optional ) {
164 struct ucode_descriptor *desc;
165
166 /* Sanity check */
168
169 /* Ignore empty optional status reports */
170 if ( optional && ( ! status->signature ) )
171 return 0;
172 DBGC ( update, "UCODE %#08x signature %#08x ucode %#08x->%#08x\n",
173 id, status->signature, status->before, status->after );
174
175 /* Check CPU signature */
176 if ( ! status->signature ) {
177 DBGC2 ( update, "UCODE %#08x has no signature\n", id );
178 return -ENOENT;
179 }
180
181 /* Check APIC ID is correct */
182 if ( status->id != id ) {
183 DBGC ( update, "UCODE %#08x wrong APIC ID %#08x\n",
184 id, status->id );
185 return -EINVAL;
186 }
187
188 /* Check that maximum APIC ID was not exceeded */
189 if ( control->apic_unexpected ) {
190 DBGC ( update, "UCODE %#08x saw unexpected APIC ID %#08x\n",
191 id, control->apic_unexpected );
192 return -ERANGE;
193 }
194
195 /* Check microcode was not downgraded */
196 if ( status->after < status->before ) {
197 DBGC ( update, "UCODE %#08x was downgraded %#08x->%#08x\n",
198 id, status->before, status->after );
199 return -ENOTTY;
200 }
201
202 /* Check that expected updates (if any) were applied */
203 for ( desc = update->desc ; desc->signature ; desc++ ) {
204 if ( ( desc->signature == status->signature ) &&
205 ( status->after < desc->version ) ) {
206 DBGC ( update, "UCODE %#08x failed update %#08x->%#08x "
207 "(wanted %#08x)\n", id, status->before,
208 status->after, desc->version );
209 return -EIO;
210 }
211 }
212
213 /* Update summary */
214 summary->count++;
215 if ( status->before < summary->low )
216 summary->low = status->before;
217 if ( status->after > summary->high )
218 summary->high = status->after;
219
220 return 0;
221}
222
223/**
224 * Update microcode on all CPUs
225 *
226 * @v image Microcode image
227 * @v update Microcode update
228 * @v summary Microcode update summary to fill in
229 * @ret rc Return status code
230 */
231static int ucode_update_all ( struct image *image,
232 const struct ucode_update *update,
233 struct ucode_summary *summary ) {
234 struct ucode_control control;
235 struct ucode_vendor *vendor;
236 struct ucode_status *status;
237 unsigned int max;
238 unsigned int id;
239 size_t len;
240 int rc;
241
242 /* Initialise summary */
243 summary->count = 0;
244 summary->low = UCODE_VERSION_MAX;
245 summary->high = UCODE_VERSION_MIN;
246
247 /* Allocate status reports */
248 max = mp_max_cpuid();
249 len = ( ( max + 1 ) * sizeof ( *status ) );
250 status = umalloc ( len );
251 if ( ! status ) {
252 DBGC ( image, "UCODE %s could not allocate %d status reports\n",
253 image->name, ( max + 1 ) );
254 rc = -ENOMEM;
255 goto err_alloc;
256 }
257 memset ( status, 0, len );
258
259 /* Construct control structure */
260 memset ( &control, 0, sizeof ( control ) );
261 control.desc = virt_to_phys ( update->desc );
262 control.status = virt_to_phys ( status );
263 vendor = update->vendor;
264 if ( vendor ) {
265 control.ver_clear = vendor->ver_clear;
266 control.ver_high = vendor->ver_high;
267 control.trigger_msr = vendor->trigger_msr;
268 } else {
269 assert ( update->count == 0 );
270 }
271 control.apic_max = max;
272
273 /* Update microcode on boot processor */
275 id = mp_boot_cpuid();
276 if ( ( rc = ucode_status ( update, &control, &status[id],
277 summary, id, 0 ) ) != 0 ) {
278 DBGC ( image, "UCODE %s failed on boot processor: %s\n",
279 image->name, strerror ( rc ) );
280 goto err_boot;
281 }
282
283 /* Update microcode on application processors, avoiding
284 * simultaneous updates on hyperthread siblings.
285 */
286 build_assert ( ( UCODE_MAX_HT & ( UCODE_MAX_HT - 1 ) ) == 0 );
287 control.apic_mask = ( UCODE_MAX_HT - 1 );
288 for ( ; control.apic_test <= control.apic_mask ; control.apic_test++ ) {
291 }
292
293 /* Check status reports */
294 summary->count = 0;
295 for ( id = 0 ; id <= max ; id++ ) {
296 if ( ( rc = ucode_status ( update, &control, &status[id],
297 summary, id, 1 ) ) != 0 ) {
298 goto err_status;
299 }
300 }
301
302 /* Success */
303 rc = 0;
304
305 err_status:
306 err_boot:
307 ufree ( status );
308 err_alloc:
309 return rc;
310}
311
312/**
313 * Add descriptor to list (if applicable)
314 *
315 * @v image Microcode image
316 * @v start Starting offset within image
317 * @v vendor CPU vendor
318 * @v desc Microcode descriptor
319 * @v platforms Supported platforms, or 0 for all platforms
320 * @v update Microcode update
321 */
322static void ucode_describe ( struct image *image, size_t start,
323 const struct ucode_vendor *vendor,
324 const struct ucode_descriptor *desc,
325 uint32_t platforms, struct ucode_update *update ) {
326
327 /* Dump descriptor information */
328 DBGC2 ( image, "UCODE %s+%#04zx %s %#08x", image->name, start,
329 ucode_vendor_name ( &vendor->id ), desc->signature );
330 if ( platforms )
331 DBGC2 ( image, " (%#02x)", platforms );
332 DBGC2 ( image, " version %#08x\n", desc->version );
333
334 /* Check applicability */
335 if ( vendor != update->vendor )
336 return;
337 if ( ( desc->signature ^ update->signature ) & UCODE_SIGNATURE_MASK )
338 return;
339 if ( platforms && ( ! ( platforms & update->platform ) ) )
340 return;
341
342 /* Add descriptor, if applicable */
343 if ( update->desc ) {
344 memcpy ( &update->desc[update->count], desc, sizeof ( *desc ) );
345 DBGC ( image, "UCODE %s+%#04zx found %s %#08x version %#08x\n",
347 desc->signature, desc->version );
348 }
349 update->count++;
350}
351
352/**
353 * Verify checksum
354 *
355 * @v image Microcode image
356 * @v start Starting offset
357 * @v len Length
358 * @ret rc Return status code
359 */
360static int ucode_verify ( struct image *image, size_t start, size_t len ) {
361 const uint32_t *dword;
363 unsigned int count;
364
365 /* Check length is a multiple of dwords */
366 if ( ( len % sizeof ( *dword ) ) != 0 ) {
367 DBGC ( image, "UCODE %s+%#04zx invalid length %#zx\n",
368 image->name, start, len );
369 return -EINVAL;
370 }
371 dword = ( image->data + start );
372
373 /* Calculate checksum */
374 count = ( len / sizeof ( *dword ) );
375 for ( checksum = 0 ; count ; count-- )
376 checksum += *(dword++);
377 if ( checksum != 0 ) {
378 DBGC ( image, "UCODE %s+%#04zx bad checksum %#08x\n",
380 return -EINVAL;
381 }
382
383 return 0;
384}
385
386/**
387 * Parse Intel microcode image
388 *
389 * @v image Microcode image
390 * @v start Starting offset within image
391 * @v update Microcode update
392 * @ret len Length consumed, or negative error
393 */
394static int ucode_parse_intel ( struct image *image, size_t start,
395 struct ucode_update *update ) {
396 const struct intel_ucode_header *hdr;
397 const struct intel_ucode_ext_header *exthdr;
398 const struct intel_ucode_ext *ext;
399 struct ucode_descriptor desc;
400 size_t remaining;
401 size_t offset;
402 size_t data_len;
403 size_t len;
404 unsigned int i;
405 int rc;
406
407 /* Read header */
408 remaining = ( image->len - start );
409 if ( remaining < sizeof ( *hdr ) ) {
410 DBGC ( image, "UCODE %s+%#04zx too small for Intel header\n",
411 image->name, start );
412 return -ENOEXEC;
413 }
414 hdr = ( image->data + start );
415
416 /* Determine lengths */
417 data_len = hdr->data_len;
418 if ( ! data_len )
420 len = hdr->len;
421 if ( ! len )
422 len = ( sizeof ( *hdr ) + data_len );
423
424 /* Verify a selection of fields */
425 if ( ( hdr->hver != INTEL_UCODE_HVER ) ||
426 ( hdr->lver != INTEL_UCODE_LVER ) ||
427 ( len < sizeof ( *hdr ) ) ||
428 ( len > remaining ) ||
429 ( data_len > ( len - sizeof ( *hdr ) ) ) ||
430 ( ( data_len % sizeof ( uint32_t ) ) != 0 ) ||
431 ( ( len % INTEL_UCODE_ALIGN ) != 0 ) ) {
432 DBGC2 ( image, "UCODE %s+%#04zx is not an Intel update\n",
433 image->name, start );
434 return -EINVAL;
435 }
436 DBGC2 ( image, "UCODE %s+%#04zx is an Intel update\n",
437 image->name, start );
438
439 /* Verify checksum */
440 if ( ( rc = ucode_verify ( image, start, len ) ) != 0 )
441 return rc;
442
443 /* Populate descriptor */
444 desc.signature = hdr->signature;
445 desc.version = hdr->version;
446 desc.address = ( virt_to_phys ( image->data ) + start +
447 sizeof ( *hdr ) );
448
449 /* Add non-extended descriptor, if applicable */
450 ucode_describe ( image, start, &ucode_intel, &desc, hdr->platforms,
451 update );
452
453 /* Construct extended descriptors, if applicable */
454 offset = ( sizeof ( *hdr ) + data_len );
455 if ( offset <= ( len - sizeof ( *exthdr ) ) ) {
456
457 /* Read extended header */
458 exthdr = ( image->data + start + offset );
459 offset += sizeof ( *exthdr );
460
461 /* Read extended signatures */
462 for ( i = 0 ; i < exthdr->count ; i++ ) {
463
464 /* Read extended signature */
465 if ( offset > ( len - sizeof ( *ext ) ) ) {
466 DBGC ( image, "UCODE %s+%#04zx extended "
467 "signature overrun\n",
468 image->name, start );
469 return -EINVAL;
470 }
471 ext = ( image->data + start + offset );
472 offset += sizeof ( *ext );
473
474 /* Avoid duplicating non-extended descriptor */
475 if ( ( ext->signature == hdr->signature ) &&
476 ( ext->platforms == hdr->platforms ) ) {
477 continue;
478 }
479
480 /* Construct descriptor, if applicable */
481 desc.signature = ext->signature;
483 ext->platforms, update );
484 }
485 }
486
487 return len;
488}
489
490/**
491 * Parse AMD microcode image
492 *
493 * @v image Microcode image
494 * @v start Starting offset within image
495 * @v update Microcode update
496 * @ret len Length consumed, or negative error
497 */
498static int ucode_parse_amd ( struct image *image, size_t start,
499 struct ucode_update *update ) {
500 const struct amd_ucode_header *hdr;
501 const struct amd_ucode_equivalence *equiv;
502 const struct amd_ucode_patch_header *phdr;
503 const struct amd_ucode_patch *patch;
504 struct ucode_descriptor desc;
505 size_t remaining;
506 size_t offset;
507 unsigned int count;
508 unsigned int used;
509 unsigned int i;
510
511 /* Read header */
512 remaining = ( image->len - start );
513 if ( remaining < sizeof ( *hdr ) ) {
514 DBGC ( image, "UCODE %s+%#04zx too small for AMD header\n",
515 image->name, start );
516 return -ENOEXEC;
517 }
518 hdr = ( image->data + start );
519
520 /* Check header */
521 if ( hdr->magic != AMD_UCODE_MAGIC ) {
522 DBGC2 ( image, "UCODE %s+%#04zx is not an AMD update\n",
523 image->name, start );
524 return -ENOEXEC;
525 }
526 DBGC2 ( image, "UCODE %s+%#04zx is an AMD update\n",
527 image->name, start );
528 if ( hdr->type != AMD_UCODE_EQUIV_TYPE ) {
529 DBGC ( image, "UCODE %s+%#04zx unsupported equivalence table "
530 "type %d\n", image->name, start, hdr->type );
531 return -ENOTSUP;
532 }
533 if ( hdr->len > ( remaining - sizeof ( *hdr ) ) ) {
534 DBGC ( image, "UCODE %s+%#04zx truncated equivalence table\n",
535 image->name, start );
536 return -EINVAL;
537 }
538
539 /* Count number of equivalence table entries */
540 offset = sizeof ( *hdr );
541 equiv = ( image->data + start + offset );
542 for ( count = 0 ; offset < ( sizeof ( *hdr ) + hdr->len ) ;
543 count++, offset += sizeof ( *equiv ) ) {
544 if ( ! equiv[count].signature )
545 break;
546 }
547 DBGC2 ( image, "UCODE %s+%#04zx has %d equivalence table entries\n",
548 image->name, start, count );
549
550 /* Parse available updates */
551 offset = ( sizeof ( *hdr ) + hdr->len );
552 used = 0;
553 while ( used < count ) {
554
555 /* Read patch header */
556 if ( ( offset + sizeof ( *phdr ) ) > remaining ) {
557 DBGC ( image, "UCODE %s+%#04zx truncated patch "
558 "header\n", image->name, start );
559 return -EINVAL;
560 }
561 phdr = ( image->data + start + offset );
562 offset += sizeof ( *phdr );
563
564 /* Validate patch header */
565 if ( phdr->type != AMD_UCODE_PATCH_TYPE ) {
566 DBGC ( image, "UCODE %s+%#04zx unsupported patch type "
567 "%d\n", image->name, start, phdr->type );
568 return -ENOTSUP;
569 }
570 if ( phdr->len < sizeof ( *patch ) ) {
571 DBGC ( image, "UCODE %s+%#04zx underlength patch\n",
572 image->name, start );
573 return -EINVAL;
574 }
575 if ( phdr->len > ( remaining - offset ) ) {
576 DBGC ( image, "UCODE %s+%#04zx truncated patch\n",
577 image->name, start );
578 return -EINVAL;
579 }
580
581 /* Read patch and construct descriptor */
582 patch = ( image->data + start + offset );
583 desc.version = patch->version;
584 desc.address = ( virt_to_phys ( image->data ) +
585 start + offset );
586 offset += phdr->len;
587
588 /* Parse equivalence table to find matching signatures */
589 for ( i = 0 ; i < count ; i++ ) {
590 if ( patch->id == equiv[i].id ) {
591 desc.signature = equiv[i].signature;
593 &desc, 0, update );
594 used++;
595 }
596 }
597 }
598
599 return offset;
600}
601
602/**
603 * Parse microcode image
604 *
605 * @v image Microcode image
606 * @v update Microcode update
607 * @ret rc Return status code
608 */
609static int ucode_parse ( struct image *image, struct ucode_update *update ) {
610 size_t start;
611 int len;
612
613 /* Attempt to parse concatenated microcode updates */
614 for ( start = 0 ; start < image->len ; start += len ) {
615
616 /* Attempt to parse as Intel microcode */
617 len = ucode_parse_intel ( image, start, update );
618 if ( len > 0 )
619 continue;
620
621 /* Attempt to parse as AMD microcode */
622 len = ucode_parse_amd ( image, start, update );
623 if ( len > 0 )
624 continue;
625
626 /* Not a recognised microcode format */
627 DBGC ( image, "UCODE %s+%zx not recognised\n",
628 image->name, start );
629 return -ENOEXEC;
630 }
631
632 return 0;
633}
634
635/**
636 * Execute microcode update
637 *
638 * @v image Microcode image
639 * @ret rc Return status code
640 */
641static int ucode_exec ( struct image *image ) {
642 struct ucode_update update;
643 struct ucode_vendor *vendor;
644 struct ucode_summary summary;
645 union ucode_vendor_id id;
647 uint32_t discard_a;
648 uint32_t discard_b;
650 uint32_t discard_d;
651 unsigned int check;
652 unsigned int i;
653 size_t len;
654 int rc;
655
656 /* Initialise update */
657 memset ( &update, 0, sizeof ( update ) );
658 cpuid ( CPUID_VENDOR_ID, 0, &discard_a, &id.dword[0], &id.dword[2],
659 &id.dword[1] );
660 cpuid ( CPUID_FEATURES, 0, &update.signature, &discard_b,
661 &discard_c, &discard_d );
662
663 /* Identify CPU vendor, if recognised */
664 for ( i = 0 ; i < ( sizeof ( ucode_vendors ) /
665 sizeof ( ucode_vendors[0] ) ) ; i++ ) {
667 if ( memcmp ( &id, &vendor->id, sizeof ( id ) ) == 0 )
668 update.vendor = vendor;
669 }
670
671 /* Identify platform, if applicable */
672 if ( update.vendor == &ucode_intel ) {
673 platform_id = rdmsr ( MSR_PLATFORM_ID );
674 update.platform =
676 }
677
678 /* Count number of matching update descriptors */
679 DBGC ( image, "UCODE %s applying to %s %#08x",
680 image->name, ucode_vendor_name ( &id ), update.signature );
681 if ( update.platform )
682 DBGC ( image, " (%#02x)", update.platform );
683 DBGC ( image, "\n" );
684 if ( ( rc = ucode_parse ( image, &update ) ) != 0 )
685 goto err_count;
686 DBGC ( image, "UCODE %s found %d matching update(s)\n",
687 image->name, update.count );
688
689 /* Allocate descriptors */
690 len = ( ( update.count + 1 /* terminator */ ) *
691 sizeof ( update.desc[0] ) );
692 update.desc = zalloc ( len );
693 if ( ! update.desc ) {
694 rc = -ENOMEM;
695 goto err_alloc;
696 }
697
698 /* Populate descriptors */
699 check = update.count;
700 update.count = 0;
701 if ( ( rc = ucode_parse ( image, &update ) ) != 0 )
702 goto err_parse;
703 assert ( check == update.count );
704
705 /* Perform update */
706 if ( ( rc = ucode_update_all ( image, &update, &summary ) ) != 0 )
707 goto err_update;
708
709 /* Print summary if directed to do so */
710 if ( image->cmdline && ( strstr ( image->cmdline, "-v" ) ) ) {
711 printf ( "Microcode: " );
712 if ( summary.low == summary.high ) {
713 printf ( "already version %#x", summary.low );
714 } else {
715 printf ( "updated version %#x->%#x",
716 summary.low, summary.high );
717 }
718 printf ( " (x%d)\n", summary.count );
719 }
720
721 err_update:
722 err_parse:
723 free ( update.desc );
724 err_alloc:
725 err_count:
726 return rc;
727}
728
729/**
730 * Probe microcode update image
731 *
732 * @v image Microcode image
733 * @ret rc Return status code
734 */
735static int ucode_probe ( struct image *image ) {
736 const union {
737 struct intel_ucode_header intel;
738 struct amd_ucode_header amd;
739 } *header;
740
741 /* Sanity check */
742 if ( image->len < sizeof ( *header ) ) {
743 DBGC ( image, "UCODE %s too short\n", image->name );
744 return -ENOEXEC;
745 }
746
747 /* Read first microcode image header */
748 header = image->data;
749
750 /* Check for something that looks like an Intel update
751 *
752 * Intel updates unfortunately have no magic signatures or
753 * other easily verifiable fields. We check a small selection
754 * of header fields that can be easily verified.
755 *
756 * We do not attempt to fully parse the update, since we want
757 * errors to be reported at the point of attempting to execute
758 * the image, and do not want to have a microcode image
759 * erroneously treated as a PXE boot executable.
760 */
761 if ( ( header->intel.hver == INTEL_UCODE_HVER ) &&
762 ( header->intel.lver == INTEL_UCODE_LVER ) &&
763 ( ( header->intel.date.century == 0x19 ) ||
764 ( ( header->intel.date.century >= 0x20 ) &&
765 ( header->intel.date.century <= 0x29 ) ) ) ) {
766 DBGC ( image, "UCODE %s+%#04zx looks like an Intel update\n",
767 image->name, ( ( size_t ) 0 ) );
768 return 0;
769 }
770
771 /* Check for AMD update signature */
772 if ( ( header->amd.magic == AMD_UCODE_MAGIC ) &&
773 ( header->amd.type == AMD_UCODE_EQUIV_TYPE ) ) {
774 DBGC ( image, "UCODE %s+%#04zx looks like an AMD update\n",
775 image->name, ( ( size_t ) 0 ) );
776 return 0;
777 }
778
779 return -ENOEXEC;
780}
781
782/** Microcode update image type */
783struct image_type ucode_image_type __image_type ( PROBE_NORMAL ) = {
784 .name = "ucode",
785 .probe = ucode_probe,
786 .exec = ucode_exec,
787};
struct golan_inbox_hdr hdr
Message header.
Definition CIB_PRM.h:0
u8 signature
CPU signature.
Definition CIB_PRM.h:7
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned int uint32_t
Definition stdint.h:12
unsigned long long uint64_t
Definition stdint.h:13
signed int int32_t
Definition stdint.h:17
unsigned char uint8_t
Definition stdint.h:10
long discard_c
Definition bigint.h:33
Assertions.
#define build_assert(condition)
Assert a condition at build time (after dead code elimination)
Definition assert.h:77
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
#define max(x, y)
Definition ath.h:41
uint16_t offset
Offset to command line.
Definition bzimage.h:3
x86 CPU feature detection
#define CPUID_FEATURES
Get standard features.
Definition cpuid.h:44
#define CPUID_VENDOR_ID
Get vendor ID and largest standard function.
Definition cpuid.h:41
static unsigned short vendor
Definition davicom.c:128
union @104331263140136355135267063077374276003064103115 u
ring len
Length.
Definition dwmac.h:226
uint8_t platform_id
Platform ID.
Definition eltorito.h:8
uint8_t id
Request identifier.
Definition ena.h:1
uint16_t ext
Extended status.
Definition ena.h:9
struct ena_llq_option header
Header locations.
Definition ena.h:5
uint8_t status
Status.
Definition ena.h:5
struct ena_llq_option desc
Descriptor counts.
Definition ena.h:9
Error codes.
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
uint32_t start
Starting offset.
Definition netvsc.h:1
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOEXEC
Exec format error.
Definition errno.h:520
#define ENOMEM
Not enough space.
Definition errno.h:535
#define EIO
Input/output error.
Definition errno.h:434
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ERANGE
Result too large.
Definition errno.h:640
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:595
Executable images.
#define PROBE_NORMAL
Normal image probe priority.
Definition image.h:156
#define __image_type(probe_order)
An executable image type.
Definition image.h:170
Multiprocessor functions.
void mp_exec_boot(mp_func_t func, void *opaque)
Execute a multiprocessor function on the boot processor.
void mp_start_all(mp_func_t func, void *opaque)
Start a multiprocessor function on all application processors.
iPXE timers
User memory allocation.
static __always_inline void * umalloc(size_t size)
Allocate external memory.
Definition umalloc.h:57
static __always_inline void ufree(void *ptr)
Free external memory.
Definition umalloc.h:68
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
Access to external ("user") memory.
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
unsigned int mp_boot_cpuid(void)
Get boot CPU identifier.
Definition mp.c:43
unsigned int mp_max_cpuid(void)
Get maximum CPU identifier.
Definition mp.c:58
Model-specific registers.
uint32_t control
Control.
Definition myson.h:3
uint8_t checksum
Checksum.
Definition pnpbios.c:12
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
unsigned long int dword
Definition smc9000.h:40
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
char * strstr(const char *haystack, const char *needle)
Find substring.
Definition string.c:310
An AMD microcode equivalence table entry.
Definition ucode.h:185
uint32_t signature
CPU signature.
Definition ucode.h:187
uint16_t id
Equivalence ID.
Definition ucode.h:191
An AMD microcode update file header.
Definition ucode.h:169
An AMD microcode patch header.
Definition ucode.h:197
uint32_t type
Patch type.
Definition ucode.h:199
uint32_t len
Patch length.
Definition ucode.h:201
An AMD microcode patch.
Definition ucode.h:205
int32_t version
Microcode version.
Definition ucode.h:209
uint16_t id
Equivalence ID.
Definition ucode.h:213
An executable image type.
Definition image.h:95
An executable image.
Definition image.h:24
const void * data
Read-only data.
Definition image.h:51
char * name
Name.
Definition image.h:38
size_t len
Length of raw file image.
Definition image.h:56
char * cmdline
Command line to pass to image.
Definition image.h:43
An Intel microcode update file extended header.
Definition ucode.h:149
uint32_t count
Extended signature count.
Definition ucode.h:151
An Intel microcode extended signature.
Definition ucode.h:159
An Intel microcode update file header.
Definition ucode.h:113
A microcode update control.
Definition ucode.h:45
A microcode update descriptor.
Definition ucode.h:75
A microcode update status report.
Definition ucode.h:89
A microcode update summary.
Definition ucode.c:101
unsigned int count
Number of CPUs processed.
Definition ucode.c:103
int32_t high
Highest observed microcode version.
Definition ucode.c:107
int32_t low
Lowest observed microcode version.
Definition ucode.c:105
A microcode update.
Definition ucode.c:87
uint32_t signature
Boot processor CPU signature.
Definition ucode.c:91
uint32_t platform
Platform ID.
Definition ucode.c:93
struct ucode_descriptor * desc
Update descriptors (if being populated)
Definition ucode.c:97
struct ucode_vendor * vendor
CPU vendor, if known.
Definition ucode.c:89
unsigned int count
Number of potentially relevant signatures found.
Definition ucode.c:95
A CPU vendor.
Definition ucode.c:75
uint32_t trigger_msr
Microcode load trigger MSR.
Definition ucode.c:79
uint8_t ver_high
Microcode version is reported via high dword.
Definition ucode.c:83
union ucode_vendor_id id
Vendor string.
Definition ucode.c:77
uint8_t ver_clear
Microcode version requires manual clear.
Definition ucode.c:81
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79
static int ucode_probe(struct image *image)
Probe microcode update image.
Definition ucode.c:735
static struct ucode_vendor ucode_amd
AMD CPU vendor.
Definition ucode.c:119
static int ucode_status(const struct ucode_update *update, const struct ucode_control *control, const struct ucode_status *status, struct ucode_summary *summary, unsigned int id, int optional)
Check status report.
Definition ucode.c:159
static struct ucode_vendor * ucode_vendors[]
List of known CPU vendors.
Definition ucode.c:125
#define UCODE_MAX_HT
Maximum number of hyperthread siblings.
Definition ucode.c:61
static int ucode_parse_intel(struct image *image, size_t start, struct ucode_update *update)
Parse Intel microcode image.
Definition ucode.c:394
static struct ucode_vendor ucode_intel
Intel CPU vendor.
Definition ucode.c:111
static const char * ucode_vendor_name(const union ucode_vendor_id *vendor)
Get CPU vendor name (for debugging)
Definition ucode.c:136
static int ucode_exec(struct image *image)
Execute microcode update.
Definition ucode.c:641
#define UCODE_WAIT_MS
Time to wait for a microcode update to complete.
Definition ucode.c:64
static int ucode_parse(struct image *image, struct ucode_update *update)
Parse microcode image.
Definition ucode.c:609
static int ucode_parse_amd(struct image *image, size_t start, struct ucode_update *update)
Parse AMD microcode image.
Definition ucode.c:498
static void ucode_describe(struct image *image, size_t start, const struct ucode_vendor *vendor, const struct ucode_descriptor *desc, uint32_t platforms, struct ucode_update *update)
Add descriptor to list (if applicable)
Definition ucode.c:322
static int ucode_verify(struct image *image, size_t start, size_t len)
Verify checksum.
Definition ucode.c:360
static int ucode_update_all(struct image *image, const struct ucode_update *update, struct ucode_summary *summary)
Update microcode on all CPUs.
Definition ucode.c:231
Microcode updates.
uint32_t apic_max
Maximum expected APIC ID.
Definition ucode.h:7
#define MSR_UCODE_TRIGGER_AMD
AMD microcode load trigger MSR.
Definition ucode.h:25
#define INTEL_UCODE_LVER
Intel microcode loader version number.
Definition ucode.h:140
uint32_t data_len
Microcode data size (or 0 to indicate 2000 bytes)
Definition ucode.h:15
#define INTEL_UCODE_DATA_LEN
Intel microcode default data length.
Definition ucode.h:143
#define INTEL_UCODE_HVER
Intel microcode header version number.
Definition ucode.h:137
#define UCODE_SIGNATURE_MASK
CPUID signature applicability mask.
Definition ucode.h:32
#define AMD_UCODE_MAGIC
AMD microcode magic signature.
Definition ucode.h:179
#define AMD_UCODE_EQUIV_TYPE
AMD microcode equivalence table type.
Definition ucode.h:182
#define AMD_UCODE_PATCH_TYPE
AMD patch type.
Definition ucode.h:219
#define INTEL_UCODE_ALIGN
Intel microcode file alignment.
Definition ucode.h:146
#define MSR_PLATFORM_ID
Platform ID MSR.
Definition ucode.h:16
#define MSR_UCODE_TRIGGER_INTEL
Intel microcode load trigger MSR.
Definition ucode.h:22
#define MSR_PLATFORM_ID_VALUE(value)
Extract platform ID from MSR value.
Definition ucode.h:19
#define UCODE_VERSION_MAX
Maximum possible microcode version.
Definition ucode.h:38
uint32_t platforms
Supported platforms.
Definition ucode.h:13
#define UCODE_VERSION_MIN
Minimum possible microcode version.
Definition ucode.h:35
A CPU vendor string.
Definition ucode.c:67
uint32_t dword[3]
CPUID registers.
Definition ucode.c:69
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition vsprintf.c:465