17d36db35SAvi Kivity 27d36db35SAvi Kivity #include "libcflat.h" 37d36db35SAvi Kivity #include "smp.h" 4850479e3SJason Wang #include "processor.h" 57d641cc5SAvi Kivity #include "atomic.h" 67d36db35SAvi Kivity 7*00bfecaaSPaolo Bonzini static void outb(unsigned short port, int val) 8*00bfecaaSPaolo Bonzini { 9*00bfecaaSPaolo Bonzini asm volatile("outb %b0, %w1" : "=a"(val) : "Nd"(port)); 10*00bfecaaSPaolo Bonzini } 11*00bfecaaSPaolo Bonzini 12*00bfecaaSPaolo Bonzini static unsigned int inb(unsigned short port) 13*00bfecaaSPaolo Bonzini { 14*00bfecaaSPaolo Bonzini unsigned int val; 15*00bfecaaSPaolo Bonzini asm volatile("xorl %0, %0; inb %w1, %b0" : "=a"(val) : "Nd"(port)); 16*00bfecaaSPaolo Bonzini return val; 17*00bfecaaSPaolo Bonzini } 18*00bfecaaSPaolo Bonzini 197d36db35SAvi Kivity static unsigned int inl(unsigned short port) 207d36db35SAvi Kivity { 217d36db35SAvi Kivity unsigned int val; 227d36db35SAvi Kivity asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port)); 237d36db35SAvi Kivity return val; 247d36db35SAvi Kivity } 257d36db35SAvi Kivity 267d36db35SAvi Kivity #define GOAL (1ull << 30) 277d36db35SAvi Kivity 28eda71b28SAvi Kivity static int nr_cpus; 29eda71b28SAvi Kivity 307d36db35SAvi Kivity #ifdef __x86_64__ 317d36db35SAvi Kivity # define R "r" 327d36db35SAvi Kivity #else 337d36db35SAvi Kivity # define R "e" 347d36db35SAvi Kivity #endif 357d36db35SAvi Kivity 36850479e3SJason Wang static void cpuid_test(void) 377d36db35SAvi Kivity { 387d36db35SAvi Kivity asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx" 397d36db35SAvi Kivity : : : "eax", "ecx", "edx"); 407d36db35SAvi Kivity } 417d36db35SAvi Kivity 427d36db35SAvi Kivity static void vmcall(void) 437d36db35SAvi Kivity { 447d36db35SAvi Kivity unsigned long a = 0, b, c, d; 457d36db35SAvi Kivity 467d36db35SAvi Kivity asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d)); 477d36db35SAvi Kivity } 487d36db35SAvi Kivity 495fecf5d8SWill Auld #define MSR_TSC_ADJUST 0x3b 507d36db35SAvi Kivity #define MSR_EFER 0xc0000080 517d36db35SAvi Kivity #define EFER_NX_MASK (1ull << 11) 527d36db35SAvi Kivity 535ada505aSJason Wang #ifdef __x86_64__ 547d36db35SAvi Kivity static void mov_from_cr8(void) 557d36db35SAvi Kivity { 567d36db35SAvi Kivity unsigned long cr8; 577d36db35SAvi Kivity 587d36db35SAvi Kivity asm volatile ("mov %%cr8, %0" : "=r"(cr8)); 597d36db35SAvi Kivity } 607d36db35SAvi Kivity 617d36db35SAvi Kivity static void mov_to_cr8(void) 627d36db35SAvi Kivity { 637d36db35SAvi Kivity unsigned long cr8 = 0; 647d36db35SAvi Kivity 657d36db35SAvi Kivity asm volatile ("mov %0, %%cr8" : : "r"(cr8)); 667d36db35SAvi Kivity } 675ada505aSJason Wang #endif 687d36db35SAvi Kivity 697d36db35SAvi Kivity static int is_smp(void) 707d36db35SAvi Kivity { 717d36db35SAvi Kivity return cpu_count() > 1; 727d36db35SAvi Kivity } 737d36db35SAvi Kivity 747d36db35SAvi Kivity static void nop(void *junk) 757d36db35SAvi Kivity { 767d36db35SAvi Kivity } 777d36db35SAvi Kivity 787d36db35SAvi Kivity static void ipi(void) 797d36db35SAvi Kivity { 807d36db35SAvi Kivity on_cpu(1, nop, 0); 817d36db35SAvi Kivity } 827d36db35SAvi Kivity 837d36db35SAvi Kivity static void ipi_halt(void) 847d36db35SAvi Kivity { 857d36db35SAvi Kivity unsigned long long t; 867d36db35SAvi Kivity 877d36db35SAvi Kivity on_cpu(1, nop, 0); 887d36db35SAvi Kivity t = rdtsc() + 2000; 897d36db35SAvi Kivity while (rdtsc() < t) 907d36db35SAvi Kivity ; 917d36db35SAvi Kivity } 927d36db35SAvi Kivity 937d36db35SAvi Kivity static void inl_pmtimer(void) 947d36db35SAvi Kivity { 957d36db35SAvi Kivity inl(0xb008); 967d36db35SAvi Kivity } 977d36db35SAvi Kivity 98*00bfecaaSPaolo Bonzini static void inl_nop_qemu(void) 99*00bfecaaSPaolo Bonzini { 100*00bfecaaSPaolo Bonzini inl(0x1234); 101*00bfecaaSPaolo Bonzini } 102*00bfecaaSPaolo Bonzini 103*00bfecaaSPaolo Bonzini static void inl_nop_kernel(void) 104*00bfecaaSPaolo Bonzini { 105*00bfecaaSPaolo Bonzini inb(0x4d0); 106*00bfecaaSPaolo Bonzini } 107*00bfecaaSPaolo Bonzini 108*00bfecaaSPaolo Bonzini static void outl_elcr_kernel(void) 109*00bfecaaSPaolo Bonzini { 110*00bfecaaSPaolo Bonzini outb(0x4d0, 0); 111*00bfecaaSPaolo Bonzini } 112*00bfecaaSPaolo Bonzini 113eda71b28SAvi Kivity static void ple_round_robin(void) 114eda71b28SAvi Kivity { 115eda71b28SAvi Kivity struct counter { 116eda71b28SAvi Kivity volatile int n1; 117eda71b28SAvi Kivity int n2; 118eda71b28SAvi Kivity } __attribute__((aligned(64))); 119eda71b28SAvi Kivity static struct counter counters[64] = { { -1, 0 } }; 120eda71b28SAvi Kivity int me = smp_id(); 121eda71b28SAvi Kivity int you; 122eda71b28SAvi Kivity volatile struct counter *p = &counters[me]; 123eda71b28SAvi Kivity 124eda71b28SAvi Kivity while (p->n1 == p->n2) 125eda71b28SAvi Kivity asm volatile ("pause"); 126eda71b28SAvi Kivity 127eda71b28SAvi Kivity p->n2 = p->n1; 128eda71b28SAvi Kivity you = me + 1; 129eda71b28SAvi Kivity if (you == nr_cpus) 130eda71b28SAvi Kivity you = 0; 131eda71b28SAvi Kivity ++counters[you].n1; 132eda71b28SAvi Kivity } 133eda71b28SAvi Kivity 1345fecf5d8SWill Auld static void rd_tsc_adjust_msr(void) 1355fecf5d8SWill Auld { 1365fecf5d8SWill Auld rdmsr(MSR_TSC_ADJUST); 1375fecf5d8SWill Auld } 1385fecf5d8SWill Auld 1395fecf5d8SWill Auld static void wr_tsc_adjust_msr(void) 1405fecf5d8SWill Auld { 1415fecf5d8SWill Auld wrmsr(MSR_TSC_ADJUST, 0x0); 1425fecf5d8SWill Auld } 1435fecf5d8SWill Auld 1447d36db35SAvi Kivity static struct test { 1457d36db35SAvi Kivity void (*func)(void); 1467d36db35SAvi Kivity const char *name; 1477d36db35SAvi Kivity int (*valid)(void); 1487d36db35SAvi Kivity int parallel; 1497d36db35SAvi Kivity } tests[] = { 150850479e3SJason Wang { cpuid_test, "cpuid", .parallel = 1, }, 1517d36db35SAvi Kivity { vmcall, "vmcall", .parallel = 1, }, 1525ada505aSJason Wang #ifdef __x86_64__ 1537d36db35SAvi Kivity { mov_from_cr8, "mov_from_cr8", .parallel = 1, }, 1547d36db35SAvi Kivity { mov_to_cr8, "mov_to_cr8" , .parallel = 1, }, 1555ada505aSJason Wang #endif 1567d36db35SAvi Kivity { inl_pmtimer, "inl_from_pmtimer", .parallel = 1, }, 157*00bfecaaSPaolo Bonzini { inl_nop_qemu, "inl_from_qemu", .parallel = 1 }, 158*00bfecaaSPaolo Bonzini { inl_nop_kernel, "inl_from_kernel", .parallel = 1 }, 159*00bfecaaSPaolo Bonzini { outl_elcr_kernel, "outl_to_kernel", .parallel = 1 }, 1607d36db35SAvi Kivity { ipi, "ipi", is_smp, .parallel = 0, }, 1617d36db35SAvi Kivity { ipi_halt, "ipi+halt", is_smp, .parallel = 0, }, 162eda71b28SAvi Kivity { ple_round_robin, "ple-round-robin", .parallel = 1 }, 1635fecf5d8SWill Auld { wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 }, 1645fecf5d8SWill Auld { rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 }, 1657d36db35SAvi Kivity }; 1667d36db35SAvi Kivity 1677d36db35SAvi Kivity unsigned iterations; 1687d641cc5SAvi Kivity static atomic_t nr_cpus_done; 1697d36db35SAvi Kivity 1707d36db35SAvi Kivity static void run_test(void *_func) 1717d36db35SAvi Kivity { 1727d36db35SAvi Kivity int i; 1737d36db35SAvi Kivity void (*func)(void) = _func; 1747d36db35SAvi Kivity 1757d36db35SAvi Kivity for (i = 0; i < iterations; ++i) 1767d36db35SAvi Kivity func(); 1777d36db35SAvi Kivity 1787d641cc5SAvi Kivity atomic_inc(&nr_cpus_done); 1797d36db35SAvi Kivity } 1807d36db35SAvi Kivity 1817d36db35SAvi Kivity static void do_test(struct test *test) 1827d36db35SAvi Kivity { 1837d36db35SAvi Kivity int i; 1847d36db35SAvi Kivity unsigned long long t1, t2; 1857d36db35SAvi Kivity void (*func)(void) = test->func; 1867d36db35SAvi Kivity 1877d36db35SAvi Kivity iterations = 32; 1887d36db35SAvi Kivity 1897d36db35SAvi Kivity if (test->valid && !test->valid()) { 1907d36db35SAvi Kivity printf("%s (skipped)\n", test->name); 1917d36db35SAvi Kivity return; 1927d36db35SAvi Kivity } 1937d36db35SAvi Kivity 1947d36db35SAvi Kivity do { 1957d36db35SAvi Kivity iterations *= 2; 1967d36db35SAvi Kivity t1 = rdtsc(); 1977d36db35SAvi Kivity 1987d36db35SAvi Kivity if (!test->parallel) { 1997d36db35SAvi Kivity for (i = 0; i < iterations; ++i) 2007d36db35SAvi Kivity func(); 2017d36db35SAvi Kivity } else { 2027d641cc5SAvi Kivity atomic_set(&nr_cpus_done, 0); 2037d36db35SAvi Kivity for (i = cpu_count(); i > 0; i--) 2047d36db35SAvi Kivity on_cpu_async(i-1, run_test, func); 2057d641cc5SAvi Kivity while (atomic_read(&nr_cpus_done) < cpu_count()) 2067d36db35SAvi Kivity ; 2077d36db35SAvi Kivity } 2087d36db35SAvi Kivity t2 = rdtsc(); 2097d36db35SAvi Kivity } while ((t2 - t1) < GOAL); 2107d36db35SAvi Kivity printf("%s %d\n", test->name, (int)((t2 - t1) / iterations)); 2117d36db35SAvi Kivity } 2127d36db35SAvi Kivity 2137d36db35SAvi Kivity static void enable_nx(void *junk) 2147d36db35SAvi Kivity { 215e46b32aaSAvi Kivity if (cpuid(0x80000001).d & (1 << 20)) 2167d36db35SAvi Kivity wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK); 2177d36db35SAvi Kivity } 2187d36db35SAvi Kivity 2190b267183SAvi Kivity bool test_wanted(struct test *test, char *wanted[], int nwanted) 2200b267183SAvi Kivity { 2210b267183SAvi Kivity int i; 2220b267183SAvi Kivity 2230b267183SAvi Kivity if (!nwanted) 2240b267183SAvi Kivity return true; 2250b267183SAvi Kivity 2260b267183SAvi Kivity for (i = 0; i < nwanted; ++i) 2270b267183SAvi Kivity if (strcmp(wanted[i], test->name) == 0) 2280b267183SAvi Kivity return true; 2290b267183SAvi Kivity 2300b267183SAvi Kivity return false; 2310b267183SAvi Kivity } 2320b267183SAvi Kivity 2330b267183SAvi Kivity int main(int ac, char **av) 2347d36db35SAvi Kivity { 2357d36db35SAvi Kivity int i; 2367d36db35SAvi Kivity 2377d36db35SAvi Kivity smp_init(); 238eda71b28SAvi Kivity nr_cpus = cpu_count(); 2397d36db35SAvi Kivity 2407d36db35SAvi Kivity for (i = cpu_count(); i > 0; i--) 2417d36db35SAvi Kivity on_cpu(i-1, enable_nx, 0); 2427d36db35SAvi Kivity 2437d36db35SAvi Kivity for (i = 0; i < ARRAY_SIZE(tests); ++i) 2440b267183SAvi Kivity if (test_wanted(&tests[i], av + 1, ac - 1)) 2457d36db35SAvi Kivity do_test(&tests[i]); 2467d36db35SAvi Kivity 2477d36db35SAvi Kivity return 0; 2487d36db35SAvi Kivity } 249