xref: /kvm-unit-tests/x86/vmexit.c (revision cb37ca1ef332dcf61188fe3214052425ae865df0)
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"
9e0a5cfcaSPaolo Bonzini #include "x86/apic.h"
10e0a5cfcaSPaolo Bonzini #include "x86/isr.h"
11e0a5cfcaSPaolo Bonzini 
12e0a5cfcaSPaolo 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 
68e0a5cfcaSPaolo Bonzini volatile int x = 0;
69e0a5cfcaSPaolo Bonzini 
70e0a5cfcaSPaolo Bonzini static void self_ipi_isr(isr_regs_t *regs)
71e0a5cfcaSPaolo Bonzini {
72e0a5cfcaSPaolo Bonzini 	x++;
73e0a5cfcaSPaolo Bonzini 	eoi();
74e0a5cfcaSPaolo Bonzini }
75e0a5cfcaSPaolo Bonzini 
76e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi(int vec)
77e0a5cfcaSPaolo Bonzini {
78e0a5cfcaSPaolo Bonzini 	wrmsr(0x83f, vec);
79e0a5cfcaSPaolo Bonzini }
80e0a5cfcaSPaolo Bonzini 
81e0a5cfcaSPaolo Bonzini static void apic_self_ipi(int vec)
82e0a5cfcaSPaolo Bonzini {
83e0a5cfcaSPaolo Bonzini         apic_icr_write(APIC_INT_ASSERT | APIC_DEST_SELF | APIC_DEST_PHYSICAL |
84e0a5cfcaSPaolo Bonzini 		       APIC_DM_FIXED | IPI_TEST_VECTOR, vec);
85e0a5cfcaSPaolo Bonzini }
86e0a5cfcaSPaolo Bonzini 
87e0a5cfcaSPaolo Bonzini static void self_ipi_sti_nop(void)
88e0a5cfcaSPaolo Bonzini {
89e0a5cfcaSPaolo Bonzini 	x = 0;
90e0a5cfcaSPaolo Bonzini 	irq_disable();
91e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
92e0a5cfcaSPaolo Bonzini 	asm volatile("sti; nop");
93e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
94e0a5cfcaSPaolo Bonzini }
95e0a5cfcaSPaolo Bonzini 
96e0a5cfcaSPaolo Bonzini static void self_ipi_sti_hlt(void)
97e0a5cfcaSPaolo Bonzini {
98e0a5cfcaSPaolo Bonzini 	x = 0;
99e0a5cfcaSPaolo Bonzini 	irq_disable();
100e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
101e0a5cfcaSPaolo Bonzini 	asm volatile("sti; hlt");
102e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
103e0a5cfcaSPaolo Bonzini }
104e0a5cfcaSPaolo Bonzini 
105e0a5cfcaSPaolo Bonzini static void self_ipi_tpr(void)
106e0a5cfcaSPaolo Bonzini {
107e0a5cfcaSPaolo Bonzini 	x = 0;
108e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
109e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
110e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
111e0a5cfcaSPaolo Bonzini 	asm volatile("nop");
112e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
113e0a5cfcaSPaolo Bonzini }
114e0a5cfcaSPaolo Bonzini 
115e0a5cfcaSPaolo Bonzini static void self_ipi_tpr_sti_nop(void)
116e0a5cfcaSPaolo Bonzini {
117e0a5cfcaSPaolo Bonzini 	x = 0;
118e0a5cfcaSPaolo Bonzini 	irq_disable();
119e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
120e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
121e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
122e0a5cfcaSPaolo Bonzini 	asm volatile("sti; nop");
123e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
124e0a5cfcaSPaolo Bonzini }
125e0a5cfcaSPaolo Bonzini 
126e0a5cfcaSPaolo Bonzini static void self_ipi_tpr_sti_hlt(void)
127e0a5cfcaSPaolo Bonzini {
128e0a5cfcaSPaolo Bonzini 	x = 0;
129e0a5cfcaSPaolo Bonzini 	irq_disable();
130e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
131e0a5cfcaSPaolo Bonzini 	apic_self_ipi(IPI_TEST_VECTOR);
132e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
133e0a5cfcaSPaolo Bonzini 	asm volatile("sti; hlt");
134e0a5cfcaSPaolo Bonzini 	if (x != 1) printf("%d", x);
135e0a5cfcaSPaolo Bonzini }
136e0a5cfcaSPaolo Bonzini 
137e0a5cfcaSPaolo Bonzini static int is_x2apic(void)
138e0a5cfcaSPaolo Bonzini {
139e0a5cfcaSPaolo Bonzini     return rdmsr(MSR_IA32_APICBASE) & APIC_EXTD;
140e0a5cfcaSPaolo Bonzini }
141e0a5cfcaSPaolo Bonzini 
142e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_sti_nop(void)
143e0a5cfcaSPaolo Bonzini {
144e0a5cfcaSPaolo Bonzini 	irq_disable();
145e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
146e0a5cfcaSPaolo Bonzini 	asm volatile("sti; nop");
147e0a5cfcaSPaolo Bonzini }
148e0a5cfcaSPaolo Bonzini 
149e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_sti_hlt(void)
150e0a5cfcaSPaolo Bonzini {
151e0a5cfcaSPaolo Bonzini 	irq_disable();
152e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
153e0a5cfcaSPaolo Bonzini 	asm volatile("sti; hlt");
154e0a5cfcaSPaolo Bonzini }
155e0a5cfcaSPaolo Bonzini 
156e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr(void)
157e0a5cfcaSPaolo Bonzini {
158e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
159e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
160e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
161e0a5cfcaSPaolo Bonzini 	asm volatile("nop");
162e0a5cfcaSPaolo Bonzini }
163e0a5cfcaSPaolo Bonzini 
164e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr_sti_nop(void)
165e0a5cfcaSPaolo Bonzini {
166e0a5cfcaSPaolo Bonzini 	irq_disable();
167e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
168e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
169e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
170e0a5cfcaSPaolo Bonzini 	asm volatile("sti; nop");
171e0a5cfcaSPaolo Bonzini }
172e0a5cfcaSPaolo Bonzini 
173e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr_sti_hlt(void)
174e0a5cfcaSPaolo Bonzini {
175e0a5cfcaSPaolo Bonzini 	irq_disable();
176e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x0f);
177e0a5cfcaSPaolo Bonzini 	x2apic_self_ipi(IPI_TEST_VECTOR);
178e0a5cfcaSPaolo Bonzini 	apic_set_tpr(0x00);
179e0a5cfcaSPaolo Bonzini 	asm volatile("sti; hlt");
180e0a5cfcaSPaolo Bonzini }
181e0a5cfcaSPaolo 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 
390cfbd129cSPaolo Bonzini static int has_tscdeadline(void)
391cfbd129cSPaolo Bonzini {
392cfbd129cSPaolo Bonzini     uint32_t lvtt;
393cfbd129cSPaolo Bonzini 
394cfbd129cSPaolo Bonzini     if (cpuid(1).c & (1 << 24)) {
395cfbd129cSPaolo Bonzini         lvtt = APIC_LVT_TIMER_TSCDEADLINE | IPI_TEST_VECTOR;
396cfbd129cSPaolo Bonzini         apic_write(APIC_LVTT, lvtt);
397cfbd129cSPaolo Bonzini         return 1;
398cfbd129cSPaolo Bonzini     } else {
399cfbd129cSPaolo Bonzini         return 0;
400cfbd129cSPaolo Bonzini     }
401cfbd129cSPaolo Bonzini }
402cfbd129cSPaolo Bonzini 
403cfbd129cSPaolo Bonzini static void tscdeadline_immed(void)
404cfbd129cSPaolo Bonzini {
405cfbd129cSPaolo Bonzini 	wrmsr(MSR_IA32_TSCDEADLINE, rdtsc());
406cfbd129cSPaolo Bonzini 	asm volatile("nop");
407cfbd129cSPaolo Bonzini }
408cfbd129cSPaolo Bonzini 
409cfbd129cSPaolo Bonzini static void tscdeadline(void)
410cfbd129cSPaolo Bonzini {
411cfbd129cSPaolo Bonzini 	x = 0;
412cfbd129cSPaolo Bonzini 	wrmsr(MSR_IA32_TSCDEADLINE, rdtsc()+3000);
413cfbd129cSPaolo Bonzini 	while (x == 0) barrier();
414cfbd129cSPaolo Bonzini }
415cfbd129cSPaolo Bonzini 
4165292dbf7SMichael S. Tsirkin static struct test tests[] = {
417850479e3SJason Wang 	{ cpuid_test, "cpuid", .parallel = 1,  },
4187d36db35SAvi Kivity 	{ vmcall, "vmcall", .parallel = 1, },
4195ada505aSJason Wang #ifdef __x86_64__
4207d36db35SAvi Kivity 	{ mov_from_cr8, "mov_from_cr8", .parallel = 1, },
4217d36db35SAvi Kivity 	{ mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
4225ada505aSJason Wang #endif
4237d36db35SAvi Kivity 	{ inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
42400bfecaaSPaolo Bonzini 	{ inl_nop_qemu, "inl_from_qemu", .parallel = 1 },
42500bfecaaSPaolo Bonzini 	{ inl_nop_kernel, "inl_from_kernel", .parallel = 1 },
42600bfecaaSPaolo Bonzini 	{ outl_elcr_kernel, "outl_to_kernel", .parallel = 1 },
4278a544409SPaolo Bonzini 	{ mov_dr, "mov_dr", .parallel = 1 },
428cfbd129cSPaolo Bonzini 	{ tscdeadline_immed, "tscdeadline_immed", has_tscdeadline, .parallel = 1, },
429cfbd129cSPaolo Bonzini 	{ tscdeadline, "tscdeadline", has_tscdeadline, .parallel = 1, },
430e0a5cfcaSPaolo Bonzini 	{ self_ipi_sti_nop, "self_ipi_sti_nop", .parallel = 0, },
431e0a5cfcaSPaolo Bonzini 	{ self_ipi_sti_hlt, "self_ipi_sti_hlt", .parallel = 0, },
432e0a5cfcaSPaolo Bonzini 	{ self_ipi_tpr, "self_ipi_tpr", .parallel = 0, },
433e0a5cfcaSPaolo Bonzini 	{ self_ipi_tpr_sti_nop, "self_ipi_tpr_sti_nop", .parallel = 0, },
434e0a5cfcaSPaolo Bonzini 	{ self_ipi_tpr_sti_hlt, "self_ipi_tpr_sti_hlt", .parallel = 0, },
435e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_sti_nop, "x2apic_self_ipi_sti_nop", is_x2apic, .parallel = 0, },
436e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_sti_hlt, "x2apic_self_ipi_sti_hlt", is_x2apic, .parallel = 0, },
437e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_tpr, "x2apic_self_ipi_tpr", is_x2apic, .parallel = 0, },
438e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_tpr_sti_nop, "x2apic_self_ipi_tpr_sti_nop", is_x2apic, .parallel = 0, },
439e0a5cfcaSPaolo Bonzini 	{ x2apic_self_ipi_tpr_sti_hlt, "x2apic_self_ipi_tpr_sti_hlt", is_x2apic, .parallel = 0, },
4407d36db35SAvi Kivity 	{ ipi, "ipi", is_smp, .parallel = 0, },
441*cb37ca1eSSerg Titaevskiy 	{ ipi_halt, "ipi_halt", is_smp, .parallel = 0, },
442*cb37ca1eSSerg Titaevskiy 	{ ple_round_robin, "ple_round_robin", .parallel = 1 },
4435fecf5d8SWill Auld 	{ wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 },
4445fecf5d8SWill Auld 	{ rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 },
4455292dbf7SMichael S. Tsirkin 	{ NULL, "pci-mem", .parallel = 0, .next = pci_mem_next },
4465292dbf7SMichael S. Tsirkin 	{ NULL, "pci-io", .parallel = 0, .next = pci_io_next },
4477d36db35SAvi Kivity };
4487d36db35SAvi Kivity 
4497d36db35SAvi Kivity unsigned iterations;
4507d36db35SAvi Kivity 
4517d36db35SAvi Kivity static void run_test(void *_func)
4527d36db35SAvi Kivity {
4537d36db35SAvi Kivity     int i;
4547d36db35SAvi Kivity     void (*func)(void) = _func;
4557d36db35SAvi Kivity 
4567d36db35SAvi Kivity     for (i = 0; i < iterations; ++i)
4577d36db35SAvi Kivity         func();
4587d36db35SAvi Kivity }
4597d36db35SAvi Kivity 
4605292dbf7SMichael S. Tsirkin static bool do_test(struct test *test)
4617d36db35SAvi Kivity {
4627d36db35SAvi Kivity 	int i;
4637d36db35SAvi Kivity 	unsigned long long t1, t2;
4645292dbf7SMichael S. Tsirkin         void (*func)(void);
4657d36db35SAvi Kivity 
4667d36db35SAvi Kivity         iterations = 32;
4677d36db35SAvi Kivity 
4687d36db35SAvi Kivity         if (test->valid && !test->valid()) {
4697d36db35SAvi Kivity 		printf("%s (skipped)\n", test->name);
4705292dbf7SMichael S. Tsirkin 		return false;
4715292dbf7SMichael S. Tsirkin 	}
4725292dbf7SMichael S. Tsirkin 
4735292dbf7SMichael S. Tsirkin 	if (test->next && !test->next(test)) {
4745292dbf7SMichael S. Tsirkin 		return false;
4755292dbf7SMichael S. Tsirkin 	}
4765292dbf7SMichael S. Tsirkin 
4775292dbf7SMichael S. Tsirkin 	func = test->func;
4785292dbf7SMichael S. Tsirkin         if (!func) {
4795292dbf7SMichael S. Tsirkin 		printf("%s (skipped)\n", test->name);
4805292dbf7SMichael S. Tsirkin 		return false;
4817d36db35SAvi Kivity 	}
4827d36db35SAvi Kivity 
4837d36db35SAvi Kivity 	do {
4847d36db35SAvi Kivity 		iterations *= 2;
4857d36db35SAvi Kivity 		t1 = rdtsc();
4867d36db35SAvi Kivity 
4877d36db35SAvi Kivity 		if (!test->parallel) {
4887d36db35SAvi Kivity 			for (i = 0; i < iterations; ++i)
4897d36db35SAvi Kivity 				func();
4907d36db35SAvi Kivity 		} else {
491b171c8c0SAndrew Jones 			on_cpus(run_test, func);
4927d36db35SAvi Kivity 		}
4937d36db35SAvi Kivity 		t2 = rdtsc();
4947d36db35SAvi Kivity 	} while ((t2 - t1) < GOAL);
4957d36db35SAvi Kivity 	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
4965292dbf7SMichael S. Tsirkin 	return test->next;
4977d36db35SAvi Kivity }
4987d36db35SAvi Kivity 
4997d36db35SAvi Kivity static void enable_nx(void *junk)
5007d36db35SAvi Kivity {
501e46b32aaSAvi Kivity 	if (cpuid(0x80000001).d & (1 << 20))
5027d36db35SAvi Kivity 		wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
5037d36db35SAvi Kivity }
5047d36db35SAvi Kivity 
5050b267183SAvi Kivity bool test_wanted(struct test *test, char *wanted[], int nwanted)
5060b267183SAvi Kivity {
5070b267183SAvi Kivity 	int i;
5080b267183SAvi Kivity 
5090b267183SAvi Kivity 	if (!nwanted)
5100b267183SAvi Kivity 		return true;
5110b267183SAvi Kivity 
5120b267183SAvi Kivity 	for (i = 0; i < nwanted; ++i)
5130b267183SAvi Kivity 		if (strcmp(wanted[i], test->name) == 0)
5140b267183SAvi Kivity 			return true;
5150b267183SAvi Kivity 
5160b267183SAvi Kivity 	return false;
5170b267183SAvi Kivity }
5180b267183SAvi Kivity 
5190b267183SAvi Kivity int main(int ac, char **av)
5207d36db35SAvi Kivity {
521a5d12b9fSPaolo Bonzini 	struct fadt_descriptor_rev1 *fadt;
5227d36db35SAvi Kivity 	int i;
523f1abb07bSAlexander Gordeev 	unsigned long membar = 0;
5244d6cefa9SPeter Xu 	struct pci_dev pcidev;
5254d6cefa9SPeter Xu 	int ret;
5267d36db35SAvi Kivity 
5277d36db35SAvi Kivity 	smp_init();
5285292dbf7SMichael S. Tsirkin 	setup_vm();
529e0a5cfcaSPaolo Bonzini 	handle_irq(IPI_TEST_VECTOR, self_ipi_isr);
530eda71b28SAvi Kivity 	nr_cpus = cpu_count();
5317d36db35SAvi Kivity 
532e0a5cfcaSPaolo Bonzini 	irq_enable();
533b171c8c0SAndrew Jones 	on_cpus(enable_nx, NULL);
5347d36db35SAvi Kivity 
535a5d12b9fSPaolo Bonzini 	fadt = find_acpi_table_addr(FACP_SIGNATURE);
536a5d12b9fSPaolo Bonzini 	pm_tmr_blk = fadt->pm_tmr_blk;
537a5d12b9fSPaolo Bonzini 	printf("PM timer port is %x\n", pm_tmr_blk);
538a5d12b9fSPaolo Bonzini 
5394d6cefa9SPeter Xu 	ret = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
5404d6cefa9SPeter Xu 	if (ret != PCIDEVADDR_INVALID) {
5414d6cefa9SPeter Xu 		pci_dev_init(&pcidev, ret);
542e954ce23SPeter Xu 		assert(pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_MEM));
543e954ce23SPeter Xu 		assert(!pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_IO));
544e954ce23SPeter Xu 		membar = pcidev.resource[PCI_TESTDEV_BAR_MEM];
545f1abb07bSAlexander Gordeev 		pci_test.memaddr = ioremap(membar, PAGE_SIZE);
546e954ce23SPeter Xu 		pci_test.iobar = pcidev.resource[PCI_TESTDEV_BAR_IO];
547fd6aada0SRadim Krčmář 		printf("pci-testdev at %#x membar %lx iobar %x\n",
5484d6cefa9SPeter Xu 		       pcidev.bdf, membar, pci_test.iobar);
5495292dbf7SMichael S. Tsirkin 	}
5505292dbf7SMichael S. Tsirkin 
5517d36db35SAvi Kivity 	for (i = 0; i < ARRAY_SIZE(tests); ++i)
5520b267183SAvi Kivity 		if (test_wanted(&tests[i], av + 1, ac - 1))
5535292dbf7SMichael S. Tsirkin 			while (do_test(&tests[i])) {}
5547d36db35SAvi Kivity 
5557d36db35SAvi Kivity 	return 0;
5567d36db35SAvi Kivity }
557