xref: /titanic_52/usr/src/uts/i86pc/os/microcode.c (revision 79ec9da85c2648e2e165ce68612ad0cb6e185618)
12449e17fSsherrym /*
22449e17fSsherrym  * CDDL HEADER START
32449e17fSsherrym  *
42449e17fSsherrym  * The contents of this file are subject to the terms of the
52449e17fSsherrym  * Common Development and Distribution License (the "License").
62449e17fSsherrym  * You may not use this file except in compliance with the License.
72449e17fSsherrym  *
82449e17fSsherrym  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92449e17fSsherrym  * or http://www.opensolaris.org/os/licensing.
102449e17fSsherrym  * See the License for the specific language governing permissions
112449e17fSsherrym  * and limitations under the License.
122449e17fSsherrym  *
132449e17fSsherrym  * When distributing Covered Code, include this CDDL HEADER in each
142449e17fSsherrym  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152449e17fSsherrym  * If applicable, add the following below this CDDL HEADER, with the
162449e17fSsherrym  * fields enclosed by brackets "[]" replaced with your own identifying
172449e17fSsherrym  * information: Portions Copyright [yyyy] [name of copyright owner]
182449e17fSsherrym  *
192449e17fSsherrym  * CDDL HEADER END
202449e17fSsherrym  */
212449e17fSsherrym 
222449e17fSsherrym /*
230ba6f73dSMark Johnson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
242449e17fSsherrym  * Use is subject to license terms.
25*79ec9da8SYuri Pankov  *
26*79ec9da8SYuri Pankov  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
272449e17fSsherrym  */
282449e17fSsherrym 
292449e17fSsherrym #include <sys/asm_linkage.h>
302449e17fSsherrym #include <sys/bootconf.h>
312449e17fSsherrym #include <sys/cpuvar.h>
322449e17fSsherrym #include <sys/cmn_err.h>
332449e17fSsherrym #include <sys/controlregs.h>
342449e17fSsherrym #include <sys/debug.h>
352449e17fSsherrym #include <sys/kobj.h>
362449e17fSsherrym #include <sys/kobj_impl.h>
372449e17fSsherrym #include <sys/machsystm.h>
385e53ed34SHans Rosenfeld #include <sys/ontrap.h>
392449e17fSsherrym #include <sys/param.h>
402449e17fSsherrym #include <sys/machparam.h>
412449e17fSsherrym #include <sys/promif.h>
422449e17fSsherrym #include <sys/sysmacros.h>
432449e17fSsherrym #include <sys/systm.h>
442449e17fSsherrym #include <sys/types.h>
452449e17fSsherrym #include <sys/thread.h>
462449e17fSsherrym #include <sys/ucode.h>
472449e17fSsherrym #include <sys/x86_archext.h>
482449e17fSsherrym #include <sys/x_call.h>
49843e1988Sjohnlev #ifdef	__xpv
50843e1988Sjohnlev #include <sys/hypervisor.h>
51843e1988Sjohnlev #endif
522449e17fSsherrym 
532449e17fSsherrym /*
54adc586deSMark Johnson  * AMD-specific equivalence table
552449e17fSsherrym  */
56adc586deSMark Johnson static ucode_eqtbl_amd_t *ucode_eqtbl_amd;
572449e17fSsherrym 
582449e17fSsherrym /*
592449e17fSsherrym  * mcpu_ucode_info for the boot CPU.  Statically allocated.
602449e17fSsherrym  */
612449e17fSsherrym static struct cpu_ucode_info cpu_ucode_info0;
622449e17fSsherrym 
63adc586deSMark Johnson static ucode_file_t ucodefile;
642449e17fSsherrym 
65adc586deSMark Johnson static void* ucode_zalloc(processorid_t, size_t);
66adc586deSMark Johnson static void ucode_free(processorid_t, void *, size_t);
67adc586deSMark Johnson 
68adc586deSMark Johnson static int ucode_capable_amd(cpu_t *);
69adc586deSMark Johnson static int ucode_capable_intel(cpu_t *);
70adc586deSMark Johnson 
71adc586deSMark Johnson static ucode_errno_t ucode_extract_amd(ucode_update_t *, uint8_t *, int);
72adc586deSMark Johnson static ucode_errno_t ucode_extract_intel(ucode_update_t *, uint8_t *,
73adc586deSMark Johnson     int);
74adc586deSMark Johnson 
75adc586deSMark Johnson static void ucode_file_reset_amd(ucode_file_t *, processorid_t);
76adc586deSMark Johnson static void ucode_file_reset_intel(ucode_file_t *, processorid_t);
77adc586deSMark Johnson 
78adc586deSMark Johnson static uint32_t ucode_load_amd(ucode_file_t *, cpu_ucode_info_t *, cpu_t *);
79adc586deSMark Johnson static uint32_t ucode_load_intel(ucode_file_t *, cpu_ucode_info_t *, cpu_t *);
80adc586deSMark Johnson 
81882a7af5SMark Johnson #ifdef	__xpv
82adc586deSMark Johnson static void ucode_load_xpv(ucode_update_t *);
830ba6f73dSMark Johnson static void ucode_chipset_amd(uint8_t *, int);
84882a7af5SMark Johnson #endif
852449e17fSsherrym 
860ba6f73dSMark Johnson static int ucode_equiv_cpu_amd(cpu_t *, uint16_t *);
87adc586deSMark Johnson 
88adc586deSMark Johnson static ucode_errno_t ucode_locate_amd(cpu_t *, cpu_ucode_info_t *,
89adc586deSMark Johnson     ucode_file_t *);
90adc586deSMark Johnson static ucode_errno_t ucode_locate_intel(cpu_t *, cpu_ucode_info_t *,
91adc586deSMark Johnson     ucode_file_t *);
92adc586deSMark Johnson 
930ba6f73dSMark Johnson #ifndef __xpv
940ba6f73dSMark Johnson static ucode_errno_t ucode_match_amd(uint16_t, cpu_ucode_info_t *,
95adc586deSMark Johnson     ucode_file_amd_t *, int);
960ba6f73dSMark Johnson #endif
97adc586deSMark Johnson static ucode_errno_t ucode_match_intel(int, cpu_ucode_info_t *,
98adc586deSMark Johnson     ucode_header_intel_t *, ucode_ext_table_intel_t *);
99adc586deSMark Johnson 
100adc586deSMark Johnson static void ucode_read_rev_amd(cpu_ucode_info_t *);
101adc586deSMark Johnson static void ucode_read_rev_intel(cpu_ucode_info_t *);
102adc586deSMark Johnson 
103adc586deSMark Johnson static const struct ucode_ops ucode_amd = {
104adc586deSMark Johnson 	MSR_AMD_PATCHLOADER,
105adc586deSMark Johnson 	ucode_capable_amd,
106adc586deSMark Johnson 	ucode_file_reset_amd,
107adc586deSMark Johnson 	ucode_read_rev_amd,
108adc586deSMark Johnson 	ucode_load_amd,
109adc586deSMark Johnson 	ucode_validate_amd,
110adc586deSMark Johnson 	ucode_extract_amd,
111adc586deSMark Johnson 	ucode_locate_amd
112adc586deSMark Johnson };
113adc586deSMark Johnson 
114adc586deSMark Johnson static const struct ucode_ops ucode_intel = {
115adc586deSMark Johnson 	MSR_INTC_UCODE_WRITE,
116adc586deSMark Johnson 	ucode_capable_intel,
117adc586deSMark Johnson 	ucode_file_reset_intel,
118adc586deSMark Johnson 	ucode_read_rev_intel,
119adc586deSMark Johnson 	ucode_load_intel,
120adc586deSMark Johnson 	ucode_validate_intel,
121adc586deSMark Johnson 	ucode_extract_intel,
122adc586deSMark Johnson 	ucode_locate_intel
123adc586deSMark Johnson };
124adc586deSMark Johnson 
125adc586deSMark Johnson const struct ucode_ops *ucode;
126adc586deSMark Johnson 
1272449e17fSsherrym static const char ucode_failure_fmt[] =
12888699bddSsherrym 	"cpu%d: failed to update microcode from version 0x%x to 0x%x\n";
1292449e17fSsherrym static const char ucode_success_fmt[] =
13088699bddSsherrym 	"?cpu%d: microcode has been updated from version 0x%x to 0x%x\n";
1312449e17fSsherrym 
1322449e17fSsherrym /*
1332449e17fSsherrym  * Force flag.  If set, the first microcode binary that matches
1342449e17fSsherrym  * signature and platform id will be used for microcode update,
1352449e17fSsherrym  * regardless of version.  Should only be used for debugging.
1362449e17fSsherrym  */
1372449e17fSsherrym int ucode_force_update = 0;
1382449e17fSsherrym 
1392449e17fSsherrym /*
1402449e17fSsherrym  * Allocate space for mcpu_ucode_info in the machcpu structure
1412449e17fSsherrym  * for all non-boot CPUs.
1422449e17fSsherrym  */
1432449e17fSsherrym void
1442449e17fSsherrym ucode_alloc_space(cpu_t *cp)
1452449e17fSsherrym {
1462449e17fSsherrym 	ASSERT(cp->cpu_id != 0);
147a3114836SGerry Liu 	ASSERT(cp->cpu_m.mcpu_ucode_info == NULL);
1482449e17fSsherrym 	cp->cpu_m.mcpu_ucode_info =
1492449e17fSsherrym 	    kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP);
1502449e17fSsherrym }
1512449e17fSsherrym 
1522449e17fSsherrym void
1532449e17fSsherrym ucode_free_space(cpu_t *cp)
1542449e17fSsherrym {
155a3114836SGerry Liu 	ASSERT(cp->cpu_m.mcpu_ucode_info != NULL);
156a3114836SGerry Liu 	ASSERT(cp->cpu_m.mcpu_ucode_info != &cpu_ucode_info0);
1572449e17fSsherrym 	kmem_free(cp->cpu_m.mcpu_ucode_info,
1582449e17fSsherrym 	    sizeof (*cp->cpu_m.mcpu_ucode_info));
159a3114836SGerry Liu 	cp->cpu_m.mcpu_ucode_info = NULL;
1602449e17fSsherrym }
1612449e17fSsherrym 
1622449e17fSsherrym /*
1632449e17fSsherrym  * Called when we are done with microcode update on all processors to free up
1642449e17fSsherrym  * space allocated for the microcode file.
1652449e17fSsherrym  */
1662449e17fSsherrym void
167adc586deSMark Johnson ucode_cleanup()
1682449e17fSsherrym {
169126b0a71SMark Johnson 	if (ucode == NULL)
170126b0a71SMark Johnson 		return;
171adc586deSMark Johnson 
172adc586deSMark Johnson 	ucode->file_reset(&ucodefile, -1);
173adc586deSMark Johnson }
174adc586deSMark Johnson 
175adc586deSMark Johnson /*
176adc586deSMark Johnson  * Allocate/free a buffer used to hold ucode data. Space for the boot CPU is
177adc586deSMark Johnson  * allocated with BOP_ALLOC() and does not require a free.
178adc586deSMark Johnson  */
179adc586deSMark Johnson static void*
180adc586deSMark Johnson ucode_zalloc(processorid_t id, size_t size)
181adc586deSMark Johnson {
182adc586deSMark Johnson 	if (id)
183adc586deSMark Johnson 		return (kmem_zalloc(size, KM_NOSLEEP));
184adc586deSMark Johnson 
185adc586deSMark Johnson 	/* BOP_ALLOC() failure results in panic */
186adc586deSMark Johnson 	return (BOP_ALLOC(bootops, NULL, size, MMU_PAGESIZE));
187adc586deSMark Johnson }
188adc586deSMark Johnson 
189adc586deSMark Johnson static void
190adc586deSMark Johnson ucode_free(processorid_t id, void* buf, size_t size)
191adc586deSMark Johnson {
192adc586deSMark Johnson 	if (id)
193adc586deSMark Johnson 		kmem_free(buf, size);
1942449e17fSsherrym }
1952449e17fSsherrym 
1962449e17fSsherrym /*
1972449e17fSsherrym  * Check whether or not a processor is capable of microcode operations
1982449e17fSsherrym  * Returns 1 if it is capable, 0 if not.
199adc586deSMark Johnson  *
200adc586deSMark Johnson  * At this point we only support microcode update for:
201adc586deSMark Johnson  * - Intel processors family 6 and above, and
202adc586deSMark Johnson  * - AMD processors family 0x10 and above.
203adc586deSMark Johnson  *
204adc586deSMark Johnson  * We also assume that we don't support a mix of Intel and
205adc586deSMark Johnson  * AMD processors in the same box.
206adc586deSMark Johnson  *
207*79ec9da8SYuri Pankov  * An i86xpv guest domain or VM can't update the microcode.
2082449e17fSsherrym  */
209*79ec9da8SYuri Pankov 
210*79ec9da8SYuri Pankov #define	XPVDOMU_OR_HVM	\
211*79ec9da8SYuri Pankov 	((hwenv == HW_XEN_PV && !is_controldom()) || (hwenv & HW_VIRTUAL) != 0)
212*79ec9da8SYuri Pankov 
213adc586deSMark Johnson /*ARGSUSED*/
2142449e17fSsherrym static int
215adc586deSMark Johnson ucode_capable_amd(cpu_t *cp)
2162449e17fSsherrym {
217b9bfdccdSStuart Maybee 	int hwenv = get_hwenv();
218b9bfdccdSStuart Maybee 
219*79ec9da8SYuri Pankov 	if (XPVDOMU_OR_HVM)
220adc586deSMark Johnson 		return (0);
221*79ec9da8SYuri Pankov 
2220ba6f73dSMark Johnson 	return (cpuid_getfamily(cp) >= 0x10);
223adc586deSMark Johnson }
2240ba6f73dSMark Johnson 
225adc586deSMark Johnson static int
226adc586deSMark Johnson ucode_capable_intel(cpu_t *cp)
227adc586deSMark Johnson {
228b9bfdccdSStuart Maybee 	int hwenv = get_hwenv();
229b9bfdccdSStuart Maybee 
230*79ec9da8SYuri Pankov 	if (XPVDOMU_OR_HVM)
231882a7af5SMark Johnson 		return (0);
232*79ec9da8SYuri Pankov 
233adc586deSMark Johnson 	return (cpuid_getfamily(cp) >= 6);
2342449e17fSsherrym }
2352449e17fSsherrym 
2362449e17fSsherrym /*
2372449e17fSsherrym  * Called when it is no longer necessary to keep the microcode around,
2382449e17fSsherrym  * or when the cached microcode doesn't match the CPU being processed.
2392449e17fSsherrym  */
2402449e17fSsherrym static void
241adc586deSMark Johnson ucode_file_reset_amd(ucode_file_t *ufp, processorid_t id)
2422449e17fSsherrym {
243adc586deSMark Johnson 	ucode_file_amd_t *ucodefp = ufp->amd;
2442449e17fSsherrym 
2452449e17fSsherrym 	if (ucodefp == NULL)
2462449e17fSsherrym 		return;
2472449e17fSsherrym 
248adc586deSMark Johnson 	ucode_free(id, ucodefp, sizeof (ucode_file_amd_t));
249adc586deSMark Johnson 	ufp->amd = NULL;
250adc586deSMark Johnson }
251adc586deSMark Johnson 
252adc586deSMark Johnson static void
253adc586deSMark Johnson ucode_file_reset_intel(ucode_file_t *ufp, processorid_t id)
254adc586deSMark Johnson {
255adc586deSMark Johnson 	ucode_file_intel_t *ucodefp = &ufp->intel;
256adc586deSMark Johnson 	int total_size, body_size;
257adc586deSMark Johnson 
258adc586deSMark Johnson 	if (ucodefp == NULL || ucodefp->uf_header == NULL)
259adc586deSMark Johnson 		return;
260adc586deSMark Johnson 
261adc586deSMark Johnson 	total_size = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size);
262adc586deSMark Johnson 	body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size);
2632449e17fSsherrym 	if (ucodefp->uf_body) {
264adc586deSMark Johnson 		ucode_free(id, ucodefp->uf_body, body_size);
2652449e17fSsherrym 		ucodefp->uf_body = NULL;
2662449e17fSsherrym 	}
2672449e17fSsherrym 
2682449e17fSsherrym 	if (ucodefp->uf_ext_table) {
269adc586deSMark Johnson 		int size = total_size - body_size - UCODE_HEADER_SIZE_INTEL;
270adc586deSMark Johnson 
271adc586deSMark Johnson 		ucode_free(id, ucodefp->uf_ext_table, size);
2722449e17fSsherrym 		ucodefp->uf_ext_table = NULL;
2732449e17fSsherrym 	}
2742449e17fSsherrym 
275adc586deSMark Johnson 	ucode_free(id, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL);
276adc586deSMark Johnson 	ucodefp->uf_header = NULL;
277adc586deSMark Johnson }
278adc586deSMark Johnson 
279adc586deSMark Johnson /*
280adc586deSMark Johnson  * Find the equivalent CPU id in the equivalence table.
281adc586deSMark Johnson  */
282adc586deSMark Johnson static int
2830ba6f73dSMark Johnson ucode_equiv_cpu_amd(cpu_t *cp, uint16_t *eq_sig)
284adc586deSMark Johnson {
285adc586deSMark Johnson 	char name[MAXPATHLEN];
286adc586deSMark Johnson 	intptr_t fd;
287adc586deSMark Johnson 	int count;
288adc586deSMark Johnson 	int offset = 0, cpi_sig = cpuid_getsig(cp);
289adc586deSMark Johnson 	ucode_eqtbl_amd_t *eqtbl = ucode_eqtbl_amd;
290adc586deSMark Johnson 
291adc586deSMark Johnson 	(void) snprintf(name, MAXPATHLEN, "/%s/%s/equivalence-table",
292adc586deSMark Johnson 	    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp));
293adc586deSMark Johnson 
294adc586deSMark Johnson 	/*
295adc586deSMark Johnson 	 * No kmem_zalloc() etc. available on boot cpu.
296adc586deSMark Johnson 	 */
297adc586deSMark Johnson 	if (cp->cpu_id == 0) {
298adc586deSMark Johnson 		if ((fd = kobj_open(name)) == -1)
299adc586deSMark Johnson 			return (EM_OPENFILE);
300adc586deSMark Johnson 		/* ucode_zalloc() cannot fail on boot cpu */
301adc586deSMark Johnson 		eqtbl = ucode_zalloc(cp->cpu_id, sizeof (*eqtbl));
302adc586deSMark Johnson 		ASSERT(eqtbl);
303adc586deSMark Johnson 		do {
304adc586deSMark Johnson 			count = kobj_read(fd, (int8_t *)eqtbl,
305adc586deSMark Johnson 			    sizeof (*eqtbl), offset);
306adc586deSMark Johnson 			if (count != sizeof (*eqtbl)) {
307adc586deSMark Johnson 				(void) kobj_close(fd);
308adc586deSMark Johnson 				return (EM_HIGHERREV);
309adc586deSMark Johnson 			}
310adc586deSMark Johnson 			offset += count;
311adc586deSMark Johnson 		} while (eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig);
312adc586deSMark Johnson 		(void) kobj_close(fd);
313adc586deSMark Johnson 	}
314adc586deSMark Johnson 
315adc586deSMark Johnson 	/*
316adc586deSMark Johnson 	 * If not already done, load the equivalence table.
317adc586deSMark Johnson 	 * Not done on boot CPU.
318adc586deSMark Johnson 	 */
319adc586deSMark Johnson 	if (eqtbl == NULL) {
320adc586deSMark Johnson 		struct _buf *eq;
321adc586deSMark Johnson 		uint64_t size;
322adc586deSMark Johnson 
323adc586deSMark Johnson 		if ((eq = kobj_open_file(name)) == (struct _buf *)-1)
324adc586deSMark Johnson 			return (EM_OPENFILE);
325adc586deSMark Johnson 
326adc586deSMark Johnson 		if (kobj_get_filesize(eq, &size) < 0) {
327adc586deSMark Johnson 			kobj_close_file(eq);
328adc586deSMark Johnson 			return (EM_OPENFILE);
329adc586deSMark Johnson 		}
330adc586deSMark Johnson 
331adc586deSMark Johnson 		ucode_eqtbl_amd = kmem_zalloc(size, KM_NOSLEEP);
332adc586deSMark Johnson 		if (ucode_eqtbl_amd == NULL) {
333adc586deSMark Johnson 			kobj_close_file(eq);
334adc586deSMark Johnson 			return (EM_NOMEM);
335adc586deSMark Johnson 		}
336adc586deSMark Johnson 
337adc586deSMark Johnson 		count = kobj_read_file(eq, (char *)ucode_eqtbl_amd, size, 0);
338adc586deSMark Johnson 		kobj_close_file(eq);
339adc586deSMark Johnson 
340adc586deSMark Johnson 		if (count != size)
341adc586deSMark Johnson 			return (EM_FILESIZE);
342adc586deSMark Johnson 	}
343adc586deSMark Johnson 
344adc586deSMark Johnson 	/* Get the equivalent CPU id. */
345adc586deSMark Johnson 	if (cp->cpu_id)
346adc586deSMark Johnson 		for (eqtbl = ucode_eqtbl_amd;
347adc586deSMark Johnson 		    eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig;
348adc586deSMark Johnson 		    eqtbl++)
349adc586deSMark Johnson 			;
350adc586deSMark Johnson 
351adc586deSMark Johnson 	*eq_sig = eqtbl->ue_equiv_cpu;
352adc586deSMark Johnson 
353adc586deSMark Johnson 	/* No equivalent CPU id found, assume outdated microcode file. */
354adc586deSMark Johnson 	if (*eq_sig == 0)
355adc586deSMark Johnson 		return (EM_HIGHERREV);
356adc586deSMark Johnson 
357adc586deSMark Johnson 	return (EM_OK);
3582449e17fSsherrym }
3592449e17fSsherrym 
3602449e17fSsherrym /*
3610ba6f73dSMark Johnson  * xVM cannot check for the presence of PCI devices. Look for chipset-
3620ba6f73dSMark Johnson  * specific microcode patches in the container file and disable them
3630ba6f73dSMark Johnson  * by setting their CPU revision to an invalid value.
3640ba6f73dSMark Johnson  */
3650ba6f73dSMark Johnson #ifdef __xpv
3660ba6f73dSMark Johnson static void
3670ba6f73dSMark Johnson ucode_chipset_amd(uint8_t *buf, int size)
3680ba6f73dSMark Johnson {
3690ba6f73dSMark Johnson 	ucode_header_amd_t *uh;
3700ba6f73dSMark Johnson 	uint32_t *ptr = (uint32_t *)buf;
3710ba6f73dSMark Johnson 	int len = 0;
3720ba6f73dSMark Johnson 
3730ba6f73dSMark Johnson 	/* skip to first microcode patch */
3740ba6f73dSMark Johnson 	ptr += 2; len = *ptr++; ptr += len >> 2; size -= len;
3750ba6f73dSMark Johnson 
3760ba6f73dSMark Johnson 	while (size >= sizeof (ucode_header_amd_t) + 8) {
3770ba6f73dSMark Johnson 		ptr++; len = *ptr++;
3780ba6f73dSMark Johnson 		uh = (ucode_header_amd_t *)ptr;
3790ba6f73dSMark Johnson 		ptr += len >> 2; size -= len;
3800ba6f73dSMark Johnson 
3810ba6f73dSMark Johnson 		if (uh->uh_nb_id) {
3820ba6f73dSMark Johnson 			cmn_err(CE_WARN, "ignoring northbridge-specific ucode: "
3830ba6f73dSMark Johnson 			    "chipset id %x, revision %x",
3840ba6f73dSMark Johnson 			    uh->uh_nb_id, uh->uh_nb_rev);
3850ba6f73dSMark Johnson 			uh->uh_cpu_rev = 0xffff;
3860ba6f73dSMark Johnson 		}
3870ba6f73dSMark Johnson 
3880ba6f73dSMark Johnson 		if (uh->uh_sb_id) {
3890ba6f73dSMark Johnson 			cmn_err(CE_WARN, "ignoring southbridge-specific ucode: "
3900ba6f73dSMark Johnson 			    "chipset id %x, revision %x",
3910ba6f73dSMark Johnson 			    uh->uh_sb_id, uh->uh_sb_rev);
3920ba6f73dSMark Johnson 			uh->uh_cpu_rev = 0xffff;
3930ba6f73dSMark Johnson 		}
3940ba6f73dSMark Johnson 	}
3950ba6f73dSMark Johnson }
3960ba6f73dSMark Johnson #endif
3970ba6f73dSMark Johnson 
3980ba6f73dSMark Johnson /*
3992449e17fSsherrym  * Populate the ucode file structure from microcode file corresponding to
4002449e17fSsherrym  * this CPU, if exists.
4012449e17fSsherrym  *
4022449e17fSsherrym  * Return EM_OK on success, corresponding error code on failure.
4032449e17fSsherrym  */
4040ba6f73dSMark Johnson /*ARGSUSED*/
4052449e17fSsherrym static ucode_errno_t
406adc586deSMark Johnson ucode_locate_amd(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp)
407adc586deSMark Johnson {
408adc586deSMark Johnson 	char name[MAXPATHLEN];
409adc586deSMark Johnson 	intptr_t fd;
4100ba6f73dSMark Johnson 	int count, rc;
411adc586deSMark Johnson 	ucode_file_amd_t *ucodefp = ufp->amd;
412adc586deSMark Johnson 
4130ba6f73dSMark Johnson #ifndef __xpv
4140ba6f73dSMark Johnson 	uint16_t eq_sig = 0;
4150ba6f73dSMark Johnson 	int i;
4160ba6f73dSMark Johnson 
417adc586deSMark Johnson 	/* get equivalent CPU id */
418adc586deSMark Johnson 	if ((rc = ucode_equiv_cpu_amd(cp, &eq_sig)) != EM_OK)
419adc586deSMark Johnson 		return (rc);
420adc586deSMark Johnson 
421adc586deSMark Johnson 	/*
422adc586deSMark Johnson 	 * Allocate a buffer for the microcode patch. If the buffer has been
423adc586deSMark Johnson 	 * allocated before, check for a matching microcode to avoid loading
424adc586deSMark Johnson 	 * the file again.
425adc586deSMark Johnson 	 */
426adc586deSMark Johnson 	if (ucodefp == NULL)
427adc586deSMark Johnson 		ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp));
428adc586deSMark Johnson 	else if (ucode_match_amd(eq_sig, uinfop, ucodefp, sizeof (*ucodefp))
429adc586deSMark Johnson 	    == EM_OK)
430adc586deSMark Johnson 		return (EM_OK);
431adc586deSMark Johnson 
432adc586deSMark Johnson 	if (ucodefp == NULL)
433adc586deSMark Johnson 		return (EM_NOMEM);
434adc586deSMark Johnson 
435adc586deSMark Johnson 	ufp->amd = ucodefp;
436adc586deSMark Johnson 
437adc586deSMark Johnson 	/*
438adc586deSMark Johnson 	 * Find the patch for this CPU. The patch files are named XXXX-YY, where
439adc586deSMark Johnson 	 * XXXX is the equivalent CPU id and YY is the running patch number.
440adc586deSMark Johnson 	 * Patches specific to certain chipsets are guaranteed to have lower
441adc586deSMark Johnson 	 * numbers than less specific patches, so we can just load the first
442adc586deSMark Johnson 	 * patch that matches.
443adc586deSMark Johnson 	 */
444adc586deSMark Johnson 
445adc586deSMark Johnson 	for (i = 0; i < 0xff; i++) {
446adc586deSMark Johnson 		(void) snprintf(name, MAXPATHLEN, "/%s/%s/%04X-%02X",
447adc586deSMark Johnson 		    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), eq_sig, i);
448adc586deSMark Johnson 		if ((fd = kobj_open(name)) == -1)
449adc586deSMark Johnson 			return (EM_NOMATCH);
450adc586deSMark Johnson 		count = kobj_read(fd, (char *)ucodefp, sizeof (*ucodefp), 0);
451adc586deSMark Johnson 		(void) kobj_close(fd);
452adc586deSMark Johnson 
453adc586deSMark Johnson 		if (ucode_match_amd(eq_sig, uinfop, ucodefp, count) == EM_OK)
454adc586deSMark Johnson 			return (EM_OK);
455adc586deSMark Johnson 	}
456adc586deSMark Johnson 	return (EM_NOMATCH);
4570ba6f73dSMark Johnson #else
4580ba6f73dSMark Johnson 	int size = 0;
4590ba6f73dSMark Johnson 	char c;
4600ba6f73dSMark Johnson 
4610ba6f73dSMark Johnson 	/*
4620ba6f73dSMark Johnson 	 * The xVM case is special. To support mixed-revision systems, the
4630ba6f73dSMark Johnson 	 * hypervisor will choose which patch to load for which CPU, so the
4640ba6f73dSMark Johnson 	 * whole microcode patch container file will have to be loaded.
4650ba6f73dSMark Johnson 	 *
4660ba6f73dSMark Johnson 	 * Since this code is only run on the boot cpu, we don't have to care
4670ba6f73dSMark Johnson 	 * about failing ucode_zalloc() or freeing allocated memory.
4680ba6f73dSMark Johnson 	 */
4690ba6f73dSMark Johnson 	if (cp->cpu_id != 0)
4700ba6f73dSMark Johnson 		return (EM_INVALIDARG);
4710ba6f73dSMark Johnson 
4720ba6f73dSMark Johnson 	(void) snprintf(name, MAXPATHLEN, "/%s/%s/container",
4730ba6f73dSMark Johnson 	    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp));
4740ba6f73dSMark Johnson 
4750ba6f73dSMark Johnson 	if ((fd = kobj_open(name)) == -1)
4760ba6f73dSMark Johnson 		return (EM_OPENFILE);
4770ba6f73dSMark Johnson 
4780ba6f73dSMark Johnson 	/* get the file size by counting bytes */
4790ba6f73dSMark Johnson 	do {
4800ba6f73dSMark Johnson 		count = kobj_read(fd, &c, 1, size);
4810ba6f73dSMark Johnson 		size += count;
4820ba6f73dSMark Johnson 	} while (count);
4830ba6f73dSMark Johnson 
4840ba6f73dSMark Johnson 	ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp));
4850ba6f73dSMark Johnson 	ASSERT(ucodefp);
4860ba6f73dSMark Johnson 	ufp->amd = ucodefp;
4870ba6f73dSMark Johnson 
4880ba6f73dSMark Johnson 	ucodefp->usize = size;
4890ba6f73dSMark Johnson 	ucodefp->ucodep = ucode_zalloc(cp->cpu_id, size);
4900ba6f73dSMark Johnson 	ASSERT(ucodefp->ucodep);
4910ba6f73dSMark Johnson 
4920ba6f73dSMark Johnson 	/* load the microcode patch container file */
4930ba6f73dSMark Johnson 	count = kobj_read(fd, (char *)ucodefp->ucodep, size, 0);
4940ba6f73dSMark Johnson 	(void) kobj_close(fd);
4950ba6f73dSMark Johnson 
4960ba6f73dSMark Johnson 	if (count != size)
4970ba6f73dSMark Johnson 		return (EM_FILESIZE);
4980ba6f73dSMark Johnson 
4990ba6f73dSMark Johnson 	/* make sure the container file is valid */
5000ba6f73dSMark Johnson 	rc = ucode->validate(ucodefp->ucodep, ucodefp->usize);
5010ba6f73dSMark Johnson 
5020ba6f73dSMark Johnson 	if (rc != EM_OK)
5030ba6f73dSMark Johnson 		return (rc);
5040ba6f73dSMark Johnson 
5050ba6f73dSMark Johnson 	/* disable chipset-specific patches */
5060ba6f73dSMark Johnson 	ucode_chipset_amd(ucodefp->ucodep, ucodefp->usize);
5070ba6f73dSMark Johnson 
5080ba6f73dSMark Johnson 	return (EM_OK);
5090ba6f73dSMark Johnson #endif
510adc586deSMark Johnson }
511adc586deSMark Johnson 
512adc586deSMark Johnson static ucode_errno_t
513adc586deSMark Johnson ucode_locate_intel(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp)
5142449e17fSsherrym {
5152449e17fSsherrym 	char		name[MAXPATHLEN];
5162449e17fSsherrym 	intptr_t	fd;
5172449e17fSsherrym 	int		count;
518adc586deSMark Johnson 	int		header_size = UCODE_HEADER_SIZE_INTEL;
5192449e17fSsherrym 	int		cpi_sig = cpuid_getsig(cp);
5202449e17fSsherrym 	ucode_errno_t	rc = EM_OK;
521adc586deSMark Johnson 	ucode_file_intel_t *ucodefp = &ufp->intel;
522adc586deSMark Johnson 
523adc586deSMark Johnson 	ASSERT(ucode);
5242449e17fSsherrym 
5252449e17fSsherrym 	/*
5262449e17fSsherrym 	 * If the microcode matches the CPU we are processing, use it.
5272449e17fSsherrym 	 */
528adc586deSMark Johnson 	if (ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header,
5292449e17fSsherrym 	    ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) {
5302449e17fSsherrym 		return (EM_OK);
5312449e17fSsherrym 	}
5322449e17fSsherrym 
5332449e17fSsherrym 	/*
5342449e17fSsherrym 	 * Look for microcode file with the right name.
5352449e17fSsherrym 	 */
5362449e17fSsherrym 	(void) snprintf(name, MAXPATHLEN, "/%s/%s/%08X-%02X",
5372449e17fSsherrym 	    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), cpi_sig,
5382449e17fSsherrym 	    uinfop->cui_platid);
5392449e17fSsherrym 	if ((fd = kobj_open(name)) == -1) {
5402449e17fSsherrym 		return (EM_OPENFILE);
5412449e17fSsherrym 	}
5422449e17fSsherrym 
5432449e17fSsherrym 	/*
5442449e17fSsherrym 	 * We found a microcode file for the CPU we are processing,
5452449e17fSsherrym 	 * reset the microcode data structure and read in the new
5462449e17fSsherrym 	 * file.
5472449e17fSsherrym 	 */
548adc586deSMark Johnson 	ucode->file_reset(ufp, cp->cpu_id);
5492449e17fSsherrym 
550adc586deSMark Johnson 	ucodefp->uf_header = ucode_zalloc(cp->cpu_id, header_size);
551adc586deSMark Johnson 	if (ucodefp->uf_header == NULL)
552adc586deSMark Johnson 		return (EM_NOMEM);
553adc586deSMark Johnson 
554adc586deSMark Johnson 	count = kobj_read(fd, (char *)ucodefp->uf_header, header_size, 0);
5552449e17fSsherrym 
5562449e17fSsherrym 	switch (count) {
557adc586deSMark Johnson 	case UCODE_HEADER_SIZE_INTEL: {
5582449e17fSsherrym 
559adc586deSMark Johnson 		ucode_header_intel_t	*uhp = ucodefp->uf_header;
5602449e17fSsherrym 		uint32_t	offset = header_size;
5612449e17fSsherrym 		int		total_size, body_size, ext_size;
5622449e17fSsherrym 		uint32_t	sum = 0;
5632449e17fSsherrym 
5642449e17fSsherrym 		/*
5652449e17fSsherrym 		 * Make sure that the header contains valid fields.
5662449e17fSsherrym 		 */
567adc586deSMark Johnson 		if ((rc = ucode_header_validate_intel(uhp)) == EM_OK) {
568adc586deSMark Johnson 			total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
569adc586deSMark Johnson 			body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
570adc586deSMark Johnson 			ucodefp->uf_body = ucode_zalloc(cp->cpu_id, body_size);
571adc586deSMark Johnson 			if (ucodefp->uf_body == NULL) {
5722449e17fSsherrym 				rc = EM_NOMEM;
5732449e17fSsherrym 				break;
5742449e17fSsherrym 			}
5752449e17fSsherrym 
5762449e17fSsherrym 			if (kobj_read(fd, (char *)ucodefp->uf_body,
5772449e17fSsherrym 			    body_size, offset) != body_size)
5782449e17fSsherrym 				rc = EM_FILESIZE;
5792449e17fSsherrym 		}
5802449e17fSsherrym 
5812449e17fSsherrym 		if (rc)
5822449e17fSsherrym 			break;
5832449e17fSsherrym 
584adc586deSMark Johnson 		sum = ucode_checksum_intel(0, header_size,
585adc586deSMark Johnson 		    (uint8_t *)ucodefp->uf_header);
586adc586deSMark Johnson 		if (ucode_checksum_intel(sum, body_size, ucodefp->uf_body)) {
5872449e17fSsherrym 			rc = EM_CHECKSUM;
5882449e17fSsherrym 			break;
5892449e17fSsherrym 		}
5902449e17fSsherrym 
5912449e17fSsherrym 		/*
5922449e17fSsherrym 		 * Check to see if there is extended signature table.
5932449e17fSsherrym 		 */
5942449e17fSsherrym 		offset = body_size + header_size;
5952449e17fSsherrym 		ext_size = total_size - offset;
5962449e17fSsherrym 
5972449e17fSsherrym 		if (ext_size <= 0)
5982449e17fSsherrym 			break;
5992449e17fSsherrym 
600adc586deSMark Johnson 		ucodefp->uf_ext_table = ucode_zalloc(cp->cpu_id, ext_size);
601adc586deSMark Johnson 		if (ucodefp->uf_ext_table == NULL) {
6022449e17fSsherrym 			rc = EM_NOMEM;
6032449e17fSsherrym 			break;
6042449e17fSsherrym 		}
6052449e17fSsherrym 
6062449e17fSsherrym 		if (kobj_read(fd, (char *)ucodefp->uf_ext_table,
6072449e17fSsherrym 		    ext_size, offset) != ext_size) {
6082449e17fSsherrym 			rc = EM_FILESIZE;
609adc586deSMark Johnson 		} else if (ucode_checksum_intel(0, ext_size,
6102449e17fSsherrym 		    (uint8_t *)(ucodefp->uf_ext_table))) {
6112449e17fSsherrym 			rc = EM_CHECKSUM;
6122449e17fSsherrym 		} else {
6132449e17fSsherrym 			int i;
6142449e17fSsherrym 
615adc586deSMark Johnson 			ext_size -= UCODE_EXT_TABLE_SIZE_INTEL;
6162449e17fSsherrym 			for (i = 0; i < ucodefp->uf_ext_table->uet_count;
6172449e17fSsherrym 			    i++) {
618adc586deSMark Johnson 				if (ucode_checksum_intel(0,
619adc586deSMark Johnson 				    UCODE_EXT_SIG_SIZE_INTEL,
6202449e17fSsherrym 				    (uint8_t *)(&(ucodefp->uf_ext_table->
6212449e17fSsherrym 				    uet_ext_sig[i])))) {
6222449e17fSsherrym 					rc = EM_CHECKSUM;
6232449e17fSsherrym 					break;
6242449e17fSsherrym 				}
6252449e17fSsherrym 			}
6262449e17fSsherrym 		}
6272449e17fSsherrym 		break;
6282449e17fSsherrym 	}
6292449e17fSsherrym 
6302449e17fSsherrym 	default:
6312449e17fSsherrym 		rc = EM_FILESIZE;
6322449e17fSsherrym 		break;
6332449e17fSsherrym 	}
6342449e17fSsherrym 
6352449e17fSsherrym 	kobj_close(fd);
6362449e17fSsherrym 
6372449e17fSsherrym 	if (rc != EM_OK)
6382449e17fSsherrym 		return (rc);
6392449e17fSsherrym 
640adc586deSMark Johnson 	rc = ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header,
6412449e17fSsherrym 	    ucodefp->uf_ext_table);
6422449e17fSsherrym 
6432449e17fSsherrym 	return (rc);
6442449e17fSsherrym }
6452449e17fSsherrym 
6460ba6f73dSMark Johnson #ifndef __xpv
647adc586deSMark Johnson static ucode_errno_t
6480ba6f73dSMark Johnson ucode_match_amd(uint16_t eq_sig, cpu_ucode_info_t *uinfop,
6490ba6f73dSMark Johnson     ucode_file_amd_t *ucodefp, int size)
650adc586deSMark Johnson {
651adc586deSMark Johnson 	ucode_header_amd_t *uh;
652adc586deSMark Johnson 
653adc586deSMark Johnson 	if (ucodefp == NULL || size < sizeof (ucode_header_amd_t))
654adc586deSMark Johnson 		return (EM_NOMATCH);
655adc586deSMark Johnson 
6565e53ed34SHans Rosenfeld 	uh = &ucodefp->uf_header;
6575e53ed34SHans Rosenfeld 
658adc586deSMark Johnson 	/*
659adc586deSMark Johnson 	 * Don't even think about loading patches that would require code
6605e53ed34SHans Rosenfeld 	 * execution. Does not apply to patches for family 0x14 and beyond.
661adc586deSMark Johnson 	 */
6625e53ed34SHans Rosenfeld 	if (uh->uh_cpu_rev < 0x5000 &&
6635e53ed34SHans Rosenfeld 	    size > offsetof(ucode_file_amd_t, uf_code_present) &&
664adc586deSMark Johnson 	    ucodefp->uf_code_present)
665adc586deSMark Johnson 		return (EM_NOMATCH);
666adc586deSMark Johnson 
667adc586deSMark Johnson 	if (eq_sig != uh->uh_cpu_rev)
668adc586deSMark Johnson 		return (EM_NOMATCH);
669adc586deSMark Johnson 
670adc586deSMark Johnson 	if (uh->uh_nb_id) {
671adc586deSMark Johnson 		cmn_err(CE_WARN, "ignoring northbridge-specific ucode: "
672adc586deSMark Johnson 		    "chipset id %x, revision %x", uh->uh_nb_id, uh->uh_nb_rev);
673adc586deSMark Johnson 		return (EM_NOMATCH);
674adc586deSMark Johnson 	}
675adc586deSMark Johnson 
676adc586deSMark Johnson 	if (uh->uh_sb_id) {
677adc586deSMark Johnson 		cmn_err(CE_WARN, "ignoring southbridge-specific ucode: "
678adc586deSMark Johnson 		    "chipset id %x, revision %x", uh->uh_sb_id, uh->uh_sb_rev);
679adc586deSMark Johnson 		return (EM_NOMATCH);
680adc586deSMark Johnson 	}
681adc586deSMark Johnson 
6825e53ed34SHans Rosenfeld 	if (uh->uh_patch_id <= uinfop->cui_rev && !ucode_force_update)
683adc586deSMark Johnson 		return (EM_HIGHERREV);
684adc586deSMark Johnson 
685adc586deSMark Johnson 	return (EM_OK);
686adc586deSMark Johnson }
6870ba6f73dSMark Johnson #endif
6882449e17fSsherrym 
6892449e17fSsherrym /*
6902449e17fSsherrym  * Returns 1 if the microcode is for this processor; 0 otherwise.
6912449e17fSsherrym  */
6922449e17fSsherrym static ucode_errno_t
693adc586deSMark Johnson ucode_match_intel(int cpi_sig, cpu_ucode_info_t *uinfop,
694adc586deSMark Johnson     ucode_header_intel_t *uhp, ucode_ext_table_intel_t *uetp)
6952449e17fSsherrym {
696adc586deSMark Johnson 	if (uhp == NULL)
697adc586deSMark Johnson 		return (EM_NOMATCH);
6982449e17fSsherrym 
699adc586deSMark Johnson 	if (UCODE_MATCH_INTEL(cpi_sig, uhp->uh_signature,
7002449e17fSsherrym 	    uinfop->cui_platid, uhp->uh_proc_flags)) {
7012449e17fSsherrym 
7022449e17fSsherrym 		if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update)
7032449e17fSsherrym 			return (EM_HIGHERREV);
7042449e17fSsherrym 
7052449e17fSsherrym 		return (EM_OK);
7062449e17fSsherrym 	}
7072449e17fSsherrym 
7082449e17fSsherrym 	if (uetp != NULL) {
7092449e17fSsherrym 		int i;
7102449e17fSsherrym 
7112449e17fSsherrym 		for (i = 0; i < uetp->uet_count; i++) {
712adc586deSMark Johnson 			ucode_ext_sig_intel_t *uesp;
7132449e17fSsherrym 
7142449e17fSsherrym 			uesp = &uetp->uet_ext_sig[i];
7152449e17fSsherrym 
716adc586deSMark Johnson 			if (UCODE_MATCH_INTEL(cpi_sig, uesp->ues_signature,
7172449e17fSsherrym 			    uinfop->cui_platid, uesp->ues_proc_flags)) {
7182449e17fSsherrym 
7192449e17fSsherrym 				if (uinfop->cui_rev >= uhp->uh_rev &&
7202449e17fSsherrym 				    !ucode_force_update)
7212449e17fSsherrym 					return (EM_HIGHERREV);
7222449e17fSsherrym 
7232449e17fSsherrym 				return (EM_OK);
7242449e17fSsherrym 			}
7252449e17fSsherrym 		}
7262449e17fSsherrym 	}
7272449e17fSsherrym 
7282449e17fSsherrym 	return (EM_NOMATCH);
7292449e17fSsherrym }
7302449e17fSsherrym 
7312449e17fSsherrym /*ARGSUSED*/
7322449e17fSsherrym static int
7332449e17fSsherrym ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)
7342449e17fSsherrym {
735adc586deSMark Johnson 	ucode_update_t *uusp = (ucode_update_t *)arg1;
736adc586deSMark Johnson 	cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info;
7375e53ed34SHans Rosenfeld #ifndef __xpv
7385e53ed34SHans Rosenfeld 	on_trap_data_t otd;
7395e53ed34SHans Rosenfeld #endif
7402449e17fSsherrym 
741adc586deSMark Johnson 	ASSERT(ucode);
7422449e17fSsherrym 	ASSERT(uusp->ucodep);
7432449e17fSsherrym 
744882a7af5SMark Johnson #ifndef	__xpv
7452449e17fSsherrym 	/*
7462449e17fSsherrym 	 * Check one more time to see if it is really necessary to update
7472449e17fSsherrym 	 * microcode just in case this is a hyperthreaded processor where
7482449e17fSsherrym 	 * the threads share the same microcode.
7492449e17fSsherrym 	 */
7502449e17fSsherrym 	if (!ucode_force_update) {
751adc586deSMark Johnson 		ucode->read_rev(uinfop);
7522449e17fSsherrym 		uusp->new_rev = uinfop->cui_rev;
7532449e17fSsherrym 		if (uinfop->cui_rev >= uusp->expected_rev)
7542449e17fSsherrym 			return (0);
7552449e17fSsherrym 	}
7562449e17fSsherrym 
7575e53ed34SHans Rosenfeld 	if (!on_trap(&otd, OT_DATA_ACCESS))
758adc586deSMark Johnson 		wrmsr(ucode->write_msr, (uintptr_t)uusp->ucodep);
7595e53ed34SHans Rosenfeld 
7605e53ed34SHans Rosenfeld 	no_trap();
761882a7af5SMark Johnson #endif
762adc586deSMark Johnson 	ucode->read_rev(uinfop);
7632449e17fSsherrym 	uusp->new_rev = uinfop->cui_rev;
7642449e17fSsherrym 
7652449e17fSsherrym 	return (0);
7662449e17fSsherrym }
7672449e17fSsherrym 
768adc586deSMark Johnson /*ARGSUSED*/
769adc586deSMark Johnson static uint32_t
770adc586deSMark Johnson ucode_load_amd(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp)
7712449e17fSsherrym {
772adc586deSMark Johnson 	ucode_file_amd_t *ucodefp = ufp->amd;
773adc586deSMark Johnson #ifdef	__xpv
774adc586deSMark Johnson 	ucode_update_t uus;
7755e53ed34SHans Rosenfeld #else
7765e53ed34SHans Rosenfeld 	on_trap_data_t otd;
777adc586deSMark Johnson #endif
778adc586deSMark Johnson 
779adc586deSMark Johnson 	ASSERT(ucode);
780adc586deSMark Johnson 	ASSERT(ucodefp);
781adc586deSMark Johnson 
782adc586deSMark Johnson #ifndef	__xpv
7832449e17fSsherrym 	kpreempt_disable();
7845e53ed34SHans Rosenfeld 	if (on_trap(&otd, OT_DATA_ACCESS)) {
7855e53ed34SHans Rosenfeld 		no_trap();
7865e53ed34SHans Rosenfeld 		kpreempt_enable();
7875e53ed34SHans Rosenfeld 		return (0);
7885e53ed34SHans Rosenfeld 	}
789adc586deSMark Johnson 	wrmsr(ucode->write_msr, (uintptr_t)ucodefp);
7905e53ed34SHans Rosenfeld 	no_trap();
791adc586deSMark Johnson 	ucode->read_rev(uinfop);
7922449e17fSsherrym 	kpreempt_enable();
7930ba6f73dSMark Johnson 
7940ba6f73dSMark Johnson 	return (ucodefp->uf_header.uh_patch_id);
795adc586deSMark Johnson #else
7960ba6f73dSMark Johnson 	uus.ucodep = ucodefp->ucodep;
7970ba6f73dSMark Johnson 	uus.usize = ucodefp->usize;
798adc586deSMark Johnson 	ucode_load_xpv(&uus);
799adc586deSMark Johnson 	ucode->read_rev(uinfop);
800adc586deSMark Johnson 	uus.new_rev = uinfop->cui_rev;
801adc586deSMark Johnson 
8020ba6f73dSMark Johnson 	return (uus.new_rev);
8030ba6f73dSMark Johnson #endif
804adc586deSMark Johnson }
805adc586deSMark Johnson 
806adc586deSMark Johnson /*ARGSUSED2*/
807adc586deSMark Johnson static uint32_t
808adc586deSMark Johnson ucode_load_intel(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp)
809adc586deSMark Johnson {
810adc586deSMark Johnson 	ucode_file_intel_t *ucodefp = &ufp->intel;
811adc586deSMark Johnson #ifdef __xpv
812adc586deSMark Johnson 	uint32_t ext_offset;
813adc586deSMark Johnson 	uint32_t body_size;
814adc586deSMark Johnson 	uint32_t ext_size;
815adc586deSMark Johnson 	uint8_t *ustart;
816adc586deSMark Johnson 	uint32_t usize;
817adc586deSMark Johnson 	ucode_update_t uus;
818adc586deSMark Johnson #endif
819adc586deSMark Johnson 
820adc586deSMark Johnson 	ASSERT(ucode);
821adc586deSMark Johnson 
822adc586deSMark Johnson #ifdef __xpv
823adc586deSMark Johnson 	/*
824adc586deSMark Johnson 	 * the hypervisor wants the header, data, and extended
825adc586deSMark Johnson 	 * signature tables. We can only get here from the boot
826adc586deSMark Johnson 	 * CPU (cpu #0), we don't need to free as ucode_zalloc() will
827adc586deSMark Johnson 	 * use BOP_ALLOC().
828adc586deSMark Johnson 	 */
829adc586deSMark Johnson 	usize = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size);
830adc586deSMark Johnson 	ustart = ucode_zalloc(cp->cpu_id, usize);
831adc586deSMark Johnson 	ASSERT(ustart);
832adc586deSMark Johnson 
833adc586deSMark Johnson 	body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size);
834adc586deSMark Johnson 	ext_offset = body_size + UCODE_HEADER_SIZE_INTEL;
835adc586deSMark Johnson 	ext_size = usize - ext_offset;
836adc586deSMark Johnson 	ASSERT(ext_size >= 0);
837adc586deSMark Johnson 
838adc586deSMark Johnson 	(void) memcpy(ustart, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL);
839adc586deSMark Johnson 	(void) memcpy(&ustart[UCODE_HEADER_SIZE_INTEL], ucodefp->uf_body,
840adc586deSMark Johnson 	    body_size);
841adc586deSMark Johnson 	if (ext_size > 0) {
842adc586deSMark Johnson 		(void) memcpy(&ustart[ext_offset],
843adc586deSMark Johnson 		    ucodefp->uf_ext_table, ext_size);
844adc586deSMark Johnson 	}
845adc586deSMark Johnson 	uus.ucodep = ustart;
846adc586deSMark Johnson 	uus.usize = usize;
847adc586deSMark Johnson 	ucode_load_xpv(&uus);
848adc586deSMark Johnson 	ucode->read_rev(uinfop);
849adc586deSMark Johnson 	uus.new_rev = uinfop->cui_rev;
850adc586deSMark Johnson #else
851adc586deSMark Johnson 	kpreempt_disable();
852adc586deSMark Johnson 	wrmsr(ucode->write_msr, (uintptr_t)ucodefp->uf_body);
853adc586deSMark Johnson 	ucode->read_rev(uinfop);
854adc586deSMark Johnson 	kpreempt_enable();
855adc586deSMark Johnson #endif
856adc586deSMark Johnson 
857adc586deSMark Johnson 	return (ucodefp->uf_header->uh_rev);
8582449e17fSsherrym }
8592449e17fSsherrym 
860882a7af5SMark Johnson 
861882a7af5SMark Johnson #ifdef	__xpv
862882a7af5SMark Johnson static void
863adc586deSMark Johnson ucode_load_xpv(ucode_update_t *uusp)
864882a7af5SMark Johnson {
865882a7af5SMark Johnson 	xen_platform_op_t op;
866882a7af5SMark Johnson 	int e;
867882a7af5SMark Johnson 
868882a7af5SMark Johnson 	ASSERT(DOMAIN_IS_INITDOMAIN(xen_info));
869882a7af5SMark Johnson 
870882a7af5SMark Johnson 	kpreempt_disable();
871882a7af5SMark Johnson 	op.cmd = XENPF_microcode_update;
872882a7af5SMark Johnson 	op.interface_version = XENPF_INTERFACE_VERSION;
873882a7af5SMark Johnson 	/*LINTED: constant in conditional context*/
874adc586deSMark Johnson 	set_xen_guest_handle(op.u.microcode.data, uusp->ucodep);
875adc586deSMark Johnson 	op.u.microcode.length = uusp->usize;
876882a7af5SMark Johnson 	e = HYPERVISOR_platform_op(&op);
877882a7af5SMark Johnson 	if (e != 0) {
878882a7af5SMark Johnson 		cmn_err(CE_WARN, "hypervisor failed to accept uCode update");
879882a7af5SMark Johnson 	}
880882a7af5SMark Johnson 	kpreempt_enable();
881882a7af5SMark Johnson }
882882a7af5SMark Johnson #endif /* __xpv */
883882a7af5SMark Johnson 
884adc586deSMark Johnson static void
885adc586deSMark Johnson ucode_read_rev_amd(cpu_ucode_info_t *uinfop)
886adc586deSMark Johnson {
887adc586deSMark Johnson 	uinfop->cui_rev = rdmsr(MSR_AMD_PATCHLEVEL);
888adc586deSMark Johnson }
889882a7af5SMark Johnson 
8902449e17fSsherrym static void
891adc586deSMark Johnson ucode_read_rev_intel(cpu_ucode_info_t *uinfop)
8922449e17fSsherrym {
8932449e17fSsherrym 	struct cpuid_regs crs;
8942449e17fSsherrym 
8952449e17fSsherrym 	/*
8962449e17fSsherrym 	 * The Intel 64 and IA-32 Architecture Software Developer's Manual
8972449e17fSsherrym 	 * recommends that MSR_INTC_UCODE_REV be loaded with 0 first, then
8982449e17fSsherrym 	 * execute cpuid to guarantee the correct reading of this register.
8992449e17fSsherrym 	 */
9002449e17fSsherrym 	wrmsr(MSR_INTC_UCODE_REV, 0);
9012449e17fSsherrym 	(void) __cpuid_insn(&crs);
9022449e17fSsherrym 	uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT);
9032449e17fSsherrym }
9042449e17fSsherrym 
905adc586deSMark Johnson static ucode_errno_t
906adc586deSMark Johnson ucode_extract_amd(ucode_update_t *uusp, uint8_t *ucodep, int size)
907adc586deSMark Johnson {
9080ba6f73dSMark Johnson #ifndef __xpv
909adc586deSMark Johnson 	uint32_t *ptr = (uint32_t *)ucodep;
910adc586deSMark Johnson 	ucode_eqtbl_amd_t *eqtbl;
911adc586deSMark Johnson 	ucode_file_amd_t *ufp;
9120ba6f73dSMark Johnson 	int count;
9130ba6f73dSMark Johnson 	int higher = 0;
9140ba6f73dSMark Johnson 	ucode_errno_t rc = EM_NOMATCH;
9150ba6f73dSMark Johnson 	uint16_t eq_sig;
916adc586deSMark Johnson 
917adc586deSMark Johnson 	/* skip over magic number & equivalence table header */
918adc586deSMark Johnson 	ptr += 2; size -= 8;
919adc586deSMark Johnson 
920adc586deSMark Johnson 	count = *ptr++; size -= 4;
921adc586deSMark Johnson 	for (eqtbl = (ucode_eqtbl_amd_t *)ptr;
922adc586deSMark Johnson 	    eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != uusp->sig;
923adc586deSMark Johnson 	    eqtbl++)
924adc586deSMark Johnson 		;
925adc586deSMark Johnson 
926adc586deSMark Johnson 	eq_sig = eqtbl->ue_equiv_cpu;
927adc586deSMark Johnson 
928adc586deSMark Johnson 	/* No equivalent CPU id found, assume outdated microcode file. */
929adc586deSMark Johnson 	if (eq_sig == 0)
930adc586deSMark Johnson 		return (EM_HIGHERREV);
931adc586deSMark Johnson 
932adc586deSMark Johnson 	/* Use the first microcode patch that matches. */
933adc586deSMark Johnson 	do {
934adc586deSMark Johnson 		ptr += count >> 2; size -= count;
935adc586deSMark Johnson 
936adc586deSMark Johnson 		if (!size)
9370ba6f73dSMark Johnson 			return (higher ? EM_HIGHERREV : EM_NOMATCH);
938adc586deSMark Johnson 
939adc586deSMark Johnson 		ptr++; size -= 4;
940adc586deSMark Johnson 		count = *ptr++; size -= 4;
941adc586deSMark Johnson 		ufp = (ucode_file_amd_t *)ptr;
9420ba6f73dSMark Johnson 
9430ba6f73dSMark Johnson 		rc = ucode_match_amd(eq_sig, &uusp->info, ufp, count);
9440ba6f73dSMark Johnson 		if (rc == EM_HIGHERREV)
9450ba6f73dSMark Johnson 			higher = 1;
9460ba6f73dSMark Johnson 	} while (rc != EM_OK);
947adc586deSMark Johnson 
948adc586deSMark Johnson 	uusp->ucodep = (uint8_t *)ufp;
949adc586deSMark Johnson 	uusp->usize = count;
950adc586deSMark Johnson 	uusp->expected_rev = ufp->uf_header.uh_patch_id;
9510ba6f73dSMark Johnson #else
9520ba6f73dSMark Johnson 	/*
9530ba6f73dSMark Johnson 	 * The hypervisor will choose the patch to load, so there is no way to
9540ba6f73dSMark Johnson 	 * know the "expected revision" in advance. This is especially true on
9550ba6f73dSMark Johnson 	 * mixed-revision systems where more than one patch will be loaded.
9560ba6f73dSMark Johnson 	 */
9570ba6f73dSMark Johnson 	uusp->expected_rev = 0;
9580ba6f73dSMark Johnson 	uusp->ucodep = ucodep;
9590ba6f73dSMark Johnson 	uusp->usize = size;
9600ba6f73dSMark Johnson 
9610ba6f73dSMark Johnson 	ucode_chipset_amd(ucodep, size);
9620ba6f73dSMark Johnson #endif
963adc586deSMark Johnson 
964adc586deSMark Johnson 	return (EM_OK);
965adc586deSMark Johnson }
966adc586deSMark Johnson 
967adc586deSMark Johnson static ucode_errno_t
968adc586deSMark Johnson ucode_extract_intel(ucode_update_t *uusp, uint8_t *ucodep, int size)
969adc586deSMark Johnson {
970adc586deSMark Johnson 	uint32_t	header_size = UCODE_HEADER_SIZE_INTEL;
971adc586deSMark Johnson 	int		remaining;
972adc586deSMark Johnson 	int		found = 0;
973adc586deSMark Johnson 	ucode_errno_t	search_rc = EM_NOMATCH; /* search result */
974adc586deSMark Johnson 
975adc586deSMark Johnson 	/*
976adc586deSMark Johnson 	 * Go through the whole buffer in case there are
977adc586deSMark Johnson 	 * multiple versions of matching microcode for this
978adc586deSMark Johnson 	 * processor.
979adc586deSMark Johnson 	 */
980adc586deSMark Johnson 	for (remaining = size; remaining > 0; ) {
981adc586deSMark Johnson 		int	total_size, body_size, ext_size;
982adc586deSMark Johnson 		uint8_t	*curbuf = &ucodep[size - remaining];
983adc586deSMark Johnson 		ucode_header_intel_t *uhp = (ucode_header_intel_t *)curbuf;
984adc586deSMark Johnson 		ucode_ext_table_intel_t *uetp = NULL;
985adc586deSMark Johnson 		ucode_errno_t tmprc;
986adc586deSMark Johnson 
987adc586deSMark Johnson 		total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
988adc586deSMark Johnson 		body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
989adc586deSMark Johnson 		ext_size = total_size - (header_size + body_size);
990adc586deSMark Johnson 
991adc586deSMark Johnson 		if (ext_size > 0)
992adc586deSMark Johnson 			uetp = (ucode_ext_table_intel_t *)
993adc586deSMark Johnson 			    &curbuf[header_size + body_size];
994adc586deSMark Johnson 
995adc586deSMark Johnson 		tmprc = ucode_match_intel(uusp->sig, &uusp->info, uhp, uetp);
996adc586deSMark Johnson 
997adc586deSMark Johnson 		/*
998adc586deSMark Johnson 		 * Since we are searching through a big file
999adc586deSMark Johnson 		 * containing microcode for pretty much all the
1000adc586deSMark Johnson 		 * processors, we are bound to get EM_NOMATCH
1001adc586deSMark Johnson 		 * at one point.  However, if we return
1002adc586deSMark Johnson 		 * EM_NOMATCH to users, it will really confuse
1003adc586deSMark Johnson 		 * them.  Therefore, if we ever find a match of
1004adc586deSMark Johnson 		 * a lower rev, we will set return code to
1005adc586deSMark Johnson 		 * EM_HIGHERREV.
1006adc586deSMark Johnson 		 */
1007adc586deSMark Johnson 		if (tmprc == EM_HIGHERREV)
1008adc586deSMark Johnson 			search_rc = EM_HIGHERREV;
1009adc586deSMark Johnson 
1010adc586deSMark Johnson 		if (tmprc == EM_OK &&
1011adc586deSMark Johnson 		    uusp->expected_rev < uhp->uh_rev) {
1012adc586deSMark Johnson #ifndef __xpv
1013adc586deSMark Johnson 			uusp->ucodep = (uint8_t *)&curbuf[header_size];
1014adc586deSMark Johnson #else
1015adc586deSMark Johnson 			uusp->ucodep = (uint8_t *)curbuf;
1016adc586deSMark Johnson #endif
1017adc586deSMark Johnson 			uusp->usize =
1018adc586deSMark Johnson 			    UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
1019adc586deSMark Johnson 			uusp->expected_rev = uhp->uh_rev;
1020adc586deSMark Johnson 			found = 1;
1021adc586deSMark Johnson 		}
1022adc586deSMark Johnson 
1023adc586deSMark Johnson 		remaining -= total_size;
1024adc586deSMark Johnson 	}
1025adc586deSMark Johnson 
1026adc586deSMark Johnson 	if (!found)
1027adc586deSMark Johnson 		return (search_rc);
1028adc586deSMark Johnson 
1029adc586deSMark Johnson 	return (EM_OK);
1030adc586deSMark Johnson }
10312449e17fSsherrym /*
10322449e17fSsherrym  * Entry point to microcode update from the ucode_drv driver.
10332449e17fSsherrym  *
10342449e17fSsherrym  * Returns EM_OK on success, corresponding error code on failure.
10352449e17fSsherrym  */
10362449e17fSsherrym ucode_errno_t
10372449e17fSsherrym ucode_update(uint8_t *ucodep, int size)
10382449e17fSsherrym {
10392449e17fSsherrym 	int		found = 0;
10402449e17fSsherrym 	processorid_t	id;
1041adc586deSMark Johnson 	ucode_update_t	cached = { 0 };
1042adc586deSMark Johnson 	ucode_update_t	*cachedp = NULL;
10432449e17fSsherrym 	ucode_errno_t	rc = EM_OK;
10442449e17fSsherrym 	ucode_errno_t	search_rc = EM_NOMATCH; /* search result */
10452449e17fSsherrym 	cpuset_t cpuset;
10462449e17fSsherrym 
1047adc586deSMark Johnson 	ASSERT(ucode);
10482449e17fSsherrym 	ASSERT(ucodep);
10492449e17fSsherrym 	CPUSET_ZERO(cpuset);
10502449e17fSsherrym 
1051adc586deSMark Johnson 	if (!ucode->capable(CPU))
10522449e17fSsherrym 		return (EM_NOTSUP);
10532449e17fSsherrym 
10542449e17fSsherrym 	mutex_enter(&cpu_lock);
10552449e17fSsherrym 
10562449e17fSsherrym 	for (id = 0; id < max_ncpus; id++) {
10572449e17fSsherrym 		cpu_t *cpu;
1058adc586deSMark Johnson 		ucode_update_t uus = { 0 };
1059adc586deSMark Johnson 		ucode_update_t *uusp = &uus;
10602449e17fSsherrym 
10612449e17fSsherrym 		/*
10622449e17fSsherrym 		 * If there is no such CPU or it is not xcall ready, skip it.
10632449e17fSsherrym 		 */
10642449e17fSsherrym 		if ((cpu = cpu_get(id)) == NULL ||
10652449e17fSsherrym 		    !(cpu->cpu_flags & CPU_READY))
10662449e17fSsherrym 			continue;
10672449e17fSsherrym 
10682449e17fSsherrym 		uusp->sig = cpuid_getsig(cpu);
10692449e17fSsherrym 		bcopy(cpu->cpu_m.mcpu_ucode_info, &uusp->info,
10702449e17fSsherrym 		    sizeof (uusp->info));
10712449e17fSsherrym 
10722449e17fSsherrym 		/*
10732449e17fSsherrym 		 * If the current CPU has the same signature and platform
10742449e17fSsherrym 		 * id as the previous one we processed, reuse the information.
10752449e17fSsherrym 		 */
10762449e17fSsherrym 		if (cachedp && cachedp->sig == cpuid_getsig(cpu) &&
10772449e17fSsherrym 		    cachedp->info.cui_platid == uusp->info.cui_platid) {
10782449e17fSsherrym 			uusp->ucodep = cachedp->ucodep;
10792449e17fSsherrym 			uusp->expected_rev = cachedp->expected_rev;
10802449e17fSsherrym 			/*
10812449e17fSsherrym 			 * Intuitively we should check here to see whether the
10822449e17fSsherrym 			 * running microcode rev is >= the expected rev, and
10832449e17fSsherrym 			 * quit if it is.  But we choose to proceed with the
10842449e17fSsherrym 			 * xcall regardless of the running version so that
10852449e17fSsherrym 			 * the other threads in an HT processor can update
10862449e17fSsherrym 			 * the cpu_ucode_info structure in machcpu.
10872449e17fSsherrym 			 */
1088adc586deSMark Johnson 		} else if ((search_rc = ucode->extract(uusp, ucodep, size))
1089adc586deSMark Johnson 		    == EM_OK) {
10902449e17fSsherrym 			bcopy(uusp, &cached, sizeof (cached));
10912449e17fSsherrym 			cachedp = &cached;
10922449e17fSsherrym 			found = 1;
10932449e17fSsherrym 		}
10942449e17fSsherrym 
10952449e17fSsherrym 		/* Nothing to do */
10962449e17fSsherrym 		if (uusp->ucodep == NULL)
10972449e17fSsherrym 			continue;
10982449e17fSsherrym 
1099882a7af5SMark Johnson #ifdef	__xpv
1100882a7af5SMark Johnson 		/*
1101882a7af5SMark Johnson 		 * for i86xpv, the hypervisor will update all the CPUs.
1102882a7af5SMark Johnson 		 * the hypervisor wants the header, data, and extended
1103882a7af5SMark Johnson 		 * signature tables. ucode_write will just read in the
1104882a7af5SMark Johnson 		 * updated version on all the CPUs after the update has
1105882a7af5SMark Johnson 		 * completed.
1106882a7af5SMark Johnson 		 */
1107c9b5d7d2SMark Johnson 		if (id == 0) {
1108adc586deSMark Johnson 			ucode_load_xpv(uusp);
1109c9b5d7d2SMark Johnson 		}
1110882a7af5SMark Johnson #endif
1111882a7af5SMark Johnson 
11122449e17fSsherrym 		CPUSET_ADD(cpuset, id);
11132449e17fSsherrym 		kpreempt_disable();
1114f34a7178SJoe Bonasera 		xc_sync((xc_arg_t)uusp, 0, 0, CPUSET2BV(cpuset), ucode_write);
11152449e17fSsherrym 		kpreempt_enable();
11162449e17fSsherrym 		CPUSET_DEL(cpuset, id);
11172449e17fSsherrym 
11185e53ed34SHans Rosenfeld 		if (uusp->new_rev != 0 && uusp->info.cui_rev == uusp->new_rev &&
11195e53ed34SHans Rosenfeld 		    !ucode_force_update) {
11200ba6f73dSMark Johnson 			rc = EM_HIGHERREV;
11210ba6f73dSMark Johnson 		} else if ((uusp->new_rev == 0) || (uusp->expected_rev != 0 &&
11220ba6f73dSMark Johnson 		    uusp->expected_rev != uusp->new_rev)) {
11232449e17fSsherrym 			cmn_err(CE_WARN, ucode_failure_fmt,
11242449e17fSsherrym 			    id, uusp->info.cui_rev, uusp->expected_rev);
11252449e17fSsherrym 			rc = EM_UPDATE;
11260ba6f73dSMark Johnson 		} else {
11270ba6f73dSMark Johnson 			cmn_err(CE_CONT, ucode_success_fmt,
11280ba6f73dSMark Johnson 			    id, uusp->info.cui_rev, uusp->new_rev);
11292449e17fSsherrym 		}
11302449e17fSsherrym 	}
11312449e17fSsherrym 
11322449e17fSsherrym 	mutex_exit(&cpu_lock);
11332449e17fSsherrym 
11342449e17fSsherrym 	if (!found)
11352449e17fSsherrym 		rc = search_rc;
11362449e17fSsherrym 
11372449e17fSsherrym 	return (rc);
11382449e17fSsherrym }
11392449e17fSsherrym 
11402449e17fSsherrym /*
11412449e17fSsherrym  * Initialize mcpu_ucode_info, and perform microcode update if necessary.
11422449e17fSsherrym  * This is the entry point from boot path where pointer to CPU structure
11432449e17fSsherrym  * is available.
11442449e17fSsherrym  *
11452449e17fSsherrym  * cpuid_info must be initialized before ucode_check can be called.
11462449e17fSsherrym  */
11472449e17fSsherrym void
11482449e17fSsherrym ucode_check(cpu_t *cp)
11492449e17fSsherrym {
1150adc586deSMark Johnson 	cpu_ucode_info_t *uinfop;
11512449e17fSsherrym 	ucode_errno_t rc = EM_OK;
1152adc586deSMark Johnson 	uint32_t new_rev = 0;
11532449e17fSsherrym 
11542449e17fSsherrym 	ASSERT(cp);
1155a3114836SGerry Liu 	/*
1156a3114836SGerry Liu 	 * Space statically allocated for BSP, ensure pointer is set
1157a3114836SGerry Liu 	 */
1158a3114836SGerry Liu 	if (cp->cpu_id == 0 && cp->cpu_m.mcpu_ucode_info == NULL)
11592449e17fSsherrym 		cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0;
11602449e17fSsherrym 
11612449e17fSsherrym 	uinfop = cp->cpu_m.mcpu_ucode_info;
11622449e17fSsherrym 	ASSERT(uinfop);
11632449e17fSsherrym 
1164adc586deSMark Johnson 	/* set up function pointers if not already done */
1165adc586deSMark Johnson 	if (!ucode)
1166adc586deSMark Johnson 		switch (cpuid_getvendor(cp)) {
1167adc586deSMark Johnson 		case X86_VENDOR_AMD:
1168adc586deSMark Johnson 			ucode = &ucode_amd;
1169adc586deSMark Johnson 			break;
1170adc586deSMark Johnson 		case X86_VENDOR_Intel:
1171adc586deSMark Johnson 			ucode = &ucode_intel;
1172adc586deSMark Johnson 			break;
1173adc586deSMark Johnson 		default:
1174126b0a71SMark Johnson 			ucode = NULL;
1175adc586deSMark Johnson 			return;
1176adc586deSMark Johnson 		}
1177adc586deSMark Johnson 
1178adc586deSMark Johnson 	if (!ucode->capable(cp))
11792449e17fSsherrym 		return;
11802449e17fSsherrym 
11812449e17fSsherrym 	/*
11822449e17fSsherrym 	 * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon
11832449e17fSsherrym 	 * (Family 6, model 5 and above) and all processors after.
11842449e17fSsherrym 	 */
1185adc586deSMark Johnson 	if ((cpuid_getvendor(cp) == X86_VENDOR_Intel) &&
1186adc586deSMark Johnson 	    ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6))) {
11872449e17fSsherrym 		uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >>
11882449e17fSsherrym 		    INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK);
11892449e17fSsherrym 	}
11902449e17fSsherrym 
1191adc586deSMark Johnson 	ucode->read_rev(uinfop);
11922449e17fSsherrym 
1193c9b5d7d2SMark Johnson #ifdef	__xpv
1194c9b5d7d2SMark Johnson 	/*
1195c9b5d7d2SMark Johnson 	 * for i86xpv, the hypervisor will update all the CPUs. We only need
1196c9b5d7d2SMark Johnson 	 * do do this on one of the CPUs (and there always is a CPU 0).
1197c9b5d7d2SMark Johnson 	 */
1198c9b5d7d2SMark Johnson 	if (cp->cpu_id != 0) {
1199c9b5d7d2SMark Johnson 		return;
1200c9b5d7d2SMark Johnson 	}
1201c9b5d7d2SMark Johnson #endif
1202c9b5d7d2SMark Johnson 
12032449e17fSsherrym 	/*
12042449e17fSsherrym 	 * Check to see if we need ucode update
12052449e17fSsherrym 	 */
1206adc586deSMark Johnson 	if ((rc = ucode->locate(cp, uinfop, &ucodefile)) == EM_OK) {
1207adc586deSMark Johnson 		new_rev = ucode->load(&ucodefile, uinfop, cp);
1208882a7af5SMark Johnson 
1209adc586deSMark Johnson 		if (uinfop->cui_rev != new_rev)
12102449e17fSsherrym 			cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id,
1211adc586deSMark Johnson 			    uinfop->cui_rev, new_rev);
12122449e17fSsherrym 	}
12132449e17fSsherrym 
12142449e17fSsherrym 	/*
12152449e17fSsherrym 	 * If we fail to find a match for any reason, free the file structure
12162449e17fSsherrym 	 * just in case we have read in a partial file.
12172449e17fSsherrym 	 *
12182449e17fSsherrym 	 * Since the scratch memory for holding the microcode for the boot CPU
12192449e17fSsherrym 	 * came from BOP_ALLOC, we will reset the data structure as if we
12202449e17fSsherrym 	 * never did the allocation so we don't have to keep track of this
12212449e17fSsherrym 	 * special chunk of memory.  We free the memory used for the rest
12222449e17fSsherrym 	 * of the CPUs in start_other_cpus().
12232449e17fSsherrym 	 */
12242449e17fSsherrym 	if (rc != EM_OK || cp->cpu_id == 0)
1225adc586deSMark Johnson 		ucode->file_reset(&ucodefile, cp->cpu_id);
12262449e17fSsherrym }
12272449e17fSsherrym 
12282449e17fSsherrym /*
12292449e17fSsherrym  * Returns microcode revision from the machcpu structure.
12302449e17fSsherrym  */
12312449e17fSsherrym ucode_errno_t
12322449e17fSsherrym ucode_get_rev(uint32_t *revp)
12332449e17fSsherrym {
12342449e17fSsherrym 	int i;
12352449e17fSsherrym 
1236adc586deSMark Johnson 	ASSERT(ucode);
12372449e17fSsherrym 	ASSERT(revp);
12382449e17fSsherrym 
1239adc586deSMark Johnson 	if (!ucode->capable(CPU))
12402449e17fSsherrym 		return (EM_NOTSUP);
12412449e17fSsherrym 
12422449e17fSsherrym 	mutex_enter(&cpu_lock);
12432449e17fSsherrym 	for (i = 0; i < max_ncpus; i++) {
12442449e17fSsherrym 		cpu_t *cpu;
12452449e17fSsherrym 
12462449e17fSsherrym 		if ((cpu = cpu_get(i)) == NULL)
12472449e17fSsherrym 			continue;
12482449e17fSsherrym 
12492449e17fSsherrym 		revp[i] = cpu->cpu_m.mcpu_ucode_info->cui_rev;
12502449e17fSsherrym 	}
12512449e17fSsherrym 	mutex_exit(&cpu_lock);
12522449e17fSsherrym 
12532449e17fSsherrym 	return (EM_OK);
12542449e17fSsherrym }
1255