1a9f8b16fSGleb Natapov 2a9f8b16fSGleb Natapov #include "x86/msr.h" 3a9f8b16fSGleb Natapov #include "x86/processor.h" 49f17508dSLike Xu #include "x86/pmu.h" 5a9f8b16fSGleb Natapov #include "x86/apic-defs.h" 6a9f8b16fSGleb Natapov #include "x86/apic.h" 7a9f8b16fSGleb Natapov #include "x86/desc.h" 8a9f8b16fSGleb Natapov #include "x86/isr.h" 995a94088SNicholas Piggin #include "vmalloc.h" 10dcda215bSPaolo Bonzini #include "alloc.h" 11a9f8b16fSGleb Natapov 12a9f8b16fSGleb Natapov #include "libcflat.h" 13a9f8b16fSGleb Natapov #include <stdint.h> 14a9f8b16fSGleb Natapov 15a9f8b16fSGleb Natapov #define N 1000000 16a9f8b16fSGleb Natapov 1720cf9147SJim Mattson // These values match the number of instructions and branches in the 1820cf9147SJim Mattson // assembly block in check_emulated_instr(). 1920cf9147SJim Mattson #define EXPECTED_INSTR 17 2020cf9147SJim Mattson #define EXPECTED_BRNCH 5 2120cf9147SJim Mattson 22*38b5b426SDapeng Mi /* Enable GLOBAL_CTRL + disable GLOBAL_CTRL + clflush/mfence instructions */ 23*38b5b426SDapeng Mi #define EXTRA_INSNS (3 + 3 +2) 2489126fa4SDapeng Mi #define LOOP_INSNS (N * 10 + EXTRA_INSNS) 2589126fa4SDapeng Mi #define LOOP_BRANCHES (N) 26*38b5b426SDapeng Mi #define LOOP_ASM(_wrmsr, _clflush) \ 2750f8e27eSDapeng Mi _wrmsr "\n\t" \ 2850f8e27eSDapeng Mi "mov %%ecx, %%edi; mov %%ebx, %%ecx;\n\t" \ 29*38b5b426SDapeng Mi _clflush "\n\t" \ 30*38b5b426SDapeng Mi "mfence;\n\t" \ 3150f8e27eSDapeng Mi "1: mov (%1), %2; add $64, %1;\n\t" \ 3250f8e27eSDapeng Mi "nop; nop; nop; nop; nop; nop; nop;\n\t" \ 3350f8e27eSDapeng Mi "loop 1b;\n\t" \ 3450f8e27eSDapeng Mi "mov %%edi, %%ecx; xor %%eax, %%eax; xor %%edx, %%edx;\n\t" \ 3550f8e27eSDapeng Mi _wrmsr "\n\t" 3650f8e27eSDapeng Mi 37*38b5b426SDapeng Mi #define _loop_asm(_wrmsr, _clflush) \ 38*38b5b426SDapeng Mi do { \ 39*38b5b426SDapeng Mi asm volatile(LOOP_ASM(_wrmsr, _clflush) \ 40*38b5b426SDapeng Mi : "=b"(tmp), "=r"(tmp2), "=r"(tmp3) \ 41*38b5b426SDapeng Mi : "a"(eax), "d"(edx), "c"(global_ctl), \ 42*38b5b426SDapeng Mi "0"(N), "1"(buf) \ 43*38b5b426SDapeng Mi : "edi"); \ 44*38b5b426SDapeng Mi } while (0) 45*38b5b426SDapeng Mi 46a9f8b16fSGleb Natapov typedef struct { 47a9f8b16fSGleb Natapov uint32_t ctr; 489720e46cSDapeng Mi uint32_t idx; 49006b089dSLike Xu uint64_t config; 50a9f8b16fSGleb Natapov uint64_t count; 51a9f8b16fSGleb Natapov } pmu_counter_t; 52a9f8b16fSGleb Natapov 53a9f8b16fSGleb Natapov struct pmu_event { 54797d79a2SThomas Huth const char *name; 55a9f8b16fSGleb Natapov uint32_t unit_sel; 56a9f8b16fSGleb Natapov int min; 57a9f8b16fSGleb Natapov int max; 587c648ce2SLike Xu } intel_gp_events[] = { 59a9f8b16fSGleb Natapov {"core cycles", 0x003c, 1*N, 50*N}, 60a9f8b16fSGleb Natapov {"instructions", 0x00c0, 10*N, 10.2*N}, 61290f4213SJim Mattson {"ref cycles", 0x013c, 1*N, 30*N}, 62290f4213SJim Mattson {"llc references", 0x4f2e, 1, 2*N}, 63a9f8b16fSGleb Natapov {"llc misses", 0x412e, 1, 1*N}, 64a9f8b16fSGleb Natapov {"branches", 0x00c4, 1*N, 1.1*N}, 65a9f8b16fSGleb Natapov {"branch misses", 0x00c5, 0, 0.1*N}, 66b883751aSLike Xu }, amd_gp_events[] = { 67b883751aSLike Xu {"core cycles", 0x0076, 1*N, 50*N}, 68b883751aSLike Xu {"instructions", 0x00c0, 10*N, 10.2*N}, 69b883751aSLike Xu {"branches", 0x00c2, 1*N, 1.1*N}, 70b883751aSLike Xu {"branch misses", 0x00c3, 0, 0.1*N}, 71a9f8b16fSGleb Natapov }, fixed_events[] = { 725d6a3a54SDapeng Mi {"fixed 0", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N}, 735d6a3a54SDapeng Mi {"fixed 1", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N}, 745d6a3a54SDapeng Mi {"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 2, 0.1*N, 30*N} 75a9f8b16fSGleb Natapov }; 76a9f8b16fSGleb Natapov 77f4e97f59SDapeng Mi /* 78f4e97f59SDapeng Mi * Events index in intel_gp_events[], ensure consistent with 79f4e97f59SDapeng Mi * intel_gp_events[]. 80f4e97f59SDapeng Mi */ 81f4e97f59SDapeng Mi enum { 8285c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX = 1, 8325cc1ea7SDapeng Mi INTEL_REF_CYCLES_IDX = 2, 84f4e97f59SDapeng Mi INTEL_BRANCHES_IDX = 5, 85f4e97f59SDapeng Mi }; 86f4e97f59SDapeng Mi 87f4e97f59SDapeng Mi /* 88f4e97f59SDapeng Mi * Events index in amd_gp_events[], ensure consistent with 89f4e97f59SDapeng Mi * amd_gp_events[]. 90f4e97f59SDapeng Mi */ 91f4e97f59SDapeng Mi enum { 9285c75578SDapeng Mi AMD_INSTRUCTIONS_IDX = 1, 93f4e97f59SDapeng Mi AMD_BRANCHES_IDX = 2, 94f4e97f59SDapeng Mi }; 95f4e97f59SDapeng Mi 96a9f8b16fSGleb Natapov char *buf; 97a9f8b16fSGleb Natapov 987c648ce2SLike Xu static struct pmu_event *gp_events; 997c648ce2SLike Xu static unsigned int gp_events_size; 1009c07c92bSDapeng Mi static unsigned int fixed_counters_num; 1017c648ce2SLike Xu 10250f8e27eSDapeng Mi static inline void __loop(void) 103a9f8b16fSGleb Natapov { 104a9f8b16fSGleb Natapov unsigned long tmp, tmp2, tmp3; 105*38b5b426SDapeng Mi u32 global_ctl = 0; 106*38b5b426SDapeng Mi u32 eax = 0; 107*38b5b426SDapeng Mi u32 edx = 0; 108a9f8b16fSGleb Natapov 109*38b5b426SDapeng Mi if (this_cpu_has(X86_FEATURE_CLFLUSH)) 110*38b5b426SDapeng Mi _loop_asm("nop", "clflush (%1)"); 111*38b5b426SDapeng Mi else 112*38b5b426SDapeng Mi _loop_asm("nop", "nop"); 11350f8e27eSDapeng Mi } 114a9f8b16fSGleb Natapov 11550f8e27eSDapeng Mi /* 11650f8e27eSDapeng Mi * Enable and disable counters in a whole asm blob to ensure 11750f8e27eSDapeng Mi * no other instructions are counted in the window between 11850f8e27eSDapeng Mi * counters enabling and really LOOP_ASM code executing. 11950f8e27eSDapeng Mi * Thus counters can verify instructions and branches events 12050f8e27eSDapeng Mi * against precise counts instead of a rough valid count range. 12150f8e27eSDapeng Mi */ 12250f8e27eSDapeng Mi static inline void __precise_loop(u64 cntrs) 12350f8e27eSDapeng Mi { 12450f8e27eSDapeng Mi unsigned long tmp, tmp2, tmp3; 125*38b5b426SDapeng Mi u32 global_ctl = pmu.msr_global_ctl; 12650f8e27eSDapeng Mi u32 eax = cntrs & (BIT_ULL(32) - 1); 12750f8e27eSDapeng Mi u32 edx = cntrs >> 32; 12850f8e27eSDapeng Mi 129*38b5b426SDapeng Mi if (this_cpu_has(X86_FEATURE_CLFLUSH)) 130*38b5b426SDapeng Mi _loop_asm("wrmsr", "clflush (%1)"); 131*38b5b426SDapeng Mi else 132*38b5b426SDapeng Mi _loop_asm("wrmsr", "nop"); 13350f8e27eSDapeng Mi } 13450f8e27eSDapeng Mi 13550f8e27eSDapeng Mi static inline void loop(u64 cntrs) 13650f8e27eSDapeng Mi { 13750f8e27eSDapeng Mi if (!this_cpu_has_perf_global_ctrl()) 13850f8e27eSDapeng Mi __loop(); 13950f8e27eSDapeng Mi else 14050f8e27eSDapeng Mi __precise_loop(cntrs); 141a9f8b16fSGleb Natapov } 142a9f8b16fSGleb Natapov 14389126fa4SDapeng Mi static void adjust_events_range(struct pmu_event *gp_events, 14489126fa4SDapeng Mi int instruction_idx, int branch_idx) 14589126fa4SDapeng Mi { 14689126fa4SDapeng Mi /* 14789126fa4SDapeng Mi * If HW supports GLOBAL_CTRL MSR, enabling and disabling PMCs are 14889126fa4SDapeng Mi * moved in __precise_loop(). Thus, instructions and branches events 14989126fa4SDapeng Mi * can be verified against a precise count instead of a rough range. 15089126fa4SDapeng Mi * 15189126fa4SDapeng Mi * Skip the precise checks on AMD, as AMD CPUs count VMRUN as a branch 15289126fa4SDapeng Mi * instruction in guest context, which* leads to intermittent failures 15389126fa4SDapeng Mi * as the counts will vary depending on how many asynchronous VM-Exits 15489126fa4SDapeng Mi * occur while running the measured code, e.g. if the host takes IRQs. 15589126fa4SDapeng Mi */ 15689126fa4SDapeng Mi if (pmu.is_intel && this_cpu_has_perf_global_ctrl()) { 15789126fa4SDapeng Mi gp_events[instruction_idx].min = LOOP_INSNS; 15889126fa4SDapeng Mi gp_events[instruction_idx].max = LOOP_INSNS; 15989126fa4SDapeng Mi gp_events[branch_idx].min = LOOP_BRANCHES; 16089126fa4SDapeng Mi gp_events[branch_idx].max = LOOP_BRANCHES; 16189126fa4SDapeng Mi } 16289126fa4SDapeng Mi } 16389126fa4SDapeng Mi 164a9f8b16fSGleb Natapov volatile uint64_t irq_received; 165a9f8b16fSGleb Natapov 166a9f8b16fSGleb Natapov static void cnt_overflow(isr_regs_t *regs) 167a9f8b16fSGleb Natapov { 168a9f8b16fSGleb Natapov irq_received++; 169c595c361SMingwei Zhang apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); 170a9f8b16fSGleb Natapov apic_write(APIC_EOI, 0); 171a9f8b16fSGleb Natapov } 172a9f8b16fSGleb Natapov 173a9f8b16fSGleb Natapov static bool check_irq(void) 174a9f8b16fSGleb Natapov { 175a9f8b16fSGleb Natapov int i; 176a9f8b16fSGleb Natapov irq_received = 0; 177787f0aebSMaxim Levitsky sti(); 178a9f8b16fSGleb Natapov for (i = 0; i < 100000 && !irq_received; i++) 179a9f8b16fSGleb Natapov asm volatile("pause"); 180787f0aebSMaxim Levitsky cli(); 181a9f8b16fSGleb Natapov return irq_received; 182a9f8b16fSGleb Natapov } 183a9f8b16fSGleb Natapov 184a9f8b16fSGleb Natapov static bool is_gp(pmu_counter_t *evt) 185a9f8b16fSGleb Natapov { 186b883751aSLike Xu if (!pmu.is_intel) 187b883751aSLike Xu return true; 188b883751aSLike Xu 18922f2901aSLike Xu return evt->ctr < MSR_CORE_PERF_FIXED_CTR0 || 19022f2901aSLike Xu evt->ctr >= MSR_IA32_PMC0; 191a9f8b16fSGleb Natapov } 192a9f8b16fSGleb Natapov 193a9f8b16fSGleb Natapov static int event_to_global_idx(pmu_counter_t *cnt) 194a9f8b16fSGleb Natapov { 195b883751aSLike Xu if (pmu.is_intel) 196cda64e80SLike Xu return cnt->ctr - (is_gp(cnt) ? pmu.msr_gp_counter_base : 197a9f8b16fSGleb Natapov (MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX)); 198b883751aSLike Xu 199b883751aSLike Xu if (pmu.msr_gp_counter_base == MSR_F15H_PERF_CTR0) 200b883751aSLike Xu return (cnt->ctr - pmu.msr_gp_counter_base) / 2; 201b883751aSLike Xu else 202b883751aSLike Xu return cnt->ctr - pmu.msr_gp_counter_base; 203a9f8b16fSGleb Natapov } 204a9f8b16fSGleb Natapov 205a9f8b16fSGleb Natapov static struct pmu_event* get_counter_event(pmu_counter_t *cnt) 206a9f8b16fSGleb Natapov { 207a9f8b16fSGleb Natapov if (is_gp(cnt)) { 208a9f8b16fSGleb Natapov int i; 209a9f8b16fSGleb Natapov 2107c648ce2SLike Xu for (i = 0; i < gp_events_size; i++) 211a9f8b16fSGleb Natapov if (gp_events[i].unit_sel == (cnt->config & 0xffff)) 212a9f8b16fSGleb Natapov return &gp_events[i]; 2139c07c92bSDapeng Mi } else { 2149c07c92bSDapeng Mi unsigned int idx = cnt->ctr - MSR_CORE_PERF_FIXED_CTR0; 2159c07c92bSDapeng Mi 2169c07c92bSDapeng Mi if (idx < ARRAY_SIZE(fixed_events)) 2179c07c92bSDapeng Mi return &fixed_events[idx]; 2189c07c92bSDapeng Mi } 219a9f8b16fSGleb Natapov 220a9f8b16fSGleb Natapov return (void*)0; 221a9f8b16fSGleb Natapov } 222a9f8b16fSGleb Natapov 223a9f8b16fSGleb Natapov static void global_enable(pmu_counter_t *cnt) 224a9f8b16fSGleb Natapov { 22562ba5036SLike Xu if (!this_cpu_has_perf_global_ctrl()) 22662ba5036SLike Xu return; 22762ba5036SLike Xu 228a9f8b16fSGleb Natapov cnt->idx = event_to_global_idx(cnt); 2298a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) | BIT_ULL(cnt->idx)); 230a9f8b16fSGleb Natapov } 231a9f8b16fSGleb Natapov 232a9f8b16fSGleb Natapov static void global_disable(pmu_counter_t *cnt) 233a9f8b16fSGleb Natapov { 23462ba5036SLike Xu if (!this_cpu_has_perf_global_ctrl()) 23562ba5036SLike Xu return; 23662ba5036SLike Xu 2378a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) & ~BIT_ULL(cnt->idx)); 238a9f8b16fSGleb Natapov } 239a9f8b16fSGleb Natapov 240e9e7577bSLike Xu static void __start_event(pmu_counter_t *evt, uint64_t count) 241a9f8b16fSGleb Natapov { 242e9e7577bSLike Xu evt->count = count; 243a9f8b16fSGleb Natapov wrmsr(evt->ctr, evt->count); 244cda64e80SLike Xu if (is_gp(evt)) { 245cda64e80SLike Xu wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)), 246a9f8b16fSGleb Natapov evt->config | EVNTSEL_EN); 247cda64e80SLike Xu } else { 248a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 249a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 250a9f8b16fSGleb Natapov uint32_t usrospmi = 0; 251a9f8b16fSGleb Natapov 252a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_OS) 253a9f8b16fSGleb Natapov usrospmi |= (1 << 0); 254a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_USR) 255a9f8b16fSGleb Natapov usrospmi |= (1 << 1); 256a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_INT) 257a9f8b16fSGleb Natapov usrospmi |= (1 << 3); // PMI on overflow 258a9f8b16fSGleb Natapov ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift); 259a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl); 260a9f8b16fSGleb Natapov } 2615a2cb3e6SLike Xu apic_write(APIC_LVTPC, PMI_VECTOR); 262a9f8b16fSGleb Natapov } 263a9f8b16fSGleb Natapov 264e9e7577bSLike Xu static void start_event(pmu_counter_t *evt) 265e9e7577bSLike Xu { 266e9e7577bSLike Xu __start_event(evt, 0); 26750f8e27eSDapeng Mi global_enable(evt); 268e9e7577bSLike Xu } 269e9e7577bSLike Xu 27050f8e27eSDapeng Mi static void __stop_event(pmu_counter_t *evt) 271a9f8b16fSGleb Natapov { 272cda64e80SLike Xu if (is_gp(evt)) { 273cda64e80SLike Xu wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)), 274a9f8b16fSGleb Natapov evt->config & ~EVNTSEL_EN); 275cda64e80SLike Xu } else { 276a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 277a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 278a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift)); 279a9f8b16fSGleb Natapov } 280a9f8b16fSGleb Natapov evt->count = rdmsr(evt->ctr); 281a9f8b16fSGleb Natapov } 282a9f8b16fSGleb Natapov 28350f8e27eSDapeng Mi static void stop_event(pmu_counter_t *evt) 28450f8e27eSDapeng Mi { 28550f8e27eSDapeng Mi global_disable(evt); 28650f8e27eSDapeng Mi __stop_event(evt); 28750f8e27eSDapeng Mi } 28850f8e27eSDapeng Mi 2898554261fSLike Xu static noinline void measure_many(pmu_counter_t *evt, int count) 290a9f8b16fSGleb Natapov { 291a9f8b16fSGleb Natapov int i; 29250f8e27eSDapeng Mi u64 cntrs = 0; 29350f8e27eSDapeng Mi 29450f8e27eSDapeng Mi for (i = 0; i < count; i++) { 29550f8e27eSDapeng Mi __start_event(&evt[i], 0); 29650f8e27eSDapeng Mi cntrs |= BIT_ULL(event_to_global_idx(&evt[i])); 29750f8e27eSDapeng Mi } 29850f8e27eSDapeng Mi loop(cntrs); 299a9f8b16fSGleb Natapov for (i = 0; i < count; i++) 30050f8e27eSDapeng Mi __stop_event(&evt[i]); 301a9f8b16fSGleb Natapov } 302a9f8b16fSGleb Natapov 3038554261fSLike Xu static void measure_one(pmu_counter_t *evt) 3048554261fSLike Xu { 3058554261fSLike Xu measure_many(evt, 1); 3068554261fSLike Xu } 3078554261fSLike Xu 308e9e7577bSLike Xu static noinline void __measure(pmu_counter_t *evt, uint64_t count) 309e9e7577bSLike Xu { 31050f8e27eSDapeng Mi u64 cntrs = BIT_ULL(event_to_global_idx(evt)); 31150f8e27eSDapeng Mi 312e9e7577bSLike Xu __start_event(evt, count); 31350f8e27eSDapeng Mi loop(cntrs); 31450f8e27eSDapeng Mi __stop_event(evt); 315e9e7577bSLike Xu } 316e9e7577bSLike Xu 317a9f8b16fSGleb Natapov static bool verify_event(uint64_t count, struct pmu_event *e) 318a9f8b16fSGleb Natapov { 3199c07c92bSDapeng Mi bool pass; 320d24d3381SDapeng Mi 3219c07c92bSDapeng Mi if (!e) 3229c07c92bSDapeng Mi return false; 3239c07c92bSDapeng Mi 3249c07c92bSDapeng Mi pass = count >= e->min && count <= e->max; 325d24d3381SDapeng Mi if (!pass) 326d24d3381SDapeng Mi printf("FAIL: %d <= %"PRId64" <= %d\n", e->min, count, e->max); 327d24d3381SDapeng Mi 328d24d3381SDapeng Mi return pass; 329a9f8b16fSGleb Natapov } 330a9f8b16fSGleb Natapov 331a9f8b16fSGleb Natapov static bool verify_counter(pmu_counter_t *cnt) 332a9f8b16fSGleb Natapov { 333a9f8b16fSGleb Natapov return verify_event(cnt->count, get_counter_event(cnt)); 334a9f8b16fSGleb Natapov } 335a9f8b16fSGleb Natapov 336a9f8b16fSGleb Natapov static void check_gp_counter(struct pmu_event *evt) 337a9f8b16fSGleb Natapov { 338a9f8b16fSGleb Natapov pmu_counter_t cnt = { 339a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, 340a9f8b16fSGleb Natapov }; 341a9f8b16fSGleb Natapov int i; 342a9f8b16fSGleb Natapov 343cda64e80SLike Xu for (i = 0; i < pmu.nr_gp_counters; i++) { 344cda64e80SLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 3458554261fSLike Xu measure_one(&cnt); 346a299895bSThomas Huth report(verify_event(cnt.count, evt), "%s-%d", evt->name, i); 347a9f8b16fSGleb Natapov } 348a9f8b16fSGleb Natapov } 349a9f8b16fSGleb Natapov 350a9f8b16fSGleb Natapov static void check_gp_counters(void) 351a9f8b16fSGleb Natapov { 352a9f8b16fSGleb Natapov int i; 353a9f8b16fSGleb Natapov 3547c648ce2SLike Xu for (i = 0; i < gp_events_size; i++) 3552719b92cSYang Weijiang if (pmu_gp_counter_is_available(i)) 356a9f8b16fSGleb Natapov check_gp_counter(&gp_events[i]); 357a9f8b16fSGleb Natapov else 358a9f8b16fSGleb Natapov printf("GP event '%s' is disabled\n", 359a9f8b16fSGleb Natapov gp_events[i].name); 360a9f8b16fSGleb Natapov } 361a9f8b16fSGleb Natapov 362a9f8b16fSGleb Natapov static void check_fixed_counters(void) 363a9f8b16fSGleb Natapov { 364a9f8b16fSGleb Natapov pmu_counter_t cnt = { 365a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR, 366a9f8b16fSGleb Natapov }; 367a9f8b16fSGleb Natapov int i; 368a9f8b16fSGleb Natapov 3699c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 370a9f8b16fSGleb Natapov cnt.ctr = fixed_events[i].unit_sel; 3718554261fSLike Xu measure_one(&cnt); 3722719b92cSYang Weijiang report(verify_event(cnt.count, &fixed_events[i]), "fixed-%d", i); 373a9f8b16fSGleb Natapov } 374a9f8b16fSGleb Natapov } 375a9f8b16fSGleb Natapov 376a9f8b16fSGleb Natapov static void check_counters_many(void) 377a9f8b16fSGleb Natapov { 378f21c809eSDapeng Mi pmu_counter_t cnt[48]; 379a9f8b16fSGleb Natapov int i, n; 380a9f8b16fSGleb Natapov 381414ee7d1SSean Christopherson for (i = 0, n = 0; n < pmu.nr_gp_counters; i++) { 3822719b92cSYang Weijiang if (!pmu_gp_counter_is_available(i)) 383a9f8b16fSGleb Natapov continue; 384a9f8b16fSGleb Natapov 385cda64e80SLike Xu cnt[n].ctr = MSR_GP_COUNTERx(n); 3864ac45293SWei Huang cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | 3877c648ce2SLike Xu gp_events[i % gp_events_size].unit_sel; 388a9f8b16fSGleb Natapov n++; 389a9f8b16fSGleb Natapov } 3909c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 391a9f8b16fSGleb Natapov cnt[n].ctr = fixed_events[i].unit_sel; 392a9f8b16fSGleb Natapov cnt[n].config = EVNTSEL_OS | EVNTSEL_USR; 393a9f8b16fSGleb Natapov n++; 394a9f8b16fSGleb Natapov } 395a9f8b16fSGleb Natapov 396f21c809eSDapeng Mi assert(n <= ARRAY_SIZE(cnt)); 3978554261fSLike Xu measure_many(cnt, n); 398a9f8b16fSGleb Natapov 399a9f8b16fSGleb Natapov for (i = 0; i < n; i++) 400a9f8b16fSGleb Natapov if (!verify_counter(&cnt[i])) 401a9f8b16fSGleb Natapov break; 402a9f8b16fSGleb Natapov 403a299895bSThomas Huth report(i == n, "all counters"); 404a9f8b16fSGleb Natapov } 405a9f8b16fSGleb Natapov 4067ec3b67aSLike Xu static uint64_t measure_for_overflow(pmu_counter_t *cnt) 4077ec3b67aSLike Xu { 4087ec3b67aSLike Xu __measure(cnt, 0); 4097ec3b67aSLike Xu /* 4107ec3b67aSLike Xu * To generate overflow, i.e. roll over to '0', the initial count just 4117ec3b67aSLike Xu * needs to be preset to the negative expected count. However, as per 4127ec3b67aSLike Xu * Intel's SDM, the preset count needs to be incremented by 1 to ensure 4137ec3b67aSLike Xu * the overflow interrupt is generated immediately instead of possibly 4147ec3b67aSLike Xu * waiting for the overflow to propagate through the counter. 4157ec3b67aSLike Xu */ 4167ec3b67aSLike Xu assert(cnt->count > 1); 4177ec3b67aSLike Xu return 1 - cnt->count; 4187ec3b67aSLike Xu } 4197ec3b67aSLike Xu 420a9f8b16fSGleb Natapov static void check_counter_overflow(void) 421a9f8b16fSGleb Natapov { 422a9f8b16fSGleb Natapov int i; 42385c75578SDapeng Mi uint64_t overflow_preset; 42485c75578SDapeng Mi int instruction_idx = pmu.is_intel ? 42585c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 42685c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 42785c75578SDapeng Mi 428a9f8b16fSGleb Natapov pmu_counter_t cnt = { 429cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 43085c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 43185c75578SDapeng Mi gp_events[instruction_idx].unit_sel /* instructions */, 432a9f8b16fSGleb Natapov }; 4337ec3b67aSLike Xu overflow_preset = measure_for_overflow(&cnt); 434a9f8b16fSGleb Natapov 435a9f8b16fSGleb Natapov /* clear status before test */ 43662ba5036SLike Xu if (this_cpu_has_perf_global_status()) 4378a2866d1SLike Xu pmu_clear_global_status(); 438a9f8b16fSGleb Natapov 4395bba1769SAndrew Jones report_prefix_push("overflow"); 4405bba1769SAndrew Jones 441cda64e80SLike Xu for (i = 0; i < pmu.nr_gp_counters + 1; i++) { 442a9f8b16fSGleb Natapov uint64_t status; 443a9f8b16fSGleb Natapov int idx; 44433cfc1b0SNadav Amit 4457ec3b67aSLike Xu cnt.count = overflow_preset; 446cda64e80SLike Xu if (pmu_use_full_writes()) 447414ee7d1SSean Christopherson cnt.count &= (1ull << pmu.gp_counter_width) - 1; 44833cfc1b0SNadav Amit 449414ee7d1SSean Christopherson if (i == pmu.nr_gp_counters) { 450b883751aSLike Xu if (!pmu.is_intel) 451b883751aSLike Xu break; 452b883751aSLike Xu 453a9f8b16fSGleb Natapov cnt.ctr = fixed_events[0].unit_sel; 4547ec3b67aSLike Xu cnt.count = measure_for_overflow(&cnt); 455cda64e80SLike Xu cnt.count &= (1ull << pmu.gp_counter_width) - 1; 456cda64e80SLike Xu } else { 457cda64e80SLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 45833cfc1b0SNadav Amit } 45933cfc1b0SNadav Amit 460a9f8b16fSGleb Natapov if (i % 2) 461a9f8b16fSGleb Natapov cnt.config |= EVNTSEL_INT; 462a9f8b16fSGleb Natapov else 463a9f8b16fSGleb Natapov cnt.config &= ~EVNTSEL_INT; 464a9f8b16fSGleb Natapov idx = event_to_global_idx(&cnt); 465e9e7577bSLike Xu __measure(&cnt, cnt.count); 466b883751aSLike Xu if (pmu.is_intel) 467a299895bSThomas Huth report(cnt.count == 1, "cntr-%d", i); 468b883751aSLike Xu else 469b883751aSLike Xu report(cnt.count == 0xffffffffffff || cnt.count < 7, "cntr-%d", i); 47062ba5036SLike Xu 47162ba5036SLike Xu if (!this_cpu_has_perf_global_status()) 47262ba5036SLike Xu continue; 47362ba5036SLike Xu 4748a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 475a299895bSThomas Huth report(status & (1ull << idx), "status-%d", i); 4768a2866d1SLike Xu wrmsr(pmu.msr_global_status_clr, status); 4778a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 478a299895bSThomas Huth report(!(status & (1ull << idx)), "status clear-%d", i); 479a299895bSThomas Huth report(check_irq() == (i % 2), "irq-%d", i); 480a9f8b16fSGleb Natapov } 4815bba1769SAndrew Jones 4825bba1769SAndrew Jones report_prefix_pop(); 483a9f8b16fSGleb Natapov } 484a9f8b16fSGleb Natapov 485a9f8b16fSGleb Natapov static void check_gp_counter_cmask(void) 486a9f8b16fSGleb Natapov { 48785c75578SDapeng Mi int instruction_idx = pmu.is_intel ? 48885c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 48985c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 49085c75578SDapeng Mi 491a9f8b16fSGleb Natapov pmu_counter_t cnt = { 492cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 49385c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 49485c75578SDapeng Mi gp_events[instruction_idx].unit_sel /* instructions */, 495a9f8b16fSGleb Natapov }; 496a9f8b16fSGleb Natapov cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT); 4978554261fSLike Xu measure_one(&cnt); 49885c75578SDapeng Mi report(cnt.count < gp_events[instruction_idx].min, "cmask"); 499a9f8b16fSGleb Natapov } 500a9f8b16fSGleb Natapov 501ca1b9de9SNadav Amit static void do_rdpmc_fast(void *ptr) 502ca1b9de9SNadav Amit { 503ca1b9de9SNadav Amit pmu_counter_t *cnt = ptr; 504ca1b9de9SNadav Amit uint32_t idx = (uint32_t)cnt->idx | (1u << 31); 505ca1b9de9SNadav Amit 506ca1b9de9SNadav Amit if (!is_gp(cnt)) 507ca1b9de9SNadav Amit idx |= 1 << 30; 508ca1b9de9SNadav Amit 509ca1b9de9SNadav Amit cnt->count = rdpmc(idx); 510ca1b9de9SNadav Amit } 511ca1b9de9SNadav Amit 512ca1b9de9SNadav Amit 513a9f8b16fSGleb Natapov static void check_rdpmc(void) 514a9f8b16fSGleb Natapov { 51522f2901aSLike Xu uint64_t val = 0xff0123456789ull; 516ca1b9de9SNadav Amit bool exc; 517a9f8b16fSGleb Natapov int i; 518a9f8b16fSGleb Natapov 5195bba1769SAndrew Jones report_prefix_push("rdpmc"); 5205bba1769SAndrew Jones 521414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 52233cfc1b0SNadav Amit uint64_t x; 523ca1b9de9SNadav Amit pmu_counter_t cnt = { 524cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(i), 525ca1b9de9SNadav Amit .idx = i 526ca1b9de9SNadav Amit }; 52733cfc1b0SNadav Amit 52833cfc1b0SNadav Amit /* 52922f2901aSLike Xu * Without full-width writes, only the low 32 bits are writable, 53022f2901aSLike Xu * and the value is sign-extended. 53133cfc1b0SNadav Amit */ 532cda64e80SLike Xu if (pmu.msr_gp_counter_base == MSR_IA32_PERFCTR0) 53333cfc1b0SNadav Amit x = (uint64_t)(int64_t)(int32_t)val; 53422f2901aSLike Xu else 53522f2901aSLike Xu x = (uint64_t)(int64_t)val; 53633cfc1b0SNadav Amit 53733cfc1b0SNadav Amit /* Mask according to the number of supported bits */ 538414ee7d1SSean Christopherson x &= (1ull << pmu.gp_counter_width) - 1; 53933cfc1b0SNadav Amit 540cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(i), val); 541a299895bSThomas Huth report(rdpmc(i) == x, "cntr-%d", i); 542ca1b9de9SNadav Amit 543ca1b9de9SNadav Amit exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 544ca1b9de9SNadav Amit if (exc) 545ca1b9de9SNadav Amit report_skip("fast-%d", i); 546ca1b9de9SNadav Amit else 547a299895bSThomas Huth report(cnt.count == (u32)val, "fast-%d", i); 548a9f8b16fSGleb Natapov } 5499c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 550414ee7d1SSean Christopherson uint64_t x = val & ((1ull << pmu.fixed_counter_width) - 1); 551ca1b9de9SNadav Amit pmu_counter_t cnt = { 552ca1b9de9SNadav Amit .ctr = MSR_CORE_PERF_FIXED_CTR0 + i, 553ca1b9de9SNadav Amit .idx = i 554ca1b9de9SNadav Amit }; 55533cfc1b0SNadav Amit 5563f914933SLike Xu wrmsr(MSR_PERF_FIXED_CTRx(i), x); 557a299895bSThomas Huth report(rdpmc(i | (1 << 30)) == x, "fixed cntr-%d", i); 558ca1b9de9SNadav Amit 559ca1b9de9SNadav Amit exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 560ca1b9de9SNadav Amit if (exc) 561ca1b9de9SNadav Amit report_skip("fixed fast-%d", i); 562ca1b9de9SNadav Amit else 563a299895bSThomas Huth report(cnt.count == (u32)x, "fixed fast-%d", i); 564a9f8b16fSGleb Natapov } 5655bba1769SAndrew Jones 5665bba1769SAndrew Jones report_prefix_pop(); 567a9f8b16fSGleb Natapov } 568a9f8b16fSGleb Natapov 569ddade902SEric Hankland static void check_running_counter_wrmsr(void) 570ddade902SEric Hankland { 57159ca1413SEric Hankland uint64_t status; 57222f2901aSLike Xu uint64_t count; 57385c75578SDapeng Mi unsigned int instruction_idx = pmu.is_intel ? 57485c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 57585c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 57685c75578SDapeng Mi 577ddade902SEric Hankland pmu_counter_t evt = { 578cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 57985c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 58085c75578SDapeng Mi gp_events[instruction_idx].unit_sel, 581ddade902SEric Hankland }; 582ddade902SEric Hankland 58359ca1413SEric Hankland report_prefix_push("running counter wrmsr"); 58459ca1413SEric Hankland 585ddade902SEric Hankland start_event(&evt); 58650f8e27eSDapeng Mi __loop(); 587cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(0), 0); 588ddade902SEric Hankland stop_event(&evt); 58985c75578SDapeng Mi report(evt.count < gp_events[instruction_idx].min, "cntr"); 59059ca1413SEric Hankland 59159ca1413SEric Hankland /* clear status before overflow test */ 59262ba5036SLike Xu if (this_cpu_has_perf_global_status()) 5938a2866d1SLike Xu pmu_clear_global_status(); 59459ca1413SEric Hankland 59559ca1413SEric Hankland start_event(&evt); 59622f2901aSLike Xu 59722f2901aSLike Xu count = -1; 598cda64e80SLike Xu if (pmu_use_full_writes()) 599414ee7d1SSean Christopherson count &= (1ull << pmu.gp_counter_width) - 1; 60022f2901aSLike Xu 601cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(0), count); 60222f2901aSLike Xu 60350f8e27eSDapeng Mi __loop(); 60459ca1413SEric Hankland stop_event(&evt); 60562ba5036SLike Xu 60662ba5036SLike Xu if (this_cpu_has_perf_global_status()) { 6078a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 6088a2866d1SLike Xu report(status & 1, "status msr bit"); 60962ba5036SLike Xu } 61059ca1413SEric Hankland 61159ca1413SEric Hankland report_prefix_pop(); 612ddade902SEric Hankland } 613ddade902SEric Hankland 61420cf9147SJim Mattson static void check_emulated_instr(void) 61520cf9147SJim Mattson { 61620cf9147SJim Mattson uint64_t status, instr_start, brnch_start; 6178b547cc2SLike Xu uint64_t gp_counter_width = (1ull << pmu.gp_counter_width) - 1; 618f4e97f59SDapeng Mi unsigned int branch_idx = pmu.is_intel ? 619f4e97f59SDapeng Mi INTEL_BRANCHES_IDX : AMD_BRANCHES_IDX; 62085c75578SDapeng Mi unsigned int instruction_idx = pmu.is_intel ? 62185c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 62285c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 62320cf9147SJim Mattson pmu_counter_t brnch_cnt = { 624cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 62520cf9147SJim Mattson /* branch instructions */ 626b883751aSLike Xu .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[branch_idx].unit_sel, 62720cf9147SJim Mattson }; 62820cf9147SJim Mattson pmu_counter_t instr_cnt = { 629cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(1), 63020cf9147SJim Mattson /* instructions */ 63185c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[instruction_idx].unit_sel, 63220cf9147SJim Mattson }; 63320cf9147SJim Mattson report_prefix_push("emulated instruction"); 63420cf9147SJim Mattson 63562ba5036SLike Xu if (this_cpu_has_perf_global_status()) 6368a2866d1SLike Xu pmu_clear_global_status(); 63720cf9147SJim Mattson 63820cf9147SJim Mattson start_event(&brnch_cnt); 63920cf9147SJim Mattson start_event(&instr_cnt); 64020cf9147SJim Mattson 64120cf9147SJim Mattson brnch_start = -EXPECTED_BRNCH; 64220cf9147SJim Mattson instr_start = -EXPECTED_INSTR; 6438b547cc2SLike Xu wrmsr(MSR_GP_COUNTERx(0), brnch_start & gp_counter_width); 6448b547cc2SLike Xu wrmsr(MSR_GP_COUNTERx(1), instr_start & gp_counter_width); 64520cf9147SJim Mattson // KVM_FEP is a magic prefix that forces emulation so 64620cf9147SJim Mattson // 'KVM_FEP "jne label\n"' just counts as a single instruction. 64720cf9147SJim Mattson asm volatile( 64820cf9147SJim Mattson "mov $0x0, %%eax\n" 64920cf9147SJim Mattson "cmp $0x0, %%eax\n" 65020cf9147SJim Mattson KVM_FEP "jne label\n" 65120cf9147SJim Mattson KVM_FEP "jne label\n" 65220cf9147SJim Mattson KVM_FEP "jne label\n" 65320cf9147SJim Mattson KVM_FEP "jne label\n" 65420cf9147SJim Mattson KVM_FEP "jne label\n" 65520cf9147SJim Mattson "mov $0xa, %%eax\n" 65620cf9147SJim Mattson "cpuid\n" 65720cf9147SJim Mattson "mov $0xa, %%eax\n" 65820cf9147SJim Mattson "cpuid\n" 65920cf9147SJim Mattson "mov $0xa, %%eax\n" 66020cf9147SJim Mattson "cpuid\n" 66120cf9147SJim Mattson "mov $0xa, %%eax\n" 66220cf9147SJim Mattson "cpuid\n" 66320cf9147SJim Mattson "mov $0xa, %%eax\n" 66420cf9147SJim Mattson "cpuid\n" 66520cf9147SJim Mattson "label:\n" 66620cf9147SJim Mattson : 66720cf9147SJim Mattson : 66820cf9147SJim Mattson : "eax", "ebx", "ecx", "edx"); 66920cf9147SJim Mattson 67062ba5036SLike Xu if (this_cpu_has_perf_global_ctrl()) 6718a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, 0); 67220cf9147SJim Mattson 67320cf9147SJim Mattson stop_event(&brnch_cnt); 67420cf9147SJim Mattson stop_event(&instr_cnt); 67520cf9147SJim Mattson 67620cf9147SJim Mattson // Check that the end count - start count is at least the expected 67720cf9147SJim Mattson // number of instructions and branches. 67820cf9147SJim Mattson report(instr_cnt.count - instr_start >= EXPECTED_INSTR, 67920cf9147SJim Mattson "instruction count"); 68020cf9147SJim Mattson report(brnch_cnt.count - brnch_start >= EXPECTED_BRNCH, 68120cf9147SJim Mattson "branch count"); 68262ba5036SLike Xu if (this_cpu_has_perf_global_status()) { 68320cf9147SJim Mattson // Additionally check that those counters overflowed properly. 6848a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 6854070b9c6SLike Xu report(status & 1, "branch counter overflow"); 6864070b9c6SLike Xu report(status & 2, "instruction counter overflow"); 68762ba5036SLike Xu } 68820cf9147SJim Mattson 68920cf9147SJim Mattson report_prefix_pop(); 69020cf9147SJim Mattson } 69120cf9147SJim Mattson 692006b089dSLike Xu #define XBEGIN_STARTED (~0u) 693006b089dSLike Xu static void check_tsx_cycles(void) 694006b089dSLike Xu { 695006b089dSLike Xu pmu_counter_t cnt; 696006b089dSLike Xu unsigned int i, ret = 0; 697006b089dSLike Xu 698006b089dSLike Xu if (!this_cpu_has(X86_FEATURE_RTM)) 699006b089dSLike Xu return; 700006b089dSLike Xu 701006b089dSLike Xu report_prefix_push("TSX cycles"); 702006b089dSLike Xu 703006b089dSLike Xu for (i = 0; i < pmu.nr_gp_counters; i++) { 704006b089dSLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 705006b089dSLike Xu 706006b089dSLike Xu if (i == 2) { 707d4ae0a71SThomas Huth /* Transactional cycles committed only on gp counter 2 */ 708006b089dSLike Xu cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x30000003c; 709006b089dSLike Xu } else { 710006b089dSLike Xu /* Transactional cycles */ 711006b089dSLike Xu cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x10000003c; 712006b089dSLike Xu } 713006b089dSLike Xu 714006b089dSLike Xu start_event(&cnt); 715006b089dSLike Xu 716006b089dSLike Xu asm volatile("xbegin 1f\n\t" 717006b089dSLike Xu "1:\n\t" 718006b089dSLike Xu : "+a" (ret) :: "memory"); 719006b089dSLike Xu 720006b089dSLike Xu /* Generate a non-canonical #GP to trigger ABORT. */ 721006b089dSLike Xu if (ret == XBEGIN_STARTED) 722006b089dSLike Xu *(int *)NONCANONICAL = 0; 723006b089dSLike Xu 724006b089dSLike Xu stop_event(&cnt); 725006b089dSLike Xu 726006b089dSLike Xu report(cnt.count > 0, "gp cntr-%d with a value of %" PRId64 "", i, cnt.count); 727006b089dSLike Xu } 728006b089dSLike Xu 729006b089dSLike Xu report_prefix_pop(); 730006b089dSLike Xu } 731006b089dSLike Xu 732f2a56148SDapeng Mi static void warm_up(void) 733f2a56148SDapeng Mi { 734f2a56148SDapeng Mi int i; 735f2a56148SDapeng Mi 736f2a56148SDapeng Mi /* 737f2a56148SDapeng Mi * Since cycles event is always run as the first event, there would be 738f2a56148SDapeng Mi * a warm-up state to warm up the cache, it leads to the measured cycles 739f2a56148SDapeng Mi * value may exceed the pre-defined cycles upper boundary and cause 740f2a56148SDapeng Mi * false positive. To avoid this, introduce an warm-up state before 741f2a56148SDapeng Mi * the real verification. 742f2a56148SDapeng Mi */ 743f2a56148SDapeng Mi for (i = 0; i < 10; i++) 74450f8e27eSDapeng Mi loop(0); 745f2a56148SDapeng Mi } 746f2a56148SDapeng Mi 74722f2901aSLike Xu static void check_counters(void) 74822f2901aSLike Xu { 74900dca75cSLike Xu if (is_fep_available()) 75000dca75cSLike Xu check_emulated_instr(); 75100dca75cSLike Xu 752f2a56148SDapeng Mi warm_up(); 75322f2901aSLike Xu check_gp_counters(); 75422f2901aSLike Xu check_fixed_counters(); 75522f2901aSLike Xu check_rdpmc(); 75622f2901aSLike Xu check_counters_many(); 75722f2901aSLike Xu check_counter_overflow(); 75822f2901aSLike Xu check_gp_counter_cmask(); 75922f2901aSLike Xu check_running_counter_wrmsr(); 760006b089dSLike Xu check_tsx_cycles(); 76122f2901aSLike Xu } 76222f2901aSLike Xu 76322f2901aSLike Xu static void do_unsupported_width_counter_write(void *index) 76422f2901aSLike Xu { 76522f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + *((int *) index), 0xffffff0123456789ull); 76622f2901aSLike Xu } 76722f2901aSLike Xu 76822f2901aSLike Xu static void check_gp_counters_write_width(void) 76922f2901aSLike Xu { 77022f2901aSLike Xu u64 val_64 = 0xffffff0123456789ull; 7714b74c718SThomas Huth u64 val_32 = val_64 & ((1ull << 32) - 1); 772414ee7d1SSean Christopherson u64 val_max_width = val_64 & ((1ull << pmu.gp_counter_width) - 1); 77322f2901aSLike Xu int i; 77422f2901aSLike Xu 77522f2901aSLike Xu /* 77622f2901aSLike Xu * MSR_IA32_PERFCTRn supports 64-bit writes, 77722f2901aSLike Xu * but only the lowest 32 bits are valid. 77822f2901aSLike Xu */ 779414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 78022f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_32); 78122f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 78222f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 78322f2901aSLike Xu 78422f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_max_width); 78522f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 78622f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 78722f2901aSLike Xu 78822f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_64); 78922f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 79022f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 79122f2901aSLike Xu } 79222f2901aSLike Xu 79322f2901aSLike Xu /* 7944340720eSLike Xu * MSR_IA32_PMCn supports writing values up to GP counter width, 79522f2901aSLike Xu * and only the lowest bits of GP counter width are valid. 79622f2901aSLike Xu */ 797414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 79822f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + i, val_32); 79922f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 80022f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 80122f2901aSLike Xu 80222f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + i, val_max_width); 80322f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_max_width); 80422f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_max_width); 80522f2901aSLike Xu 80622f2901aSLike Xu report(test_for_exception(GP_VECTOR, 80722f2901aSLike Xu do_unsupported_width_counter_write, &i), 80822f2901aSLike Xu "writing unsupported width to MSR_IA32_PMC%d raises #GP", i); 80922f2901aSLike Xu } 81022f2901aSLike Xu } 81122f2901aSLike Xu 812290f4213SJim Mattson /* 813290f4213SJim Mattson * Per the SDM, reference cycles are currently implemented using the 814290f4213SJim Mattson * core crystal clock, TSC, or bus clock. Calibrate to the TSC 815290f4213SJim Mattson * frequency to set reasonable expectations. 816290f4213SJim Mattson */ 817290f4213SJim Mattson static void set_ref_cycle_expectations(void) 818290f4213SJim Mattson { 819290f4213SJim Mattson pmu_counter_t cnt = { 820290f4213SJim Mattson .ctr = MSR_IA32_PERFCTR0, 82125cc1ea7SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 82225cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].unit_sel, 823290f4213SJim Mattson }; 824290f4213SJim Mattson uint64_t tsc_delta; 825290f4213SJim Mattson uint64_t t0, t1, t2, t3; 826290f4213SJim Mattson 8272719b92cSYang Weijiang /* Bit 2 enumerates the availability of reference cycles events. */ 828414ee7d1SSean Christopherson if (!pmu.nr_gp_counters || !pmu_gp_counter_is_available(2)) 829290f4213SJim Mattson return; 830290f4213SJim Mattson 83162ba5036SLike Xu if (this_cpu_has_perf_global_ctrl()) 8328a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, 0); 833290f4213SJim Mattson 834290f4213SJim Mattson t0 = fenced_rdtsc(); 835290f4213SJim Mattson start_event(&cnt); 836290f4213SJim Mattson t1 = fenced_rdtsc(); 837290f4213SJim Mattson 838290f4213SJim Mattson /* 839290f4213SJim Mattson * This loop has to run long enough to dominate the VM-exit 840290f4213SJim Mattson * costs for playing with the PMU MSRs on start and stop. 841290f4213SJim Mattson * 842290f4213SJim Mattson * On a 2.6GHz Ice Lake, with the TSC frequency at 104 times 843290f4213SJim Mattson * the core crystal clock, this function calculated a guest 844290f4213SJim Mattson * TSC : ref cycles ratio of around 105 with ECX initialized 845290f4213SJim Mattson * to one billion. 846290f4213SJim Mattson */ 847290f4213SJim Mattson asm volatile("loop ." : "+c"((int){1000000000ull})); 848290f4213SJim Mattson 849290f4213SJim Mattson t2 = fenced_rdtsc(); 850290f4213SJim Mattson stop_event(&cnt); 851290f4213SJim Mattson t3 = fenced_rdtsc(); 852290f4213SJim Mattson 853290f4213SJim Mattson tsc_delta = ((t2 - t1) + (t3 - t0)) / 2; 854290f4213SJim Mattson 855290f4213SJim Mattson if (!tsc_delta) 856290f4213SJim Mattson return; 857290f4213SJim Mattson 85825cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].min = 85925cc1ea7SDapeng Mi (intel_gp_events[INTEL_REF_CYCLES_IDX].min * cnt.count) / tsc_delta; 86025cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].max = 86125cc1ea7SDapeng Mi (intel_gp_events[INTEL_REF_CYCLES_IDX].max * cnt.count) / tsc_delta; 862290f4213SJim Mattson } 863290f4213SJim Mattson 86485c21181SLike Xu static void check_invalid_rdpmc_gp(void) 86585c21181SLike Xu { 86685c21181SLike Xu uint64_t val; 86785c21181SLike Xu 86885c21181SLike Xu report(rdpmc_safe(64, &val) == GP_VECTOR, 86985c21181SLike Xu "Expected #GP on RDPMC(64)"); 87085c21181SLike Xu } 87185c21181SLike Xu 872a9f8b16fSGleb Natapov int main(int ac, char **av) 873a9f8b16fSGleb Natapov { 87489126fa4SDapeng Mi int instruction_idx; 87589126fa4SDapeng Mi int branch_idx; 87689126fa4SDapeng Mi 877a9f8b16fSGleb Natapov setup_vm(); 8785a2cb3e6SLike Xu handle_irq(PMI_VECTOR, cnt_overflow); 879dcda215bSPaolo Bonzini buf = malloc(N*64); 880a9f8b16fSGleb Natapov 88185c21181SLike Xu check_invalid_rdpmc_gp(); 88285c21181SLike Xu 883b883751aSLike Xu if (pmu.is_intel) { 884414ee7d1SSean Christopherson if (!pmu.version) { 88503041e97SLike Xu report_skip("No Intel Arch PMU is detected!"); 88632b9603cSRadim Krčmář return report_summary(); 887a9f8b16fSGleb Natapov } 8887c648ce2SLike Xu gp_events = (struct pmu_event *)intel_gp_events; 8897c648ce2SLike Xu gp_events_size = sizeof(intel_gp_events)/sizeof(intel_gp_events[0]); 89089126fa4SDapeng Mi instruction_idx = INTEL_INSTRUCTIONS_IDX; 89189126fa4SDapeng Mi branch_idx = INTEL_BRANCHES_IDX; 892b883751aSLike Xu report_prefix_push("Intel"); 893290f4213SJim Mattson set_ref_cycle_expectations(); 894b883751aSLike Xu } else { 895b883751aSLike Xu gp_events_size = sizeof(amd_gp_events)/sizeof(amd_gp_events[0]); 896b883751aSLike Xu gp_events = (struct pmu_event *)amd_gp_events; 89789126fa4SDapeng Mi instruction_idx = AMD_INSTRUCTIONS_IDX; 89889126fa4SDapeng Mi branch_idx = AMD_BRANCHES_IDX; 899b883751aSLike Xu report_prefix_push("AMD"); 900b883751aSLike Xu } 90189126fa4SDapeng Mi adjust_events_range(gp_events, instruction_idx, branch_idx); 902290f4213SJim Mattson 903414ee7d1SSean Christopherson printf("PMU version: %d\n", pmu.version); 904414ee7d1SSean Christopherson printf("GP counters: %d\n", pmu.nr_gp_counters); 905414ee7d1SSean Christopherson printf("GP counter width: %d\n", pmu.gp_counter_width); 906414ee7d1SSean Christopherson printf("Mask length: %d\n", pmu.gp_counter_mask_length); 907414ee7d1SSean Christopherson printf("Fixed counters: %d\n", pmu.nr_fixed_counters); 908414ee7d1SSean Christopherson printf("Fixed counter width: %d\n", pmu.fixed_counter_width); 9090ef1f6a8SPaolo Bonzini 9109c07c92bSDapeng Mi fixed_counters_num = MIN(pmu.nr_fixed_counters, ARRAY_SIZE(fixed_events)); 9119c07c92bSDapeng Mi if (pmu.nr_fixed_counters > ARRAY_SIZE(fixed_events)) 9129c07c92bSDapeng Mi report_info("Fixed counters number %d > defined fixed events %u. " 9139c07c92bSDapeng Mi "Please update test case.", pmu.nr_fixed_counters, 9149c07c92bSDapeng Mi (uint32_t)ARRAY_SIZE(fixed_events)); 9159c07c92bSDapeng Mi 9165a2cb3e6SLike Xu apic_write(APIC_LVTPC, PMI_VECTOR); 917a9f8b16fSGleb Natapov 918afa714b2SPaolo Bonzini check_counters(); 91920cf9147SJim Mattson 920879e7f07SLike Xu if (pmu_has_full_writes()) { 921cda64e80SLike Xu pmu.msr_gp_counter_base = MSR_IA32_PMC0; 922cda64e80SLike Xu 92322f2901aSLike Xu report_prefix_push("full-width writes"); 92422f2901aSLike Xu check_counters(); 92522f2901aSLike Xu check_gp_counters_write_width(); 926d7714e16SLike Xu report_prefix_pop(); 92722f2901aSLike Xu } 928a9f8b16fSGleb Natapov 929b883751aSLike Xu if (!pmu.is_intel) { 930b883751aSLike Xu report_prefix_push("K7"); 931b883751aSLike Xu pmu.nr_gp_counters = AMD64_NUM_COUNTERS; 932b883751aSLike Xu pmu.msr_gp_counter_base = MSR_K7_PERFCTR0; 933b883751aSLike Xu pmu.msr_gp_event_select_base = MSR_K7_EVNTSEL0; 934b883751aSLike Xu check_counters(); 935b883751aSLike Xu report_prefix_pop(); 936b883751aSLike Xu } 937b883751aSLike Xu 938f3cdd159SJan Kiszka return report_summary(); 939a9f8b16fSGleb Natapov } 940