xref: /kvm-unit-tests/x86/vmexit.c (revision 5fecf5d8cad101e2a3ce7af85ed18bc44624e552)
17d36db35SAvi Kivity 
27d36db35SAvi Kivity #include "libcflat.h"
37d36db35SAvi Kivity #include "smp.h"
4850479e3SJason Wang #include "processor.h"
57d641cc5SAvi Kivity #include "atomic.h"
67d36db35SAvi Kivity 
77d36db35SAvi Kivity static unsigned int inl(unsigned short port)
87d36db35SAvi Kivity {
97d36db35SAvi Kivity     unsigned int val;
107d36db35SAvi Kivity     asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
117d36db35SAvi Kivity     return val;
127d36db35SAvi Kivity }
137d36db35SAvi Kivity 
147d36db35SAvi Kivity #define GOAL (1ull << 30)
157d36db35SAvi Kivity 
16eda71b28SAvi Kivity static int nr_cpus;
17eda71b28SAvi Kivity 
187d36db35SAvi Kivity #ifdef __x86_64__
197d36db35SAvi Kivity #  define R "r"
207d36db35SAvi Kivity #else
217d36db35SAvi Kivity #  define R "e"
227d36db35SAvi Kivity #endif
237d36db35SAvi Kivity 
24850479e3SJason Wang static void cpuid_test(void)
257d36db35SAvi Kivity {
267d36db35SAvi Kivity 	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
277d36db35SAvi Kivity 		      : : : "eax", "ecx", "edx");
287d36db35SAvi Kivity }
297d36db35SAvi Kivity 
307d36db35SAvi Kivity static void vmcall(void)
317d36db35SAvi Kivity {
327d36db35SAvi Kivity 	unsigned long a = 0, b, c, d;
337d36db35SAvi Kivity 
347d36db35SAvi Kivity 	asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
357d36db35SAvi Kivity }
367d36db35SAvi Kivity 
37*5fecf5d8SWill Auld #define MSR_TSC_ADJUST 0x3b
387d36db35SAvi Kivity #define MSR_EFER 0xc0000080
397d36db35SAvi Kivity #define EFER_NX_MASK            (1ull << 11)
407d36db35SAvi Kivity 
415ada505aSJason Wang #ifdef __x86_64__
427d36db35SAvi Kivity static void mov_from_cr8(void)
437d36db35SAvi Kivity {
447d36db35SAvi Kivity 	unsigned long cr8;
457d36db35SAvi Kivity 
467d36db35SAvi Kivity 	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
477d36db35SAvi Kivity }
487d36db35SAvi Kivity 
497d36db35SAvi Kivity static void mov_to_cr8(void)
507d36db35SAvi Kivity {
517d36db35SAvi Kivity 	unsigned long cr8 = 0;
527d36db35SAvi Kivity 
537d36db35SAvi Kivity 	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
547d36db35SAvi Kivity }
555ada505aSJason Wang #endif
567d36db35SAvi Kivity 
577d36db35SAvi Kivity static int is_smp(void)
587d36db35SAvi Kivity {
597d36db35SAvi Kivity 	return cpu_count() > 1;
607d36db35SAvi Kivity }
617d36db35SAvi Kivity 
627d36db35SAvi Kivity static void nop(void *junk)
637d36db35SAvi Kivity {
647d36db35SAvi Kivity }
657d36db35SAvi Kivity 
667d36db35SAvi Kivity static void ipi(void)
677d36db35SAvi Kivity {
687d36db35SAvi Kivity 	on_cpu(1, nop, 0);
697d36db35SAvi Kivity }
707d36db35SAvi Kivity 
717d36db35SAvi Kivity static void ipi_halt(void)
727d36db35SAvi Kivity {
737d36db35SAvi Kivity 	unsigned long long t;
747d36db35SAvi Kivity 
757d36db35SAvi Kivity 	on_cpu(1, nop, 0);
767d36db35SAvi Kivity 	t = rdtsc() + 2000;
777d36db35SAvi Kivity 	while (rdtsc() < t)
787d36db35SAvi Kivity 		;
797d36db35SAvi Kivity }
807d36db35SAvi Kivity 
817d36db35SAvi Kivity static void inl_pmtimer(void)
827d36db35SAvi Kivity {
837d36db35SAvi Kivity     inl(0xb008);
847d36db35SAvi Kivity }
857d36db35SAvi Kivity 
86eda71b28SAvi Kivity static void ple_round_robin(void)
87eda71b28SAvi Kivity {
88eda71b28SAvi Kivity 	struct counter {
89eda71b28SAvi Kivity 		volatile int n1;
90eda71b28SAvi Kivity 		int n2;
91eda71b28SAvi Kivity 	} __attribute__((aligned(64)));
92eda71b28SAvi Kivity 	static struct counter counters[64] = { { -1, 0 } };
93eda71b28SAvi Kivity 	int me = smp_id();
94eda71b28SAvi Kivity 	int you;
95eda71b28SAvi Kivity 	volatile struct counter *p = &counters[me];
96eda71b28SAvi Kivity 
97eda71b28SAvi Kivity 	while (p->n1 == p->n2)
98eda71b28SAvi Kivity 		asm volatile ("pause");
99eda71b28SAvi Kivity 
100eda71b28SAvi Kivity 	p->n2 = p->n1;
101eda71b28SAvi Kivity 	you = me + 1;
102eda71b28SAvi Kivity 	if (you == nr_cpus)
103eda71b28SAvi Kivity 		you = 0;
104eda71b28SAvi Kivity 	++counters[you].n1;
105eda71b28SAvi Kivity }
106eda71b28SAvi Kivity 
107*5fecf5d8SWill Auld static void rd_tsc_adjust_msr(void)
108*5fecf5d8SWill Auld {
109*5fecf5d8SWill Auld 	rdmsr(MSR_TSC_ADJUST);
110*5fecf5d8SWill Auld }
111*5fecf5d8SWill Auld 
112*5fecf5d8SWill Auld static void wr_tsc_adjust_msr(void)
113*5fecf5d8SWill Auld {
114*5fecf5d8SWill Auld 	wrmsr(MSR_TSC_ADJUST, 0x0);
115*5fecf5d8SWill Auld }
116*5fecf5d8SWill Auld 
1177d36db35SAvi Kivity static struct test {
1187d36db35SAvi Kivity 	void (*func)(void);
1197d36db35SAvi Kivity 	const char *name;
1207d36db35SAvi Kivity 	int (*valid)(void);
1217d36db35SAvi Kivity 	int parallel;
1227d36db35SAvi Kivity } tests[] = {
123850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
1247d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
1255ada505aSJason Wang #ifdef __x86_64__
1267d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
1277d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
1285ada505aSJason Wang #endif
1297d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
1307d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
1317d36db35SAvi Kivity 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
132eda71b28SAvi Kivity 	{ ple_round_robin, "ple-round-robin", .parallel = 1 },
133*5fecf5d8SWill Auld 	{ wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 },
134*5fecf5d8SWill Auld 	{ rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 },
1357d36db35SAvi Kivity };
1367d36db35SAvi Kivity 
1377d36db35SAvi Kivity unsigned iterations;
1387d641cc5SAvi Kivity static atomic_t nr_cpus_done;
1397d36db35SAvi Kivity 
1407d36db35SAvi Kivity static void run_test(void *_func)
1417d36db35SAvi Kivity {
1427d36db35SAvi Kivity     int i;
1437d36db35SAvi Kivity     void (*func)(void) = _func;
1447d36db35SAvi Kivity 
1457d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
1467d36db35SAvi Kivity         func();
1477d36db35SAvi Kivity 
1487d641cc5SAvi Kivity     atomic_inc(&nr_cpus_done);
1497d36db35SAvi Kivity }
1507d36db35SAvi Kivity 
1517d36db35SAvi Kivity static void do_test(struct test *test)
1527d36db35SAvi Kivity {
1537d36db35SAvi Kivity 	int i;
1547d36db35SAvi Kivity 	unsigned long long t1, t2;
1557d36db35SAvi Kivity         void (*func)(void) = test->func;
1567d36db35SAvi Kivity 
1577d36db35SAvi Kivity         iterations = 32;
1587d36db35SAvi Kivity 
1597d36db35SAvi Kivity         if (test->valid && !test->valid()) {
1607d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
1617d36db35SAvi Kivity 		return;
1627d36db35SAvi Kivity 	}
1637d36db35SAvi Kivity 
1647d36db35SAvi Kivity 	do {
1657d36db35SAvi Kivity 		iterations *= 2;
1667d36db35SAvi Kivity 		t1 = rdtsc();
1677d36db35SAvi Kivity 
1687d36db35SAvi Kivity 		if (!test->parallel) {
1697d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
1707d36db35SAvi Kivity 				func();
1717d36db35SAvi Kivity 		} else {
1727d641cc5SAvi Kivity 			atomic_set(&nr_cpus_done, 0);
1737d36db35SAvi Kivity 			for (i = cpu_count(); i > 0; i--)
1747d36db35SAvi Kivity 				on_cpu_async(i-1, run_test, func);
1757d641cc5SAvi Kivity 			while (atomic_read(&nr_cpus_done) < cpu_count())
1767d36db35SAvi Kivity 				;
1777d36db35SAvi Kivity 		}
1787d36db35SAvi Kivity 		t2 = rdtsc();
1797d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
1807d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
1817d36db35SAvi Kivity }
1827d36db35SAvi Kivity 
1837d36db35SAvi Kivity static void enable_nx(void *junk)
1847d36db35SAvi Kivity {
185e46b32aaSAvi Kivity 	if (cpuid(0x80000001).d & (1 << 20))
1867d36db35SAvi Kivity 		wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
1877d36db35SAvi Kivity }
1887d36db35SAvi Kivity 
1890b267183SAvi Kivity bool test_wanted(struct test *test, char *wanted[], int nwanted)
1900b267183SAvi Kivity {
1910b267183SAvi Kivity 	int i;
1920b267183SAvi Kivity 
1930b267183SAvi Kivity 	if (!nwanted)
1940b267183SAvi Kivity 		return true;
1950b267183SAvi Kivity 
1960b267183SAvi Kivity 	for (i = 0; i < nwanted; ++i)
1970b267183SAvi Kivity 		if (strcmp(wanted[i], test->name) == 0)
1980b267183SAvi Kivity 			return true;
1990b267183SAvi Kivity 
2000b267183SAvi Kivity 	return false;
2010b267183SAvi Kivity }
2020b267183SAvi Kivity 
2030b267183SAvi Kivity int main(int ac, char **av)
2047d36db35SAvi Kivity {
2057d36db35SAvi Kivity 	int i;
2067d36db35SAvi Kivity 
2077d36db35SAvi Kivity 	smp_init();
208eda71b28SAvi Kivity 	nr_cpus = cpu_count();
2097d36db35SAvi Kivity 
2107d36db35SAvi Kivity 	for (i = cpu_count(); i > 0; i--)
2117d36db35SAvi Kivity 		on_cpu(i-1, enable_nx, 0);
2127d36db35SAvi Kivity 
2137d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
2140b267183SAvi Kivity 		if (test_wanted(&tests[i], av + 1, ac - 1))
2157d36db35SAvi Kivity 			do_test(&tests[i]);
2167d36db35SAvi Kivity 
2177d36db35SAvi Kivity 	return 0;
2187d36db35SAvi Kivity }
219