17d36db35SAvi Kivity #include "libcflat.h" 2*670b1f54SNikos Nikoleris #include "acpi.h" 37d36db35SAvi Kivity #include "smp.h" 4456c55bcSAndrew Jones #include "pci.h" 55292dbf7SMichael S. Tsirkin #include "x86/vm.h" 65292dbf7SMichael S. Tsirkin #include "x86/desc.h" 7e0a5cfcaSPaolo Bonzini #include "x86/apic.h" 8e0a5cfcaSPaolo Bonzini #include "x86/isr.h" 9e0a5cfcaSPaolo Bonzini 10e0a5cfcaSPaolo Bonzini #define IPI_TEST_VECTOR 0xb0 117d36db35SAvi Kivity 125292dbf7SMichael S. Tsirkin struct test { 135292dbf7SMichael S. Tsirkin void (*func)(void); 145292dbf7SMichael S. Tsirkin const char *name; 155292dbf7SMichael S. Tsirkin int (*valid)(void); 165292dbf7SMichael S. Tsirkin int parallel; 175292dbf7SMichael S. Tsirkin bool (*next)(struct test *); 185292dbf7SMichael S. Tsirkin }; 195292dbf7SMichael S. Tsirkin 207d36db35SAvi Kivity #define GOAL (1ull << 30) 217d36db35SAvi Kivity 22eda71b28SAvi Kivity static int nr_cpus; 2357c063c5SPaolo Bonzini static u64 cr4_shadow; 24eda71b28SAvi Kivity 25850479e3SJason Wang static void cpuid_test(void) 267d36db35SAvi Kivity { 277d36db35SAvi Kivity asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx" 287d36db35SAvi Kivity : : : "eax", "ecx", "edx"); 297d36db35SAvi Kivity } 307d36db35SAvi Kivity 317d36db35SAvi Kivity static void vmcall(void) 327d36db35SAvi Kivity { 337d36db35SAvi Kivity unsigned long a = 0, b, c, d; 347d36db35SAvi Kivity 357d36db35SAvi Kivity asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d)); 367d36db35SAvi Kivity } 377d36db35SAvi Kivity 387d36db35SAvi Kivity #define MSR_EFER 0xc0000080 397d36db35SAvi Kivity #define EFER_NX_MASK (1ull << 11) 407d36db35SAvi Kivity 415ada505aSJason Wang #ifdef __x86_64__ 427d36db35SAvi Kivity static void mov_from_cr8(void) 437d36db35SAvi Kivity { 447d36db35SAvi Kivity unsigned long cr8; 457d36db35SAvi Kivity 467d36db35SAvi Kivity asm volatile ("mov %%cr8, %0" : "=r"(cr8)); 477d36db35SAvi Kivity } 487d36db35SAvi Kivity 497d36db35SAvi Kivity static void mov_to_cr8(void) 507d36db35SAvi Kivity { 517d36db35SAvi Kivity unsigned long cr8 = 0; 527d36db35SAvi Kivity 537d36db35SAvi Kivity asm volatile ("mov %0, %%cr8" : : "r"(cr8)); 547d36db35SAvi Kivity } 555ada505aSJason Wang #endif 567d36db35SAvi Kivity 577d36db35SAvi Kivity static int is_smp(void) 587d36db35SAvi Kivity { 597d36db35SAvi Kivity return cpu_count() > 1; 607d36db35SAvi Kivity } 617d36db35SAvi Kivity 627d36db35SAvi Kivity static void nop(void *junk) 637d36db35SAvi Kivity { 647d36db35SAvi Kivity } 657d36db35SAvi Kivity 66e0a5cfcaSPaolo Bonzini volatile int x = 0; 678a8c1fc3SPaolo Bonzini volatile uint64_t tsc_eoi = 0; 688a8c1fc3SPaolo Bonzini volatile uint64_t tsc_ipi = 0; 69e0a5cfcaSPaolo Bonzini 70e0a5cfcaSPaolo Bonzini static void self_ipi_isr(isr_regs_t *regs) 71e0a5cfcaSPaolo Bonzini { 72e0a5cfcaSPaolo Bonzini x++; 738a8c1fc3SPaolo Bonzini uint64_t start = rdtsc(); 74e0a5cfcaSPaolo Bonzini eoi(); 758a8c1fc3SPaolo Bonzini tsc_eoi += rdtsc() - start; 76e0a5cfcaSPaolo Bonzini } 77e0a5cfcaSPaolo Bonzini 78e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi(int vec) 79e0a5cfcaSPaolo Bonzini { 808a8c1fc3SPaolo Bonzini uint64_t start = rdtsc(); 81e0a5cfcaSPaolo Bonzini wrmsr(0x83f, vec); 828a8c1fc3SPaolo Bonzini tsc_ipi += rdtsc() - start; 83e0a5cfcaSPaolo Bonzini } 84e0a5cfcaSPaolo Bonzini 85e0a5cfcaSPaolo Bonzini static void apic_self_ipi(int vec) 86e0a5cfcaSPaolo Bonzini { 878a8c1fc3SPaolo Bonzini uint64_t start = rdtsc(); 88e0a5cfcaSPaolo Bonzini apic_icr_write(APIC_INT_ASSERT | APIC_DEST_SELF | APIC_DEST_PHYSICAL | 89e0a5cfcaSPaolo Bonzini APIC_DM_FIXED | IPI_TEST_VECTOR, vec); 908a8c1fc3SPaolo Bonzini tsc_ipi += rdtsc() - start; 91e0a5cfcaSPaolo Bonzini } 92e0a5cfcaSPaolo Bonzini 93e0a5cfcaSPaolo Bonzini static void self_ipi_sti_nop(void) 94e0a5cfcaSPaolo Bonzini { 95e0a5cfcaSPaolo Bonzini x = 0; 96e0a5cfcaSPaolo Bonzini irq_disable(); 97e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR); 98e0a5cfcaSPaolo Bonzini asm volatile("sti; nop"); 99e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x); 100e0a5cfcaSPaolo Bonzini } 101e0a5cfcaSPaolo Bonzini 102e0a5cfcaSPaolo Bonzini static void self_ipi_sti_hlt(void) 103e0a5cfcaSPaolo Bonzini { 104e0a5cfcaSPaolo Bonzini x = 0; 105e0a5cfcaSPaolo Bonzini irq_disable(); 106e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR); 107a3001422SOliver Upton safe_halt(); 108e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x); 109e0a5cfcaSPaolo Bonzini } 110e0a5cfcaSPaolo Bonzini 111e0a5cfcaSPaolo Bonzini static void self_ipi_tpr(void) 112e0a5cfcaSPaolo Bonzini { 113e0a5cfcaSPaolo Bonzini x = 0; 114e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f); 115e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR); 116e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00); 117e0a5cfcaSPaolo Bonzini asm volatile("nop"); 118e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x); 119e0a5cfcaSPaolo Bonzini } 120e0a5cfcaSPaolo Bonzini 121e0a5cfcaSPaolo Bonzini static void self_ipi_tpr_sti_nop(void) 122e0a5cfcaSPaolo Bonzini { 123e0a5cfcaSPaolo Bonzini x = 0; 124e0a5cfcaSPaolo Bonzini irq_disable(); 125e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f); 126e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR); 127e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00); 128e0a5cfcaSPaolo Bonzini asm volatile("sti; nop"); 129e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x); 130e0a5cfcaSPaolo Bonzini } 131e0a5cfcaSPaolo Bonzini 132e0a5cfcaSPaolo Bonzini static void self_ipi_tpr_sti_hlt(void) 133e0a5cfcaSPaolo Bonzini { 134e0a5cfcaSPaolo Bonzini x = 0; 135e0a5cfcaSPaolo Bonzini irq_disable(); 136e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f); 137e0a5cfcaSPaolo Bonzini apic_self_ipi(IPI_TEST_VECTOR); 138e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00); 139a3001422SOliver Upton safe_halt(); 140e0a5cfcaSPaolo Bonzini if (x != 1) printf("%d", x); 141e0a5cfcaSPaolo Bonzini } 142e0a5cfcaSPaolo Bonzini 143e0a5cfcaSPaolo Bonzini static int is_x2apic(void) 144e0a5cfcaSPaolo Bonzini { 145e0a5cfcaSPaolo Bonzini return rdmsr(MSR_IA32_APICBASE) & APIC_EXTD; 146e0a5cfcaSPaolo Bonzini } 147e0a5cfcaSPaolo Bonzini 148e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_sti_nop(void) 149e0a5cfcaSPaolo Bonzini { 150e0a5cfcaSPaolo Bonzini irq_disable(); 151e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR); 152e0a5cfcaSPaolo Bonzini asm volatile("sti; nop"); 153e0a5cfcaSPaolo Bonzini } 154e0a5cfcaSPaolo Bonzini 155e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_sti_hlt(void) 156e0a5cfcaSPaolo Bonzini { 157e0a5cfcaSPaolo Bonzini irq_disable(); 158e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR); 159a3001422SOliver Upton safe_halt(); 160e0a5cfcaSPaolo Bonzini } 161e0a5cfcaSPaolo Bonzini 162e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr(void) 163e0a5cfcaSPaolo Bonzini { 164e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f); 165e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR); 166e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00); 167e0a5cfcaSPaolo Bonzini asm volatile("nop"); 168e0a5cfcaSPaolo Bonzini } 169e0a5cfcaSPaolo Bonzini 170e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr_sti_nop(void) 171e0a5cfcaSPaolo Bonzini { 172e0a5cfcaSPaolo Bonzini irq_disable(); 173e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f); 174e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR); 175e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00); 176e0a5cfcaSPaolo Bonzini asm volatile("sti; nop"); 177e0a5cfcaSPaolo Bonzini } 178e0a5cfcaSPaolo Bonzini 179e0a5cfcaSPaolo Bonzini static void x2apic_self_ipi_tpr_sti_hlt(void) 180e0a5cfcaSPaolo Bonzini { 181e0a5cfcaSPaolo Bonzini irq_disable(); 182e0a5cfcaSPaolo Bonzini apic_set_tpr(0x0f); 183e0a5cfcaSPaolo Bonzini x2apic_self_ipi(IPI_TEST_VECTOR); 184e0a5cfcaSPaolo Bonzini apic_set_tpr(0x00); 185a3001422SOliver Upton safe_halt(); 186e0a5cfcaSPaolo Bonzini } 187e0a5cfcaSPaolo Bonzini 1887d36db35SAvi Kivity static void ipi(void) 1897d36db35SAvi Kivity { 1908a8c1fc3SPaolo Bonzini uint64_t start = rdtsc(); 1917d36db35SAvi Kivity on_cpu(1, nop, 0); 1928a8c1fc3SPaolo Bonzini tsc_ipi += rdtsc() - start; 1937d36db35SAvi Kivity } 1947d36db35SAvi Kivity 1957d36db35SAvi Kivity static void ipi_halt(void) 1967d36db35SAvi Kivity { 1977d36db35SAvi Kivity unsigned long long t; 1987d36db35SAvi Kivity 1997d36db35SAvi Kivity on_cpu(1, nop, 0); 2007d36db35SAvi Kivity t = rdtsc() + 2000; 2017d36db35SAvi Kivity while (rdtsc() < t) 2027d36db35SAvi Kivity ; 2037d36db35SAvi Kivity } 2047d36db35SAvi Kivity 205a5d12b9fSPaolo Bonzini int pm_tmr_blk; 2067d36db35SAvi Kivity static void inl_pmtimer(void) 2077d36db35SAvi Kivity { 2081982ff44SSean Christopherson if (!pm_tmr_blk) { 2091982ff44SSean Christopherson struct fadt_descriptor_rev1 *fadt; 2101982ff44SSean Christopherson 2111982ff44SSean Christopherson fadt = find_acpi_table_addr(FACP_SIGNATURE); 2121982ff44SSean Christopherson pm_tmr_blk = fadt->pm_tmr_blk; 2131982ff44SSean Christopherson printf("PM timer port is %x\n", pm_tmr_blk); 2141982ff44SSean Christopherson } 215a5d12b9fSPaolo Bonzini inl(pm_tmr_blk); 2167d36db35SAvi Kivity } 2177d36db35SAvi Kivity 21800bfecaaSPaolo Bonzini static void inl_nop_qemu(void) 21900bfecaaSPaolo Bonzini { 22000bfecaaSPaolo Bonzini inl(0x1234); 22100bfecaaSPaolo Bonzini } 22200bfecaaSPaolo Bonzini 22300bfecaaSPaolo Bonzini static void inl_nop_kernel(void) 22400bfecaaSPaolo Bonzini { 22500bfecaaSPaolo Bonzini inb(0x4d0); 22600bfecaaSPaolo Bonzini } 22700bfecaaSPaolo Bonzini 22800bfecaaSPaolo Bonzini static void outl_elcr_kernel(void) 22900bfecaaSPaolo Bonzini { 230f22a66a1SAndrew Jones outb(0, 0x4d0); 23100bfecaaSPaolo Bonzini } 23200bfecaaSPaolo Bonzini 2338a544409SPaolo Bonzini static void mov_dr(void) 2348a544409SPaolo Bonzini { 2358a544409SPaolo Bonzini asm volatile("mov %0, %%dr7" : : "r" (0x400L)); 2368a544409SPaolo Bonzini } 2378a544409SPaolo Bonzini 238eda71b28SAvi Kivity static void ple_round_robin(void) 239eda71b28SAvi Kivity { 240eda71b28SAvi Kivity struct counter { 241eda71b28SAvi Kivity volatile int n1; 242eda71b28SAvi Kivity int n2; 243eda71b28SAvi Kivity } __attribute__((aligned(64))); 244eda71b28SAvi Kivity static struct counter counters[64] = { { -1, 0 } }; 245eda71b28SAvi Kivity int me = smp_id(); 246eda71b28SAvi Kivity int you; 247eda71b28SAvi Kivity volatile struct counter *p = &counters[me]; 248eda71b28SAvi Kivity 249eda71b28SAvi Kivity while (p->n1 == p->n2) 250eda71b28SAvi Kivity asm volatile ("pause"); 251eda71b28SAvi Kivity 252eda71b28SAvi Kivity p->n2 = p->n1; 253eda71b28SAvi Kivity you = me + 1; 254eda71b28SAvi Kivity if (you == nr_cpus) 255eda71b28SAvi Kivity you = 0; 256eda71b28SAvi Kivity ++counters[you].n1; 257eda71b28SAvi Kivity } 258eda71b28SAvi Kivity 2595fecf5d8SWill Auld static void rd_tsc_adjust_msr(void) 2605fecf5d8SWill Auld { 2612352e986SPaolo Bonzini rdmsr(MSR_IA32_TSC_ADJUST); 2625fecf5d8SWill Auld } 2635fecf5d8SWill Auld 2645fecf5d8SWill Auld static void wr_tsc_adjust_msr(void) 2655fecf5d8SWill Auld { 2662352e986SPaolo Bonzini wrmsr(MSR_IA32_TSC_ADJUST, 0x0); 2675fecf5d8SWill Auld } 2685fecf5d8SWill Auld 2699e018cb8SPaolo Bonzini static void wr_kernel_gs_base(void) 2709e018cb8SPaolo Bonzini { 2719e018cb8SPaolo Bonzini wrmsr(MSR_KERNEL_GS_BASE, 0x0); 2729e018cb8SPaolo Bonzini } 2739e018cb8SPaolo Bonzini 2745292dbf7SMichael S. Tsirkin static struct pci_test { 2755292dbf7SMichael S. Tsirkin unsigned iobar; 2765292dbf7SMichael S. Tsirkin unsigned ioport; 2775292dbf7SMichael S. Tsirkin volatile void *memaddr; 2785292dbf7SMichael S. Tsirkin volatile void *mem; 2795292dbf7SMichael S. Tsirkin int test_idx; 2805292dbf7SMichael S. Tsirkin uint32_t data; 2815292dbf7SMichael S. Tsirkin uint32_t offset; 2825292dbf7SMichael S. Tsirkin } pci_test = { 2835292dbf7SMichael S. Tsirkin .test_idx = -1 2845292dbf7SMichael S. Tsirkin }; 2855292dbf7SMichael S. Tsirkin 2865292dbf7SMichael S. Tsirkin static void pci_mem_testb(void) 2875292dbf7SMichael S. Tsirkin { 2885292dbf7SMichael S. Tsirkin *(volatile uint8_t *)pci_test.mem = pci_test.data; 2895292dbf7SMichael S. Tsirkin } 2905292dbf7SMichael S. Tsirkin 2915292dbf7SMichael S. Tsirkin static void pci_mem_testw(void) 2925292dbf7SMichael S. Tsirkin { 2935292dbf7SMichael S. Tsirkin *(volatile uint16_t *)pci_test.mem = pci_test.data; 2945292dbf7SMichael S. Tsirkin } 2955292dbf7SMichael S. Tsirkin 2965292dbf7SMichael S. Tsirkin static void pci_mem_testl(void) 2975292dbf7SMichael S. Tsirkin { 2985292dbf7SMichael S. Tsirkin *(volatile uint32_t *)pci_test.mem = pci_test.data; 2995292dbf7SMichael S. Tsirkin } 3005292dbf7SMichael S. Tsirkin 3015292dbf7SMichael S. Tsirkin static void pci_io_testb(void) 3025292dbf7SMichael S. Tsirkin { 303f22a66a1SAndrew Jones outb(pci_test.data, pci_test.ioport); 3045292dbf7SMichael S. Tsirkin } 3055292dbf7SMichael S. Tsirkin 3065292dbf7SMichael S. Tsirkin static void pci_io_testw(void) 3075292dbf7SMichael S. Tsirkin { 308f22a66a1SAndrew Jones outw(pci_test.data, pci_test.ioport); 3095292dbf7SMichael S. Tsirkin } 3105292dbf7SMichael S. Tsirkin 3115292dbf7SMichael S. Tsirkin static void pci_io_testl(void) 3125292dbf7SMichael S. Tsirkin { 313f22a66a1SAndrew Jones outl(pci_test.data, pci_test.ioport); 3145292dbf7SMichael S. Tsirkin } 3155292dbf7SMichael S. Tsirkin 3165292dbf7SMichael S. Tsirkin static uint8_t ioreadb(unsigned long addr, bool io) 3175292dbf7SMichael S. Tsirkin { 3185292dbf7SMichael S. Tsirkin if (io) { 3195292dbf7SMichael S. Tsirkin return inb(addr); 3205292dbf7SMichael S. Tsirkin } else { 3215292dbf7SMichael S. Tsirkin return *(volatile uint8_t *)addr; 3225292dbf7SMichael S. Tsirkin } 3235292dbf7SMichael S. Tsirkin } 3245292dbf7SMichael S. Tsirkin 3255292dbf7SMichael S. Tsirkin static uint32_t ioreadl(unsigned long addr, bool io) 3265292dbf7SMichael S. Tsirkin { 3275292dbf7SMichael S. Tsirkin /* Note: assumes little endian */ 3285292dbf7SMichael S. Tsirkin if (io) { 3295292dbf7SMichael S. Tsirkin return inl(addr); 3305292dbf7SMichael S. Tsirkin } else { 3315292dbf7SMichael S. Tsirkin return *(volatile uint32_t *)addr; 3325292dbf7SMichael S. Tsirkin } 3335292dbf7SMichael S. Tsirkin } 3345292dbf7SMichael S. Tsirkin 3355292dbf7SMichael S. Tsirkin static void iowriteb(unsigned long addr, uint8_t data, bool io) 3365292dbf7SMichael S. Tsirkin { 3375292dbf7SMichael S. Tsirkin if (io) { 338f22a66a1SAndrew Jones outb(data, addr); 3395292dbf7SMichael S. Tsirkin } else { 3405292dbf7SMichael S. Tsirkin *(volatile uint8_t *)addr = data; 3415292dbf7SMichael S. Tsirkin } 3425292dbf7SMichael S. Tsirkin } 3435292dbf7SMichael S. Tsirkin 3445292dbf7SMichael S. Tsirkin static bool pci_next(struct test *test, unsigned long addr, bool io) 3455292dbf7SMichael S. Tsirkin { 3465292dbf7SMichael S. Tsirkin int i; 3475292dbf7SMichael S. Tsirkin uint8_t width; 3485292dbf7SMichael S. Tsirkin 3495292dbf7SMichael S. Tsirkin if (!pci_test.memaddr) { 3505292dbf7SMichael S. Tsirkin test->func = NULL; 3515292dbf7SMichael S. Tsirkin return true; 3525292dbf7SMichael S. Tsirkin } 3535292dbf7SMichael S. Tsirkin pci_test.test_idx++; 3545292dbf7SMichael S. Tsirkin iowriteb(addr + offsetof(struct pci_test_dev_hdr, test), 3555292dbf7SMichael S. Tsirkin pci_test.test_idx, io); 3565292dbf7SMichael S. Tsirkin width = ioreadb(addr + offsetof(struct pci_test_dev_hdr, width), 3575292dbf7SMichael S. Tsirkin io); 3585292dbf7SMichael S. Tsirkin switch (width) { 3595292dbf7SMichael S. Tsirkin case 1: 3605292dbf7SMichael S. Tsirkin test->func = io ? pci_io_testb : pci_mem_testb; 3615292dbf7SMichael S. Tsirkin break; 3625292dbf7SMichael S. Tsirkin case 2: 3635292dbf7SMichael S. Tsirkin test->func = io ? pci_io_testw : pci_mem_testw; 3645292dbf7SMichael S. Tsirkin break; 3655292dbf7SMichael S. Tsirkin case 4: 3665292dbf7SMichael S. Tsirkin test->func = io ? pci_io_testl : pci_mem_testl; 3675292dbf7SMichael S. Tsirkin break; 3685292dbf7SMichael S. Tsirkin default: 3695292dbf7SMichael S. Tsirkin /* Reset index for purposes of the next test */ 3705292dbf7SMichael S. Tsirkin pci_test.test_idx = -1; 3715292dbf7SMichael S. Tsirkin test->func = NULL; 3725292dbf7SMichael S. Tsirkin return false; 3735292dbf7SMichael S. Tsirkin } 3745292dbf7SMichael S. Tsirkin pci_test.data = ioreadl(addr + offsetof(struct pci_test_dev_hdr, data), 3755292dbf7SMichael S. Tsirkin io); 3765292dbf7SMichael S. Tsirkin pci_test.offset = ioreadl(addr + offsetof(struct pci_test_dev_hdr, 3775292dbf7SMichael S. Tsirkin offset), io); 3785292dbf7SMichael S. Tsirkin for (i = 0; i < pci_test.offset; ++i) { 3795292dbf7SMichael S. Tsirkin char c = ioreadb(addr + offsetof(struct pci_test_dev_hdr, 3805292dbf7SMichael S. Tsirkin name) + i, io); 3815292dbf7SMichael S. Tsirkin if (!c) { 3825292dbf7SMichael S. Tsirkin break; 3835292dbf7SMichael S. Tsirkin } 3845292dbf7SMichael S. Tsirkin printf("%c",c); 3855292dbf7SMichael S. Tsirkin } 3865292dbf7SMichael S. Tsirkin printf(":"); 3875292dbf7SMichael S. Tsirkin return true; 3885292dbf7SMichael S. Tsirkin } 3895292dbf7SMichael S. Tsirkin 3905292dbf7SMichael S. Tsirkin static bool pci_mem_next(struct test *test) 3915292dbf7SMichael S. Tsirkin { 3925292dbf7SMichael S. Tsirkin bool ret; 3935292dbf7SMichael S. Tsirkin ret = pci_next(test, ((unsigned long)pci_test.memaddr), false); 3945292dbf7SMichael S. Tsirkin if (ret) { 3955292dbf7SMichael S. Tsirkin pci_test.mem = pci_test.memaddr + pci_test.offset; 3965292dbf7SMichael S. Tsirkin } 3975292dbf7SMichael S. Tsirkin return ret; 3985292dbf7SMichael S. Tsirkin } 3995292dbf7SMichael S. Tsirkin 4005292dbf7SMichael S. Tsirkin static bool pci_io_next(struct test *test) 4015292dbf7SMichael S. Tsirkin { 4025292dbf7SMichael S. Tsirkin bool ret; 4035292dbf7SMichael S. Tsirkin ret = pci_next(test, ((unsigned long)pci_test.iobar), true); 4045292dbf7SMichael S. Tsirkin if (ret) { 4055292dbf7SMichael S. Tsirkin pci_test.ioport = pci_test.iobar + pci_test.offset; 4065292dbf7SMichael S. Tsirkin } 4075292dbf7SMichael S. Tsirkin return ret; 4085292dbf7SMichael S. Tsirkin } 4095292dbf7SMichael S. Tsirkin 410cfbd129cSPaolo Bonzini static int has_tscdeadline(void) 411cfbd129cSPaolo Bonzini { 412cfbd129cSPaolo Bonzini uint32_t lvtt; 413cfbd129cSPaolo Bonzini 414badc98caSKrish Sadhukhan if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { 415cfbd129cSPaolo Bonzini lvtt = APIC_LVT_TIMER_TSCDEADLINE | IPI_TEST_VECTOR; 416cfbd129cSPaolo Bonzini apic_write(APIC_LVTT, lvtt); 417cfbd129cSPaolo Bonzini return 1; 418cfbd129cSPaolo Bonzini } else { 419cfbd129cSPaolo Bonzini return 0; 420cfbd129cSPaolo Bonzini } 421cfbd129cSPaolo Bonzini } 422cfbd129cSPaolo Bonzini 423cfbd129cSPaolo Bonzini static void tscdeadline_immed(void) 424cfbd129cSPaolo Bonzini { 425cfbd129cSPaolo Bonzini wrmsr(MSR_IA32_TSCDEADLINE, rdtsc()); 426cfbd129cSPaolo Bonzini asm volatile("nop"); 427cfbd129cSPaolo Bonzini } 428cfbd129cSPaolo Bonzini 429cfbd129cSPaolo Bonzini static void tscdeadline(void) 430cfbd129cSPaolo Bonzini { 431cfbd129cSPaolo Bonzini x = 0; 432cfbd129cSPaolo Bonzini wrmsr(MSR_IA32_TSCDEADLINE, rdtsc()+3000); 433cfbd129cSPaolo Bonzini while (x == 0) barrier(); 434cfbd129cSPaolo Bonzini } 435cfbd129cSPaolo Bonzini 4366163f75dSPaolo Bonzini static void wr_tsx_ctrl_msr(void) 4376163f75dSPaolo Bonzini { 4386163f75dSPaolo Bonzini wrmsr(MSR_IA32_TSX_CTRL, 0); 4396163f75dSPaolo Bonzini } 4406163f75dSPaolo Bonzini 4416163f75dSPaolo Bonzini static int has_tsx_ctrl(void) 4426163f75dSPaolo Bonzini { 44345472bc5SSean Christopherson return this_cpu_has(X86_FEATURE_ARCH_CAPABILITIES) && 44445472bc5SSean Christopherson (rdmsr(MSR_IA32_ARCH_CAPABILITIES) & ARCH_CAP_TSX_CTRL_MSR); 4456163f75dSPaolo Bonzini } 4466163f75dSPaolo Bonzini 447f2665de7SPaolo Bonzini static void wr_ibrs_msr(void) 448f2665de7SPaolo Bonzini { 449f2665de7SPaolo Bonzini wrmsr(MSR_IA32_SPEC_CTRL, 1); 450f2665de7SPaolo Bonzini wrmsr(MSR_IA32_SPEC_CTRL, 0); 451f2665de7SPaolo Bonzini } 452f2665de7SPaolo Bonzini 453f2665de7SPaolo Bonzini static int has_ibpb(void) 454f2665de7SPaolo Bonzini { 45545472bc5SSean Christopherson return this_cpu_has(X86_FEATURE_SPEC_CTRL) || 45645472bc5SSean Christopherson this_cpu_has(X86_FEATURE_AMD_IBPB); 45745472bc5SSean Christopherson } 45845472bc5SSean Christopherson 45945472bc5SSean Christopherson static int has_spec_ctrl(void) 46045472bc5SSean Christopherson { 46145472bc5SSean Christopherson return this_cpu_has(X86_FEATURE_SPEC_CTRL); 462f2665de7SPaolo Bonzini } 463f2665de7SPaolo Bonzini 464f2665de7SPaolo Bonzini static void wr_ibpb_msr(void) 465f2665de7SPaolo Bonzini { 4664fba1a2cSSean Christopherson wrmsr(MSR_IA32_PRED_CMD, PRED_CMD_IBPB); 467f2665de7SPaolo Bonzini } 468f2665de7SPaolo Bonzini 46957c063c5SPaolo Bonzini static void toggle_cr0_wp(void) 47057c063c5SPaolo Bonzini { 47157c063c5SPaolo Bonzini write_cr0(X86_CR0_PE|X86_CR0_PG); 47257c063c5SPaolo Bonzini write_cr0(X86_CR0_PE|X86_CR0_WP|X86_CR0_PG); 47357c063c5SPaolo Bonzini } 47457c063c5SPaolo Bonzini 47557c063c5SPaolo Bonzini static void toggle_cr4_pge(void) 47657c063c5SPaolo Bonzini { 47757c063c5SPaolo Bonzini write_cr4(cr4_shadow ^ X86_CR4_PGE); 47857c063c5SPaolo Bonzini write_cr4(cr4_shadow); 47957c063c5SPaolo Bonzini } 48057c063c5SPaolo Bonzini 4815292dbf7SMichael S. Tsirkin static struct test tests[] = { 482850479e3SJason Wang { cpuid_test, "cpuid", .parallel = 1, }, 4837d36db35SAvi Kivity { vmcall, "vmcall", .parallel = 1, }, 4845ada505aSJason Wang #ifdef __x86_64__ 4857d36db35SAvi Kivity { mov_from_cr8, "mov_from_cr8", .parallel = 1, }, 4867d36db35SAvi Kivity { mov_to_cr8, "mov_to_cr8" , .parallel = 1, }, 4875ada505aSJason Wang #endif 4887d36db35SAvi Kivity { inl_pmtimer, "inl_from_pmtimer", .parallel = 1, }, 48900bfecaaSPaolo Bonzini { inl_nop_qemu, "inl_from_qemu", .parallel = 1 }, 49000bfecaaSPaolo Bonzini { inl_nop_kernel, "inl_from_kernel", .parallel = 1 }, 49100bfecaaSPaolo Bonzini { outl_elcr_kernel, "outl_to_kernel", .parallel = 1 }, 4928a544409SPaolo Bonzini { mov_dr, "mov_dr", .parallel = 1 }, 493cfbd129cSPaolo Bonzini { tscdeadline_immed, "tscdeadline_immed", has_tscdeadline, .parallel = 1, }, 494cfbd129cSPaolo Bonzini { tscdeadline, "tscdeadline", has_tscdeadline, .parallel = 1, }, 495e0a5cfcaSPaolo Bonzini { self_ipi_sti_nop, "self_ipi_sti_nop", .parallel = 0, }, 496e0a5cfcaSPaolo Bonzini { self_ipi_sti_hlt, "self_ipi_sti_hlt", .parallel = 0, }, 497e0a5cfcaSPaolo Bonzini { self_ipi_tpr, "self_ipi_tpr", .parallel = 0, }, 498e0a5cfcaSPaolo Bonzini { self_ipi_tpr_sti_nop, "self_ipi_tpr_sti_nop", .parallel = 0, }, 499e0a5cfcaSPaolo Bonzini { self_ipi_tpr_sti_hlt, "self_ipi_tpr_sti_hlt", .parallel = 0, }, 500e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_sti_nop, "x2apic_self_ipi_sti_nop", is_x2apic, .parallel = 0, }, 501e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_sti_hlt, "x2apic_self_ipi_sti_hlt", is_x2apic, .parallel = 0, }, 502e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_tpr, "x2apic_self_ipi_tpr", is_x2apic, .parallel = 0, }, 503e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_tpr_sti_nop, "x2apic_self_ipi_tpr_sti_nop", is_x2apic, .parallel = 0, }, 504e0a5cfcaSPaolo Bonzini { x2apic_self_ipi_tpr_sti_hlt, "x2apic_self_ipi_tpr_sti_hlt", is_x2apic, .parallel = 0, }, 5057d36db35SAvi Kivity { ipi, "ipi", is_smp, .parallel = 0, }, 506cb37ca1eSSerg Titaevskiy { ipi_halt, "ipi_halt", is_smp, .parallel = 0, }, 507cb37ca1eSSerg Titaevskiy { ple_round_robin, "ple_round_robin", .parallel = 1 }, 5089e018cb8SPaolo Bonzini { wr_kernel_gs_base, "wr_kernel_gs_base", .parallel = 1 }, 5096163f75dSPaolo Bonzini { wr_tsx_ctrl_msr, "wr_tsx_ctrl_msr", has_tsx_ctrl, .parallel = 1, }, 510f2665de7SPaolo Bonzini { wr_ibrs_msr, "wr_ibrs_msr", has_spec_ctrl, .parallel = 1 }, 511f2665de7SPaolo Bonzini { wr_ibpb_msr, "wr_ibpb_msr", has_ibpb, .parallel = 1 }, 5125fecf5d8SWill Auld { wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 }, 5135fecf5d8SWill Auld { rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 }, 51457c063c5SPaolo Bonzini { toggle_cr0_wp, "toggle_cr0_wp" , .parallel = 1, }, 51557c063c5SPaolo Bonzini { toggle_cr4_pge, "toggle_cr4_pge" , .parallel = 1, }, 5165292dbf7SMichael S. Tsirkin { NULL, "pci-mem", .parallel = 0, .next = pci_mem_next }, 5175292dbf7SMichael S. Tsirkin { NULL, "pci-io", .parallel = 0, .next = pci_io_next }, 5187d36db35SAvi Kivity }; 5197d36db35SAvi Kivity 5207d36db35SAvi Kivity unsigned iterations; 5217d36db35SAvi Kivity 5227d36db35SAvi Kivity static void run_test(void *_func) 5237d36db35SAvi Kivity { 5247d36db35SAvi Kivity int i; 5257d36db35SAvi Kivity void (*func)(void) = _func; 5267d36db35SAvi Kivity 5277d36db35SAvi Kivity for (i = 0; i < iterations; ++i) 5287d36db35SAvi Kivity func(); 5297d36db35SAvi Kivity } 5307d36db35SAvi Kivity 5315292dbf7SMichael S. Tsirkin static bool do_test(struct test *test) 5327d36db35SAvi Kivity { 5337d36db35SAvi Kivity int i; 5347d36db35SAvi Kivity unsigned long long t1, t2; 5355292dbf7SMichael S. Tsirkin void (*func)(void); 5367d36db35SAvi Kivity 5377d36db35SAvi Kivity iterations = 32; 5387d36db35SAvi Kivity 5397d36db35SAvi Kivity if (test->valid && !test->valid()) { 5407d36db35SAvi Kivity printf("%s (skipped)\n", test->name); 5415292dbf7SMichael S. Tsirkin return false; 5425292dbf7SMichael S. Tsirkin } 5435292dbf7SMichael S. Tsirkin 5445292dbf7SMichael S. Tsirkin if (test->next && !test->next(test)) { 5455292dbf7SMichael S. Tsirkin return false; 5465292dbf7SMichael S. Tsirkin } 5475292dbf7SMichael S. Tsirkin 5485292dbf7SMichael S. Tsirkin func = test->func; 5495292dbf7SMichael S. Tsirkin if (!func) { 5505292dbf7SMichael S. Tsirkin printf("%s (skipped)\n", test->name); 5515292dbf7SMichael S. Tsirkin return false; 5527d36db35SAvi Kivity } 5537d36db35SAvi Kivity 5547d36db35SAvi Kivity do { 5558a8c1fc3SPaolo Bonzini tsc_eoi = tsc_ipi = 0; 5567d36db35SAvi Kivity iterations *= 2; 5577d36db35SAvi Kivity t1 = rdtsc(); 5587d36db35SAvi Kivity 5597d36db35SAvi Kivity if (!test->parallel) { 5607d36db35SAvi Kivity for (i = 0; i < iterations; ++i) 5617d36db35SAvi Kivity func(); 5627d36db35SAvi Kivity } else { 563b171c8c0SAndrew Jones on_cpus(run_test, func); 5647d36db35SAvi Kivity } 5657d36db35SAvi Kivity t2 = rdtsc(); 5667d36db35SAvi Kivity } while ((t2 - t1) < GOAL); 5677d36db35SAvi Kivity printf("%s %d\n", test->name, (int)((t2 - t1) / iterations)); 5688a8c1fc3SPaolo Bonzini if (tsc_ipi) 5698a8c1fc3SPaolo Bonzini printf(" ipi %s %d\n", test->name, (int)(tsc_ipi / iterations)); 5708a8c1fc3SPaolo Bonzini if (tsc_eoi) 5718a8c1fc3SPaolo Bonzini printf(" eoi %s %d\n", test->name, (int)(tsc_eoi / iterations)); 5728a8c1fc3SPaolo Bonzini 5735292dbf7SMichael S. Tsirkin return test->next; 5747d36db35SAvi Kivity } 5757d36db35SAvi Kivity 5767d36db35SAvi Kivity static void enable_nx(void *junk) 5777d36db35SAvi Kivity { 578badc98caSKrish Sadhukhan if (this_cpu_has(X86_FEATURE_NX)) 5797d36db35SAvi Kivity wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK); 5807d36db35SAvi Kivity } 5817d36db35SAvi Kivity 582db4898e8SThomas Huth static bool test_wanted(struct test *test, char *wanted[], int nwanted) 5830b267183SAvi Kivity { 5840b267183SAvi Kivity int i; 5850b267183SAvi Kivity 5860b267183SAvi Kivity if (!nwanted) 5870b267183SAvi Kivity return true; 5880b267183SAvi Kivity 5890b267183SAvi Kivity for (i = 0; i < nwanted; ++i) 5900b267183SAvi Kivity if (strcmp(wanted[i], test->name) == 0) 5910b267183SAvi Kivity return true; 5920b267183SAvi Kivity 5930b267183SAvi Kivity return false; 5940b267183SAvi Kivity } 5950b267183SAvi Kivity 5960b267183SAvi Kivity int main(int ac, char **av) 5977d36db35SAvi Kivity { 5987d36db35SAvi Kivity int i; 599f1abb07bSAlexander Gordeev unsigned long membar = 0; 6004d6cefa9SPeter Xu struct pci_dev pcidev; 6014d6cefa9SPeter Xu int ret; 6027d36db35SAvi Kivity 6035292dbf7SMichael S. Tsirkin setup_vm(); 60457c063c5SPaolo Bonzini cr4_shadow = read_cr4(); 605e0a5cfcaSPaolo Bonzini handle_irq(IPI_TEST_VECTOR, self_ipi_isr); 606eda71b28SAvi Kivity nr_cpus = cpu_count(); 6077d36db35SAvi Kivity 608e0a5cfcaSPaolo Bonzini irq_enable(); 609b171c8c0SAndrew Jones on_cpus(enable_nx, NULL); 6107d36db35SAvi Kivity 6114d6cefa9SPeter Xu ret = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST); 6124d6cefa9SPeter Xu if (ret != PCIDEVADDR_INVALID) { 6134d6cefa9SPeter Xu pci_dev_init(&pcidev, ret); 614e954ce23SPeter Xu assert(pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_MEM)); 615e954ce23SPeter Xu assert(!pci_bar_is_memory(&pcidev, PCI_TESTDEV_BAR_IO)); 616e954ce23SPeter Xu membar = pcidev.resource[PCI_TESTDEV_BAR_MEM]; 617f1abb07bSAlexander Gordeev pci_test.memaddr = ioremap(membar, PAGE_SIZE); 618e954ce23SPeter Xu pci_test.iobar = pcidev.resource[PCI_TESTDEV_BAR_IO]; 619fd6aada0SRadim Krčmář printf("pci-testdev at %#x membar %lx iobar %x\n", 6204d6cefa9SPeter Xu pcidev.bdf, membar, pci_test.iobar); 6215292dbf7SMichael S. Tsirkin } 6225292dbf7SMichael S. Tsirkin 6237d36db35SAvi Kivity for (i = 0; i < ARRAY_SIZE(tests); ++i) 6240b267183SAvi Kivity if (test_wanted(&tests[i], av + 1, ac - 1)) 6255292dbf7SMichael S. Tsirkin while (do_test(&tests[i])) {} 6267d36db35SAvi Kivity 6277d36db35SAvi Kivity return 0; 6287d36db35SAvi Kivity } 629