xref: /kvm-unit-tests/x86/vmexit.c (revision eda71b28fa122203e316483b35f37aaacd42f545)
17d36db35SAvi Kivity 
27d36db35SAvi Kivity #include "libcflat.h"
37d36db35SAvi Kivity #include "smp.h"
4850479e3SJason Wang #include "processor.h"
57d36db35SAvi Kivity 
67d36db35SAvi Kivity static unsigned int inl(unsigned short port)
77d36db35SAvi Kivity {
87d36db35SAvi Kivity     unsigned int val;
97d36db35SAvi Kivity     asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
107d36db35SAvi Kivity     return val;
117d36db35SAvi Kivity }
127d36db35SAvi Kivity 
137d36db35SAvi Kivity #define GOAL (1ull << 30)
147d36db35SAvi Kivity 
15*eda71b28SAvi Kivity static int nr_cpus;
16*eda71b28SAvi Kivity 
177d36db35SAvi Kivity #ifdef __x86_64__
187d36db35SAvi Kivity #  define R "r"
197d36db35SAvi Kivity #else
207d36db35SAvi Kivity #  define R "e"
217d36db35SAvi Kivity #endif
227d36db35SAvi Kivity 
23850479e3SJason Wang static void cpuid_test(void)
247d36db35SAvi Kivity {
257d36db35SAvi Kivity 	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
267d36db35SAvi Kivity 		      : : : "eax", "ecx", "edx");
277d36db35SAvi Kivity }
287d36db35SAvi Kivity 
297d36db35SAvi Kivity static void vmcall(void)
307d36db35SAvi Kivity {
317d36db35SAvi Kivity 	unsigned long a = 0, b, c, d;
327d36db35SAvi Kivity 
337d36db35SAvi Kivity 	asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
347d36db35SAvi Kivity }
357d36db35SAvi Kivity 
367d36db35SAvi Kivity #define MSR_EFER 0xc0000080
377d36db35SAvi Kivity #define EFER_NX_MASK            (1ull << 11)
387d36db35SAvi Kivity 
395ada505aSJason Wang #ifdef __x86_64__
407d36db35SAvi Kivity static void mov_from_cr8(void)
417d36db35SAvi Kivity {
427d36db35SAvi Kivity 	unsigned long cr8;
437d36db35SAvi Kivity 
447d36db35SAvi Kivity 	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
457d36db35SAvi Kivity }
467d36db35SAvi Kivity 
477d36db35SAvi Kivity static void mov_to_cr8(void)
487d36db35SAvi Kivity {
497d36db35SAvi Kivity 	unsigned long cr8 = 0;
507d36db35SAvi Kivity 
517d36db35SAvi Kivity 	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
527d36db35SAvi Kivity }
535ada505aSJason Wang #endif
547d36db35SAvi Kivity 
557d36db35SAvi Kivity static int is_smp(void)
567d36db35SAvi Kivity {
577d36db35SAvi Kivity 	return cpu_count() > 1;
587d36db35SAvi Kivity }
597d36db35SAvi Kivity 
607d36db35SAvi Kivity static void nop(void *junk)
617d36db35SAvi Kivity {
627d36db35SAvi Kivity }
637d36db35SAvi Kivity 
647d36db35SAvi Kivity static void ipi(void)
657d36db35SAvi Kivity {
667d36db35SAvi Kivity 	on_cpu(1, nop, 0);
677d36db35SAvi Kivity }
687d36db35SAvi Kivity 
697d36db35SAvi Kivity static void ipi_halt(void)
707d36db35SAvi Kivity {
717d36db35SAvi Kivity 	unsigned long long t;
727d36db35SAvi Kivity 
737d36db35SAvi Kivity 	on_cpu(1, nop, 0);
747d36db35SAvi Kivity 	t = rdtsc() + 2000;
757d36db35SAvi Kivity 	while (rdtsc() < t)
767d36db35SAvi Kivity 		;
777d36db35SAvi Kivity }
787d36db35SAvi Kivity 
797d36db35SAvi Kivity static void inl_pmtimer(void)
807d36db35SAvi Kivity {
817d36db35SAvi Kivity     inl(0xb008);
827d36db35SAvi Kivity }
837d36db35SAvi Kivity 
84*eda71b28SAvi Kivity static void ple_round_robin(void)
85*eda71b28SAvi Kivity {
86*eda71b28SAvi Kivity 	struct counter {
87*eda71b28SAvi Kivity 		volatile int n1;
88*eda71b28SAvi Kivity 		int n2;
89*eda71b28SAvi Kivity 	} __attribute__((aligned(64)));
90*eda71b28SAvi Kivity 	static struct counter counters[64] = { { -1, 0 } };
91*eda71b28SAvi Kivity 	int me = smp_id();
92*eda71b28SAvi Kivity 	int you;
93*eda71b28SAvi Kivity 	volatile struct counter *p = &counters[me];
94*eda71b28SAvi Kivity 
95*eda71b28SAvi Kivity 	while (p->n1 == p->n2)
96*eda71b28SAvi Kivity 		asm volatile ("pause");
97*eda71b28SAvi Kivity 
98*eda71b28SAvi Kivity 	p->n2 = p->n1;
99*eda71b28SAvi Kivity 	you = me + 1;
100*eda71b28SAvi Kivity 	if (you == nr_cpus)
101*eda71b28SAvi Kivity 		you = 0;
102*eda71b28SAvi Kivity 	++counters[you].n1;
103*eda71b28SAvi Kivity }
104*eda71b28SAvi Kivity 
1057d36db35SAvi Kivity static struct test {
1067d36db35SAvi Kivity 	void (*func)(void);
1077d36db35SAvi Kivity 	const char *name;
1087d36db35SAvi Kivity 	int (*valid)(void);
1097d36db35SAvi Kivity 	int parallel;
1107d36db35SAvi Kivity } tests[] = {
111850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
1127d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
1135ada505aSJason Wang #ifdef __x86_64__
1147d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
1157d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
1165ada505aSJason Wang #endif
1177d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
1187d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
1197d36db35SAvi Kivity 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
120*eda71b28SAvi Kivity 	{ ple_round_robin, "ple-round-robin", .parallel = 1 },
1217d36db35SAvi Kivity };
1227d36db35SAvi Kivity 
1237d36db35SAvi Kivity unsigned iterations;
1247d36db35SAvi Kivity volatile int nr_cpus_done;
1257d36db35SAvi Kivity 
1267d36db35SAvi Kivity static void run_test(void *_func)
1277d36db35SAvi Kivity {
1287d36db35SAvi Kivity     int i;
1297d36db35SAvi Kivity     void (*func)(void) = _func;
1307d36db35SAvi Kivity 
1317d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
1327d36db35SAvi Kivity         func();
1337d36db35SAvi Kivity 
1347d36db35SAvi Kivity     nr_cpus_done++;
1357d36db35SAvi Kivity }
1367d36db35SAvi Kivity 
1377d36db35SAvi Kivity static void do_test(struct test *test)
1387d36db35SAvi Kivity {
1397d36db35SAvi Kivity 	int i;
1407d36db35SAvi Kivity 	unsigned long long t1, t2;
1417d36db35SAvi Kivity         void (*func)(void) = test->func;
1427d36db35SAvi Kivity 
1437d36db35SAvi Kivity         iterations = 32;
1447d36db35SAvi Kivity 
1457d36db35SAvi Kivity         if (test->valid && !test->valid()) {
1467d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
1477d36db35SAvi Kivity 		return;
1487d36db35SAvi Kivity 	}
1497d36db35SAvi Kivity 
1507d36db35SAvi Kivity 	do {
1517d36db35SAvi Kivity 		iterations *= 2;
1527d36db35SAvi Kivity 		t1 = rdtsc();
1537d36db35SAvi Kivity 
1547d36db35SAvi Kivity 		if (!test->parallel) {
1557d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
1567d36db35SAvi Kivity 				func();
1577d36db35SAvi Kivity 		} else {
1587d36db35SAvi Kivity 			nr_cpus_done = 0;
1597d36db35SAvi Kivity 			for (i = cpu_count(); i > 0; i--)
1607d36db35SAvi Kivity 				on_cpu_async(i-1, run_test, func);
1617d36db35SAvi Kivity 			while (nr_cpus_done < cpu_count())
1627d36db35SAvi Kivity 				;
1637d36db35SAvi Kivity 		}
1647d36db35SAvi Kivity 		t2 = rdtsc();
1657d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
1667d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
1677d36db35SAvi Kivity }
1687d36db35SAvi Kivity 
1697d36db35SAvi Kivity static void enable_nx(void *junk)
1707d36db35SAvi Kivity {
171e46b32aaSAvi Kivity 	if (cpuid(0x80000001).d & (1 << 20))
1727d36db35SAvi Kivity 		wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
1737d36db35SAvi Kivity }
1747d36db35SAvi Kivity 
1750b267183SAvi Kivity bool test_wanted(struct test *test, char *wanted[], int nwanted)
1760b267183SAvi Kivity {
1770b267183SAvi Kivity 	int i;
1780b267183SAvi Kivity 
1790b267183SAvi Kivity 	if (!nwanted)
1800b267183SAvi Kivity 		return true;
1810b267183SAvi Kivity 
1820b267183SAvi Kivity 	for (i = 0; i < nwanted; ++i)
1830b267183SAvi Kivity 		if (strcmp(wanted[i], test->name) == 0)
1840b267183SAvi Kivity 			return true;
1850b267183SAvi Kivity 
1860b267183SAvi Kivity 	return false;
1870b267183SAvi Kivity }
1880b267183SAvi Kivity 
1890b267183SAvi Kivity int main(int ac, char **av)
1907d36db35SAvi Kivity {
1917d36db35SAvi Kivity 	int i;
1927d36db35SAvi Kivity 
1937d36db35SAvi Kivity 	smp_init();
194*eda71b28SAvi Kivity 	nr_cpus = cpu_count();
1957d36db35SAvi Kivity 
1967d36db35SAvi Kivity 	for (i = cpu_count(); i > 0; i--)
1977d36db35SAvi Kivity 		on_cpu(i-1, enable_nx, 0);
1987d36db35SAvi Kivity 
1997d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
2000b267183SAvi Kivity 		if (test_wanted(&tests[i], av + 1, ac - 1))
2017d36db35SAvi Kivity 			do_test(&tests[i]);
2027d36db35SAvi Kivity 
2037d36db35SAvi Kivity 	return 0;
2047d36db35SAvi Kivity }
205