xref: /illumos-gate/usr/src/uts/i86pc/os/cmi.c (revision 2dc5cbd37af38054ac6aab88a3ecee22a13ed2eb)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright (c) 2018, Joyent, Inc.
26  */
27 
28 /*
29  * Public interface to routines implemented by CPU modules
30  */
31 
32 #include <sys/types.h>
33 #include <sys/atomic.h>
34 #include <sys/x86_archext.h>
35 #include <sys/cpu_module_impl.h>
36 #include <sys/cpu_module_ms.h>
37 #include <sys/fm/util.h>
38 #include <sys/reboot.h>
39 #include <sys/modctl.h>
40 #include <sys/param.h>
41 #include <sys/cmn_err.h>
42 #include <sys/systm.h>
43 #include <sys/fm/protocol.h>
44 #include <sys/pcb.h>
45 #include <sys/ontrap.h>
46 #include <sys/psw.h>
47 #include <sys/privregs.h>
48 #include <sys/machsystm.h>
49 
50 /*
51  * Set to force cmi_init to fail.
52  */
53 int cmi_no_init = 0;
54 
55 /*
56  * Set to avoid MCA initialization.
57  */
58 int cmi_no_mca_init = 0;
59 
60 /*
61  * If cleared for debugging we will not attempt to load a model-specific
62  * cpu module but will load the generic cpu module instead.
63  */
64 int cmi_force_generic = 0;
65 
66 /*
67  * If cleared for debugging, we will suppress panicking on fatal hardware
68  * errors.  This should *only* be used for debugging; it use can and will
69  * cause data corruption if actual hardware errors are detected by the system.
70  */
71 int cmi_panic_on_uncorrectable_error = 1;
72 
73 #ifndef __xpv
74 /*
75  * Set to indicate whether we are able to enable cmci interrupt.
76  */
77 int cmi_enable_cmci = 0;
78 #endif
79 
80 /*
81  * Subdirectory (relative to the module search path) in which we will
82  * look for cpu modules.
83  */
84 #define	CPUMOD_SUBDIR	"cpu"
85 
86 /*
87  * CPU modules have a filenames such as "cpu.AuthenticAMD.15" and
88  * "cpu.generic" - the "cpu" prefix is specified by the following.
89  */
90 #define	CPUMOD_PREFIX	"cpu"
91 
92 /*
93  * Structure used to keep track of cpu modules we have loaded and their ops
94  */
95 typedef struct cmi {
96 	struct cmi *cmi_next;
97 	struct cmi *cmi_prev;
98 	const cmi_ops_t *cmi_ops;
99 	struct modctl *cmi_modp;
100 	uint_t cmi_refcnt;
101 } cmi_t;
102 
103 static cmi_t *cmi_list;
104 static const cmi_mc_ops_t *cmi_mc_global_ops;
105 static void *cmi_mc_global_data;
106 static kmutex_t cmi_load_lock;
107 
108 /*
109  * Functions we need from cmi_hw.c that are not part of the cpu_module.h
110  * interface.
111  */
112 extern cmi_hdl_t cmi_hdl_create(enum cmi_hdl_class, uint_t, uint_t, uint_t);
113 extern void cmi_hdl_destroy(cmi_hdl_t ophdl);
114 extern void cmi_hdl_setcmi(cmi_hdl_t, void *, void *);
115 extern void *cmi_hdl_getcmi(cmi_hdl_t);
116 extern void cmi_hdl_setmc(cmi_hdl_t, const struct cmi_mc_ops *, void *);
117 extern void cmi_hdl_inj_begin(cmi_hdl_t);
118 extern void cmi_hdl_inj_end(cmi_hdl_t);
119 extern void cmi_read_smbios(cmi_hdl_t);
120 
121 #define	HDL2CMI(hdl)		cmi_hdl_getcmi(hdl)
122 
123 #define	CMI_OPS(cmi)		(cmi)->cmi_ops
124 #define	CMI_OP_PRESENT(cmi, op)	((cmi) && CMI_OPS(cmi)->op != NULL)
125 
126 #define	CMI_MATCH_VENDOR	0	/* Just match on vendor */
127 #define	CMI_MATCH_FAMILY	1	/* Match down to family */
128 #define	CMI_MATCH_MODEL		2	/* Match down to model */
129 #define	CMI_MATCH_STEPPING	3	/* Match down to stepping */
130 
131 static void
132 cmi_link(cmi_t *cmi)
133 {
134 	ASSERT(MUTEX_HELD(&cmi_load_lock));
135 
136 	cmi->cmi_prev = NULL;
137 	cmi->cmi_next = cmi_list;
138 	if (cmi_list != NULL)
139 		cmi_list->cmi_prev = cmi;
140 	cmi_list = cmi;
141 }
142 
143 static void
144 cmi_unlink(cmi_t *cmi)
145 {
146 	ASSERT(MUTEX_HELD(&cmi_load_lock));
147 	ASSERT(cmi->cmi_refcnt == 0);
148 
149 	if (cmi->cmi_prev != NULL)
150 		cmi->cmi_prev = cmi->cmi_next;
151 
152 	if (cmi->cmi_next != NULL)
153 		cmi->cmi_next->cmi_prev = cmi->cmi_prev;
154 
155 	if (cmi_list == cmi)
156 		cmi_list = cmi->cmi_next;
157 }
158 
159 /*
160  * Hold the module in memory.  We call to CPU modules without using the
161  * stubs mechanism, so these modules must be manually held in memory.
162  * The mod_ref acts as if another loaded module has a dependency on us.
163  */
164 static void
165 cmi_hold(cmi_t *cmi)
166 {
167 	ASSERT(MUTEX_HELD(&cmi_load_lock));
168 
169 	mutex_enter(&mod_lock);
170 	cmi->cmi_modp->mod_ref++;
171 	mutex_exit(&mod_lock);
172 	cmi->cmi_refcnt++;
173 }
174 
175 static void
176 cmi_rele(cmi_t *cmi)
177 {
178 	ASSERT(MUTEX_HELD(&cmi_load_lock));
179 
180 	mutex_enter(&mod_lock);
181 	cmi->cmi_modp->mod_ref--;
182 	mutex_exit(&mod_lock);
183 
184 	if (--cmi->cmi_refcnt == 0) {
185 		cmi_unlink(cmi);
186 		kmem_free(cmi, sizeof (cmi_t));
187 	}
188 }
189 
190 static cmi_ops_t *
191 cmi_getops(modctl_t *modp)
192 {
193 	cmi_ops_t *ops;
194 
195 	if ((ops = (cmi_ops_t *)modlookup_by_modctl(modp, "_cmi_ops")) ==
196 	    NULL) {
197 		cmn_err(CE_WARN, "cpu module '%s' is invalid: no _cmi_ops "
198 		    "found", modp->mod_modname);
199 		return (NULL);
200 	}
201 
202 	if (ops->cmi_init == NULL) {
203 		cmn_err(CE_WARN, "cpu module '%s' is invalid: no cmi_init "
204 		    "entry point", modp->mod_modname);
205 		return (NULL);
206 	}
207 
208 	return (ops);
209 }
210 
211 static cmi_t *
212 cmi_load_modctl(modctl_t *modp)
213 {
214 	cmi_ops_t *ops;
215 	uintptr_t ver;
216 	cmi_t *cmi;
217 	cmi_api_ver_t apiver;
218 
219 	ASSERT(MUTEX_HELD(&cmi_load_lock));
220 
221 	for (cmi = cmi_list; cmi != NULL; cmi = cmi->cmi_next) {
222 		if (cmi->cmi_modp == modp)
223 			return (cmi);
224 	}
225 
226 	if ((ver = modlookup_by_modctl(modp, "_cmi_api_version")) == NULL) {
227 		/*
228 		 * Apparently a cpu module before versioning was introduced -
229 		 * we call this version 0.
230 		 */
231 		apiver = CMI_API_VERSION_0;
232 	} else {
233 		apiver = *((cmi_api_ver_t *)ver);
234 		if (!CMI_API_VERSION_CHKMAGIC(apiver)) {
235 			cmn_err(CE_WARN, "cpu module '%s' is invalid: "
236 			    "_cmi_api_version 0x%x has bad magic",
237 			    modp->mod_modname, apiver);
238 			return (NULL);
239 		}
240 	}
241 
242 	if (apiver != CMI_API_VERSION) {
243 		cmn_err(CE_WARN, "cpu module '%s' has API version %d, "
244 		    "kernel requires API version %d", modp->mod_modname,
245 		    CMI_API_VERSION_TOPRINT(apiver),
246 		    CMI_API_VERSION_TOPRINT(CMI_API_VERSION));
247 		return (NULL);
248 	}
249 
250 	if ((ops = cmi_getops(modp)) == NULL)
251 		return (NULL);
252 
253 	cmi = kmem_zalloc(sizeof (*cmi), KM_SLEEP);
254 	cmi->cmi_ops = ops;
255 	cmi->cmi_modp = modp;
256 
257 	cmi_link(cmi);
258 
259 	return (cmi);
260 }
261 
262 static int
263 cmi_cpu_match(cmi_hdl_t hdl1, cmi_hdl_t hdl2, int match)
264 {
265 	if (match >= CMI_MATCH_VENDOR &&
266 	    cmi_hdl_vendor(hdl1) != cmi_hdl_vendor(hdl2))
267 		return (0);
268 
269 	if (match >= CMI_MATCH_FAMILY &&
270 	    cmi_hdl_family(hdl1) != cmi_hdl_family(hdl2))
271 		return (0);
272 
273 	if (match >= CMI_MATCH_MODEL &&
274 	    cmi_hdl_model(hdl1) != cmi_hdl_model(hdl2))
275 		return (0);
276 
277 	if (match >= CMI_MATCH_STEPPING &&
278 	    cmi_hdl_stepping(hdl1) != cmi_hdl_stepping(hdl2))
279 		return (0);
280 
281 	return (1);
282 }
283 
284 static int
285 cmi_search_list_cb(cmi_hdl_t whdl, void *arg1, void *arg2, void *arg3)
286 {
287 	cmi_hdl_t thdl = (cmi_hdl_t)arg1;
288 	int match = *((int *)arg2);
289 	cmi_hdl_t *rsltp = (cmi_hdl_t *)arg3;
290 
291 	if (cmi_cpu_match(thdl, whdl, match)) {
292 		cmi_hdl_hold(whdl);	/* short-term hold */
293 		*rsltp = whdl;
294 		return (CMI_HDL_WALK_DONE);
295 	} else {
296 		return (CMI_HDL_WALK_NEXT);
297 	}
298 }
299 
300 static cmi_t *
301 cmi_search_list(cmi_hdl_t hdl, int match)
302 {
303 	cmi_hdl_t dhdl = NULL;
304 	cmi_t *cmi = NULL;
305 
306 	ASSERT(MUTEX_HELD(&cmi_load_lock));
307 
308 	cmi_hdl_walk(cmi_search_list_cb, (void *)hdl, (void *)&match, &dhdl);
309 	if (dhdl) {
310 		cmi = HDL2CMI(dhdl);
311 		cmi_hdl_rele(dhdl);	/* held in cmi_search_list_cb */
312 	}
313 
314 	return (cmi);
315 }
316 
317 static cmi_t *
318 cmi_load_module(cmi_hdl_t hdl, int match, int *chosenp)
319 {
320 	modctl_t *modp;
321 	cmi_t *cmi;
322 	int modid;
323 	uint_t s[3];
324 
325 	ASSERT(MUTEX_HELD(&cmi_load_lock));
326 	ASSERT(match == CMI_MATCH_STEPPING || match == CMI_MATCH_MODEL ||
327 	    match == CMI_MATCH_FAMILY || match == CMI_MATCH_VENDOR);
328 
329 	/*
330 	 * Have we already loaded a module for a cpu with the same
331 	 * vendor/family/model/stepping?
332 	 */
333 	if ((cmi = cmi_search_list(hdl, match)) != NULL) {
334 		cmi_hold(cmi);
335 		return (cmi);
336 	}
337 
338 	s[0] = cmi_hdl_family(hdl);
339 	s[1] = cmi_hdl_model(hdl);
340 	s[2] = cmi_hdl_stepping(hdl);
341 	modid = modload_qualified(CPUMOD_SUBDIR, CPUMOD_PREFIX,
342 	    cmi_hdl_vendorstr(hdl), ".", s, match, chosenp);
343 
344 	if (modid == -1)
345 		return (NULL);
346 
347 	modp = mod_hold_by_id(modid);
348 	cmi = cmi_load_modctl(modp);
349 	if (cmi)
350 		cmi_hold(cmi);
351 	mod_release_mod(modp);
352 
353 	return (cmi);
354 }
355 
356 /*
357  * Try to load a cpu module with specific support for this chip type.
358  */
359 static cmi_t *
360 cmi_load_specific(cmi_hdl_t hdl, void **datap)
361 {
362 	cmi_t *cmi;
363 	int err;
364 	int i;
365 
366 	ASSERT(MUTEX_HELD(&cmi_load_lock));
367 
368 	for (i = CMI_MATCH_STEPPING; i >= CMI_MATCH_VENDOR; i--) {
369 		int suffixlevel;
370 
371 		if ((cmi = cmi_load_module(hdl, i, &suffixlevel)) == NULL)
372 			return (NULL);
373 
374 		/*
375 		 * A module has loaded and has a _cmi_ops structure, and the
376 		 * module has been held for this instance.  Call its cmi_init
377 		 * entry point - we expect success (0) or ENOTSUP.
378 		 */
379 		if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) == 0) {
380 			if (boothowto & RB_VERBOSE) {
381 				printf("initialized cpu module '%s' on "
382 				    "chip %d core %d strand %d\n",
383 				    cmi->cmi_modp->mod_modname,
384 				    cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
385 				    cmi_hdl_strandid(hdl));
386 			}
387 			return (cmi);
388 		} else if (err != ENOTSUP) {
389 			cmn_err(CE_WARN, "failed to init cpu module '%s' on "
390 			    "chip %d core %d strand %d: err=%d\n",
391 			    cmi->cmi_modp->mod_modname,
392 			    cmi_hdl_chipid(hdl), cmi_hdl_coreid(hdl),
393 			    cmi_hdl_strandid(hdl), err);
394 		}
395 
396 		/*
397 		 * The module failed or declined to init, so release
398 		 * it and update i to be equal to the number
399 		 * of suffices actually used in the last module path.
400 		 */
401 		cmi_rele(cmi);
402 		i = suffixlevel;
403 	}
404 
405 	return (NULL);
406 }
407 
408 /*
409  * Load the generic IA32 MCA cpu module, which may still supplement
410  * itself with model-specific support through cpu model-specific modules.
411  */
412 static cmi_t *
413 cmi_load_generic(cmi_hdl_t hdl, void **datap)
414 {
415 	modctl_t *modp;
416 	cmi_t *cmi;
417 	int modid;
418 	int err;
419 
420 	ASSERT(MUTEX_HELD(&cmi_load_lock));
421 
422 	if ((modid = modload(CPUMOD_SUBDIR, CPUMOD_PREFIX ".generic")) == -1)
423 		return (NULL);
424 
425 	modp = mod_hold_by_id(modid);
426 	cmi = cmi_load_modctl(modp);
427 	if (cmi)
428 		cmi_hold(cmi);
429 	mod_release_mod(modp);
430 
431 	if (cmi == NULL)
432 		return (NULL);
433 
434 	if ((err = cmi->cmi_ops->cmi_init(hdl, datap)) != 0) {
435 		if (err != ENOTSUP)
436 			cmn_err(CE_WARN, CPUMOD_PREFIX ".generic failed to "
437 			    "init: err=%d", err);
438 		cmi_rele(cmi);
439 		return (NULL);
440 	}
441 
442 	return (cmi);
443 }
444 
445 cmi_hdl_t
446 cmi_init(enum cmi_hdl_class class, uint_t chipid, uint_t coreid,
447     uint_t strandid)
448 {
449 	cmi_t *cmi = NULL;
450 	cmi_hdl_t hdl;
451 	void *data;
452 
453 	if (cmi_no_init) {
454 		cmi_no_mca_init = 1;
455 		return (NULL);
456 	}
457 
458 	mutex_enter(&cmi_load_lock);
459 
460 	if ((hdl = cmi_hdl_create(class, chipid, coreid, strandid)) == NULL) {
461 		mutex_exit(&cmi_load_lock);
462 		cmn_err(CE_WARN, "There will be no MCA support on chip %d "
463 		    "core %d strand %d (cmi_hdl_create returned NULL)\n",
464 		    chipid, coreid, strandid);
465 		return (NULL);
466 	}
467 
468 	if (!cmi_force_generic)
469 		cmi = cmi_load_specific(hdl, &data);
470 
471 	if (cmi == NULL && (cmi = cmi_load_generic(hdl, &data)) == NULL) {
472 		cmn_err(CE_WARN, "There will be no MCA support on chip %d "
473 		    "core %d strand %d\n", chipid, coreid, strandid);
474 		cmi_hdl_rele(hdl);
475 		mutex_exit(&cmi_load_lock);
476 		return (NULL);
477 	}
478 
479 	cmi_hdl_setcmi(hdl, cmi, data);
480 
481 	cms_init(hdl);
482 
483 	cmi_read_smbios(hdl);
484 
485 	mutex_exit(&cmi_load_lock);
486 
487 	return (hdl);
488 }
489 
490 /*
491  * cmi_fini is called on DR deconfigure of a cpu resource.
492  * It should not be called at simple offline of a cpu.
493  */
494 void
495 cmi_fini(cmi_hdl_t hdl)
496 {
497 	cmi_t *cmi = HDL2CMI(hdl);
498 
499 	if (cms_present(hdl))
500 		cms_fini(hdl);
501 
502 	if (CMI_OP_PRESENT(cmi, cmi_fini))
503 		CMI_OPS(cmi)->cmi_fini(hdl);
504 
505 	cmi_hdl_destroy(hdl);
506 }
507 
508 /*
509  * cmi_post_startup is called from post_startup for the boot cpu only (no
510  * other cpus are started yet).
511  */
512 void
513 cmi_post_startup(void)
514 {
515 	cmi_hdl_t hdl;
516 	cmi_t *cmi;
517 
518 	if (cmi_no_mca_init != 0 ||
519 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
520 		return;
521 
522 	cmi = HDL2CMI(hdl);
523 
524 	if (CMI_OP_PRESENT(cmi, cmi_post_startup))
525 		CMI_OPS(cmi)->cmi_post_startup(hdl);
526 
527 	cmi_hdl_rele(hdl);
528 }
529 
530 /*
531  * Called just once from start_other_cpus when all processors are started.
532  * This will not be called for each cpu, so the registered op must not
533  * assume it is called as such.  We are not necessarily executing on
534  * the boot cpu.
535  */
536 void
537 cmi_post_mpstartup(void)
538 {
539 	cmi_hdl_t hdl;
540 	cmi_t *cmi;
541 
542 	if (cmi_no_mca_init != 0 ||
543 	    (hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
544 		return;
545 
546 	cmi = HDL2CMI(hdl);
547 
548 	if (CMI_OP_PRESENT(cmi, cmi_post_mpstartup))
549 		CMI_OPS(cmi)->cmi_post_mpstartup(hdl);
550 
551 	cmi_hdl_rele(hdl);
552 }
553 
554 void
555 cmi_faulted_enter(cmi_hdl_t hdl)
556 {
557 	cmi_t *cmi = HDL2CMI(hdl);
558 
559 	if (cmi_no_mca_init != 0)
560 		return;
561 
562 	if (CMI_OP_PRESENT(cmi, cmi_faulted_enter))
563 		CMI_OPS(cmi)->cmi_faulted_enter(hdl);
564 }
565 
566 void
567 cmi_faulted_exit(cmi_hdl_t hdl)
568 {
569 	cmi_t *cmi = HDL2CMI(hdl);
570 
571 	if (cmi_no_mca_init != 0)
572 		return;
573 
574 	if (CMI_OP_PRESENT(cmi, cmi_faulted_exit))
575 		CMI_OPS(cmi)->cmi_faulted_exit(hdl);
576 }
577 
578 void
579 cmi_mca_init(cmi_hdl_t hdl)
580 {
581 	cmi_t *cmi;
582 
583 	if (cmi_no_mca_init != 0)
584 		return;
585 
586 	cmi = HDL2CMI(hdl);
587 
588 	if (CMI_OP_PRESENT(cmi, cmi_mca_init))
589 		CMI_OPS(cmi)->cmi_mca_init(hdl);
590 }
591 
592 #define	CMI_RESPONSE_PANIC		0x0	/* panic must have value 0 */
593 #define	CMI_RESPONSE_NONE		0x1
594 #define	CMI_RESPONSE_CKILL		0x2
595 #define	CMI_RESPONSE_REBOOT		0x3	/* not implemented */
596 #define	CMI_RESPONSE_ONTRAP_PROT	0x4
597 #define	CMI_RESPONSE_LOFAULT_PROT	0x5
598 
599 /*
600  * Return 0 if we will panic in response to this machine check, otherwise
601  * non-zero.  If the caller is cmi_mca_trap in this file then the nonzero
602  * return values are to be interpreted from CMI_RESPONSE_* above.
603  *
604  * This function must just return what will be done without actually
605  * doing anything; this includes not changing the regs.
606  */
607 int
608 cmi_mce_response(struct regs *rp, uint64_t disp)
609 {
610 	int panicrsp = cmi_panic_on_uncorrectable_error ? CMI_RESPONSE_PANIC :
611 	    CMI_RESPONSE_NONE;
612 	on_trap_data_t *otp;
613 
614 	ASSERT(rp != NULL);	/* don't call for polling, only on #MC */
615 
616 	/*
617 	 * If no bits are set in the disposition then there is nothing to
618 	 * worry about and we do not need to trampoline to ontrap or
619 	 * lofault handlers.
620 	 */
621 	if (disp == 0)
622 		return (CMI_RESPONSE_NONE);
623 
624 	/*
625 	 * Unconstrained errors cannot be forgiven, even by ontrap or
626 	 * lofault protection.  The data is not poisoned and may not
627 	 * even belong to the trapped context - eg a writeback of
628 	 * data that is found to be bad.
629 	 */
630 	if (disp & CMI_ERRDISP_UC_UNCONSTRAINED)
631 		return (panicrsp);
632 
633 	/*
634 	 * ontrap OT_DATA_EC and lofault protection forgive any disposition
635 	 * other than unconstrained, even those normally forced fatal.
636 	 */
637 	if ((otp = curthread->t_ontrap) != NULL && otp->ot_prot & OT_DATA_EC)
638 		return (CMI_RESPONSE_ONTRAP_PROT);
639 	else if (curthread->t_lofault)
640 		return (CMI_RESPONSE_LOFAULT_PROT);
641 
642 	/*
643 	 * Forced-fatal errors are terminal even in user mode.
644 	 */
645 	if (disp & CMI_ERRDISP_FORCEFATAL)
646 		return (panicrsp);
647 
648 	/*
649 	 * If the trapped context is corrupt or we have no instruction pointer
650 	 * to resume at (and aren't trampolining to a fault handler)
651 	 * then in the kernel case we must panic and in usermode we
652 	 * kill the affected contract.
653 	 */
654 	if (disp & (CMI_ERRDISP_CURCTXBAD | CMI_ERRDISP_RIPV_INVALID))
655 		return (USERMODE(rp->r_cs) ?  CMI_RESPONSE_CKILL : panicrsp);
656 
657 	/*
658 	 * Anything else is harmless
659 	 */
660 	return (CMI_RESPONSE_NONE);
661 }
662 
663 int cma_mca_trap_panic_suppressed = 0;
664 
665 static void
666 cmi_mca_panic(void)
667 {
668 	if (cmi_panic_on_uncorrectable_error) {
669 		fm_panic("Unrecoverable Machine-Check Exception");
670 	} else {
671 		cmn_err(CE_WARN, "suppressing panic from fatal #mc");
672 		cma_mca_trap_panic_suppressed++;
673 	}
674 }
675 
676 
677 int cma_mca_trap_contract_kills = 0;
678 int cma_mca_trap_ontrap_forgiven = 0;
679 int cma_mca_trap_lofault_forgiven = 0;
680 
681 /*
682  * Native #MC handler - we branch to here from mcetrap
683  */
684 /*ARGSUSED*/
685 void
686 cmi_mca_trap(struct regs *rp)
687 {
688 #ifndef	__xpv
689 	cmi_hdl_t hdl = NULL;
690 	uint64_t disp;
691 	cmi_t *cmi;
692 	int s;
693 
694 	if (cmi_no_mca_init != 0)
695 		return;
696 
697 	/*
698 	 * This function can call cmn_err, and the cpu module cmi_mca_trap
699 	 * entry point may also elect to call cmn_err (e.g., if it can't
700 	 * log the error onto an errorq, say very early in boot).
701 	 * We need to let cprintf know that we must not block.
702 	 */
703 	s = spl8();
704 
705 	if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
706 	    cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
707 	    (cmi = HDL2CMI(hdl)) == NULL ||
708 	    !CMI_OP_PRESENT(cmi, cmi_mca_trap)) {
709 
710 		cmn_err(CE_WARN, "#MC exception on cpuid %d: %s",
711 		    CPU->cpu_id,
712 		    hdl ? "handle lookup ok but no #MC handler found" :
713 		    "handle lookup failed");
714 
715 		if (hdl != NULL)
716 			cmi_hdl_rele(hdl);
717 
718 		splx(s);
719 		return;
720 	}
721 
722 	disp = CMI_OPS(cmi)->cmi_mca_trap(hdl, rp);
723 
724 	switch (cmi_mce_response(rp, disp)) {
725 	default:
726 		cmn_err(CE_WARN, "Invalid response from cmi_mce_response");
727 		/*FALLTHRU*/
728 
729 	case CMI_RESPONSE_PANIC:
730 		cmi_mca_panic();
731 		break;
732 
733 	case CMI_RESPONSE_NONE:
734 		break;
735 
736 	case CMI_RESPONSE_CKILL:
737 		ttolwp(curthread)->lwp_pcb.pcb_flags |= ASYNC_HWERR;
738 		aston(curthread);
739 		cma_mca_trap_contract_kills++;
740 		break;
741 
742 	case CMI_RESPONSE_ONTRAP_PROT: {
743 		on_trap_data_t *otp = curthread->t_ontrap;
744 		otp->ot_trap = OT_DATA_EC;
745 		rp->r_pc = otp->ot_trampoline;
746 		cma_mca_trap_ontrap_forgiven++;
747 		break;
748 	}
749 
750 	case CMI_RESPONSE_LOFAULT_PROT:
751 		rp->r_r0 = EFAULT;
752 		rp->r_pc = curthread->t_lofault;
753 		cma_mca_trap_lofault_forgiven++;
754 		break;
755 	}
756 
757 	cmi_hdl_rele(hdl);
758 	splx(s);
759 #endif	/* __xpv */
760 }
761 
762 void
763 cmi_hdl_poke(cmi_hdl_t hdl)
764 {
765 	cmi_t *cmi = HDL2CMI(hdl);
766 
767 	if (!CMI_OP_PRESENT(cmi, cmi_hdl_poke))
768 		return;
769 
770 	CMI_OPS(cmi)->cmi_hdl_poke(hdl);
771 }
772 
773 #ifndef	__xpv
774 void
775 cmi_cmci_trap()
776 {
777 	cmi_hdl_t hdl = NULL;
778 	cmi_t *cmi;
779 
780 	if (cmi_no_mca_init != 0)
781 		return;
782 
783 	if ((hdl = cmi_hdl_lookup(CMI_HDL_NATIVE, cmi_ntv_hwchipid(CPU),
784 	    cmi_ntv_hwcoreid(CPU), cmi_ntv_hwstrandid(CPU))) == NULL ||
785 	    (cmi = HDL2CMI(hdl)) == NULL ||
786 	    !CMI_OP_PRESENT(cmi, cmi_cmci_trap)) {
787 
788 		cmn_err(CE_WARN, "CMCI interrupt on cpuid %d: %s",
789 		    CPU->cpu_id,
790 		    hdl ? "handle lookup ok but no CMCI handler found" :
791 		    "handle lookup failed");
792 
793 		if (hdl != NULL)
794 			cmi_hdl_rele(hdl);
795 
796 		return;
797 	}
798 
799 	CMI_OPS(cmi)->cmi_cmci_trap(hdl);
800 
801 	cmi_hdl_rele(hdl);
802 }
803 #endif	/* __xpv */
804 
805 void
806 cmi_mc_register(cmi_hdl_t hdl, const cmi_mc_ops_t *mcops, void *mcdata)
807 {
808 	if (!cmi_no_mca_init)
809 		cmi_hdl_setmc(hdl, mcops, mcdata);
810 }
811 
812 cmi_errno_t
813 cmi_mc_register_global(const cmi_mc_ops_t *mcops, void *mcdata)
814 {
815 	if (!cmi_no_mca_init) {
816 		if (cmi_mc_global_ops != NULL || cmi_mc_global_data != NULL ||
817 		    mcops == NULL || mcops->cmi_mc_patounum == NULL ||
818 		    mcops->cmi_mc_unumtopa == NULL) {
819 			return (CMIERR_UNKNOWN);
820 		}
821 		cmi_mc_global_data = mcdata;
822 		cmi_mc_global_ops = mcops;
823 	}
824 	return (CMI_SUCCESS);
825 }
826 
827 void
828 cmi_mc_sw_memscrub_disable(void)
829 {
830 	memscrub_disable();
831 }
832 
833 cmi_errno_t
834 cmi_mc_patounum(uint64_t pa, uint8_t valid_hi, uint8_t valid_lo, uint32_t synd,
835     int syndtype, mc_unum_t *up)
836 {
837 	const struct cmi_mc_ops *mcops;
838 	cmi_hdl_t hdl;
839 	cmi_errno_t rv;
840 
841 	if (cmi_no_mca_init)
842 		return (CMIERR_MC_ABSENT);
843 
844 	if (cmi_mc_global_ops != NULL) {
845 		if (cmi_mc_global_ops->cmi_mc_patounum == NULL)
846 			return (CMIERR_MC_NOTSUP);
847 		return (cmi_mc_global_ops->cmi_mc_patounum(cmi_mc_global_data,
848 		    pa, valid_hi, valid_lo, synd, syndtype, up));
849 	}
850 
851 	if ((hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
852 		return (CMIERR_MC_ABSENT);
853 
854 	if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
855 	    mcops->cmi_mc_patounum == NULL) {
856 		cmi_hdl_rele(hdl);
857 		return (CMIERR_MC_NOTSUP);
858 	}
859 
860 	rv = mcops->cmi_mc_patounum(cmi_hdl_getmcdata(hdl), pa, valid_hi,
861 	    valid_lo, synd, syndtype, up);
862 
863 	cmi_hdl_rele(hdl);
864 
865 	return (rv);
866 }
867 
868 cmi_errno_t
869 cmi_mc_unumtopa(mc_unum_t *up, nvlist_t *nvl, uint64_t *pap)
870 {
871 	const struct cmi_mc_ops *mcops;
872 	cmi_hdl_t hdl;
873 	cmi_errno_t rv;
874 	nvlist_t *hcsp;
875 
876 	if (up != NULL && nvl != NULL)
877 		return (CMIERR_API);	/* convert from just one form */
878 
879 	if (cmi_no_mca_init)
880 		return (CMIERR_MC_ABSENT);
881 
882 	if (cmi_mc_global_ops != NULL) {
883 		if (cmi_mc_global_ops->cmi_mc_unumtopa == NULL)
884 			return (CMIERR_MC_NOTSUP);
885 		return (cmi_mc_global_ops->cmi_mc_unumtopa(cmi_mc_global_data,
886 		    up, nvl, pap));
887 	}
888 
889 	if ((hdl = cmi_hdl_any()) == NULL)	/* short-term hold */
890 		return (CMIERR_MC_ABSENT);
891 
892 	if ((mcops = cmi_hdl_getmcops(hdl)) == NULL ||
893 	    mcops->cmi_mc_unumtopa == NULL) {
894 		cmi_hdl_rele(hdl);
895 
896 		if (nvl != NULL && nvlist_lookup_nvlist(nvl,
897 		    FM_FMRI_HC_SPECIFIC, &hcsp) == 0 &&
898 		    (nvlist_lookup_uint64(hcsp,
899 		    "asru-" FM_FMRI_HC_SPECIFIC_PHYSADDR, pap) == 0 ||
900 		    nvlist_lookup_uint64(hcsp, FM_FMRI_HC_SPECIFIC_PHYSADDR,
901 		    pap) == 0)) {
902 			return (CMIERR_MC_PARTIALUNUMTOPA);
903 		} else {
904 			return (mcops && mcops->cmi_mc_unumtopa == NULL ?
905 			    CMIERR_MC_NOTSUP : CMIERR_MC_ABSENT);
906 		}
907 	}
908 
909 	rv = mcops->cmi_mc_unumtopa(cmi_hdl_getmcdata(hdl), up, nvl, pap);
910 
911 	cmi_hdl_rele(hdl);
912 
913 	return (rv);
914 }
915 
916 void
917 cmi_mc_logout(cmi_hdl_t hdl, boolean_t ismc, boolean_t sync)
918 {
919 	const struct cmi_mc_ops *mcops;
920 
921 	if (cmi_no_mca_init)
922 		return;
923 
924 	if (cmi_mc_global_ops != NULL)
925 		mcops = cmi_mc_global_ops;
926 	else
927 		mcops = cmi_hdl_getmcops(hdl);
928 
929 	if (mcops != NULL && mcops->cmi_mc_logout != NULL)
930 		mcops->cmi_mc_logout(hdl, ismc, sync);
931 }
932 
933 cmi_errno_t
934 cmi_hdl_msrinject(cmi_hdl_t hdl, cmi_mca_regs_t *regs, uint_t nregs,
935     int force)
936 {
937 	cmi_t *cmi = cmi_hdl_getcmi(hdl);
938 	cmi_errno_t rc;
939 
940 	if (!CMI_OP_PRESENT(cmi, cmi_msrinject))
941 		return (CMIERR_NOTSUP);
942 
943 	cmi_hdl_inj_begin(hdl);
944 	rc = CMI_OPS(cmi)->cmi_msrinject(hdl, regs, nregs, force);
945 	cmi_hdl_inj_end(hdl);
946 
947 	return (rc);
948 }
949 
950 boolean_t
951 cmi_panic_on_ue(void)
952 {
953 	return (cmi_panic_on_uncorrectable_error ? B_TRUE : B_FALSE);
954 }
955 
956 void
957 cmi_panic_callback(void)
958 {
959 	cmi_hdl_t hdl;
960 	cmi_t *cmi;
961 
962 	if (cmi_no_mca_init || (hdl = cmi_hdl_any()) == NULL)
963 		return;
964 
965 	cmi = cmi_hdl_getcmi(hdl);
966 	if (CMI_OP_PRESENT(cmi, cmi_panic_callback))
967 		CMI_OPS(cmi)->cmi_panic_callback();
968 
969 	cmi_hdl_rele(hdl);
970 }
971 
972 
973 const char *
974 cmi_hdl_chipident(cmi_hdl_t hdl)
975 {
976 	cmi_t *cmi = cmi_hdl_getcmi(hdl);
977 
978 	if (!CMI_OP_PRESENT(cmi, cmi_ident))
979 		return (NULL);
980 
981 	return (CMI_OPS(cmi)->cmi_ident(hdl));
982 }
983