17d36db35SAvi Kivity #include "libcflat.h"
2670b1f54SNikos Nikoleris #include "acpi.h"
37d36db35SAvi Kivity #include "smp.h"
4*95a94088SNicholas Piggin #include "vmalloc.h"
5456c55bcSAndrew Jones #include "pci.h"
65292dbf7SMichael S. Tsirkin #include "x86/vm.h"
75292dbf7SMichael S. Tsirkin #include "x86/desc.h"
8e0a5cfcaSPaolo Bonzini #include "x86/apic.h"
9e0a5cfcaSPaolo Bonzini #include "x86/isr.h"
10e0a5cfcaSPaolo Bonzini
11e0a5cfcaSPaolo Bonzini #define IPI_TEST_VECTOR 0xb0
127d36db35SAvi Kivity
135292dbf7SMichael S. Tsirkin struct test {
145292dbf7SMichael S. Tsirkin void (*func)(void);
155292dbf7SMichael S. Tsirkin const char *name;
165292dbf7SMichael S. Tsirkin int (*valid)(void);
175292dbf7SMichael S. Tsirkin int parallel;
185292dbf7SMichael S. Tsirkin bool (*next)(struct test *);
195292dbf7SMichael S. Tsirkin };
205292dbf7SMichael S. Tsirkin
217d36db35SAvi Kivity #define GOAL (1ull << 30)
227d36db35SAvi Kivity
23eda71b28SAvi Kivity static int nr_cpus;
2457c063c5SPaolo Bonzini static u64 cr4_shadow;
25eda71b28SAvi Kivity
cpuid_test(void)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
vmcall(void)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
397d36db35SAvi Kivity #define MSR_EFER 0xc0000080
407d36db35SAvi Kivity #define EFER_NX_MASK (1ull << 11)
417d36db35SAvi Kivity
425ada505aSJason Wang #ifdef __x86_64__
mov_from_cr8(void)437d36db35SAvi Kivity static void mov_from_cr8(void)
447d36db35SAvi Kivity {
457d36db35SAvi Kivity unsigned long cr8;
467d36db35SAvi Kivity
477d36db35SAvi Kivity asm volatile ("mov %%cr8, %0" : "=r"(cr8));
487d36db35SAvi Kivity }
497d36db35SAvi Kivity
mov_to_cr8(void)507d36db35SAvi Kivity static void mov_to_cr8(void)
517d36db35SAvi Kivity {
527d36db35SAvi Kivity unsigned long cr8 = 0;
537d36db35SAvi Kivity
547d36db35SAvi Kivity asm volatile ("mov %0, %%cr8" : : "r"(cr8));
557d36db35SAvi Kivity }
565ada505aSJason Wang #endif
577d36db35SAvi Kivity
is_smp(void)587d36db35SAvi Kivity static int is_smp(void)
597d36db35SAvi Kivity {
607d36db35SAvi Kivity return cpu_count() > 1;
617d36db35SAvi Kivity }
627d36db35SAvi Kivity
nop(void * junk)637d36db35SAvi Kivity static void nop(void *junk)
647d36db35SAvi Kivity {
657d36db35SAvi Kivity }
667d36db35SAvi Kivity
67e0a5cfcaSPaolo Bonzini volatile int x = 0;
688a8c1fc3SPaolo Bonzini volatile uint64_t tsc_eoi = 0;
698a8c1fc3SPaolo Bonzini volatile uint64_t tsc_ipi = 0;
70e0a5cfcaSPaolo Bonzini
self_ipi_isr(isr_regs_t * regs)71e0a5cfcaSPaolo Bonzini static void self_ipi_isr(isr_regs_t *regs)
72e0a5cfcaSPaolo Bonzini {
73e0a5cfcaSPaolo Bonzini x++;
748a8c1fc3SPaolo Bonzini uint64_t start = rdtsc();
75e0a5cfcaSPaolo Bonzini eoi();
768a8c1fc3SPaolo Bonzini tsc_eoi += rdtsc() - start;
77e0a5cfcaSPaolo Bonzini }
78e0a5cfcaSPaolo Bonzini
x2apic_self_ipi(int vec)79e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi(int vec)
80e0a5cfcaSPaolo Bonzini {
818a8c1fc3SPaolo Bonzini uint64_t start = rdtsc();
82e0a5cfcaSPaolo Bonzini wrmsr(0x83f, vec);
838a8c1fc3SPaolo Bonzini tsc_ipi += rdtsc() - start;
84e0a5cfcaSPaolo Bonzini }
85e0a5cfcaSPaolo Bonzini
apic_self_ipi(int vec)86e0a5cfcaSPaolo Bonzini static void apic_self_ipi(int vec)
87e0a5cfcaSPaolo Bonzini {
888a8c1fc3SPaolo Bonzini uint64_t start = rdtsc();
89e0a5cfcaSPaolo Bonzini apic_icr_write(APIC_INT_ASSERT | APIC_DEST_SELF | APIC_DEST_PHYSICAL |
90e0a5cfcaSPaolo Bonzini APIC_DM_FIXED | IPI_TEST_VECTOR, vec);
918a8c1fc3SPaolo Bonzini tsc_ipi += rdtsc() - start;
92e0a5cfcaSPaolo Bonzini }
93e0a5cfcaSPaolo Bonzini
self_ipi_sti_nop(void)94e0a5cfcaSPaolo Bonzini static void self_ipi_sti_nop(void)
95e0a5cfcaSPaolo Bonzini {
96e0a5cfcaSPaolo Bonzini x = 0;
97787f0aebSMaxim Levitsky cli();
98e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR);
99e0a5cfcaSPaolo Bonzini asm volatile("sti; nop");
100e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x);
101e0a5cfcaSPaolo Bonzini }
102e0a5cfcaSPaolo Bonzini
self_ipi_sti_hlt(void)103e0a5cfcaSPaolo Bonzini static void self_ipi_sti_hlt(void)
104e0a5cfcaSPaolo Bonzini {
105e0a5cfcaSPaolo Bonzini x = 0;
106787f0aebSMaxim Levitsky cli();
107e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR);
108a3001422SOliver Upton safe_halt();
109e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x);
110e0a5cfcaSPaolo Bonzini }
111e0a5cfcaSPaolo Bonzini
self_ipi_tpr(void)112e0a5cfcaSPaolo Bonzini static void self_ipi_tpr(void)
113e0a5cfcaSPaolo Bonzini {
114e0a5cfcaSPaolo Bonzini x = 0;
115e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f);
116e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR);
117e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00);
118e0a5cfcaSPaolo Bonzini asm volatile("nop");
119e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x);
120e0a5cfcaSPaolo Bonzini }
121e0a5cfcaSPaolo Bonzini
self_ipi_tpr_sti_nop(void)122e0a5cfcaSPaolo Bonzini static void self_ipi_tpr_sti_nop(void)
123e0a5cfcaSPaolo Bonzini {
124e0a5cfcaSPaolo Bonzini x = 0;
125787f0aebSMaxim Levitsky cli();
126e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f);
127e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR);
128e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00);
129e0a5cfcaSPaolo Bonzini asm volatile("sti; nop");
130e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x);
131e0a5cfcaSPaolo Bonzini }
132e0a5cfcaSPaolo Bonzini
self_ipi_tpr_sti_hlt(void)133e0a5cfcaSPaolo Bonzini static void self_ipi_tpr_sti_hlt(void)
134e0a5cfcaSPaolo Bonzini {
135e0a5cfcaSPaolo Bonzini x = 0;
136787f0aebSMaxim Levitsky cli();
137e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f);
138e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR);
139e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00);
140a3001422SOliver Upton safe_halt();
141e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x);
142e0a5cfcaSPaolo Bonzini }
143e0a5cfcaSPaolo Bonzini
is_x2apic(void)144e0a5cfcaSPaolo Bonzini static int is_x2apic(void)
145e0a5cfcaSPaolo Bonzini {
146e0a5cfcaSPaolo Bonzini return rdmsr(MSR_IA32_APICBASE) & APIC_EXTD;
147e0a5cfcaSPaolo Bonzini }
148e0a5cfcaSPaolo Bonzini
x2apic_self_ipi_sti_nop(void)149e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_sti_nop(void)
150e0a5cfcaSPaolo Bonzini {
151787f0aebSMaxim Levitsky cli();
152e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR);
153e0a5cfcaSPaolo Bonzini asm volatile("sti; nop");
154e0a5cfcaSPaolo Bonzini }
155e0a5cfcaSPaolo Bonzini
x2apic_self_ipi_sti_hlt(void)156e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_sti_hlt(void)
157e0a5cfcaSPaolo Bonzini {
158787f0aebSMaxim Levitsky cli();
159e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR);
160a3001422SOliver Upton safe_halt();
161e0a5cfcaSPaolo Bonzini }
162e0a5cfcaSPaolo Bonzini
x2apic_self_ipi_tpr(void)163e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr(void)
164e0a5cfcaSPaolo Bonzini {
165e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f);
166e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR);
167e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00);
168e0a5cfcaSPaolo Bonzini asm volatile("nop");
169e0a5cfcaSPaolo Bonzini }
170e0a5cfcaSPaolo Bonzini
x2apic_self_ipi_tpr_sti_nop(void)171e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr_sti_nop(void)
172e0a5cfcaSPaolo Bonzini {
173787f0aebSMaxim Levitsky cli();
174e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f);
175e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR);
176e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00);
177e0a5cfcaSPaolo Bonzini asm volatile("sti; nop");
178e0a5cfcaSPaolo Bonzini }
179e0a5cfcaSPaolo Bonzini
x2apic_self_ipi_tpr_sti_hlt(void)180e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr_sti_hlt(void)
181e0a5cfcaSPaolo Bonzini {
182787f0aebSMaxim Levitsky cli();
183e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f);
184e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR);
185e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00);
186a3001422SOliver Upton safe_halt();
187e0a5cfcaSPaolo Bonzini }
188e0a5cfcaSPaolo Bonzini
ipi(void)1897d36db35SAvi Kivity static void ipi(void)
1907d36db35SAvi Kivity {
1918a8c1fc3SPaolo Bonzini uint64_t start = rdtsc();
1927d36db35SAvi Kivity on_cpu(1, nop, 0);
1938a8c1fc3SPaolo Bonzini tsc_ipi += rdtsc() - start;
1947d36db35SAvi Kivity }
1957d36db35SAvi Kivity
ipi_halt(void)1967d36db35SAvi Kivity static void ipi_halt(void)
1977d36db35SAvi Kivity {
1987d36db35SAvi Kivity unsigned long long t;
1997d36db35SAvi Kivity
2007d36db35SAvi Kivity on_cpu(1, nop, 0);
2017d36db35SAvi Kivity t = rdtsc() + 2000;
2027d36db35SAvi Kivity while (rdtsc() < t)
2037d36db35SAvi Kivity ;
2047d36db35SAvi Kivity }
2057d36db35SAvi Kivity
206a5d12b9fSPaolo Bonzini int pm_tmr_blk;
inl_pmtimer(void)2077d36db35SAvi Kivity static void inl_pmtimer(void)
2087d36db35SAvi Kivity {
2091982ff44SSean Christopherson if (!pm_tmr_blk) {
21064cd0cc1SNikos Nikoleris struct acpi_table_fadt *fadt;
2111982ff44SSean Christopherson
2121982ff44SSean Christopherson fadt = find_acpi_table_addr(FACP_SIGNATURE);
2131982ff44SSean Christopherson pm_tmr_blk = fadt->pm_tmr_blk;
2141982ff44SSean Christopherson printf("PM timer port is %x\n", pm_tmr_blk);
2151982ff44SSean Christopherson }
216a5d12b9fSPaolo Bonzini inl(pm_tmr_blk);
2177d36db35SAvi Kivity }
2187d36db35SAvi Kivity
inl_nop_qemu(void)21900bfecaaSPaolo Bonzini static void inl_nop_qemu(void)
22000bfecaaSPaolo Bonzini {
22100bfecaaSPaolo Bonzini inl(0x1234);
22200bfecaaSPaolo Bonzini }
22300bfecaaSPaolo Bonzini
inl_nop_kernel(void)22400bfecaaSPaolo Bonzini static void inl_nop_kernel(void)
22500bfecaaSPaolo Bonzini {
22600bfecaaSPaolo Bonzini inb(0x4d0);
22700bfecaaSPaolo Bonzini }
22800bfecaaSPaolo Bonzini
outl_elcr_kernel(void)22900bfecaaSPaolo Bonzini static void outl_elcr_kernel(void)
23000bfecaaSPaolo Bonzini {
231f22a66a1SAndrew Jones outb(0, 0x4d0);
23200bfecaaSPaolo Bonzini }
23300bfecaaSPaolo Bonzini
mov_dr(void)2348a544409SPaolo Bonzini static void mov_dr(void)
2358a544409SPaolo Bonzini {
2368a544409SPaolo Bonzini asm volatile("mov %0, %%dr7" : : "r" (0x400L));
2378a544409SPaolo Bonzini }
2388a544409SPaolo Bonzini
ple_round_robin(void)239eda71b28SAvi Kivity static void ple_round_robin(void)
240eda71b28SAvi Kivity {
241eda71b28SAvi Kivity struct counter {
242eda71b28SAvi Kivity volatile int n1;
243eda71b28SAvi Kivity int n2;
244eda71b28SAvi Kivity } __attribute__((aligned(64)));
245eda71b28SAvi Kivity static struct counter counters[64] = { { -1, 0 } };
246eda71b28SAvi Kivity int me = smp_id();
247eda71b28SAvi Kivity int you;
248eda71b28SAvi Kivity volatile struct counter *p = &counters[me];
249eda71b28SAvi Kivity
250eda71b28SAvi Kivity while (p->n1 == p->n2)
251eda71b28SAvi Kivity asm volatile ("pause");
252eda71b28SAvi Kivity
253eda71b28SAvi Kivity p->n2 = p->n1;
254eda71b28SAvi Kivity you = me + 1;
255eda71b28SAvi Kivity if (you == nr_cpus)
256eda71b28SAvi Kivity you = 0;
257eda71b28SAvi Kivity ++counters[you].n1;
258eda71b28SAvi Kivity }
259eda71b28SAvi Kivity
rd_tsc_adjust_msr(void)2605fecf5d8SWill Auld static void rd_tsc_adjust_msr(void)
2615fecf5d8SWill Auld {
2622352e986SPaolo Bonzini rdmsr(MSR_IA32_TSC_ADJUST);
2635fecf5d8SWill Auld }
2645fecf5d8SWill Auld
wr_tsc_adjust_msr(void)2655fecf5d8SWill Auld static void wr_tsc_adjust_msr(void)
2665fecf5d8SWill Auld {
2672352e986SPaolo Bonzini wrmsr(MSR_IA32_TSC_ADJUST, 0x0);
2685fecf5d8SWill Auld }
2695fecf5d8SWill Auld
wr_kernel_gs_base(void)2709e018cb8SPaolo Bonzini static void wr_kernel_gs_base(void)
2719e018cb8SPaolo Bonzini {
2729e018cb8SPaolo Bonzini wrmsr(MSR_KERNEL_GS_BASE, 0x0);
2739e018cb8SPaolo Bonzini }
2749e018cb8SPaolo Bonzini
2755292dbf7SMichael S. Tsirkin static struct pci_test {
2765292dbf7SMichael S. Tsirkin unsigned iobar;
2775292dbf7SMichael S. Tsirkin unsigned ioport;
2785292dbf7SMichael S. Tsirkin volatile void *memaddr;
2795292dbf7SMichael S. Tsirkin volatile void *mem;
2805292dbf7SMichael S. Tsirkin int test_idx;
2815292dbf7SMichael S. Tsirkin uint32_t data;
2825292dbf7SMichael S. Tsirkin uint32_t offset;
2835292dbf7SMichael S. Tsirkin } pci_test = {
2845292dbf7SMichael S. Tsirkin .test_idx = -1
2855292dbf7SMichael S. Tsirkin };
2865292dbf7SMichael S. Tsirkin
pci_mem_testb(void)2875292dbf7SMichael S. Tsirkin static void pci_mem_testb(void)
2885292dbf7SMichael S. Tsirkin {
2895292dbf7SMichael S. Tsirkin *(volatile uint8_t *)pci_test.mem = pci_test.data;
2905292dbf7SMichael S. Tsirkin }
2915292dbf7SMichael S. Tsirkin
pci_mem_testw(void)2925292dbf7SMichael S. Tsirkin static void pci_mem_testw(void)
2935292dbf7SMichael S. Tsirkin {
2945292dbf7SMichael S. Tsirkin *(volatile uint16_t *)pci_test.mem = pci_test.data;
2955292dbf7SMichael S. Tsirkin }
2965292dbf7SMichael S. Tsirkin
pci_mem_testl(void)2975292dbf7SMichael S. Tsirkin static void pci_mem_testl(void)
2985292dbf7SMichael S. Tsirkin {
2995292dbf7SMichael S. Tsirkin *(volatile uint32_t *)pci_test.mem = pci_test.data;
3005292dbf7SMichael S. Tsirkin }
3015292dbf7SMichael S. Tsirkin
pci_io_testb(void)3025292dbf7SMichael S. Tsirkin static void pci_io_testb(void)
3035292dbf7SMichael S. Tsirkin {
304f22a66a1SAndrew Jones outb(pci_test.data, pci_test.ioport);
3055292dbf7SMichael S. Tsirkin }
3065292dbf7SMichael S. Tsirkin
pci_io_testw(void)3075292dbf7SMichael S. Tsirkin static void pci_io_testw(void)
3085292dbf7SMichael S. Tsirkin {
309f22a66a1SAndrew Jones outw(pci_test.data, pci_test.ioport);
3105292dbf7SMichael S. Tsirkin }
3115292dbf7SMichael S. Tsirkin
pci_io_testl(void)3125292dbf7SMichael S. Tsirkin static void pci_io_testl(void)
3135292dbf7SMichael S. Tsirkin {
314f22a66a1SAndrew Jones outl(pci_test.data, pci_test.ioport);
3155292dbf7SMichael S. Tsirkin }
3165292dbf7SMichael S. Tsirkin
ioreadb(unsigned long addr,bool io)3175292dbf7SMichael S. Tsirkin static uint8_t ioreadb(unsigned long addr, bool io)
3185292dbf7SMichael S. Tsirkin {
3195292dbf7SMichael S. Tsirkin if (io) {
3205292dbf7SMichael S. Tsirkin return inb(addr);
3215292dbf7SMichael S. Tsirkin } else {
3225292dbf7SMichael S. Tsirkin return *(volatile uint8_t *)addr;
3235292dbf7SMichael S. Tsirkin }
3245292dbf7SMichael S. Tsirkin }
3255292dbf7SMichael S. Tsirkin
ioreadl(unsigned long addr,bool io)3265292dbf7SMichael S. Tsirkin static uint32_t ioreadl(unsigned long addr, bool io)
3275292dbf7SMichael S. Tsirkin {
3285292dbf7SMichael S. Tsirkin /* Note: assumes little endian */
3295292dbf7SMichael S. Tsirkin if (io) {
3305292dbf7SMichael S. Tsirkin return inl(addr);
3315292dbf7SMichael S. Tsirkin } else {
3325292dbf7SMichael S. Tsirkin return *(volatile uint32_t *)addr;
3335292dbf7SMichael S. Tsirkin }
3345292dbf7SMichael S. Tsirkin }
3355292dbf7SMichael S. Tsirkin
iowriteb(unsigned long addr,uint8_t data,bool io)3365292dbf7SMichael S. Tsirkin static void iowriteb(unsigned long addr, uint8_t data, bool io)
3375292dbf7SMichael S. Tsirkin {
3385292dbf7SMichael S. Tsirkin if (io) {
339f22a66a1SAndrew Jones outb(data, addr);
3405292dbf7SMichael S. Tsirkin } else {
3415292dbf7SMichael S. Tsirkin *(volatile uint8_t *)addr = data;
3425292dbf7SMichael S. Tsirkin }
3435292dbf7SMichael S. Tsirkin }
3445292dbf7SMichael S. Tsirkin
pci_next(struct test * test,unsigned long addr,bool io)3455292dbf7SMichael S. Tsirkin static bool pci_next(struct test *test, unsigned long addr, bool io)
3465292dbf7SMichael S. Tsirkin {
3475292dbf7SMichael S. Tsirkin int i;
3485292dbf7SMichael S. Tsirkin uint8_t width;
3495292dbf7SMichael S. Tsirkin
3505292dbf7SMichael S. Tsirkin if (!pci_test.memaddr) {
3515292dbf7SMichael S. Tsirkin test->func = NULL;
3525292dbf7SMichael S. Tsirkin return true;
3535292dbf7SMichael S. Tsirkin }
3545292dbf7SMichael S. Tsirkin pci_test.test_idx++;
3555292dbf7SMichael S. Tsirkin iowriteb(addr + offsetof(struct pci_test_dev_hdr, test),
3565292dbf7SMichael S. Tsirkin pci_test.test_idx, io);
3575292dbf7SMichael S. Tsirkin width = ioreadb(addr + offsetof(struct pci_test_dev_hdr, width),
3585292dbf7SMichael S. Tsirkin io);
3595292dbf7SMichael S. Tsirkin switch (width) {
3605292dbf7SMichael S. Tsirkin case 1:
3615292dbf7SMichael S. Tsirkin test->func = io ? pci_io_testb : pci_mem_testb;
3625292dbf7SMichael S. Tsirkin break;
3635292dbf7SMichael S. Tsirkin case 2:
3645292dbf7SMichael S. Tsirkin test->func = io ? pci_io_testw : pci_mem_testw;
3655292dbf7SMichael S. Tsirkin break;
3665292dbf7SMichael S. Tsirkin case 4:
3675292dbf7SMichael S. Tsirkin test->func = io ? pci_io_testl : pci_mem_testl;
3685292dbf7SMichael S. Tsirkin break;
3695292dbf7SMichael S. Tsirkin default:
3705292dbf7SMichael S. Tsirkin /* Reset index for purposes of the next test */
3715292dbf7SMichael S. Tsirkin pci_test.test_idx = -1;
3725292dbf7SMichael S. Tsirkin test->func = NULL;
3735292dbf7SMichael S. Tsirkin return false;
3745292dbf7SMichael S. Tsirkin }
3755292dbf7SMichael S. Tsirkin pci_test.data = ioreadl(addr + offsetof(struct pci_test_dev_hdr, data),
3765292dbf7SMichael S. Tsirkin io);
3775292dbf7SMichael S. Tsirkin pci_test.offset = ioreadl(addr + offsetof(struct pci_test_dev_hdr,
3785292dbf7SMichael S. Tsirkin offset), io);
3795292dbf7SMichael S. Tsirkin for (i = 0; i < pci_test.offset; ++i) {
3805292dbf7SMichael S. Tsirkin char c = ioreadb(addr + offsetof(struct pci_test_dev_hdr,
3815292dbf7SMichael S. Tsirkin name) + i, io);
3825292dbf7SMichael S. Tsirkin if (!c) {
3835292dbf7SMichael S. Tsirkin break;
3845292dbf7SMichael S. Tsirkin }
3855292dbf7SMichael S. Tsirkin printf("%c",c);
3865292dbf7SMichael S. Tsirkin }
3875292dbf7SMichael S. Tsirkin printf(":");
3885292dbf7SMichael S. Tsirkin return true;
3895292dbf7SMichael S. Tsirkin }
3905292dbf7SMichael S. Tsirkin
pci_mem_next(struct test * test)3915292dbf7SMichael S. Tsirkin static bool pci_mem_next(struct test *test)
3925292dbf7SMichael S. Tsirkin {
3935292dbf7SMichael S. Tsirkin bool ret;
3945292dbf7SMichael S. Tsirkin ret = pci_next(test, ((unsigned long)pci_test.memaddr), false);
3955292dbf7SMichael S. Tsirkin if (ret) {
3965292dbf7SMichael S. Tsirkin pci_test.mem = pci_test.memaddr + pci_test.offset;
3975292dbf7SMichael S. Tsirkin }
3985292dbf7SMichael S. Tsirkin return ret;
3995292dbf7SMichael S. Tsirkin }
4005292dbf7SMichael S. Tsirkin
pci_io_next(struct test * test)4015292dbf7SMichael S. Tsirkin static bool pci_io_next(struct test *test)
4025292dbf7SMichael S. Tsirkin {
4035292dbf7SMichael S. Tsirkin bool ret;
4045292dbf7SMichael S. Tsirkin ret = pci_next(test, ((unsigned long)pci_test.iobar), true);
4055292dbf7SMichael S. Tsirkin if (ret) {
4065292dbf7SMichael S. Tsirkin pci_test.ioport = pci_test.iobar + pci_test.offset;
4075292dbf7SMichael S. Tsirkin }
4085292dbf7SMichael S. Tsirkin return ret;
4095292dbf7SMichael S. Tsirkin }
4105292dbf7SMichael S. Tsirkin
has_tscdeadline(void)411cfbd129cSPaolo Bonzini static int has_tscdeadline(void)
412cfbd129cSPaolo Bonzini {
413cfbd129cSPaolo Bonzini uint32_t lvtt;
414cfbd129cSPaolo Bonzini
415badc98caSKrish Sadhukhan if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) {
416cfbd129cSPaolo Bonzini lvtt = APIC_LVT_TIMER_TSCDEADLINE | IPI_TEST_VECTOR;
417cfbd129cSPaolo Bonzini apic_write(APIC_LVTT, lvtt);
418cfbd129cSPaolo Bonzini return 1;
419cfbd129cSPaolo Bonzini } else {
420cfbd129cSPaolo Bonzini return 0;
421cfbd129cSPaolo Bonzini }
422cfbd129cSPaolo Bonzini }
423cfbd129cSPaolo Bonzini
tscdeadline_immed(void)424cfbd129cSPaolo Bonzini static void tscdeadline_immed(void)
425cfbd129cSPaolo Bonzini {
426cfbd129cSPaolo Bonzini wrmsr(MSR_IA32_TSCDEADLINE, rdtsc());
427cfbd129cSPaolo Bonzini asm volatile("nop");
428cfbd129cSPaolo Bonzini }
429cfbd129cSPaolo Bonzini
tscdeadline(void)430cfbd129cSPaolo Bonzini static void tscdeadline(void)
431cfbd129cSPaolo Bonzini {
432cfbd129cSPaolo Bonzini x = 0;
433cfbd129cSPaolo Bonzini wrmsr(MSR_IA32_TSCDEADLINE, rdtsc()+3000);
434cfbd129cSPaolo Bonzini while (x == 0) barrier();
435cfbd129cSPaolo Bonzini }
436cfbd129cSPaolo Bonzini
wr_tsx_ctrl_msr(void)4376163f75dSPaolo Bonzini static void wr_tsx_ctrl_msr(void)
4386163f75dSPaolo Bonzini {
4396163f75dSPaolo Bonzini wrmsr(MSR_IA32_TSX_CTRL, 0);
4406163f75dSPaolo Bonzini }
4416163f75dSPaolo Bonzini
has_tsx_ctrl(void)4426163f75dSPaolo Bonzini static int has_tsx_ctrl(void)
4436163f75dSPaolo Bonzini {
44445472bc5SSean Christopherson return this_cpu_has(X86_FEATURE_ARCH_CAPABILITIES) &&
44545472bc5SSean Christopherson (rdmsr(MSR_IA32_ARCH_CAPABILITIES) & ARCH_CAP_TSX_CTRL_MSR);
4466163f75dSPaolo Bonzini }
4476163f75dSPaolo Bonzini
wr_ibrs_msr(void)448f2665de7SPaolo Bonzini static void wr_ibrs_msr(void)
449f2665de7SPaolo Bonzini {
450f2665de7SPaolo Bonzini wrmsr(MSR_IA32_SPEC_CTRL, 1);
451f2665de7SPaolo Bonzini wrmsr(MSR_IA32_SPEC_CTRL, 0);
452f2665de7SPaolo Bonzini }
453f2665de7SPaolo Bonzini
has_ibpb(void)454f2665de7SPaolo Bonzini static int has_ibpb(void)
455f2665de7SPaolo Bonzini {
45645472bc5SSean Christopherson return this_cpu_has(X86_FEATURE_SPEC_CTRL) ||
45745472bc5SSean Christopherson this_cpu_has(X86_FEATURE_AMD_IBPB);
45845472bc5SSean Christopherson }
45945472bc5SSean Christopherson
has_spec_ctrl(void)46045472bc5SSean Christopherson static int has_spec_ctrl(void)
46145472bc5SSean Christopherson {
46245472bc5SSean Christopherson return this_cpu_has(X86_FEATURE_SPEC_CTRL);
463f2665de7SPaolo Bonzini }
464f2665de7SPaolo Bonzini
wr_ibpb_msr(void)465f2665de7SPaolo Bonzini static void wr_ibpb_msr(void)
466f2665de7SPaolo Bonzini {
4674fba1a2cSSean Christopherson wrmsr(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
468f2665de7SPaolo Bonzini }
469f2665de7SPaolo Bonzini
toggle_cr0_wp(void)47057c063c5SPaolo Bonzini static void toggle_cr0_wp(void)
47157c063c5SPaolo Bonzini {
47257c063c5SPaolo Bonzini write_cr0(X86_CR0_PE|X86_CR0_PG);
47357c063c5SPaolo Bonzini write_cr0(X86_CR0_PE|X86_CR0_WP|X86_CR0_PG);
47457c063c5SPaolo Bonzini }
47557c063c5SPaolo Bonzini
toggle_cr4_pge(void)47657c063c5SPaolo Bonzini static void toggle_cr4_pge(void)
47757c063c5SPaolo Bonzini {
47857c063c5SPaolo Bonzini write_cr4(cr4_shadow ^ X86_CR4_PGE);
47957c063c5SPaolo Bonzini write_cr4(cr4_shadow);
48057c063c5SPaolo Bonzini }
48157c063c5SPaolo Bonzini
4825292dbf7SMichael S. Tsirkin static struct test tests[] = {
483850479e3SJason Wang { cpuid_test, "cpuid", .parallel = 1, },
4847d36db35SAvi Kivity { vmcall, "vmcall", .parallel = 1, },
4855ada505aSJason Wang #ifdef __x86_64__
4867d36db35SAvi Kivity { mov_from_cr8, "mov_from_cr8", .parallel = 1, },
4877d36db35SAvi Kivity { mov_to_cr8, "mov_to_cr8" , .parallel = 1, },
4885ada505aSJason Wang #endif
4897d36db35SAvi Kivity { inl_pmtimer, "inl_from_pmtimer", .parallel = 1, },
49000bfecaaSPaolo Bonzini { inl_nop_qemu, "inl_from_qemu", .parallel = 1 },
49100bfecaaSPaolo Bonzini { inl_nop_kernel, "inl_from_kernel", .parallel = 1 },
49200bfecaaSPaolo Bonzini { outl_elcr_kernel, "outl_to_kernel", .parallel = 1 },
4938a544409SPaolo Bonzini { mov_dr, "mov_dr", .parallel = 1 },
494cfbd129cSPaolo Bonzini { tscdeadline_immed, "tscdeadline_immed", has_tscdeadline, .parallel = 1, },
495cfbd129cSPaolo Bonzini { tscdeadline, "tscdeadline", has_tscdeadline, .parallel = 1, },
496e0a5cfcaSPaolo Bonzini { self_ipi_sti_nop, "self_ipi_sti_nop", .parallel = 0, },
497e0a5cfcaSPaolo Bonzini { self_ipi_sti_hlt, "self_ipi_sti_hlt", .parallel = 0, },
498e0a5cfcaSPaolo Bonzini { self_ipi_tpr, "self_ipi_tpr", .parallel = 0, },
499e0a5cfcaSPaolo Bonzini { self_ipi_tpr_sti_nop, "self_ipi_tpr_sti_nop", .parallel = 0, },
500e0a5cfcaSPaolo Bonzini { self_ipi_tpr_sti_hlt, "self_ipi_tpr_sti_hlt", .parallel = 0, },
501e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_sti_nop, "x2apic_self_ipi_sti_nop", is_x2apic, .parallel = 0, },
502e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_sti_hlt, "x2apic_self_ipi_sti_hlt", is_x2apic, .parallel = 0, },
503e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_tpr, "x2apic_self_ipi_tpr", is_x2apic, .parallel = 0, },
504e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_tpr_sti_nop, "x2apic_self_ipi_tpr_sti_nop", is_x2apic, .parallel = 0, },
505e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_tpr_sti_hlt, "x2apic_self_ipi_tpr_sti_hlt", is_x2apic, .parallel = 0, },
5067d36db35SAvi Kivity { ipi, "ipi", is_smp, .parallel = 0, },
507cb37ca1eSSerg Titaevskiy { ipi_halt, "ipi_halt", is_smp, .parallel = 0, },
508cb37ca1eSSerg Titaevskiy { ple_round_robin, "ple_round_robin", .parallel = 1 },
5099e018cb8SPaolo Bonzini { wr_kernel_gs_base, "wr_kernel_gs_base", .parallel = 1 },
5106163f75dSPaolo Bonzini { wr_tsx_ctrl_msr, "wr_tsx_ctrl_msr", has_tsx_ctrl, .parallel = 1, },
511f2665de7SPaolo Bonzini { wr_ibrs_msr, "wr_ibrs_msr", has_spec_ctrl, .parallel = 1 },
512f2665de7SPaolo Bonzini { wr_ibpb_msr, "wr_ibpb_msr", has_ibpb, .parallel = 1 },
5135fecf5d8SWill Auld { wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 },
5145fecf5d8SWill Auld { rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 },
51557c063c5SPaolo Bonzini { toggle_cr0_wp, "toggle_cr0_wp" , .parallel = 1, },
51657c063c5SPaolo Bonzini { toggle_cr4_pge, "toggle_cr4_pge" , .parallel = 1, },
5175292dbf7SMichael S. Tsirkin { NULL, "pci-mem", .parallel = 0, .next = pci_mem_next },
5185292dbf7SMichael S. Tsirkin { NULL, "pci-io", .parallel = 0, .next = pci_io_next },
5197d36db35SAvi Kivity };
5207d36db35SAvi Kivity
5217d36db35SAvi Kivity unsigned iterations;
5227d36db35SAvi Kivity
run_test(void * _func)5237d36db35SAvi Kivity static void run_test(void *_func)
5247d36db35SAvi Kivity {
5257d36db35SAvi Kivity int i;
5267d36db35SAvi Kivity void (*func)(void) = _func;
5277d36db35SAvi Kivity
5287d36db35SAvi Kivity for (i = 0; i < iterations; ++i)
5297d36db35SAvi Kivity func();
5307d36db35SAvi Kivity }
5317d36db35SAvi Kivity
do_test(struct test * test)5325292dbf7SMichael S. Tsirkin static bool do_test(struct test *test)
5337d36db35SAvi Kivity {
5347d36db35SAvi Kivity int i;
5357d36db35SAvi Kivity unsigned long long t1, t2;
5365292dbf7SMichael S. Tsirkin void (*func)(void);
5377d36db35SAvi Kivity
5387d36db35SAvi Kivity iterations = 32;
5397d36db35SAvi Kivity
5407d36db35SAvi Kivity if (test->valid && !test->valid()) {
5417d36db35SAvi Kivity printf("%s (skipped)\n", test->name);
5425292dbf7SMichael S. Tsirkin return false;
5435292dbf7SMichael S. Tsirkin }
5445292dbf7SMichael S. Tsirkin
5455292dbf7SMichael S. Tsirkin if (test->next && !test->next(test)) {
5465292dbf7SMichael S. Tsirkin return false;
5475292dbf7SMichael S. Tsirkin }
5485292dbf7SMichael S. Tsirkin
5495292dbf7SMichael S. Tsirkin func = test->func;
5505292dbf7SMichael S. Tsirkin if (!func) {
5515292dbf7SMichael S. Tsirkin printf("%s (skipped)\n", test->name);
5525292dbf7SMichael S. Tsirkin return false;
5537d36db35SAvi Kivity }
5547d36db35SAvi Kivity
5557d36db35SAvi Kivity do {
5568a8c1fc3SPaolo Bonzini tsc_eoi = tsc_ipi = 0;
5577d36db35SAvi Kivity iterations *= 2;
5587d36db35SAvi Kivity t1 = rdtsc();
5597d36db35SAvi Kivity
5607d36db35SAvi Kivity if (!test->parallel) {
5617d36db35SAvi Kivity for (i = 0; i < iterations; ++i)
5627d36db35SAvi Kivity func();
5637d36db35SAvi Kivity } else {
564b171c8c0SAndrew Jones on_cpus(run_test, func);
5657d36db35SAvi Kivity }
5667d36db35SAvi Kivity t2 = rdtsc();
5677d36db35SAvi Kivity } while ((t2 - t1) < GOAL);
5687d36db35SAvi Kivity printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
5698a8c1fc3SPaolo Bonzini if (tsc_ipi)
5708a8c1fc3SPaolo Bonzini printf(" ipi %s %d\n", test->name, (int)(tsc_ipi / iterations));
5718a8c1fc3SPaolo Bonzini if (tsc_eoi)
5728a8c1fc3SPaolo Bonzini printf(" eoi %s %d\n", test->name, (int)(tsc_eoi / iterations));
5738a8c1fc3SPaolo Bonzini
5745292dbf7SMichael S. Tsirkin return test->next;
5757d36db35SAvi Kivity }
5767d36db35SAvi Kivity
enable_nx(void * junk)5777d36db35SAvi Kivity static void enable_nx(void *junk)
5787d36db35SAvi Kivity {
579badc98caSKrish Sadhukhan if (this_cpu_has(X86_FEATURE_NX))
5807d36db35SAvi Kivity wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK);
5817d36db35SAvi Kivity }
5827d36db35SAvi Kivity
test_wanted(struct test * test,char * wanted[],int nwanted)583db4898e8SThomas Huth static bool test_wanted(struct test *test, char *wanted[], int nwanted)
5840b267183SAvi Kivity {
5850b267183SAvi Kivity int i;
5860b267183SAvi Kivity
5870b267183SAvi Kivity if (!nwanted)
5880b267183SAvi Kivity return true;
5890b267183SAvi Kivity
5900b267183SAvi Kivity for (i = 0; i < nwanted; ++i)
5910b267183SAvi Kivity if (strcmp(wanted[i], test->name) == 0)
5920b267183SAvi Kivity return true;
5930b267183SAvi Kivity
5940b267183SAvi Kivity return false;
5950b267183SAvi Kivity }
5960b267183SAvi Kivity
main(int ac,char ** av)5970b267183SAvi Kivity int main(int ac, char **av)
5987d36db35SAvi Kivity {
5997d36db35SAvi Kivity int i;
600f1abb07bSAlexander Gordeev unsigned long membar = 0;
6014d6cefa9SPeter Xu struct pci_dev pcidev;
6024d6cefa9SPeter Xu int ret;
6037d36db35SAvi Kivity
6045292dbf7SMichael S. Tsirkin setup_vm();
60557c063c5SPaolo Bonzini cr4_shadow = read_cr4();
606e0a5cfcaSPaolo Bonzini handle_irq(IPI_TEST_VECTOR, self_ipi_isr);
607eda71b28SAvi Kivity nr_cpus = cpu_count();
6087d36db35SAvi Kivity
609787f0aebSMaxim Levitsky sti();
610b171c8c0SAndrew Jones on_cpus(enable_nx, NULL);
6117d36db35SAvi Kivity
6124d6cefa9SPeter Xu ret = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST);
6134d6cefa9SPeter Xu if (ret != PCIDEVADDR_INVALID) {
6144d6cefa9SPeter Xu pci_dev_init(&pcidev, ret);
615e954ce23SPeter Xu assert(pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_MEM));
616e954ce23SPeter Xu assert(!pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_IO));
617e954ce23SPeter Xu membar = pcidev.resource[PCI_TESTDEV_BAR_MEM];
618f1abb07bSAlexander Gordeev pci_test.memaddr = ioremap(membar, PAGE_SIZE);
619e954ce23SPeter Xu pci_test.iobar = pcidev.resource[PCI_TESTDEV_BAR_IO];
620fd6aada0SRadim Krčmář printf("pci-testdev at %#x membar %lx iobar %x\n",
6214d6cefa9SPeter Xu pcidev.bdf, membar, pci_test.iobar);
6225292dbf7SMichael S. Tsirkin }
6235292dbf7SMichael S. Tsirkin
6247d36db35SAvi Kivity for (i = 0; i < ARRAY_SIZE(tests); ++i)
6250b267183SAvi Kivity if (test_wanted(&tests[i], av + 1, ac - 1))
6265292dbf7SMichael S. Tsirkin while (do_test(&tests[i])) {}
6277d36db35SAvi Kivity
6287d36db35SAvi Kivity return 0;
6297d36db35SAvi Kivity }
630