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 static void mov_from_cr8(void) 53 { 54 unsigned long cr8; 55 56 asm volatile ("mov %%cr8, %0" : "=r"(cr8)); 57 } 58 59 static void mov_to_cr8(void) 60 { 61 unsigned long cr8 = 0; 62 63 asm volatile ("mov %0, %%cr8" : : "r"(cr8)); 64 } 65 66 static int is_smp(void) 67 { 68 return cpu_count() > 1; 69 } 70 71 static void nop(void *junk) 72 { 73 } 74 75 static void ipi(void) 76 { 77 on_cpu(1, nop, 0); 78 } 79 80 static void ipi_halt(void) 81 { 82 unsigned long long t; 83 84 on_cpu(1, nop, 0); 85 t = rdtsc() + 2000; 86 while (rdtsc() < t) 87 ; 88 } 89 90 static void inl_pmtimer(void) 91 { 92 inl(0xb008); 93 } 94 95 static struct test { 96 void (*func)(void); 97 const char *name; 98 int (*valid)(void); 99 int parallel; 100 } tests[] = { 101 { cpuid_test, "cpuid", .parallel = 1, }, 102 { vmcall, "vmcall", .parallel = 1, }, 103 { mov_from_cr8, "mov_from_cr8", .parallel = 1, }, 104 { mov_to_cr8, "mov_to_cr8" , .parallel = 1, }, 105 { inl_pmtimer, "inl_from_pmtimer", .parallel = 1, }, 106 { ipi, "ipi", is_smp, .parallel = 0, }, 107 { ipi_halt, "ipi+halt", is_smp, .parallel = 0, }, 108 }; 109 110 unsigned iterations; 111 volatile int nr_cpus_done; 112 113 static void run_test(void *_func) 114 { 115 int i; 116 void (*func)(void) = _func; 117 118 for (i = 0; i < iterations; ++i) 119 func(); 120 121 nr_cpus_done++; 122 } 123 124 static void do_test(struct test *test) 125 { 126 int i; 127 unsigned long long t1, t2; 128 void (*func)(void) = test->func; 129 130 iterations = 32; 131 132 if (test->valid && !test->valid()) { 133 printf("%s (skipped)\n", test->name); 134 return; 135 } 136 137 do { 138 iterations *= 2; 139 t1 = rdtsc(); 140 141 if (!test->parallel) { 142 for (i = 0; i < iterations; ++i) 143 func(); 144 } else { 145 nr_cpus_done = 0; 146 for (i = cpu_count(); i > 0; i--) 147 on_cpu_async(i-1, run_test, func); 148 while (nr_cpus_done < cpu_count()) 149 ; 150 } 151 t2 = rdtsc(); 152 } while ((t2 - t1) < GOAL); 153 printf("%s %d\n", test->name, (int)((t2 - t1) / iterations)); 154 } 155 156 static void enable_nx(void *junk) 157 { 158 wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NX_MASK); 159 } 160 161 int main(void) 162 { 163 int i; 164 165 smp_init(); 166 167 for (i = cpu_count(); i > 0; i--) 168 on_cpu(i-1, enable_nx, 0); 169 170 for (i = 0; i < ARRAY_SIZE(tests); ++i) 171 do_test(&tests[i]); 172 173 return 0; 174 } 175