xref: /titanic_51/usr/src/uts/i86pc/os/microcode.c (revision 2449e17f82f6097fd2c665b64723e31ceecbeca6)
1*2449e17fSsherrym /*
2*2449e17fSsherrym  * CDDL HEADER START
3*2449e17fSsherrym  *
4*2449e17fSsherrym  * The contents of this file are subject to the terms of the
5*2449e17fSsherrym  * Common Development and Distribution License (the "License").
6*2449e17fSsherrym  * You may not use this file except in compliance with the License.
7*2449e17fSsherrym  *
8*2449e17fSsherrym  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2449e17fSsherrym  * or http://www.opensolaris.org/os/licensing.
10*2449e17fSsherrym  * See the License for the specific language governing permissions
11*2449e17fSsherrym  * and limitations under the License.
12*2449e17fSsherrym  *
13*2449e17fSsherrym  * When distributing Covered Code, include this CDDL HEADER in each
14*2449e17fSsherrym  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2449e17fSsherrym  * If applicable, add the following below this CDDL HEADER, with the
16*2449e17fSsherrym  * fields enclosed by brackets "[]" replaced with your own identifying
17*2449e17fSsherrym  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2449e17fSsherrym  *
19*2449e17fSsherrym  * CDDL HEADER END
20*2449e17fSsherrym  */
21*2449e17fSsherrym 
22*2449e17fSsherrym /*
23*2449e17fSsherrym  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*2449e17fSsherrym  * Use is subject to license terms.
25*2449e17fSsherrym  */
26*2449e17fSsherrym 
27*2449e17fSsherrym #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2449e17fSsherrym 
29*2449e17fSsherrym #include <sys/asm_linkage.h>
30*2449e17fSsherrym #include <sys/bootconf.h>
31*2449e17fSsherrym #include <sys/cpuvar.h>
32*2449e17fSsherrym #include <sys/cmn_err.h>
33*2449e17fSsherrym #include <sys/controlregs.h>
34*2449e17fSsherrym #include <sys/debug.h>
35*2449e17fSsherrym #include <sys/kobj.h>
36*2449e17fSsherrym #include <sys/kobj_impl.h>
37*2449e17fSsherrym #include <sys/machsystm.h>
38*2449e17fSsherrym #include <sys/param.h>
39*2449e17fSsherrym #include <sys/machparam.h>
40*2449e17fSsherrym #include <sys/promif.h>
41*2449e17fSsherrym #include <sys/sysmacros.h>
42*2449e17fSsherrym #include <sys/systm.h>
43*2449e17fSsherrym #include <sys/types.h>
44*2449e17fSsherrym #include <sys/thread.h>
45*2449e17fSsherrym #include <sys/ucode.h>
46*2449e17fSsherrym #include <sys/x86_archext.h>
47*2449e17fSsherrym #include <sys/x_call.h>
48*2449e17fSsherrym 
49*2449e17fSsherrym /*
50*2449e17fSsherrym  * Microcode specific information per core
51*2449e17fSsherrym  */
52*2449e17fSsherrym struct cpu_ucode_info {
53*2449e17fSsherrym 	uint32_t	cui_platid;	/* platform id */
54*2449e17fSsherrym 	uint32_t	cui_rev;	/* microcode revision */
55*2449e17fSsherrym };
56*2449e17fSsherrym 
57*2449e17fSsherrym /*
58*2449e17fSsherrym  * Data structure used for xcall
59*2449e17fSsherrym  */
60*2449e17fSsherrym struct ucode_update_struct {
61*2449e17fSsherrym 	uint32_t		sig;	/* signature */
62*2449e17fSsherrym 	struct cpu_ucode_info	info;	/* ucode info */
63*2449e17fSsherrym 	uint32_t		expected_rev;
64*2449e17fSsherrym 	uint32_t		new_rev;
65*2449e17fSsherrym 	uint8_t			*ucodep; /* pointer to ucode body */
66*2449e17fSsherrym };
67*2449e17fSsherrym 
68*2449e17fSsherrym /*
69*2449e17fSsherrym  * mcpu_ucode_info for the boot CPU.  Statically allocated.
70*2449e17fSsherrym  */
71*2449e17fSsherrym static struct cpu_ucode_info cpu_ucode_info0;
72*2449e17fSsherrym 
73*2449e17fSsherrym static ucode_file_t ucodefile = { 0 };
74*2449e17fSsherrym 
75*2449e17fSsherrym static int ucode_capable(cpu_t *);
76*2449e17fSsherrym static void ucode_file_reset(ucode_file_t *, processorid_t);
77*2449e17fSsherrym static ucode_errno_t ucode_match(int, struct cpu_ucode_info *,
78*2449e17fSsherrym     ucode_header_t *, ucode_ext_table_t *);
79*2449e17fSsherrym static ucode_errno_t ucode_locate(cpu_t *, struct cpu_ucode_info *,
80*2449e17fSsherrym     ucode_file_t *);
81*2449e17fSsherrym static void ucode_update_intel(uint8_t *, struct cpu_ucode_info *);
82*2449e17fSsherrym static void ucode_read_rev(struct cpu_ucode_info *);
83*2449e17fSsherrym 
84*2449e17fSsherrym static const char ucode_failure_fmt[] =
85*2449e17fSsherrym 	"cpu%d: failed to update microcode code from version 0x%x to 0x%x\n";
86*2449e17fSsherrym static const char ucode_success_fmt[] =
87*2449e17fSsherrym 	"?cpu%d: microcode code has been updated from version 0x%x to 0x%x\n";
88*2449e17fSsherrym 
89*2449e17fSsherrym /*
90*2449e17fSsherrym  * Force flag.  If set, the first microcode binary that matches
91*2449e17fSsherrym  * signature and platform id will be used for microcode update,
92*2449e17fSsherrym  * regardless of version.  Should only be used for debugging.
93*2449e17fSsherrym  */
94*2449e17fSsherrym int ucode_force_update = 0;
95*2449e17fSsherrym 
96*2449e17fSsherrym /*
97*2449e17fSsherrym  * Allocate space for mcpu_ucode_info in the machcpu structure
98*2449e17fSsherrym  * for all non-boot CPUs.
99*2449e17fSsherrym  */
100*2449e17fSsherrym void
101*2449e17fSsherrym ucode_alloc_space(cpu_t *cp)
102*2449e17fSsherrym {
103*2449e17fSsherrym 	ASSERT(cp->cpu_id != 0);
104*2449e17fSsherrym 	cp->cpu_m.mcpu_ucode_info =
105*2449e17fSsherrym 	    kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP);
106*2449e17fSsherrym }
107*2449e17fSsherrym 
108*2449e17fSsherrym void
109*2449e17fSsherrym ucode_free_space(cpu_t *cp)
110*2449e17fSsherrym {
111*2449e17fSsherrym 	ASSERT(cp->cpu_id != 0);
112*2449e17fSsherrym 	kmem_free(cp->cpu_m.mcpu_ucode_info,
113*2449e17fSsherrym 	    sizeof (*cp->cpu_m.mcpu_ucode_info));
114*2449e17fSsherrym }
115*2449e17fSsherrym 
116*2449e17fSsherrym /*
117*2449e17fSsherrym  * Called when we are done with microcode update on all processors to free up
118*2449e17fSsherrym  * space allocated for the microcode file.
119*2449e17fSsherrym  */
120*2449e17fSsherrym void
121*2449e17fSsherrym ucode_free()
122*2449e17fSsherrym {
123*2449e17fSsherrym 	ucode_file_reset(&ucodefile, -1);
124*2449e17fSsherrym }
125*2449e17fSsherrym 
126*2449e17fSsherrym /*
127*2449e17fSsherrym  * Check whether or not a processor is capable of microcode operations
128*2449e17fSsherrym  * Returns 1 if it is capable, 0 if not.
129*2449e17fSsherrym  */
130*2449e17fSsherrym static int
131*2449e17fSsherrym ucode_capable(cpu_t *cp)
132*2449e17fSsherrym {
133*2449e17fSsherrym 	/*
134*2449e17fSsherrym 	 * At this point we only support microcode update for Intel
135*2449e17fSsherrym 	 * processors family 6 and above.
136*2449e17fSsherrym 	 *
137*2449e17fSsherrym 	 * We also assume that we don't support a mix of Intel and
138*2449e17fSsherrym 	 * AMD processors in the same box.
139*2449e17fSsherrym 	 */
140*2449e17fSsherrym 	if (cpuid_getvendor(cp) != X86_VENDOR_Intel ||
141*2449e17fSsherrym 	    cpuid_getfamily(cp) < 6)
142*2449e17fSsherrym 		return (0);
143*2449e17fSsherrym 	else
144*2449e17fSsherrym 		return (1);
145*2449e17fSsherrym }
146*2449e17fSsherrym 
147*2449e17fSsherrym /*
148*2449e17fSsherrym  * Called when it is no longer necessary to keep the microcode around,
149*2449e17fSsherrym  * or when the cached microcode doesn't match the CPU being processed.
150*2449e17fSsherrym  */
151*2449e17fSsherrym static void
152*2449e17fSsherrym ucode_file_reset(ucode_file_t *ucodefp, processorid_t id)
153*2449e17fSsherrym {
154*2449e17fSsherrym 	int total_size, body_size;
155*2449e17fSsherrym 
156*2449e17fSsherrym 	if (ucodefp == NULL)
157*2449e17fSsherrym 		return;
158*2449e17fSsherrym 
159*2449e17fSsherrym 	total_size = UCODE_TOTAL_SIZE(ucodefp->uf_header.uh_total_size);
160*2449e17fSsherrym 	body_size = UCODE_BODY_SIZE(ucodefp->uf_header.uh_body_size);
161*2449e17fSsherrym 	if (ucodefp->uf_body) {
162*2449e17fSsherrym 		/*
163*2449e17fSsherrym 		 * Space for the boot CPU is allocated with BOP_ALLOC()
164*2449e17fSsherrym 		 * and does not require a free.
165*2449e17fSsherrym 		 */
166*2449e17fSsherrym 		if (id != 0)
167*2449e17fSsherrym 			kmem_free(ucodefp->uf_body, body_size);
168*2449e17fSsherrym 		ucodefp->uf_body = NULL;
169*2449e17fSsherrym 	}
170*2449e17fSsherrym 
171*2449e17fSsherrym 	if (ucodefp->uf_ext_table) {
172*2449e17fSsherrym 		int size = total_size - body_size - UCODE_HEADER_SIZE;
173*2449e17fSsherrym 		/*
174*2449e17fSsherrym 		 * Space for the boot CPU is allocated with BOP_ALLOC()
175*2449e17fSsherrym 		 * and does not require a free.
176*2449e17fSsherrym 		 */
177*2449e17fSsherrym 		if (id != 0)
178*2449e17fSsherrym 			kmem_free(ucodefp->uf_ext_table, size);
179*2449e17fSsherrym 		ucodefp->uf_ext_table = NULL;
180*2449e17fSsherrym 	}
181*2449e17fSsherrym 
182*2449e17fSsherrym 	bzero(&ucodefp->uf_header, UCODE_HEADER_SIZE);
183*2449e17fSsherrym }
184*2449e17fSsherrym 
185*2449e17fSsherrym /*
186*2449e17fSsherrym  * Populate the ucode file structure from microcode file corresponding to
187*2449e17fSsherrym  * this CPU, if exists.
188*2449e17fSsherrym  *
189*2449e17fSsherrym  * Return EM_OK on success, corresponding error code on failure.
190*2449e17fSsherrym  */
191*2449e17fSsherrym static ucode_errno_t
192*2449e17fSsherrym ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
193*2449e17fSsherrym {
194*2449e17fSsherrym 	char		name[MAXPATHLEN];
195*2449e17fSsherrym 	intptr_t	fd;
196*2449e17fSsherrym 	int		count;
197*2449e17fSsherrym 	int		header_size = UCODE_HEADER_SIZE;
198*2449e17fSsherrym 	int		cpi_sig = cpuid_getsig(cp);
199*2449e17fSsherrym 	ucode_errno_t	rc = EM_OK;
200*2449e17fSsherrym 
201*2449e17fSsherrym 	/*
202*2449e17fSsherrym 	 * If the microcode matches the CPU we are processing, use it.
203*2449e17fSsherrym 	 */
204*2449e17fSsherrym 	if (ucode_match(cpi_sig, uinfop, &ucodefp->uf_header,
205*2449e17fSsherrym 	    ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) {
206*2449e17fSsherrym 		return (EM_OK);
207*2449e17fSsherrym 	}
208*2449e17fSsherrym 
209*2449e17fSsherrym 	/*
210*2449e17fSsherrym 	 * Look for microcode file with the right name.
211*2449e17fSsherrym 	 */
212*2449e17fSsherrym 	(void) snprintf(name, MAXPATHLEN, "/%s/%s/%08X-%02X",
213*2449e17fSsherrym 	    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), cpi_sig,
214*2449e17fSsherrym 	    uinfop->cui_platid);
215*2449e17fSsherrym 	if ((fd = kobj_open(name)) == -1) {
216*2449e17fSsherrym 		return (EM_OPENFILE);
217*2449e17fSsherrym 	}
218*2449e17fSsherrym 
219*2449e17fSsherrym 	/*
220*2449e17fSsherrym 	 * We found a microcode file for the CPU we are processing,
221*2449e17fSsherrym 	 * reset the microcode data structure and read in the new
222*2449e17fSsherrym 	 * file.
223*2449e17fSsherrym 	 */
224*2449e17fSsherrym 	ucode_file_reset(ucodefp, cp->cpu_id);
225*2449e17fSsherrym 
226*2449e17fSsherrym 	count = kobj_read(fd, (char *)&ucodefp->uf_header, header_size, 0);
227*2449e17fSsherrym 
228*2449e17fSsherrym 	switch (count) {
229*2449e17fSsherrym 	case UCODE_HEADER_SIZE: {
230*2449e17fSsherrym 
231*2449e17fSsherrym 		ucode_header_t	*uhp = &ucodefp->uf_header;
232*2449e17fSsherrym 		uint32_t	offset = header_size;
233*2449e17fSsherrym 		int		total_size, body_size, ext_size;
234*2449e17fSsherrym 		uint32_t	sum = 0;
235*2449e17fSsherrym 
236*2449e17fSsherrym 		/*
237*2449e17fSsherrym 		 * Make sure that the header contains valid fields.
238*2449e17fSsherrym 		 */
239*2449e17fSsherrym 		if ((rc = ucode_header_validate(uhp)) == EM_OK) {
240*2449e17fSsherrym 			total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size);
241*2449e17fSsherrym 			body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
242*2449e17fSsherrym 			if (cp->cpu_id != 0) {
243*2449e17fSsherrym 				if ((ucodefp->uf_body = kmem_zalloc(body_size,
244*2449e17fSsherrym 				    KM_NOSLEEP)) == NULL) {
245*2449e17fSsherrym 					rc = EM_NOMEM;
246*2449e17fSsherrym 					break;
247*2449e17fSsherrym 				}
248*2449e17fSsherrym 			} else {
249*2449e17fSsherrym 				/*
250*2449e17fSsherrym 				 * BOP_ALLOC() failure results in panic so we
251*2449e17fSsherrym 				 * don't have to check for NULL return.
252*2449e17fSsherrym 				 */
253*2449e17fSsherrym 				ucodefp->uf_body =
254*2449e17fSsherrym 				    (uint8_t *)BOP_ALLOC(bootops,
255*2449e17fSsherrym 				    NULL, body_size, MMU_PAGESIZE);
256*2449e17fSsherrym 			}
257*2449e17fSsherrym 
258*2449e17fSsherrym 			if (kobj_read(fd, (char *)ucodefp->uf_body,
259*2449e17fSsherrym 			    body_size, offset) != body_size)
260*2449e17fSsherrym 				rc = EM_FILESIZE;
261*2449e17fSsherrym 		}
262*2449e17fSsherrym 
263*2449e17fSsherrym 		if (rc)
264*2449e17fSsherrym 			break;
265*2449e17fSsherrym 
266*2449e17fSsherrym 		sum = ucode_checksum(0, header_size,
267*2449e17fSsherrym 		    (uint8_t *)&ucodefp->uf_header);
268*2449e17fSsherrym 		if (ucode_checksum(sum, body_size, ucodefp->uf_body)) {
269*2449e17fSsherrym 			rc = EM_CHECKSUM;
270*2449e17fSsherrym 			break;
271*2449e17fSsherrym 		}
272*2449e17fSsherrym 
273*2449e17fSsherrym 		/*
274*2449e17fSsherrym 		 * Check to see if there is extended signature table.
275*2449e17fSsherrym 		 */
276*2449e17fSsherrym 		offset = body_size + header_size;
277*2449e17fSsherrym 		ext_size = total_size - offset;
278*2449e17fSsherrym 
279*2449e17fSsherrym 		if (ext_size <= 0)
280*2449e17fSsherrym 			break;
281*2449e17fSsherrym 
282*2449e17fSsherrym 		if (cp->cpu_id != 0) {
283*2449e17fSsherrym 			if ((ucodefp->uf_ext_table = kmem_zalloc(ext_size,
284*2449e17fSsherrym 			    KM_NOSLEEP)) == NULL) {
285*2449e17fSsherrym 				rc = EM_NOMEM;
286*2449e17fSsherrym 				break;
287*2449e17fSsherrym 			}
288*2449e17fSsherrym 		} else {
289*2449e17fSsherrym 			/*
290*2449e17fSsherrym 			 * BOP_ALLOC() failure results in panic so we
291*2449e17fSsherrym 			 * don't have to check for NULL return.
292*2449e17fSsherrym 			 */
293*2449e17fSsherrym 			ucodefp->uf_ext_table =
294*2449e17fSsherrym 			    (ucode_ext_table_t *)BOP_ALLOC(bootops, NULL,
295*2449e17fSsherrym 			    ext_size, MMU_PAGESIZE);
296*2449e17fSsherrym 		}
297*2449e17fSsherrym 
298*2449e17fSsherrym 		if (kobj_read(fd, (char *)ucodefp->uf_ext_table,
299*2449e17fSsherrym 		    ext_size, offset) != ext_size) {
300*2449e17fSsherrym 			rc = EM_FILESIZE;
301*2449e17fSsherrym 		} else if (ucode_checksum(0, ext_size,
302*2449e17fSsherrym 		    (uint8_t *)(ucodefp->uf_ext_table))) {
303*2449e17fSsherrym 			rc = EM_CHECKSUM;
304*2449e17fSsherrym 		} else {
305*2449e17fSsherrym 			int i;
306*2449e17fSsherrym 
307*2449e17fSsherrym 			ext_size -= UCODE_EXT_TABLE_SIZE;
308*2449e17fSsherrym 			for (i = 0; i < ucodefp->uf_ext_table->uet_count;
309*2449e17fSsherrym 			    i++) {
310*2449e17fSsherrym 				if (ucode_checksum(0, UCODE_EXT_SIG_SIZE,
311*2449e17fSsherrym 				    (uint8_t *)(&(ucodefp->uf_ext_table->
312*2449e17fSsherrym 				    uet_ext_sig[i])))) {
313*2449e17fSsherrym 					rc = EM_CHECKSUM;
314*2449e17fSsherrym 					break;
315*2449e17fSsherrym 				}
316*2449e17fSsherrym 			}
317*2449e17fSsherrym 		}
318*2449e17fSsherrym 		break;
319*2449e17fSsherrym 	}
320*2449e17fSsherrym 
321*2449e17fSsherrym 	default:
322*2449e17fSsherrym 		rc = EM_FILESIZE;
323*2449e17fSsherrym 		break;
324*2449e17fSsherrym 	}
325*2449e17fSsherrym 
326*2449e17fSsherrym 	kobj_close(fd);
327*2449e17fSsherrym 
328*2449e17fSsherrym 	if (rc != EM_OK)
329*2449e17fSsherrym 		return (rc);
330*2449e17fSsherrym 
331*2449e17fSsherrym 	rc = ucode_match(cpi_sig, uinfop, &ucodefp->uf_header,
332*2449e17fSsherrym 	    ucodefp->uf_ext_table);
333*2449e17fSsherrym 
334*2449e17fSsherrym 	return (rc);
335*2449e17fSsherrym }
336*2449e17fSsherrym 
337*2449e17fSsherrym 
338*2449e17fSsherrym /*
339*2449e17fSsherrym  * Returns 1 if the microcode is for this processor; 0 otherwise.
340*2449e17fSsherrym  */
341*2449e17fSsherrym static ucode_errno_t
342*2449e17fSsherrym ucode_match(int cpi_sig, struct cpu_ucode_info *uinfop,
343*2449e17fSsherrym     ucode_header_t *uhp, ucode_ext_table_t *uetp)
344*2449e17fSsherrym {
345*2449e17fSsherrym 	ASSERT(uhp);
346*2449e17fSsherrym 
347*2449e17fSsherrym 	if (UCODE_MATCH(cpi_sig, uhp->uh_signature,
348*2449e17fSsherrym 	    uinfop->cui_platid, uhp->uh_proc_flags)) {
349*2449e17fSsherrym 
350*2449e17fSsherrym 		if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update)
351*2449e17fSsherrym 			return (EM_HIGHERREV);
352*2449e17fSsherrym 
353*2449e17fSsherrym 		return (EM_OK);
354*2449e17fSsherrym 	}
355*2449e17fSsherrym 
356*2449e17fSsherrym 	if (uetp != NULL) {
357*2449e17fSsherrym 		int i;
358*2449e17fSsherrym 
359*2449e17fSsherrym 		for (i = 0; i < uetp->uet_count; i++) {
360*2449e17fSsherrym 			ucode_ext_sig_t *uesp;
361*2449e17fSsherrym 
362*2449e17fSsherrym 			uesp = &uetp->uet_ext_sig[i];
363*2449e17fSsherrym 
364*2449e17fSsherrym 			if (UCODE_MATCH(cpi_sig, uesp->ues_signature,
365*2449e17fSsherrym 			    uinfop->cui_platid, uesp->ues_proc_flags)) {
366*2449e17fSsherrym 
367*2449e17fSsherrym 				if (uinfop->cui_rev >= uhp->uh_rev &&
368*2449e17fSsherrym 				    !ucode_force_update)
369*2449e17fSsherrym 					return (EM_HIGHERREV);
370*2449e17fSsherrym 
371*2449e17fSsherrym 				return (EM_OK);
372*2449e17fSsherrym 			}
373*2449e17fSsherrym 		}
374*2449e17fSsherrym 	}
375*2449e17fSsherrym 
376*2449e17fSsherrym 	return (EM_NOMATCH);
377*2449e17fSsherrym }
378*2449e17fSsherrym 
379*2449e17fSsherrym /*ARGSUSED*/
380*2449e17fSsherrym static int
381*2449e17fSsherrym ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)
382*2449e17fSsherrym {
383*2449e17fSsherrym 	struct ucode_update_struct *uusp = (struct ucode_update_struct *)arg1;
384*2449e17fSsherrym 	struct cpu_ucode_info *uinfop = CPU->cpu_m.mcpu_ucode_info;
385*2449e17fSsherrym 
386*2449e17fSsherrym 	ASSERT(uusp->ucodep);
387*2449e17fSsherrym 
388*2449e17fSsherrym 	/*
389*2449e17fSsherrym 	 * Check one more time to see if it is really necessary to update
390*2449e17fSsherrym 	 * microcode just in case this is a hyperthreaded processor where
391*2449e17fSsherrym 	 * the threads share the same microcode.
392*2449e17fSsherrym 	 */
393*2449e17fSsherrym 	if (!ucode_force_update) {
394*2449e17fSsherrym 		ucode_read_rev(uinfop);
395*2449e17fSsherrym 		uusp->new_rev = uinfop->cui_rev;
396*2449e17fSsherrym 		if (uinfop->cui_rev >= uusp->expected_rev)
397*2449e17fSsherrym 			return (0);
398*2449e17fSsherrym 	}
399*2449e17fSsherrym 
400*2449e17fSsherrym 	wrmsr(MSR_INTC_UCODE_WRITE,
401*2449e17fSsherrym 	    (uint64_t)(intptr_t)(uusp->ucodep));
402*2449e17fSsherrym 	ucode_read_rev(uinfop);
403*2449e17fSsherrym 	uusp->new_rev = uinfop->cui_rev;
404*2449e17fSsherrym 
405*2449e17fSsherrym 	return (0);
406*2449e17fSsherrym }
407*2449e17fSsherrym 
408*2449e17fSsherrym 
409*2449e17fSsherrym static void
410*2449e17fSsherrym ucode_update_intel(uint8_t *ucode_body, struct cpu_ucode_info *uinfop)
411*2449e17fSsherrym {
412*2449e17fSsherrym 	kpreempt_disable();
413*2449e17fSsherrym 	wrmsr(MSR_INTC_UCODE_WRITE, (uint64_t)(uintptr_t)ucode_body);
414*2449e17fSsherrym 	ucode_read_rev(uinfop);
415*2449e17fSsherrym 	kpreempt_enable();
416*2449e17fSsherrym }
417*2449e17fSsherrym 
418*2449e17fSsherrym static void
419*2449e17fSsherrym ucode_read_rev(struct cpu_ucode_info *uinfop)
420*2449e17fSsherrym {
421*2449e17fSsherrym 	struct cpuid_regs crs;
422*2449e17fSsherrym 
423*2449e17fSsherrym 	/*
424*2449e17fSsherrym 	 * The Intel 64 and IA-32 Architecture Software Developer's Manual
425*2449e17fSsherrym 	 * recommends that MSR_INTC_UCODE_REV be loaded with 0 first, then
426*2449e17fSsherrym 	 * execute cpuid to guarantee the correct reading of this register.
427*2449e17fSsherrym 	 */
428*2449e17fSsherrym 	wrmsr(MSR_INTC_UCODE_REV, 0);
429*2449e17fSsherrym 	(void) __cpuid_insn(&crs);
430*2449e17fSsherrym 	uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT);
431*2449e17fSsherrym }
432*2449e17fSsherrym 
433*2449e17fSsherrym /*
434*2449e17fSsherrym  * Entry point to microcode update from the ucode_drv driver.
435*2449e17fSsherrym  *
436*2449e17fSsherrym  * Returns EM_OK on success, corresponding error code on failure.
437*2449e17fSsherrym  */
438*2449e17fSsherrym ucode_errno_t
439*2449e17fSsherrym ucode_update(uint8_t *ucodep, int size)
440*2449e17fSsherrym {
441*2449e17fSsherrym 	uint32_t	header_size = UCODE_HEADER_SIZE;
442*2449e17fSsherrym 	int		remaining;
443*2449e17fSsherrym 	int		found = 0;
444*2449e17fSsherrym 	processorid_t	id;
445*2449e17fSsherrym 	struct ucode_update_struct cached = { 0 };
446*2449e17fSsherrym 	struct ucode_update_struct *cachedp = NULL;
447*2449e17fSsherrym 	ucode_errno_t	rc = EM_OK;
448*2449e17fSsherrym 	ucode_errno_t	search_rc = EM_NOMATCH; /* search result */
449*2449e17fSsherrym 	cpuset_t cpuset;
450*2449e17fSsherrym 
451*2449e17fSsherrym 	ASSERT(ucodep);
452*2449e17fSsherrym 
453*2449e17fSsherrym 	CPUSET_ZERO(cpuset);
454*2449e17fSsherrym 
455*2449e17fSsherrym 	if (!ucode_capable(CPU))
456*2449e17fSsherrym 		return (EM_NOTSUP);
457*2449e17fSsherrym 
458*2449e17fSsherrym 	mutex_enter(&cpu_lock);
459*2449e17fSsherrym 
460*2449e17fSsherrym 	for (id = 0; id < max_ncpus; id++) {
461*2449e17fSsherrym 		cpu_t *cpu;
462*2449e17fSsherrym 		struct ucode_update_struct uus = { 0 };
463*2449e17fSsherrym 		struct ucode_update_struct *uusp = &uus;
464*2449e17fSsherrym 
465*2449e17fSsherrym 		/*
466*2449e17fSsherrym 		 * If there is no such CPU or it is not xcall ready, skip it.
467*2449e17fSsherrym 		 */
468*2449e17fSsherrym 		if ((cpu = cpu_get(id)) == NULL ||
469*2449e17fSsherrym 		    !(cpu->cpu_flags & CPU_READY))
470*2449e17fSsherrym 			continue;
471*2449e17fSsherrym 
472*2449e17fSsherrym 		uusp->sig = cpuid_getsig(cpu);
473*2449e17fSsherrym 		bcopy(cpu->cpu_m.mcpu_ucode_info, &uusp->info,
474*2449e17fSsherrym 		    sizeof (uusp->info));
475*2449e17fSsherrym 
476*2449e17fSsherrym 		/*
477*2449e17fSsherrym 		 * If the current CPU has the same signature and platform
478*2449e17fSsherrym 		 * id as the previous one we processed, reuse the information.
479*2449e17fSsherrym 		 */
480*2449e17fSsherrym 		if (cachedp && cachedp->sig == cpuid_getsig(cpu) &&
481*2449e17fSsherrym 		    cachedp->info.cui_platid == uusp->info.cui_platid) {
482*2449e17fSsherrym 			uusp->ucodep = cachedp->ucodep;
483*2449e17fSsherrym 			uusp->expected_rev = cachedp->expected_rev;
484*2449e17fSsherrym 			/*
485*2449e17fSsherrym 			 * Intuitively we should check here to see whether the
486*2449e17fSsherrym 			 * running microcode rev is >= the expected rev, and
487*2449e17fSsherrym 			 * quit if it is.  But we choose to proceed with the
488*2449e17fSsherrym 			 * xcall regardless of the running version so that
489*2449e17fSsherrym 			 * the other threads in an HT processor can update
490*2449e17fSsherrym 			 * the cpu_ucode_info structure in machcpu.
491*2449e17fSsherrym 			 */
492*2449e17fSsherrym 		} else {
493*2449e17fSsherrym 			/*
494*2449e17fSsherrym 			 * Go through the whole buffer in case there are
495*2449e17fSsherrym 			 * multiple versions of matching microcode for this
496*2449e17fSsherrym 			 * processor.
497*2449e17fSsherrym 			 */
498*2449e17fSsherrym 			for (remaining = size; remaining > 0; ) {
499*2449e17fSsherrym 				int	total_size, body_size, ext_size;
500*2449e17fSsherrym 				uint8_t	*curbuf = &ucodep[size - remaining];
501*2449e17fSsherrym 				ucode_header_t	*uhp = (ucode_header_t *)curbuf;
502*2449e17fSsherrym 				ucode_ext_table_t *uetp = NULL;
503*2449e17fSsherrym 				ucode_errno_t tmprc;
504*2449e17fSsherrym 
505*2449e17fSsherrym 				total_size =
506*2449e17fSsherrym 				    UCODE_TOTAL_SIZE(uhp->uh_total_size);
507*2449e17fSsherrym 				body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
508*2449e17fSsherrym 				ext_size = total_size -
509*2449e17fSsherrym 				    (header_size + body_size);
510*2449e17fSsherrym 
511*2449e17fSsherrym 				if (ext_size > 0)
512*2449e17fSsherrym 					uetp = (ucode_ext_table_t *)
513*2449e17fSsherrym 					    &curbuf[header_size + body_size];
514*2449e17fSsherrym 
515*2449e17fSsherrym 				tmprc = ucode_match(uusp->sig, &uusp->info,
516*2449e17fSsherrym 				    uhp, uetp);
517*2449e17fSsherrym 
518*2449e17fSsherrym 				/*
519*2449e17fSsherrym 				 * Since we are searching through a big file
520*2449e17fSsherrym 				 * containing microcode for pretty much all the
521*2449e17fSsherrym 				 * processors, we are bound to get EM_NOMATCH
522*2449e17fSsherrym 				 * at one point.  However, if we return
523*2449e17fSsherrym 				 * EM_NOMATCH to users, it will really confuse
524*2449e17fSsherrym 				 * them.  Therefore, if we ever find a match of
525*2449e17fSsherrym 				 * a lower rev, we will set return code to
526*2449e17fSsherrym 				 * EM_HIGHERREV.
527*2449e17fSsherrym 				 */
528*2449e17fSsherrym 				if (tmprc == EM_HIGHERREV)
529*2449e17fSsherrym 					search_rc = EM_HIGHERREV;
530*2449e17fSsherrym 
531*2449e17fSsherrym 				if (tmprc == EM_OK &&
532*2449e17fSsherrym 				    uusp->expected_rev < uhp->uh_rev) {
533*2449e17fSsherrym 					uusp->ucodep = &curbuf[header_size];
534*2449e17fSsherrym 					uusp->expected_rev = uhp->uh_rev;
535*2449e17fSsherrym 					bcopy(uusp, &cached, sizeof (cached));
536*2449e17fSsherrym 					cachedp = &cached;
537*2449e17fSsherrym 					found = 1;
538*2449e17fSsherrym 				}
539*2449e17fSsherrym 
540*2449e17fSsherrym 				remaining -= total_size;
541*2449e17fSsherrym 			}
542*2449e17fSsherrym 		}
543*2449e17fSsherrym 
544*2449e17fSsherrym 		/* Nothing to do */
545*2449e17fSsherrym 		if (uusp->ucodep == NULL)
546*2449e17fSsherrym 			continue;
547*2449e17fSsherrym 
548*2449e17fSsherrym 		CPUSET_ADD(cpuset, id);
549*2449e17fSsherrym 		kpreempt_disable();
550*2449e17fSsherrym 		xc_sync((xc_arg_t)uusp, 0, 0, X_CALL_HIPRI, cpuset,
551*2449e17fSsherrym 		    ucode_write);
552*2449e17fSsherrym 		kpreempt_enable();
553*2449e17fSsherrym 		CPUSET_DEL(cpuset, id);
554*2449e17fSsherrym 
555*2449e17fSsherrym 		if (uusp->expected_rev == uusp->new_rev) {
556*2449e17fSsherrym 			cmn_err(CE_CONT, ucode_success_fmt,
557*2449e17fSsherrym 			    id, uusp->info.cui_rev, uusp->expected_rev);
558*2449e17fSsherrym 		} else {
559*2449e17fSsherrym 			cmn_err(CE_WARN, ucode_failure_fmt,
560*2449e17fSsherrym 			    id, uusp->info.cui_rev, uusp->expected_rev);
561*2449e17fSsherrym 			rc = EM_UPDATE;
562*2449e17fSsherrym 		}
563*2449e17fSsherrym 	}
564*2449e17fSsherrym 
565*2449e17fSsherrym 	mutex_exit(&cpu_lock);
566*2449e17fSsherrym 
567*2449e17fSsherrym 	if (!found)
568*2449e17fSsherrym 		rc = search_rc;
569*2449e17fSsherrym 
570*2449e17fSsherrym 	return (rc);
571*2449e17fSsherrym }
572*2449e17fSsherrym 
573*2449e17fSsherrym /*
574*2449e17fSsherrym  * Initialize mcpu_ucode_info, and perform microcode update if necessary.
575*2449e17fSsherrym  * This is the entry point from boot path where pointer to CPU structure
576*2449e17fSsherrym  * is available.
577*2449e17fSsherrym  *
578*2449e17fSsherrym  * cpuid_info must be initialized before ucode_check can be called.
579*2449e17fSsherrym  */
580*2449e17fSsherrym void
581*2449e17fSsherrym ucode_check(cpu_t *cp)
582*2449e17fSsherrym {
583*2449e17fSsherrym #ifdef __xpv
584*2449e17fSsherrym {
585*2449e17fSsherrym 	This needs to be ported.  Only do ucode update from dom0.  In
586*2449e17fSsherrym 	    addition figure out how to bind to physical CPUs when doing
587*2449e17fSsherrym 	    it in dom0.
588*2449e17fSsherrym }
589*2449e17fSsherrym #endif	/* __xpv */
590*2449e17fSsherrym 
591*2449e17fSsherrym 	struct cpu_ucode_info *uinfop;
592*2449e17fSsherrym 	ucode_errno_t rc = EM_OK;
593*2449e17fSsherrym 
594*2449e17fSsherrym 	ASSERT(cp);
595*2449e17fSsherrym 	if (cp->cpu_id == 0)
596*2449e17fSsherrym 		cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0;
597*2449e17fSsherrym 
598*2449e17fSsherrym 	uinfop = cp->cpu_m.mcpu_ucode_info;
599*2449e17fSsherrym 	ASSERT(uinfop);
600*2449e17fSsherrym 
601*2449e17fSsherrym 	if (!ucode_capable(cp))
602*2449e17fSsherrym 		return;
603*2449e17fSsherrym 
604*2449e17fSsherrym 	/*
605*2449e17fSsherrym 	 * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon
606*2449e17fSsherrym 	 * (Family 6, model 5 and above) and all processors after.
607*2449e17fSsherrym 	 */
608*2449e17fSsherrym 	if ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6)) {
609*2449e17fSsherrym 		uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >>
610*2449e17fSsherrym 		    INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK);
611*2449e17fSsherrym 	}
612*2449e17fSsherrym 
613*2449e17fSsherrym 	ucode_read_rev(uinfop);
614*2449e17fSsherrym 
615*2449e17fSsherrym 	/*
616*2449e17fSsherrym 	 * Check to see if we need ucode update
617*2449e17fSsherrym 	 */
618*2449e17fSsherrym 	if ((rc = ucode_locate(cp, uinfop, &ucodefile)) == EM_OK) {
619*2449e17fSsherrym 		ucode_update_intel(ucodefile.uf_body, uinfop);
620*2449e17fSsherrym 
621*2449e17fSsherrym 		if (uinfop->cui_rev != ucodefile.uf_header.uh_rev)
622*2449e17fSsherrym 			cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id,
623*2449e17fSsherrym 			    uinfop->cui_rev, ucodefile.uf_header.uh_rev);
624*2449e17fSsherrym 	}
625*2449e17fSsherrym 
626*2449e17fSsherrym 	/*
627*2449e17fSsherrym 	 * If we fail to find a match for any reason, free the file structure
628*2449e17fSsherrym 	 * just in case we have read in a partial file.
629*2449e17fSsherrym 	 *
630*2449e17fSsherrym 	 * Since the scratch memory for holding the microcode for the boot CPU
631*2449e17fSsherrym 	 * came from BOP_ALLOC, we will reset the data structure as if we
632*2449e17fSsherrym 	 * never did the allocation so we don't have to keep track of this
633*2449e17fSsherrym 	 * special chunk of memory.  We free the memory used for the rest
634*2449e17fSsherrym 	 * of the CPUs in start_other_cpus().
635*2449e17fSsherrym 	 */
636*2449e17fSsherrym 	if (rc != EM_OK || cp->cpu_id == 0)
637*2449e17fSsherrym 		ucode_file_reset(&ucodefile, cp->cpu_id);
638*2449e17fSsherrym }
639*2449e17fSsherrym 
640*2449e17fSsherrym /*
641*2449e17fSsherrym  * Returns microcode revision from the machcpu structure.
642*2449e17fSsherrym  */
643*2449e17fSsherrym ucode_errno_t
644*2449e17fSsherrym ucode_get_rev(uint32_t *revp)
645*2449e17fSsherrym {
646*2449e17fSsherrym 	int i;
647*2449e17fSsherrym 
648*2449e17fSsherrym 	ASSERT(revp);
649*2449e17fSsherrym 
650*2449e17fSsherrym 	if (!ucode_capable(CPU))
651*2449e17fSsherrym 		return (EM_NOTSUP);
652*2449e17fSsherrym 
653*2449e17fSsherrym 	mutex_enter(&cpu_lock);
654*2449e17fSsherrym 	for (i = 0; i < max_ncpus; i++) {
655*2449e17fSsherrym 		cpu_t *cpu;
656*2449e17fSsherrym 
657*2449e17fSsherrym 		if ((cpu = cpu_get(i)) == NULL)
658*2449e17fSsherrym 			continue;
659*2449e17fSsherrym 
660*2449e17fSsherrym 		revp[i] = cpu->cpu_m.mcpu_ucode_info->cui_rev;
661*2449e17fSsherrym 	}
662*2449e17fSsherrym 	mutex_exit(&cpu_lock);
663*2449e17fSsherrym 
664*2449e17fSsherrym 	return (EM_OK);
665*2449e17fSsherrym }
666