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