xref: /kvm-unit-tests/x86/vmexit.c (revision 8a5444098aa1735670d9e4ff2673d73b0c71fd61)
17d36db35SAvi Kivity #include "libcflat.h"
27d36db35SAvi Kivity #include "smp.h"
3850479e3SJason Wang #include "processor.h"
47d641cc5SAvi Kivity #include "atomic.h"
55292dbf7SMichael S. Tsirkin #include "x86/vm.h"
65292dbf7SMichael S. Tsirkin #include "x86/desc.h"
75292dbf7SMichael S. Tsirkin #include "x86/pci.h"
87d36db35SAvi Kivity 
95292dbf7SMichael S. Tsirkin struct test {
105292dbf7SMichael S. Tsirkin 	void (*func)(void);
115292dbf7SMichael S. Tsirkin 	const char *name;
125292dbf7SMichael S. Tsirkin 	int (*valid)(void);
135292dbf7SMichael S. Tsirkin 	int parallel;
145292dbf7SMichael S. Tsirkin 	bool (*next)(struct test *);
155292dbf7SMichael S. Tsirkin };
165292dbf7SMichael S. Tsirkin 
175292dbf7SMichael S. Tsirkin static void outb(unsigned short port, unsigned val)
1800bfecaaSPaolo Bonzini {
195292dbf7SMichael S. Tsirkin     asm volatile("outb %b0, %w1" : : "a"(val), "Nd"(port));
205292dbf7SMichael S. Tsirkin }
215292dbf7SMichael S. Tsirkin 
225292dbf7SMichael S. Tsirkin static void outw(unsigned short port, unsigned val)
235292dbf7SMichael S. Tsirkin {
245292dbf7SMichael S. Tsirkin     asm volatile("outw %w0, %w1" : : "a"(val), "Nd"(port));
255292dbf7SMichael S. Tsirkin }
265292dbf7SMichael S. Tsirkin 
275292dbf7SMichael S. Tsirkin static void outl(unsigned short port, unsigned val)
285292dbf7SMichael S. Tsirkin {
290b9e64c4SGleb Natapov     asm volatile("outl %0, %w1" : : "a"(val), "Nd"(port));
3000bfecaaSPaolo Bonzini }
3100bfecaaSPaolo Bonzini 
3200bfecaaSPaolo Bonzini static unsigned int inb(unsigned short port)
3300bfecaaSPaolo Bonzini {
3400bfecaaSPaolo Bonzini     unsigned int val;
3500bfecaaSPaolo Bonzini     asm volatile("xorl %0, %0; inb %w1, %b0" : "=a"(val) : "Nd"(port));
3600bfecaaSPaolo Bonzini     return val;
3700bfecaaSPaolo Bonzini }
3800bfecaaSPaolo Bonzini 
397d36db35SAvi Kivity static unsigned int inl(unsigned short port)
407d36db35SAvi Kivity {
417d36db35SAvi Kivity     unsigned int val;
427d36db35SAvi Kivity     asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port));
437d36db35SAvi Kivity     return val;
447d36db35SAvi Kivity }
457d36db35SAvi Kivity 
467d36db35SAvi Kivity #define GOAL (1ull << 30)
477d36db35SAvi Kivity 
48eda71b28SAvi Kivity static int nr_cpus;
49eda71b28SAvi Kivity 
507d36db35SAvi Kivity #ifdef __x86_64__
517d36db35SAvi Kivity #  define R "r"
527d36db35SAvi Kivity #else
537d36db35SAvi Kivity #  define R "e"
547d36db35SAvi Kivity #endif
557d36db35SAvi Kivity 
56850479e3SJason Wang static void cpuid_test(void)
577d36db35SAvi Kivity {
587d36db35SAvi Kivity 	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
597d36db35SAvi Kivity 		      : : : "eax", "ecx", "edx");
607d36db35SAvi Kivity }
617d36db35SAvi Kivity 
627d36db35SAvi Kivity static void vmcall(void)
637d36db35SAvi Kivity {
647d36db35SAvi Kivity 	unsigned long a = 0, b, c, d;
657d36db35SAvi Kivity 
667d36db35SAvi Kivity 	asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
677d36db35SAvi Kivity }
687d36db35SAvi Kivity 
695fecf5d8SWill Auld #define MSR_TSC_ADJUST 0x3b
707d36db35SAvi Kivity #define MSR_EFER 0xc0000080
717d36db35SAvi Kivity #define EFER_NX_MASK            (1ull << 11)
727d36db35SAvi Kivity 
735ada505aSJason Wang #ifdef __x86_64__
747d36db35SAvi Kivity static void mov_from_cr8(void)
757d36db35SAvi Kivity {
767d36db35SAvi Kivity 	unsigned long cr8;
777d36db35SAvi Kivity 
787d36db35SAvi Kivity 	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
797d36db35SAvi Kivity }
807d36db35SAvi Kivity 
817d36db35SAvi Kivity static void mov_to_cr8(void)
827d36db35SAvi Kivity {
837d36db35SAvi Kivity 	unsigned long cr8 = 0;
847d36db35SAvi Kivity 
857d36db35SAvi Kivity 	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
867d36db35SAvi Kivity }
875ada505aSJason Wang #endif
887d36db35SAvi Kivity 
897d36db35SAvi Kivity static int is_smp(void)
907d36db35SAvi Kivity {
917d36db35SAvi Kivity 	return cpu_count() > 1;
927d36db35SAvi Kivity }
937d36db35SAvi Kivity 
947d36db35SAvi Kivity static void nop(void *junk)
957d36db35SAvi Kivity {
967d36db35SAvi Kivity }
977d36db35SAvi Kivity 
987d36db35SAvi Kivity static void ipi(void)
997d36db35SAvi Kivity {
1007d36db35SAvi Kivity 	on_cpu(1, nop, 0);
1017d36db35SAvi Kivity }
1027d36db35SAvi Kivity 
1037d36db35SAvi Kivity static void ipi_halt(void)
1047d36db35SAvi Kivity {
1057d36db35SAvi Kivity 	unsigned long long t;
1067d36db35SAvi Kivity 
1077d36db35SAvi Kivity 	on_cpu(1, nop, 0);
1087d36db35SAvi Kivity 	t = rdtsc() + 2000;
1097d36db35SAvi Kivity 	while (rdtsc() < t)
1107d36db35SAvi Kivity 		;
1117d36db35SAvi Kivity }
1127d36db35SAvi Kivity 
1137d36db35SAvi Kivity static void inl_pmtimer(void)
1147d36db35SAvi Kivity {
1157d36db35SAvi Kivity     inl(0xb008);
1167d36db35SAvi Kivity }
1177d36db35SAvi Kivity 
11800bfecaaSPaolo Bonzini static void inl_nop_qemu(void)
11900bfecaaSPaolo Bonzini {
12000bfecaaSPaolo Bonzini     inl(0x1234);
12100bfecaaSPaolo Bonzini }
12200bfecaaSPaolo Bonzini 
12300bfecaaSPaolo Bonzini static void inl_nop_kernel(void)
12400bfecaaSPaolo Bonzini {
12500bfecaaSPaolo Bonzini     inb(0x4d0);
12600bfecaaSPaolo Bonzini }
12700bfecaaSPaolo Bonzini 
12800bfecaaSPaolo Bonzini static void outl_elcr_kernel(void)
12900bfecaaSPaolo Bonzini {
13000bfecaaSPaolo Bonzini     outb(0x4d0, 0);
13100bfecaaSPaolo Bonzini }
13200bfecaaSPaolo Bonzini 
133*8a544409SPaolo Bonzini static void mov_dr(void)
134*8a544409SPaolo Bonzini {
135*8a544409SPaolo Bonzini     asm volatile("mov %0, %%dr7" : : "r" (0x400L));
136*8a544409SPaolo Bonzini }
137*8a544409SPaolo Bonzini 
138eda71b28SAvi Kivity static void ple_round_robin(void)
139eda71b28SAvi Kivity {
140eda71b28SAvi Kivity 	struct counter {
141eda71b28SAvi Kivity 		volatile int n1;
142eda71b28SAvi Kivity 		int n2;
143eda71b28SAvi Kivity 	} __attribute__((aligned(64)));
144eda71b28SAvi Kivity 	static struct counter counters[64] = { { -1, 0 } };
145eda71b28SAvi Kivity 	int me = smp_id();
146eda71b28SAvi Kivity 	int you;
147eda71b28SAvi Kivity 	volatile struct counter *p = &counters[me];
148eda71b28SAvi Kivity 
149eda71b28SAvi Kivity 	while (p->n1 == p->n2)
150eda71b28SAvi Kivity 		asm volatile ("pause");
151eda71b28SAvi Kivity 
152eda71b28SAvi Kivity 	p->n2 = p->n1;
153eda71b28SAvi Kivity 	you = me + 1;
154eda71b28SAvi Kivity 	if (you == nr_cpus)
155eda71b28SAvi Kivity 		you = 0;
156eda71b28SAvi Kivity 	++counters[you].n1;
157eda71b28SAvi Kivity }
158eda71b28SAvi Kivity 
1595fecf5d8SWill Auld static void rd_tsc_adjust_msr(void)
1605fecf5d8SWill Auld {
1615fecf5d8SWill Auld 	rdmsr(MSR_TSC_ADJUST);
1625fecf5d8SWill Auld }
1635fecf5d8SWill Auld 
1645fecf5d8SWill Auld static void wr_tsc_adjust_msr(void)
1655fecf5d8SWill Auld {
1665fecf5d8SWill Auld 	wrmsr(MSR_TSC_ADJUST, 0x0);
1675fecf5d8SWill Auld }
1685fecf5d8SWill Auld 
1695292dbf7SMichael S. Tsirkin struct pci_test_dev_hdr {
1705292dbf7SMichael S. Tsirkin     uint8_t test;
1715292dbf7SMichael S. Tsirkin     uint8_t width;
1725292dbf7SMichael S. Tsirkin     uint8_t pad0[2];
1735292dbf7SMichael S. Tsirkin     uint32_t offset;
1745292dbf7SMichael S. Tsirkin     uint32_t data;
1755292dbf7SMichael S. Tsirkin     uint32_t count;
1765292dbf7SMichael S. Tsirkin     uint8_t name[];
1775292dbf7SMichael S. Tsirkin };
1785292dbf7SMichael S. Tsirkin 
1795292dbf7SMichael S. Tsirkin static struct pci_test {
1805292dbf7SMichael S. Tsirkin 	unsigned iobar;
1815292dbf7SMichael S. Tsirkin 	unsigned ioport;
1825292dbf7SMichael S. Tsirkin 	volatile void *memaddr;
1835292dbf7SMichael S. Tsirkin 	volatile void *mem;
1845292dbf7SMichael S. Tsirkin 	int test_idx;
1855292dbf7SMichael S. Tsirkin 	uint32_t data;
1865292dbf7SMichael S. Tsirkin 	uint32_t offset;
1875292dbf7SMichael S. Tsirkin } pci_test = {
1885292dbf7SMichael S. Tsirkin 	.test_idx = -1
1895292dbf7SMichael S. Tsirkin };
1905292dbf7SMichael S. Tsirkin 
1915292dbf7SMichael S. Tsirkin static void pci_mem_testb(void)
1925292dbf7SMichael S. Tsirkin {
1935292dbf7SMichael S. Tsirkin 	*(volatile uint8_t *)pci_test.mem = pci_test.data;
1945292dbf7SMichael S. Tsirkin }
1955292dbf7SMichael S. Tsirkin 
1965292dbf7SMichael S. Tsirkin static void pci_mem_testw(void)
1975292dbf7SMichael S. Tsirkin {
1985292dbf7SMichael S. Tsirkin 	*(volatile uint16_t *)pci_test.mem = pci_test.data;
1995292dbf7SMichael S. Tsirkin }
2005292dbf7SMichael S. Tsirkin 
2015292dbf7SMichael S. Tsirkin static void pci_mem_testl(void)
2025292dbf7SMichael S. Tsirkin {
2035292dbf7SMichael S. Tsirkin 	*(volatile uint32_t *)pci_test.mem = pci_test.data;
2045292dbf7SMichael S. Tsirkin }
2055292dbf7SMichael S. Tsirkin 
2065292dbf7SMichael S. Tsirkin static void pci_io_testb(void)
2075292dbf7SMichael S. Tsirkin {
2085292dbf7SMichael S. Tsirkin 	outb(pci_test.ioport, pci_test.data);
2095292dbf7SMichael S. Tsirkin }
2105292dbf7SMichael S. Tsirkin 
2115292dbf7SMichael S. Tsirkin static void pci_io_testw(void)
2125292dbf7SMichael S. Tsirkin {
2135292dbf7SMichael S. Tsirkin 	outw(pci_test.ioport, pci_test.data);
2145292dbf7SMichael S. Tsirkin }
2155292dbf7SMichael S. Tsirkin 
2165292dbf7SMichael S. Tsirkin static void pci_io_testl(void)
2175292dbf7SMichael S. Tsirkin {
2185292dbf7SMichael S. Tsirkin 	outl(pci_test.ioport, pci_test.data);
2195292dbf7SMichael S. Tsirkin }
2205292dbf7SMichael S. Tsirkin 
2215292dbf7SMichael S. Tsirkin static uint8_t ioreadb(unsigned long addr, bool io)
2225292dbf7SMichael S. Tsirkin {
2235292dbf7SMichael S. Tsirkin 	if (io) {
2245292dbf7SMichael S. Tsirkin 		return inb(addr);
2255292dbf7SMichael S. Tsirkin 	} else {
2265292dbf7SMichael S. Tsirkin 		return *(volatile uint8_t *)addr;
2275292dbf7SMichael S. Tsirkin 	}
2285292dbf7SMichael S. Tsirkin }
2295292dbf7SMichael S. Tsirkin 
2305292dbf7SMichael S. Tsirkin static uint32_t ioreadl(unsigned long addr, bool io)
2315292dbf7SMichael S. Tsirkin {
2325292dbf7SMichael S. Tsirkin 	/* Note: assumes little endian */
2335292dbf7SMichael S. Tsirkin 	if (io) {
2345292dbf7SMichael S. Tsirkin 		return inl(addr);
2355292dbf7SMichael S. Tsirkin 	} else {
2365292dbf7SMichael S. Tsirkin 		return *(volatile uint32_t *)addr;
2375292dbf7SMichael S. Tsirkin 	}
2385292dbf7SMichael S. Tsirkin }
2395292dbf7SMichael S. Tsirkin 
2405292dbf7SMichael S. Tsirkin static void iowriteb(unsigned long addr, uint8_t data, bool io)
2415292dbf7SMichael S. Tsirkin {
2425292dbf7SMichael S. Tsirkin 	if (io) {
2435292dbf7SMichael S. Tsirkin 		outb(addr, data);
2445292dbf7SMichael S. Tsirkin 	} else {
2455292dbf7SMichael S. Tsirkin 		*(volatile uint8_t *)addr = data;
2465292dbf7SMichael S. Tsirkin 	}
2475292dbf7SMichael S. Tsirkin }
2485292dbf7SMichael S. Tsirkin 
2495292dbf7SMichael S. Tsirkin static bool pci_next(struct test *test, unsigned long addr, bool io)
2505292dbf7SMichael S. Tsirkin {
2515292dbf7SMichael S. Tsirkin 	int i;
2525292dbf7SMichael S. Tsirkin 	uint8_t width;
2535292dbf7SMichael S. Tsirkin 
2545292dbf7SMichael S. Tsirkin 	if (!pci_test.memaddr) {
2555292dbf7SMichael S. Tsirkin 		test->func = NULL;
2565292dbf7SMichael S. Tsirkin 		return true;
2575292dbf7SMichael S. Tsirkin 	}
2585292dbf7SMichael S. Tsirkin 	pci_test.test_idx++;
2595292dbf7SMichael S. Tsirkin 	iowriteb(addr + offsetof(struct pci_test_dev_hdr, test),
2605292dbf7SMichael S. Tsirkin 		 pci_test.test_idx, io);
2615292dbf7SMichael S. Tsirkin 	width = ioreadb(addr + offsetof(struct pci_test_dev_hdr, width),
2625292dbf7SMichael S. Tsirkin 			io);
2635292dbf7SMichael S. Tsirkin 	switch (width) {
2645292dbf7SMichael S. Tsirkin 		case 1:
2655292dbf7SMichael S. Tsirkin 			test->func = io ? pci_io_testb : pci_mem_testb;
2665292dbf7SMichael S. Tsirkin 			break;
2675292dbf7SMichael S. Tsirkin 		case 2:
2685292dbf7SMichael S. Tsirkin 			test->func = io ? pci_io_testw : pci_mem_testw;
2695292dbf7SMichael S. Tsirkin 			break;
2705292dbf7SMichael S. Tsirkin 		case 4:
2715292dbf7SMichael S. Tsirkin 			test->func = io ? pci_io_testl : pci_mem_testl;
2725292dbf7SMichael S. Tsirkin 			break;
2735292dbf7SMichael S. Tsirkin 		default:
2745292dbf7SMichael S. Tsirkin 			/* Reset index for purposes of the next test */
2755292dbf7SMichael S. Tsirkin 			pci_test.test_idx = -1;
2765292dbf7SMichael S. Tsirkin 			test->func = NULL;
2775292dbf7SMichael S. Tsirkin 			return false;
2785292dbf7SMichael S. Tsirkin 	}
2795292dbf7SMichael S. Tsirkin 	pci_test.data = ioreadl(addr + offsetof(struct pci_test_dev_hdr, data),
2805292dbf7SMichael S. Tsirkin 				io);
2815292dbf7SMichael S. Tsirkin 	pci_test.offset = ioreadl(addr + offsetof(struct pci_test_dev_hdr,
2825292dbf7SMichael S. Tsirkin 						  offset), io);
2835292dbf7SMichael S. Tsirkin 	for (i = 0; i < pci_test.offset; ++i) {
2845292dbf7SMichael S. Tsirkin 		char c = ioreadb(addr + offsetof(struct pci_test_dev_hdr,
2855292dbf7SMichael S. Tsirkin 						 name) + i, io);
2865292dbf7SMichael S. Tsirkin 		if (!c) {
2875292dbf7SMichael S. Tsirkin 			break;
2885292dbf7SMichael S. Tsirkin 		}
2895292dbf7SMichael S. Tsirkin 		printf("%c",c);
2905292dbf7SMichael S. Tsirkin 	}
2915292dbf7SMichael S. Tsirkin 	printf(":");
2925292dbf7SMichael S. Tsirkin 	return true;
2935292dbf7SMichael S. Tsirkin }
2945292dbf7SMichael S. Tsirkin 
2955292dbf7SMichael S. Tsirkin static bool pci_mem_next(struct test *test)
2965292dbf7SMichael S. Tsirkin {
2975292dbf7SMichael S. Tsirkin 	bool ret;
2985292dbf7SMichael S. Tsirkin 	ret = pci_next(test, ((unsigned long)pci_test.memaddr), false);
2995292dbf7SMichael S. Tsirkin 	if (ret) {
3005292dbf7SMichael S. Tsirkin 		pci_test.mem = pci_test.memaddr + pci_test.offset;
3015292dbf7SMichael S. Tsirkin 	}
3025292dbf7SMichael S. Tsirkin 	return ret;
3035292dbf7SMichael S. Tsirkin }
3045292dbf7SMichael S. Tsirkin 
3055292dbf7SMichael S. Tsirkin static bool pci_io_next(struct test *test)
3065292dbf7SMichael S. Tsirkin {
3075292dbf7SMichael S. Tsirkin 	bool ret;
3085292dbf7SMichael S. Tsirkin 	ret = pci_next(test, ((unsigned long)pci_test.iobar), true);
3095292dbf7SMichael S. Tsirkin 	if (ret) {
3105292dbf7SMichael S. Tsirkin 		pci_test.ioport = pci_test.iobar + pci_test.offset;
3115292dbf7SMichael S. Tsirkin 	}
3125292dbf7SMichael S. Tsirkin 	return ret;
3135292dbf7SMichael S. Tsirkin }
3145292dbf7SMichael S. Tsirkin 
3155292dbf7SMichael S. Tsirkin static struct test tests[] = {
316850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
3177d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
3185ada505aSJason Wang #ifdef __x86_64__
3197d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
3207d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
3215ada505aSJason Wang #endif
3227d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
32300bfecaaSPaolo Bonzini 	{ inl_nop_qemu, "inl_from_qemu", .parallel = 1 },
32400bfecaaSPaolo Bonzini 	{ inl_nop_kernel, "inl_from_kernel", .parallel = 1 },
32500bfecaaSPaolo Bonzini 	{ outl_elcr_kernel, "outl_to_kernel", .parallel = 1 },
326*8a544409SPaolo Bonzini 	{ mov_dr, "mov_dr", .parallel = 1 },
3277d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
3287d36db35SAvi Kivity 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
329eda71b28SAvi Kivity 	{ ple_round_robin, "ple-round-robin", .parallel = 1 },
3305fecf5d8SWill Auld 	{ wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 },
3315fecf5d8SWill Auld 	{ rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 },
3325292dbf7SMichael S. Tsirkin 	{ NULL, "pci-mem", .parallel = 0, .next = pci_mem_next },
3335292dbf7SMichael S. Tsirkin 	{ NULL, "pci-io", .parallel = 0, .next = pci_io_next },
3347d36db35SAvi Kivity };
3357d36db35SAvi Kivity 
3367d36db35SAvi Kivity unsigned iterations;
3377d641cc5SAvi Kivity static atomic_t nr_cpus_done;
3387d36db35SAvi Kivity 
3397d36db35SAvi Kivity static void run_test(void *_func)
3407d36db35SAvi Kivity {
3417d36db35SAvi Kivity     int i;
3427d36db35SAvi Kivity     void (*func)(void) = _func;
3437d36db35SAvi Kivity 
3447d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
3457d36db35SAvi Kivity         func();
3467d36db35SAvi Kivity 
3477d641cc5SAvi Kivity     atomic_inc(&nr_cpus_done);
3487d36db35SAvi Kivity }
3497d36db35SAvi Kivity 
3505292dbf7SMichael S. Tsirkin static bool do_test(struct test *test)
3517d36db35SAvi Kivity {
3527d36db35SAvi Kivity 	int i;
3537d36db35SAvi Kivity 	unsigned long long t1, t2;
3545292dbf7SMichael S. Tsirkin         void (*func)(void);
3557d36db35SAvi Kivity 
3567d36db35SAvi Kivity         iterations = 32;
3577d36db35SAvi Kivity 
3587d36db35SAvi Kivity         if (test->valid && !test->valid()) {
3597d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
3605292dbf7SMichael S. Tsirkin 		return false;
3615292dbf7SMichael S. Tsirkin 	}
3625292dbf7SMichael S. Tsirkin 
3635292dbf7SMichael S. Tsirkin 	if (test->next && !test->next(test)) {
3645292dbf7SMichael S. Tsirkin 		return false;
3655292dbf7SMichael S. Tsirkin 	}
3665292dbf7SMichael S. Tsirkin 
3675292dbf7SMichael S. Tsirkin 	func = test->func;
3685292dbf7SMichael S. Tsirkin         if (!func) {
3695292dbf7SMichael S. Tsirkin 		printf("%s (skipped)\n", test->name);
3705292dbf7SMichael S. Tsirkin 		return false;
3717d36db35SAvi Kivity 	}
3727d36db35SAvi Kivity 
3737d36db35SAvi Kivity 	do {
3747d36db35SAvi Kivity 		iterations *= 2;
3757d36db35SAvi Kivity 		t1 = rdtsc();
3767d36db35SAvi Kivity 
3777d36db35SAvi Kivity 		if (!test->parallel) {
3787d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
3797d36db35SAvi Kivity 				func();
3807d36db35SAvi Kivity 		} else {
3817d641cc5SAvi Kivity 			atomic_set(&nr_cpus_done, 0);
3827d36db35SAvi Kivity 			for (i = cpu_count(); i > 0; i--)
3837d36db35SAvi Kivity 				on_cpu_async(i-1, run_test, func);
3847d641cc5SAvi Kivity 			while (atomic_read(&nr_cpus_done) < cpu_count())
3857d36db35SAvi Kivity 				;
3867d36db35SAvi Kivity 		}
3877d36db35SAvi Kivity 		t2 = rdtsc();
3887d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
3897d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
3905292dbf7SMichael S. Tsirkin 	return test->next;
3917d36db35SAvi Kivity }
3927d36db35SAvi Kivity 
3937d36db35SAvi Kivity static void enable_nx(void *junk)
3947d36db35SAvi Kivity {
395e46b32aaSAvi Kivity 	if (cpuid(0x80000001).d & (1 << 20))
3967d36db35SAvi Kivity 		wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
3977d36db35SAvi Kivity }
3987d36db35SAvi Kivity 
3990b267183SAvi Kivity bool test_wanted(struct test *test, char *wanted[], int nwanted)
4000b267183SAvi Kivity {
4010b267183SAvi Kivity 	int i;
4020b267183SAvi Kivity 
4030b267183SAvi Kivity 	if (!nwanted)
4040b267183SAvi Kivity 		return true;
4050b267183SAvi Kivity 
4060b267183SAvi Kivity 	for (i = 0; i < nwanted; ++i)
4070b267183SAvi Kivity 		if (strcmp(wanted[i], test->name) == 0)
4080b267183SAvi Kivity 			return true;
4090b267183SAvi Kivity 
4100b267183SAvi Kivity 	return false;
4110b267183SAvi Kivity }
4120b267183SAvi Kivity 
4130b267183SAvi Kivity int main(int ac, char **av)
4147d36db35SAvi Kivity {
4157d36db35SAvi Kivity 	int i;
4165292dbf7SMichael S. Tsirkin 	unsigned long membar = 0, base, offset;
4175292dbf7SMichael S. Tsirkin 	void *m;
4185292dbf7SMichael S. Tsirkin 	pcidevaddr_t pcidev;
4197d36db35SAvi Kivity 
4207d36db35SAvi Kivity 	smp_init();
4215292dbf7SMichael S. Tsirkin 	setup_vm();
422eda71b28SAvi Kivity 	nr_cpus = cpu_count();
4237d36db35SAvi Kivity 
4247d36db35SAvi Kivity 	for (i = cpu_count(); i > 0; i--)
4257d36db35SAvi Kivity 		on_cpu(i-1, enable_nx, 0);
4267d36db35SAvi Kivity 
4275292dbf7SMichael S. Tsirkin 	pcidev = pci_find_dev(0x1b36, 0x0005);
4285292dbf7SMichael S. Tsirkin 	if (pcidev) {
4295292dbf7SMichael S. Tsirkin 		for (i = 0; i < 2; i++) {
4305292dbf7SMichael S. Tsirkin 			if (!pci_bar_is_valid(pcidev, i)) {
4315292dbf7SMichael S. Tsirkin 				continue;
4325292dbf7SMichael S. Tsirkin 			}
4335292dbf7SMichael S. Tsirkin 			if (pci_bar_is_memory(pcidev, i)) {
4345292dbf7SMichael S. Tsirkin 				membar = pci_bar_addr(pcidev, i);
4355292dbf7SMichael S. Tsirkin 				base = membar & ~4095;
4365292dbf7SMichael S. Tsirkin 				offset = membar - base;
4375292dbf7SMichael S. Tsirkin 				m = alloc_vpages(1);
4385292dbf7SMichael S. Tsirkin 
4395292dbf7SMichael S. Tsirkin 				install_page((void *)read_cr3(), base, m);
4405292dbf7SMichael S. Tsirkin 				pci_test.memaddr = m + offset;
4415292dbf7SMichael S. Tsirkin 			} else {
4425292dbf7SMichael S. Tsirkin 				pci_test.iobar = pci_bar_addr(pcidev, i);
4435292dbf7SMichael S. Tsirkin 			}
4445292dbf7SMichael S. Tsirkin 		}
4455292dbf7SMichael S. Tsirkin 		printf("pci-testdev at 0x%x membar %lx iobar %x\n",
4465292dbf7SMichael S. Tsirkin 		       pcidev, membar, pci_test.iobar);
4475292dbf7SMichael S. Tsirkin 	}
4485292dbf7SMichael S. Tsirkin 
4497d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
4500b267183SAvi Kivity 		if (test_wanted(&tests[i], av + 1, ac - 1))
4515292dbf7SMichael S. Tsirkin 			while (do_test(&tests[i])) {}
4527d36db35SAvi Kivity 
4537d36db35SAvi Kivity 	return 0;
4547d36db35SAvi Kivity }
455