iPXE
ucode.c File Reference

Microcode updates. More...

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <ipxe/uaccess.h>
#include <ipxe/umalloc.h>
#include <ipxe/image.h>
#include <ipxe/cpuid.h>
#include <ipxe/msr.h>
#include <ipxe/mp.h>
#include <ipxe/timer.h>
#include <ipxe/ucode.h>

Go to the source code of this file.

Data Structures

union  ucode_vendor_id
 A CPU vendor string. More...
struct  ucode_vendor
 A CPU vendor. More...
struct  ucode_update
 A microcode update. More...
struct  ucode_summary
 A microcode update summary. More...

Macros

#define UCODE_MAX_HT   8
 Maximum number of hyperthread siblings.
#define UCODE_WAIT_MS   10
 Time to wait for a microcode update to complete.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static const char * ucode_vendor_name (const union ucode_vendor_id *vendor)
 Get CPU vendor name (for debugging).
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.
static int ucode_update_all (struct image *image, const struct ucode_update *update, struct ucode_summary *summary)
 Update microcode on all CPUs.
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).
static int ucode_verify (struct image *image, size_t start, size_t len)
 Verify checksum.
static int ucode_parse_intel (struct image *image, size_t start, struct ucode_update *update)
 Parse Intel microcode image.
static int ucode_parse_amd (struct image *image, size_t start, struct ucode_update *update)
 Parse AMD microcode image.
static int ucode_parse (struct image *image, struct ucode_update *update)
 Parse microcode image.
static int ucode_exec (struct image *image)
 Execute microcode update.
static int ucode_probe (struct image *image)
 Probe microcode update image.
struct image_type ucode_image_type __image_type (PROBE_NORMAL)
 Microcode update image type.

Variables

static struct ucode_vendor ucode_intel
 Intel CPU vendor.
static struct ucode_vendor ucode_amd
 AMD CPU vendor.
static struct ucode_vendorucode_vendors []
 List of known CPU vendors.

Detailed Description

Microcode updates.

Definition in file ucode.c.

Macro Definition Documentation

◆ UCODE_MAX_HT

#define UCODE_MAX_HT   8

Maximum number of hyperthread siblings.

Microcode updates must not be performed on hyperthread siblings at the same time, since they share microcode storage.

Hyperthread siblings are always the lowest level of the CPU topology and correspond to the least significant bits of the APIC ID. We may therefore avoid collisions by performing the microcode updates in batches, with each batch targeting just one value for the least significant N bits of the APIC ID.

We assume that no CPUs exist with more than this number of hyperthread siblings. (This must be a power of two.)

Definition at line 61 of file ucode.c.

Referenced by ucode_update_all().

◆ UCODE_WAIT_MS

#define UCODE_WAIT_MS   10

Time to wait for a microcode update to complete.

Definition at line 64 of file ucode.c.

Referenced by ucode_update_all().

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ ucode_vendor_name()

const char * ucode_vendor_name ( const union ucode_vendor_id * vendor)
static

Get CPU vendor name (for debugging).

Parameters
vendorCPU vendor
Return values
nameName

Definition at line 136 of file ucode.c.

136 {
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}
static unsigned short vendor
Definition davicom.c:128
union @104331263140136355135267063077374276003064103115 u
void * memcpy(void *dest, const void *src, size_t len) __nonnull
A CPU vendor string.
Definition ucode.c:67

References memcpy(), u, and vendor.

Referenced by ucode_describe(), and ucode_exec().

◆ ucode_status()

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 )
static

Check status report.

Parameters
updateMicrocode update
controlMicrocode update control
statusMicrocode update status
summaryMicrocode update summary
idAPIC ID
optionalStatus report is optional
Return values
rcReturn status code

Definition at line 159 of file ucode.c.

163 {
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}
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
uint8_t id
Request identifier.
Definition ena.h:1
uint8_t status
Status.
Definition ena.h:5
struct ena_llq_option desc
Descriptor counts.
Definition ena.h:9
#define DBGC2(...)
Definition compiler.h:547
#define DBGC(...)
Definition compiler.h:530
#define ENOENT
No such file or directory.
Definition errno.h:558
#define EINVAL
Invalid argument.
Definition errno.h:472
#define EIO
Input/output error.
Definition errno.h:477
#define ERANGE
Result too large.
Definition errno.h:683
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:638
uint32_t control
Control.
Definition myson.h:3
A microcode update descriptor.
Definition ucode.h:75
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
struct ucode_descriptor * desc
Update descriptors (if being populated).
Definition ucode.c:97
uint32_t apic_max
Maximum expected APIC ID.
Definition ucode.h:7

References apic_max, assert, control, ucode_summary::count, DBGC, DBGC2, desc, ucode_update::desc, EINVAL, EIO, ENOENT, ENOTTY, ERANGE, ucode_summary::high, id, ucode_summary::low, and status.

◆ ucode_update_all()

int ucode_update_all ( struct image * image,
const struct ucode_update * update,
struct ucode_summary * summary )
static

Update microcode on all CPUs.

Parameters
imageMicrocode image
updateMicrocode update
summaryMicrocode update summary to fill in
Return values
rcReturn status code

Definition at line 231 of file ucode.c.

233 {
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}
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
#define build_assert(condition)
Assert a condition at build time (after dead code elimination).
Definition assert.h:88
#define max(x, y)
Definition ath.h:41
ring len
Length.
Definition dwmac.h:226
#define ENOMEM
Not enough space.
Definition errno.h:578
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.
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
void * memset(void *dest, int character, size_t len) __nonnull
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
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An executable image.
Definition image.h:24
char * name
Name.
Definition image.h:38
A microcode update control.
Definition ucode.h:45
A microcode update status report.
Definition ucode.h:89
A microcode update.
Definition ucode.c:87
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
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79
#define UCODE_MAX_HT
Maximum number of hyperthread siblings.
Definition ucode.c:61
#define UCODE_WAIT_MS
Time to wait for a microcode update to complete.
Definition ucode.c:64
#define UCODE_VERSION_MAX
Maximum possible microcode version.
Definition ucode.h:38
#define UCODE_VERSION_MIN
Minimum possible microcode version.
Definition ucode.h:35

References assert, build_assert, control, ucode_summary::count, ucode_update::count, DBGC, ucode_update::desc, ENOMEM, ucode_summary::high, id, len, ucode_summary::low, max, mdelay(), memset(), mp_boot_cpuid(), mp_exec_boot(), mp_max_cpuid(), mp_start_all(), image::name, rc, status, strerror(), UCODE_MAX_HT, UCODE_VERSION_MAX, UCODE_VERSION_MIN, UCODE_WAIT_MS, ufree(), umalloc(), ucode_update::vendor, and vendor.

Referenced by ucode_exec().

◆ ucode_describe()

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 )
static

Add descriptor to list (if applicable).

Parameters
imageMicrocode image
startStarting offset within image
vendorCPU vendor
descMicrocode descriptor
platformsSupported platforms, or 0 for all platforms
updateMicrocode update

Definition at line 322 of file ucode.c.

325 {
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}
uint32_t start
Starting offset.
Definition netvsc.h:1
uint32_t signature
Boot processor CPU signature.
Definition ucode.c:91
uint32_t platform
Platform ID.
Definition ucode.c:93
static const char * ucode_vendor_name(const union ucode_vendor_id *vendor)
Get CPU vendor name (for debugging).
Definition ucode.c:136
#define UCODE_SIGNATURE_MASK
CPUID signature applicability mask.
Definition ucode.h:32
uint32_t platforms
Supported platforms.
Definition ucode.h:13

References ucode_update::count, DBGC, DBGC2, desc, ucode_update::desc, memcpy(), image::name, ucode_update::platform, platforms, ucode_update::signature, start, UCODE_SIGNATURE_MASK, ucode_vendor_name(), ucode_update::vendor, and vendor.

Referenced by ucode_parse_amd(), and ucode_parse_intel().

◆ ucode_verify()

int ucode_verify ( struct image * image,
size_t start,
size_t len )
static

Verify checksum.

Parameters
imageMicrocode image
startStarting offset
lenLength
Return values
rcReturn status code

Definition at line 360 of file ucode.c.

360 {
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}
unsigned int uint32_t
Definition stdint.h:12
static unsigned int count
Number of entries.
Definition dwmac.h:220
uint8_t checksum
Checksum.
Definition pnpbios.c:12
unsigned long int dword
Definition smc9000.h:40
const void * data
Read-only data.
Definition image.h:51

References checksum, count, image::data, DBGC, EINVAL, len, image::name, and start.

Referenced by ucode_parse_intel().

◆ ucode_parse_intel()

int ucode_parse_intel ( struct image * image,
size_t start,
struct ucode_update * update )
static

Parse Intel microcode image.

Parameters
imageMicrocode image
startStarting offset within image
updateMicrocode update
Return values
lenLength consumed, or negative error

Definition at line 394 of file ucode.c.

395 {
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}
struct golan_inbox_hdr hdr
Message header.
Definition CIB_PRM.h:0
uint16_t offset
Offset to command line.
Definition bzimage.h:3
uint16_t ext
Extended status.
Definition ena.h:9
#define ENOEXEC
Exec format error.
Definition errno.h:563
size_t len
Length of raw file image.
Definition image.h:63
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
static struct ucode_vendor ucode_intel
Intel CPU vendor.
Definition ucode.c:111
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
#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 INTEL_UCODE_ALIGN
Intel microcode file alignment.
Definition ucode.h:146

References intel_ucode_ext_header::count, image::data, data_len, DBGC, DBGC2, desc, EINVAL, ENOEXEC, ext, hdr, INTEL_UCODE_ALIGN, INTEL_UCODE_DATA_LEN, INTEL_UCODE_HVER, INTEL_UCODE_LVER, image::len, len, image::name, offset, rc, start, ucode_describe(), ucode_intel, and ucode_verify().

Referenced by ucode_parse().

◆ ucode_parse_amd()

int ucode_parse_amd ( struct image * image,
size_t start,
struct ucode_update * update )
static

Parse AMD microcode image.

Parameters
imageMicrocode image
startStarting offset within image
updateMicrocode update
Return values
lenLength consumed, or negative error

Definition at line 498 of file ucode.c.

499 {
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 ;
543 ( offset + sizeof ( *equiv ) ) <= ( sizeof ( *hdr ) + hdr->len );
544 count++, offset += sizeof ( *equiv ) ) {
545 if ( ! equiv[count].signature )
546 break;
547 }
548 DBGC2 ( image, "UCODE %s+%#04zx has %d equivalence table entries\n",
549 image->name, start, count );
550
551 /* Parse available updates */
552 offset = ( sizeof ( *hdr ) + hdr->len );
553 used = 0;
554 while ( used < count ) {
555
556 /* Read patch header */
557 if ( ( offset + sizeof ( *phdr ) ) > remaining ) {
558 DBGC ( image, "UCODE %s+%#04zx truncated patch "
559 "header\n", image->name, start );
560 return -EINVAL;
561 }
562 phdr = ( image->data + start + offset );
563 offset += sizeof ( *phdr );
564
565 /* Validate patch header */
566 if ( phdr->type != AMD_UCODE_PATCH_TYPE ) {
567 DBGC ( image, "UCODE %s+%#04zx unsupported patch type "
568 "%d\n", image->name, start, phdr->type );
569 return -ENOTSUP;
570 }
571 if ( phdr->len < sizeof ( *patch ) ) {
572 DBGC ( image, "UCODE %s+%#04zx underlength patch\n",
573 image->name, start );
574 return -EINVAL;
575 }
576 if ( phdr->len > ( remaining - offset ) ) {
577 DBGC ( image, "UCODE %s+%#04zx truncated patch\n",
578 image->name, start );
579 return -EINVAL;
580 }
581
582 /* Read patch and construct descriptor */
583 patch = ( image->data + start + offset );
584 desc.version = patch->version;
585 desc.address = ( virt_to_phys ( image->data ) +
586 start + offset );
587 offset += phdr->len;
588
589 /* Parse equivalence table to find matching signatures */
590 for ( i = 0 ; i < count ; i++ ) {
591 if ( patch->id == equiv[i].id ) {
592 desc.signature = equiv[i].signature;
594 &desc, 0, update );
595 used++;
596 }
597 }
598 }
599
600 return offset;
601}
u8 signature
CPU signature.
Definition CIB_PRM.h:7
#define ENOTSUP
Operation not supported.
Definition errno.h:633
An AMD microcode equivalence table entry.
Definition ucode.h:185
uint32_t signature
CPU signature.
Definition ucode.h:187
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
static struct ucode_vendor ucode_amd
AMD CPU vendor.
Definition ucode.c:119
#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

References AMD_UCODE_EQUIV_TYPE, AMD_UCODE_MAGIC, AMD_UCODE_PATCH_TYPE, count, image::data, DBGC, DBGC2, desc, EINVAL, ENOEXEC, ENOTSUP, hdr, amd_ucode_equivalence::id, amd_ucode_patch::id, amd_ucode_patch_header::len, image::len, image::name, offset, amd_ucode_equivalence::signature, signature, start, amd_ucode_patch_header::type, ucode_amd, ucode_describe(), and amd_ucode_patch::version.

Referenced by ucode_parse().

◆ ucode_parse()

int ucode_parse ( struct image * image,
struct ucode_update * update )
static

Parse microcode image.

Parameters
imageMicrocode image
updateMicrocode update
Return values
rcReturn status code

Definition at line 610 of file ucode.c.

610 {
611 size_t start;
612 int len;
613
614 /* Attempt to parse concatenated microcode updates */
615 for ( start = 0 ; start < image->len ; start += len ) {
616
617 /* Attempt to parse as Intel microcode */
618 len = ucode_parse_intel ( image, start, update );
619 if ( len > 0 )
620 continue;
621
622 /* Attempt to parse as AMD microcode */
623 len = ucode_parse_amd ( image, start, update );
624 if ( len > 0 )
625 continue;
626
627 /* Not a recognised microcode format */
628 DBGC ( image, "UCODE %s+%zx not recognised\n",
629 image->name, start );
630 return -ENOEXEC;
631 }
632
633 return 0;
634}
static int ucode_parse_intel(struct image *image, size_t start, struct ucode_update *update)
Parse Intel microcode image.
Definition ucode.c:394
static int ucode_parse_amd(struct image *image, size_t start, struct ucode_update *update)
Parse AMD microcode image.
Definition ucode.c:498

References DBGC, ENOEXEC, image::len, len, image::name, start, ucode_parse_amd(), and ucode_parse_intel().

Referenced by ucode_exec().

◆ ucode_exec()

int ucode_exec ( struct image * image)
static

Execute microcode update.

Parameters
imageMicrocode image
Return values
rcReturn status code

Definition at line 642 of file ucode.c.

642 {
643 struct ucode_update update;
644 struct ucode_vendor *vendor;
645 struct ucode_summary summary;
646 union ucode_vendor_id id;
648 uint32_t discard_a;
649 uint32_t discard_b;
651 uint32_t discard_d;
652 unsigned int check;
653 unsigned int i;
654 size_t len;
655 int rc;
656
657 /* Initialise update */
658 memset ( &update, 0, sizeof ( update ) );
659 cpuid ( CPUID_VENDOR_ID, 0, &discard_a, &id.dword[0], &id.dword[2],
660 &id.dword[1] );
661 cpuid ( CPUID_FEATURES, 0, &update.signature, &discard_b,
662 &discard_c, &discard_d );
663
664 /* Identify CPU vendor, if recognised */
665 for ( i = 0 ; i < ( sizeof ( ucode_vendors ) /
666 sizeof ( ucode_vendors[0] ) ) ; i++ ) {
668 if ( memcmp ( &id, &vendor->id, sizeof ( id ) ) == 0 )
669 update.vendor = vendor;
670 }
671
672 /* Identify platform, if applicable */
673 if ( update.vendor == &ucode_intel ) {
674 platform_id = rdmsr ( MSR_PLATFORM_ID );
675 update.platform =
677 }
678
679 /* Count number of matching update descriptors */
680 DBGC ( image, "UCODE %s applying to %s %#08x",
681 image->name, ucode_vendor_name ( &id ), update.signature );
682 if ( update.platform )
683 DBGC ( image, " (%#02x)", update.platform );
684 DBGC ( image, "\n" );
685 if ( ( rc = ucode_parse ( image, &update ) ) != 0 )
686 goto err_count;
687 DBGC ( image, "UCODE %s found %d matching update(s)\n",
688 image->name, update.count );
689
690 /* Allocate descriptors */
691 len = ( ( update.count + 1 /* terminator */ ) *
692 sizeof ( update.desc[0] ) );
693 update.desc = zalloc ( len );
694 if ( ! update.desc ) {
695 rc = -ENOMEM;
696 goto err_alloc;
697 }
698
699 /* Populate descriptors */
700 check = update.count;
701 update.count = 0;
702 if ( ( rc = ucode_parse ( image, &update ) ) != 0 )
703 goto err_parse;
704 assert ( check == update.count );
705
706 /* Perform update */
707 if ( ( rc = ucode_update_all ( image, &update, &summary ) ) != 0 )
708 goto err_update;
709
710 /* Print summary if directed to do so */
711 if ( image->cmdline && ( strstr ( image->cmdline, "-v" ) ) ) {
712 printf ( "Microcode: " );
713 if ( summary.low == summary.high ) {
714 printf ( "already version %#x", summary.low );
715 } else {
716 printf ( "updated version %#x->%#x",
717 summary.low, summary.high );
718 }
719 printf ( " (x%d)\n", summary.count );
720 }
721
722 err_update:
723 err_parse:
724 free ( update.desc );
725 err_alloc:
726 err_count:
727 return rc;
728}
unsigned long long uint64_t
Definition stdint.h:13
long discard_c
Definition bigint.h:32
#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
uint8_t platform_id
Platform ID.
Definition eltorito.h:8
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:718
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
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:324
char * cmdline
Command line to pass to image.
Definition image.h:43
A microcode update summary.
Definition ucode.c:101
static struct ucode_vendor * ucode_vendors[]
List of known CPU vendors.
Definition ucode.c:125
static int ucode_parse(struct image *image, struct ucode_update *update)
Parse microcode image.
Definition ucode.c:610
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
#define MSR_PLATFORM_ID
Platform ID MSR.
Definition ucode.h:16
#define MSR_PLATFORM_ID_VALUE(value)
Extract platform ID from MSR value.
Definition ucode.h:19
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition vsprintf.c:485

References assert, image::cmdline, ucode_summary::count, ucode_update::count, CPUID_FEATURES, CPUID_VENDOR_ID, DBGC, ucode_update::desc, discard_c, ENOMEM, free, ucode_summary::high, id, len, ucode_summary::low, memcmp(), memset(), MSR_PLATFORM_ID, MSR_PLATFORM_ID_VALUE, image::name, ucode_update::platform, platform_id, printf(), rc, ucode_update::signature, strstr(), ucode_intel, ucode_parse(), ucode_update_all(), ucode_vendor_name(), ucode_vendors, ucode_update::vendor, vendor, and zalloc().

Referenced by __image_type().

◆ ucode_probe()

int ucode_probe ( struct image * image)
static

Probe microcode update image.

Parameters
imageMicrocode image
Return values
rcReturn status code

Definition at line 736 of file ucode.c.

736 {
737 const union {
738 struct intel_ucode_header intel;
739 struct amd_ucode_header amd;
740 } *header;
741
742 /* Sanity check */
743 if ( image->len < sizeof ( *header ) ) {
744 DBGC ( image, "UCODE %s too short\n", image->name );
745 return -ENOEXEC;
746 }
747
748 /* Read first microcode image header */
749 header = image->data;
750
751 /* Check for something that looks like an Intel update
752 *
753 * Intel updates unfortunately have no magic signatures or
754 * other easily verifiable fields. We check a small selection
755 * of header fields that can be easily verified.
756 *
757 * We do not attempt to fully parse the update, since we want
758 * errors to be reported at the point of attempting to execute
759 * the image, and do not want to have a microcode image
760 * erroneously treated as a PXE boot executable.
761 */
762 if ( ( header->intel.hver == INTEL_UCODE_HVER ) &&
763 ( header->intel.lver == INTEL_UCODE_LVER ) &&
764 ( ( header->intel.date.century == 0x19 ) ||
765 ( ( header->intel.date.century >= 0x20 ) &&
766 ( header->intel.date.century <= 0x29 ) ) ) ) {
767 DBGC ( image, "UCODE %s+%#04zx looks like an Intel update\n",
768 image->name, ( ( size_t ) 0 ) );
769 return 0;
770 }
771
772 /* Check for AMD update signature */
773 if ( ( header->amd.magic == AMD_UCODE_MAGIC ) &&
774 ( header->amd.type == AMD_UCODE_EQUIV_TYPE ) ) {
775 DBGC ( image, "UCODE %s+%#04zx looks like an AMD update\n",
776 image->name, ( ( size_t ) 0 ) );
777 return 0;
778 }
779
780 return -ENOEXEC;
781}
struct ena_llq_option header
Header locations.
Definition ena.h:5

References AMD_UCODE_EQUIV_TYPE, AMD_UCODE_MAGIC, image::data, DBGC, ENOEXEC, header, INTEL_UCODE_HVER, INTEL_UCODE_LVER, image::len, and image::name.

Referenced by __image_type().

◆ __image_type()

struct image_type ucode_image_type __image_type ( PROBE_NORMAL )

Microcode update image type.

References __image_type, PROBE_NORMAL, ucode_exec(), and ucode_probe().

Variable Documentation

◆ ucode_intel

struct ucode_vendor ucode_intel
static
Initial value:
= {
.id = { .string = "GenuineIntel" },
.ver_clear = 1,
.ver_high = 1,
.trigger_msr = MSR_UCODE_TRIGGER_INTEL,
}
#define MSR_UCODE_TRIGGER_INTEL
Intel microcode load trigger MSR.
Definition ucode.h:22

Intel CPU vendor.

Definition at line 111 of file ucode.c.

111 {
112 .id = { .string = "GenuineIntel" },
113 .ver_clear = 1,
114 .ver_high = 1,
115 .trigger_msr = MSR_UCODE_TRIGGER_INTEL,
116};

Referenced by ucode_exec(), and ucode_parse_intel().

◆ ucode_amd

struct ucode_vendor ucode_amd
static
Initial value:
= {
.id = { .string = "AuthenticAMD" },
.trigger_msr = MSR_UCODE_TRIGGER_AMD,
}
#define MSR_UCODE_TRIGGER_AMD
AMD microcode load trigger MSR.
Definition ucode.h:25

AMD CPU vendor.

Definition at line 119 of file ucode.c.

119 {
120 .id = { .string = "AuthenticAMD" },
121 .trigger_msr = MSR_UCODE_TRIGGER_AMD,
122};

Referenced by ucode_parse_amd().

◆ ucode_vendors

struct ucode_vendor* ucode_vendors[]
static
Initial value:

List of known CPU vendors.

Definition at line 125 of file ucode.c.

125 {
127 &ucode_amd,
128};

Referenced by ucode_exec().