xref: /kvm-unit-tests/x86/vmexit.c (revision 5ada505acb000f74fb6bfddb485767b1c5f12858)
17d36db35SAvi Kivity 
27d36db35SAvi Kivity #include "libcflat.h"
37d36db35SAvi Kivity #include "smp.h"
4850479e3SJason Wang #include "processor.h"
57d36db35SAvi Kivity 
67d36db35SAvi Kivity static inline unsigned long long rdtsc()
77d36db35SAvi Kivity {
87d36db35SAvi Kivity 	long long r;
97d36db35SAvi Kivity 
107d36db35SAvi Kivity #ifdef __x86_64__
117d36db35SAvi Kivity 	unsigned a, d;
127d36db35SAvi Kivity 
137d36db35SAvi Kivity 	asm volatile ("rdtsc" : "=a"(a), "=d"(d));
147d36db35SAvi Kivity 	r = a | ((long long)d << 32);
157d36db35SAvi Kivity #else
167d36db35SAvi Kivity 	asm volatile ("rdtsc" : "=A"(r));
177d36db35SAvi Kivity #endif
187d36db35SAvi Kivity 	return r;
197d36db35SAvi Kivity }
207d36db35SAvi Kivity 
217d36db35SAvi Kivity static unsigned int inl(unsigned short port)
227d36db35SAvi Kivity {
237d36db35SAvi Kivity     unsigned int val;
247d36db35SAvi Kivity     asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
257d36db35SAvi Kivity     return val;
267d36db35SAvi Kivity }
277d36db35SAvi Kivity 
287d36db35SAvi Kivity #define GOAL (1ull << 30)
297d36db35SAvi 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 
497d36db35SAvi Kivity #define MSR_EFER 0xc0000080
507d36db35SAvi Kivity #define EFER_NX_MASK            (1ull << 11)
517d36db35SAvi Kivity 
52*5ada505aSJason Wang #ifdef __x86_64__
537d36db35SAvi Kivity static void mov_from_cr8(void)
547d36db35SAvi Kivity {
557d36db35SAvi Kivity 	unsigned long cr8;
567d36db35SAvi Kivity 
577d36db35SAvi Kivity 	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
587d36db35SAvi Kivity }
597d36db35SAvi Kivity 
607d36db35SAvi Kivity static void mov_to_cr8(void)
617d36db35SAvi Kivity {
627d36db35SAvi Kivity 	unsigned long cr8 = 0;
637d36db35SAvi Kivity 
647d36db35SAvi Kivity 	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
657d36db35SAvi Kivity }
66*5ada505aSJason Wang #endif
677d36db35SAvi Kivity 
687d36db35SAvi Kivity static int is_smp(void)
697d36db35SAvi Kivity {
707d36db35SAvi Kivity 	return cpu_count() > 1;
717d36db35SAvi Kivity }
727d36db35SAvi Kivity 
737d36db35SAvi Kivity static void nop(void *junk)
747d36db35SAvi Kivity {
757d36db35SAvi Kivity }
767d36db35SAvi Kivity 
777d36db35SAvi Kivity static void ipi(void)
787d36db35SAvi Kivity {
797d36db35SAvi Kivity 	on_cpu(1, nop, 0);
807d36db35SAvi Kivity }
817d36db35SAvi Kivity 
827d36db35SAvi Kivity static void ipi_halt(void)
837d36db35SAvi Kivity {
847d36db35SAvi Kivity 	unsigned long long t;
857d36db35SAvi Kivity 
867d36db35SAvi Kivity 	on_cpu(1, nop, 0);
877d36db35SAvi Kivity 	t = rdtsc() + 2000;
887d36db35SAvi Kivity 	while (rdtsc() < t)
897d36db35SAvi Kivity 		;
907d36db35SAvi Kivity }
917d36db35SAvi Kivity 
927d36db35SAvi Kivity static void inl_pmtimer(void)
937d36db35SAvi Kivity {
947d36db35SAvi Kivity     inl(0xb008);
957d36db35SAvi Kivity }
967d36db35SAvi Kivity 
977d36db35SAvi Kivity static struct test {
987d36db35SAvi Kivity 	void (*func)(void);
997d36db35SAvi Kivity 	const char *name;
1007d36db35SAvi Kivity 	int (*valid)(void);
1017d36db35SAvi Kivity 	int parallel;
1027d36db35SAvi Kivity } tests[] = {
103850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
1047d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
105*5ada505aSJason Wang #ifdef __x86_64__
1067d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
1077d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
108*5ada505aSJason Wang #endif
1097d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
1107d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
1117d36db35SAvi Kivity 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
1127d36db35SAvi Kivity };
1137d36db35SAvi Kivity 
1147d36db35SAvi Kivity unsigned iterations;
1157d36db35SAvi Kivity volatile int nr_cpus_done;
1167d36db35SAvi Kivity 
1177d36db35SAvi Kivity static void run_test(void *_func)
1187d36db35SAvi Kivity {
1197d36db35SAvi Kivity     int i;
1207d36db35SAvi Kivity     void (*func)(void) = _func;
1217d36db35SAvi Kivity 
1227d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
1237d36db35SAvi Kivity         func();
1247d36db35SAvi Kivity 
1257d36db35SAvi Kivity     nr_cpus_done++;
1267d36db35SAvi Kivity }
1277d36db35SAvi Kivity 
1287d36db35SAvi Kivity static void do_test(struct test *test)
1297d36db35SAvi Kivity {
1307d36db35SAvi Kivity 	int i;
1317d36db35SAvi Kivity 	unsigned long long t1, t2;
1327d36db35SAvi Kivity         void (*func)(void) = test->func;
1337d36db35SAvi Kivity 
1347d36db35SAvi Kivity         iterations = 32;
1357d36db35SAvi Kivity 
1367d36db35SAvi Kivity         if (test->valid && !test->valid()) {
1377d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
1387d36db35SAvi Kivity 		return;
1397d36db35SAvi Kivity 	}
1407d36db35SAvi Kivity 
1417d36db35SAvi Kivity 	do {
1427d36db35SAvi Kivity 		iterations *= 2;
1437d36db35SAvi Kivity 		t1 = rdtsc();
1447d36db35SAvi Kivity 
1457d36db35SAvi Kivity 		if (!test->parallel) {
1467d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
1477d36db35SAvi Kivity 				func();
1487d36db35SAvi Kivity 		} else {
1497d36db35SAvi Kivity 			nr_cpus_done = 0;
1507d36db35SAvi Kivity 			for (i = cpu_count(); i > 0; i--)
1517d36db35SAvi Kivity 				on_cpu_async(i-1, run_test, func);
1527d36db35SAvi Kivity 			while (nr_cpus_done < cpu_count())
1537d36db35SAvi Kivity 				;
1547d36db35SAvi Kivity 		}
1557d36db35SAvi Kivity 		t2 = rdtsc();
1567d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
1577d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
1587d36db35SAvi Kivity }
1597d36db35SAvi Kivity 
1607d36db35SAvi Kivity static void enable_nx(void *junk)
1617d36db35SAvi Kivity {
1627d36db35SAvi Kivity 	wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
1637d36db35SAvi Kivity }
1647d36db35SAvi Kivity 
1657d36db35SAvi Kivity int main(void)
1667d36db35SAvi Kivity {
1677d36db35SAvi Kivity 	int i;
1687d36db35SAvi Kivity 
1697d36db35SAvi Kivity 	smp_init();
1707d36db35SAvi Kivity 
1717d36db35SAvi Kivity 	for (i = cpu_count(); i > 0; i--)
1727d36db35SAvi Kivity 		on_cpu(i-1, enable_nx, 0);
1737d36db35SAvi Kivity 
1747d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
1757d36db35SAvi Kivity 		do_test(&tests[i]);
1767d36db35SAvi Kivity 
1777d36db35SAvi Kivity 	return 0;
1787d36db35SAvi Kivity }
179