1*a9f8b16fSGleb Natapov 2*a9f8b16fSGleb Natapov #include "x86/msr.h" 3*a9f8b16fSGleb Natapov #include "x86/processor.h" 4*a9f8b16fSGleb Natapov #include "x86/apic-defs.h" 5*a9f8b16fSGleb Natapov #include "x86/apic.h" 6*a9f8b16fSGleb Natapov #include "x86/desc.h" 7*a9f8b16fSGleb Natapov #include "x86/isr.h" 8*a9f8b16fSGleb Natapov #include "x86/vm.h" 9*a9f8b16fSGleb Natapov 10*a9f8b16fSGleb Natapov #include "libcflat.h" 11*a9f8b16fSGleb Natapov #include <stdint.h> 12*a9f8b16fSGleb Natapov 13*a9f8b16fSGleb Natapov #define FIXED_CNT_INDEX 32 14*a9f8b16fSGleb Natapov #define PC_VECTOR 32 15*a9f8b16fSGleb Natapov 16*a9f8b16fSGleb Natapov #define EVNSEL_EVENT_SHIFT 0 17*a9f8b16fSGleb Natapov #define EVNTSEL_UMASK_SHIFT 8 18*a9f8b16fSGleb Natapov #define EVNTSEL_USR_SHIFT 16 19*a9f8b16fSGleb Natapov #define EVNTSEL_OS_SHIFT 17 20*a9f8b16fSGleb Natapov #define EVNTSEL_EDGE_SHIFT 18 21*a9f8b16fSGleb Natapov #define EVNTSEL_PC_SHIFT 19 22*a9f8b16fSGleb Natapov #define EVNTSEL_INT_SHIFT 20 23*a9f8b16fSGleb Natapov #define EVNTSEL_EN_SHIF 22 24*a9f8b16fSGleb Natapov #define EVNTSEL_INV_SHIF 23 25*a9f8b16fSGleb Natapov #define EVNTSEL_CMASK_SHIFT 24 26*a9f8b16fSGleb Natapov 27*a9f8b16fSGleb Natapov #define EVNTSEL_EN (1 << EVNTSEL_EN_SHIF) 28*a9f8b16fSGleb Natapov #define EVNTSEL_USR (1 << EVNTSEL_USR_SHIFT) 29*a9f8b16fSGleb Natapov #define EVNTSEL_OS (1 << EVNTSEL_OS_SHIFT) 30*a9f8b16fSGleb Natapov #define EVNTSEL_PC (1 << EVNTSEL_PC_SHIFT) 31*a9f8b16fSGleb Natapov #define EVNTSEL_INT (1 << EVNTSEL_INT_SHIFT) 32*a9f8b16fSGleb Natapov #define EVNTSEL_INV (1 << EVNTSEL_INV_SHIF) 33*a9f8b16fSGleb Natapov 34*a9f8b16fSGleb Natapov #define N 1000000 35*a9f8b16fSGleb Natapov 36*a9f8b16fSGleb Natapov typedef struct { 37*a9f8b16fSGleb Natapov uint32_t ctr; 38*a9f8b16fSGleb Natapov uint32_t config; 39*a9f8b16fSGleb Natapov uint64_t count; 40*a9f8b16fSGleb Natapov int idx; 41*a9f8b16fSGleb Natapov } pmu_counter_t; 42*a9f8b16fSGleb Natapov 43*a9f8b16fSGleb Natapov union cpuid10_eax { 44*a9f8b16fSGleb Natapov struct { 45*a9f8b16fSGleb Natapov unsigned int version_id:8; 46*a9f8b16fSGleb Natapov unsigned int num_counters:8; 47*a9f8b16fSGleb Natapov unsigned int bit_width:8; 48*a9f8b16fSGleb Natapov unsigned int mask_length:8; 49*a9f8b16fSGleb Natapov } split; 50*a9f8b16fSGleb Natapov unsigned int full; 51*a9f8b16fSGleb Natapov } eax; 52*a9f8b16fSGleb Natapov 53*a9f8b16fSGleb Natapov union cpuid10_ebx { 54*a9f8b16fSGleb Natapov struct { 55*a9f8b16fSGleb Natapov unsigned int no_unhalted_core_cycles:1; 56*a9f8b16fSGleb Natapov unsigned int no_instructions_retired:1; 57*a9f8b16fSGleb Natapov unsigned int no_unhalted_reference_cycles:1; 58*a9f8b16fSGleb Natapov unsigned int no_llc_reference:1; 59*a9f8b16fSGleb Natapov unsigned int no_llc_misses:1; 60*a9f8b16fSGleb Natapov unsigned int no_branch_instruction_retired:1; 61*a9f8b16fSGleb Natapov unsigned int no_branch_misses_retired:1; 62*a9f8b16fSGleb Natapov } split; 63*a9f8b16fSGleb Natapov unsigned int full; 64*a9f8b16fSGleb Natapov } ebx; 65*a9f8b16fSGleb Natapov 66*a9f8b16fSGleb Natapov union cpuid10_edx { 67*a9f8b16fSGleb Natapov struct { 68*a9f8b16fSGleb Natapov unsigned int num_counters_fixed:5; 69*a9f8b16fSGleb Natapov unsigned int bit_width_fixed:8; 70*a9f8b16fSGleb Natapov unsigned int reserved:19; 71*a9f8b16fSGleb Natapov } split; 72*a9f8b16fSGleb Natapov unsigned int full; 73*a9f8b16fSGleb Natapov } edx; 74*a9f8b16fSGleb Natapov 75*a9f8b16fSGleb Natapov struct pmu_event { 76*a9f8b16fSGleb Natapov char *name; 77*a9f8b16fSGleb Natapov uint32_t unit_sel; 78*a9f8b16fSGleb Natapov int min; 79*a9f8b16fSGleb Natapov int max; 80*a9f8b16fSGleb Natapov } gp_events[] = { 81*a9f8b16fSGleb Natapov {"core cycles", 0x003c, 1*N, 50*N}, 82*a9f8b16fSGleb Natapov {"instructions", 0x00c0, 10*N, 10.2*N}, 83*a9f8b16fSGleb Natapov {"ref cycles", 0x013c, 1*N, 30*N}, 84*a9f8b16fSGleb Natapov {"llc refference", 0x4f2e, 1, 1*N}, 85*a9f8b16fSGleb Natapov {"llc misses", 0x412e, 1, 1*N}, 86*a9f8b16fSGleb Natapov {"branches", 0x00c4, 1*N, 1.1*N}, 87*a9f8b16fSGleb Natapov {"branch misses", 0x00c5, 0, 0.1*N}, 88*a9f8b16fSGleb Natapov }, fixed_events[] = { 89*a9f8b16fSGleb Natapov {"fixed 1", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N}, 90*a9f8b16fSGleb Natapov {"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N}, 91*a9f8b16fSGleb Natapov {"fixed 3", MSR_CORE_PERF_FIXED_CTR0 + 2, 1*N, 30*N} 92*a9f8b16fSGleb Natapov }; 93*a9f8b16fSGleb Natapov 94*a9f8b16fSGleb Natapov static int tests, failures; 95*a9f8b16fSGleb Natapov 96*a9f8b16fSGleb Natapov char *buf; 97*a9f8b16fSGleb Natapov 98*a9f8b16fSGleb Natapov static inline void loop() 99*a9f8b16fSGleb Natapov { 100*a9f8b16fSGleb Natapov unsigned long tmp, tmp2, tmp3; 101*a9f8b16fSGleb Natapov 102*a9f8b16fSGleb Natapov asm volatile("1: mov (%1), %2; add $64, %1; nop; nop; nop; nop; nop; nop; nop; loop 1b" 103*a9f8b16fSGleb Natapov : "=c"(tmp), "=r"(tmp2), "=r"(tmp3): "0"(N), "1"(buf)); 104*a9f8b16fSGleb Natapov 105*a9f8b16fSGleb Natapov } 106*a9f8b16fSGleb Natapov 107*a9f8b16fSGleb Natapov volatile uint64_t irq_received; 108*a9f8b16fSGleb Natapov 109*a9f8b16fSGleb Natapov static void cnt_overflow(isr_regs_t *regs) 110*a9f8b16fSGleb Natapov { 111*a9f8b16fSGleb Natapov irq_received++; 112*a9f8b16fSGleb Natapov apic_write(APIC_EOI, 0); 113*a9f8b16fSGleb Natapov } 114*a9f8b16fSGleb Natapov 115*a9f8b16fSGleb Natapov static bool check_irq(void) 116*a9f8b16fSGleb Natapov { 117*a9f8b16fSGleb Natapov int i; 118*a9f8b16fSGleb Natapov irq_received = 0; 119*a9f8b16fSGleb Natapov irq_enable(); 120*a9f8b16fSGleb Natapov for (i = 0; i < 100000 && !irq_received; i++) 121*a9f8b16fSGleb Natapov asm volatile("pause"); 122*a9f8b16fSGleb Natapov irq_disable(); 123*a9f8b16fSGleb Natapov return irq_received; 124*a9f8b16fSGleb Natapov } 125*a9f8b16fSGleb Natapov 126*a9f8b16fSGleb Natapov static bool is_gp(pmu_counter_t *evt) 127*a9f8b16fSGleb Natapov { 128*a9f8b16fSGleb Natapov return evt->ctr < MSR_CORE_PERF_FIXED_CTR0; 129*a9f8b16fSGleb Natapov } 130*a9f8b16fSGleb Natapov 131*a9f8b16fSGleb Natapov static int event_to_global_idx(pmu_counter_t *cnt) 132*a9f8b16fSGleb Natapov { 133*a9f8b16fSGleb Natapov return cnt->ctr - (is_gp(cnt) ? MSR_IA32_PERFCTR0 : 134*a9f8b16fSGleb Natapov (MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX)); 135*a9f8b16fSGleb Natapov } 136*a9f8b16fSGleb Natapov 137*a9f8b16fSGleb Natapov static struct pmu_event* get_counter_event(pmu_counter_t *cnt) 138*a9f8b16fSGleb Natapov { 139*a9f8b16fSGleb Natapov if (is_gp(cnt)) { 140*a9f8b16fSGleb Natapov int i; 141*a9f8b16fSGleb Natapov 142*a9f8b16fSGleb Natapov for (i = 0; i < sizeof(gp_events)/sizeof(gp_events[0]); i++) 143*a9f8b16fSGleb Natapov if (gp_events[i].unit_sel == (cnt->config & 0xffff)) 144*a9f8b16fSGleb Natapov return &gp_events[i]; 145*a9f8b16fSGleb Natapov } else 146*a9f8b16fSGleb Natapov return &fixed_events[cnt->ctr - MSR_CORE_PERF_FIXED_CTR0]; 147*a9f8b16fSGleb Natapov 148*a9f8b16fSGleb Natapov return (void*)0; 149*a9f8b16fSGleb Natapov } 150*a9f8b16fSGleb Natapov 151*a9f8b16fSGleb Natapov static void global_enable(pmu_counter_t *cnt) 152*a9f8b16fSGleb Natapov { 153*a9f8b16fSGleb Natapov cnt->idx = event_to_global_idx(cnt); 154*a9f8b16fSGleb Natapov 155*a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_CTRL) | 156*a9f8b16fSGleb Natapov (1ull << cnt->idx)); 157*a9f8b16fSGleb Natapov } 158*a9f8b16fSGleb Natapov 159*a9f8b16fSGleb Natapov static void global_disable(pmu_counter_t *cnt) 160*a9f8b16fSGleb Natapov { 161*a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_CTRL) & 162*a9f8b16fSGleb Natapov ~(1ull << cnt->idx)); 163*a9f8b16fSGleb Natapov } 164*a9f8b16fSGleb Natapov 165*a9f8b16fSGleb Natapov 166*a9f8b16fSGleb Natapov static void start_event(pmu_counter_t *evt) 167*a9f8b16fSGleb Natapov { 168*a9f8b16fSGleb Natapov wrmsr(evt->ctr, evt->count); 169*a9f8b16fSGleb Natapov if (is_gp(evt)) 170*a9f8b16fSGleb Natapov wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt), 171*a9f8b16fSGleb Natapov evt->config | EVNTSEL_EN); 172*a9f8b16fSGleb Natapov else { 173*a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 174*a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 175*a9f8b16fSGleb Natapov uint32_t usrospmi = 0; 176*a9f8b16fSGleb Natapov 177*a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_OS) 178*a9f8b16fSGleb Natapov usrospmi |= (1 << 0); 179*a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_USR) 180*a9f8b16fSGleb Natapov usrospmi |= (1 << 1); 181*a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_INT) 182*a9f8b16fSGleb Natapov usrospmi |= (1 << 3); // PMI on overflow 183*a9f8b16fSGleb Natapov ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift); 184*a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl); 185*a9f8b16fSGleb Natapov } 186*a9f8b16fSGleb Natapov global_enable(evt); 187*a9f8b16fSGleb Natapov } 188*a9f8b16fSGleb Natapov 189*a9f8b16fSGleb Natapov static void stop_event(pmu_counter_t *evt) 190*a9f8b16fSGleb Natapov { 191*a9f8b16fSGleb Natapov global_disable(evt); 192*a9f8b16fSGleb Natapov if (is_gp(evt)) 193*a9f8b16fSGleb Natapov wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt), 194*a9f8b16fSGleb Natapov evt->config & ~EVNTSEL_EN); 195*a9f8b16fSGleb Natapov else { 196*a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 197*a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 198*a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift)); 199*a9f8b16fSGleb Natapov } 200*a9f8b16fSGleb Natapov evt->count = rdmsr(evt->ctr); 201*a9f8b16fSGleb Natapov } 202*a9f8b16fSGleb Natapov 203*a9f8b16fSGleb Natapov static void measure(pmu_counter_t *evt, int count) 204*a9f8b16fSGleb Natapov { 205*a9f8b16fSGleb Natapov int i; 206*a9f8b16fSGleb Natapov for (i = 0; i < count; i++) 207*a9f8b16fSGleb Natapov start_event(&evt[i]); 208*a9f8b16fSGleb Natapov loop(); 209*a9f8b16fSGleb Natapov for (i = 0; i < count; i++) 210*a9f8b16fSGleb Natapov stop_event(&evt[i]); 211*a9f8b16fSGleb Natapov } 212*a9f8b16fSGleb Natapov 213*a9f8b16fSGleb Natapov static void report(const char *name, int n, bool pass) 214*a9f8b16fSGleb Natapov { 215*a9f8b16fSGleb Natapov printf("%s: pmu %s-%d\n", pass ? "PASS" : "FAIL", name, n); 216*a9f8b16fSGleb Natapov tests += 1; 217*a9f8b16fSGleb Natapov failures += !pass; 218*a9f8b16fSGleb Natapov } 219*a9f8b16fSGleb Natapov 220*a9f8b16fSGleb Natapov static bool verify_event(uint64_t count, struct pmu_event *e) 221*a9f8b16fSGleb Natapov { 222*a9f8b16fSGleb Natapov // printf("%lld >= %lld <= %lld\n", e->min, count, e->max); 223*a9f8b16fSGleb Natapov return count >= e->min && count <= e->max; 224*a9f8b16fSGleb Natapov 225*a9f8b16fSGleb Natapov } 226*a9f8b16fSGleb Natapov 227*a9f8b16fSGleb Natapov static bool verify_counter(pmu_counter_t *cnt) 228*a9f8b16fSGleb Natapov { 229*a9f8b16fSGleb Natapov return verify_event(cnt->count, get_counter_event(cnt)); 230*a9f8b16fSGleb Natapov } 231*a9f8b16fSGleb Natapov 232*a9f8b16fSGleb Natapov static void check_gp_counter(struct pmu_event *evt) 233*a9f8b16fSGleb Natapov { 234*a9f8b16fSGleb Natapov pmu_counter_t cnt = { 235*a9f8b16fSGleb Natapov .ctr = MSR_IA32_PERFCTR0, 236*a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, 237*a9f8b16fSGleb Natapov }; 238*a9f8b16fSGleb Natapov int i; 239*a9f8b16fSGleb Natapov 240*a9f8b16fSGleb Natapov for (i = 0; i < eax.split.num_counters; i++, cnt.ctr++) { 241*a9f8b16fSGleb Natapov cnt.count = 0; 242*a9f8b16fSGleb Natapov measure(&cnt, 1); 243*a9f8b16fSGleb Natapov report(evt->name, i, verify_event(cnt.count, evt)); 244*a9f8b16fSGleb Natapov } 245*a9f8b16fSGleb Natapov } 246*a9f8b16fSGleb Natapov 247*a9f8b16fSGleb Natapov static void check_gp_counters(void) 248*a9f8b16fSGleb Natapov { 249*a9f8b16fSGleb Natapov int i; 250*a9f8b16fSGleb Natapov 251*a9f8b16fSGleb Natapov for (i = 0; i < sizeof(gp_events)/sizeof(gp_events[0]); i++) 252*a9f8b16fSGleb Natapov if (!(ebx.full & (1 << i))) 253*a9f8b16fSGleb Natapov check_gp_counter(&gp_events[i]); 254*a9f8b16fSGleb Natapov else 255*a9f8b16fSGleb Natapov printf("GP event '%s' is disabled\n", 256*a9f8b16fSGleb Natapov gp_events[i].name); 257*a9f8b16fSGleb Natapov } 258*a9f8b16fSGleb Natapov 259*a9f8b16fSGleb Natapov static void check_fixed_counters(void) 260*a9f8b16fSGleb Natapov { 261*a9f8b16fSGleb Natapov pmu_counter_t cnt = { 262*a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR, 263*a9f8b16fSGleb Natapov }; 264*a9f8b16fSGleb Natapov int i; 265*a9f8b16fSGleb Natapov 266*a9f8b16fSGleb Natapov for (i = 0; i < edx.split.num_counters_fixed; i++) { 267*a9f8b16fSGleb Natapov cnt.count = 0; 268*a9f8b16fSGleb Natapov cnt.ctr = fixed_events[i].unit_sel; 269*a9f8b16fSGleb Natapov measure(&cnt, 1); 270*a9f8b16fSGleb Natapov report("fixed", i, verify_event(cnt.count, &fixed_events[i])); 271*a9f8b16fSGleb Natapov } 272*a9f8b16fSGleb Natapov } 273*a9f8b16fSGleb Natapov 274*a9f8b16fSGleb Natapov static void check_counters_many(void) 275*a9f8b16fSGleb Natapov { 276*a9f8b16fSGleb Natapov pmu_counter_t cnt[10]; 277*a9f8b16fSGleb Natapov int i, n; 278*a9f8b16fSGleb Natapov 279*a9f8b16fSGleb Natapov for (i = 0, n = 0; n < eax.split.num_counters; i++) { 280*a9f8b16fSGleb Natapov if (ebx.full & (1 << i)) 281*a9f8b16fSGleb Natapov continue; 282*a9f8b16fSGleb Natapov 283*a9f8b16fSGleb Natapov cnt[n].count = 0; 284*a9f8b16fSGleb Natapov cnt[n].ctr = MSR_IA32_PERFCTR0 + n; 285*a9f8b16fSGleb Natapov cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | gp_events[i].unit_sel; 286*a9f8b16fSGleb Natapov n++; 287*a9f8b16fSGleb Natapov } 288*a9f8b16fSGleb Natapov for (i = 0; i < edx.split.num_counters_fixed; i++) { 289*a9f8b16fSGleb Natapov cnt[n].count = 0; 290*a9f8b16fSGleb Natapov cnt[n].ctr = fixed_events[i].unit_sel; 291*a9f8b16fSGleb Natapov cnt[n].config = EVNTSEL_OS | EVNTSEL_USR; 292*a9f8b16fSGleb Natapov n++; 293*a9f8b16fSGleb Natapov } 294*a9f8b16fSGleb Natapov 295*a9f8b16fSGleb Natapov measure(cnt, n); 296*a9f8b16fSGleb Natapov 297*a9f8b16fSGleb Natapov for (i = 0; i < n; i++) 298*a9f8b16fSGleb Natapov if (!verify_counter(&cnt[i])) 299*a9f8b16fSGleb Natapov break; 300*a9f8b16fSGleb Natapov 301*a9f8b16fSGleb Natapov report("all counters", 0, i == n); 302*a9f8b16fSGleb Natapov } 303*a9f8b16fSGleb Natapov 304*a9f8b16fSGleb Natapov static void check_counter_overflow(void) 305*a9f8b16fSGleb Natapov { 306*a9f8b16fSGleb Natapov uint64_t count; 307*a9f8b16fSGleb Natapov int i; 308*a9f8b16fSGleb Natapov pmu_counter_t cnt = { 309*a9f8b16fSGleb Natapov .ctr = MSR_IA32_PERFCTR0, 310*a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */, 311*a9f8b16fSGleb Natapov .count = 0, 312*a9f8b16fSGleb Natapov }; 313*a9f8b16fSGleb Natapov measure(&cnt, 1); 314*a9f8b16fSGleb Natapov count = cnt.count; 315*a9f8b16fSGleb Natapov 316*a9f8b16fSGleb Natapov /* clear status before test */ 317*a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_STATUS)); 318*a9f8b16fSGleb Natapov 319*a9f8b16fSGleb Natapov for (i = 0; i < eax.split.num_counters + 1; i++, cnt.ctr++) { 320*a9f8b16fSGleb Natapov uint64_t status; 321*a9f8b16fSGleb Natapov int idx; 322*a9f8b16fSGleb Natapov if (i == eax.split.num_counters) 323*a9f8b16fSGleb Natapov cnt.ctr = fixed_events[0].unit_sel; 324*a9f8b16fSGleb Natapov if (i % 2) 325*a9f8b16fSGleb Natapov cnt.config |= EVNTSEL_INT; 326*a9f8b16fSGleb Natapov else 327*a9f8b16fSGleb Natapov cnt.config &= ~EVNTSEL_INT; 328*a9f8b16fSGleb Natapov idx = event_to_global_idx(&cnt); 329*a9f8b16fSGleb Natapov cnt.count = 1 - count; 330*a9f8b16fSGleb Natapov measure(&cnt, 1); 331*a9f8b16fSGleb Natapov report("overflow", i, cnt.count == 1); 332*a9f8b16fSGleb Natapov status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); 333*a9f8b16fSGleb Natapov report("overflow status", i, status & (1ull << idx)); 334*a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, status); 335*a9f8b16fSGleb Natapov status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); 336*a9f8b16fSGleb Natapov report("overflow status clear", i, !(status & (1ull << idx))); 337*a9f8b16fSGleb Natapov report("overflow irq", i, check_irq() == (i % 2)); 338*a9f8b16fSGleb Natapov } 339*a9f8b16fSGleb Natapov } 340*a9f8b16fSGleb Natapov 341*a9f8b16fSGleb Natapov static void check_gp_counter_cmask(void) 342*a9f8b16fSGleb Natapov { 343*a9f8b16fSGleb Natapov pmu_counter_t cnt = { 344*a9f8b16fSGleb Natapov .ctr = MSR_IA32_PERFCTR0, 345*a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */, 346*a9f8b16fSGleb Natapov .count = 0, 347*a9f8b16fSGleb Natapov }; 348*a9f8b16fSGleb Natapov cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT); 349*a9f8b16fSGleb Natapov measure(&cnt, 1); 350*a9f8b16fSGleb Natapov report("cmask", 0, cnt.count < gp_events[1].min); 351*a9f8b16fSGleb Natapov } 352*a9f8b16fSGleb Natapov 353*a9f8b16fSGleb Natapov static void check_rdpmc(void) 354*a9f8b16fSGleb Natapov { 355*a9f8b16fSGleb Natapov uint64_t val = 0x1f3456789ull; 356*a9f8b16fSGleb Natapov int i; 357*a9f8b16fSGleb Natapov 358*a9f8b16fSGleb Natapov for (i = 0; i < eax.split.num_counters; i++) { 359*a9f8b16fSGleb Natapov uint64_t x = (val & 0xffffffff) | 360*a9f8b16fSGleb Natapov ((1ull << (eax.split.bit_width - 32)) - 1) << 32; 361*a9f8b16fSGleb Natapov wrmsr(MSR_IA32_PERFCTR0 + i, val); 362*a9f8b16fSGleb Natapov report("rdpmc", i, rdpmc(i) == x); 363*a9f8b16fSGleb Natapov report("rdpmc fast", i, rdpmc(i | (1<<31)) == (u32)val); 364*a9f8b16fSGleb Natapov } 365*a9f8b16fSGleb Natapov for (i = 0; i < edx.split.num_counters_fixed; i++) { 366*a9f8b16fSGleb Natapov uint64_t x = (val & 0xffffffff) | 367*a9f8b16fSGleb Natapov ((1ull << (edx.split.bit_width_fixed - 32)) - 1) << 32; 368*a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR0 + i, val); 369*a9f8b16fSGleb Natapov report("rdpmc fixed", i, rdpmc(i | (1 << 30)) == x); 370*a9f8b16fSGleb Natapov report("rdpmc fixed fast", i, rdpmc(i | (3<<30)) == (u32)val); 371*a9f8b16fSGleb Natapov } 372*a9f8b16fSGleb Natapov } 373*a9f8b16fSGleb Natapov 374*a9f8b16fSGleb Natapov int main(int ac, char **av) 375*a9f8b16fSGleb Natapov { 376*a9f8b16fSGleb Natapov struct cpuid id = cpuid(10); 377*a9f8b16fSGleb Natapov 378*a9f8b16fSGleb Natapov setup_vm(); 379*a9f8b16fSGleb Natapov setup_idt(); 380*a9f8b16fSGleb Natapov handle_irq(PC_VECTOR, cnt_overflow); 381*a9f8b16fSGleb Natapov buf = vmalloc(N*64); 382*a9f8b16fSGleb Natapov 383*a9f8b16fSGleb Natapov eax.full = id.a; 384*a9f8b16fSGleb Natapov ebx.full = id.b; 385*a9f8b16fSGleb Natapov edx.full = id.d; 386*a9f8b16fSGleb Natapov 387*a9f8b16fSGleb Natapov if (!eax.split.version_id) { 388*a9f8b16fSGleb Natapov printf("No pmu is detected!\n"); 389*a9f8b16fSGleb Natapov return 1; 390*a9f8b16fSGleb Natapov } 391*a9f8b16fSGleb Natapov printf("PMU version: %d\n", eax.split.version_id); 392*a9f8b16fSGleb Natapov printf("GP counters: %d\n", eax.split.num_counters); 393*a9f8b16fSGleb Natapov printf("GP counter width: %d\n", eax.split.bit_width); 394*a9f8b16fSGleb Natapov printf("Mask length: %d\n", eax.split.mask_length); 395*a9f8b16fSGleb Natapov printf("Fixed counters: %d\n", edx.split.num_counters_fixed); 396*a9f8b16fSGleb Natapov printf("Fixed counter width: %d\n", edx.split.bit_width_fixed); 397*a9f8b16fSGleb Natapov 398*a9f8b16fSGleb Natapov apic_write(APIC_LVTPC, PC_VECTOR); 399*a9f8b16fSGleb Natapov 400*a9f8b16fSGleb Natapov check_gp_counters(); 401*a9f8b16fSGleb Natapov check_fixed_counters(); 402*a9f8b16fSGleb Natapov check_rdpmc(); 403*a9f8b16fSGleb Natapov check_counters_many(); 404*a9f8b16fSGleb Natapov check_counter_overflow(); 405*a9f8b16fSGleb Natapov check_gp_counter_cmask(); 406*a9f8b16fSGleb Natapov 407*a9f8b16fSGleb Natapov printf("\n%d tests, %d failures\n", tests, failures); 408*a9f8b16fSGleb Natapov return !failures ? 0 : 1; 409*a9f8b16fSGleb Natapov } 410