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