Changeset View
Changeset View
Standalone View
Standalone View
sysutils/cpu-microcode-intel/files/ucode-split.c
| Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | struct microcode_update_header { | ||||
| uint32_t checksum; /* Over update data and header */ | uint32_t checksum; /* Over update data and header */ | ||||
| uint32_t loader_revision; | uint32_t loader_revision; | ||||
| uint32_t processor_flags; | uint32_t processor_flags; | ||||
| uint32_t data_size; | uint32_t data_size; | ||||
| uint32_t total_size; | uint32_t total_size; | ||||
| uint32_t reserved[3]; | uint32_t reserved[3]; | ||||
| }; | }; | ||||
| /* SDM (March 2026) vol 3A 12.11.2 Optional Extended Signature Table. */ | |||||
| struct ucode_intel_extsig_table { | |||||
| uint32_t signature_count; | |||||
| uint32_t checksum; | |||||
| uint32_t reserved[3]; | |||||
| }; | |||||
| struct ucode_intel_extsig { | |||||
| uint32_t processor_signature; | |||||
| uint32_t processor_flags; | |||||
| uint32_t checksum; | |||||
| }; | |||||
| /* | /* | ||||
| * SDM vol 2A CPUID EAX = 01h Returns Model, Family, Stepping Information. | * SDM vol 2A CPUID EAX = 01h Returns Model, Family, Stepping Information. | ||||
| * Caller must free the returned string. | * Caller must free the returned string. | ||||
| */ | */ | ||||
| static char * | static char * | ||||
| format_signature(uint32_t signature) | format_signature(uint32_t signature) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | dump_header(const struct microcode_update_header *hdr) | ||||
| printf("datasize\t0x%x\t\t0x%x\n", hdr->data_size, | printf("datasize\t0x%x\t\t0x%x\n", hdr->data_size, | ||||
| hdr->data_size != 0 ? hdr->data_size : 2000); | hdr->data_size != 0 ? hdr->data_size : 2000); | ||||
| printf("size\t\t0x%x\t\t0x%x\n", hdr->total_size, | printf("size\t\t0x%x\t\t0x%x\n", hdr->total_size, | ||||
| hdr->total_size != 0 ? hdr->total_size : 2048); | hdr->total_size != 0 ? hdr->total_size : 2048); | ||||
| free(sig_str); | free(sig_str); | ||||
| } | } | ||||
| static void | static void | ||||
| copy_entry(int ifd, off_t entry_start, uint32_t total_size, | |||||
| const char *output_file, char *buf, bool vflag) | |||||
| { | |||||
| off_t off; | |||||
| size_t len, resid; | |||||
| ssize_t rv; | |||||
| int ofd; | |||||
| ofd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); | |||||
| if (ofd < 0) | |||||
| err(1, "open"); | |||||
| resid = total_size; | |||||
| off = entry_start; | |||||
| while (resid > 0) { | |||||
| len = resid < bufsize ? resid : bufsize; | |||||
| rv = pread(ifd, buf, len, off); | |||||
| if (rv < 0) | |||||
| err(1, "pread"); | |||||
| else if (rv < (ssize_t)len) | |||||
| errx(1, "truncated microcode data"); | |||||
| if (write(ofd, buf, len) < (ssize_t)len) | |||||
| err(1, "write"); | |||||
| resid -= len; | |||||
| off += len; | |||||
| } | |||||
| if (vflag) | |||||
| printf("written to %s\n", output_file); | |||||
| close(ofd); | |||||
| } | |||||
| static void | |||||
| usage(void) | usage(void) | ||||
| { | { | ||||
| printf("ucode-split [-v] microcode_file\n"); | printf("ucode-split [-v] microcode_file\n"); | ||||
| exit(1); | exit(1); | ||||
| } | } | ||||
| int | int | ||||
| main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
| { | { | ||||
| struct microcode_update_header hdr; | struct microcode_update_header hdr; | ||||
| struct ucode_intel_extsig_table etbl; | |||||
| struct ucode_intel_extsig extsig; | |||||
| char *buf, *output_file, *sig_str; | char *buf, *output_file, *sig_str; | ||||
| size_t len, resid; | off_t entry_start; | ||||
| uint32_t data_size, total_size, i; | |||||
| ssize_t rv; | ssize_t rv; | ||||
| int c, ifd, ofd; | int c, ifd; | ||||
| bool vflag; | bool vflag; | ||||
| vflag = false; | vflag = false; | ||||
| while ((c = getopt(argc, argv, "v")) != -1) { | while ((c = getopt(argc, argv, "v")) != -1) { | ||||
| switch (c) { | switch (c) { | ||||
| case 'v': | case 'v': | ||||
| vflag = true; | vflag = true; | ||||
| break; | break; | ||||
| Show All 11 Lines | main(int argc, char *argv[]) | ||||
| if (ifd < 0) | if (ifd < 0) | ||||
| err(1, "open"); | err(1, "open"); | ||||
| buf = malloc(bufsize); | buf = malloc(bufsize); | ||||
| if (buf == NULL) | if (buf == NULL) | ||||
| err(1, "malloc"); | err(1, "malloc"); | ||||
| for (;;) { | for (;;) { | ||||
| entry_start = lseek(ifd, 0, SEEK_CUR); | |||||
| if (entry_start < 0) | |||||
| err(1, "lseek"); | |||||
| /* Read header. */ | /* Read header. */ | ||||
| rv = read(ifd, &hdr, sizeof(hdr)); | rv = read(ifd, &hdr, sizeof(hdr)); | ||||
| if (rv < 0) { | if (rv < 0) { | ||||
| err(1, "read"); | err(1, "read"); | ||||
| } else if (rv == 0) { | } else if (rv == 0) { | ||||
| break; | break; | ||||
| } else if (rv < (ssize_t)sizeof(hdr)) { | } else if (rv < (ssize_t)sizeof(hdr)) { | ||||
| errx(1, "invalid microcode header"); | errx(1, "invalid microcode header"); | ||||
| } | } | ||||
| if (hdr.header_version != 1) | if (hdr.header_version != 1) | ||||
| errx(1, "invalid header version"); | errx(1, "invalid header version"); | ||||
| if (vflag) | if (vflag) | ||||
| dump_header(&hdr); | dump_header(&hdr); | ||||
| data_size = hdr.data_size != 0 ? hdr.data_size : 2000; | |||||
| total_size = hdr.total_size != 0 ? hdr.total_size : 2048; | |||||
| /* Arbitrarily chosen maximum size. */ | |||||
| if (total_size - sizeof(hdr) > 1 << 24) | |||||
| errx(1, "header total_size too large"); | |||||
| /* Write primary output file. */ | |||||
| sig_str = format_signature(hdr.processor_signature); | sig_str = format_signature(hdr.processor_signature); | ||||
| asprintf(&output_file, "%s.%02x", sig_str, | asprintf(&output_file, "%s.%02x", sig_str, | ||||
| hdr.processor_flags & 0xff); | hdr.processor_flags & 0xff); | ||||
| free(sig_str); | free(sig_str); | ||||
| if (output_file == NULL) | if (output_file == NULL) | ||||
| err(1, "asprintf"); | err(1, "asprintf"); | ||||
| ofd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); | copy_entry(ifd, entry_start, total_size, output_file, buf, vflag); | ||||
| if (ofd < 0) | free(output_file); | ||||
| err(1, "open"); | |||||
| /* Write header. */ | /* | ||||
| rv = write(ofd, &hdr, sizeof(hdr)); | * Process the extended signature table, if present. Each | ||||
| if (rv < (ssize_t)sizeof(hdr)) | * entry names an additional processor signature and platform | ||||
| err(1, "write"); | * flags combination covered by this microcode blob, so write | ||||
| * a copy of the blob for each. | |||||
| */ | |||||
| if (total_size > data_size + sizeof(hdr)) { | |||||
| if (lseek(ifd, entry_start + sizeof(hdr) + data_size, | |||||
| SEEK_SET) < 0) | |||||
| err(1, "lseek"); | |||||
| rv = read(ifd, &etbl, sizeof(etbl)); | |||||
markj: You might handle this error case in the same way as in copy_entry(), i.e., check for `rv < 0`… | |||||
| if (rv < 0) | |||||
| err(1, "read"); | |||||
| else if (rv < (ssize_t)sizeof(etbl)) | |||||
| errx(1, "truncated extended signature table"); | |||||
Not Done Inline ActionsSame here. markj: Same here. | |||||
| /* Copy data. */ | for (i = 0; i < etbl.signature_count; i++) { | ||||
| resid = (hdr.total_size != 0 ? hdr.total_size : 2048) - | rv = read(ifd, &extsig, sizeof(extsig)); | ||||
| sizeof(hdr); | |||||
| if (resid > 1 << 24) /* Arbitrary chosen maximum size. */ | |||||
| errx(1, "header total_size too large"); | |||||
| while (resid > 0) { | |||||
| len = resid < bufsize ? resid : bufsize; | |||||
| rv = read(ifd, buf, len); | |||||
| if (rv < 0) | if (rv < 0) | ||||
| err(1, "read"); | err(1, "read"); | ||||
| else if (rv < (ssize_t)len) | else if (rv < (ssize_t)sizeof(extsig)) | ||||
| errx(1, "truncated microcode data"); | errx(1, "truncated extended signature " | ||||
| if (write(ofd, buf, len) < (ssize_t)len) | "entry %u", i); | ||||
| err(1, "write"); | |||||
Not Done Inline ActionsI'm not sure there's much point in skipping identical entries? copy_entry() will just overwrite the file again. markj: I'm not sure there's much point in skipping identical entries? copy_entry() will just overwrite… | |||||
| resid -= len; | sig_str = format_signature( | ||||
| extsig.processor_signature); | |||||
| asprintf(&output_file, "%s.%02x", sig_str, | |||||
| extsig.processor_flags & 0xff); | |||||
| free(sig_str); | |||||
| if (output_file == NULL) | |||||
| err(1, "asprintf"); | |||||
| copy_entry(ifd, entry_start, total_size, | |||||
| output_file, buf, vflag); | |||||
| free(output_file); | |||||
| } | } | ||||
Done Inline ActionsWouldn't it be simpler to make copy_entry() use pread(2)? markj: Wouldn't it be simpler to make copy_entry() use pread(2)? | |||||
Done Inline ActionsIndeed. Thanks. jrm: Indeed. Thanks. | |||||
| } | |||||
| if (vflag) | if (vflag) | ||||
| printf("written to %s\n\n", output_file); | printf("\n"); | ||||
| close(ofd); | |||||
| free(output_file); | /* Advance to the next entry. */ | ||||
| if (lseek(ifd, entry_start + total_size, SEEK_SET) < 0) | |||||
| err(1, "lseek"); | |||||
| } | } | ||||
| free(buf); | |||||
| close(ifd); | |||||
| } | } | ||||
You might handle this error case in the same way as in copy_entry(), i.e., check for rv < 0 separately so you can print errno.