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