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
ucode_select_intel(cpu_t * cp)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
ucode_capable_intel(cpu_t * cp)72 ucode_capable_intel(cpu_t *cp)
73 {
74 	return (cpuid_getfamily(cp) >= 6);
75 }
76 
77 static void
ucode_file_reset_intel(processorid_t id)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
ucode_match_intel(int cpi_sig,cpu_ucode_info_t * uinfop,ucode_header_intel_t * uhp,ucode_ext_table_intel_t * uetp)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
ucode_locate_intel(cpu_t * cp,cpu_ucode_info_t * uinfop)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
ucode_read_rev_intel(cpu_ucode_info_t * uinfop)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
ucode_load_intel(cpu_ucode_info_t * uinfop)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
ucode_extract_intel(ucode_update_t * uusp,uint8_t * ucodep,int size)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