xref: /illumos-gate/usr/src/uts/intel/os/microcode.c (revision 42a10e59)
1d32f26eeSAndy Fiddaman /*
2d32f26eeSAndy Fiddaman  * CDDL HEADER START
3d32f26eeSAndy Fiddaman  *
4d32f26eeSAndy Fiddaman  * The contents of this file are subject to the terms of the
5d32f26eeSAndy Fiddaman  * Common Development and Distribution License (the "License").
6d32f26eeSAndy Fiddaman  * You may not use this file except in compliance with the License.
7d32f26eeSAndy Fiddaman  *
8d32f26eeSAndy Fiddaman  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d32f26eeSAndy Fiddaman  * or http://www.opensolaris.org/os/licensing.
10d32f26eeSAndy Fiddaman  * See the License for the specific language governing permissions
11d32f26eeSAndy Fiddaman  * and limitations under the License.
12d32f26eeSAndy Fiddaman  *
13d32f26eeSAndy Fiddaman  * When distributing Covered Code, include this CDDL HEADER in each
14d32f26eeSAndy Fiddaman  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d32f26eeSAndy Fiddaman  * If applicable, add the following below this CDDL HEADER, with the
16d32f26eeSAndy Fiddaman  * fields enclosed by brackets "[]" replaced with your own identifying
17d32f26eeSAndy Fiddaman  * information: Portions Copyright [yyyy] [name of copyright owner]
18d32f26eeSAndy Fiddaman  *
19d32f26eeSAndy Fiddaman  * CDDL HEADER END
20d32f26eeSAndy Fiddaman  */
21d32f26eeSAndy Fiddaman 
22d32f26eeSAndy Fiddaman /*
23d32f26eeSAndy Fiddaman  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24d32f26eeSAndy Fiddaman  * Use is subject to license terms.
25d32f26eeSAndy Fiddaman  *
26d32f26eeSAndy Fiddaman  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27d32f26eeSAndy Fiddaman  * Copyright (c) 2018, Joyent, Inc.
28d32f26eeSAndy Fiddaman  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
29d32f26eeSAndy Fiddaman  * Copyright 2023 Oxide Computer Company
30d32f26eeSAndy Fiddaman  */
31d32f26eeSAndy Fiddaman 
32d32f26eeSAndy Fiddaman #include <sys/bootconf.h>
33d32f26eeSAndy Fiddaman #include <sys/cmn_err.h>
34d32f26eeSAndy Fiddaman #include <sys/controlregs.h>
35d32f26eeSAndy Fiddaman #include <sys/utsname.h>
36d32f26eeSAndy Fiddaman #include <sys/debug.h>
37d32f26eeSAndy Fiddaman #include <sys/kobj.h>
38d32f26eeSAndy Fiddaman #include <sys/kobj_impl.h>
39d32f26eeSAndy Fiddaman #include <sys/ontrap.h>
40d32f26eeSAndy Fiddaman #include <sys/systeminfo.h>
41d32f26eeSAndy Fiddaman #include <sys/systm.h>
42d32f26eeSAndy Fiddaman #include <sys/ucode.h>
43d32f26eeSAndy Fiddaman #include <sys/x86_archext.h>
44d32f26eeSAndy Fiddaman #include <sys/x_call.h>
45d32f26eeSAndy Fiddaman 
46d32f26eeSAndy Fiddaman /*
47d32f26eeSAndy Fiddaman  * mcpu_ucode_info for the boot CPU.  Statically allocated.
48d32f26eeSAndy Fiddaman  */
49d32f26eeSAndy Fiddaman static struct cpu_ucode_info cpu_ucode_info0;
50d32f26eeSAndy Fiddaman static const ucode_source_t *ucode;
51d32f26eeSAndy Fiddaman static char *ucodepath;
52d32f26eeSAndy Fiddaman static kmutex_t ucode_lock;
53d32f26eeSAndy Fiddaman static bool ucode_cleanup_done = false;
54d32f26eeSAndy Fiddaman 
55d32f26eeSAndy Fiddaman static const char ucode_failure_fmt[] =
56d32f26eeSAndy Fiddaman 	"cpu%d: failed to update microcode from version 0x%x to 0x%x";
57d32f26eeSAndy Fiddaman static const char ucode_success_fmt[] =
58d32f26eeSAndy Fiddaman 	"?cpu%d: microcode has been updated from version 0x%x to 0x%x\n";
59d32f26eeSAndy Fiddaman 
60d32f26eeSAndy Fiddaman SET_DECLARE(ucode_source_set, ucode_source_t);
61d32f26eeSAndy Fiddaman 
62d32f26eeSAndy Fiddaman /*
63d32f26eeSAndy Fiddaman  * Force flag.  If set, the first microcode binary that matches
64d32f26eeSAndy Fiddaman  * signature and platform id will be used for microcode update,
65d32f26eeSAndy Fiddaman  * regardless of version.  Should only be used for debugging.
66d32f26eeSAndy Fiddaman  */
67d32f26eeSAndy Fiddaman int ucode_force_update = 0;
68d32f26eeSAndy Fiddaman 
69d32f26eeSAndy Fiddaman void
ucode_init(void)70d32f26eeSAndy Fiddaman ucode_init(void)
71d32f26eeSAndy Fiddaman {
72d32f26eeSAndy Fiddaman 	mutex_init(&ucode_lock, NULL, MUTEX_DEFAULT, NULL);
73d32f26eeSAndy Fiddaman }
74d32f26eeSAndy Fiddaman 
75d32f26eeSAndy Fiddaman /*
76d32f26eeSAndy Fiddaman  * Allocate space for mcpu_ucode_info in the machcpu structure
77d32f26eeSAndy Fiddaman  * for all non-boot CPUs.
78d32f26eeSAndy Fiddaman  */
79d32f26eeSAndy Fiddaman void
ucode_alloc_space(cpu_t * cp)80d32f26eeSAndy Fiddaman ucode_alloc_space(cpu_t *cp)
81d32f26eeSAndy Fiddaman {
82d32f26eeSAndy Fiddaman 	ASSERT(cp->cpu_id != 0);
83d32f26eeSAndy Fiddaman 	ASSERT(cp->cpu_m.mcpu_ucode_info == NULL);
84d32f26eeSAndy Fiddaman 	cp->cpu_m.mcpu_ucode_info =
85d32f26eeSAndy Fiddaman 	    kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP);
86d32f26eeSAndy Fiddaman }
87d32f26eeSAndy Fiddaman 
88d32f26eeSAndy Fiddaman void
ucode_free_space(cpu_t * cp)89d32f26eeSAndy Fiddaman ucode_free_space(cpu_t *cp)
90d32f26eeSAndy Fiddaman {
91d32f26eeSAndy Fiddaman 	ASSERT(cp->cpu_m.mcpu_ucode_info != NULL);
92d32f26eeSAndy Fiddaman 	ASSERT(cp->cpu_m.mcpu_ucode_info != &cpu_ucode_info0);
93d32f26eeSAndy Fiddaman 	kmem_free(cp->cpu_m.mcpu_ucode_info,
94d32f26eeSAndy Fiddaman 	    sizeof (*cp->cpu_m.mcpu_ucode_info));
95d32f26eeSAndy Fiddaman 	cp->cpu_m.mcpu_ucode_info = NULL;
96d32f26eeSAndy Fiddaman }
97d32f26eeSAndy Fiddaman 
98d32f26eeSAndy Fiddaman const char *
ucode_path(void)99d32f26eeSAndy Fiddaman ucode_path(void)
100d32f26eeSAndy Fiddaman {
101d32f26eeSAndy Fiddaman 	ASSERT(ucodepath != NULL);
102d32f26eeSAndy Fiddaman 	return (ucodepath);
103d32f26eeSAndy Fiddaman }
104d32f26eeSAndy Fiddaman 
105d32f26eeSAndy Fiddaman /*
106d32f26eeSAndy Fiddaman  * Allocate/free a buffer used to hold ucode data. Space for the boot CPU is
107d32f26eeSAndy Fiddaman  * allocated with BOP_ALLOC() and does not require a free.
108d32f26eeSAndy Fiddaman  */
109d32f26eeSAndy Fiddaman void *
ucode_zalloc(processorid_t id,size_t size)110d32f26eeSAndy Fiddaman ucode_zalloc(processorid_t id, size_t size)
111d32f26eeSAndy Fiddaman {
112d32f26eeSAndy Fiddaman 	if (id != 0)
113d32f26eeSAndy Fiddaman 		return (kmem_zalloc(size, KM_NOSLEEP));
114d32f26eeSAndy Fiddaman 
115d32f26eeSAndy Fiddaman 	/* BOP_ALLOC() failure results in panic */
116d32f26eeSAndy Fiddaman 	return (BOP_ALLOC(bootops, NULL, size, MMU_PAGESIZE));
117d32f26eeSAndy Fiddaman }
118d32f26eeSAndy Fiddaman 
119d32f26eeSAndy Fiddaman void
ucode_free(processorid_t id,void * buf,size_t size)120d32f26eeSAndy Fiddaman ucode_free(processorid_t id, void *buf, size_t size)
121d32f26eeSAndy Fiddaman {
122d32f26eeSAndy Fiddaman 	if (id != 0 && buf != NULL)
123d32f26eeSAndy Fiddaman 		kmem_free(buf, size);
124d32f26eeSAndy Fiddaman }
125d32f26eeSAndy Fiddaman 
126d32f26eeSAndy Fiddaman /*
127d32f26eeSAndy Fiddaman  * Called to free up space allocated for the microcode file. This is called
128d32f26eeSAndy Fiddaman  * from start_other_cpus() after an update attempt has been performed on all
129d32f26eeSAndy Fiddaman  * CPUs.
130d32f26eeSAndy Fiddaman  */
131d32f26eeSAndy Fiddaman void
ucode_cleanup(void)132d32f26eeSAndy Fiddaman ucode_cleanup(void)
133d32f26eeSAndy Fiddaman {
134d32f26eeSAndy Fiddaman 	mutex_enter(&ucode_lock);
135d32f26eeSAndy Fiddaman 	if (ucode != NULL)
136d32f26eeSAndy Fiddaman 		ucode->us_file_reset(-1);
137d32f26eeSAndy Fiddaman 	ucode_cleanup_done = true;
138d32f26eeSAndy Fiddaman 	mutex_exit(&ucode_lock);
139d32f26eeSAndy Fiddaman 
140d32f26eeSAndy Fiddaman 	/*
141d32f26eeSAndy Fiddaman 	 * We purposefully do not free 'ucodepath' here so that it persists for
142d32f26eeSAndy Fiddaman 	 * any future callers to ucode_check(), such as could occur on systems
143d32f26eeSAndy Fiddaman 	 * that support DR.
144d32f26eeSAndy Fiddaman 	 */
145d32f26eeSAndy Fiddaman }
146d32f26eeSAndy Fiddaman 
147d32f26eeSAndy Fiddaman static int
ucode_write(xc_arg_t arg1,xc_arg_t unused2,xc_arg_t unused3)148d32f26eeSAndy Fiddaman ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)
149d32f26eeSAndy Fiddaman {
150d32f26eeSAndy Fiddaman 	ucode_update_t *uusp = (ucode_update_t *)arg1;
151d32f26eeSAndy Fiddaman 	cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info;
152d32f26eeSAndy Fiddaman 	on_trap_data_t otd;
153d32f26eeSAndy Fiddaman 
154d32f26eeSAndy Fiddaman 	ASSERT(ucode != NULL);
155d32f26eeSAndy Fiddaman 	ASSERT(uusp->ucodep != NULL);
156d32f26eeSAndy Fiddaman 
157d32f26eeSAndy Fiddaman 	/*
158d32f26eeSAndy Fiddaman 	 * Check one more time to see if it is really necessary to update
159d32f26eeSAndy Fiddaman 	 * microcode just in case this is a hyperthreaded processor where
160d32f26eeSAndy Fiddaman 	 * the threads share the same microcode.
161d32f26eeSAndy Fiddaman 	 */
162d32f26eeSAndy Fiddaman 	if (!ucode_force_update) {
163d32f26eeSAndy Fiddaman 		ucode->us_read_rev(uinfop);
164d32f26eeSAndy Fiddaman 		uusp->new_rev = uinfop->cui_rev;
165d32f26eeSAndy Fiddaman 		if (uinfop->cui_rev >= uusp->expected_rev)
166d32f26eeSAndy Fiddaman 			return (0);
167d32f26eeSAndy Fiddaman 	}
168d32f26eeSAndy Fiddaman 
169d32f26eeSAndy Fiddaman 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
170d32f26eeSAndy Fiddaman 		if (ucode->us_invalidate) {
171d32f26eeSAndy Fiddaman 			/*
172d32f26eeSAndy Fiddaman 			 * On some platforms a cache invalidation is required
173d32f26eeSAndy Fiddaman 			 * for the ucode update to be successful due to the
174d32f26eeSAndy Fiddaman 			 * parts of the processor that the microcode is
175d32f26eeSAndy Fiddaman 			 * updating.
176d32f26eeSAndy Fiddaman 			 */
177d32f26eeSAndy Fiddaman 			invalidate_cache();
178d32f26eeSAndy Fiddaman 		}
179d32f26eeSAndy Fiddaman 		wrmsr(ucode->us_write_msr, (uintptr_t)uusp->ucodep);
180d32f26eeSAndy Fiddaman 	}
181d32f26eeSAndy Fiddaman 
182d32f26eeSAndy Fiddaman 	no_trap();
183d32f26eeSAndy Fiddaman 	ucode->us_read_rev(uinfop);
184d32f26eeSAndy Fiddaman 	uusp->new_rev = uinfop->cui_rev;
185d32f26eeSAndy Fiddaman 
186d32f26eeSAndy Fiddaman 	return (0);
187d32f26eeSAndy Fiddaman }
188d32f26eeSAndy Fiddaman 
189d32f26eeSAndy Fiddaman /*
190d32f26eeSAndy Fiddaman  * Entry points to microcode update from the 'ucode' driver.
191d32f26eeSAndy Fiddaman  */
192d32f26eeSAndy Fiddaman 
193d32f26eeSAndy Fiddaman ucode_errno_t
ucode_validate(uint8_t * ucodep,int size)194d32f26eeSAndy Fiddaman ucode_validate(uint8_t *ucodep, int size)
195d32f26eeSAndy Fiddaman {
196d32f26eeSAndy Fiddaman 	if (ucode == NULL)
197d32f26eeSAndy Fiddaman 		return (EM_NOTSUP);
198d32f26eeSAndy Fiddaman 	return (ucode->us_validate(ucodep, size));
199d32f26eeSAndy Fiddaman }
200d32f26eeSAndy Fiddaman 
201d32f26eeSAndy Fiddaman ucode_errno_t
ucode_update(uint8_t * ucodep,int size)202d32f26eeSAndy Fiddaman ucode_update(uint8_t *ucodep, int size)
203d32f26eeSAndy Fiddaman {
204d32f26eeSAndy Fiddaman 	int		found = 0;
205d32f26eeSAndy Fiddaman 	ucode_update_t	cached = { 0 };
206d32f26eeSAndy Fiddaman 	ucode_update_t	*cachedp = NULL;
207d32f26eeSAndy Fiddaman 	ucode_errno_t	rc = EM_OK;
208d32f26eeSAndy Fiddaman 	ucode_errno_t	search_rc = EM_NOMATCH; /* search result */
209d32f26eeSAndy Fiddaman 	cpuset_t cpuset;
210d32f26eeSAndy Fiddaman 
211d32f26eeSAndy Fiddaman 	ASSERT(ucode != 0);
212d32f26eeSAndy Fiddaman 	ASSERT(ucodep != 0);
213d32f26eeSAndy Fiddaman 	CPUSET_ZERO(cpuset);
214d32f26eeSAndy Fiddaman 
215d32f26eeSAndy Fiddaman 	if (!ucode->us_capable(CPU))
216d32f26eeSAndy Fiddaman 		return (EM_NOTSUP);
217d32f26eeSAndy Fiddaman 
218d32f26eeSAndy Fiddaman 	mutex_enter(&cpu_lock);
219d32f26eeSAndy Fiddaman 
220d32f26eeSAndy Fiddaman 	for (processorid_t id = 0; id < max_ncpus; id++) {
221d32f26eeSAndy Fiddaman 		cpu_t *cpu;
222d32f26eeSAndy Fiddaman 		ucode_update_t uus = { 0 };
223d32f26eeSAndy Fiddaman 		ucode_update_t *uusp = &uus;
224d32f26eeSAndy Fiddaman 
225d32f26eeSAndy Fiddaman 		/*
226d32f26eeSAndy Fiddaman 		 * If there is no such CPU or it is not xcall ready, skip it.
227d32f26eeSAndy Fiddaman 		 */
228d32f26eeSAndy Fiddaman 		if ((cpu = cpu_get(id)) == NULL ||
229d32f26eeSAndy Fiddaman 		    !(cpu->cpu_flags & CPU_READY)) {
230d32f26eeSAndy Fiddaman 			continue;
231d32f26eeSAndy Fiddaman 		}
232d32f26eeSAndy Fiddaman 
233d32f26eeSAndy Fiddaman 		uusp->sig = cpuid_getsig(cpu);
234d32f26eeSAndy Fiddaman 		bcopy(cpu->cpu_m.mcpu_ucode_info, &uusp->info,
235d32f26eeSAndy Fiddaman 		    sizeof (uusp->info));
236d32f26eeSAndy Fiddaman 
237d32f26eeSAndy Fiddaman 		/*
238d32f26eeSAndy Fiddaman 		 * If the current CPU has the same signature and platform
239d32f26eeSAndy Fiddaman 		 * id as the previous one we processed, reuse the information.
240d32f26eeSAndy Fiddaman 		 */
241d32f26eeSAndy Fiddaman 		if (cachedp && cachedp->sig == cpuid_getsig(cpu) &&
242d32f26eeSAndy Fiddaman 		    cachedp->info.cui_platid == uusp->info.cui_platid) {
243d32f26eeSAndy Fiddaman 			uusp->ucodep = cachedp->ucodep;
244d32f26eeSAndy Fiddaman 			uusp->expected_rev = cachedp->expected_rev;
245d32f26eeSAndy Fiddaman 			/*
246d32f26eeSAndy Fiddaman 			 * Intuitively we should check here to see whether the
247d32f26eeSAndy Fiddaman 			 * running microcode rev is >= the expected rev, and
248d32f26eeSAndy Fiddaman 			 * quit if it is.  But we choose to proceed with the
249d32f26eeSAndy Fiddaman 			 * xcall regardless of the running version so that
250d32f26eeSAndy Fiddaman 			 * the other threads in an HT processor can update
251d32f26eeSAndy Fiddaman 			 * the cpu_ucode_info structure in machcpu.
252d32f26eeSAndy Fiddaman 			 */
253d32f26eeSAndy Fiddaman 		} else if ((search_rc = ucode->us_extract(uusp, ucodep, size))
254d32f26eeSAndy Fiddaman 		    == EM_OK) {
255d32f26eeSAndy Fiddaman 			bcopy(uusp, &cached, sizeof (cached));
256d32f26eeSAndy Fiddaman 			cachedp = &cached;
257d32f26eeSAndy Fiddaman 			found = 1;
258d32f26eeSAndy Fiddaman 		}
259d32f26eeSAndy Fiddaman 
260d32f26eeSAndy Fiddaman 		/* Nothing to do */
261d32f26eeSAndy Fiddaman 		if (uusp->ucodep == NULL)
262d32f26eeSAndy Fiddaman 			continue;
263d32f26eeSAndy Fiddaman 
264d32f26eeSAndy Fiddaman 		CPUSET_ADD(cpuset, id);
265d32f26eeSAndy Fiddaman 		kpreempt_disable();
266d32f26eeSAndy Fiddaman 		xc_sync((xc_arg_t)uusp, 0, 0, CPUSET2BV(cpuset), ucode_write);
267d32f26eeSAndy Fiddaman 		kpreempt_enable();
268d32f26eeSAndy Fiddaman 		CPUSET_DEL(cpuset, id);
269d32f26eeSAndy Fiddaman 
270d32f26eeSAndy Fiddaman 		if (uusp->new_rev != 0 && uusp->info.cui_rev == uusp->new_rev &&
271d32f26eeSAndy Fiddaman 		    !ucode_force_update) {
272d32f26eeSAndy Fiddaman 			rc = EM_HIGHERREV;
273d32f26eeSAndy Fiddaman 		} else if ((uusp->new_rev == 0) || (uusp->expected_rev != 0 &&
274d32f26eeSAndy Fiddaman 		    uusp->expected_rev != uusp->new_rev)) {
275d32f26eeSAndy Fiddaman 			cmn_err(CE_WARN, ucode_failure_fmt,
276d32f26eeSAndy Fiddaman 			    id, uusp->info.cui_rev, uusp->expected_rev);
277d32f26eeSAndy Fiddaman 			rc = EM_UPDATE;
278d32f26eeSAndy Fiddaman 		} else {
279d32f26eeSAndy Fiddaman 			cmn_err(CE_CONT, ucode_success_fmt,
280d32f26eeSAndy Fiddaman 			    id, uusp->info.cui_rev, uusp->new_rev);
281d32f26eeSAndy Fiddaman 		}
282d32f26eeSAndy Fiddaman 	}
283d32f26eeSAndy Fiddaman 
284d32f26eeSAndy Fiddaman 	mutex_exit(&cpu_lock);
285d32f26eeSAndy Fiddaman 
286d32f26eeSAndy Fiddaman 	if (!found) {
287d32f26eeSAndy Fiddaman 		rc = search_rc;
288d32f26eeSAndy Fiddaman 	} else if (rc == EM_OK) {
289d32f26eeSAndy Fiddaman 		cpuid_post_ucodeadm();
290d32f26eeSAndy Fiddaman 	}
291d32f26eeSAndy Fiddaman 
292d32f26eeSAndy Fiddaman 	return (rc);
293d32f26eeSAndy Fiddaman }
294d32f26eeSAndy Fiddaman 
295d32f26eeSAndy Fiddaman /*
296d32f26eeSAndy Fiddaman  * Entry point to microcode update from mlsetup() and mp_startup()
297d32f26eeSAndy Fiddaman  * Initialize mcpu_ucode_info, and perform microcode update if necessary.
298d32f26eeSAndy Fiddaman  * cpuid_info must be initialized before ucode_check can be called.
299d32f26eeSAndy Fiddaman  */
300d32f26eeSAndy Fiddaman void
ucode_check(cpu_t * cp)301d32f26eeSAndy Fiddaman ucode_check(cpu_t *cp)
302d32f26eeSAndy Fiddaman {
303d32f26eeSAndy Fiddaman 	cpu_ucode_info_t *uinfop;
304d32f26eeSAndy Fiddaman 	ucode_errno_t rc = EM_OK;
305d32f26eeSAndy Fiddaman 	bool bsp = (cp->cpu_id == 0);
306d32f26eeSAndy Fiddaman 
307d32f26eeSAndy Fiddaman 	ASSERT(cp != NULL);
308d32f26eeSAndy Fiddaman 
309d32f26eeSAndy Fiddaman 	mutex_enter(&ucode_lock);
310d32f26eeSAndy Fiddaman 
311d32f26eeSAndy Fiddaman 	if (bsp) {
312d32f26eeSAndy Fiddaman 		/* Space statically allocated for BSP; ensure pointer is set */
313d32f26eeSAndy Fiddaman 		if (cp->cpu_m.mcpu_ucode_info == NULL)
314d32f26eeSAndy Fiddaman 			cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0;
315d32f26eeSAndy Fiddaman 
316d32f26eeSAndy Fiddaman 		/* Set up function pointers if not already done */
317d32f26eeSAndy Fiddaman 		if (ucode == NULL) {
318d32f26eeSAndy Fiddaman 			ucode_source_t **src;
319d32f26eeSAndy Fiddaman 
320d32f26eeSAndy Fiddaman 			SET_FOREACH(src, ucode_source_set) {
321d32f26eeSAndy Fiddaman 				if ((*src)->us_select(cp)) {
322d32f26eeSAndy Fiddaman 					ucode = *src;
323d32f26eeSAndy Fiddaman 					break;
324d32f26eeSAndy Fiddaman 				}
325d32f26eeSAndy Fiddaman 			}
326d32f26eeSAndy Fiddaman 
327999b0f56SAndy Fiddaman 			if (ucode == NULL)
328d32f26eeSAndy Fiddaman 				goto out;
329d32f26eeSAndy Fiddaman 
330999b0f56SAndy Fiddaman #ifdef DEBUG
331d32f26eeSAndy Fiddaman 			cmn_err(CE_CONT, "?ucode: selected %s\n",
332d32f26eeSAndy Fiddaman 			    ucode->us_name);
333999b0f56SAndy Fiddaman #endif
334d32f26eeSAndy Fiddaman 		}
335d32f26eeSAndy Fiddaman 	}
336d32f26eeSAndy Fiddaman 
337d32f26eeSAndy Fiddaman 	if (ucode == NULL)
338d32f26eeSAndy Fiddaman 		goto out;
339d32f26eeSAndy Fiddaman 
340d32f26eeSAndy Fiddaman 	if (ucodepath == NULL) {
341d32f26eeSAndy Fiddaman 		size_t sz;
342d32f26eeSAndy Fiddaman 		char *plat;
343d32f26eeSAndy Fiddaman 
344d32f26eeSAndy Fiddaman 		if (bsp) {
345d32f26eeSAndy Fiddaman 			const char *prop = "impl-arch-name";
346d32f26eeSAndy Fiddaman 			int len;
347d32f26eeSAndy Fiddaman 
348d32f26eeSAndy Fiddaman 			len = BOP_GETPROPLEN(bootops, prop);
349d32f26eeSAndy Fiddaman 
350d32f26eeSAndy Fiddaman 			if (len <= 0) {
351d32f26eeSAndy Fiddaman 				cmn_err(CE_WARN,
352d32f26eeSAndy Fiddaman 				    "ucode: could not find %s property", prop);
353d32f26eeSAndy Fiddaman 				goto out;
354d32f26eeSAndy Fiddaman 			}
355d32f26eeSAndy Fiddaman 
356d32f26eeSAndy Fiddaman 			/*
357d32f26eeSAndy Fiddaman 			 * On the BSP, this memory is allocated via BOP_ALLOC()
358d32f26eeSAndy Fiddaman 			 * -- which panics on failure -- and does not need to
359d32f26eeSAndy Fiddaman 			 * be explicitly freed.
360d32f26eeSAndy Fiddaman 			 */
361d32f26eeSAndy Fiddaman 			plat = ucode_zalloc(cp->cpu_id, len + 1);
362d32f26eeSAndy Fiddaman 			(void) BOP_GETPROP(bootops, prop, plat);
363d32f26eeSAndy Fiddaman 		} else {
364d32f26eeSAndy Fiddaman 			/*
365d32f26eeSAndy Fiddaman 			 * from common/conf/param.c, already filled in by
366d32f26eeSAndy Fiddaman 			 * setup_ddi() by this point.
367d32f26eeSAndy Fiddaman 			 */
368d32f26eeSAndy Fiddaman 			plat = platform;
369d32f26eeSAndy Fiddaman 		}
370d32f26eeSAndy Fiddaman 		if (plat[0] == '\0') {
371d32f26eeSAndy Fiddaman 			/*
372d32f26eeSAndy Fiddaman 			 * If we can't determine the architecture name,
373d32f26eeSAndy Fiddaman 			 * we cannot find microcode files for it.
374d32f26eeSAndy Fiddaman 			 * Return without setting 'ucode'.
375d32f26eeSAndy Fiddaman 			 */
376d32f26eeSAndy Fiddaman 			cmn_err(CE_WARN, "ucode: could not determine arch");
377d32f26eeSAndy Fiddaman 			goto out;
378d32f26eeSAndy Fiddaman 		}
379d32f26eeSAndy Fiddaman 
380d32f26eeSAndy Fiddaman 		sz = snprintf(NULL, 0, "/platform/%s/ucode", plat) + 1;
381d32f26eeSAndy Fiddaman 		/*
382d32f26eeSAndy Fiddaman 		 * Note that on the boot CPU, this allocation will be satisfied
383d32f26eeSAndy Fiddaman 		 * via BOP_ALLOC() and the returned address will not be valid
384d32f26eeSAndy Fiddaman 		 * once we come back into this function for the remaining CPUs.
385d32f26eeSAndy Fiddaman 		 * To deal with this, we throw the memory away at the end of
386d32f26eeSAndy Fiddaman 		 * this function if we are the BSP. The next CPU through here
387d32f26eeSAndy Fiddaman 		 * will re-create it using kmem and then it persists.
388d32f26eeSAndy Fiddaman 		 */
389d32f26eeSAndy Fiddaman 		ucodepath = ucode_zalloc(cp->cpu_id, sz);
390d32f26eeSAndy Fiddaman 		if (ucodepath == NULL) {
391d32f26eeSAndy Fiddaman 			cmn_err(CE_WARN,
392d32f26eeSAndy Fiddaman 			    "ucode: could not allocate memory for path");
393d32f26eeSAndy Fiddaman 			goto out;
394d32f26eeSAndy Fiddaman 		}
395d32f26eeSAndy Fiddaman 		(void) snprintf(ucodepath, sz, "/platform/%s/ucode", plat);
396d32f26eeSAndy Fiddaman 	}
397d32f26eeSAndy Fiddaman 
398d32f26eeSAndy Fiddaman 	uinfop = cp->cpu_m.mcpu_ucode_info;
399d32f26eeSAndy Fiddaman 	ASSERT(uinfop != NULL);
400d32f26eeSAndy Fiddaman 
401d32f26eeSAndy Fiddaman 	if (!ucode->us_capable(cp))
402d32f26eeSAndy Fiddaman 		goto out;
403d32f26eeSAndy Fiddaman 
404d32f26eeSAndy Fiddaman 	ucode->us_read_rev(uinfop);
405d32f26eeSAndy Fiddaman 
406d32f26eeSAndy Fiddaman 	/*
407d32f26eeSAndy Fiddaman 	 * Check to see if we need ucode update
408d32f26eeSAndy Fiddaman 	 */
409d32f26eeSAndy Fiddaman 	if ((rc = ucode->us_locate(cp, uinfop)) == EM_OK) {
410d32f26eeSAndy Fiddaman 		uint32_t old_rev, new_rev;
411d32f26eeSAndy Fiddaman 
412d32f26eeSAndy Fiddaman 		old_rev = uinfop->cui_rev;
413d32f26eeSAndy Fiddaman 		new_rev = ucode->us_load(uinfop);
414d32f26eeSAndy Fiddaman 
415d32f26eeSAndy Fiddaman 		if (uinfop->cui_rev != new_rev) {
416d32f26eeSAndy Fiddaman 			cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id,
417d32f26eeSAndy Fiddaman 			    old_rev, new_rev);
418d32f26eeSAndy Fiddaman 		} else {
419d32f26eeSAndy Fiddaman 			cmn_err(CE_CONT, ucode_success_fmt, cp->cpu_id,
420d32f26eeSAndy Fiddaman 			    old_rev, new_rev);
421d32f26eeSAndy Fiddaman 		}
422d32f26eeSAndy Fiddaman 	}
423d32f26eeSAndy Fiddaman 
424d32f26eeSAndy Fiddaman 	/*
425d32f26eeSAndy Fiddaman 	 * If we fail to find a match for any reason, free the file structure
426d32f26eeSAndy Fiddaman 	 * just in case we have read in a partial file.
427d32f26eeSAndy Fiddaman 	 *
428d32f26eeSAndy Fiddaman 	 * Since the scratch memory for holding the microcode for the boot CPU
429d32f26eeSAndy Fiddaman 	 * came from BOP_ALLOC, we will reset the data structure as if we
430d32f26eeSAndy Fiddaman 	 * never did the allocation so we don't have to keep track of this
431d32f26eeSAndy Fiddaman 	 * special chunk of memory.  We free the memory used for the rest
432d32f26eeSAndy Fiddaman 	 * of the CPUs in start_other_cpus().
433d32f26eeSAndy Fiddaman 	 *
434d32f26eeSAndy Fiddaman 	 * In case we end up here after ucode_cleanup() has been called, such
435d32f26eeSAndy Fiddaman 	 * as could occur with CPU hotplug, we also clear the memory and reset
436d32f26eeSAndy Fiddaman 	 * the data structure as nothing else will call ucode_cleanup() and we
437d32f26eeSAndy Fiddaman 	 * don't need to cache the data as we do during boot when starting the
438d32f26eeSAndy Fiddaman 	 * APs.
439d32f26eeSAndy Fiddaman 	 */
440d32f26eeSAndy Fiddaman 	if (rc != EM_OK || bsp || ucode_cleanup_done)
441d32f26eeSAndy Fiddaman 		ucode->us_file_reset(cp->cpu_id);
442d32f26eeSAndy Fiddaman 
443d32f26eeSAndy Fiddaman out:
444d32f26eeSAndy Fiddaman 	/*
445d32f26eeSAndy Fiddaman 	 * If this is the boot CPU, discard the memory that came from BOP_ALLOC
446d32f26eeSAndy Fiddaman 	 * and was used to build the ucode path.
447d32f26eeSAndy Fiddaman 	 */
448d32f26eeSAndy Fiddaman 	if (bsp)
449d32f26eeSAndy Fiddaman 		ucodepath = NULL;
450d32f26eeSAndy Fiddaman 
451d32f26eeSAndy Fiddaman 	mutex_exit(&ucode_lock);
452d32f26eeSAndy Fiddaman }
453d32f26eeSAndy Fiddaman 
454d32f26eeSAndy Fiddaman /*
455d32f26eeSAndy Fiddaman  * Returns microcode revision from the machcpu structure.
456d32f26eeSAndy Fiddaman  */
457d32f26eeSAndy Fiddaman ucode_errno_t
ucode_get_rev(uint32_t * revp)458d32f26eeSAndy Fiddaman ucode_get_rev(uint32_t *revp)
459d32f26eeSAndy Fiddaman {
460d32f26eeSAndy Fiddaman 	int i;
461d32f26eeSAndy Fiddaman 
462d32f26eeSAndy Fiddaman 	ASSERT(revp != NULL);
463d32f26eeSAndy Fiddaman 
464*42a10e59SAndy Fiddaman 	if (ucode == NULL || !ucode->us_capable(CPU))
465d32f26eeSAndy Fiddaman 		return (EM_NOTSUP);
466d32f26eeSAndy Fiddaman 
467d32f26eeSAndy Fiddaman 	mutex_enter(&cpu_lock);
468d32f26eeSAndy Fiddaman 	for (i = 0; i < max_ncpus; i++) {
469d32f26eeSAndy Fiddaman 		cpu_t *cpu;
470d32f26eeSAndy Fiddaman 
471d32f26eeSAndy Fiddaman 		if ((cpu = cpu_get(i)) == NULL)
472d32f26eeSAndy Fiddaman 			continue;
473d32f26eeSAndy Fiddaman 
474d32f26eeSAndy Fiddaman 		revp[i] = cpu->cpu_m.mcpu_ucode_info->cui_rev;
475d32f26eeSAndy Fiddaman 	}
476d32f26eeSAndy Fiddaman 	mutex_exit(&cpu_lock);
477d32f26eeSAndy Fiddaman 
478d32f26eeSAndy Fiddaman 	return (EM_OK);
479d32f26eeSAndy Fiddaman }
480