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