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_intel.h> 41 #include <ucode/ucode_errno.h> 42 #include <ucode/ucode_utils_intel.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_intel_t intel_ucodef; 51 52 /* 53 * Check whether this module can be used for microcode updates on this 54 * platform. 55 */ 56 static bool 57 ucode_select_intel(cpu_t *cp) 58 { 59 if ((get_hwenv() & HW_VIRTUAL) != 0) 60 return (false); 61 62 return (cpuid_getvendor(cp) == X86_VENDOR_Intel); 63 } 64 65 /* 66 * Check whether or not a processor is capable of microcode operations 67 * 68 * At this point we only support microcode update for: 69 * - Intel processors family 6 and above. 70 */ 71 static bool 72 ucode_capable_intel(cpu_t *cp) 73 { 74 return (cpuid_getfamily(cp) >= 6); 75 } 76 77 static void 78 ucode_file_reset_intel(processorid_t id) 79 { 80 ucode_file_intel_t *ucodefp = &intel_ucodef; 81 int total_size, body_size; 82 83 if (ucodefp->uf_header == NULL) 84 return; 85 86 total_size = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size); 87 body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size); 88 89 if (ucodefp->uf_body != NULL) { 90 ucode_free(id, ucodefp->uf_body, body_size); 91 ucodefp->uf_body = NULL; 92 } 93 94 if (ucodefp->uf_ext_table != NULL) { 95 int size = total_size - body_size - UCODE_HEADER_SIZE_INTEL; 96 97 ucode_free(id, ucodefp->uf_ext_table, size); 98 ucodefp->uf_ext_table = NULL; 99 } 100 101 ucode_free(id, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL); 102 ucodefp->uf_header = NULL; 103 } 104 105 /* 106 * Checks if the microcode is for this processor. 107 */ 108 static ucode_errno_t 109 ucode_match_intel(int cpi_sig, cpu_ucode_info_t *uinfop, 110 ucode_header_intel_t *uhp, ucode_ext_table_intel_t *uetp) 111 { 112 if (uhp == NULL) 113 return (EM_NOMATCH); 114 115 if (UCODE_MATCH_INTEL(cpi_sig, uhp->uh_signature, 116 uinfop->cui_platid, uhp->uh_proc_flags)) { 117 118 if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update) 119 return (EM_HIGHERREV); 120 121 return (EM_OK); 122 } 123 124 if (uetp != NULL) { 125 for (uint_t i = 0; i < uetp->uet_count; i++) { 126 ucode_ext_sig_intel_t *uesp; 127 128 uesp = &uetp->uet_ext_sig[i]; 129 130 if (UCODE_MATCH_INTEL(cpi_sig, uesp->ues_signature, 131 uinfop->cui_platid, uesp->ues_proc_flags)) { 132 133 if (uinfop->cui_rev >= uhp->uh_rev && 134 !ucode_force_update) 135 return (EM_HIGHERREV); 136 137 return (EM_OK); 138 } 139 } 140 } 141 142 return (EM_NOMATCH); 143 } 144 145 static ucode_errno_t 146 ucode_locate_intel(cpu_t *cp, cpu_ucode_info_t *uinfop) 147 { 148 char name[MAXPATHLEN]; 149 intptr_t fd; 150 int count; 151 int header_size = UCODE_HEADER_SIZE_INTEL; 152 int cpi_sig = cpuid_getsig(cp); 153 ucode_errno_t rc = EM_OK; 154 ucode_file_intel_t *ucodefp = &intel_ucodef; 155 156 /* 157 * If the microcode matches the CPU we are processing, use it. 158 */ 159 if (ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header, 160 ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) { 161 return (EM_OK); 162 } 163 164 /* 165 * Look for microcode file with the right name. 166 */ 167 (void) snprintf(name, MAXPATHLEN, "%s/%s/%08X-%02X", 168 ucode_path(), cpuid_getvendorstr(cp), cpi_sig, 169 uinfop->cui_platid); 170 if ((fd = kobj_open(name)) == -1) { 171 return (EM_OPENFILE); 172 } 173 174 /* 175 * We found a microcode file for the CPU we are processing, 176 * reset the microcode data structure and read in the new 177 * file. 178 */ 179 ucode_file_reset_intel(cp->cpu_id); 180 181 ucodefp->uf_header = ucode_zalloc(cp->cpu_id, header_size); 182 if (ucodefp->uf_header == NULL) 183 return (EM_NOMEM); 184 185 count = kobj_read(fd, (char *)ucodefp->uf_header, header_size, 0); 186 187 switch (count) { 188 case UCODE_HEADER_SIZE_INTEL: { 189 190 ucode_header_intel_t *uhp = ucodefp->uf_header; 191 uint32_t offset = header_size; 192 int total_size, body_size, ext_size; 193 uint32_t sum = 0; 194 195 /* 196 * Make sure that the header contains valid fields. 197 */ 198 if ((rc = ucode_header_validate_intel(uhp)) == EM_OK) { 199 total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 200 body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 201 ucodefp->uf_body = ucode_zalloc(cp->cpu_id, body_size); 202 if (ucodefp->uf_body == NULL) { 203 rc = EM_NOMEM; 204 break; 205 } 206 207 if (kobj_read(fd, (char *)ucodefp->uf_body, 208 body_size, offset) != body_size) 209 rc = EM_FILESIZE; 210 } 211 212 if (rc) 213 break; 214 215 sum = ucode_checksum_intel(0, header_size, 216 (uint8_t *)ucodefp->uf_header); 217 if (ucode_checksum_intel(sum, body_size, ucodefp->uf_body)) { 218 rc = EM_CHECKSUM; 219 break; 220 } 221 222 /* 223 * Check to see if there is extended signature table. 224 */ 225 offset = body_size + header_size; 226 ext_size = total_size - offset; 227 228 if (ext_size <= 0) 229 break; 230 231 ucodefp->uf_ext_table = ucode_zalloc(cp->cpu_id, ext_size); 232 if (ucodefp->uf_ext_table == NULL) { 233 rc = EM_NOMEM; 234 break; 235 } 236 237 if (kobj_read(fd, (char *)ucodefp->uf_ext_table, 238 ext_size, offset) != ext_size) { 239 rc = EM_FILESIZE; 240 } else if (ucode_checksum_intel(0, ext_size, 241 (uint8_t *)(ucodefp->uf_ext_table))) { 242 rc = EM_EXTCHECKSUM; 243 } else { 244 int i; 245 246 for (i = 0; i < ucodefp->uf_ext_table->uet_count; i++) { 247 ucode_ext_sig_intel_t *sig; 248 249 sig = &ucodefp->uf_ext_table->uet_ext_sig[i]; 250 251 if (ucode_checksum_intel_extsig(uhp, 252 sig) != 0) { 253 rc = EM_SIGCHECKSUM; 254 break; 255 } 256 } 257 } 258 break; 259 } 260 261 default: 262 rc = EM_FILESIZE; 263 break; 264 } 265 266 kobj_close(fd); 267 268 if (rc != EM_OK) 269 return (rc); 270 271 rc = ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header, 272 ucodefp->uf_ext_table); 273 274 return (rc); 275 } 276 277 static void 278 ucode_read_rev_intel(cpu_ucode_info_t *uinfop) 279 { 280 struct cpuid_regs crs; 281 282 /* 283 * The Intel 64 and IA-32 Architecture Software Developer's Manual 284 * recommends that MSR_INTC_UCODE_REV be loaded with 0 first, then 285 * execute cpuid to guarantee the correct reading of this register. 286 */ 287 wrmsr(MSR_INTC_UCODE_REV, 0); 288 (void) __cpuid_insn(&crs); 289 uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT); 290 291 /* 292 * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon 293 * (Family 6, model 5 and above) and all processors after. 294 */ 295 if ((cpuid_getmodel(CPU) >= 5 || cpuid_getfamily(CPU) > 6)) { 296 uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >> 297 INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK); 298 } 299 } 300 301 static uint32_t 302 ucode_load_intel(cpu_ucode_info_t *uinfop) 303 { 304 ucode_file_intel_t *ucodefp = &intel_ucodef; 305 306 kpreempt_disable(); 307 /* 308 * On some platforms a cache invalidation is required for the 309 * ucode update to be successful due to the parts of the 310 * processor that the microcode is updating. 311 */ 312 invalidate_cache(); 313 wrmsr(MSR_INTC_UCODE_WRITE, (uintptr_t)ucodefp->uf_body); 314 ucode_read_rev_intel(uinfop); 315 kpreempt_enable(); 316 317 return (ucodefp->uf_header->uh_rev); 318 } 319 320 static ucode_errno_t 321 ucode_extract_intel(ucode_update_t *uusp, uint8_t *ucodep, int size) 322 { 323 uint32_t header_size = UCODE_HEADER_SIZE_INTEL; 324 int remaining; 325 int found = 0; 326 ucode_errno_t search_rc = EM_NOMATCH; /* search result */ 327 328 /* 329 * Go through the whole buffer in case there are 330 * multiple versions of matching microcode for this 331 * processor. 332 */ 333 for (remaining = size; remaining > 0; ) { 334 int total_size, body_size, ext_size; 335 uint8_t *curbuf = &ucodep[size - remaining]; 336 ucode_header_intel_t *uhp = (ucode_header_intel_t *)curbuf; 337 ucode_ext_table_intel_t *uetp = NULL; 338 ucode_errno_t tmprc; 339 340 total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 341 body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 342 ext_size = total_size - (header_size + body_size); 343 344 if (ext_size > 0) 345 uetp = (ucode_ext_table_intel_t *) 346 &curbuf[header_size + body_size]; 347 348 tmprc = ucode_match_intel(uusp->sig, &uusp->info, uhp, uetp); 349 350 /* 351 * Since we are searching through a big file 352 * containing microcode for pretty much all the 353 * processors, we are bound to get EM_NOMATCH 354 * at one point. However, if we return 355 * EM_NOMATCH to users, it will really confuse 356 * them. Therefore, if we ever find a match of 357 * a lower rev, we will set return code to 358 * EM_HIGHERREV. 359 */ 360 if (tmprc == EM_HIGHERREV) 361 search_rc = EM_HIGHERREV; 362 363 if (tmprc == EM_OK && 364 uusp->expected_rev < uhp->uh_rev) { 365 uusp->ucodep = (uint8_t *)&curbuf[header_size]; 366 uusp->usize = 367 UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 368 uusp->expected_rev = uhp->uh_rev; 369 found = 1; 370 } 371 372 remaining -= total_size; 373 } 374 375 if (!found) 376 return (search_rc); 377 378 return (EM_OK); 379 } 380 381 static const ucode_source_t ucode_intel = { 382 .us_name = "Intel microcode updater", 383 .us_write_msr = MSR_INTC_UCODE_WRITE, 384 .us_invalidate = true, 385 .us_select = ucode_select_intel, 386 .us_capable = ucode_capable_intel, 387 .us_file_reset = ucode_file_reset_intel, 388 .us_read_rev = ucode_read_rev_intel, 389 .us_load = ucode_load_intel, 390 .us_validate = ucode_validate_intel, 391 .us_extract = ucode_extract_intel, 392 .us_locate = ucode_locate_intel 393 }; 394 UCODE_SOURCE(ucode_intel); 395