1*d2f938fdSPatrick Mooney /*
2*d2f938fdSPatrick Mooney  * This file and its contents are supplied under the terms of the
3*d2f938fdSPatrick Mooney  * Common Development and Distribution License ("CDDL"), version 1.0.
4*d2f938fdSPatrick Mooney  * You may only use this file in accordance with the terms of version
5*d2f938fdSPatrick Mooney  * 1.0 of the CDDL.
6*d2f938fdSPatrick Mooney  *
7*d2f938fdSPatrick Mooney  * A full copy of the text of the CDDL should have accompanied this
8*d2f938fdSPatrick Mooney  * source.  A copy of the CDDL is also available via the Internet at
9*d2f938fdSPatrick Mooney  * http://www.illumos.org/license/CDDL.
10*d2f938fdSPatrick Mooney  */
11*d2f938fdSPatrick Mooney 
12*d2f938fdSPatrick Mooney /*
13*d2f938fdSPatrick Mooney  * Copyright 2022 Oxide Computer Company
14*d2f938fdSPatrick Mooney  */
15*d2f938fdSPatrick Mooney 
16*d2f938fdSPatrick Mooney #include "payload_common.h"
17*d2f938fdSPatrick Mooney #include "payload_utils.h"
18*d2f938fdSPatrick Mooney #include "test_defs.h"
19*d2f938fdSPatrick Mooney 
20*d2f938fdSPatrick Mooney #define	MSR_APICBASE	0x1b
21*d2f938fdSPatrick Mooney #define	MSR_X2APIC_BASE	0x800
22*d2f938fdSPatrick Mooney #define	MSR_X2APIC_MAX	0x8ff
23*d2f938fdSPatrick Mooney 
24*d2f938fdSPatrick Mooney #define	APICBASE_X2APIC	(1 << 10)
25*d2f938fdSPatrick Mooney 
26*d2f938fdSPatrick Mooney static bool
reg_readable(uint32_t reg)27*d2f938fdSPatrick Mooney reg_readable(uint32_t reg)
28*d2f938fdSPatrick Mooney {
29*d2f938fdSPatrick Mooney 	switch (reg) {
30*d2f938fdSPatrick Mooney 	case 0x802: /* ID */
31*d2f938fdSPatrick Mooney 	case 0x803: /* VER */
32*d2f938fdSPatrick Mooney 
33*d2f938fdSPatrick Mooney 	case 0x808: /* TPR */
34*d2f938fdSPatrick Mooney 	case 0x809: /* APR */
35*d2f938fdSPatrick Mooney 	case 0x80a: /* PPR */
36*d2f938fdSPatrick Mooney 
37*d2f938fdSPatrick Mooney 	case 0x80c: /* RRR */
38*d2f938fdSPatrick Mooney 	case 0x80d: /* LDR */
39*d2f938fdSPatrick Mooney 	case 0x80e: /* DFR */
40*d2f938fdSPatrick Mooney 	case 0x80f: /* SVR */
41*d2f938fdSPatrick Mooney 
42*d2f938fdSPatrick Mooney 	case 0x810 ... 0x817: /* ISR */
43*d2f938fdSPatrick Mooney 	case 0x818 ... 0x81f: /* TMR */
44*d2f938fdSPatrick Mooney 	case 0x820 ... 0x827: /* IRR */
45*d2f938fdSPatrick Mooney 
46*d2f938fdSPatrick Mooney 	case 0x828: /* ESR */
47*d2f938fdSPatrick Mooney 
48*d2f938fdSPatrick Mooney 	case 0x82f: /* LVT_CMCI */
49*d2f938fdSPatrick Mooney 	case 0x830: /* ICR */
50*d2f938fdSPatrick Mooney 
51*d2f938fdSPatrick Mooney 	case 0x832: /* LVT_TIMER */
52*d2f938fdSPatrick Mooney 	case 0x833: /* LVT_THERMAL */
53*d2f938fdSPatrick Mooney 	case 0x834: /* LVT_PERF */
54*d2f938fdSPatrick Mooney 	case 0x835: /* LVT_LINT0 */
55*d2f938fdSPatrick Mooney 	case 0x836: /* LVT_LINT1 */
56*d2f938fdSPatrick Mooney 	case 0x837: /* LVT_ERROR */
57*d2f938fdSPatrick Mooney 	case 0x838: /* TIMER_ICR */
58*d2f938fdSPatrick Mooney 	case 0x839: /* TIMER_CCR */
59*d2f938fdSPatrick Mooney 
60*d2f938fdSPatrick Mooney 	case 0x83e: /* TIMER_DCR */
61*d2f938fdSPatrick Mooney 		return (true);
62*d2f938fdSPatrick Mooney 	default:
63*d2f938fdSPatrick Mooney 		return (false);
64*d2f938fdSPatrick Mooney 	}
65*d2f938fdSPatrick Mooney }
66*d2f938fdSPatrick Mooney 
67*d2f938fdSPatrick Mooney static bool
reg_writable(uint32_t reg)68*d2f938fdSPatrick Mooney reg_writable(uint32_t reg)
69*d2f938fdSPatrick Mooney {
70*d2f938fdSPatrick Mooney 	switch (reg) {
71*d2f938fdSPatrick Mooney 	case 0x802: /* ID */
72*d2f938fdSPatrick Mooney 
73*d2f938fdSPatrick Mooney 	case 0x808: /* TPR */
74*d2f938fdSPatrick Mooney 
75*d2f938fdSPatrick Mooney 	case 0x80b: /* EOI */
76*d2f938fdSPatrick Mooney 
77*d2f938fdSPatrick Mooney 	case 0x80d: /* LDR */
78*d2f938fdSPatrick Mooney 	case 0x80e: /* DFR */
79*d2f938fdSPatrick Mooney 	case 0x80f: /* SVR */
80*d2f938fdSPatrick Mooney 
81*d2f938fdSPatrick Mooney 	case 0x828: /* ESR */
82*d2f938fdSPatrick Mooney 
83*d2f938fdSPatrick Mooney 	case 0x82f: /* LVT_CMCI */
84*d2f938fdSPatrick Mooney 	case 0x830: /* ICR */
85*d2f938fdSPatrick Mooney 
86*d2f938fdSPatrick Mooney 	case 0x832: /* LVT_TIMER */
87*d2f938fdSPatrick Mooney 	case 0x833: /* LVT_THERMAL */
88*d2f938fdSPatrick Mooney 	case 0x834: /* LVT_PERF */
89*d2f938fdSPatrick Mooney 	case 0x835: /* LVT_LINT0 */
90*d2f938fdSPatrick Mooney 	case 0x836: /* LVT_LINT1 */
91*d2f938fdSPatrick Mooney 	case 0x837: /* LVT_ERROR */
92*d2f938fdSPatrick Mooney 	case 0x838: /* TIMER_ICR */
93*d2f938fdSPatrick Mooney 
94*d2f938fdSPatrick Mooney 	case 0x83e: /* TIMER_DCR */
95*d2f938fdSPatrick Mooney 	case 0x83f: /* SELF_IPI */
96*d2f938fdSPatrick Mooney 		return (true);
97*d2f938fdSPatrick Mooney 	default:
98*d2f938fdSPatrick Mooney 		return (false);
99*d2f938fdSPatrick Mooney 	}
100*d2f938fdSPatrick Mooney }
101*d2f938fdSPatrick Mooney 
102*d2f938fdSPatrick Mooney void
start(void)103*d2f938fdSPatrick Mooney start(void)
104*d2f938fdSPatrick Mooney {
105*d2f938fdSPatrick Mooney 	uint64_t base = rdmsr(MSR_APICBASE);
106*d2f938fdSPatrick Mooney 	if ((base & APICBASE_X2APIC) == 0) {
107*d2f938fdSPatrick Mooney 		/* bail if the host has not enabled x2apic for us */
108*d2f938fdSPatrick Mooney 		outb(IOP_TEST_RESULT, TEST_RESULT_FAIL);
109*d2f938fdSPatrick Mooney 	}
110*d2f938fdSPatrick Mooney 
111*d2f938fdSPatrick Mooney 	for (uint32_t msr = MSR_X2APIC_BASE; msr <= MSR_X2APIC_MAX; msr++) {
112*d2f938fdSPatrick Mooney 		uint64_t val = 0;
113*d2f938fdSPatrick Mooney 
114*d2f938fdSPatrick Mooney 		if (reg_readable(msr)) {
115*d2f938fdSPatrick Mooney 			val = rdmsr(msr);
116*d2f938fdSPatrick Mooney 		}
117*d2f938fdSPatrick Mooney 
118*d2f938fdSPatrick Mooney 		if (reg_writable(msr)) {
119*d2f938fdSPatrick Mooney 			if (msr == 0x828) {
120*d2f938fdSPatrick Mooney 				/*
121*d2f938fdSPatrick Mooney 				 * While the LAPIC is in x2APIC mode, writes to
122*d2f938fdSPatrick Mooney 				 * the ESR must carry a value of 0.
123*d2f938fdSPatrick Mooney 				 */
124*d2f938fdSPatrick Mooney 				val = 0;
125*d2f938fdSPatrick Mooney 			}
126*d2f938fdSPatrick Mooney 			wrmsr(msr, val);
127*d2f938fdSPatrick Mooney 		}
128*d2f938fdSPatrick Mooney 	}
129*d2f938fdSPatrick Mooney 
130*d2f938fdSPatrick Mooney 	/* If we made it this far without a #GP, it counts as a win */
131*d2f938fdSPatrick Mooney 	outb(IOP_TEST_RESULT, TEST_RESULT_PASS);
132*d2f938fdSPatrick Mooney }
133