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