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:50
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:522
#define DBGC(...)
Definition compiler.h:505
#define ENOENT
No such file or directory.
Definition errno.h:515
#define EINVAL
Invalid argument.
Definition errno.h:429
#define EIO
Input/output error.
Definition errno.h:434
#define ERANGE
Result too large.
Definition errno.h:640
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:595
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:77
#define max(x, y)
Definition ath.h:41
ring len
Length.
Definition dwmac.h:226
#define ENOMEM
Not enough space.
Definition errno.h:535
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:520
size_t len
Length of raw file image.
Definition image.h:56
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 ; 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}
u8 signature
CPU signature.
Definition CIB_PRM.h:7
#define ENOTSUP
Operation not supported.
Definition errno.h:590
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 609 of file ucode.c.

609 {
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}
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 641 of file ucode.c.

641 {
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}
unsigned long long uint64_t
Definition stdint.h:13
long discard_c
Definition bigint.h:33
#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:662
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:310
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:609
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:465

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 735 of file ucode.c.

735 {
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}
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().