xref: /kvm-unit-tests/x86/msr.c (revision c85124d28a51ea3619e91cf6da788142677f4a4d)
1 /* msr tests */
2 
3 #include "libcflat.h"
4 #include "processor.h"
5 #include "msr.h"
6 #include <stdlib.h>
7 
8 /**
9  * This test allows two modes:
10  * 1. Default: the `msr_info' array contains the default test configurations
11  * 2. Custom: by providing command line arguments it is possible to test any MSR and value
12  *	Parameters order:
13  *		1. msr index as a base 16 number
14  *		2. value as a base 16 number
15  */
16 
17 struct msr_info {
18 	int index;
19 	bool is_64bit_only;
20 	const char *name;
21 	unsigned long long value;
22 	unsigned long long keep;
23 };
24 
25 
26 #define addr_64 0x0000123456789abcULL
27 #define addr_ul (unsigned long)addr_64
28 
29 #define MSR_TEST(msr, val, ro)	\
30 	{ .index = msr, .name = #msr, .value = val, .is_64bit_only = false, .keep = ro }
31 #define MSR_TEST_ONLY64(msr, val, ro)	\
32 	{ .index = msr, .name = #msr, .value = val, .is_64bit_only = true, .keep = ro }
33 
34 struct msr_info msr_info[] =
35 {
36 	MSR_TEST(MSR_IA32_SYSENTER_CS, 0x1234, 0),
37 	MSR_TEST(MSR_IA32_SYSENTER_ESP, addr_ul, 0),
38 	MSR_TEST(MSR_IA32_SYSENTER_EIP, addr_ul, 0),
39 	// reserved: 1:2, 4:6, 8:10, 13:15, 17, 19:21, 24:33, 35:63
40 	// read-only: 7, 11, 12
41 	MSR_TEST(MSR_IA32_MISC_ENABLE, 0x400c50809, 0x1880),
42 	MSR_TEST(MSR_IA32_CR_PAT, 0x07070707, 0),
43 	MSR_TEST_ONLY64(MSR_FS_BASE, addr_64, 0),
44 	MSR_TEST_ONLY64(MSR_GS_BASE, addr_64, 0),
45 	MSR_TEST_ONLY64(MSR_KERNEL_GS_BASE, addr_64, 0),
46 	MSR_TEST(MSR_EFER, EFER_SCE, 0),
47 	MSR_TEST_ONLY64(MSR_LSTAR, addr_64, 0),
48 	MSR_TEST_ONLY64(MSR_CSTAR, addr_64, 0),
49 	MSR_TEST_ONLY64(MSR_SYSCALL_MASK, 0xffffffff, 0),
50 //	MSR_IA32_DEBUGCTLMSR needs svm feature LBRV
51 //	MSR_VM_HSAVE_PA only AMD host
52 };
53 
54 static void test_msr_rw(struct msr_info *msr, unsigned long long val)
55 {
56 	unsigned long long r, orig;
57 
58 	orig = rdmsr(msr->index);
59 	/*
60 	 * Special case EFER since clearing LME/LMA is not allowed in 64-bit mode,
61 	 * and conversely setting those bits on 32-bit CPUs is not allowed.  Treat
62 	 * the desired value as extra bits to set.
63 	 */
64 	if (msr->index == MSR_EFER)
65 		val |= orig;
66 	else
67 		val = (val & ~msr->keep) | (orig & msr->keep);
68 	wrmsr(msr->index, val);
69 	r = rdmsr(msr->index);
70 	wrmsr(msr->index, orig);
71 	if (r != val) {
72 		printf("testing %s: output = %#" PRIx32 ":%#" PRIx32
73 		       " expected = %#" PRIx32 ":%#" PRIx32 "\n", msr->name,
74 		       (u32)(r >> 32), (u32)r, (u32)(val >> 32), (u32)val);
75 	}
76 	report(val == r, "%s", msr->name);
77 }
78 
79 static void test_wrmsr_fault(struct msr_info *msr, unsigned long long val)
80 {
81 	unsigned char vector = wrmsr_checking(msr->index, val);
82 
83 	report(vector == GP_VECTOR,
84 	       "Expected #GP on WRSMR(%s, 0x%llx), got vector %d",
85 	       msr->name, val, vector);
86 }
87 
88 static void test_rdmsr_fault(struct msr_info *msr)
89 {
90 	unsigned char vector = rdmsr_checking(msr->index);
91 
92 	report(vector == GP_VECTOR,
93 	       "Expected #GP on RDSMR(%s), got vector %d", msr->name, vector);
94 }
95 
96 static void test_msr(struct msr_info *msr, bool is_64bit_host)
97 {
98 	if (is_64bit_host || !msr->is_64bit_only) {
99 		test_msr_rw(msr, msr->value);
100 
101 		/*
102 		 * The 64-bit only MSRs that take an address always perform
103 		 * canonical checks on both Intel and AMD.
104 		 */
105 		if (msr->is_64bit_only &&
106 		    msr->value == addr_64)
107 			test_wrmsr_fault(msr, NONCANONICAL);
108 	} else {
109 		test_wrmsr_fault(msr, msr->value);
110 		test_rdmsr_fault(msr);
111 	}
112 }
113 
114 int main(int ac, char **av)
115 {
116 	bool is_64bit_host = this_cpu_has(X86_FEATURE_LM);
117 	int i;
118 
119 	if (ac == 3) {
120 		char msr_name[16];
121 		int index = strtoul(av[1], NULL, 0x10);
122 		snprintf(msr_name, sizeof(msr_name), "MSR:0x%x", index);
123 
124 		struct msr_info msr = {
125 			.index = index,
126 			.name = msr_name,
127 			.value = strtoull(av[2], NULL, 0x10)
128 		};
129 		test_msr(&msr, is_64bit_host);
130 	} else {
131 		for (i = 0 ; i < ARRAY_SIZE(msr_info); i++) {
132 			test_msr(&msr_info[i], is_64bit_host);
133 		}
134 	}
135 
136 	return report_summary();
137 }
138