xref: /kvm-unit-tests/x86/vmexit.c (revision 850479e34fc448ede1909b24a28c58bd68b565c2)
17d36db35SAvi Kivity 
27d36db35SAvi Kivity #include "libcflat.h"
37d36db35SAvi Kivity #include "smp.h"
4*850479e3SJason 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 
36*850479e3SJason 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 
527d36db35SAvi Kivity static void mov_from_cr8(void)
537d36db35SAvi Kivity {
547d36db35SAvi Kivity 	unsigned long cr8;
557d36db35SAvi Kivity 
567d36db35SAvi Kivity 	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
577d36db35SAvi Kivity }
587d36db35SAvi Kivity 
597d36db35SAvi Kivity static void mov_to_cr8(void)
607d36db35SAvi Kivity {
617d36db35SAvi Kivity 	unsigned long cr8 = 0;
627d36db35SAvi Kivity 
637d36db35SAvi Kivity 	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
647d36db35SAvi Kivity }
657d36db35SAvi Kivity 
667d36db35SAvi Kivity static int is_smp(void)
677d36db35SAvi Kivity {
687d36db35SAvi Kivity 	return cpu_count() > 1;
697d36db35SAvi Kivity }
707d36db35SAvi Kivity 
717d36db35SAvi Kivity static void nop(void *junk)
727d36db35SAvi Kivity {
737d36db35SAvi Kivity }
747d36db35SAvi Kivity 
757d36db35SAvi Kivity static void ipi(void)
767d36db35SAvi Kivity {
777d36db35SAvi Kivity 	on_cpu(1, nop, 0);
787d36db35SAvi Kivity }
797d36db35SAvi Kivity 
807d36db35SAvi Kivity static void ipi_halt(void)
817d36db35SAvi Kivity {
827d36db35SAvi Kivity 	unsigned long long t;
837d36db35SAvi Kivity 
847d36db35SAvi Kivity 	on_cpu(1, nop, 0);
857d36db35SAvi Kivity 	t = rdtsc() + 2000;
867d36db35SAvi Kivity 	while (rdtsc() < t)
877d36db35SAvi Kivity 		;
887d36db35SAvi Kivity }
897d36db35SAvi Kivity 
907d36db35SAvi Kivity static void inl_pmtimer(void)
917d36db35SAvi Kivity {
927d36db35SAvi Kivity     inl(0xb008);
937d36db35SAvi Kivity }
947d36db35SAvi Kivity 
957d36db35SAvi Kivity static struct test {
967d36db35SAvi Kivity 	void (*func)(void);
977d36db35SAvi Kivity 	const char *name;
987d36db35SAvi Kivity 	int (*valid)(void);
997d36db35SAvi Kivity 	int parallel;
1007d36db35SAvi Kivity } tests[] = {
101*850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
1027d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
1037d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
1047d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
1057d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
1067d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
1077d36db35SAvi Kivity 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
1087d36db35SAvi Kivity };
1097d36db35SAvi Kivity 
1107d36db35SAvi Kivity unsigned iterations;
1117d36db35SAvi Kivity volatile int nr_cpus_done;
1127d36db35SAvi Kivity 
1137d36db35SAvi Kivity static void run_test(void *_func)
1147d36db35SAvi Kivity {
1157d36db35SAvi Kivity     int i;
1167d36db35SAvi Kivity     void (*func)(void) = _func;
1177d36db35SAvi Kivity 
1187d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
1197d36db35SAvi Kivity         func();
1207d36db35SAvi Kivity 
1217d36db35SAvi Kivity     nr_cpus_done++;
1227d36db35SAvi Kivity }
1237d36db35SAvi Kivity 
1247d36db35SAvi Kivity static void do_test(struct test *test)
1257d36db35SAvi Kivity {
1267d36db35SAvi Kivity 	int i;
1277d36db35SAvi Kivity 	unsigned long long t1, t2;
1287d36db35SAvi Kivity         void (*func)(void) = test->func;
1297d36db35SAvi Kivity 
1307d36db35SAvi Kivity         iterations = 32;
1317d36db35SAvi Kivity 
1327d36db35SAvi Kivity         if (test->valid && !test->valid()) {
1337d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
1347d36db35SAvi Kivity 		return;
1357d36db35SAvi Kivity 	}
1367d36db35SAvi Kivity 
1377d36db35SAvi Kivity 	do {
1387d36db35SAvi Kivity 		iterations *= 2;
1397d36db35SAvi Kivity 		t1 = rdtsc();
1407d36db35SAvi Kivity 
1417d36db35SAvi Kivity 		if (!test->parallel) {
1427d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
1437d36db35SAvi Kivity 				func();
1447d36db35SAvi Kivity 		} else {
1457d36db35SAvi Kivity 			nr_cpus_done = 0;
1467d36db35SAvi Kivity 			for (i = cpu_count(); i > 0; i--)
1477d36db35SAvi Kivity 				on_cpu_async(i-1, run_test, func);
1487d36db35SAvi Kivity 			while (nr_cpus_done < cpu_count())
1497d36db35SAvi Kivity 				;
1507d36db35SAvi Kivity 		}
1517d36db35SAvi Kivity 		t2 = rdtsc();
1527d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
1537d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
1547d36db35SAvi Kivity }
1557d36db35SAvi Kivity 
1567d36db35SAvi Kivity static void enable_nx(void *junk)
1577d36db35SAvi Kivity {
1587d36db35SAvi Kivity 	wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
1597d36db35SAvi Kivity }
1607d36db35SAvi Kivity 
1617d36db35SAvi Kivity int main(void)
1627d36db35SAvi Kivity {
1637d36db35SAvi Kivity 	int i;
1647d36db35SAvi Kivity 
1657d36db35SAvi Kivity 	smp_init();
1667d36db35SAvi Kivity 
1677d36db35SAvi Kivity 	for (i = cpu_count(); i > 0; i--)
1687d36db35SAvi Kivity 		on_cpu(i-1, enable_nx, 0);
1697d36db35SAvi Kivity 
1707d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
1717d36db35SAvi Kivity 		do_test(&tests[i]);
1727d36db35SAvi Kivity 
1737d36db35SAvi Kivity 	return 0;
1747d36db35SAvi Kivity }
175