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