xref: /kvm-unit-tests/x86/vmexit.c (revision 00bfecaaa5a4d035507086635259a0dd7e4531be)
17d36db35SAvi Kivity 
27d36db35SAvi Kivity #include "libcflat.h"
37d36db35SAvi Kivity #include "smp.h"
4850479e3SJason Wang #include "processor.h"
57d641cc5SAvi Kivity #include "atomic.h"
67d36db35SAvi Kivity 
7*00bfecaaSPaolo Bonzini static void outb(unsigned short port, int val)
8*00bfecaaSPaolo Bonzini {
9*00bfecaaSPaolo Bonzini     asm volatile("outb %b0, %w1" : "=a"(val) : "Nd"(port));
10*00bfecaaSPaolo Bonzini }
11*00bfecaaSPaolo Bonzini 
12*00bfecaaSPaolo Bonzini static unsigned int inb(unsigned short port)
13*00bfecaaSPaolo Bonzini {
14*00bfecaaSPaolo Bonzini     unsigned int val;
15*00bfecaaSPaolo Bonzini     asm volatile("xorl %0, %0; inb %w1, %b0" : "=a"(val) : "Nd"(port));
16*00bfecaaSPaolo Bonzini     return val;
17*00bfecaaSPaolo Bonzini }
18*00bfecaaSPaolo Bonzini 
197d36db35SAvi Kivity static unsigned int inl(unsigned short port)
207d36db35SAvi Kivity {
217d36db35SAvi Kivity     unsigned int val;
227d36db35SAvi Kivity     asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
237d36db35SAvi Kivity     return val;
247d36db35SAvi Kivity }
257d36db35SAvi Kivity 
267d36db35SAvi Kivity #define GOAL (1ull << 30)
277d36db35SAvi Kivity 
28eda71b28SAvi Kivity static int nr_cpus;
29eda71b28SAvi Kivity 
307d36db35SAvi Kivity #ifdef __x86_64__
317d36db35SAvi Kivity #  define R "r"
327d36db35SAvi Kivity #else
337d36db35SAvi Kivity #  define R "e"
347d36db35SAvi Kivity #endif
357d36db35SAvi Kivity 
36850479e3SJason Wang static void cpuid_test(void)
377d36db35SAvi Kivity {
387d36db35SAvi Kivity 	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
397d36db35SAvi Kivity 		      : : : "eax", "ecx", "edx");
407d36db35SAvi Kivity }
417d36db35SAvi Kivity 
427d36db35SAvi Kivity static void vmcall(void)
437d36db35SAvi Kivity {
447d36db35SAvi Kivity 	unsigned long a = 0, b, c, d;
457d36db35SAvi Kivity 
467d36db35SAvi Kivity 	asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
477d36db35SAvi Kivity }
487d36db35SAvi Kivity 
495fecf5d8SWill Auld #define MSR_TSC_ADJUST 0x3b
507d36db35SAvi Kivity #define MSR_EFER 0xc0000080
517d36db35SAvi Kivity #define EFER_NX_MASK            (1ull << 11)
527d36db35SAvi Kivity 
535ada505aSJason Wang #ifdef __x86_64__
547d36db35SAvi Kivity static void mov_from_cr8(void)
557d36db35SAvi Kivity {
567d36db35SAvi Kivity 	unsigned long cr8;
577d36db35SAvi Kivity 
587d36db35SAvi Kivity 	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
597d36db35SAvi Kivity }
607d36db35SAvi Kivity 
617d36db35SAvi Kivity static void mov_to_cr8(void)
627d36db35SAvi Kivity {
637d36db35SAvi Kivity 	unsigned long cr8 = 0;
647d36db35SAvi Kivity 
657d36db35SAvi Kivity 	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
667d36db35SAvi Kivity }
675ada505aSJason Wang #endif
687d36db35SAvi Kivity 
697d36db35SAvi Kivity static int is_smp(void)
707d36db35SAvi Kivity {
717d36db35SAvi Kivity 	return cpu_count() > 1;
727d36db35SAvi Kivity }
737d36db35SAvi Kivity 
747d36db35SAvi Kivity static void nop(void *junk)
757d36db35SAvi Kivity {
767d36db35SAvi Kivity }
777d36db35SAvi Kivity 
787d36db35SAvi Kivity static void ipi(void)
797d36db35SAvi Kivity {
807d36db35SAvi Kivity 	on_cpu(1, nop, 0);
817d36db35SAvi Kivity }
827d36db35SAvi Kivity 
837d36db35SAvi Kivity static void ipi_halt(void)
847d36db35SAvi Kivity {
857d36db35SAvi Kivity 	unsigned long long t;
867d36db35SAvi Kivity 
877d36db35SAvi Kivity 	on_cpu(1, nop, 0);
887d36db35SAvi Kivity 	t = rdtsc() + 2000;
897d36db35SAvi Kivity 	while (rdtsc() < t)
907d36db35SAvi Kivity 		;
917d36db35SAvi Kivity }
927d36db35SAvi Kivity 
937d36db35SAvi Kivity static void inl_pmtimer(void)
947d36db35SAvi Kivity {
957d36db35SAvi Kivity     inl(0xb008);
967d36db35SAvi Kivity }
977d36db35SAvi Kivity 
98*00bfecaaSPaolo Bonzini static void inl_nop_qemu(void)
99*00bfecaaSPaolo Bonzini {
100*00bfecaaSPaolo Bonzini     inl(0x1234);
101*00bfecaaSPaolo Bonzini }
102*00bfecaaSPaolo Bonzini 
103*00bfecaaSPaolo Bonzini static void inl_nop_kernel(void)
104*00bfecaaSPaolo Bonzini {
105*00bfecaaSPaolo Bonzini     inb(0x4d0);
106*00bfecaaSPaolo Bonzini }
107*00bfecaaSPaolo Bonzini 
108*00bfecaaSPaolo Bonzini static void outl_elcr_kernel(void)
109*00bfecaaSPaolo Bonzini {
110*00bfecaaSPaolo Bonzini     outb(0x4d0, 0);
111*00bfecaaSPaolo Bonzini }
112*00bfecaaSPaolo Bonzini 
113eda71b28SAvi Kivity static void ple_round_robin(void)
114eda71b28SAvi Kivity {
115eda71b28SAvi Kivity 	struct counter {
116eda71b28SAvi Kivity 		volatile int n1;
117eda71b28SAvi Kivity 		int n2;
118eda71b28SAvi Kivity 	} __attribute__((aligned(64)));
119eda71b28SAvi Kivity 	static struct counter counters[64] = { { -1, 0 } };
120eda71b28SAvi Kivity 	int me = smp_id();
121eda71b28SAvi Kivity 	int you;
122eda71b28SAvi Kivity 	volatile struct counter *p = &counters[me];
123eda71b28SAvi Kivity 
124eda71b28SAvi Kivity 	while (p->n1 == p->n2)
125eda71b28SAvi Kivity 		asm volatile ("pause");
126eda71b28SAvi Kivity 
127eda71b28SAvi Kivity 	p->n2 = p->n1;
128eda71b28SAvi Kivity 	you = me + 1;
129eda71b28SAvi Kivity 	if (you == nr_cpus)
130eda71b28SAvi Kivity 		you = 0;
131eda71b28SAvi Kivity 	++counters[you].n1;
132eda71b28SAvi Kivity }
133eda71b28SAvi Kivity 
1345fecf5d8SWill Auld static void rd_tsc_adjust_msr(void)
1355fecf5d8SWill Auld {
1365fecf5d8SWill Auld 	rdmsr(MSR_TSC_ADJUST);
1375fecf5d8SWill Auld }
1385fecf5d8SWill Auld 
1395fecf5d8SWill Auld static void wr_tsc_adjust_msr(void)
1405fecf5d8SWill Auld {
1415fecf5d8SWill Auld 	wrmsr(MSR_TSC_ADJUST, 0x0);
1425fecf5d8SWill Auld }
1435fecf5d8SWill Auld 
1447d36db35SAvi Kivity static struct test {
1457d36db35SAvi Kivity 	void (*func)(void);
1467d36db35SAvi Kivity 	const char *name;
1477d36db35SAvi Kivity 	int (*valid)(void);
1487d36db35SAvi Kivity 	int parallel;
1497d36db35SAvi Kivity } tests[] = {
150850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
1517d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
1525ada505aSJason Wang #ifdef __x86_64__
1537d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
1547d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
1555ada505aSJason Wang #endif
1567d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
157*00bfecaaSPaolo Bonzini 	{ inl_nop_qemu, "inl_from_qemu", .parallel = 1 },
158*00bfecaaSPaolo Bonzini 	{ inl_nop_kernel, "inl_from_kernel", .parallel = 1 },
159*00bfecaaSPaolo Bonzini 	{ outl_elcr_kernel, "outl_to_kernel", .parallel = 1 },
1607d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
1617d36db35SAvi Kivity 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
162eda71b28SAvi Kivity 	{ ple_round_robin, "ple-round-robin", .parallel = 1 },
1635fecf5d8SWill Auld 	{ wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 },
1645fecf5d8SWill Auld 	{ rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 },
1657d36db35SAvi Kivity };
1667d36db35SAvi Kivity 
1677d36db35SAvi Kivity unsigned iterations;
1687d641cc5SAvi Kivity static atomic_t nr_cpus_done;
1697d36db35SAvi Kivity 
1707d36db35SAvi Kivity static void run_test(void *_func)
1717d36db35SAvi Kivity {
1727d36db35SAvi Kivity     int i;
1737d36db35SAvi Kivity     void (*func)(void) = _func;
1747d36db35SAvi Kivity 
1757d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
1767d36db35SAvi Kivity         func();
1777d36db35SAvi Kivity 
1787d641cc5SAvi Kivity     atomic_inc(&nr_cpus_done);
1797d36db35SAvi Kivity }
1807d36db35SAvi Kivity 
1817d36db35SAvi Kivity static void do_test(struct test *test)
1827d36db35SAvi Kivity {
1837d36db35SAvi Kivity 	int i;
1847d36db35SAvi Kivity 	unsigned long long t1, t2;
1857d36db35SAvi Kivity         void (*func)(void) = test->func;
1867d36db35SAvi Kivity 
1877d36db35SAvi Kivity         iterations = 32;
1887d36db35SAvi Kivity 
1897d36db35SAvi Kivity         if (test->valid && !test->valid()) {
1907d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
1917d36db35SAvi Kivity 		return;
1927d36db35SAvi Kivity 	}
1937d36db35SAvi Kivity 
1947d36db35SAvi Kivity 	do {
1957d36db35SAvi Kivity 		iterations *= 2;
1967d36db35SAvi Kivity 		t1 = rdtsc();
1977d36db35SAvi Kivity 
1987d36db35SAvi Kivity 		if (!test->parallel) {
1997d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
2007d36db35SAvi Kivity 				func();
2017d36db35SAvi Kivity 		} else {
2027d641cc5SAvi Kivity 			atomic_set(&nr_cpus_done, 0);
2037d36db35SAvi Kivity 			for (i = cpu_count(); i > 0; i--)
2047d36db35SAvi Kivity 				on_cpu_async(i-1, run_test, func);
2057d641cc5SAvi Kivity 			while (atomic_read(&nr_cpus_done) < cpu_count())
2067d36db35SAvi Kivity 				;
2077d36db35SAvi Kivity 		}
2087d36db35SAvi Kivity 		t2 = rdtsc();
2097d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
2107d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
2117d36db35SAvi Kivity }
2127d36db35SAvi Kivity 
2137d36db35SAvi Kivity static void enable_nx(void *junk)
2147d36db35SAvi Kivity {
215e46b32aaSAvi Kivity 	if (cpuid(0x80000001).d & (1 << 20))
2167d36db35SAvi Kivity 		wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
2177d36db35SAvi Kivity }
2187d36db35SAvi Kivity 
2190b267183SAvi Kivity bool test_wanted(struct test *test, char *wanted[], int nwanted)
2200b267183SAvi Kivity {
2210b267183SAvi Kivity 	int i;
2220b267183SAvi Kivity 
2230b267183SAvi Kivity 	if (!nwanted)
2240b267183SAvi Kivity 		return true;
2250b267183SAvi Kivity 
2260b267183SAvi Kivity 	for (i = 0; i < nwanted; ++i)
2270b267183SAvi Kivity 		if (strcmp(wanted[i], test->name) == 0)
2280b267183SAvi Kivity 			return true;
2290b267183SAvi Kivity 
2300b267183SAvi Kivity 	return false;
2310b267183SAvi Kivity }
2320b267183SAvi Kivity 
2330b267183SAvi Kivity int main(int ac, char **av)
2347d36db35SAvi Kivity {
2357d36db35SAvi Kivity 	int i;
2367d36db35SAvi Kivity 
2377d36db35SAvi Kivity 	smp_init();
238eda71b28SAvi Kivity 	nr_cpus = cpu_count();
2397d36db35SAvi Kivity 
2407d36db35SAvi Kivity 	for (i = cpu_count(); i > 0; i--)
2417d36db35SAvi Kivity 		on_cpu(i-1, enable_nx, 0);
2427d36db35SAvi Kivity 
2437d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
2440b267183SAvi Kivity 		if (test_wanted(&tests[i], av + 1, ac - 1))
2457d36db35SAvi Kivity 			do_test(&tests[i]);
2467d36db35SAvi Kivity 
2477d36db35SAvi Kivity 	return 0;
2487d36db35SAvi Kivity }
249