xref: /kvm-unit-tests/x86/vmexit.c (revision e0a5cfcac103439353eca11db0bea652cac2f2c5)
17d36db35SAvi Kivity #include "libcflat.h"
27d36db35SAvi Kivity #include "smp.h"
3850479e3SJason Wang #include "processor.h"
47d641cc5SAvi Kivity #include "atomic.h"
5456c55bcSAndrew Jones #include "pci.h"
65292dbf7SMichael S. Tsirkin #include "x86/vm.h"
75292dbf7SMichael S. Tsirkin #include "x86/desc.h"
8a5d12b9fSPaolo Bonzini #include "x86/acpi.h"
9*e0a5cfcaSPaolo Bonzini #include "x86/apic.h"
10*e0a5cfcaSPaolo Bonzini #include "x86/isr.h"
11*e0a5cfcaSPaolo Bonzini 
12*e0a5cfcaSPaolo Bonzini #define IPI_TEST_VECTOR	0xb0
137d36db35SAvi Kivity 
145292dbf7SMichael S. Tsirkin struct test {
155292dbf7SMichael S. Tsirkin 	void (*func)(void);
165292dbf7SMichael S. Tsirkin 	const char *name;
175292dbf7SMichael S. Tsirkin 	int (*valid)(void);
185292dbf7SMichael S. Tsirkin 	int parallel;
195292dbf7SMichael S. Tsirkin 	bool (*next)(struct test *);
205292dbf7SMichael S. Tsirkin };
215292dbf7SMichael S. Tsirkin 
227d36db35SAvi Kivity #define GOAL (1ull << 30)
237d36db35SAvi Kivity 
24eda71b28SAvi Kivity static int nr_cpus;
25eda71b28SAvi Kivity 
26850479e3SJason Wang static void cpuid_test(void)
277d36db35SAvi Kivity {
287d36db35SAvi Kivity 	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
297d36db35SAvi Kivity 		      : : : "eax", "ecx", "edx");
307d36db35SAvi Kivity }
317d36db35SAvi Kivity 
327d36db35SAvi Kivity static void vmcall(void)
337d36db35SAvi Kivity {
347d36db35SAvi Kivity 	unsigned long a = 0, b, c, d;
357d36db35SAvi Kivity 
367d36db35SAvi Kivity 	asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
377d36db35SAvi Kivity }
387d36db35SAvi Kivity 
395fecf5d8SWill Auld #define MSR_TSC_ADJUST 0x3b
407d36db35SAvi Kivity #define MSR_EFER 0xc0000080
417d36db35SAvi Kivity #define EFER_NX_MASK            (1ull << 11)
427d36db35SAvi Kivity 
435ada505aSJason Wang #ifdef __x86_64__
447d36db35SAvi Kivity static void mov_from_cr8(void)
457d36db35SAvi Kivity {
467d36db35SAvi Kivity 	unsigned long cr8;
477d36db35SAvi Kivity 
487d36db35SAvi Kivity 	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
497d36db35SAvi Kivity }
507d36db35SAvi Kivity 
517d36db35SAvi Kivity static void mov_to_cr8(void)
527d36db35SAvi Kivity {
537d36db35SAvi Kivity 	unsigned long cr8 = 0;
547d36db35SAvi Kivity 
557d36db35SAvi Kivity 	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
567d36db35SAvi Kivity }
575ada505aSJason Wang #endif
587d36db35SAvi Kivity 
597d36db35SAvi Kivity static int is_smp(void)
607d36db35SAvi Kivity {
617d36db35SAvi Kivity 	return cpu_count() > 1;
627d36db35SAvi Kivity }
637d36db35SAvi Kivity 
647d36db35SAvi Kivity static void nop(void *junk)
657d36db35SAvi Kivity {
667d36db35SAvi Kivity }
677d36db35SAvi Kivity 
68*e0a5cfcaSPaolo Bonzini volatile int x = 0;
69*e0a5cfcaSPaolo Bonzini 
70*e0a5cfcaSPaolo Bonzini static void self_ipi_isr(isr_regs_t *regs)
71*e0a5cfcaSPaolo Bonzini {
72*e0a5cfcaSPaolo Bonzini 	x++;
73*e0a5cfcaSPaolo Bonzini 	eoi();
74*e0a5cfcaSPaolo Bonzini }
75*e0a5cfcaSPaolo Bonzini 
76*e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi(int vec)
77*e0a5cfcaSPaolo Bonzini {
78*e0a5cfcaSPaolo Bonzini 	wrmsr(0x83f, vec);
79*e0a5cfcaSPaolo Bonzini }
80*e0a5cfcaSPaolo Bonzini 
81*e0a5cfcaSPaolo Bonzini static void apic_self_ipi(int vec)
82*e0a5cfcaSPaolo Bonzini {
83*e0a5cfcaSPaolo Bonzini         apic_icr_write(APIC_INT_ASSERT | APIC_DEST_SELF | APIC_DEST_PHYSICAL |
84*e0a5cfcaSPaolo Bonzini 		       APIC_DM_FIXED | IPI_TEST_VECTOR, vec);
85*e0a5cfcaSPaolo Bonzini }
86*e0a5cfcaSPaolo Bonzini 
87*e0a5cfcaSPaolo Bonzini static void self_ipi_sti_nop(void)
88*e0a5cfcaSPaolo Bonzini {
89*e0a5cfcaSPaolo Bonzini 	x = 0;
90*e0a5cfcaSPaolo Bonzini 	irq_disable();
91*e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
92*e0a5cfcaSPaolo Bonzini 	asm volatile("sti; nop");
93*e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
94*e0a5cfcaSPaolo Bonzini }
95*e0a5cfcaSPaolo Bonzini 
96*e0a5cfcaSPaolo Bonzini static void self_ipi_sti_hlt(void)
97*e0a5cfcaSPaolo Bonzini {
98*e0a5cfcaSPaolo Bonzini 	x = 0;
99*e0a5cfcaSPaolo Bonzini 	irq_disable();
100*e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
101*e0a5cfcaSPaolo Bonzini 	asm volatile("sti; hlt");
102*e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
103*e0a5cfcaSPaolo Bonzini }
104*e0a5cfcaSPaolo Bonzini 
105*e0a5cfcaSPaolo Bonzini static void self_ipi_tpr(void)
106*e0a5cfcaSPaolo Bonzini {
107*e0a5cfcaSPaolo Bonzini 	x = 0;
108*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
109*e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
110*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
111*e0a5cfcaSPaolo Bonzini 	asm volatile("nop");
112*e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
113*e0a5cfcaSPaolo Bonzini }
114*e0a5cfcaSPaolo Bonzini 
115*e0a5cfcaSPaolo Bonzini static void self_ipi_tpr_sti_nop(void)
116*e0a5cfcaSPaolo Bonzini {
117*e0a5cfcaSPaolo Bonzini 	x = 0;
118*e0a5cfcaSPaolo Bonzini 	irq_disable();
119*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
120*e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
121*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
122*e0a5cfcaSPaolo Bonzini 	asm volatile("sti; nop");
123*e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
124*e0a5cfcaSPaolo Bonzini }
125*e0a5cfcaSPaolo Bonzini 
126*e0a5cfcaSPaolo Bonzini static void self_ipi_tpr_sti_hlt(void)
127*e0a5cfcaSPaolo Bonzini {
128*e0a5cfcaSPaolo Bonzini 	x = 0;
129*e0a5cfcaSPaolo Bonzini 	irq_disable();
130*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
131*e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
132*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
133*e0a5cfcaSPaolo Bonzini 	asm volatile("sti; hlt");
134*e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
135*e0a5cfcaSPaolo Bonzini }
136*e0a5cfcaSPaolo Bonzini 
137*e0a5cfcaSPaolo Bonzini static int is_x2apic(void)
138*e0a5cfcaSPaolo Bonzini {
139*e0a5cfcaSPaolo Bonzini     return rdmsr(MSR_IA32_APICBASE) & APIC_EXTD;
140*e0a5cfcaSPaolo Bonzini }
141*e0a5cfcaSPaolo Bonzini 
142*e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_sti_nop(void)
143*e0a5cfcaSPaolo Bonzini {
144*e0a5cfcaSPaolo Bonzini 	irq_disable();
145*e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
146*e0a5cfcaSPaolo Bonzini 	asm volatile("sti; nop");
147*e0a5cfcaSPaolo Bonzini }
148*e0a5cfcaSPaolo Bonzini 
149*e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_sti_hlt(void)
150*e0a5cfcaSPaolo Bonzini {
151*e0a5cfcaSPaolo Bonzini 	irq_disable();
152*e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
153*e0a5cfcaSPaolo Bonzini 	asm volatile("sti; hlt");
154*e0a5cfcaSPaolo Bonzini }
155*e0a5cfcaSPaolo Bonzini 
156*e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr(void)
157*e0a5cfcaSPaolo Bonzini {
158*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
159*e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
160*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
161*e0a5cfcaSPaolo Bonzini 	asm volatile("nop");
162*e0a5cfcaSPaolo Bonzini }
163*e0a5cfcaSPaolo Bonzini 
164*e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr_sti_nop(void)
165*e0a5cfcaSPaolo Bonzini {
166*e0a5cfcaSPaolo Bonzini 	irq_disable();
167*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
168*e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
169*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
170*e0a5cfcaSPaolo Bonzini 	asm volatile("sti; nop");
171*e0a5cfcaSPaolo Bonzini }
172*e0a5cfcaSPaolo Bonzini 
173*e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr_sti_hlt(void)
174*e0a5cfcaSPaolo Bonzini {
175*e0a5cfcaSPaolo Bonzini 	irq_disable();
176*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
177*e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
178*e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
179*e0a5cfcaSPaolo Bonzini 	asm volatile("sti; hlt");
180*e0a5cfcaSPaolo Bonzini }
181*e0a5cfcaSPaolo Bonzini 
1827d36db35SAvi Kivity static void ipi(void)
1837d36db35SAvi Kivity {
1847d36db35SAvi Kivity 	on_cpu(1, nop, 0);
1857d36db35SAvi Kivity }
1867d36db35SAvi Kivity 
1877d36db35SAvi Kivity static void ipi_halt(void)
1887d36db35SAvi Kivity {
1897d36db35SAvi Kivity 	unsigned long long t;
1907d36db35SAvi Kivity 
1917d36db35SAvi Kivity 	on_cpu(1, nop, 0);
1927d36db35SAvi Kivity 	t = rdtsc() + 2000;
1937d36db35SAvi Kivity 	while (rdtsc() < t)
1947d36db35SAvi Kivity 		;
1957d36db35SAvi Kivity }
1967d36db35SAvi Kivity 
197a5d12b9fSPaolo Bonzini int pm_tmr_blk;
1987d36db35SAvi Kivity static void inl_pmtimer(void)
1997d36db35SAvi Kivity {
200a5d12b9fSPaolo Bonzini     inl(pm_tmr_blk);
2017d36db35SAvi Kivity }
2027d36db35SAvi Kivity 
20300bfecaaSPaolo Bonzini static void inl_nop_qemu(void)
20400bfecaaSPaolo Bonzini {
20500bfecaaSPaolo Bonzini     inl(0x1234);
20600bfecaaSPaolo Bonzini }
20700bfecaaSPaolo Bonzini 
20800bfecaaSPaolo Bonzini static void inl_nop_kernel(void)
20900bfecaaSPaolo Bonzini {
21000bfecaaSPaolo Bonzini     inb(0x4d0);
21100bfecaaSPaolo Bonzini }
21200bfecaaSPaolo Bonzini 
21300bfecaaSPaolo Bonzini static void outl_elcr_kernel(void)
21400bfecaaSPaolo Bonzini {
215f22a66a1SAndrew Jones     outb(0, 0x4d0);
21600bfecaaSPaolo Bonzini }
21700bfecaaSPaolo Bonzini 
2188a544409SPaolo Bonzini static void mov_dr(void)
2198a544409SPaolo Bonzini {
2208a544409SPaolo Bonzini     asm volatile("mov %0, %%dr7" : : "r" (0x400L));
2218a544409SPaolo Bonzini }
2228a544409SPaolo Bonzini 
223eda71b28SAvi Kivity static void ple_round_robin(void)
224eda71b28SAvi Kivity {
225eda71b28SAvi Kivity 	struct counter {
226eda71b28SAvi Kivity 		volatile int n1;
227eda71b28SAvi Kivity 		int n2;
228eda71b28SAvi Kivity 	} __attribute__((aligned(64)));
229eda71b28SAvi Kivity 	static struct counter counters[64] = { { -1, 0 } };
230eda71b28SAvi Kivity 	int me = smp_id();
231eda71b28SAvi Kivity 	int you;
232eda71b28SAvi Kivity 	volatile struct counter *p = &counters[me];
233eda71b28SAvi Kivity 
234eda71b28SAvi Kivity 	while (p->n1 == p->n2)
235eda71b28SAvi Kivity 		asm volatile ("pause");
236eda71b28SAvi Kivity 
237eda71b28SAvi Kivity 	p->n2 = p->n1;
238eda71b28SAvi Kivity 	you = me + 1;
239eda71b28SAvi Kivity 	if (you == nr_cpus)
240eda71b28SAvi Kivity 		you = 0;
241eda71b28SAvi Kivity 	++counters[you].n1;
242eda71b28SAvi Kivity }
243eda71b28SAvi Kivity 
2445fecf5d8SWill Auld static void rd_tsc_adjust_msr(void)
2455fecf5d8SWill Auld {
2465fecf5d8SWill Auld 	rdmsr(MSR_TSC_ADJUST);
2475fecf5d8SWill Auld }
2485fecf5d8SWill Auld 
2495fecf5d8SWill Auld static void wr_tsc_adjust_msr(void)
2505fecf5d8SWill Auld {
2515fecf5d8SWill Auld 	wrmsr(MSR_TSC_ADJUST, 0x0);
2525fecf5d8SWill Auld }
2535fecf5d8SWill Auld 
2545292dbf7SMichael S. Tsirkin static struct pci_test {
2555292dbf7SMichael S. Tsirkin 	unsigned iobar;
2565292dbf7SMichael S. Tsirkin 	unsigned ioport;
2575292dbf7SMichael S. Tsirkin 	volatile void *memaddr;
2585292dbf7SMichael S. Tsirkin 	volatile void *mem;
2595292dbf7SMichael S. Tsirkin 	int test_idx;
2605292dbf7SMichael S. Tsirkin 	uint32_t data;
2615292dbf7SMichael S. Tsirkin 	uint32_t offset;
2625292dbf7SMichael S. Tsirkin } pci_test = {
2635292dbf7SMichael S. Tsirkin 	.test_idx = -1
2645292dbf7SMichael S. Tsirkin };
2655292dbf7SMichael S. Tsirkin 
2665292dbf7SMichael S. Tsirkin static void pci_mem_testb(void)
2675292dbf7SMichael S. Tsirkin {
2685292dbf7SMichael S. Tsirkin 	*(volatile uint8_t *)pci_test.mem = pci_test.data;
2695292dbf7SMichael S. Tsirkin }
2705292dbf7SMichael S. Tsirkin 
2715292dbf7SMichael S. Tsirkin static void pci_mem_testw(void)
2725292dbf7SMichael S. Tsirkin {
2735292dbf7SMichael S. Tsirkin 	*(volatile uint16_t *)pci_test.mem = pci_test.data;
2745292dbf7SMichael S. Tsirkin }
2755292dbf7SMichael S. Tsirkin 
2765292dbf7SMichael S. Tsirkin static void pci_mem_testl(void)
2775292dbf7SMichael S. Tsirkin {
2785292dbf7SMichael S. Tsirkin 	*(volatile uint32_t *)pci_test.mem = pci_test.data;
2795292dbf7SMichael S. Tsirkin }
2805292dbf7SMichael S. Tsirkin 
2815292dbf7SMichael S. Tsirkin static void pci_io_testb(void)
2825292dbf7SMichael S. Tsirkin {
283f22a66a1SAndrew Jones 	outb(pci_test.data, pci_test.ioport);
2845292dbf7SMichael S. Tsirkin }
2855292dbf7SMichael S. Tsirkin 
2865292dbf7SMichael S. Tsirkin static void pci_io_testw(void)
2875292dbf7SMichael S. Tsirkin {
288f22a66a1SAndrew Jones 	outw(pci_test.data, pci_test.ioport);
2895292dbf7SMichael S. Tsirkin }
2905292dbf7SMichael S. Tsirkin 
2915292dbf7SMichael S. Tsirkin static void pci_io_testl(void)
2925292dbf7SMichael S. Tsirkin {
293f22a66a1SAndrew Jones 	outl(pci_test.data, pci_test.ioport);
2945292dbf7SMichael S. Tsirkin }
2955292dbf7SMichael S. Tsirkin 
2965292dbf7SMichael S. Tsirkin static uint8_t ioreadb(unsigned long addr, bool io)
2975292dbf7SMichael S. Tsirkin {
2985292dbf7SMichael S. Tsirkin 	if (io) {
2995292dbf7SMichael S. Tsirkin 		return inb(addr);
3005292dbf7SMichael S. Tsirkin 	} else {
3015292dbf7SMichael S. Tsirkin 		return *(volatile uint8_t *)addr;
3025292dbf7SMichael S. Tsirkin 	}
3035292dbf7SMichael S. Tsirkin }
3045292dbf7SMichael S. Tsirkin 
3055292dbf7SMichael S. Tsirkin static uint32_t ioreadl(unsigned long addr, bool io)
3065292dbf7SMichael S. Tsirkin {
3075292dbf7SMichael S. Tsirkin 	/* Note: assumes little endian */
3085292dbf7SMichael S. Tsirkin 	if (io) {
3095292dbf7SMichael S. Tsirkin 		return inl(addr);
3105292dbf7SMichael S. Tsirkin 	} else {
3115292dbf7SMichael S. Tsirkin 		return *(volatile uint32_t *)addr;
3125292dbf7SMichael S. Tsirkin 	}
3135292dbf7SMichael S. Tsirkin }
3145292dbf7SMichael S. Tsirkin 
3155292dbf7SMichael S. Tsirkin static void iowriteb(unsigned long addr, uint8_t data, bool io)
3165292dbf7SMichael S. Tsirkin {
3175292dbf7SMichael S. Tsirkin 	if (io) {
318f22a66a1SAndrew Jones 		outb(data, addr);
3195292dbf7SMichael S. Tsirkin 	} else {
3205292dbf7SMichael S. Tsirkin 		*(volatile uint8_t *)addr = data;
3215292dbf7SMichael S. Tsirkin 	}
3225292dbf7SMichael S. Tsirkin }
3235292dbf7SMichael S. Tsirkin 
3245292dbf7SMichael S. Tsirkin static bool pci_next(struct test *test, unsigned long addr, bool io)
3255292dbf7SMichael S. Tsirkin {
3265292dbf7SMichael S. Tsirkin 	int i;
3275292dbf7SMichael S. Tsirkin 	uint8_t width;
3285292dbf7SMichael S. Tsirkin 
3295292dbf7SMichael S. Tsirkin 	if (!pci_test.memaddr) {
3305292dbf7SMichael S. Tsirkin 		test->func = NULL;
3315292dbf7SMichael S. Tsirkin 		return true;
3325292dbf7SMichael S. Tsirkin 	}
3335292dbf7SMichael S. Tsirkin 	pci_test.test_idx++;
3345292dbf7SMichael S. Tsirkin 	iowriteb(addr + offsetof(struct pci_test_dev_hdr, test),
3355292dbf7SMichael S. Tsirkin 		 pci_test.test_idx, io);
3365292dbf7SMichael S. Tsirkin 	width = ioreadb(addr + offsetof(struct pci_test_dev_hdr, width),
3375292dbf7SMichael S. Tsirkin 			io);
3385292dbf7SMichael S. Tsirkin 	switch (width) {
3395292dbf7SMichael S. Tsirkin 		case 1:
3405292dbf7SMichael S. Tsirkin 			test->func = io ? pci_io_testb : pci_mem_testb;
3415292dbf7SMichael S. Tsirkin 			break;
3425292dbf7SMichael S. Tsirkin 		case 2:
3435292dbf7SMichael S. Tsirkin 			test->func = io ? pci_io_testw : pci_mem_testw;
3445292dbf7SMichael S. Tsirkin 			break;
3455292dbf7SMichael S. Tsirkin 		case 4:
3465292dbf7SMichael S. Tsirkin 			test->func = io ? pci_io_testl : pci_mem_testl;
3475292dbf7SMichael S. Tsirkin 			break;
3485292dbf7SMichael S. Tsirkin 		default:
3495292dbf7SMichael S. Tsirkin 			/* Reset index for purposes of the next test */
3505292dbf7SMichael S. Tsirkin 			pci_test.test_idx = -1;
3515292dbf7SMichael S. Tsirkin 			test->func = NULL;
3525292dbf7SMichael S. Tsirkin 			return false;
3535292dbf7SMichael S. Tsirkin 	}
3545292dbf7SMichael S. Tsirkin 	pci_test.data = ioreadl(addr + offsetof(struct pci_test_dev_hdr, data),
3555292dbf7SMichael S. Tsirkin 				io);
3565292dbf7SMichael S. Tsirkin 	pci_test.offset = ioreadl(addr + offsetof(struct pci_test_dev_hdr,
3575292dbf7SMichael S. Tsirkin 						  offset), io);
3585292dbf7SMichael S. Tsirkin 	for (i = 0; i < pci_test.offset; ++i) {
3595292dbf7SMichael S. Tsirkin 		char c = ioreadb(addr + offsetof(struct pci_test_dev_hdr,
3605292dbf7SMichael S. Tsirkin 						 name) + i, io);
3615292dbf7SMichael S. Tsirkin 		if (!c) {
3625292dbf7SMichael S. Tsirkin 			break;
3635292dbf7SMichael S. Tsirkin 		}
3645292dbf7SMichael S. Tsirkin 		printf("%c",c);
3655292dbf7SMichael S. Tsirkin 	}
3665292dbf7SMichael S. Tsirkin 	printf(":");
3675292dbf7SMichael S. Tsirkin 	return true;
3685292dbf7SMichael S. Tsirkin }
3695292dbf7SMichael S. Tsirkin 
3705292dbf7SMichael S. Tsirkin static bool pci_mem_next(struct test *test)
3715292dbf7SMichael S. Tsirkin {
3725292dbf7SMichael S. Tsirkin 	bool ret;
3735292dbf7SMichael S. Tsirkin 	ret = pci_next(test, ((unsigned long)pci_test.memaddr), false);
3745292dbf7SMichael S. Tsirkin 	if (ret) {
3755292dbf7SMichael S. Tsirkin 		pci_test.mem = pci_test.memaddr + pci_test.offset;
3765292dbf7SMichael S. Tsirkin 	}
3775292dbf7SMichael S. Tsirkin 	return ret;
3785292dbf7SMichael S. Tsirkin }
3795292dbf7SMichael S. Tsirkin 
3805292dbf7SMichael S. Tsirkin static bool pci_io_next(struct test *test)
3815292dbf7SMichael S. Tsirkin {
3825292dbf7SMichael S. Tsirkin 	bool ret;
3835292dbf7SMichael S. Tsirkin 	ret = pci_next(test, ((unsigned long)pci_test.iobar), true);
3845292dbf7SMichael S. Tsirkin 	if (ret) {
3855292dbf7SMichael S. Tsirkin 		pci_test.ioport = pci_test.iobar + pci_test.offset;
3865292dbf7SMichael S. Tsirkin 	}
3875292dbf7SMichael S. Tsirkin 	return ret;
3885292dbf7SMichael S. Tsirkin }
3895292dbf7SMichael S. Tsirkin 
3905292dbf7SMichael S. Tsirkin static struct test tests[] = {
391850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
3927d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
3935ada505aSJason Wang #ifdef __x86_64__
3947d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
3957d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
3965ada505aSJason Wang #endif
3977d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
39800bfecaaSPaolo Bonzini 	{ inl_nop_qemu, "inl_from_qemu", .parallel = 1 },
39900bfecaaSPaolo Bonzini 	{ inl_nop_kernel, "inl_from_kernel", .parallel = 1 },
40000bfecaaSPaolo Bonzini 	{ outl_elcr_kernel, "outl_to_kernel", .parallel = 1 },
4018a544409SPaolo Bonzini 	{ mov_dr, "mov_dr", .parallel = 1 },
402*e0a5cfcaSPaolo Bonzini 	{ self_ipi_sti_nop, "self_ipi_sti_nop", .parallel = 0, },
403*e0a5cfcaSPaolo Bonzini 	{ self_ipi_sti_hlt, "self_ipi_sti_hlt", .parallel = 0, },
404*e0a5cfcaSPaolo Bonzini 	{ self_ipi_tpr, "self_ipi_tpr", .parallel = 0, },
405*e0a5cfcaSPaolo Bonzini 	{ self_ipi_tpr_sti_nop, "self_ipi_tpr_sti_nop", .parallel = 0, },
406*e0a5cfcaSPaolo Bonzini 	{ self_ipi_tpr_sti_hlt, "self_ipi_tpr_sti_hlt", .parallel = 0, },
407*e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_sti_nop, "x2apic_self_ipi_sti_nop", is_x2apic, .parallel = 0, },
408*e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_sti_hlt, "x2apic_self_ipi_sti_hlt", is_x2apic, .parallel = 0, },
409*e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_tpr, "x2apic_self_ipi_tpr", is_x2apic, .parallel = 0, },
410*e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_tpr_sti_nop, "x2apic_self_ipi_tpr_sti_nop", is_x2apic, .parallel = 0, },
411*e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_tpr_sti_hlt, "x2apic_self_ipi_tpr_sti_hlt", is_x2apic, .parallel = 0, },
4127d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
4137d36db35SAvi Kivity 	{ ipi_halt, "ipi+halt", is_smp, .parallel = 0, },
414eda71b28SAvi Kivity 	{ ple_round_robin, "ple-round-robin", .parallel = 1 },
4155fecf5d8SWill Auld 	{ wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 },
4165fecf5d8SWill Auld 	{ rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 },
4175292dbf7SMichael S. Tsirkin 	{ NULL, "pci-mem", .parallel = 0, .next = pci_mem_next },
4185292dbf7SMichael S. Tsirkin 	{ NULL, "pci-io", .parallel = 0, .next = pci_io_next },
4197d36db35SAvi Kivity };
4207d36db35SAvi Kivity 
4217d36db35SAvi Kivity unsigned iterations;
4227d641cc5SAvi Kivity static atomic_t nr_cpus_done;
4237d36db35SAvi Kivity 
4247d36db35SAvi Kivity static void run_test(void *_func)
4257d36db35SAvi Kivity {
4267d36db35SAvi Kivity     int i;
4277d36db35SAvi Kivity     void (*func)(void) = _func;
4287d36db35SAvi Kivity 
4297d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
4307d36db35SAvi Kivity         func();
4317d36db35SAvi Kivity 
4327d641cc5SAvi Kivity     atomic_inc(&nr_cpus_done);
4337d36db35SAvi Kivity }
4347d36db35SAvi Kivity 
4355292dbf7SMichael S. Tsirkin static bool do_test(struct test *test)
4367d36db35SAvi Kivity {
4377d36db35SAvi Kivity 	int i;
4387d36db35SAvi Kivity 	unsigned long long t1, t2;
4395292dbf7SMichael S. Tsirkin         void (*func)(void);
4407d36db35SAvi Kivity 
4417d36db35SAvi Kivity         iterations = 32;
4427d36db35SAvi Kivity 
4437d36db35SAvi Kivity         if (test->valid && !test->valid()) {
4447d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
4455292dbf7SMichael S. Tsirkin 		return false;
4465292dbf7SMichael S. Tsirkin 	}
4475292dbf7SMichael S. Tsirkin 
4485292dbf7SMichael S. Tsirkin 	if (test->next && !test->next(test)) {
4495292dbf7SMichael S. Tsirkin 		return false;
4505292dbf7SMichael S. Tsirkin 	}
4515292dbf7SMichael S. Tsirkin 
4525292dbf7SMichael S. Tsirkin 	func = test->func;
4535292dbf7SMichael S. Tsirkin         if (!func) {
4545292dbf7SMichael S. Tsirkin 		printf("%s (skipped)\n", test->name);
4555292dbf7SMichael S. Tsirkin 		return false;
4567d36db35SAvi Kivity 	}
4577d36db35SAvi Kivity 
4587d36db35SAvi Kivity 	do {
4597d36db35SAvi Kivity 		iterations *= 2;
4607d36db35SAvi Kivity 		t1 = rdtsc();
4617d36db35SAvi Kivity 
4627d36db35SAvi Kivity 		if (!test->parallel) {
4637d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
4647d36db35SAvi Kivity 				func();
4657d36db35SAvi Kivity 		} else {
4667d641cc5SAvi Kivity 			atomic_set(&nr_cpus_done, 0);
4677d36db35SAvi Kivity 			for (i = cpu_count(); i > 0; i--)
4687d36db35SAvi Kivity 				on_cpu_async(i-1, run_test, func);
4697d641cc5SAvi Kivity 			while (atomic_read(&nr_cpus_done) < cpu_count())
4707d36db35SAvi Kivity 				;
4717d36db35SAvi Kivity 		}
4727d36db35SAvi Kivity 		t2 = rdtsc();
4737d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
4747d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
4755292dbf7SMichael S. Tsirkin 	return test->next;
4767d36db35SAvi Kivity }
4777d36db35SAvi Kivity 
4787d36db35SAvi Kivity static void enable_nx(void *junk)
4797d36db35SAvi Kivity {
480e46b32aaSAvi Kivity 	if (cpuid(0x80000001).d & (1 << 20))
4817d36db35SAvi Kivity 		wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
4827d36db35SAvi Kivity }
4837d36db35SAvi Kivity 
4840b267183SAvi Kivity bool test_wanted(struct test *test, char *wanted[], int nwanted)
4850b267183SAvi Kivity {
4860b267183SAvi Kivity 	int i;
4870b267183SAvi Kivity 
4880b267183SAvi Kivity 	if (!nwanted)
4890b267183SAvi Kivity 		return true;
4900b267183SAvi Kivity 
4910b267183SAvi Kivity 	for (i = 0; i < nwanted; ++i)
4920b267183SAvi Kivity 		if (strcmp(wanted[i], test->name) == 0)
4930b267183SAvi Kivity 			return true;
4940b267183SAvi Kivity 
4950b267183SAvi Kivity 	return false;
4960b267183SAvi Kivity }
4970b267183SAvi Kivity 
4980b267183SAvi Kivity int main(int ac, char **av)
4997d36db35SAvi Kivity {
500a5d12b9fSPaolo Bonzini 	struct fadt_descriptor_rev1 *fadt;
5017d36db35SAvi Kivity 	int i;
502f1abb07bSAlexander Gordeev 	unsigned long membar = 0;
5035292dbf7SMichael S. Tsirkin 	pcidevaddr_t pcidev;
5047d36db35SAvi Kivity 
5057d36db35SAvi Kivity 	smp_init();
5065292dbf7SMichael S. Tsirkin 	setup_vm();
507*e0a5cfcaSPaolo Bonzini 	handle_irq(IPI_TEST_VECTOR, self_ipi_isr);
508eda71b28SAvi Kivity 	nr_cpus = cpu_count();
5097d36db35SAvi Kivity 
510*e0a5cfcaSPaolo Bonzini 	irq_enable();
5117d36db35SAvi Kivity 	for (i = cpu_count(); i > 0; i--)
5127d36db35SAvi Kivity 		on_cpu(i-1, enable_nx, 0);
5137d36db35SAvi Kivity 
514a5d12b9fSPaolo Bonzini 	fadt = find_acpi_table_addr(FACP_SIGNATURE);
515a5d12b9fSPaolo Bonzini 	pm_tmr_blk = fadt->pm_tmr_blk;
516a5d12b9fSPaolo Bonzini 	printf("PM timer port is %x\n", pm_tmr_blk);
517a5d12b9fSPaolo Bonzini 
518289ebf8fSAndrew Jones 	pcidev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
519d3a8ad49SAndrew Jones 	if (pcidev != PCIDEVADDR_INVALID) {
520289ebf8fSAndrew Jones 		for (i = 0; i < PCI_TESTDEV_NUM_BARS; i++) {
5215292dbf7SMichael S. Tsirkin 			if (!pci_bar_is_valid(pcidev, i)) {
5225292dbf7SMichael S. Tsirkin 				continue;
5235292dbf7SMichael S. Tsirkin 			}
5245292dbf7SMichael S. Tsirkin 			if (pci_bar_is_memory(pcidev, i)) {
525647f92c7SAlexander Gordeev 				membar = pci_bar_get_addr(pcidev, i);
526f1abb07bSAlexander Gordeev 				pci_test.memaddr = ioremap(membar, PAGE_SIZE);
5275292dbf7SMichael S. Tsirkin 			} else {
528647f92c7SAlexander Gordeev 				pci_test.iobar = pci_bar_get_addr(pcidev, i);
5295292dbf7SMichael S. Tsirkin 			}
5305292dbf7SMichael S. Tsirkin 		}
5315292dbf7SMichael S. Tsirkin 		printf("pci-testdev at 0x%x membar %lx iobar %x\n",
5325292dbf7SMichael S. Tsirkin 		       pcidev, membar, pci_test.iobar);
5335292dbf7SMichael S. Tsirkin 	}
5345292dbf7SMichael S. Tsirkin 
5357d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
5360b267183SAvi Kivity 		if (test_wanted(&tests[i], av + 1, ac - 1))
5375292dbf7SMichael S. Tsirkin 			while (do_test(&tests[i])) {}
5387d36db35SAvi Kivity 
5397d36db35SAvi Kivity 	return 0;
5407d36db35SAvi Kivity }
541