1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 27 * Copyright (c) 2018, Joyent, Inc. 28 * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. 29 * Copyright 2024 Oxide Computer Company 30 */ 31 32 #include <sys/stdbool.h> 33 #include <sys/cmn_err.h> 34 #include <sys/controlregs.h> 35 #include <sys/kobj.h> 36 #include <sys/kobj_impl.h> 37 #include <sys/ontrap.h> 38 #include <sys/sysmacros.h> 39 #include <sys/systm.h> 40 #include <sys/ucode.h> 41 #include <sys/ucode_amd.h> 42 #include <ucode/ucode_errno.h> 43 #include <ucode/ucode_utils_amd.h> 44 #include <sys/x86_archext.h> 45 46 extern void *ucode_zalloc(size_t); 47 extern void ucode_free(void *, size_t); 48 extern const char *ucode_path(void); 49 extern int ucode_force_update; 50 extern bool ucode_use_kmem; 51 52 static ucode_file_amd_t *amd_ucodef; 53 static ucode_eqtbl_amd_t *ucode_eqtbl_amd; 54 static uint_t ucode_eqtbl_amd_entries; 55 56 /* 57 * Check whether this module can be used for microcode updates on this 58 * platform. 59 */ 60 static bool 61 ucode_select_amd(cpu_t *cp) 62 { 63 if ((get_hwenv() & HW_VIRTUAL) != 0) 64 return (false); 65 66 return (cpuid_getvendor(cp) == X86_VENDOR_AMD); 67 } 68 69 /* 70 * Check whether or not a processor is capable of microcode operations 71 * 72 * At this point we only support microcode update for: 73 * - AMD processors family 0x10 and above. 74 */ 75 static bool 76 ucode_capable_amd(cpu_t *cp) 77 { 78 return (cpuid_getfamily(cp) >= 0x10); 79 } 80 81 /* 82 * Called when it is no longer necessary to keep the microcode around, 83 * or when the cached microcode doesn't match the CPU being processed. 84 */ 85 static void 86 ucode_file_reset_amd(void) 87 { 88 if (amd_ucodef == NULL) 89 return; 90 91 ucode_free(amd_ucodef, sizeof (*amd_ucodef)); 92 amd_ucodef = NULL; 93 } 94 95 /* 96 * Find the equivalent CPU id in the equivalence table. 97 */ 98 static ucode_errno_t 99 ucode_equiv_cpu_amd(cpu_t *cp, uint16_t *eq_sig) 100 { 101 char *name = NULL; 102 int cpi_sig = cpuid_getsig(cp); 103 ucode_errno_t ret = EM_OK; 104 105 if (ucode_eqtbl_amd == NULL) { 106 name = ucode_zalloc(MAXPATHLEN); 107 if (name == NULL) 108 return (EM_NOMEM); 109 110 (void) snprintf(name, MAXPATHLEN, "%s/%s/%s", 111 ucode_path(), cpuid_getvendorstr(cp), 112 UCODE_AMD_EQUIVALENCE_TABLE_NAME); 113 } 114 115 if (!ucode_use_kmem) { 116 /* 117 * No kmem_zalloc() etc. available yet. 118 */ 119 ucode_eqtbl_amd_t eqtbl; 120 int count, offset = 0; 121 intptr_t fd; 122 123 ASSERT3P(name, !=, NULL); 124 125 if ((fd = kobj_open(name)) == -1) { 126 ret = EM_OPENFILE; 127 goto out; 128 } 129 do { 130 count = kobj_read(fd, (int8_t *)&eqtbl, 131 sizeof (eqtbl), offset); 132 if (count != sizeof (eqtbl)) { 133 (void) kobj_close(fd); 134 ret = EM_HIGHERREV; 135 goto out; 136 } 137 offset += count; 138 } while (eqtbl.ue_inst_cpu != 0 && 139 eqtbl.ue_inst_cpu != cpi_sig); 140 (void) kobj_close(fd); 141 *eq_sig = eqtbl.ue_equiv_cpu; 142 } else { 143 ucode_eqtbl_amd_t *eqtbl; 144 145 /* 146 * If not already done, load the equivalence table. 147 */ 148 if (ucode_eqtbl_amd == NULL) { 149 struct _buf *eq; 150 uint64_t size; 151 int count; 152 153 ASSERT3P(name, !=, NULL); 154 155 if ((eq = kobj_open_file(name)) == (struct _buf *)-1) { 156 ret = EM_OPENFILE; 157 goto out; 158 } 159 160 if (kobj_get_filesize(eq, &size) < 0) { 161 kobj_close_file(eq); 162 ret = EM_OPENFILE; 163 goto out; 164 } 165 166 if (size == 0 || 167 size % sizeof (*ucode_eqtbl_amd) != 0) { 168 kobj_close_file(eq); 169 ret = EM_HIGHERREV; 170 goto out; 171 } 172 173 ucode_eqtbl_amd = kmem_zalloc(size, KM_NOSLEEP); 174 if (ucode_eqtbl_amd == NULL) { 175 kobj_close_file(eq); 176 ret = EM_NOMEM; 177 goto out; 178 } 179 count = kobj_read_file(eq, (char *)ucode_eqtbl_amd, 180 size, 0); 181 kobj_close_file(eq); 182 183 if (count != size) { 184 ucode_eqtbl_amd_entries = 0; 185 ret = EM_FILESIZE; 186 goto out; 187 } 188 189 ucode_eqtbl_amd_entries = 190 size / sizeof (*ucode_eqtbl_amd); 191 } 192 193 eqtbl = ucode_eqtbl_amd; 194 *eq_sig = 0; 195 for (uint_t i = 0; i < ucode_eqtbl_amd_entries; i++, eqtbl++) { 196 if (eqtbl->ue_inst_cpu == 0) { 197 /* End of table */ 198 ret = EM_HIGHERREV; 199 goto out; 200 } 201 if (eqtbl->ue_inst_cpu == cpi_sig) { 202 *eq_sig = eqtbl->ue_equiv_cpu; 203 ret = EM_OK; 204 goto out; 205 } 206 } 207 /* 208 * No equivalent CPU id found, assume outdated microcode file. 209 */ 210 ret = EM_HIGHERREV; 211 } 212 213 out: 214 ucode_free(name, MAXPATHLEN); 215 216 return (ret); 217 } 218 219 static ucode_errno_t 220 ucode_match_amd(uint16_t eq_sig, cpu_ucode_info_t *uinfop, 221 ucode_file_amd_t *ucodefp, int size) 222 { 223 ucode_header_amd_t *uh; 224 225 if (ucodefp == NULL || size < sizeof (ucode_header_amd_t)) 226 return (EM_NOMATCH); 227 228 uh = &ucodefp->uf_header; 229 230 /* 231 * Don't even think about loading patches that would require code 232 * execution. Does not apply to patches for family 0x14 and beyond. 233 */ 234 if (uh->uh_cpu_rev < 0x5000 && 235 size > offsetof(ucode_file_amd_t, uf_code_present) && 236 ucodefp->uf_code_present) { 237 return (EM_NOMATCH); 238 } 239 240 if (eq_sig != uh->uh_cpu_rev) 241 return (EM_NOMATCH); 242 243 if (uh->uh_nb_id) { 244 cmn_err(CE_WARN, "ignoring northbridge-specific ucode: " 245 "chipset id %x, revision %x", uh->uh_nb_id, uh->uh_nb_rev); 246 return (EM_NOMATCH); 247 } 248 249 if (uh->uh_sb_id) { 250 cmn_err(CE_WARN, "ignoring southbridge-specific ucode: " 251 "chipset id %x, revision %x", uh->uh_sb_id, uh->uh_sb_rev); 252 return (EM_NOMATCH); 253 } 254 255 if (uh->uh_patch_id <= uinfop->cui_rev && !ucode_force_update) 256 return (EM_HIGHERREV); 257 258 return (EM_OK); 259 } 260 261 /* 262 * Copy the given ucode into cpu_ucode_info_t in preparation for loading onto 263 * the corresponding CPU via ucode_load_amd(). 264 */ 265 static ucode_errno_t 266 ucode_copy_amd(const ucode_file_amd_t *ucodefp, cpu_ucode_info_t *uinfop) 267 { 268 ASSERT3P(uinfop->cui_pending_ucode, ==, NULL); 269 270 uinfop->cui_pending_ucode = ucode_zalloc(sizeof (*ucodefp)); 271 if (uinfop->cui_pending_ucode == NULL) 272 return (EM_NOMEM); 273 memcpy(uinfop->cui_pending_ucode, ucodefp, sizeof (*ucodefp)); 274 275 uinfop->cui_pending_size = sizeof (*ucodefp); 276 uinfop->cui_pending_rev = ucodefp->uf_header.uh_patch_id; 277 278 return (EM_OK); 279 } 280 281 /* 282 * Populate the ucode file structure from microcode file corresponding to 283 * this CPU, if exists. 284 * 285 * Return EM_OK on success, corresponding error code on failure. 286 */ 287 static ucode_errno_t 288 ucode_locate_amd(cpu_t *cp, cpu_ucode_info_t *uinfop) 289 { 290 ucode_file_amd_t *ucodefp = amd_ucodef; 291 uint16_t eq_sig; 292 int rc; 293 294 /* get equivalent CPU id */ 295 eq_sig = 0; 296 if ((rc = ucode_equiv_cpu_amd(cp, &eq_sig)) != EM_OK) 297 return (rc); 298 299 /* 300 * Allocate a buffer for the microcode patch. If the buffer has been 301 * allocated before, check for a matching microcode to avoid loading 302 * the file again. 303 */ 304 305 if (ucodefp == NULL) { 306 ucodefp = ucode_zalloc(sizeof (*ucodefp)); 307 } else if (ucode_match_amd(eq_sig, uinfop, ucodefp, sizeof (*ucodefp)) 308 == EM_OK) { 309 return (ucode_copy_amd(ucodefp, uinfop)); 310 } 311 312 if (ucodefp == NULL) 313 return (EM_NOMEM); 314 315 amd_ucodef = ucodefp; 316 317 /* 318 * Find the patch for this CPU. The patch files are named XXXX-YY, where 319 * XXXX is the equivalent CPU id and YY is the running patch number. 320 * Patches specific to certain chipsets are guaranteed to have lower 321 * numbers than less specific patches, so we can just load the first 322 * patch that matches. 323 */ 324 325 for (uint_t i = 0; i < 0xff; i++) { 326 char name[MAXPATHLEN]; 327 intptr_t fd; 328 int count; 329 330 (void) snprintf(name, MAXPATHLEN, "%s/%s/%04X-%02X", 331 ucode_path(), cpuid_getvendorstr(cp), eq_sig, i); 332 if ((fd = kobj_open(name)) == -1) 333 return (EM_NOMATCH); 334 count = kobj_read(fd, (char *)ucodefp, sizeof (*ucodefp), 0); 335 (void) kobj_close(fd); 336 337 if (ucode_match_amd(eq_sig, uinfop, ucodefp, count) == EM_OK) { 338 return (ucode_copy_amd(ucodefp, uinfop)); 339 } 340 } 341 return (EM_NOMATCH); 342 } 343 344 static void 345 ucode_read_rev_amd(cpu_ucode_info_t *uinfop) 346 { 347 uinfop->cui_rev = rdmsr(MSR_AMD_PATCHLEVEL); 348 } 349 350 static void 351 ucode_load_amd(cpu_ucode_info_t *uinfop) 352 { 353 ucode_file_amd_t *ucodefp = uinfop->cui_pending_ucode; 354 on_trap_data_t otd; 355 356 VERIFY3P(ucodefp, !=, NULL); 357 VERIFY3U(ucodefp->uf_header.uh_patch_id, ==, uinfop->cui_pending_rev); 358 359 kpreempt_disable(); 360 if (on_trap(&otd, OT_DATA_ACCESS)) { 361 no_trap(); 362 goto out; 363 } 364 wrmsr(MSR_AMD_PATCHLOADER, (uintptr_t)ucodefp); 365 no_trap(); 366 367 out: 368 kpreempt_enable(); 369 } 370 371 static ucode_errno_t 372 ucode_extract_amd(ucode_update_t *uusp, uint8_t *ucodep, int size) 373 { 374 uint32_t *ptr = (uint32_t *)ucodep; 375 ucode_eqtbl_amd_t *eqtbl; 376 ucode_file_amd_t *ufp; 377 int count; 378 int higher = 0; 379 ucode_errno_t rc = EM_NOMATCH; 380 uint16_t eq_sig; 381 382 /* skip over magic number & equivalence table header */ 383 ptr += 2; size -= 8; 384 385 count = *ptr++; size -= 4; 386 for (eqtbl = (ucode_eqtbl_amd_t *)ptr; 387 eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != uusp->sig; 388 eqtbl++) 389 ; 390 391 eq_sig = eqtbl->ue_equiv_cpu; 392 393 /* No equivalent CPU id found, assume outdated microcode file. */ 394 if (eq_sig == 0) 395 return (EM_HIGHERREV); 396 397 /* Use the first microcode patch that matches. */ 398 do { 399 ptr += count >> 2; size -= count; 400 401 if (!size) 402 return (higher ? EM_HIGHERREV : EM_NOMATCH); 403 404 ptr++; size -= 4; 405 count = *ptr++; size -= 4; 406 ufp = (ucode_file_amd_t *)ptr; 407 408 rc = ucode_match_amd(eq_sig, &uusp->info, ufp, count); 409 if (rc == EM_HIGHERREV) 410 higher = 1; 411 } while (rc != EM_OK); 412 413 uusp->ucodep = (uint8_t *)ufp; 414 uusp->usize = count; 415 uusp->expected_rev = ufp->uf_header.uh_patch_id; 416 417 return (EM_OK); 418 } 419 420 static const ucode_source_t ucode_amd = { 421 .us_name = "AMD microcode updater", 422 .us_write_msr = MSR_AMD_PATCHLOADER, 423 .us_invalidate = false, 424 .us_select = ucode_select_amd, 425 .us_capable = ucode_capable_amd, 426 .us_file_reset = ucode_file_reset_amd, 427 .us_read_rev = ucode_read_rev_amd, 428 .us_load = ucode_load_amd, 429 .us_validate = ucode_validate_amd, 430 .us_extract = ucode_extract_amd, 431 .us_locate = ucode_locate_amd 432 }; 433 UCODE_SOURCE(ucode_amd); 434