1/* $OpenBSD: ucode.c,v 1.6 2023/09/10 09:32:31 jsg Exp $ */ 2/* 3 * Copyright (c) 2018 Stefan Fritsch <fritsch@genua.de> 4 * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/systm.h> 21#include <sys/mutex.h> 22#include <sys/malloc.h> 23 24#include <uvm/uvm_extern.h> 25 26#include <machine/cpu.h> 27#include <machine/cpufunc.h> 28#include <machine/specialreg.h> 29#include <machine/biosvar.h> 30 31/* #define UCODE_DEBUG */ 32#ifdef UCODE_DEBUG 33#define DPRINTF(x) do { if (cpu_ucode_debug > 0) printf x; } while (0) 34#define DPRINTFN(n, x) do { if (cpu_ucode_debug >= (n)) printf x; } while (0) 35int cpu_ucode_debug = 1; 36#else 37#define DPRINTF(x) do { ; } while (0) 38#define DPRINTFN(n, x) do { ; } while (0) 39#endif 40 41struct intel_ucode_header { 42 uint32_t header_version; 43 uint32_t update_revision; 44 uint32_t date; 45 uint32_t processor_sig; 46 uint32_t checksum; 47 uint32_t loader_rev; 48 uint32_t processor_flags; 49 uint32_t data_size; 50 uint32_t total_size; 51 uint32_t reserved[3]; 52}; 53 54struct intel_ucode_ext_sig_header { 55 uint32_t ext_sig_count; 56 uint32_t checksum; 57 uint32_t reserved[3]; 58}; 59 60struct intel_ucode_ext_sig { 61 uint32_t processor_sig; 62 uint32_t processor_flags; 63 uint32_t checksum; 64}; 65 66#define INTEL_UCODE_DEFAULT_DATA_SIZE 2000 67 68/* Generic */ 69char * cpu_ucode_data; 70size_t cpu_ucode_size; 71 72void cpu_ucode_setup(void); 73void cpu_ucode_apply(struct cpu_info *); 74 75struct mutex cpu_ucode_mtx = MUTEX_INITIALIZER(IPL_HIGH); 76 77/* Intel */ 78void cpu_ucode_intel_apply(struct cpu_info *); 79struct intel_ucode_header * 80 cpu_ucode_intel_find(char *, size_t, uint32_t); 81int cpu_ucode_intel_verify(struct intel_ucode_header *); 82int cpu_ucode_intel_match(struct intel_ucode_header *, uint32_t, uint32_t, 83 uint32_t); 84uint32_t cpu_ucode_intel_rev(void); 85 86struct intel_ucode_header *cpu_ucode_intel_applied; 87 88void cpu_ucode_amd_apply(struct cpu_info *); 89 90void 91cpu_ucode_setup(void) 92{ 93 vaddr_t va; 94 paddr_t pa; 95 int i, npages; 96 size_t size; 97 98 if (bios_ucode == NULL) 99 return; 100 101 if (!bios_ucode->uc_addr || !bios_ucode->uc_size) 102 return; 103 104 cpu_ucode_size = bios_ucode->uc_size; 105 size = round_page(bios_ucode->uc_size); 106 npages = size / PAGE_SIZE; 107 108 va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, &kd_nowait); 109 if (va == 0) 110 return; 111 for (i = 0; i < npages; i++) { 112 pa = bios_ucode->uc_addr + (i * PAGE_SIZE); 113 pmap_enter(pmap_kernel(), va + (i * PAGE_SIZE), pa, 114 PROT_READ, 115 PROT_READ | PMAP_WIRED); 116 pmap_update(pmap_kernel()); 117 } 118 119 cpu_ucode_data = malloc(cpu_ucode_size, M_DEVBUF, M_WAITOK); 120 121 memcpy((void *)cpu_ucode_data, (void *)va, cpu_ucode_size); 122 123 pmap_remove(pmap_kernel(), va, va + size); 124 pmap_update(pmap_kernel()); 125 km_free((void *)va, size, &kv_any, &kp_none); 126} 127 128/* 129 * Called per-CPU. 130 */ 131void 132cpu_ucode_apply(struct cpu_info *ci) 133{ 134 if (strcmp(cpu_vendor, "GenuineIntel") == 0) 135 cpu_ucode_intel_apply(ci); 136 else if (strcmp(cpu_vendor, "AuthenticAMD") == 0) 137 cpu_ucode_amd_apply(ci); 138} 139 140#define AMD_MAGIC 0x00414d44 141 142struct amd_equiv { 143 uint32_t id; 144 uint32_t a; 145 uint32_t b; 146 uint16_t eid; 147 uint16_t c; 148} __packed; 149 150struct amd_patch { 151 uint32_t type; 152 uint32_t len; 153 uint32_t a; 154 uint32_t level; 155 uint8_t c[16]; 156 uint16_t eid; 157} __packed; 158 159void 160cpu_ucode_amd_apply(struct cpu_info *ci) 161{ 162 uint64_t level; 163 uint32_t magic, tlen, i; 164 uint16_t eid = 0; 165 uint32_t sig, ebx, ecx, edx; 166 uint64_t start = 0; 167 uint32_t patch_len = 0; 168 169 if (cpu_ucode_data == NULL || cpu_ucode_size == 0) { 170 DPRINTF(("%s: no microcode provided\n", __func__)); 171 return; 172 } 173 174 /* 175 * Grab a mutex, because we are not allowed to run updates 176 * simultaneously on HT siblings. 177 */ 178 mtx_enter(&cpu_ucode_mtx); 179 180 CPUID(1, sig, ebx, ecx, edx); 181 182 level = rdmsr(MSR_PATCH_LEVEL); 183 DPRINTF(("%s: cur patch level 0x%llx\n", __func__, level)); 184 185 memcpy(&magic, cpu_ucode_data, 4); 186 if (magic != AMD_MAGIC) { 187 DPRINTF(("%s: bad magic %x\n", __func__, magic)); 188 goto out; 189 } 190 191 memcpy(&tlen, &cpu_ucode_data[8], 4); 192 193 /* find equivalence id matching our cpu signature */ 194 for (i = 12; i < 12 + tlen;) { 195 struct amd_equiv ae; 196 if (i + sizeof(ae) > cpu_ucode_size) { 197 DPRINTF(("%s: truncated etable\n", __func__)); 198 goto out; 199 } 200 memcpy(&ae, &cpu_ucode_data[i], sizeof(ae)); 201 i += sizeof(ae); 202 if (ae.id == sig) 203 eid = ae.eid; 204 } 205 206 /* look for newer patch with the equivalence id */ 207 while (i < cpu_ucode_size) { 208 struct amd_patch ap; 209 if (i + sizeof(ap) > cpu_ucode_size) { 210 DPRINTF(("%s: truncated ptable\n", __func__)); 211 goto out; 212 } 213 memcpy(&ap, &cpu_ucode_data[i], sizeof(ap)); 214 if (ap.type == 1 && ap.eid == eid && ap.level > level) { 215 start = (uint64_t)&cpu_ucode_data[i + 8]; 216 patch_len = ap.len; 217 } 218 if (i + ap.len + 8 > cpu_ucode_size) { 219 DPRINTF(("%s: truncated patch\n", __func__)); 220 goto out; 221 } 222 i += ap.len + 8; 223 } 224 225 if (start != 0) { 226 /* alignment required on fam 15h */ 227 uint8_t *p = malloc(patch_len, M_TEMP, M_NOWAIT); 228 if (p == NULL) 229 goto out; 230 memcpy(p, (uint8_t *)start, patch_len); 231 start = (uint64_t)p; 232 wrmsr(MSR_PATCH_LOADER, start); 233 level = rdmsr(MSR_PATCH_LEVEL); 234 DPRINTF(("%s: new patch level 0x%llx\n", __func__, level)); 235 free(p, M_TEMP, patch_len); 236 } 237out: 238 mtx_leave(&cpu_ucode_mtx); 239} 240 241void 242cpu_ucode_intel_apply(struct cpu_info *ci) 243{ 244 struct intel_ucode_header *update; 245 uint32_t old_rev, new_rev; 246 paddr_t data; 247 248 if (cpu_ucode_data == NULL || cpu_ucode_size == 0) { 249 DPRINTF(("%s: no microcode provided\n", __func__)); 250 return; 251 } 252 253 /* 254 * Grab a mutex, because we are not allowed to run updates 255 * simultaneously on HT siblings. 256 */ 257 mtx_enter(&cpu_ucode_mtx); 258 259 old_rev = cpu_ucode_intel_rev(); 260 update = cpu_ucode_intel_applied; 261 if (update == NULL) 262 update = cpu_ucode_intel_find(cpu_ucode_data, 263 cpu_ucode_size, old_rev); 264 if (update == NULL) { 265 DPRINTF(("%s: no microcode update found\n", __func__)); 266 goto out; 267 } 268 if (update->update_revision == old_rev) { 269 DPRINTF(("%s: microcode already up-to-date\n", __func__)); 270 goto out; 271 } 272 273 /* Apply microcode. */ 274 data = (paddr_t)update; 275 data += sizeof(struct intel_ucode_header); 276 wbinvd(); 277 wrmsr(MSR_BIOS_UPDT_TRIG, data); 278 279 new_rev = cpu_ucode_intel_rev(); 280 if (new_rev != old_rev) { 281 DPRINTF(("%s: microcode updated cpu %ld rev %#x->%#x (%x)\n", 282 __func__, ci->ci_cpuid, old_rev, new_rev, update->date)); 283 if (cpu_ucode_intel_applied == NULL) 284 cpu_ucode_intel_applied = update; 285 } else { 286 DPRINTF(("%s: microcode update failed cpu %ld rev %#x->%#x != %#x\n", 287 __func__, ci->ci_cpuid, old_rev, update->update_revision, new_rev)); 288 } 289 290out: 291 mtx_leave(&cpu_ucode_mtx); 292} 293 294struct intel_ucode_header * 295cpu_ucode_intel_find(char *data, size_t left, uint32_t current) 296{ 297 uint64_t platform_id = (rdmsr(MSR_PLATFORM_ID) >> 50) & 7; 298 uint32_t sig, dummy1, dummy2, dummy3; 299 uint32_t mask = 1UL << platform_id; 300 struct intel_ucode_header *hdr; 301 uint32_t total_size; 302 int n = 0; 303 304 CPUID(1, sig, dummy1, dummy2, dummy3); 305 306 while (left > 0) { 307 hdr = (struct intel_ucode_header *)data; 308 if (left < sizeof(struct intel_ucode_header)) { 309 DPRINTF(("%s:%d: not enough data for header (%zd)\n", 310 __func__, n, left)); 311 break; 312 } 313 /* 314 * Older microcode has an empty length. In that case we 315 * have to use the default length of 2000. 316 */ 317 if (hdr->data_size) 318 total_size = hdr->total_size; 319 else 320 total_size = INTEL_UCODE_DEFAULT_DATA_SIZE + 321 sizeof(struct intel_ucode_header); 322 if (total_size > left) { 323 DPRINTF(("%s:%d: size %u out of range (%zd)\n", 324 __func__, n, total_size, left)); 325 break; 326 } 327 if (cpu_ucode_intel_verify(hdr)) { 328 DPRINTF(("%s:%d: broken data\n", __func__, n)); 329 break; 330 } 331 if (cpu_ucode_intel_match(hdr, sig, mask, current)) 332 return hdr; 333 n++; 334 left -= total_size; 335 data += total_size; 336 } 337 DPRINTF(("%s: no update found\n", __func__)); 338 return NULL; 339} 340 341int 342cpu_ucode_intel_verify(struct intel_ucode_header *hdr) 343{ 344 uint32_t *data = (uint32_t *)hdr; 345 size_t total_size; 346 uint32_t sum; 347 int i; 348 349 CTASSERT(sizeof(struct intel_ucode_header) == 48); 350 351 if ((paddr_t)data % 16 != 0) { 352 DPRINTF(("%s: misaligned microcode update\n", __func__)); 353 return 1; 354 } 355 if (hdr->loader_rev != 1) { 356 DPRINTF(("%s: unsupported loader rev\n", __func__)); 357 return 1; 358 } 359 360 if (hdr->data_size) 361 total_size = hdr->total_size; 362 else 363 total_size = INTEL_UCODE_DEFAULT_DATA_SIZE + 364 sizeof(struct intel_ucode_header); 365 if (total_size % 4 != 0) { 366 DPRINTF(("%s: inconsistent size\n", __func__)); 367 return 1; 368 } 369 370 sum = 0; 371 for (i = 0; i < total_size / 4; i++) 372 sum += data[i]; 373 if (sum != 0) { 374 DPRINTF(("%s: wrong checksum (%#x)\n", __func__, sum)); 375 return 1; 376 } 377 378 return 0; 379} 380 381int 382cpu_ucode_intel_match(struct intel_ucode_header *hdr, 383 uint32_t processor_sig, uint32_t processor_mask, 384 uint32_t ucode_revision) 385{ 386 struct intel_ucode_ext_sig_header *ehdr; 387 struct intel_ucode_ext_sig *esig; 388 uint32_t data_size, total_size; 389 unsigned i; 390 391 data_size = hdr->data_size; 392 total_size = hdr->total_size; 393 394 /* 395 * Older microcode has an empty length. In that case we 396 * have to use the default length of 2000. 397 */ 398 if (!data_size) { 399 data_size = INTEL_UCODE_DEFAULT_DATA_SIZE; 400 total_size = INTEL_UCODE_DEFAULT_DATA_SIZE + 401 sizeof(struct intel_ucode_header); 402 } 403 404 if (ucode_revision > hdr->update_revision) 405 return 0; 406 if (hdr->processor_sig == processor_sig && 407 (hdr->processor_flags & processor_mask)) 408 return 1; 409 if (total_size <= sizeof(struct intel_ucode_header) + 410 data_size + sizeof(struct intel_ucode_ext_sig_header)) 411 return 0; 412 413 ehdr = (void *)((char *)hdr + sizeof(struct intel_ucode_header) + 414 data_size); 415 esig = (void *)&ehdr[1]; 416 for (i = 0; i < ehdr->ext_sig_count; i++) { 417 if (esig[i].processor_sig == processor_sig && 418 (esig[i].processor_flags & processor_mask)) 419 return 1; 420 } 421 422 return 0; 423} 424 425uint32_t 426cpu_ucode_intel_rev(void) 427{ 428 uint32_t eax, ebx, ecx, edx; 429 uint64_t rev; 430 431 wrmsr(MSR_BIOS_SIGN, 0); 432 CPUID(1, eax, ebx, ecx, edx); 433 rev = rdmsr(MSR_BIOS_SIGN); 434 return rev >> 32; 435} 436