xref: /kvm-unit-tests/x86/msr.c (revision 65096195ec2dca22bd250c1b46fe67d8ddbee03d)
17d36db35SAvi Kivity /* msr tests */
27d36db35SAvi Kivity 
37d36db35SAvi Kivity #include "libcflat.h"
4850479e3SJason Wang #include "processor.h"
5d1bdd07cSAvi Kivity #include "msr.h"
65b4855b3SDaniele Ahmed #include <stdlib.h>
75b4855b3SDaniele Ahmed 
85b4855b3SDaniele Ahmed /**
95b4855b3SDaniele Ahmed  * This test allows two modes:
105b4855b3SDaniele Ahmed  * 1. Default: the `msr_info' array contains the default test configurations
115b4855b3SDaniele Ahmed  * 2. Custom: by providing command line arguments it is possible to test any MSR and value
125b4855b3SDaniele Ahmed  *	Parameters order:
135b4855b3SDaniele Ahmed  *		1. msr index as a base 16 number
145b4855b3SDaniele Ahmed  *		2. value as a base 16 number
155b4855b3SDaniele Ahmed  */
167d36db35SAvi Kivity 
177d36db35SAvi Kivity struct msr_info {
187d36db35SAvi Kivity 	int index;
19142ff635SSean Christopherson 	bool is_64bit_only;
20797d79a2SThomas Huth 	const char *name;
217d36db35SAvi Kivity 	unsigned long long value;
22bab19cadSPaolo Bonzini 	unsigned long long keep;
237d36db35SAvi Kivity };
247d36db35SAvi Kivity 
257d36db35SAvi Kivity 
267d36db35SAvi Kivity #define addr_64 0x0000123456789abcULL
278feb8cfbSSean Christopherson #define addr_ul (unsigned long)addr_64
287d36db35SAvi Kivity 
29ca85dda2SSean Christopherson #define MSR_TEST(msr, val, ro)	\
30ca85dda2SSean Christopherson 	{ .index = msr, .name = #msr, .value = val, .is_64bit_only = false, .keep = ro }
31ca85dda2SSean Christopherson #define MSR_TEST_ONLY64(msr, val, ro)	\
32ca85dda2SSean Christopherson 	{ .index = msr, .name = #msr, .value = val, .is_64bit_only = true, .keep = ro }
3364662079SSean Christopherson 
347d36db35SAvi Kivity struct msr_info msr_info[] =
357d36db35SAvi Kivity {
36ca85dda2SSean Christopherson 	MSR_TEST(MSR_IA32_SYSENTER_CS, 0x1234, 0),
37ca85dda2SSean Christopherson 	MSR_TEST(MSR_IA32_SYSENTER_ESP, addr_ul, 0),
38ca85dda2SSean Christopherson 	MSR_TEST(MSR_IA32_SYSENTER_EIP, addr_ul, 0),
397d36db35SAvi Kivity 	// reserved: 1:2, 4:6, 8:10, 13:15, 17, 19:21, 24:33, 35:63
40bab19cadSPaolo Bonzini 	// read-only: 7, 11, 12
41ca85dda2SSean Christopherson 	MSR_TEST(MSR_IA32_MISC_ENABLE, 0x400c50809, 0x1880),
42ca85dda2SSean Christopherson 	MSR_TEST(MSR_IA32_CR_PAT, 0x07070707, 0),
43ca85dda2SSean Christopherson 	MSR_TEST_ONLY64(MSR_FS_BASE, addr_64, 0),
44ca85dda2SSean Christopherson 	MSR_TEST_ONLY64(MSR_GS_BASE, addr_64, 0),
45ca85dda2SSean Christopherson 	MSR_TEST_ONLY64(MSR_KERNEL_GS_BASE, addr_64, 0),
46ca85dda2SSean Christopherson 	MSR_TEST(MSR_EFER, EFER_SCE, 0),
47ca85dda2SSean Christopherson 	MSR_TEST_ONLY64(MSR_LSTAR, addr_64, 0),
48ca85dda2SSean Christopherson 	MSR_TEST_ONLY64(MSR_CSTAR, addr_64, 0),
49ca85dda2SSean Christopherson 	MSR_TEST_ONLY64(MSR_SYSCALL_MASK, 0xffffffff, 0),
507d36db35SAvi Kivity //	MSR_IA32_DEBUGCTLMSR needs svm feature LBRV
517d36db35SAvi Kivity //	MSR_VM_HSAVE_PA only AMD host
527d36db35SAvi Kivity };
537d36db35SAvi Kivity 
54039d9207SSean Christopherson static void __test_msr_rw(u32 msr, const char *name, unsigned long long val,
55fb0d9894SSean Christopherson 			  unsigned long long keep_mask)
567d36db35SAvi Kivity {
57a73d6ae4SSean Christopherson 	unsigned long long r, orig;
5850273266SSean Christopherson 
59fb0d9894SSean Christopherson 	orig = rdmsr(msr);
60dcae8d5fSSean Christopherson 	/*
61dcae8d5fSSean Christopherson 	 * Special case EFER since clearing LME/LMA is not allowed in 64-bit mode,
62dcae8d5fSSean Christopherson 	 * and conversely setting those bits on 32-bit CPUs is not allowed.  Treat
63dcae8d5fSSean Christopherson 	 * the desired value as extra bits to set.
64dcae8d5fSSean Christopherson 	 */
65fb0d9894SSean Christopherson 	if (msr == MSR_EFER)
66dcae8d5fSSean Christopherson 		val |= orig;
67bab19cadSPaolo Bonzini 	else
68fb0d9894SSean Christopherson 		val = (val & ~keep_mask) | (orig & keep_mask);
69fb0d9894SSean Christopherson 
70fb0d9894SSean Christopherson 	wrmsr(msr, val);
71fb0d9894SSean Christopherson 	r = rdmsr(msr);
72fb0d9894SSean Christopherson 	wrmsr(msr, orig);
73fb0d9894SSean Christopherson 
749295327cSSean Christopherson 	if (r != val) {
75d26193a0SRoman Bolshakov 		printf("testing %s: output = %#" PRIx32 ":%#" PRIx32
76fb0d9894SSean Christopherson 		       " expected = %#" PRIx32 ":%#" PRIx32 "\n", name,
779295327cSSean Christopherson 		       (u32)(r >> 32), (u32)r, (u32)(val >> 32), (u32)val);
787d36db35SAvi Kivity 	}
79fb0d9894SSean Christopherson 	report(val == r, "%s", name);
807d36db35SAvi Kivity }
817d36db35SAvi Kivity 
82039d9207SSean Christopherson static void test_msr_rw(u32 msr, const char *name, unsigned long long val)
83039d9207SSean Christopherson {
84039d9207SSean Christopherson 	__test_msr_rw(msr, name, val, 0);
85039d9207SSean Christopherson }
86039d9207SSean Christopherson 
87fb0d9894SSean Christopherson static void test_wrmsr_fault(u32 msr, const char *name, unsigned long long val)
88142ff635SSean Christopherson {
894143fbfdSSean Christopherson 	unsigned char vector = wrmsr_safe(msr, val);
90142ff635SSean Christopherson 
91142ff635SSean Christopherson 	report(vector == GP_VECTOR,
92142ff635SSean Christopherson 	       "Expected #GP on WRSMR(%s, 0x%llx), got vector %d",
93fb0d9894SSean Christopherson 	       name, val, vector);
94142ff635SSean Christopherson }
95142ff635SSean Christopherson 
96fb0d9894SSean Christopherson static void test_rdmsr_fault(u32 msr, const char *name)
97142ff635SSean Christopherson {
980a4d8626SSean Christopherson 	uint64_t ignored;
990a4d8626SSean Christopherson 	unsigned char vector = rdmsr_safe(msr, &ignored);
100142ff635SSean Christopherson 
101142ff635SSean Christopherson 	report(vector == GP_VECTOR,
102fb0d9894SSean Christopherson 	       "Expected #GP on RDSMR(%s), got vector %d", name, vector);
103142ff635SSean Christopherson }
104142ff635SSean Christopherson 
1059e8ecb28SDaniele Ahmed static void test_msr(struct msr_info *msr, bool is_64bit_host)
1069e8ecb28SDaniele Ahmed {
1079e8ecb28SDaniele Ahmed 	if (is_64bit_host || !msr->is_64bit_only) {
108039d9207SSean Christopherson 		__test_msr_rw(msr->index, msr->name, msr->value, msr->keep);
1099e8ecb28SDaniele Ahmed 
1109e8ecb28SDaniele Ahmed 		/*
1119e8ecb28SDaniele Ahmed 		 * The 64-bit only MSRs that take an address always perform
1129e8ecb28SDaniele Ahmed 		 * canonical checks on both Intel and AMD.
1139e8ecb28SDaniele Ahmed 		 */
1149e8ecb28SDaniele Ahmed 		if (msr->is_64bit_only &&
1159e8ecb28SDaniele Ahmed 		    msr->value == addr_64)
116fb0d9894SSean Christopherson 			test_wrmsr_fault(msr->index, msr->name, NONCANONICAL);
1179e8ecb28SDaniele Ahmed 	} else {
118fb0d9894SSean Christopherson 		test_wrmsr_fault(msr->index, msr->name, msr->value);
119fb0d9894SSean Christopherson 		test_rdmsr_fault(msr->index, msr->name);
1209e8ecb28SDaniele Ahmed 	}
1219e8ecb28SDaniele Ahmed }
1229e8ecb28SDaniele Ahmed 
123*65096195SSean Christopherson static void test_custom_msr(int ac, char **av)
1247d36db35SAvi Kivity {
125142ff635SSean Christopherson 	bool is_64bit_host = this_cpu_has(X86_FEATURE_LM);
126039d9207SSean Christopherson 	char msr_name[32];
1275b4855b3SDaniele Ahmed 	int index = strtoul(av[1], NULL, 0x10);
1285b4855b3SDaniele Ahmed 	snprintf(msr_name, sizeof(msr_name), "MSR:0x%x", index);
1295b4855b3SDaniele Ahmed 
1305b4855b3SDaniele Ahmed 	struct msr_info msr = {
1315b4855b3SDaniele Ahmed 		.index = index,
1325b4855b3SDaniele Ahmed 		.name = msr_name,
1335b4855b3SDaniele Ahmed 		.value = strtoull(av[2], NULL, 0x10)
1345b4855b3SDaniele Ahmed 	};
1355b4855b3SDaniele Ahmed 	test_msr(&msr, is_64bit_host);
136*65096195SSean Christopherson }
137*65096195SSean Christopherson 
138*65096195SSean Christopherson static void test_misc_msrs(void)
139*65096195SSean Christopherson {
140*65096195SSean Christopherson 	bool is_64bit_host = this_cpu_has(X86_FEATURE_LM);
141*65096195SSean Christopherson 	int i;
142*65096195SSean Christopherson 
143039d9207SSean Christopherson 	for (i = 0 ; i < ARRAY_SIZE(msr_info); i++)
1449e8ecb28SDaniele Ahmed 		test_msr(&msr_info[i], is_64bit_host);
145*65096195SSean Christopherson }
146*65096195SSean Christopherson 
147*65096195SSean Christopherson static void test_mce_msrs(void)
148*65096195SSean Christopherson {
149*65096195SSean Christopherson 	bool is_64bit_host = this_cpu_has(X86_FEATURE_LM);
150*65096195SSean Christopherson 	unsigned int nr_mce_banks;
151*65096195SSean Christopherson 	char msr_name[32];
152*65096195SSean Christopherson 	int i;
153039d9207SSean Christopherson 
154039d9207SSean Christopherson 	nr_mce_banks = rdmsr(MSR_IA32_MCG_CAP) & 0xff;
155039d9207SSean Christopherson 	for (i = 0; i < nr_mce_banks; i++) {
156039d9207SSean Christopherson 		snprintf(msr_name, sizeof(msr_name), "MSR_IA32_MC%u_CTL", i);
157039d9207SSean Christopherson 		test_msr_rw(MSR_IA32_MCx_CTL(i), msr_name, 0);
158039d9207SSean Christopherson 		test_msr_rw(MSR_IA32_MCx_CTL(i), msr_name, -1ull);
159039d9207SSean Christopherson 		test_wrmsr_fault(MSR_IA32_MCx_CTL(i), msr_name, NONCANONICAL);
160039d9207SSean Christopherson 
161039d9207SSean Christopherson 		snprintf(msr_name, sizeof(msr_name), "MSR_IA32_MC%u_STATUS", i);
162039d9207SSean Christopherson 		test_msr_rw(MSR_IA32_MCx_STATUS(i), msr_name, 0);
163039d9207SSean Christopherson 		/*
164*65096195SSean Christopherson 		 * STATUS MSRs can only be written with '0' (to clear the MSR),
165*65096195SSean Christopherson 		 * except on AMD-based systems with bit 18 set in MSR_K7_HWCR.
166*65096195SSean Christopherson 		 * That bit is not architectural and should not be set by
167*65096195SSean Christopherson 		 * default by KVM or by the VMM (though this might fail if run
168*65096195SSean Christopherson 		 * on bare metal).
169039d9207SSean Christopherson 		 */
170039d9207SSean Christopherson 		test_wrmsr_fault(MSR_IA32_MCx_STATUS(i), msr_name, 1);
171039d9207SSean Christopherson 
172039d9207SSean Christopherson 		snprintf(msr_name, sizeof(msr_name), "MSR_IA32_MC%u_ADDR", i);
173039d9207SSean Christopherson 		test_msr_rw(MSR_IA32_MCx_ADDR(i), msr_name, 0);
174039d9207SSean Christopherson 		test_msr_rw(MSR_IA32_MCx_ADDR(i), msr_name, -1ull);
175039d9207SSean Christopherson 		/*
176*65096195SSean Christopherson 		 * The ADDR is a physical address, and all bits are writable on
177*65096195SSean Christopherson 		 * 64-bit hosts.  Don't test the negative case, as KVM doesn't
178*65096195SSean Christopherson 		 * enforce checks on bits 63:36 for 32-bit hosts.  The behavior
179*65096195SSean Christopherson 		 * depends on the underlying hardware, e.g. a 32-bit guest on a
180*65096195SSean Christopherson 		 * 64-bit host may observe 64-bit values in the ADDR MSRs.
181039d9207SSean Christopherson 		 */
182039d9207SSean Christopherson 		if (is_64bit_host)
183039d9207SSean Christopherson 			test_msr_rw(MSR_IA32_MCx_ADDR(i), msr_name, NONCANONICAL);
184039d9207SSean Christopherson 
185039d9207SSean Christopherson 		snprintf(msr_name, sizeof(msr_name), "MSR_IA32_MC%u_MISC", i);
186039d9207SSean Christopherson 		test_msr_rw(MSR_IA32_MCx_MISC(i), msr_name, 0);
187039d9207SSean Christopherson 		test_msr_rw(MSR_IA32_MCx_MISC(i), msr_name, -1ull);
188039d9207SSean Christopherson 		test_msr_rw(MSR_IA32_MCx_MISC(i), msr_name, NONCANONICAL);
189039d9207SSean Christopherson 	}
190039d9207SSean Christopherson 
191039d9207SSean Christopherson 	/*
192*65096195SSean Christopherson 	 * The theoretical maximum number of MCE banks is 32 (on Intel CPUs,
193*65096195SSean Christopherson 	 * without jumping to a new base address), as the last unclaimed MSR is
194*65096195SSean Christopherson 	 * 0x479; 0x480 begins the VMX MSRs.  Verify accesses to theoretically
195*65096195SSean Christopherson 	 * legal, unsupported MSRs fault.
196039d9207SSean Christopherson 	 */
197039d9207SSean Christopherson 	for (i = nr_mce_banks; i < 32; i++) {
198039d9207SSean Christopherson 		snprintf(msr_name, sizeof(msr_name), "MSR_IA32_MC%u_CTL", i);
199039d9207SSean Christopherson 		test_rdmsr_fault(MSR_IA32_MCx_CTL(i), msr_name);
200039d9207SSean Christopherson 		test_wrmsr_fault(MSR_IA32_MCx_CTL(i), msr_name, 0);
201039d9207SSean Christopherson 
202039d9207SSean Christopherson 		snprintf(msr_name, sizeof(msr_name), "MSR_IA32_MC%u_STATUS", i);
203039d9207SSean Christopherson 		test_rdmsr_fault(MSR_IA32_MCx_STATUS(i), msr_name);
204039d9207SSean Christopherson 		test_wrmsr_fault(MSR_IA32_MCx_STATUS(i), msr_name, 0);
205039d9207SSean Christopherson 
206039d9207SSean Christopherson 		snprintf(msr_name, sizeof(msr_name), "MSR_IA32_MC%u_ADDR", i);
207039d9207SSean Christopherson 		test_rdmsr_fault(MSR_IA32_MCx_ADDR(i), msr_name);
208039d9207SSean Christopherson 		test_wrmsr_fault(MSR_IA32_MCx_ADDR(i), msr_name, 0);
209039d9207SSean Christopherson 
210039d9207SSean Christopherson 		snprintf(msr_name, sizeof(msr_name), "MSR_IA32_MC%u_MISC", i);
211039d9207SSean Christopherson 		test_rdmsr_fault(MSR_IA32_MCx_MISC(i), msr_name);
212039d9207SSean Christopherson 		test_wrmsr_fault(MSR_IA32_MCx_MISC(i), msr_name, 0);
213142ff635SSean Christopherson 	}
2145b4855b3SDaniele Ahmed }
2157d36db35SAvi Kivity 
216*65096195SSean Christopherson int main(int ac, char **av)
217*65096195SSean Christopherson {
218*65096195SSean Christopherson 	/*
219*65096195SSean Christopherson 	 * If the user provided an MSR+value, test exactly that and skip all
220*65096195SSean Christopherson 	 * built-in testcases.
221*65096195SSean Christopherson 	 */
222*65096195SSean Christopherson 	if (ac == 3) {
223*65096195SSean Christopherson 		test_custom_msr(ac, av);
224*65096195SSean Christopherson 	} else {
225*65096195SSean Christopherson 		test_misc_msrs();
226*65096195SSean Christopherson 		test_mce_msrs();
227*65096195SSean Christopherson 	}
228*65096195SSean Christopherson 
229f3cdd159SJan Kiszka 	return report_summary();
2307d36db35SAvi Kivity }
231