summaryrefslogtreecommitdiff
path: root/usr/src/test/bhyve-tests/tests/kdev/payload_vlapic_msr_access.c
blob: 0598f705311501c8d6014f9f0308914f30d33361 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2022 Oxide Computer Company
 */

#include "payload_common.h"
#include "payload_utils.h"
#include "test_defs.h"

#define	MSR_APICBASE	0x1b
#define	MSR_X2APIC_BASE	0x800
#define	MSR_X2APIC_MAX	0x8ff

#define	APICBASE_X2APIC	(1 << 10)

static bool
reg_readable(uint32_t reg)
{
	switch (reg) {
	case 0x802: /* ID */
	case 0x803: /* VER */

	case 0x808: /* TPR */
	case 0x809: /* APR */
	case 0x80a: /* PPR */

	case 0x80c: /* RRR */
	case 0x80d: /* LDR */
	case 0x80e: /* DFR */
	case 0x80f: /* SVR */

	case 0x810 ... 0x817: /* ISR */
	case 0x818 ... 0x81f: /* TMR */
	case 0x820 ... 0x827: /* IRR */

	case 0x828: /* ESR */

	case 0x82f: /* LVT_CMCI */
	case 0x830: /* ICR */

	case 0x832: /* LVT_TIMER */
	case 0x833: /* LVT_THERMAL */
	case 0x834: /* LVT_PERF */
	case 0x835: /* LVT_LINT0 */
	case 0x836: /* LVT_LINT1 */
	case 0x837: /* LVT_ERROR */
	case 0x838: /* TIMER_ICR */
	case 0x839: /* TIMER_CCR */

	case 0x83e: /* TIMER_DCR */
		return (true);
	default:
		return (false);
	}
}

static bool
reg_writable(uint32_t reg)
{
	switch (reg) {
	case 0x802: /* ID */

	case 0x808: /* TPR */

	case 0x80b: /* EOI */

	case 0x80d: /* LDR */
	case 0x80e: /* DFR */
	case 0x80f: /* SVR */

	case 0x828: /* ESR */

	case 0x82f: /* LVT_CMCI */
	case 0x830: /* ICR */

	case 0x832: /* LVT_TIMER */
	case 0x833: /* LVT_THERMAL */
	case 0x834: /* LVT_PERF */
	case 0x835: /* LVT_LINT0 */
	case 0x836: /* LVT_LINT1 */
	case 0x837: /* LVT_ERROR */
	case 0x838: /* TIMER_ICR */

	case 0x83e: /* TIMER_DCR */
	case 0x83f: /* SELF_IPI */
		return (true);
	default:
		return (false);
	}
}

void
start(void)
{
	uint64_t base = rdmsr(MSR_APICBASE);
	if ((base & APICBASE_X2APIC) == 0) {
		/* bail if the host has not enabled x2apic for us */
		outb(IOP_TEST_RESULT, TEST_RESULT_FAIL);
	}

	for (uint32_t msr = MSR_X2APIC_BASE; msr <= MSR_X2APIC_MAX; msr++) {
		uint64_t val = 0;

		if (reg_readable(msr)) {
			val = rdmsr(msr);
		}

		if (reg_writable(msr)) {
			if (msr == 0x828) {
				/*
				 * While the LAPIC is in x2APIC mode, writes to
				 * the ESR must carry a value of 0.
				 */
				val = 0;
			}
			wrmsr(msr, val);
		}
	}

	/* If we made it this far without a #GP, it counts as a win */
	outb(IOP_TEST_RESULT, TEST_RESULT_PASS);
}