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