xref: /kvm-unit-tests/x86/msr.c (revision 5b4855b3e694c95adfd3c1937b4026cd590e27d4)
17d36db35SAvi Kivity /* msr tests */
27d36db35SAvi Kivity 
37d36db35SAvi Kivity #include "libcflat.h"
4850479e3SJason Wang #include "processor.h"
5d1bdd07cSAvi Kivity #include "msr.h"
6*5b4855b3SDaniele Ahmed #include <stdlib.h>
7*5b4855b3SDaniele Ahmed 
8*5b4855b3SDaniele Ahmed /**
9*5b4855b3SDaniele Ahmed  * This test allows two modes:
10*5b4855b3SDaniele Ahmed  * 1. Default: the `msr_info' array contains the default test configurations
11*5b4855b3SDaniele Ahmed  * 2. Custom: by providing command line arguments it is possible to test any MSR and value
12*5b4855b3SDaniele Ahmed  *	Parameters order:
13*5b4855b3SDaniele Ahmed  *		1. msr index as a base 16 number
14*5b4855b3SDaniele Ahmed  *		2. value as a base 16 number
15*5b4855b3SDaniele 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;
227d36db35SAvi Kivity };
237d36db35SAvi Kivity 
247d36db35SAvi Kivity 
257d36db35SAvi Kivity #define addr_64 0x0000123456789abcULL
268feb8cfbSSean Christopherson #define addr_ul (unsigned long)addr_64
277d36db35SAvi Kivity 
28142ff635SSean Christopherson #define MSR_TEST(msr, val, only64)	\
29142ff635SSean Christopherson 	{ .index = msr, .name = #msr, .value = val, .is_64bit_only = only64 }
3064662079SSean Christopherson 
317d36db35SAvi Kivity struct msr_info msr_info[] =
327d36db35SAvi Kivity {
33142ff635SSean Christopherson 	MSR_TEST(MSR_IA32_SYSENTER_CS, 0x1234, false),
34142ff635SSean Christopherson 	MSR_TEST(MSR_IA32_SYSENTER_ESP, addr_ul, false),
35142ff635SSean Christopherson 	MSR_TEST(MSR_IA32_SYSENTER_EIP, addr_ul, false),
367d36db35SAvi Kivity 	// reserved: 1:2, 4:6, 8:10, 13:15, 17, 19:21, 24:33, 35:63
37142ff635SSean Christopherson 	MSR_TEST(MSR_IA32_MISC_ENABLE, 0x400c51889, false),
38142ff635SSean Christopherson 	MSR_TEST(MSR_IA32_CR_PAT, 0x07070707, false),
39142ff635SSean Christopherson 	MSR_TEST(MSR_FS_BASE, addr_64, true),
40142ff635SSean Christopherson 	MSR_TEST(MSR_GS_BASE, addr_64, true),
41142ff635SSean Christopherson 	MSR_TEST(MSR_KERNEL_GS_BASE, addr_64, true),
42dcae8d5fSSean Christopherson 	MSR_TEST(MSR_EFER, EFER_SCE, false),
43142ff635SSean Christopherson 	MSR_TEST(MSR_LSTAR, addr_64, true),
44142ff635SSean Christopherson 	MSR_TEST(MSR_CSTAR, addr_64, true),
45142ff635SSean Christopherson 	MSR_TEST(MSR_SYSCALL_MASK, 0xffffffff, true),
467d36db35SAvi Kivity //	MSR_IA32_DEBUGCTLMSR needs svm feature LBRV
477d36db35SAvi Kivity //	MSR_VM_HSAVE_PA only AMD host
487d36db35SAvi Kivity };
497d36db35SAvi Kivity 
503e788d91SSean Christopherson static void test_msr_rw(struct msr_info *msr, unsigned long long val)
517d36db35SAvi Kivity {
52a73d6ae4SSean Christopherson 	unsigned long long r, orig;
5350273266SSean Christopherson 
543e788d91SSean Christopherson 	orig = rdmsr(msr->index);
55dcae8d5fSSean Christopherson 	/*
56dcae8d5fSSean Christopherson 	 * Special case EFER since clearing LME/LMA is not allowed in 64-bit mode,
57dcae8d5fSSean Christopherson 	 * and conversely setting those bits on 32-bit CPUs is not allowed.  Treat
58dcae8d5fSSean Christopherson 	 * the desired value as extra bits to set.
59dcae8d5fSSean Christopherson 	 */
60dcae8d5fSSean Christopherson 	if (msr->index == MSR_EFER)
61dcae8d5fSSean Christopherson 		val |= orig;
623e788d91SSean Christopherson 	wrmsr(msr->index, val);
633e788d91SSean Christopherson 	r = rdmsr(msr->index);
643e788d91SSean Christopherson 	wrmsr(msr->index, orig);
659295327cSSean Christopherson 	if (r != val) {
66d26193a0SRoman Bolshakov 		printf("testing %s: output = %#" PRIx32 ":%#" PRIx32
673e788d91SSean Christopherson 		       " expected = %#" PRIx32 ":%#" PRIx32 "\n", msr->name,
689295327cSSean Christopherson 		       (u32)(r >> 32), (u32)r, (u32)(val >> 32), (u32)val);
697d36db35SAvi Kivity 	}
703e788d91SSean Christopherson 	report(val == r, "%s", msr->name);
717d36db35SAvi Kivity }
727d36db35SAvi Kivity 
73142ff635SSean Christopherson static void test_wrmsr_fault(struct msr_info *msr, unsigned long long val)
74142ff635SSean Christopherson {
75142ff635SSean Christopherson 	unsigned char vector = wrmsr_checking(msr->index, val);
76142ff635SSean Christopherson 
77142ff635SSean Christopherson 	report(vector == GP_VECTOR,
78142ff635SSean Christopherson 	       "Expected #GP on WRSMR(%s, 0x%llx), got vector %d",
79142ff635SSean Christopherson 	       msr->name, val, vector);
80142ff635SSean Christopherson }
81142ff635SSean Christopherson 
82142ff635SSean Christopherson static void test_rdmsr_fault(struct msr_info *msr)
83142ff635SSean Christopherson {
84142ff635SSean Christopherson 	unsigned char vector = rdmsr_checking(msr->index);
85142ff635SSean Christopherson 
86142ff635SSean Christopherson 	report(vector == GP_VECTOR,
87142ff635SSean Christopherson 	       "Expected #GP on RDSMR(%s), got vector %d", msr->name, vector);
88142ff635SSean Christopherson }
89142ff635SSean Christopherson 
909e8ecb28SDaniele Ahmed static void test_msr(struct msr_info *msr, bool is_64bit_host)
919e8ecb28SDaniele Ahmed {
929e8ecb28SDaniele Ahmed 	if (is_64bit_host || !msr->is_64bit_only) {
939e8ecb28SDaniele Ahmed 		test_msr_rw(msr, msr->value);
949e8ecb28SDaniele Ahmed 
959e8ecb28SDaniele Ahmed 		/*
969e8ecb28SDaniele Ahmed 		 * The 64-bit only MSRs that take an address always perform
979e8ecb28SDaniele Ahmed 		 * canonical checks on both Intel and AMD.
989e8ecb28SDaniele Ahmed 		 */
999e8ecb28SDaniele Ahmed 		if (msr->is_64bit_only &&
1009e8ecb28SDaniele Ahmed 		    msr->value == addr_64)
1019e8ecb28SDaniele Ahmed 			test_wrmsr_fault(msr, NONCANONICAL);
1029e8ecb28SDaniele Ahmed 	} else {
1039e8ecb28SDaniele Ahmed 		test_wrmsr_fault(msr, msr->value);
1049e8ecb28SDaniele Ahmed 		test_rdmsr_fault(msr);
1059e8ecb28SDaniele Ahmed 	}
1069e8ecb28SDaniele Ahmed }
1079e8ecb28SDaniele Ahmed 
1087d36db35SAvi Kivity int main(int ac, char **av)
1097d36db35SAvi Kivity {
110142ff635SSean Christopherson 	bool is_64bit_host = this_cpu_has(X86_FEATURE_LM);
11164662079SSean Christopherson 	int i;
11264662079SSean Christopherson 
113*5b4855b3SDaniele Ahmed 	if (ac == 3) {
114*5b4855b3SDaniele Ahmed 		char msr_name[16];
115*5b4855b3SDaniele Ahmed 		int index = strtoul(av[1], NULL, 0x10);
116*5b4855b3SDaniele Ahmed 		snprintf(msr_name, sizeof(msr_name), "MSR:0x%x", index);
117*5b4855b3SDaniele Ahmed 
118*5b4855b3SDaniele Ahmed 		struct msr_info msr = {
119*5b4855b3SDaniele Ahmed 			.index = index,
120*5b4855b3SDaniele Ahmed 			.name = msr_name,
121*5b4855b3SDaniele Ahmed 			.value = strtoull(av[2], NULL, 0x10)
122*5b4855b3SDaniele Ahmed 		};
123*5b4855b3SDaniele Ahmed 		test_msr(&msr, is_64bit_host);
124*5b4855b3SDaniele Ahmed 	} else {
125142ff635SSean Christopherson 		for (i = 0 ; i < ARRAY_SIZE(msr_info); i++) {
1269e8ecb28SDaniele Ahmed 			test_msr(&msr_info[i], is_64bit_host);
127142ff635SSean Christopherson 		}
128*5b4855b3SDaniele Ahmed 	}
1297d36db35SAvi Kivity 
130f3cdd159SJan Kiszka 	return report_summary();
1317d36db35SAvi Kivity }
132