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*89126fa4SDapeng Mi /* Enable GLOBAL_CTRL + disable GLOBAL_CTRL instructions */ 23*89126fa4SDapeng Mi #define EXTRA_INSNS (3 + 3) 24*89126fa4SDapeng Mi #define LOOP_INSNS (N * 10 + EXTRA_INSNS) 25*89126fa4SDapeng Mi #define LOOP_BRANCHES (N) 2650f8e27eSDapeng Mi #define LOOP_ASM(_wrmsr) \ 2750f8e27eSDapeng Mi _wrmsr "\n\t" \ 2850f8e27eSDapeng Mi "mov %%ecx, %%edi; mov %%ebx, %%ecx;\n\t" \ 2950f8e27eSDapeng Mi "1: mov (%1), %2; add $64, %1;\n\t" \ 3050f8e27eSDapeng Mi "nop; nop; nop; nop; nop; nop; nop;\n\t" \ 3150f8e27eSDapeng Mi "loop 1b;\n\t" \ 3250f8e27eSDapeng Mi "mov %%edi, %%ecx; xor %%eax, %%eax; xor %%edx, %%edx;\n\t" \ 3350f8e27eSDapeng Mi _wrmsr "\n\t" 3450f8e27eSDapeng Mi 35a9f8b16fSGleb Natapov typedef struct { 36a9f8b16fSGleb Natapov uint32_t ctr; 379720e46cSDapeng Mi uint32_t idx; 38006b089dSLike Xu uint64_t config; 39a9f8b16fSGleb Natapov uint64_t count; 40a9f8b16fSGleb Natapov } pmu_counter_t; 41a9f8b16fSGleb Natapov 42a9f8b16fSGleb Natapov struct pmu_event { 43797d79a2SThomas Huth const char *name; 44a9f8b16fSGleb Natapov uint32_t unit_sel; 45a9f8b16fSGleb Natapov int min; 46a9f8b16fSGleb Natapov int max; 477c648ce2SLike Xu } intel_gp_events[] = { 48a9f8b16fSGleb Natapov {"core cycles", 0x003c, 1*N, 50*N}, 49a9f8b16fSGleb Natapov {"instructions", 0x00c0, 10*N, 10.2*N}, 50290f4213SJim Mattson {"ref cycles", 0x013c, 1*N, 30*N}, 51290f4213SJim Mattson {"llc references", 0x4f2e, 1, 2*N}, 52a9f8b16fSGleb Natapov {"llc misses", 0x412e, 1, 1*N}, 53a9f8b16fSGleb Natapov {"branches", 0x00c4, 1*N, 1.1*N}, 54a9f8b16fSGleb Natapov {"branch misses", 0x00c5, 0, 0.1*N}, 55b883751aSLike Xu }, amd_gp_events[] = { 56b883751aSLike Xu {"core cycles", 0x0076, 1*N, 50*N}, 57b883751aSLike Xu {"instructions", 0x00c0, 10*N, 10.2*N}, 58b883751aSLike Xu {"branches", 0x00c2, 1*N, 1.1*N}, 59b883751aSLike Xu {"branch misses", 0x00c3, 0, 0.1*N}, 60a9f8b16fSGleb Natapov }, fixed_events[] = { 615d6a3a54SDapeng Mi {"fixed 0", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N}, 625d6a3a54SDapeng Mi {"fixed 1", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N}, 635d6a3a54SDapeng Mi {"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 2, 0.1*N, 30*N} 64a9f8b16fSGleb Natapov }; 65a9f8b16fSGleb Natapov 66f4e97f59SDapeng Mi /* 67f4e97f59SDapeng Mi * Events index in intel_gp_events[], ensure consistent with 68f4e97f59SDapeng Mi * intel_gp_events[]. 69f4e97f59SDapeng Mi */ 70f4e97f59SDapeng Mi enum { 7185c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX = 1, 7225cc1ea7SDapeng Mi INTEL_REF_CYCLES_IDX = 2, 73f4e97f59SDapeng Mi INTEL_BRANCHES_IDX = 5, 74f4e97f59SDapeng Mi }; 75f4e97f59SDapeng Mi 76f4e97f59SDapeng Mi /* 77f4e97f59SDapeng Mi * Events index in amd_gp_events[], ensure consistent with 78f4e97f59SDapeng Mi * amd_gp_events[]. 79f4e97f59SDapeng Mi */ 80f4e97f59SDapeng Mi enum { 8185c75578SDapeng Mi AMD_INSTRUCTIONS_IDX = 1, 82f4e97f59SDapeng Mi AMD_BRANCHES_IDX = 2, 83f4e97f59SDapeng Mi }; 84f4e97f59SDapeng Mi 85a9f8b16fSGleb Natapov char *buf; 86a9f8b16fSGleb Natapov 877c648ce2SLike Xu static struct pmu_event *gp_events; 887c648ce2SLike Xu static unsigned int gp_events_size; 899c07c92bSDapeng Mi static unsigned int fixed_counters_num; 907c648ce2SLike Xu 9150f8e27eSDapeng Mi 9250f8e27eSDapeng Mi static inline void __loop(void) 93a9f8b16fSGleb Natapov { 94a9f8b16fSGleb Natapov unsigned long tmp, tmp2, tmp3; 95a9f8b16fSGleb Natapov 9650f8e27eSDapeng Mi asm volatile(LOOP_ASM("nop") 9750f8e27eSDapeng Mi : "=c"(tmp), "=r"(tmp2), "=r"(tmp3) 9850f8e27eSDapeng Mi : "0"(N), "1"(buf)); 9950f8e27eSDapeng Mi } 100a9f8b16fSGleb Natapov 10150f8e27eSDapeng Mi /* 10250f8e27eSDapeng Mi * Enable and disable counters in a whole asm blob to ensure 10350f8e27eSDapeng Mi * no other instructions are counted in the window between 10450f8e27eSDapeng Mi * counters enabling and really LOOP_ASM code executing. 10550f8e27eSDapeng Mi * Thus counters can verify instructions and branches events 10650f8e27eSDapeng Mi * against precise counts instead of a rough valid count range. 10750f8e27eSDapeng Mi */ 10850f8e27eSDapeng Mi static inline void __precise_loop(u64 cntrs) 10950f8e27eSDapeng Mi { 11050f8e27eSDapeng Mi unsigned long tmp, tmp2, tmp3; 11150f8e27eSDapeng Mi unsigned int global_ctl = pmu.msr_global_ctl; 11250f8e27eSDapeng Mi u32 eax = cntrs & (BIT_ULL(32) - 1); 11350f8e27eSDapeng Mi u32 edx = cntrs >> 32; 11450f8e27eSDapeng Mi 11550f8e27eSDapeng Mi asm volatile(LOOP_ASM("wrmsr") 11650f8e27eSDapeng Mi : "=b"(tmp), "=r"(tmp2), "=r"(tmp3) 11750f8e27eSDapeng Mi : "a"(eax), "d"(edx), "c"(global_ctl), 11850f8e27eSDapeng Mi "0"(N), "1"(buf) 11950f8e27eSDapeng Mi : "edi"); 12050f8e27eSDapeng Mi } 12150f8e27eSDapeng Mi 12250f8e27eSDapeng Mi static inline void loop(u64 cntrs) 12350f8e27eSDapeng Mi { 12450f8e27eSDapeng Mi if (!this_cpu_has_perf_global_ctrl()) 12550f8e27eSDapeng Mi __loop(); 12650f8e27eSDapeng Mi else 12750f8e27eSDapeng Mi __precise_loop(cntrs); 128a9f8b16fSGleb Natapov } 129a9f8b16fSGleb Natapov 130*89126fa4SDapeng Mi static void adjust_events_range(struct pmu_event *gp_events, 131*89126fa4SDapeng Mi int instruction_idx, int branch_idx) 132*89126fa4SDapeng Mi { 133*89126fa4SDapeng Mi /* 134*89126fa4SDapeng Mi * If HW supports GLOBAL_CTRL MSR, enabling and disabling PMCs are 135*89126fa4SDapeng Mi * moved in __precise_loop(). Thus, instructions and branches events 136*89126fa4SDapeng Mi * can be verified against a precise count instead of a rough range. 137*89126fa4SDapeng Mi * 138*89126fa4SDapeng Mi * Skip the precise checks on AMD, as AMD CPUs count VMRUN as a branch 139*89126fa4SDapeng Mi * instruction in guest context, which* leads to intermittent failures 140*89126fa4SDapeng Mi * as the counts will vary depending on how many asynchronous VM-Exits 141*89126fa4SDapeng Mi * occur while running the measured code, e.g. if the host takes IRQs. 142*89126fa4SDapeng Mi */ 143*89126fa4SDapeng Mi if (pmu.is_intel && this_cpu_has_perf_global_ctrl()) { 144*89126fa4SDapeng Mi gp_events[instruction_idx].min = LOOP_INSNS; 145*89126fa4SDapeng Mi gp_events[instruction_idx].max = LOOP_INSNS; 146*89126fa4SDapeng Mi gp_events[branch_idx].min = LOOP_BRANCHES; 147*89126fa4SDapeng Mi gp_events[branch_idx].max = LOOP_BRANCHES; 148*89126fa4SDapeng Mi } 149*89126fa4SDapeng Mi } 150*89126fa4SDapeng Mi 151a9f8b16fSGleb Natapov volatile uint64_t irq_received; 152a9f8b16fSGleb Natapov 153a9f8b16fSGleb Natapov static void cnt_overflow(isr_regs_t *regs) 154a9f8b16fSGleb Natapov { 155a9f8b16fSGleb Natapov irq_received++; 156c595c361SMingwei Zhang apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); 157a9f8b16fSGleb Natapov apic_write(APIC_EOI, 0); 158a9f8b16fSGleb Natapov } 159a9f8b16fSGleb Natapov 160a9f8b16fSGleb Natapov static bool check_irq(void) 161a9f8b16fSGleb Natapov { 162a9f8b16fSGleb Natapov int i; 163a9f8b16fSGleb Natapov irq_received = 0; 164787f0aebSMaxim Levitsky sti(); 165a9f8b16fSGleb Natapov for (i = 0; i < 100000 && !irq_received; i++) 166a9f8b16fSGleb Natapov asm volatile("pause"); 167787f0aebSMaxim Levitsky cli(); 168a9f8b16fSGleb Natapov return irq_received; 169a9f8b16fSGleb Natapov } 170a9f8b16fSGleb Natapov 171a9f8b16fSGleb Natapov static bool is_gp(pmu_counter_t *evt) 172a9f8b16fSGleb Natapov { 173b883751aSLike Xu if (!pmu.is_intel) 174b883751aSLike Xu return true; 175b883751aSLike Xu 17622f2901aSLike Xu return evt->ctr < MSR_CORE_PERF_FIXED_CTR0 || 17722f2901aSLike Xu evt->ctr >= MSR_IA32_PMC0; 178a9f8b16fSGleb Natapov } 179a9f8b16fSGleb Natapov 180a9f8b16fSGleb Natapov static int event_to_global_idx(pmu_counter_t *cnt) 181a9f8b16fSGleb Natapov { 182b883751aSLike Xu if (pmu.is_intel) 183cda64e80SLike Xu return cnt->ctr - (is_gp(cnt) ? pmu.msr_gp_counter_base : 184a9f8b16fSGleb Natapov (MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX)); 185b883751aSLike Xu 186b883751aSLike Xu if (pmu.msr_gp_counter_base == MSR_F15H_PERF_CTR0) 187b883751aSLike Xu return (cnt->ctr - pmu.msr_gp_counter_base) / 2; 188b883751aSLike Xu else 189b883751aSLike Xu return cnt->ctr - pmu.msr_gp_counter_base; 190a9f8b16fSGleb Natapov } 191a9f8b16fSGleb Natapov 192a9f8b16fSGleb Natapov static struct pmu_event* get_counter_event(pmu_counter_t *cnt) 193a9f8b16fSGleb Natapov { 194a9f8b16fSGleb Natapov if (is_gp(cnt)) { 195a9f8b16fSGleb Natapov int i; 196a9f8b16fSGleb Natapov 1977c648ce2SLike Xu for (i = 0; i < gp_events_size; i++) 198a9f8b16fSGleb Natapov if (gp_events[i].unit_sel == (cnt->config & 0xffff)) 199a9f8b16fSGleb Natapov return &gp_events[i]; 2009c07c92bSDapeng Mi } else { 2019c07c92bSDapeng Mi unsigned int idx = cnt->ctr - MSR_CORE_PERF_FIXED_CTR0; 2029c07c92bSDapeng Mi 2039c07c92bSDapeng Mi if (idx < ARRAY_SIZE(fixed_events)) 2049c07c92bSDapeng Mi return &fixed_events[idx]; 2059c07c92bSDapeng Mi } 206a9f8b16fSGleb Natapov 207a9f8b16fSGleb Natapov return (void*)0; 208a9f8b16fSGleb Natapov } 209a9f8b16fSGleb Natapov 210a9f8b16fSGleb Natapov static void global_enable(pmu_counter_t *cnt) 211a9f8b16fSGleb Natapov { 21262ba5036SLike Xu if (!this_cpu_has_perf_global_ctrl()) 21362ba5036SLike Xu return; 21462ba5036SLike Xu 215a9f8b16fSGleb Natapov cnt->idx = event_to_global_idx(cnt); 2168a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) | BIT_ULL(cnt->idx)); 217a9f8b16fSGleb Natapov } 218a9f8b16fSGleb Natapov 219a9f8b16fSGleb Natapov static void global_disable(pmu_counter_t *cnt) 220a9f8b16fSGleb Natapov { 22162ba5036SLike Xu if (!this_cpu_has_perf_global_ctrl()) 22262ba5036SLike Xu return; 22362ba5036SLike Xu 2248a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) & ~BIT_ULL(cnt->idx)); 225a9f8b16fSGleb Natapov } 226a9f8b16fSGleb Natapov 227e9e7577bSLike Xu static void __start_event(pmu_counter_t *evt, uint64_t count) 228a9f8b16fSGleb Natapov { 229e9e7577bSLike Xu evt->count = count; 230a9f8b16fSGleb Natapov wrmsr(evt->ctr, evt->count); 231cda64e80SLike Xu if (is_gp(evt)) { 232cda64e80SLike Xu wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)), 233a9f8b16fSGleb Natapov evt->config | EVNTSEL_EN); 234cda64e80SLike Xu } else { 235a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 236a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 237a9f8b16fSGleb Natapov uint32_t usrospmi = 0; 238a9f8b16fSGleb Natapov 239a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_OS) 240a9f8b16fSGleb Natapov usrospmi |= (1 << 0); 241a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_USR) 242a9f8b16fSGleb Natapov usrospmi |= (1 << 1); 243a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_INT) 244a9f8b16fSGleb Natapov usrospmi |= (1 << 3); // PMI on overflow 245a9f8b16fSGleb Natapov ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift); 246a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl); 247a9f8b16fSGleb Natapov } 2485a2cb3e6SLike Xu apic_write(APIC_LVTPC, PMI_VECTOR); 249a9f8b16fSGleb Natapov } 250a9f8b16fSGleb Natapov 251e9e7577bSLike Xu static void start_event(pmu_counter_t *evt) 252e9e7577bSLike Xu { 253e9e7577bSLike Xu __start_event(evt, 0); 25450f8e27eSDapeng Mi global_enable(evt); 255e9e7577bSLike Xu } 256e9e7577bSLike Xu 25750f8e27eSDapeng Mi static void __stop_event(pmu_counter_t *evt) 258a9f8b16fSGleb Natapov { 259cda64e80SLike Xu if (is_gp(evt)) { 260cda64e80SLike Xu wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)), 261a9f8b16fSGleb Natapov evt->config & ~EVNTSEL_EN); 262cda64e80SLike Xu } else { 263a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 264a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 265a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift)); 266a9f8b16fSGleb Natapov } 267a9f8b16fSGleb Natapov evt->count = rdmsr(evt->ctr); 268a9f8b16fSGleb Natapov } 269a9f8b16fSGleb Natapov 27050f8e27eSDapeng Mi static void stop_event(pmu_counter_t *evt) 27150f8e27eSDapeng Mi { 27250f8e27eSDapeng Mi global_disable(evt); 27350f8e27eSDapeng Mi __stop_event(evt); 27450f8e27eSDapeng Mi } 27550f8e27eSDapeng Mi 2768554261fSLike Xu static noinline void measure_many(pmu_counter_t *evt, int count) 277a9f8b16fSGleb Natapov { 278a9f8b16fSGleb Natapov int i; 27950f8e27eSDapeng Mi u64 cntrs = 0; 28050f8e27eSDapeng Mi 28150f8e27eSDapeng Mi for (i = 0; i < count; i++) { 28250f8e27eSDapeng Mi __start_event(&evt[i], 0); 28350f8e27eSDapeng Mi cntrs |= BIT_ULL(event_to_global_idx(&evt[i])); 28450f8e27eSDapeng Mi } 28550f8e27eSDapeng Mi loop(cntrs); 286a9f8b16fSGleb Natapov for (i = 0; i < count; i++) 28750f8e27eSDapeng Mi __stop_event(&evt[i]); 288a9f8b16fSGleb Natapov } 289a9f8b16fSGleb Natapov 2908554261fSLike Xu static void measure_one(pmu_counter_t *evt) 2918554261fSLike Xu { 2928554261fSLike Xu measure_many(evt, 1); 2938554261fSLike Xu } 2948554261fSLike Xu 295e9e7577bSLike Xu static noinline void __measure(pmu_counter_t *evt, uint64_t count) 296e9e7577bSLike Xu { 29750f8e27eSDapeng Mi u64 cntrs = BIT_ULL(event_to_global_idx(evt)); 29850f8e27eSDapeng Mi 299e9e7577bSLike Xu __start_event(evt, count); 30050f8e27eSDapeng Mi loop(cntrs); 30150f8e27eSDapeng Mi __stop_event(evt); 302e9e7577bSLike Xu } 303e9e7577bSLike Xu 304a9f8b16fSGleb Natapov static bool verify_event(uint64_t count, struct pmu_event *e) 305a9f8b16fSGleb Natapov { 3069c07c92bSDapeng Mi bool pass; 307d24d3381SDapeng Mi 3089c07c92bSDapeng Mi if (!e) 3099c07c92bSDapeng Mi return false; 3109c07c92bSDapeng Mi 3119c07c92bSDapeng Mi pass = count >= e->min && count <= e->max; 312d24d3381SDapeng Mi if (!pass) 313d24d3381SDapeng Mi printf("FAIL: %d <= %"PRId64" <= %d\n", e->min, count, e->max); 314d24d3381SDapeng Mi 315d24d3381SDapeng Mi return pass; 316a9f8b16fSGleb Natapov } 317a9f8b16fSGleb Natapov 318a9f8b16fSGleb Natapov static bool verify_counter(pmu_counter_t *cnt) 319a9f8b16fSGleb Natapov { 320a9f8b16fSGleb Natapov return verify_event(cnt->count, get_counter_event(cnt)); 321a9f8b16fSGleb Natapov } 322a9f8b16fSGleb Natapov 323a9f8b16fSGleb Natapov static void check_gp_counter(struct pmu_event *evt) 324a9f8b16fSGleb Natapov { 325a9f8b16fSGleb Natapov pmu_counter_t cnt = { 326a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, 327a9f8b16fSGleb Natapov }; 328a9f8b16fSGleb Natapov int i; 329a9f8b16fSGleb Natapov 330cda64e80SLike Xu for (i = 0; i < pmu.nr_gp_counters; i++) { 331cda64e80SLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 3328554261fSLike Xu measure_one(&cnt); 333a299895bSThomas Huth report(verify_event(cnt.count, evt), "%s-%d", evt->name, i); 334a9f8b16fSGleb Natapov } 335a9f8b16fSGleb Natapov } 336a9f8b16fSGleb Natapov 337a9f8b16fSGleb Natapov static void check_gp_counters(void) 338a9f8b16fSGleb Natapov { 339a9f8b16fSGleb Natapov int i; 340a9f8b16fSGleb Natapov 3417c648ce2SLike Xu for (i = 0; i < gp_events_size; i++) 3422719b92cSYang Weijiang if (pmu_gp_counter_is_available(i)) 343a9f8b16fSGleb Natapov check_gp_counter(&gp_events[i]); 344a9f8b16fSGleb Natapov else 345a9f8b16fSGleb Natapov printf("GP event '%s' is disabled\n", 346a9f8b16fSGleb Natapov gp_events[i].name); 347a9f8b16fSGleb Natapov } 348a9f8b16fSGleb Natapov 349a9f8b16fSGleb Natapov static void check_fixed_counters(void) 350a9f8b16fSGleb Natapov { 351a9f8b16fSGleb Natapov pmu_counter_t cnt = { 352a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR, 353a9f8b16fSGleb Natapov }; 354a9f8b16fSGleb Natapov int i; 355a9f8b16fSGleb Natapov 3569c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 357a9f8b16fSGleb Natapov cnt.ctr = fixed_events[i].unit_sel; 3588554261fSLike Xu measure_one(&cnt); 3592719b92cSYang Weijiang report(verify_event(cnt.count, &fixed_events[i]), "fixed-%d", i); 360a9f8b16fSGleb Natapov } 361a9f8b16fSGleb Natapov } 362a9f8b16fSGleb Natapov 363a9f8b16fSGleb Natapov static void check_counters_many(void) 364a9f8b16fSGleb Natapov { 365f21c809eSDapeng Mi pmu_counter_t cnt[48]; 366a9f8b16fSGleb Natapov int i, n; 367a9f8b16fSGleb Natapov 368414ee7d1SSean Christopherson for (i = 0, n = 0; n < pmu.nr_gp_counters; i++) { 3692719b92cSYang Weijiang if (!pmu_gp_counter_is_available(i)) 370a9f8b16fSGleb Natapov continue; 371a9f8b16fSGleb Natapov 372cda64e80SLike Xu cnt[n].ctr = MSR_GP_COUNTERx(n); 3734ac45293SWei Huang cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | 3747c648ce2SLike Xu gp_events[i % gp_events_size].unit_sel; 375a9f8b16fSGleb Natapov n++; 376a9f8b16fSGleb Natapov } 3779c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 378a9f8b16fSGleb Natapov cnt[n].ctr = fixed_events[i].unit_sel; 379a9f8b16fSGleb Natapov cnt[n].config = EVNTSEL_OS | EVNTSEL_USR; 380a9f8b16fSGleb Natapov n++; 381a9f8b16fSGleb Natapov } 382a9f8b16fSGleb Natapov 383f21c809eSDapeng Mi assert(n <= ARRAY_SIZE(cnt)); 3848554261fSLike Xu measure_many(cnt, n); 385a9f8b16fSGleb Natapov 386a9f8b16fSGleb Natapov for (i = 0; i < n; i++) 387a9f8b16fSGleb Natapov if (!verify_counter(&cnt[i])) 388a9f8b16fSGleb Natapov break; 389a9f8b16fSGleb Natapov 390a299895bSThomas Huth report(i == n, "all counters"); 391a9f8b16fSGleb Natapov } 392a9f8b16fSGleb Natapov 3937ec3b67aSLike Xu static uint64_t measure_for_overflow(pmu_counter_t *cnt) 3947ec3b67aSLike Xu { 3957ec3b67aSLike Xu __measure(cnt, 0); 3967ec3b67aSLike Xu /* 3977ec3b67aSLike Xu * To generate overflow, i.e. roll over to '0', the initial count just 3987ec3b67aSLike Xu * needs to be preset to the negative expected count. However, as per 3997ec3b67aSLike Xu * Intel's SDM, the preset count needs to be incremented by 1 to ensure 4007ec3b67aSLike Xu * the overflow interrupt is generated immediately instead of possibly 4017ec3b67aSLike Xu * waiting for the overflow to propagate through the counter. 4027ec3b67aSLike Xu */ 4037ec3b67aSLike Xu assert(cnt->count > 1); 4047ec3b67aSLike Xu return 1 - cnt->count; 4057ec3b67aSLike Xu } 4067ec3b67aSLike Xu 407a9f8b16fSGleb Natapov static void check_counter_overflow(void) 408a9f8b16fSGleb Natapov { 409a9f8b16fSGleb Natapov int i; 41085c75578SDapeng Mi uint64_t overflow_preset; 41185c75578SDapeng Mi int instruction_idx = pmu.is_intel ? 41285c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 41385c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 41485c75578SDapeng Mi 415a9f8b16fSGleb Natapov pmu_counter_t cnt = { 416cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 41785c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 41885c75578SDapeng Mi gp_events[instruction_idx].unit_sel /* instructions */, 419a9f8b16fSGleb Natapov }; 4207ec3b67aSLike Xu overflow_preset = measure_for_overflow(&cnt); 421a9f8b16fSGleb Natapov 422a9f8b16fSGleb Natapov /* clear status before test */ 42362ba5036SLike Xu if (this_cpu_has_perf_global_status()) 4248a2866d1SLike Xu pmu_clear_global_status(); 425a9f8b16fSGleb Natapov 4265bba1769SAndrew Jones report_prefix_push("overflow"); 4275bba1769SAndrew Jones 428cda64e80SLike Xu for (i = 0; i < pmu.nr_gp_counters + 1; i++) { 429a9f8b16fSGleb Natapov uint64_t status; 430a9f8b16fSGleb Natapov int idx; 43133cfc1b0SNadav Amit 4327ec3b67aSLike Xu cnt.count = overflow_preset; 433cda64e80SLike Xu if (pmu_use_full_writes()) 434414ee7d1SSean Christopherson cnt.count &= (1ull << pmu.gp_counter_width) - 1; 43533cfc1b0SNadav Amit 436414ee7d1SSean Christopherson if (i == pmu.nr_gp_counters) { 437b883751aSLike Xu if (!pmu.is_intel) 438b883751aSLike Xu break; 439b883751aSLike Xu 440a9f8b16fSGleb Natapov cnt.ctr = fixed_events[0].unit_sel; 4417ec3b67aSLike Xu cnt.count = measure_for_overflow(&cnt); 442cda64e80SLike Xu cnt.count &= (1ull << pmu.gp_counter_width) - 1; 443cda64e80SLike Xu } else { 444cda64e80SLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 44533cfc1b0SNadav Amit } 44633cfc1b0SNadav Amit 447a9f8b16fSGleb Natapov if (i % 2) 448a9f8b16fSGleb Natapov cnt.config |= EVNTSEL_INT; 449a9f8b16fSGleb Natapov else 450a9f8b16fSGleb Natapov cnt.config &= ~EVNTSEL_INT; 451a9f8b16fSGleb Natapov idx = event_to_global_idx(&cnt); 452e9e7577bSLike Xu __measure(&cnt, cnt.count); 453b883751aSLike Xu if (pmu.is_intel) 454a299895bSThomas Huth report(cnt.count == 1, "cntr-%d", i); 455b883751aSLike Xu else 456b883751aSLike Xu report(cnt.count == 0xffffffffffff || cnt.count < 7, "cntr-%d", i); 45762ba5036SLike Xu 45862ba5036SLike Xu if (!this_cpu_has_perf_global_status()) 45962ba5036SLike Xu continue; 46062ba5036SLike Xu 4618a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 462a299895bSThomas Huth report(status & (1ull << idx), "status-%d", i); 4638a2866d1SLike Xu wrmsr(pmu.msr_global_status_clr, status); 4648a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 465a299895bSThomas Huth report(!(status & (1ull << idx)), "status clear-%d", i); 466a299895bSThomas Huth report(check_irq() == (i % 2), "irq-%d", i); 467a9f8b16fSGleb Natapov } 4685bba1769SAndrew Jones 4695bba1769SAndrew Jones report_prefix_pop(); 470a9f8b16fSGleb Natapov } 471a9f8b16fSGleb Natapov 472a9f8b16fSGleb Natapov static void check_gp_counter_cmask(void) 473a9f8b16fSGleb Natapov { 47485c75578SDapeng Mi int instruction_idx = pmu.is_intel ? 47585c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 47685c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 47785c75578SDapeng Mi 478a9f8b16fSGleb Natapov pmu_counter_t cnt = { 479cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 48085c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 48185c75578SDapeng Mi gp_events[instruction_idx].unit_sel /* instructions */, 482a9f8b16fSGleb Natapov }; 483a9f8b16fSGleb Natapov cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT); 4848554261fSLike Xu measure_one(&cnt); 48585c75578SDapeng Mi report(cnt.count < gp_events[instruction_idx].min, "cmask"); 486a9f8b16fSGleb Natapov } 487a9f8b16fSGleb Natapov 488ca1b9de9SNadav Amit static void do_rdpmc_fast(void *ptr) 489ca1b9de9SNadav Amit { 490ca1b9de9SNadav Amit pmu_counter_t *cnt = ptr; 491ca1b9de9SNadav Amit uint32_t idx = (uint32_t)cnt->idx | (1u << 31); 492ca1b9de9SNadav Amit 493ca1b9de9SNadav Amit if (!is_gp(cnt)) 494ca1b9de9SNadav Amit idx |= 1 << 30; 495ca1b9de9SNadav Amit 496ca1b9de9SNadav Amit cnt->count = rdpmc(idx); 497ca1b9de9SNadav Amit } 498ca1b9de9SNadav Amit 499ca1b9de9SNadav Amit 500a9f8b16fSGleb Natapov static void check_rdpmc(void) 501a9f8b16fSGleb Natapov { 50222f2901aSLike Xu uint64_t val = 0xff0123456789ull; 503ca1b9de9SNadav Amit bool exc; 504a9f8b16fSGleb Natapov int i; 505a9f8b16fSGleb Natapov 5065bba1769SAndrew Jones report_prefix_push("rdpmc"); 5075bba1769SAndrew Jones 508414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 50933cfc1b0SNadav Amit uint64_t x; 510ca1b9de9SNadav Amit pmu_counter_t cnt = { 511cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(i), 512ca1b9de9SNadav Amit .idx = i 513ca1b9de9SNadav Amit }; 51433cfc1b0SNadav Amit 51533cfc1b0SNadav Amit /* 51622f2901aSLike Xu * Without full-width writes, only the low 32 bits are writable, 51722f2901aSLike Xu * and the value is sign-extended. 51833cfc1b0SNadav Amit */ 519cda64e80SLike Xu if (pmu.msr_gp_counter_base == MSR_IA32_PERFCTR0) 52033cfc1b0SNadav Amit x = (uint64_t)(int64_t)(int32_t)val; 52122f2901aSLike Xu else 52222f2901aSLike Xu x = (uint64_t)(int64_t)val; 52333cfc1b0SNadav Amit 52433cfc1b0SNadav Amit /* Mask according to the number of supported bits */ 525414ee7d1SSean Christopherson x &= (1ull << pmu.gp_counter_width) - 1; 52633cfc1b0SNadav Amit 527cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(i), val); 528a299895bSThomas Huth report(rdpmc(i) == x, "cntr-%d", i); 529ca1b9de9SNadav Amit 530ca1b9de9SNadav Amit exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 531ca1b9de9SNadav Amit if (exc) 532ca1b9de9SNadav Amit report_skip("fast-%d", i); 533ca1b9de9SNadav Amit else 534a299895bSThomas Huth report(cnt.count == (u32)val, "fast-%d", i); 535a9f8b16fSGleb Natapov } 5369c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 537414ee7d1SSean Christopherson uint64_t x = val & ((1ull << pmu.fixed_counter_width) - 1); 538ca1b9de9SNadav Amit pmu_counter_t cnt = { 539ca1b9de9SNadav Amit .ctr = MSR_CORE_PERF_FIXED_CTR0 + i, 540ca1b9de9SNadav Amit .idx = i 541ca1b9de9SNadav Amit }; 54233cfc1b0SNadav Amit 5433f914933SLike Xu wrmsr(MSR_PERF_FIXED_CTRx(i), x); 544a299895bSThomas Huth report(rdpmc(i | (1 << 30)) == x, "fixed cntr-%d", i); 545ca1b9de9SNadav Amit 546ca1b9de9SNadav Amit exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 547ca1b9de9SNadav Amit if (exc) 548ca1b9de9SNadav Amit report_skip("fixed fast-%d", i); 549ca1b9de9SNadav Amit else 550a299895bSThomas Huth report(cnt.count == (u32)x, "fixed fast-%d", i); 551a9f8b16fSGleb Natapov } 5525bba1769SAndrew Jones 5535bba1769SAndrew Jones report_prefix_pop(); 554a9f8b16fSGleb Natapov } 555a9f8b16fSGleb Natapov 556ddade902SEric Hankland static void check_running_counter_wrmsr(void) 557ddade902SEric Hankland { 55859ca1413SEric Hankland uint64_t status; 55922f2901aSLike Xu uint64_t count; 56085c75578SDapeng Mi unsigned int instruction_idx = pmu.is_intel ? 56185c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 56285c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 56385c75578SDapeng Mi 564ddade902SEric Hankland pmu_counter_t evt = { 565cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 56685c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 56785c75578SDapeng Mi gp_events[instruction_idx].unit_sel, 568ddade902SEric Hankland }; 569ddade902SEric Hankland 57059ca1413SEric Hankland report_prefix_push("running counter wrmsr"); 57159ca1413SEric Hankland 572ddade902SEric Hankland start_event(&evt); 57350f8e27eSDapeng Mi __loop(); 574cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(0), 0); 575ddade902SEric Hankland stop_event(&evt); 57685c75578SDapeng Mi report(evt.count < gp_events[instruction_idx].min, "cntr"); 57759ca1413SEric Hankland 57859ca1413SEric Hankland /* clear status before overflow test */ 57962ba5036SLike Xu if (this_cpu_has_perf_global_status()) 5808a2866d1SLike Xu pmu_clear_global_status(); 58159ca1413SEric Hankland 58259ca1413SEric Hankland start_event(&evt); 58322f2901aSLike Xu 58422f2901aSLike Xu count = -1; 585cda64e80SLike Xu if (pmu_use_full_writes()) 586414ee7d1SSean Christopherson count &= (1ull << pmu.gp_counter_width) - 1; 58722f2901aSLike Xu 588cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(0), count); 58922f2901aSLike Xu 59050f8e27eSDapeng Mi __loop(); 59159ca1413SEric Hankland stop_event(&evt); 59262ba5036SLike Xu 59362ba5036SLike Xu if (this_cpu_has_perf_global_status()) { 5948a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 5958a2866d1SLike Xu report(status & 1, "status msr bit"); 59662ba5036SLike Xu } 59759ca1413SEric Hankland 59859ca1413SEric Hankland report_prefix_pop(); 599ddade902SEric Hankland } 600ddade902SEric Hankland 60120cf9147SJim Mattson static void check_emulated_instr(void) 60220cf9147SJim Mattson { 60320cf9147SJim Mattson uint64_t status, instr_start, brnch_start; 6048b547cc2SLike Xu uint64_t gp_counter_width = (1ull << pmu.gp_counter_width) - 1; 605f4e97f59SDapeng Mi unsigned int branch_idx = pmu.is_intel ? 606f4e97f59SDapeng Mi INTEL_BRANCHES_IDX : AMD_BRANCHES_IDX; 60785c75578SDapeng Mi unsigned int instruction_idx = pmu.is_intel ? 60885c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 60985c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 61020cf9147SJim Mattson pmu_counter_t brnch_cnt = { 611cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 61220cf9147SJim Mattson /* branch instructions */ 613b883751aSLike Xu .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[branch_idx].unit_sel, 61420cf9147SJim Mattson }; 61520cf9147SJim Mattson pmu_counter_t instr_cnt = { 616cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(1), 61720cf9147SJim Mattson /* instructions */ 61885c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[instruction_idx].unit_sel, 61920cf9147SJim Mattson }; 62020cf9147SJim Mattson report_prefix_push("emulated instruction"); 62120cf9147SJim Mattson 62262ba5036SLike Xu if (this_cpu_has_perf_global_status()) 6238a2866d1SLike Xu pmu_clear_global_status(); 62420cf9147SJim Mattson 62520cf9147SJim Mattson start_event(&brnch_cnt); 62620cf9147SJim Mattson start_event(&instr_cnt); 62720cf9147SJim Mattson 62820cf9147SJim Mattson brnch_start = -EXPECTED_BRNCH; 62920cf9147SJim Mattson instr_start = -EXPECTED_INSTR; 6308b547cc2SLike Xu wrmsr(MSR_GP_COUNTERx(0), brnch_start & gp_counter_width); 6318b547cc2SLike Xu wrmsr(MSR_GP_COUNTERx(1), instr_start & gp_counter_width); 63220cf9147SJim Mattson // KVM_FEP is a magic prefix that forces emulation so 63320cf9147SJim Mattson // 'KVM_FEP "jne label\n"' just counts as a single instruction. 63420cf9147SJim Mattson asm volatile( 63520cf9147SJim Mattson "mov $0x0, %%eax\n" 63620cf9147SJim Mattson "cmp $0x0, %%eax\n" 63720cf9147SJim Mattson KVM_FEP "jne label\n" 63820cf9147SJim Mattson KVM_FEP "jne label\n" 63920cf9147SJim Mattson KVM_FEP "jne label\n" 64020cf9147SJim Mattson KVM_FEP "jne label\n" 64120cf9147SJim Mattson KVM_FEP "jne label\n" 64220cf9147SJim Mattson "mov $0xa, %%eax\n" 64320cf9147SJim Mattson "cpuid\n" 64420cf9147SJim Mattson "mov $0xa, %%eax\n" 64520cf9147SJim Mattson "cpuid\n" 64620cf9147SJim Mattson "mov $0xa, %%eax\n" 64720cf9147SJim Mattson "cpuid\n" 64820cf9147SJim Mattson "mov $0xa, %%eax\n" 64920cf9147SJim Mattson "cpuid\n" 65020cf9147SJim Mattson "mov $0xa, %%eax\n" 65120cf9147SJim Mattson "cpuid\n" 65220cf9147SJim Mattson "label:\n" 65320cf9147SJim Mattson : 65420cf9147SJim Mattson : 65520cf9147SJim Mattson : "eax", "ebx", "ecx", "edx"); 65620cf9147SJim Mattson 65762ba5036SLike Xu if (this_cpu_has_perf_global_ctrl()) 6588a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, 0); 65920cf9147SJim Mattson 66020cf9147SJim Mattson stop_event(&brnch_cnt); 66120cf9147SJim Mattson stop_event(&instr_cnt); 66220cf9147SJim Mattson 66320cf9147SJim Mattson // Check that the end count - start count is at least the expected 66420cf9147SJim Mattson // number of instructions and branches. 66520cf9147SJim Mattson report(instr_cnt.count - instr_start >= EXPECTED_INSTR, 66620cf9147SJim Mattson "instruction count"); 66720cf9147SJim Mattson report(brnch_cnt.count - brnch_start >= EXPECTED_BRNCH, 66820cf9147SJim Mattson "branch count"); 66962ba5036SLike Xu if (this_cpu_has_perf_global_status()) { 67020cf9147SJim Mattson // Additionally check that those counters overflowed properly. 6718a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 6724070b9c6SLike Xu report(status & 1, "branch counter overflow"); 6734070b9c6SLike Xu report(status & 2, "instruction counter overflow"); 67462ba5036SLike Xu } 67520cf9147SJim Mattson 67620cf9147SJim Mattson report_prefix_pop(); 67720cf9147SJim Mattson } 67820cf9147SJim Mattson 679006b089dSLike Xu #define XBEGIN_STARTED (~0u) 680006b089dSLike Xu static void check_tsx_cycles(void) 681006b089dSLike Xu { 682006b089dSLike Xu pmu_counter_t cnt; 683006b089dSLike Xu unsigned int i, ret = 0; 684006b089dSLike Xu 685006b089dSLike Xu if (!this_cpu_has(X86_FEATURE_RTM)) 686006b089dSLike Xu return; 687006b089dSLike Xu 688006b089dSLike Xu report_prefix_push("TSX cycles"); 689006b089dSLike Xu 690006b089dSLike Xu for (i = 0; i < pmu.nr_gp_counters; i++) { 691006b089dSLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 692006b089dSLike Xu 693006b089dSLike Xu if (i == 2) { 694d4ae0a71SThomas Huth /* Transactional cycles committed only on gp counter 2 */ 695006b089dSLike Xu cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x30000003c; 696006b089dSLike Xu } else { 697006b089dSLike Xu /* Transactional cycles */ 698006b089dSLike Xu cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x10000003c; 699006b089dSLike Xu } 700006b089dSLike Xu 701006b089dSLike Xu start_event(&cnt); 702006b089dSLike Xu 703006b089dSLike Xu asm volatile("xbegin 1f\n\t" 704006b089dSLike Xu "1:\n\t" 705006b089dSLike Xu : "+a" (ret) :: "memory"); 706006b089dSLike Xu 707006b089dSLike Xu /* Generate a non-canonical #GP to trigger ABORT. */ 708006b089dSLike Xu if (ret == XBEGIN_STARTED) 709006b089dSLike Xu *(int *)NONCANONICAL = 0; 710006b089dSLike Xu 711006b089dSLike Xu stop_event(&cnt); 712006b089dSLike Xu 713006b089dSLike Xu report(cnt.count > 0, "gp cntr-%d with a value of %" PRId64 "", i, cnt.count); 714006b089dSLike Xu } 715006b089dSLike Xu 716006b089dSLike Xu report_prefix_pop(); 717006b089dSLike Xu } 718006b089dSLike Xu 719f2a56148SDapeng Mi static void warm_up(void) 720f2a56148SDapeng Mi { 721f2a56148SDapeng Mi int i; 722f2a56148SDapeng Mi 723f2a56148SDapeng Mi /* 724f2a56148SDapeng Mi * Since cycles event is always run as the first event, there would be 725f2a56148SDapeng Mi * a warm-up state to warm up the cache, it leads to the measured cycles 726f2a56148SDapeng Mi * value may exceed the pre-defined cycles upper boundary and cause 727f2a56148SDapeng Mi * false positive. To avoid this, introduce an warm-up state before 728f2a56148SDapeng Mi * the real verification. 729f2a56148SDapeng Mi */ 730f2a56148SDapeng Mi for (i = 0; i < 10; i++) 73150f8e27eSDapeng Mi loop(0); 732f2a56148SDapeng Mi } 733f2a56148SDapeng Mi 73422f2901aSLike Xu static void check_counters(void) 73522f2901aSLike Xu { 73600dca75cSLike Xu if (is_fep_available()) 73700dca75cSLike Xu check_emulated_instr(); 73800dca75cSLike Xu 739f2a56148SDapeng Mi warm_up(); 74022f2901aSLike Xu check_gp_counters(); 74122f2901aSLike Xu check_fixed_counters(); 74222f2901aSLike Xu check_rdpmc(); 74322f2901aSLike Xu check_counters_many(); 74422f2901aSLike Xu check_counter_overflow(); 74522f2901aSLike Xu check_gp_counter_cmask(); 74622f2901aSLike Xu check_running_counter_wrmsr(); 747006b089dSLike Xu check_tsx_cycles(); 74822f2901aSLike Xu } 74922f2901aSLike Xu 75022f2901aSLike Xu static void do_unsupported_width_counter_write(void *index) 75122f2901aSLike Xu { 75222f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + *((int *) index), 0xffffff0123456789ull); 75322f2901aSLike Xu } 75422f2901aSLike Xu 75522f2901aSLike Xu static void check_gp_counters_write_width(void) 75622f2901aSLike Xu { 75722f2901aSLike Xu u64 val_64 = 0xffffff0123456789ull; 7584b74c718SThomas Huth u64 val_32 = val_64 & ((1ull << 32) - 1); 759414ee7d1SSean Christopherson u64 val_max_width = val_64 & ((1ull << pmu.gp_counter_width) - 1); 76022f2901aSLike Xu int i; 76122f2901aSLike Xu 76222f2901aSLike Xu /* 76322f2901aSLike Xu * MSR_IA32_PERFCTRn supports 64-bit writes, 76422f2901aSLike Xu * but only the lowest 32 bits are valid. 76522f2901aSLike Xu */ 766414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 76722f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_32); 76822f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 76922f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 77022f2901aSLike Xu 77122f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_max_width); 77222f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 77322f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 77422f2901aSLike Xu 77522f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_64); 77622f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 77722f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 77822f2901aSLike Xu } 77922f2901aSLike Xu 78022f2901aSLike Xu /* 7814340720eSLike Xu * MSR_IA32_PMCn supports writing values up to GP counter width, 78222f2901aSLike Xu * and only the lowest bits of GP counter width are valid. 78322f2901aSLike Xu */ 784414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 78522f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + i, val_32); 78622f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 78722f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 78822f2901aSLike Xu 78922f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + i, val_max_width); 79022f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_max_width); 79122f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_max_width); 79222f2901aSLike Xu 79322f2901aSLike Xu report(test_for_exception(GP_VECTOR, 79422f2901aSLike Xu do_unsupported_width_counter_write, &i), 79522f2901aSLike Xu "writing unsupported width to MSR_IA32_PMC%d raises #GP", i); 79622f2901aSLike Xu } 79722f2901aSLike Xu } 79822f2901aSLike Xu 799290f4213SJim Mattson /* 800290f4213SJim Mattson * Per the SDM, reference cycles are currently implemented using the 801290f4213SJim Mattson * core crystal clock, TSC, or bus clock. Calibrate to the TSC 802290f4213SJim Mattson * frequency to set reasonable expectations. 803290f4213SJim Mattson */ 804290f4213SJim Mattson static void set_ref_cycle_expectations(void) 805290f4213SJim Mattson { 806290f4213SJim Mattson pmu_counter_t cnt = { 807290f4213SJim Mattson .ctr = MSR_IA32_PERFCTR0, 80825cc1ea7SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 80925cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].unit_sel, 810290f4213SJim Mattson }; 811290f4213SJim Mattson uint64_t tsc_delta; 812290f4213SJim Mattson uint64_t t0, t1, t2, t3; 813290f4213SJim Mattson 8142719b92cSYang Weijiang /* Bit 2 enumerates the availability of reference cycles events. */ 815414ee7d1SSean Christopherson if (!pmu.nr_gp_counters || !pmu_gp_counter_is_available(2)) 816290f4213SJim Mattson return; 817290f4213SJim Mattson 81862ba5036SLike Xu if (this_cpu_has_perf_global_ctrl()) 8198a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, 0); 820290f4213SJim Mattson 821290f4213SJim Mattson t0 = fenced_rdtsc(); 822290f4213SJim Mattson start_event(&cnt); 823290f4213SJim Mattson t1 = fenced_rdtsc(); 824290f4213SJim Mattson 825290f4213SJim Mattson /* 826290f4213SJim Mattson * This loop has to run long enough to dominate the VM-exit 827290f4213SJim Mattson * costs for playing with the PMU MSRs on start and stop. 828290f4213SJim Mattson * 829290f4213SJim Mattson * On a 2.6GHz Ice Lake, with the TSC frequency at 104 times 830290f4213SJim Mattson * the core crystal clock, this function calculated a guest 831290f4213SJim Mattson * TSC : ref cycles ratio of around 105 with ECX initialized 832290f4213SJim Mattson * to one billion. 833290f4213SJim Mattson */ 834290f4213SJim Mattson asm volatile("loop ." : "+c"((int){1000000000ull})); 835290f4213SJim Mattson 836290f4213SJim Mattson t2 = fenced_rdtsc(); 837290f4213SJim Mattson stop_event(&cnt); 838290f4213SJim Mattson t3 = fenced_rdtsc(); 839290f4213SJim Mattson 840290f4213SJim Mattson tsc_delta = ((t2 - t1) + (t3 - t0)) / 2; 841290f4213SJim Mattson 842290f4213SJim Mattson if (!tsc_delta) 843290f4213SJim Mattson return; 844290f4213SJim Mattson 84525cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].min = 84625cc1ea7SDapeng Mi (intel_gp_events[INTEL_REF_CYCLES_IDX].min * cnt.count) / tsc_delta; 84725cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].max = 84825cc1ea7SDapeng Mi (intel_gp_events[INTEL_REF_CYCLES_IDX].max * cnt.count) / tsc_delta; 849290f4213SJim Mattson } 850290f4213SJim Mattson 85185c21181SLike Xu static void check_invalid_rdpmc_gp(void) 85285c21181SLike Xu { 85385c21181SLike Xu uint64_t val; 85485c21181SLike Xu 85585c21181SLike Xu report(rdpmc_safe(64, &val) == GP_VECTOR, 85685c21181SLike Xu "Expected #GP on RDPMC(64)"); 85785c21181SLike Xu } 85885c21181SLike Xu 859a9f8b16fSGleb Natapov int main(int ac, char **av) 860a9f8b16fSGleb Natapov { 861*89126fa4SDapeng Mi int instruction_idx; 862*89126fa4SDapeng Mi int branch_idx; 863*89126fa4SDapeng Mi 864a9f8b16fSGleb Natapov setup_vm(); 8655a2cb3e6SLike Xu handle_irq(PMI_VECTOR, cnt_overflow); 866dcda215bSPaolo Bonzini buf = malloc(N*64); 867a9f8b16fSGleb Natapov 86885c21181SLike Xu check_invalid_rdpmc_gp(); 86985c21181SLike Xu 870b883751aSLike Xu if (pmu.is_intel) { 871414ee7d1SSean Christopherson if (!pmu.version) { 87203041e97SLike Xu report_skip("No Intel Arch PMU is detected!"); 87332b9603cSRadim Krčmář return report_summary(); 874a9f8b16fSGleb Natapov } 8757c648ce2SLike Xu gp_events = (struct pmu_event *)intel_gp_events; 8767c648ce2SLike Xu gp_events_size = sizeof(intel_gp_events)/sizeof(intel_gp_events[0]); 877*89126fa4SDapeng Mi instruction_idx = INTEL_INSTRUCTIONS_IDX; 878*89126fa4SDapeng Mi branch_idx = INTEL_BRANCHES_IDX; 879b883751aSLike Xu report_prefix_push("Intel"); 880290f4213SJim Mattson set_ref_cycle_expectations(); 881b883751aSLike Xu } else { 882b883751aSLike Xu gp_events_size = sizeof(amd_gp_events)/sizeof(amd_gp_events[0]); 883b883751aSLike Xu gp_events = (struct pmu_event *)amd_gp_events; 884*89126fa4SDapeng Mi instruction_idx = AMD_INSTRUCTIONS_IDX; 885*89126fa4SDapeng Mi branch_idx = AMD_BRANCHES_IDX; 886b883751aSLike Xu report_prefix_push("AMD"); 887b883751aSLike Xu } 888*89126fa4SDapeng Mi adjust_events_range(gp_events, instruction_idx, branch_idx); 889290f4213SJim Mattson 890414ee7d1SSean Christopherson printf("PMU version: %d\n", pmu.version); 891414ee7d1SSean Christopherson printf("GP counters: %d\n", pmu.nr_gp_counters); 892414ee7d1SSean Christopherson printf("GP counter width: %d\n", pmu.gp_counter_width); 893414ee7d1SSean Christopherson printf("Mask length: %d\n", pmu.gp_counter_mask_length); 894414ee7d1SSean Christopherson printf("Fixed counters: %d\n", pmu.nr_fixed_counters); 895414ee7d1SSean Christopherson printf("Fixed counter width: %d\n", pmu.fixed_counter_width); 8960ef1f6a8SPaolo Bonzini 8979c07c92bSDapeng Mi fixed_counters_num = MIN(pmu.nr_fixed_counters, ARRAY_SIZE(fixed_events)); 8989c07c92bSDapeng Mi if (pmu.nr_fixed_counters > ARRAY_SIZE(fixed_events)) 8999c07c92bSDapeng Mi report_info("Fixed counters number %d > defined fixed events %u. " 9009c07c92bSDapeng Mi "Please update test case.", pmu.nr_fixed_counters, 9019c07c92bSDapeng Mi (uint32_t)ARRAY_SIZE(fixed_events)); 9029c07c92bSDapeng Mi 9035a2cb3e6SLike Xu apic_write(APIC_LVTPC, PMI_VECTOR); 904a9f8b16fSGleb Natapov 905afa714b2SPaolo Bonzini check_counters(); 90620cf9147SJim Mattson 907879e7f07SLike Xu if (pmu_has_full_writes()) { 908cda64e80SLike Xu pmu.msr_gp_counter_base = MSR_IA32_PMC0; 909cda64e80SLike Xu 91022f2901aSLike Xu report_prefix_push("full-width writes"); 91122f2901aSLike Xu check_counters(); 91222f2901aSLike Xu check_gp_counters_write_width(); 913d7714e16SLike Xu report_prefix_pop(); 91422f2901aSLike Xu } 915a9f8b16fSGleb Natapov 916b883751aSLike Xu if (!pmu.is_intel) { 917b883751aSLike Xu report_prefix_push("K7"); 918b883751aSLike Xu pmu.nr_gp_counters = AMD64_NUM_COUNTERS; 919b883751aSLike Xu pmu.msr_gp_counter_base = MSR_K7_PERFCTR0; 920b883751aSLike Xu pmu.msr_gp_event_select_base = MSR_K7_EVNTSEL0; 921b883751aSLike Xu check_counters(); 922b883751aSLike Xu report_prefix_pop(); 923b883751aSLike Xu } 924b883751aSLike Xu 925f3cdd159SJan Kiszka return report_summary(); 926a9f8b16fSGleb Natapov } 927