1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2018 The FreeBSD Foundation. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <err.h> 29 #include <fcntl.h> 30 #include <stdbool.h> 31 #include <stdint.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 static const size_t bufsize = 65536; 38 39 /* SDM vol 3 9.11.1 Intel microcode header. */ 40 struct microcode_update_header { 41 uint32_t header_version; 42 uint32_t update_revision; 43 uint32_t date; /* BCD mmddyyyy */ 44 uint32_t processor_signature; 45 uint32_t checksum; /* Over update data and header */ 46 uint32_t loader_revision; 47 uint32_t processor_flags; 48 uint32_t data_size; 49 uint32_t total_size; 50 uint32_t reserved[3]; 51 }; 52 53 /* 54 * SDM vol 2A CPUID EAX = 01h Returns Model, Family, Stepping Information. 55 * Caller must free the returned string. 56 */ 57 58 static char * 59 format_signature(uint32_t signature) 60 { 61 char *buf; 62 unsigned family, model, stepping; 63 64 family = (signature & 0xf00) >> 8; 65 model = (signature & 0xf0) >> 4; 66 stepping = signature & 0xf; 67 if (family == 0x06 || family == 0x0f) 68 model += (signature & 0xf0000) >> 12; 69 if (family == 0x0f) 70 family += (signature & 0xff00000) >> 20; 71 asprintf(&buf, "%02x-%02x-%02x", family, model, stepping); 72 if (buf == NULL) 73 err(1, "asprintf"); 74 return (buf); 75 } 76 77 static void 78 dump_header(const struct microcode_update_header *hdr) 79 { 80 char *sig_str; 81 int i; 82 bool platformid_printed; 83 84 sig_str = format_signature(hdr->processor_signature); 85 printf("header version\t0x%x\n", hdr->header_version); 86 printf("revision\t0x%x\n", hdr->update_revision); 87 printf("date\t\t0x%x\t%04x-%02x-%02x\n", hdr->date, 88 hdr->date & 0xffff, (hdr->date & 0xff000000) >> 24, 89 (hdr->date & 0xff0000) >> 16); 90 printf("signature\t0x%x\t\t%s\n", hdr->processor_signature, sig_str); 91 printf("checksum\t0x%x\n", hdr->checksum); 92 printf("loader revision\t0x%x\n", hdr->loader_revision); 93 printf("processor flags\t0x%x", hdr->processor_flags); 94 platformid_printed = false; 95 for (i = 0; i < 8; i++) { 96 if (hdr->processor_flags & 1 << i) { 97 printf("%s%d", platformid_printed ? ", " : "\t\t", i); 98 platformid_printed = true; 99 } 100 } 101 printf("\n"); 102 printf("datasize\t0x%x\t\t0x%x\n", hdr->data_size, 103 hdr->data_size != 0 ? hdr->data_size : 2000); 104 printf("size\t\t0x%x\t\t0x%x\n", hdr->total_size, 105 hdr->total_size != 0 ? hdr->total_size : 2048); 106 free(sig_str); 107 } 108 109 static void 110 usage(void) 111 { 112 113 printf("ucode-split [-nv] microcode_file\n"); 114 exit(1); 115 } 116 117 int 118 main(int argc, char *argv[]) 119 { 120 struct microcode_update_header hdr; 121 char *buf, *output_file, *sig_str; 122 size_t len, resid; 123 ssize_t rv; 124 int c, ifd, ofd; 125 bool nflag, vflag; 126 127 nflag = vflag = false; 128 while ((c = getopt(argc, argv, "nv")) != -1) { 129 switch (c) { 130 case 'n': 131 nflag = true; 132 break; 133 case 'v': 134 vflag = true; 135 break; 136 default: 137 usage(); 138 } 139 } 140 argc -= optind; 141 argv += optind; 142 143 if (argc != 1) 144 usage(); 145 146 ifd = open(argv[0], O_RDONLY); 147 if (ifd < 0) 148 err(1, "open"); 149 150 buf = malloc(bufsize); 151 if (buf == NULL) 152 err(1, "malloc"); 153 154 for (;;) { 155 /* Read header. */ 156 rv = read(ifd, &hdr, sizeof(hdr)); 157 if (rv < 0) { 158 err(1, "read"); 159 } else if (rv == 0) { 160 break; 161 } else if (rv < (ssize_t)sizeof(hdr)) { 162 errx(1, "invalid microcode header"); 163 } 164 if (hdr.header_version != 1) 165 errx(1, "invalid header version"); 166 167 if (vflag) 168 dump_header(&hdr); 169 170 resid = (hdr.total_size != 0 ? hdr.total_size : 2048) - 171 sizeof(hdr); 172 if (resid > 1 << 24) /* Arbitrary chosen maximum size. */ 173 errx(1, "header total_size too large"); 174 175 if (nflag) { 176 if (lseek(ifd, resid, SEEK_CUR) == -1) 177 err(1, "lseek"); 178 printf("\n"); 179 } else { 180 sig_str = format_signature(hdr.processor_signature); 181 asprintf(&output_file, "%s.%02x", sig_str, 182 hdr.processor_flags & 0xff); 183 free(sig_str); 184 if (output_file == NULL) 185 err(1, "asprintf"); 186 ofd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 187 0600); 188 if (ofd < 0) 189 err(1, "open"); 190 191 /* Write header. */ 192 rv = write(ofd, &hdr, sizeof(hdr)); 193 if (rv < (ssize_t)sizeof(hdr)) 194 err(1, "write"); 195 196 /* Copy data. */ 197 while (resid > 0) { 198 len = resid < bufsize ? resid : bufsize; 199 rv = read(ifd, buf, len); 200 if (rv < 0) 201 err(1, "read"); 202 else if (rv < (ssize_t)len) 203 errx(1, "truncated microcode data"); 204 if (write(ofd, buf, len) < (ssize_t)len) 205 err(1, "write"); 206 resid -= len; 207 } 208 if (vflag) 209 printf("written to %s\n\n", output_file); 210 close(ofd); 211 free(output_file); 212 } 213 } 214 } 215