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