xref: /kvm-unit-tests/x86/vmexit.c (revision e46b32aa8f50806bf21ab90016a25d6cb4046d7a)
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 
157d36db35SAvi Kivity #ifdef __x86_64__
167d36db35SAvi Kivity #  define R "r"
177d36db35SAvi Kivity #else
187d36db35SAvi Kivity #  define R "e"
197d36db35SAvi Kivity #endif
207d36db35SAvi Kivity 
21850479e3SJason Wang static void cpuid_test(void)
227d36db35SAvi Kivity {
237d36db35SAvi Kivity 	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
247d36db35SAvi Kivity 		      : : : "eax", "ecx", "edx");
257d36db35SAvi Kivity }
267d36db35SAvi Kivity 
277d36db35SAvi Kivity static void vmcall(void)
287d36db35SAvi Kivity {
297d36db35SAvi Kivity 	unsigned long a = 0, b, c, d;
307d36db35SAvi Kivity 
317d36db35SAvi Kivity 	asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
327d36db35SAvi Kivity }
337d36db35SAvi Kivity 
347d36db35SAvi Kivity #define MSR_EFER 0xc0000080
357d36db35SAvi Kivity #define EFER_NX_MASK            (1ull << 11)
367d36db35SAvi Kivity 
375ada505aSJason Wang #ifdef __x86_64__
387d36db35SAvi Kivity static void mov_from_cr8(void)
397d36db35SAvi Kivity {
407d36db35SAvi Kivity 	unsigned long cr8;
417d36db35SAvi Kivity 
427d36db35SAvi Kivity 	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
437d36db35SAvi Kivity }
447d36db35SAvi Kivity 
457d36db35SAvi Kivity static void mov_to_cr8(void)
467d36db35SAvi Kivity {
477d36db35SAvi Kivity 	unsigned long cr8 = 0;
487d36db35SAvi Kivity 
497d36db35SAvi Kivity 	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
507d36db35SAvi Kivity }
515ada505aSJason Wang #endif
527d36db35SAvi Kivity 
537d36db35SAvi Kivity static int is_smp(void)
547d36db35SAvi Kivity {
557d36db35SAvi Kivity 	return cpu_count() > 1;
567d36db35SAvi Kivity }
577d36db35SAvi Kivity 
587d36db35SAvi Kivity static void nop(void *junk)
597d36db35SAvi Kivity {
607d36db35SAvi Kivity }
617d36db35SAvi Kivity 
627d36db35SAvi Kivity static void ipi(void)
637d36db35SAvi Kivity {
647d36db35SAvi Kivity 	on_cpu(1, nop, 0);
657d36db35SAvi Kivity }
667d36db35SAvi Kivity 
677d36db35SAvi Kivity static void ipi_halt(void)
687d36db35SAvi Kivity {
697d36db35SAvi Kivity 	unsigned long long t;
707d36db35SAvi Kivity 
717d36db35SAvi Kivity 	on_cpu(1, nop, 0);
727d36db35SAvi Kivity 	t = rdtsc() + 2000;
737d36db35SAvi Kivity 	while (rdtsc() < t)
747d36db35SAvi Kivity 		;
757d36db35SAvi Kivity }
767d36db35SAvi Kivity 
777d36db35SAvi Kivity static void inl_pmtimer(void)
787d36db35SAvi Kivity {
797d36db35SAvi Kivity     inl(0xb008);
807d36db35SAvi Kivity }
817d36db35SAvi Kivity 
827d36db35SAvi Kivity static struct test {
837d36db35SAvi Kivity 	void (*func)(void);
847d36db35SAvi Kivity 	const char *name;
857d36db35SAvi Kivity 	int (*valid)(void);
867d36db35SAvi Kivity 	int parallel;
877d36db35SAvi Kivity } tests[] = {
88850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
897d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
905ada505aSJason Wang #ifdef __x86_64__
917d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
927d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
935ada505aSJason Wang #endif
947d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
957d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
967d36db35SAvi Kivity 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
977d36db35SAvi Kivity };
987d36db35SAvi Kivity 
997d36db35SAvi Kivity unsigned iterations;
1007d36db35SAvi Kivity volatile int nr_cpus_done;
1017d36db35SAvi Kivity 
1027d36db35SAvi Kivity static void run_test(void *_func)
1037d36db35SAvi Kivity {
1047d36db35SAvi Kivity     int i;
1057d36db35SAvi Kivity     void (*func)(void) = _func;
1067d36db35SAvi Kivity 
1077d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
1087d36db35SAvi Kivity         func();
1097d36db35SAvi Kivity 
1107d36db35SAvi Kivity     nr_cpus_done++;
1117d36db35SAvi Kivity }
1127d36db35SAvi Kivity 
1137d36db35SAvi Kivity static void do_test(struct test *test)
1147d36db35SAvi Kivity {
1157d36db35SAvi Kivity 	int i;
1167d36db35SAvi Kivity 	unsigned long long t1, t2;
1177d36db35SAvi Kivity         void (*func)(void) = test->func;
1187d36db35SAvi Kivity 
1197d36db35SAvi Kivity         iterations = 32;
1207d36db35SAvi Kivity 
1217d36db35SAvi Kivity         if (test->valid && !test->valid()) {
1227d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
1237d36db35SAvi Kivity 		return;
1247d36db35SAvi Kivity 	}
1257d36db35SAvi Kivity 
1267d36db35SAvi Kivity 	do {
1277d36db35SAvi Kivity 		iterations *= 2;
1287d36db35SAvi Kivity 		t1 = rdtsc();
1297d36db35SAvi Kivity 
1307d36db35SAvi Kivity 		if (!test->parallel) {
1317d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
1327d36db35SAvi Kivity 				func();
1337d36db35SAvi Kivity 		} else {
1347d36db35SAvi Kivity 			nr_cpus_done = 0;
1357d36db35SAvi Kivity 			for (i = cpu_count(); i > 0; i--)
1367d36db35SAvi Kivity 				on_cpu_async(i-1, run_test, func);
1377d36db35SAvi Kivity 			while (nr_cpus_done < cpu_count())
1387d36db35SAvi Kivity 				;
1397d36db35SAvi Kivity 		}
1407d36db35SAvi Kivity 		t2 = rdtsc();
1417d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
1427d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
1437d36db35SAvi Kivity }
1447d36db35SAvi Kivity 
1457d36db35SAvi Kivity static void enable_nx(void *junk)
1467d36db35SAvi Kivity {
147*e46b32aaSAvi Kivity 	if (cpuid(0x80000001).d & (1 << 20))
1487d36db35SAvi Kivity 		wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
1497d36db35SAvi Kivity }
1507d36db35SAvi Kivity 
1517d36db35SAvi Kivity int main(void)
1527d36db35SAvi Kivity {
1537d36db35SAvi Kivity 	int i;
1547d36db35SAvi Kivity 
1557d36db35SAvi Kivity 	smp_init();
1567d36db35SAvi Kivity 
1577d36db35SAvi Kivity 	for (i = cpu_count(); i > 0; i--)
1587d36db35SAvi Kivity 		on_cpu(i-1, enable_nx, 0);
1597d36db35SAvi Kivity 
1607d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
1617d36db35SAvi Kivity 		do_test(&tests[i]);
1627d36db35SAvi Kivity 
1637d36db35SAvi Kivity 	return 0;
1647d36db35SAvi Kivity }
165