1 2 #include "libcflat.h" 3 #include "smp.h" 4 #include "processor.h" 5 #include "atomic.h" 6 7 static unsigned int inl(unsigned short port) 8 { 9 unsigned int val; 10 asm volatile("inl %w1, %0" : "=a"(val) : "Nd"(port)); 11 return val; 12 } 13 14 #define GOAL (1ull << 30) 15 16 static int nr_cpus; 17 18 #ifdef __x86_64__ 19 # define R "r" 20 #else 21 # define R "e" 22 #endif 23 24 static void cpuid_test(void) 25 { 26 asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx" 27 : : : "eax", "ecx", "edx"); 28 } 29 30 static void vmcall(void) 31 { 32 unsigned long a = 0, b, c, d; 33 34 asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d)); 35 } 36 37 #define MSR_TSC_ADJUST 0x3b 38 #define MSR_EFER 0xc0000080 39 #define EFER_NX_MASK (1ull << 11) 40 41 #ifdef __x86_64__ 42 static void mov_from_cr8(void) 43 { 44 unsigned long cr8; 45 46 asm volatile ("mov %%cr8, %0" : "=r"(cr8)); 47 } 48 49 static void mov_to_cr8(void) 50 { 51 unsigned long cr8 = 0; 52 53 asm volatile ("mov %0, %%cr8" : : "r"(cr8)); 54 } 55 #endif 56 57 static int is_smp(void) 58 { 59 return cpu_count() > 1; 60 } 61 62 static void nop(void *junk) 63 { 64 } 65 66 static void ipi(void) 67 { 68 on_cpu(1, nop, 0); 69 } 70 71 static void ipi_halt(void) 72 { 73 unsigned long long t; 74 75 on_cpu(1, nop, 0); 76 t = rdtsc() + 2000; 77 while (rdtsc() < t) 78 ; 79 } 80 81 static void inl_pmtimer(void) 82 { 83 inl(0xb008); 84 } 85 86 static void ple_round_robin(void) 87 { 88 struct counter { 89 volatile int n1; 90 int n2; 91 } __attribute__((aligned(64))); 92 static struct counter counters[64] = { { -1, 0 } }; 93 int me = smp_id(); 94 int you; 95 volatile struct counter *p = &counters[me]; 96 97 while (p->n1 == p->n2) 98 asm volatile ("pause"); 99 100 p->n2 = p->n1; 101 you = me + 1; 102 if (you == nr_cpus) 103 you = 0; 104 ++counters[you].n1; 105 } 106 107 static void rd_tsc_adjust_msr(void) 108 { 109 rdmsr(MSR_TSC_ADJUST); 110 } 111 112 static void wr_tsc_adjust_msr(void) 113 { 114 wrmsr(MSR_TSC_ADJUST, 0x0); 115 } 116 117 static struct test { 118 void (*func)(void); 119 const char *name; 120 int (*valid)(void); 121 int parallel; 122 } tests[] = { 123 { cpuid_test, "cpuid", .parallel = 1, }, 124 { vmcall, "vmcall", .parallel = 1, }, 125 #ifdef __x86_64__ 126 { mov_from_cr8, "mov_from_cr8", .parallel = 1, }, 127 { mov_to_cr8, "mov_to_cr8" , .parallel = 1, }, 128 #endif 129 { inl_pmtimer, "inl_from_pmtimer", .parallel = 1, }, 130 { ipi, "ipi", is_smp, .parallel = 0, }, 131 { ipi_halt, "ipi+halt", is_smp, .parallel = 0, }, 132 { ple_round_robin, "ple-round-robin", .parallel = 1 }, 133 { wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 }, 134 { rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 }, 135 }; 136 137 unsigned iterations; 138 static atomic_t nr_cpus_done; 139 140 static void run_test(void *_func) 141 { 142 int i; 143 void (*func)(void) = _func; 144 145 for (i = 0; i < iterations; ++i) 146 func(); 147 148 atomic_inc(&nr_cpus_done); 149 } 150 151 static void do_test(struct test *test) 152 { 153 int i; 154 unsigned long long t1, t2; 155 void (*func)(void) = test->func; 156 157 iterations = 32; 158 159 if (test->valid && !test->valid()) { 160 printf("%s (skipped)\n", test->name); 161 return; 162 } 163 164 do { 165 iterations *= 2; 166 t1 = rdtsc(); 167 168 if (!test->parallel) { 169 for (i = 0; i < iterations; ++i) 170 func(); 171 } else { 172 atomic_set(&nr_cpus_done, 0); 173 for (i = cpu_count(); i > 0; i--) 174 on_cpu_async(i-1, run_test, func); 175 while (atomic_read(&nr_cpus_done) < cpu_count()) 176 ; 177 } 178 t2 = rdtsc(); 179 } while ((t2 - t1) < GOAL); 180 printf("%s %d\n", test->name, (int)((t2 - t1) / iterations)); 181 } 182 183 static void enable_nx(void *junk) 184 { 185 if (cpuid(0x80000001).d & (1 << 20)) 186 wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK); 187 } 188 189 bool test_wanted(struct test *test, char *wanted[], int nwanted) 190 { 191 int i; 192 193 if (!nwanted) 194 return true; 195 196 for (i = 0; i < nwanted; ++i) 197 if (strcmp(wanted[i], test->name) == 0) 198 return true; 199 200 return false; 201 } 202 203 int main(int ac, char **av) 204 { 205 int i; 206 207 smp_init(); 208 nr_cpus = cpu_count(); 209 210 for (i = cpu_count(); i > 0; i--) 211 on_cpu(i-1, enable_nx, 0); 212 213 for (i = 0; i < ARRAY_SIZE(tests); ++i) 214 if (test_wanted(&tests[i], av + 1, ac - 1)) 215 do_test(&tests[i]); 216 217 return 0; 218 } 219