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 228dbfe326SDapeng Mi #define IBPB_JMP_INSNS 9 238dbfe326SDapeng Mi #define IBPB_JMP_BRANCHES 2 248dbfe326SDapeng Mi 258dbfe326SDapeng Mi #if defined(__i386__) || defined(_M_IX86) /* i386 */ 268dbfe326SDapeng Mi #define IBPB_JMP_ASM(_wrmsr) \ 278dbfe326SDapeng Mi "mov $1, %%eax; xor %%edx, %%edx;\n\t" \ 288dbfe326SDapeng Mi "mov $73, %%ecx;\n\t" \ 2950f8e27eSDapeng Mi _wrmsr "\n\t" \ 308dbfe326SDapeng Mi "call 1f\n\t" \ 318dbfe326SDapeng Mi "1: pop %%eax\n\t" \ 328dbfe326SDapeng Mi "add $(2f-1b), %%eax\n\t" \ 338dbfe326SDapeng Mi "jmp *%%eax;\n\t" \ 348dbfe326SDapeng Mi "nop;\n\t" \ 358dbfe326SDapeng Mi "2: nop;\n\t" 368dbfe326SDapeng Mi #else /* x86_64 */ 378dbfe326SDapeng Mi #define IBPB_JMP_ASM(_wrmsr) \ 388dbfe326SDapeng Mi "mov $1, %%eax; xor %%edx, %%edx;\n\t" \ 398dbfe326SDapeng Mi "mov $73, %%ecx;\n\t" \ 408dbfe326SDapeng Mi _wrmsr "\n\t" \ 418dbfe326SDapeng Mi "call 1f\n\t" \ 428dbfe326SDapeng Mi "1: pop %%rax\n\t" \ 438dbfe326SDapeng Mi "add $(2f-1b), %%rax\n\t" \ 448dbfe326SDapeng Mi "jmp *%%rax;\n\t" \ 458dbfe326SDapeng Mi "nop;\n\t" \ 468dbfe326SDapeng Mi "2: nop;\n\t" 478dbfe326SDapeng Mi #endif 488dbfe326SDapeng Mi 498dbfe326SDapeng Mi /* GLOBAL_CTRL enable + disable + clflush/mfence + IBPB_JMP */ 508dbfe326SDapeng Mi #define EXTRA_INSNS (3 + 3 + 2 + IBPB_JMP_INSNS) 518dbfe326SDapeng Mi #define LOOP_INSNS (N * 10 + EXTRA_INSNS) 528dbfe326SDapeng Mi #define LOOP_BRANCHES (N + IBPB_JMP_BRANCHES) 538dbfe326SDapeng Mi #define LOOP_ASM(_wrmsr1, _clflush, _wrmsr2) \ 548dbfe326SDapeng Mi _wrmsr1 "\n\t" \ 5550f8e27eSDapeng Mi "mov %%ecx, %%edi; mov %%ebx, %%ecx;\n\t" \ 5638b5b426SDapeng Mi _clflush "\n\t" \ 5738b5b426SDapeng Mi "mfence;\n\t" \ 5850f8e27eSDapeng Mi "1: mov (%1), %2; add $64, %1;\n\t" \ 5950f8e27eSDapeng Mi "nop; nop; nop; nop; nop; nop; nop;\n\t" \ 6050f8e27eSDapeng Mi "loop 1b;\n\t" \ 618dbfe326SDapeng Mi IBPB_JMP_ASM(_wrmsr2) \ 6250f8e27eSDapeng Mi "mov %%edi, %%ecx; xor %%eax, %%eax; xor %%edx, %%edx;\n\t" \ 638dbfe326SDapeng Mi _wrmsr1 "\n\t" 6450f8e27eSDapeng Mi 658dbfe326SDapeng Mi #define _loop_asm(_wrmsr1, _clflush, _wrmsr2) \ 6638b5b426SDapeng Mi do { \ 678dbfe326SDapeng Mi asm volatile(LOOP_ASM(_wrmsr1, _clflush, _wrmsr2) \ 6838b5b426SDapeng Mi : "=b"(tmp), "=r"(tmp2), "=r"(tmp3) \ 6938b5b426SDapeng Mi : "a"(eax), "d"(edx), "c"(global_ctl), \ 7038b5b426SDapeng Mi "0"(N), "1"(buf) \ 7138b5b426SDapeng Mi : "edi"); \ 7238b5b426SDapeng Mi } while (0) 7338b5b426SDapeng Mi 74a9f8b16fSGleb Natapov typedef struct { 75a9f8b16fSGleb Natapov uint32_t ctr; 769720e46cSDapeng Mi uint32_t idx; 77006b089dSLike Xu uint64_t config; 78a9f8b16fSGleb Natapov uint64_t count; 79a9f8b16fSGleb Natapov } pmu_counter_t; 80a9f8b16fSGleb Natapov 81a9f8b16fSGleb Natapov struct pmu_event { 82797d79a2SThomas Huth const char *name; 83a9f8b16fSGleb Natapov uint32_t unit_sel; 84a9f8b16fSGleb Natapov int min; 85a9f8b16fSGleb Natapov int max; 867c648ce2SLike Xu } intel_gp_events[] = { 87a9f8b16fSGleb Natapov {"core cycles", 0x003c, 1*N, 50*N}, 88a9f8b16fSGleb Natapov {"instructions", 0x00c0, 10*N, 10.2*N}, 89290f4213SJim Mattson {"ref cycles", 0x013c, 1*N, 30*N}, 90290f4213SJim Mattson {"llc references", 0x4f2e, 1, 2*N}, 91a9f8b16fSGleb Natapov {"llc misses", 0x412e, 1, 1*N}, 92a9f8b16fSGleb Natapov {"branches", 0x00c4, 1*N, 1.1*N}, 93*28437cdbSDapeng Mi {"branch misses", 0x00c5, 1, 0.1*N}, 94b883751aSLike Xu }, amd_gp_events[] = { 95b883751aSLike Xu {"core cycles", 0x0076, 1*N, 50*N}, 96b883751aSLike Xu {"instructions", 0x00c0, 10*N, 10.2*N}, 97b883751aSLike Xu {"branches", 0x00c2, 1*N, 1.1*N}, 98*28437cdbSDapeng Mi {"branch misses", 0x00c3, 1, 0.1*N}, 99a9f8b16fSGleb Natapov }, fixed_events[] = { 1005d6a3a54SDapeng Mi {"fixed 0", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N}, 1015d6a3a54SDapeng Mi {"fixed 1", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N}, 1025d6a3a54SDapeng Mi {"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 2, 0.1*N, 30*N} 103a9f8b16fSGleb Natapov }; 104a9f8b16fSGleb Natapov 105f4e97f59SDapeng Mi /* 106f4e97f59SDapeng Mi * Events index in intel_gp_events[], ensure consistent with 107f4e97f59SDapeng Mi * intel_gp_events[]. 108f4e97f59SDapeng Mi */ 109f4e97f59SDapeng Mi enum { 11085c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX = 1, 11125cc1ea7SDapeng Mi INTEL_REF_CYCLES_IDX = 2, 112e0d0022fSDapeng Mi INTEL_LLC_MISSES_IDX = 4, 113f4e97f59SDapeng Mi INTEL_BRANCHES_IDX = 5, 114*28437cdbSDapeng Mi INTEL_BRANCH_MISS_IDX = 6, 115f4e97f59SDapeng Mi }; 116f4e97f59SDapeng Mi 117f4e97f59SDapeng Mi /* 118f4e97f59SDapeng Mi * Events index in amd_gp_events[], ensure consistent with 119f4e97f59SDapeng Mi * amd_gp_events[]. 120f4e97f59SDapeng Mi */ 121f4e97f59SDapeng Mi enum { 12285c75578SDapeng Mi AMD_INSTRUCTIONS_IDX = 1, 123f4e97f59SDapeng Mi AMD_BRANCHES_IDX = 2, 124*28437cdbSDapeng Mi AMD_BRANCH_MISS_IDX = 3, 125f4e97f59SDapeng Mi }; 126f4e97f59SDapeng Mi 127a9f8b16fSGleb Natapov char *buf; 128a9f8b16fSGleb Natapov 1297c648ce2SLike Xu static struct pmu_event *gp_events; 1307c648ce2SLike Xu static unsigned int gp_events_size; 1319c07c92bSDapeng Mi static unsigned int fixed_counters_num; 1327c648ce2SLike Xu 1338dbfe326SDapeng Mi static int has_ibpb(void) 1348dbfe326SDapeng Mi { 1358dbfe326SDapeng Mi return this_cpu_has(X86_FEATURE_SPEC_CTRL) || 1368dbfe326SDapeng Mi this_cpu_has(X86_FEATURE_AMD_IBPB); 1378dbfe326SDapeng Mi } 1388dbfe326SDapeng Mi 13950f8e27eSDapeng Mi static inline void __loop(void) 140a9f8b16fSGleb Natapov { 141a9f8b16fSGleb Natapov unsigned long tmp, tmp2, tmp3; 14238b5b426SDapeng Mi u32 global_ctl = 0; 14338b5b426SDapeng Mi u32 eax = 0; 14438b5b426SDapeng Mi u32 edx = 0; 145a9f8b16fSGleb Natapov 1468dbfe326SDapeng Mi if (this_cpu_has(X86_FEATURE_CLFLUSH) && has_ibpb()) 1478dbfe326SDapeng Mi _loop_asm("nop", "clflush (%1)", "wrmsr"); 1488dbfe326SDapeng Mi else if (this_cpu_has(X86_FEATURE_CLFLUSH)) 1498dbfe326SDapeng Mi _loop_asm("nop", "clflush (%1)", "nop"); 1508dbfe326SDapeng Mi else if (has_ibpb()) 1518dbfe326SDapeng Mi _loop_asm("nop", "nop", "wrmsr"); 15238b5b426SDapeng Mi else 1538dbfe326SDapeng Mi _loop_asm("nop", "nop", "nop"); 15450f8e27eSDapeng Mi } 155a9f8b16fSGleb Natapov 15650f8e27eSDapeng Mi /* 15750f8e27eSDapeng Mi * Enable and disable counters in a whole asm blob to ensure 15850f8e27eSDapeng Mi * no other instructions are counted in the window between 15950f8e27eSDapeng Mi * counters enabling and really LOOP_ASM code executing. 16050f8e27eSDapeng Mi * Thus counters can verify instructions and branches events 16150f8e27eSDapeng Mi * against precise counts instead of a rough valid count range. 16250f8e27eSDapeng Mi */ 16350f8e27eSDapeng Mi static inline void __precise_loop(u64 cntrs) 16450f8e27eSDapeng Mi { 16550f8e27eSDapeng Mi unsigned long tmp, tmp2, tmp3; 16638b5b426SDapeng Mi u32 global_ctl = pmu.msr_global_ctl; 16750f8e27eSDapeng Mi u32 eax = cntrs & (BIT_ULL(32) - 1); 16850f8e27eSDapeng Mi u32 edx = cntrs >> 32; 16950f8e27eSDapeng Mi 1708dbfe326SDapeng Mi if (this_cpu_has(X86_FEATURE_CLFLUSH) && has_ibpb()) 1718dbfe326SDapeng Mi _loop_asm("wrmsr", "clflush (%1)", "wrmsr"); 1728dbfe326SDapeng Mi else if (this_cpu_has(X86_FEATURE_CLFLUSH)) 1738dbfe326SDapeng Mi _loop_asm("wrmsr", "clflush (%1)", "nop"); 1748dbfe326SDapeng Mi else if (has_ibpb()) 1758dbfe326SDapeng Mi _loop_asm("wrmsr", "nop", "wrmsr"); 17638b5b426SDapeng Mi else 1778dbfe326SDapeng Mi _loop_asm("wrmsr", "nop", "nop"); 17850f8e27eSDapeng Mi } 17950f8e27eSDapeng Mi 18050f8e27eSDapeng Mi static inline void loop(u64 cntrs) 18150f8e27eSDapeng Mi { 18250f8e27eSDapeng Mi if (!this_cpu_has_perf_global_ctrl()) 18350f8e27eSDapeng Mi __loop(); 18450f8e27eSDapeng Mi else 18550f8e27eSDapeng Mi __precise_loop(cntrs); 186a9f8b16fSGleb Natapov } 187a9f8b16fSGleb Natapov 18889126fa4SDapeng Mi static void adjust_events_range(struct pmu_event *gp_events, 189*28437cdbSDapeng Mi int instruction_idx, int branch_idx, 190*28437cdbSDapeng Mi int branch_miss_idx) 19189126fa4SDapeng Mi { 19289126fa4SDapeng Mi /* 19389126fa4SDapeng Mi * If HW supports GLOBAL_CTRL MSR, enabling and disabling PMCs are 19489126fa4SDapeng Mi * moved in __precise_loop(). Thus, instructions and branches events 19589126fa4SDapeng Mi * can be verified against a precise count instead of a rough range. 19689126fa4SDapeng Mi * 19789126fa4SDapeng Mi * Skip the precise checks on AMD, as AMD CPUs count VMRUN as a branch 19889126fa4SDapeng Mi * instruction in guest context, which* leads to intermittent failures 19989126fa4SDapeng Mi * as the counts will vary depending on how many asynchronous VM-Exits 20089126fa4SDapeng Mi * occur while running the measured code, e.g. if the host takes IRQs. 20189126fa4SDapeng Mi */ 20289126fa4SDapeng Mi if (pmu.is_intel && this_cpu_has_perf_global_ctrl()) { 20389126fa4SDapeng Mi gp_events[instruction_idx].min = LOOP_INSNS; 20489126fa4SDapeng Mi gp_events[instruction_idx].max = LOOP_INSNS; 20589126fa4SDapeng Mi gp_events[branch_idx].min = LOOP_BRANCHES; 20689126fa4SDapeng Mi gp_events[branch_idx].max = LOOP_BRANCHES; 20789126fa4SDapeng Mi } 208*28437cdbSDapeng Mi 209*28437cdbSDapeng Mi /* 210*28437cdbSDapeng Mi * For CPUs without IBPB support, no way to force to trigger a branch 211*28437cdbSDapeng Mi * miss and the measured branch misses is possible to be 0. Thus 212*28437cdbSDapeng Mi * overwrite the lower boundary of branch misses event to 0 to avoid 213*28437cdbSDapeng Mi * false positive. 214*28437cdbSDapeng Mi */ 215*28437cdbSDapeng Mi if (!has_ibpb()) 216*28437cdbSDapeng Mi gp_events[branch_miss_idx].min = 0; 21789126fa4SDapeng Mi } 21889126fa4SDapeng Mi 219a9f8b16fSGleb Natapov volatile uint64_t irq_received; 220a9f8b16fSGleb Natapov 221a9f8b16fSGleb Natapov static void cnt_overflow(isr_regs_t *regs) 222a9f8b16fSGleb Natapov { 223a9f8b16fSGleb Natapov irq_received++; 224c595c361SMingwei Zhang apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); 225a9f8b16fSGleb Natapov apic_write(APIC_EOI, 0); 226a9f8b16fSGleb Natapov } 227a9f8b16fSGleb Natapov 228a9f8b16fSGleb Natapov static bool check_irq(void) 229a9f8b16fSGleb Natapov { 230a9f8b16fSGleb Natapov int i; 231a9f8b16fSGleb Natapov irq_received = 0; 232787f0aebSMaxim Levitsky sti(); 233a9f8b16fSGleb Natapov for (i = 0; i < 100000 && !irq_received; i++) 234a9f8b16fSGleb Natapov asm volatile("pause"); 235787f0aebSMaxim Levitsky cli(); 236a9f8b16fSGleb Natapov return irq_received; 237a9f8b16fSGleb Natapov } 238a9f8b16fSGleb Natapov 239a9f8b16fSGleb Natapov static bool is_gp(pmu_counter_t *evt) 240a9f8b16fSGleb Natapov { 241b883751aSLike Xu if (!pmu.is_intel) 242b883751aSLike Xu return true; 243b883751aSLike Xu 24422f2901aSLike Xu return evt->ctr < MSR_CORE_PERF_FIXED_CTR0 || 24522f2901aSLike Xu evt->ctr >= MSR_IA32_PMC0; 246a9f8b16fSGleb Natapov } 247a9f8b16fSGleb Natapov 248a9f8b16fSGleb Natapov static int event_to_global_idx(pmu_counter_t *cnt) 249a9f8b16fSGleb Natapov { 250b883751aSLike Xu if (pmu.is_intel) 251cda64e80SLike Xu return cnt->ctr - (is_gp(cnt) ? pmu.msr_gp_counter_base : 252a9f8b16fSGleb Natapov (MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX)); 253b883751aSLike Xu 254b883751aSLike Xu if (pmu.msr_gp_counter_base == MSR_F15H_PERF_CTR0) 255b883751aSLike Xu return (cnt->ctr - pmu.msr_gp_counter_base) / 2; 256b883751aSLike Xu else 257b883751aSLike Xu return cnt->ctr - pmu.msr_gp_counter_base; 258a9f8b16fSGleb Natapov } 259a9f8b16fSGleb Natapov 260a9f8b16fSGleb Natapov static struct pmu_event* get_counter_event(pmu_counter_t *cnt) 261a9f8b16fSGleb Natapov { 262a9f8b16fSGleb Natapov if (is_gp(cnt)) { 263a9f8b16fSGleb Natapov int i; 264a9f8b16fSGleb Natapov 2657c648ce2SLike Xu for (i = 0; i < gp_events_size; i++) 266a9f8b16fSGleb Natapov if (gp_events[i].unit_sel == (cnt->config & 0xffff)) 267a9f8b16fSGleb Natapov return &gp_events[i]; 2689c07c92bSDapeng Mi } else { 2699c07c92bSDapeng Mi unsigned int idx = cnt->ctr - MSR_CORE_PERF_FIXED_CTR0; 2709c07c92bSDapeng Mi 2719c07c92bSDapeng Mi if (idx < ARRAY_SIZE(fixed_events)) 2729c07c92bSDapeng Mi return &fixed_events[idx]; 2739c07c92bSDapeng Mi } 274a9f8b16fSGleb Natapov 275a9f8b16fSGleb Natapov return (void*)0; 276a9f8b16fSGleb Natapov } 277a9f8b16fSGleb Natapov 278a9f8b16fSGleb Natapov static void global_enable(pmu_counter_t *cnt) 279a9f8b16fSGleb Natapov { 28062ba5036SLike Xu if (!this_cpu_has_perf_global_ctrl()) 28162ba5036SLike Xu return; 28262ba5036SLike Xu 283a9f8b16fSGleb Natapov cnt->idx = event_to_global_idx(cnt); 2848a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) | BIT_ULL(cnt->idx)); 285a9f8b16fSGleb Natapov } 286a9f8b16fSGleb Natapov 287a9f8b16fSGleb Natapov static void global_disable(pmu_counter_t *cnt) 288a9f8b16fSGleb Natapov { 28962ba5036SLike Xu if (!this_cpu_has_perf_global_ctrl()) 29062ba5036SLike Xu return; 29162ba5036SLike Xu 2928a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) & ~BIT_ULL(cnt->idx)); 293a9f8b16fSGleb Natapov } 294a9f8b16fSGleb Natapov 295e9e7577bSLike Xu static void __start_event(pmu_counter_t *evt, uint64_t count) 296a9f8b16fSGleb Natapov { 297e9e7577bSLike Xu evt->count = count; 298a9f8b16fSGleb Natapov wrmsr(evt->ctr, evt->count); 299cda64e80SLike Xu if (is_gp(evt)) { 300cda64e80SLike Xu wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)), 301a9f8b16fSGleb Natapov evt->config | EVNTSEL_EN); 302cda64e80SLike Xu } else { 303a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 304a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 305a9f8b16fSGleb Natapov uint32_t usrospmi = 0; 306a9f8b16fSGleb Natapov 307a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_OS) 308a9f8b16fSGleb Natapov usrospmi |= (1 << 0); 309a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_USR) 310a9f8b16fSGleb Natapov usrospmi |= (1 << 1); 311a9f8b16fSGleb Natapov if (evt->config & EVNTSEL_INT) 312a9f8b16fSGleb Natapov usrospmi |= (1 << 3); // PMI on overflow 313a9f8b16fSGleb Natapov ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift); 314a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl); 315a9f8b16fSGleb Natapov } 3165a2cb3e6SLike Xu apic_write(APIC_LVTPC, PMI_VECTOR); 317a9f8b16fSGleb Natapov } 318a9f8b16fSGleb Natapov 319e9e7577bSLike Xu static void start_event(pmu_counter_t *evt) 320e9e7577bSLike Xu { 321e9e7577bSLike Xu __start_event(evt, 0); 32250f8e27eSDapeng Mi global_enable(evt); 323e9e7577bSLike Xu } 324e9e7577bSLike Xu 32550f8e27eSDapeng Mi static void __stop_event(pmu_counter_t *evt) 326a9f8b16fSGleb Natapov { 327cda64e80SLike Xu if (is_gp(evt)) { 328cda64e80SLike Xu wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)), 329a9f8b16fSGleb Natapov evt->config & ~EVNTSEL_EN); 330cda64e80SLike Xu } else { 331a9f8b16fSGleb Natapov uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 332a9f8b16fSGleb Natapov int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 333a9f8b16fSGleb Natapov wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift)); 334a9f8b16fSGleb Natapov } 335a9f8b16fSGleb Natapov evt->count = rdmsr(evt->ctr); 336a9f8b16fSGleb Natapov } 337a9f8b16fSGleb Natapov 33850f8e27eSDapeng Mi static void stop_event(pmu_counter_t *evt) 33950f8e27eSDapeng Mi { 34050f8e27eSDapeng Mi global_disable(evt); 34150f8e27eSDapeng Mi __stop_event(evt); 34250f8e27eSDapeng Mi } 34350f8e27eSDapeng Mi 3448554261fSLike Xu static noinline void measure_many(pmu_counter_t *evt, int count) 345a9f8b16fSGleb Natapov { 346a9f8b16fSGleb Natapov int i; 34750f8e27eSDapeng Mi u64 cntrs = 0; 34850f8e27eSDapeng Mi 34950f8e27eSDapeng Mi for (i = 0; i < count; i++) { 35050f8e27eSDapeng Mi __start_event(&evt[i], 0); 35150f8e27eSDapeng Mi cntrs |= BIT_ULL(event_to_global_idx(&evt[i])); 35250f8e27eSDapeng Mi } 35350f8e27eSDapeng Mi loop(cntrs); 354a9f8b16fSGleb Natapov for (i = 0; i < count; i++) 35550f8e27eSDapeng Mi __stop_event(&evt[i]); 356a9f8b16fSGleb Natapov } 357a9f8b16fSGleb Natapov 3588554261fSLike Xu static void measure_one(pmu_counter_t *evt) 3598554261fSLike Xu { 3608554261fSLike Xu measure_many(evt, 1); 3618554261fSLike Xu } 3628554261fSLike Xu 363e9e7577bSLike Xu static noinline void __measure(pmu_counter_t *evt, uint64_t count) 364e9e7577bSLike Xu { 36550f8e27eSDapeng Mi u64 cntrs = BIT_ULL(event_to_global_idx(evt)); 36650f8e27eSDapeng Mi 367e9e7577bSLike Xu __start_event(evt, count); 36850f8e27eSDapeng Mi loop(cntrs); 36950f8e27eSDapeng Mi __stop_event(evt); 370e9e7577bSLike Xu } 371e9e7577bSLike Xu 372a9f8b16fSGleb Natapov static bool verify_event(uint64_t count, struct pmu_event *e) 373a9f8b16fSGleb Natapov { 3749c07c92bSDapeng Mi bool pass; 375d24d3381SDapeng Mi 3769c07c92bSDapeng Mi if (!e) 3779c07c92bSDapeng Mi return false; 3789c07c92bSDapeng Mi 3799c07c92bSDapeng Mi pass = count >= e->min && count <= e->max; 380d24d3381SDapeng Mi if (!pass) 381d24d3381SDapeng Mi printf("FAIL: %d <= %"PRId64" <= %d\n", e->min, count, e->max); 382d24d3381SDapeng Mi 383d24d3381SDapeng Mi return pass; 384a9f8b16fSGleb Natapov } 385a9f8b16fSGleb Natapov 386a9f8b16fSGleb Natapov static bool verify_counter(pmu_counter_t *cnt) 387a9f8b16fSGleb Natapov { 388a9f8b16fSGleb Natapov return verify_event(cnt->count, get_counter_event(cnt)); 389a9f8b16fSGleb Natapov } 390a9f8b16fSGleb Natapov 391a9f8b16fSGleb Natapov static void check_gp_counter(struct pmu_event *evt) 392a9f8b16fSGleb Natapov { 393a9f8b16fSGleb Natapov pmu_counter_t cnt = { 394a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, 395a9f8b16fSGleb Natapov }; 396a9f8b16fSGleb Natapov int i; 397a9f8b16fSGleb Natapov 398cda64e80SLike Xu for (i = 0; i < pmu.nr_gp_counters; i++) { 399cda64e80SLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 4008554261fSLike Xu measure_one(&cnt); 401a299895bSThomas Huth report(verify_event(cnt.count, evt), "%s-%d", evt->name, i); 402a9f8b16fSGleb Natapov } 403a9f8b16fSGleb Natapov } 404a9f8b16fSGleb Natapov 405a9f8b16fSGleb Natapov static void check_gp_counters(void) 406a9f8b16fSGleb Natapov { 407a9f8b16fSGleb Natapov int i; 408a9f8b16fSGleb Natapov 4097c648ce2SLike Xu for (i = 0; i < gp_events_size; i++) 4102719b92cSYang Weijiang if (pmu_gp_counter_is_available(i)) 411a9f8b16fSGleb Natapov check_gp_counter(&gp_events[i]); 412a9f8b16fSGleb Natapov else 413a9f8b16fSGleb Natapov printf("GP event '%s' is disabled\n", 414a9f8b16fSGleb Natapov gp_events[i].name); 415a9f8b16fSGleb Natapov } 416a9f8b16fSGleb Natapov 417a9f8b16fSGleb Natapov static void check_fixed_counters(void) 418a9f8b16fSGleb Natapov { 419a9f8b16fSGleb Natapov pmu_counter_t cnt = { 420a9f8b16fSGleb Natapov .config = EVNTSEL_OS | EVNTSEL_USR, 421a9f8b16fSGleb Natapov }; 422a9f8b16fSGleb Natapov int i; 423a9f8b16fSGleb Natapov 4249c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 425a9f8b16fSGleb Natapov cnt.ctr = fixed_events[i].unit_sel; 4268554261fSLike Xu measure_one(&cnt); 4272719b92cSYang Weijiang report(verify_event(cnt.count, &fixed_events[i]), "fixed-%d", i); 428a9f8b16fSGleb Natapov } 429a9f8b16fSGleb Natapov } 430a9f8b16fSGleb Natapov 431a9f8b16fSGleb Natapov static void check_counters_many(void) 432a9f8b16fSGleb Natapov { 433f21c809eSDapeng Mi pmu_counter_t cnt[48]; 434a9f8b16fSGleb Natapov int i, n; 435a9f8b16fSGleb Natapov 436414ee7d1SSean Christopherson for (i = 0, n = 0; n < pmu.nr_gp_counters; i++) { 4372719b92cSYang Weijiang if (!pmu_gp_counter_is_available(i)) 438a9f8b16fSGleb Natapov continue; 439a9f8b16fSGleb Natapov 440cda64e80SLike Xu cnt[n].ctr = MSR_GP_COUNTERx(n); 4414ac45293SWei Huang cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | 4427c648ce2SLike Xu gp_events[i % gp_events_size].unit_sel; 443a9f8b16fSGleb Natapov n++; 444a9f8b16fSGleb Natapov } 4459c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 446a9f8b16fSGleb Natapov cnt[n].ctr = fixed_events[i].unit_sel; 447a9f8b16fSGleb Natapov cnt[n].config = EVNTSEL_OS | EVNTSEL_USR; 448a9f8b16fSGleb Natapov n++; 449a9f8b16fSGleb Natapov } 450a9f8b16fSGleb Natapov 451f21c809eSDapeng Mi assert(n <= ARRAY_SIZE(cnt)); 4528554261fSLike Xu measure_many(cnt, n); 453a9f8b16fSGleb Natapov 454a9f8b16fSGleb Natapov for (i = 0; i < n; i++) 455a9f8b16fSGleb Natapov if (!verify_counter(&cnt[i])) 456a9f8b16fSGleb Natapov break; 457a9f8b16fSGleb Natapov 458a299895bSThomas Huth report(i == n, "all counters"); 459a9f8b16fSGleb Natapov } 460a9f8b16fSGleb Natapov 4617ec3b67aSLike Xu static uint64_t measure_for_overflow(pmu_counter_t *cnt) 4627ec3b67aSLike Xu { 4637ec3b67aSLike Xu __measure(cnt, 0); 4647ec3b67aSLike Xu /* 4657ec3b67aSLike Xu * To generate overflow, i.e. roll over to '0', the initial count just 4667ec3b67aSLike Xu * needs to be preset to the negative expected count. However, as per 4677ec3b67aSLike Xu * Intel's SDM, the preset count needs to be incremented by 1 to ensure 4687ec3b67aSLike Xu * the overflow interrupt is generated immediately instead of possibly 4697ec3b67aSLike Xu * waiting for the overflow to propagate through the counter. 4707ec3b67aSLike Xu */ 4717ec3b67aSLike Xu assert(cnt->count > 1); 4727ec3b67aSLike Xu return 1 - cnt->count; 4737ec3b67aSLike Xu } 4747ec3b67aSLike Xu 475a9f8b16fSGleb Natapov static void check_counter_overflow(void) 476a9f8b16fSGleb Natapov { 477a9f8b16fSGleb Natapov int i; 47885c75578SDapeng Mi uint64_t overflow_preset; 47985c75578SDapeng Mi int instruction_idx = pmu.is_intel ? 48085c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 48185c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 48285c75578SDapeng Mi 483a9f8b16fSGleb Natapov pmu_counter_t cnt = { 484cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 48585c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 48685c75578SDapeng Mi gp_events[instruction_idx].unit_sel /* instructions */, 487a9f8b16fSGleb Natapov }; 4887ec3b67aSLike Xu overflow_preset = measure_for_overflow(&cnt); 489a9f8b16fSGleb Natapov 490a9f8b16fSGleb Natapov /* clear status before test */ 49162ba5036SLike Xu if (this_cpu_has_perf_global_status()) 4928a2866d1SLike Xu pmu_clear_global_status(); 493a9f8b16fSGleb Natapov 4945bba1769SAndrew Jones report_prefix_push("overflow"); 4955bba1769SAndrew Jones 496cda64e80SLike Xu for (i = 0; i < pmu.nr_gp_counters + 1; i++) { 497a9f8b16fSGleb Natapov uint64_t status; 498a9f8b16fSGleb Natapov int idx; 49933cfc1b0SNadav Amit 5007ec3b67aSLike Xu cnt.count = overflow_preset; 501cda64e80SLike Xu if (pmu_use_full_writes()) 502414ee7d1SSean Christopherson cnt.count &= (1ull << pmu.gp_counter_width) - 1; 50333cfc1b0SNadav Amit 504414ee7d1SSean Christopherson if (i == pmu.nr_gp_counters) { 505b883751aSLike Xu if (!pmu.is_intel) 506b883751aSLike Xu break; 507b883751aSLike Xu 508a9f8b16fSGleb Natapov cnt.ctr = fixed_events[0].unit_sel; 5097ec3b67aSLike Xu cnt.count = measure_for_overflow(&cnt); 510cda64e80SLike Xu cnt.count &= (1ull << pmu.gp_counter_width) - 1; 511cda64e80SLike Xu } else { 512cda64e80SLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 51333cfc1b0SNadav Amit } 51433cfc1b0SNadav Amit 515a9f8b16fSGleb Natapov if (i % 2) 516a9f8b16fSGleb Natapov cnt.config |= EVNTSEL_INT; 517a9f8b16fSGleb Natapov else 518a9f8b16fSGleb Natapov cnt.config &= ~EVNTSEL_INT; 519a9f8b16fSGleb Natapov idx = event_to_global_idx(&cnt); 520e9e7577bSLike Xu __measure(&cnt, cnt.count); 521b883751aSLike Xu if (pmu.is_intel) 522a299895bSThomas Huth report(cnt.count == 1, "cntr-%d", i); 523b883751aSLike Xu else 524b883751aSLike Xu report(cnt.count == 0xffffffffffff || cnt.count < 7, "cntr-%d", i); 52562ba5036SLike Xu 52662ba5036SLike Xu if (!this_cpu_has_perf_global_status()) 52762ba5036SLike Xu continue; 52862ba5036SLike Xu 5298a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 530a299895bSThomas Huth report(status & (1ull << idx), "status-%d", i); 5318a2866d1SLike Xu wrmsr(pmu.msr_global_status_clr, status); 5328a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 533a299895bSThomas Huth report(!(status & (1ull << idx)), "status clear-%d", i); 534a299895bSThomas Huth report(check_irq() == (i % 2), "irq-%d", i); 535a9f8b16fSGleb Natapov } 5365bba1769SAndrew Jones 5375bba1769SAndrew Jones report_prefix_pop(); 538a9f8b16fSGleb Natapov } 539a9f8b16fSGleb Natapov 540a9f8b16fSGleb Natapov static void check_gp_counter_cmask(void) 541a9f8b16fSGleb Natapov { 54285c75578SDapeng Mi int instruction_idx = pmu.is_intel ? 54385c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 54485c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 54585c75578SDapeng Mi 546a9f8b16fSGleb Natapov pmu_counter_t cnt = { 547cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 54885c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 54985c75578SDapeng Mi gp_events[instruction_idx].unit_sel /* instructions */, 550a9f8b16fSGleb Natapov }; 551a9f8b16fSGleb Natapov cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT); 5528554261fSLike Xu measure_one(&cnt); 55385c75578SDapeng Mi report(cnt.count < gp_events[instruction_idx].min, "cmask"); 554a9f8b16fSGleb Natapov } 555a9f8b16fSGleb Natapov 556ca1b9de9SNadav Amit static void do_rdpmc_fast(void *ptr) 557ca1b9de9SNadav Amit { 558ca1b9de9SNadav Amit pmu_counter_t *cnt = ptr; 559ca1b9de9SNadav Amit uint32_t idx = (uint32_t)cnt->idx | (1u << 31); 560ca1b9de9SNadav Amit 561ca1b9de9SNadav Amit if (!is_gp(cnt)) 562ca1b9de9SNadav Amit idx |= 1 << 30; 563ca1b9de9SNadav Amit 564ca1b9de9SNadav Amit cnt->count = rdpmc(idx); 565ca1b9de9SNadav Amit } 566ca1b9de9SNadav Amit 567ca1b9de9SNadav Amit 568a9f8b16fSGleb Natapov static void check_rdpmc(void) 569a9f8b16fSGleb Natapov { 57022f2901aSLike Xu uint64_t val = 0xff0123456789ull; 571ca1b9de9SNadav Amit bool exc; 572a9f8b16fSGleb Natapov int i; 573a9f8b16fSGleb Natapov 5745bba1769SAndrew Jones report_prefix_push("rdpmc"); 5755bba1769SAndrew Jones 576414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 57733cfc1b0SNadav Amit uint64_t x; 578ca1b9de9SNadav Amit pmu_counter_t cnt = { 579cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(i), 580ca1b9de9SNadav Amit .idx = i 581ca1b9de9SNadav Amit }; 58233cfc1b0SNadav Amit 58333cfc1b0SNadav Amit /* 58422f2901aSLike Xu * Without full-width writes, only the low 32 bits are writable, 58522f2901aSLike Xu * and the value is sign-extended. 58633cfc1b0SNadav Amit */ 587cda64e80SLike Xu if (pmu.msr_gp_counter_base == MSR_IA32_PERFCTR0) 58833cfc1b0SNadav Amit x = (uint64_t)(int64_t)(int32_t)val; 58922f2901aSLike Xu else 59022f2901aSLike Xu x = (uint64_t)(int64_t)val; 59133cfc1b0SNadav Amit 59233cfc1b0SNadav Amit /* Mask according to the number of supported bits */ 593414ee7d1SSean Christopherson x &= (1ull << pmu.gp_counter_width) - 1; 59433cfc1b0SNadav Amit 595cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(i), val); 596a299895bSThomas Huth report(rdpmc(i) == x, "cntr-%d", i); 597ca1b9de9SNadav Amit 598ca1b9de9SNadav Amit exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 599ca1b9de9SNadav Amit if (exc) 600ca1b9de9SNadav Amit report_skip("fast-%d", i); 601ca1b9de9SNadav Amit else 602a299895bSThomas Huth report(cnt.count == (u32)val, "fast-%d", i); 603a9f8b16fSGleb Natapov } 6049c07c92bSDapeng Mi for (i = 0; i < fixed_counters_num; i++) { 605414ee7d1SSean Christopherson uint64_t x = val & ((1ull << pmu.fixed_counter_width) - 1); 606ca1b9de9SNadav Amit pmu_counter_t cnt = { 607ca1b9de9SNadav Amit .ctr = MSR_CORE_PERF_FIXED_CTR0 + i, 608ca1b9de9SNadav Amit .idx = i 609ca1b9de9SNadav Amit }; 61033cfc1b0SNadav Amit 6113f914933SLike Xu wrmsr(MSR_PERF_FIXED_CTRx(i), x); 612a299895bSThomas Huth report(rdpmc(i | (1 << 30)) == x, "fixed cntr-%d", i); 613ca1b9de9SNadav Amit 614ca1b9de9SNadav Amit exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 615ca1b9de9SNadav Amit if (exc) 616ca1b9de9SNadav Amit report_skip("fixed fast-%d", i); 617ca1b9de9SNadav Amit else 618a299895bSThomas Huth report(cnt.count == (u32)x, "fixed fast-%d", i); 619a9f8b16fSGleb Natapov } 6205bba1769SAndrew Jones 6215bba1769SAndrew Jones report_prefix_pop(); 622a9f8b16fSGleb Natapov } 623a9f8b16fSGleb Natapov 624ddade902SEric Hankland static void check_running_counter_wrmsr(void) 625ddade902SEric Hankland { 62659ca1413SEric Hankland uint64_t status; 62722f2901aSLike Xu uint64_t count; 62885c75578SDapeng Mi unsigned int instruction_idx = pmu.is_intel ? 62985c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 63085c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 63185c75578SDapeng Mi 632ddade902SEric Hankland pmu_counter_t evt = { 633cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 63485c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 63585c75578SDapeng Mi gp_events[instruction_idx].unit_sel, 636ddade902SEric Hankland }; 637ddade902SEric Hankland 63859ca1413SEric Hankland report_prefix_push("running counter wrmsr"); 63959ca1413SEric Hankland 640ddade902SEric Hankland start_event(&evt); 64150f8e27eSDapeng Mi __loop(); 642cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(0), 0); 643ddade902SEric Hankland stop_event(&evt); 64485c75578SDapeng Mi report(evt.count < gp_events[instruction_idx].min, "cntr"); 64559ca1413SEric Hankland 64659ca1413SEric Hankland /* clear status before overflow test */ 64762ba5036SLike Xu if (this_cpu_has_perf_global_status()) 6488a2866d1SLike Xu pmu_clear_global_status(); 64959ca1413SEric Hankland 65059ca1413SEric Hankland start_event(&evt); 65122f2901aSLike Xu 65222f2901aSLike Xu count = -1; 653cda64e80SLike Xu if (pmu_use_full_writes()) 654414ee7d1SSean Christopherson count &= (1ull << pmu.gp_counter_width) - 1; 65522f2901aSLike Xu 656cda64e80SLike Xu wrmsr(MSR_GP_COUNTERx(0), count); 65722f2901aSLike Xu 65850f8e27eSDapeng Mi __loop(); 65959ca1413SEric Hankland stop_event(&evt); 66062ba5036SLike Xu 66162ba5036SLike Xu if (this_cpu_has_perf_global_status()) { 6628a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 6638a2866d1SLike Xu report(status & 1, "status msr bit"); 66462ba5036SLike Xu } 66559ca1413SEric Hankland 66659ca1413SEric Hankland report_prefix_pop(); 667ddade902SEric Hankland } 668ddade902SEric Hankland 66920cf9147SJim Mattson static void check_emulated_instr(void) 67020cf9147SJim Mattson { 67120cf9147SJim Mattson uint64_t status, instr_start, brnch_start; 6728b547cc2SLike Xu uint64_t gp_counter_width = (1ull << pmu.gp_counter_width) - 1; 673f4e97f59SDapeng Mi unsigned int branch_idx = pmu.is_intel ? 674f4e97f59SDapeng Mi INTEL_BRANCHES_IDX : AMD_BRANCHES_IDX; 67585c75578SDapeng Mi unsigned int instruction_idx = pmu.is_intel ? 67685c75578SDapeng Mi INTEL_INSTRUCTIONS_IDX : 67785c75578SDapeng Mi AMD_INSTRUCTIONS_IDX; 67820cf9147SJim Mattson pmu_counter_t brnch_cnt = { 679cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(0), 68020cf9147SJim Mattson /* branch instructions */ 681b883751aSLike Xu .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[branch_idx].unit_sel, 68220cf9147SJim Mattson }; 68320cf9147SJim Mattson pmu_counter_t instr_cnt = { 684cda64e80SLike Xu .ctr = MSR_GP_COUNTERx(1), 68520cf9147SJim Mattson /* instructions */ 68685c75578SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[instruction_idx].unit_sel, 68720cf9147SJim Mattson }; 68820cf9147SJim Mattson report_prefix_push("emulated instruction"); 68920cf9147SJim Mattson 69062ba5036SLike Xu if (this_cpu_has_perf_global_status()) 6918a2866d1SLike Xu pmu_clear_global_status(); 69220cf9147SJim Mattson 69320cf9147SJim Mattson start_event(&brnch_cnt); 69420cf9147SJim Mattson start_event(&instr_cnt); 69520cf9147SJim Mattson 69620cf9147SJim Mattson brnch_start = -EXPECTED_BRNCH; 69720cf9147SJim Mattson instr_start = -EXPECTED_INSTR; 6988b547cc2SLike Xu wrmsr(MSR_GP_COUNTERx(0), brnch_start & gp_counter_width); 6998b547cc2SLike Xu wrmsr(MSR_GP_COUNTERx(1), instr_start & gp_counter_width); 70020cf9147SJim Mattson // KVM_FEP is a magic prefix that forces emulation so 70120cf9147SJim Mattson // 'KVM_FEP "jne label\n"' just counts as a single instruction. 70220cf9147SJim Mattson asm volatile( 70320cf9147SJim Mattson "mov $0x0, %%eax\n" 70420cf9147SJim Mattson "cmp $0x0, %%eax\n" 70520cf9147SJim Mattson KVM_FEP "jne label\n" 70620cf9147SJim Mattson KVM_FEP "jne label\n" 70720cf9147SJim Mattson KVM_FEP "jne label\n" 70820cf9147SJim Mattson KVM_FEP "jne label\n" 70920cf9147SJim Mattson KVM_FEP "jne label\n" 71020cf9147SJim Mattson "mov $0xa, %%eax\n" 71120cf9147SJim Mattson "cpuid\n" 71220cf9147SJim Mattson "mov $0xa, %%eax\n" 71320cf9147SJim Mattson "cpuid\n" 71420cf9147SJim Mattson "mov $0xa, %%eax\n" 71520cf9147SJim Mattson "cpuid\n" 71620cf9147SJim Mattson "mov $0xa, %%eax\n" 71720cf9147SJim Mattson "cpuid\n" 71820cf9147SJim Mattson "mov $0xa, %%eax\n" 71920cf9147SJim Mattson "cpuid\n" 72020cf9147SJim Mattson "label:\n" 72120cf9147SJim Mattson : 72220cf9147SJim Mattson : 72320cf9147SJim Mattson : "eax", "ebx", "ecx", "edx"); 72420cf9147SJim Mattson 72562ba5036SLike Xu if (this_cpu_has_perf_global_ctrl()) 7268a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, 0); 72720cf9147SJim Mattson 72820cf9147SJim Mattson stop_event(&brnch_cnt); 72920cf9147SJim Mattson stop_event(&instr_cnt); 73020cf9147SJim Mattson 73120cf9147SJim Mattson // Check that the end count - start count is at least the expected 73220cf9147SJim Mattson // number of instructions and branches. 73320cf9147SJim Mattson report(instr_cnt.count - instr_start >= EXPECTED_INSTR, 73420cf9147SJim Mattson "instruction count"); 73520cf9147SJim Mattson report(brnch_cnt.count - brnch_start >= EXPECTED_BRNCH, 73620cf9147SJim Mattson "branch count"); 73762ba5036SLike Xu if (this_cpu_has_perf_global_status()) { 73820cf9147SJim Mattson // Additionally check that those counters overflowed properly. 7398a2866d1SLike Xu status = rdmsr(pmu.msr_global_status); 7404070b9c6SLike Xu report(status & 1, "branch counter overflow"); 7414070b9c6SLike Xu report(status & 2, "instruction counter overflow"); 74262ba5036SLike Xu } 74320cf9147SJim Mattson 74420cf9147SJim Mattson report_prefix_pop(); 74520cf9147SJim Mattson } 74620cf9147SJim Mattson 747006b089dSLike Xu #define XBEGIN_STARTED (~0u) 748006b089dSLike Xu static void check_tsx_cycles(void) 749006b089dSLike Xu { 750006b089dSLike Xu pmu_counter_t cnt; 751006b089dSLike Xu unsigned int i, ret = 0; 752006b089dSLike Xu 753006b089dSLike Xu if (!this_cpu_has(X86_FEATURE_RTM)) 754006b089dSLike Xu return; 755006b089dSLike Xu 756006b089dSLike Xu report_prefix_push("TSX cycles"); 757006b089dSLike Xu 758006b089dSLike Xu for (i = 0; i < pmu.nr_gp_counters; i++) { 759006b089dSLike Xu cnt.ctr = MSR_GP_COUNTERx(i); 760006b089dSLike Xu 761006b089dSLike Xu if (i == 2) { 762d4ae0a71SThomas Huth /* Transactional cycles committed only on gp counter 2 */ 763006b089dSLike Xu cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x30000003c; 764006b089dSLike Xu } else { 765006b089dSLike Xu /* Transactional cycles */ 766006b089dSLike Xu cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x10000003c; 767006b089dSLike Xu } 768006b089dSLike Xu 769006b089dSLike Xu start_event(&cnt); 770006b089dSLike Xu 771006b089dSLike Xu asm volatile("xbegin 1f\n\t" 772006b089dSLike Xu "1:\n\t" 773006b089dSLike Xu : "+a" (ret) :: "memory"); 774006b089dSLike Xu 775006b089dSLike Xu /* Generate a non-canonical #GP to trigger ABORT. */ 776006b089dSLike Xu if (ret == XBEGIN_STARTED) 777006b089dSLike Xu *(int *)NONCANONICAL = 0; 778006b089dSLike Xu 779006b089dSLike Xu stop_event(&cnt); 780006b089dSLike Xu 781006b089dSLike Xu report(cnt.count > 0, "gp cntr-%d with a value of %" PRId64 "", i, cnt.count); 782006b089dSLike Xu } 783006b089dSLike Xu 784006b089dSLike Xu report_prefix_pop(); 785006b089dSLike Xu } 786006b089dSLike Xu 787f2a56148SDapeng Mi static void warm_up(void) 788f2a56148SDapeng Mi { 789f2a56148SDapeng Mi int i; 790f2a56148SDapeng Mi 791f2a56148SDapeng Mi /* 792f2a56148SDapeng Mi * Since cycles event is always run as the first event, there would be 793f2a56148SDapeng Mi * a warm-up state to warm up the cache, it leads to the measured cycles 794f2a56148SDapeng Mi * value may exceed the pre-defined cycles upper boundary and cause 795f2a56148SDapeng Mi * false positive. To avoid this, introduce an warm-up state before 796f2a56148SDapeng Mi * the real verification. 797f2a56148SDapeng Mi */ 798f2a56148SDapeng Mi for (i = 0; i < 10; i++) 79950f8e27eSDapeng Mi loop(0); 800f2a56148SDapeng Mi } 801f2a56148SDapeng Mi 80222f2901aSLike Xu static void check_counters(void) 80322f2901aSLike Xu { 80400dca75cSLike Xu if (is_fep_available()) 80500dca75cSLike Xu check_emulated_instr(); 80600dca75cSLike Xu 807f2a56148SDapeng Mi warm_up(); 80822f2901aSLike Xu check_gp_counters(); 80922f2901aSLike Xu check_fixed_counters(); 81022f2901aSLike Xu check_rdpmc(); 81122f2901aSLike Xu check_counters_many(); 81222f2901aSLike Xu check_counter_overflow(); 81322f2901aSLike Xu check_gp_counter_cmask(); 81422f2901aSLike Xu check_running_counter_wrmsr(); 815006b089dSLike Xu check_tsx_cycles(); 81622f2901aSLike Xu } 81722f2901aSLike Xu 81822f2901aSLike Xu static void do_unsupported_width_counter_write(void *index) 81922f2901aSLike Xu { 82022f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + *((int *) index), 0xffffff0123456789ull); 82122f2901aSLike Xu } 82222f2901aSLike Xu 82322f2901aSLike Xu static void check_gp_counters_write_width(void) 82422f2901aSLike Xu { 82522f2901aSLike Xu u64 val_64 = 0xffffff0123456789ull; 8264b74c718SThomas Huth u64 val_32 = val_64 & ((1ull << 32) - 1); 827414ee7d1SSean Christopherson u64 val_max_width = val_64 & ((1ull << pmu.gp_counter_width) - 1); 82822f2901aSLike Xu int i; 82922f2901aSLike Xu 83022f2901aSLike Xu /* 83122f2901aSLike Xu * MSR_IA32_PERFCTRn supports 64-bit writes, 83222f2901aSLike Xu * but only the lowest 32 bits are valid. 83322f2901aSLike Xu */ 834414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 83522f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_32); 83622f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 83722f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 83822f2901aSLike Xu 83922f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_max_width); 84022f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 84122f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 84222f2901aSLike Xu 84322f2901aSLike Xu wrmsr(MSR_IA32_PERFCTR0 + i, val_64); 84422f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 84522f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 84622f2901aSLike Xu } 84722f2901aSLike Xu 84822f2901aSLike Xu /* 8494340720eSLike Xu * MSR_IA32_PMCn supports writing values up to GP counter width, 85022f2901aSLike Xu * and only the lowest bits of GP counter width are valid. 85122f2901aSLike Xu */ 852414ee7d1SSean Christopherson for (i = 0; i < pmu.nr_gp_counters; i++) { 85322f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + i, val_32); 85422f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 85522f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 85622f2901aSLike Xu 85722f2901aSLike Xu wrmsr(MSR_IA32_PMC0 + i, val_max_width); 85822f2901aSLike Xu assert(rdmsr(MSR_IA32_PMC0 + i) == val_max_width); 85922f2901aSLike Xu assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_max_width); 86022f2901aSLike Xu 86122f2901aSLike Xu report(test_for_exception(GP_VECTOR, 86222f2901aSLike Xu do_unsupported_width_counter_write, &i), 86322f2901aSLike Xu "writing unsupported width to MSR_IA32_PMC%d raises #GP", i); 86422f2901aSLike Xu } 86522f2901aSLike Xu } 86622f2901aSLike Xu 867290f4213SJim Mattson /* 868290f4213SJim Mattson * Per the SDM, reference cycles are currently implemented using the 869290f4213SJim Mattson * core crystal clock, TSC, or bus clock. Calibrate to the TSC 870290f4213SJim Mattson * frequency to set reasonable expectations. 871290f4213SJim Mattson */ 872290f4213SJim Mattson static void set_ref_cycle_expectations(void) 873290f4213SJim Mattson { 874290f4213SJim Mattson pmu_counter_t cnt = { 875290f4213SJim Mattson .ctr = MSR_IA32_PERFCTR0, 87625cc1ea7SDapeng Mi .config = EVNTSEL_OS | EVNTSEL_USR | 87725cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].unit_sel, 878290f4213SJim Mattson }; 879290f4213SJim Mattson uint64_t tsc_delta; 880290f4213SJim Mattson uint64_t t0, t1, t2, t3; 881290f4213SJim Mattson 8822719b92cSYang Weijiang /* Bit 2 enumerates the availability of reference cycles events. */ 883414ee7d1SSean Christopherson if (!pmu.nr_gp_counters || !pmu_gp_counter_is_available(2)) 884290f4213SJim Mattson return; 885290f4213SJim Mattson 88662ba5036SLike Xu if (this_cpu_has_perf_global_ctrl()) 8878a2866d1SLike Xu wrmsr(pmu.msr_global_ctl, 0); 888290f4213SJim Mattson 889290f4213SJim Mattson t0 = fenced_rdtsc(); 890290f4213SJim Mattson start_event(&cnt); 891290f4213SJim Mattson t1 = fenced_rdtsc(); 892290f4213SJim Mattson 893290f4213SJim Mattson /* 894290f4213SJim Mattson * This loop has to run long enough to dominate the VM-exit 895290f4213SJim Mattson * costs for playing with the PMU MSRs on start and stop. 896290f4213SJim Mattson * 897290f4213SJim Mattson * On a 2.6GHz Ice Lake, with the TSC frequency at 104 times 898290f4213SJim Mattson * the core crystal clock, this function calculated a guest 899290f4213SJim Mattson * TSC : ref cycles ratio of around 105 with ECX initialized 900290f4213SJim Mattson * to one billion. 901290f4213SJim Mattson */ 902290f4213SJim Mattson asm volatile("loop ." : "+c"((int){1000000000ull})); 903290f4213SJim Mattson 904290f4213SJim Mattson t2 = fenced_rdtsc(); 905290f4213SJim Mattson stop_event(&cnt); 906290f4213SJim Mattson t3 = fenced_rdtsc(); 907290f4213SJim Mattson 908290f4213SJim Mattson tsc_delta = ((t2 - t1) + (t3 - t0)) / 2; 909290f4213SJim Mattson 910290f4213SJim Mattson if (!tsc_delta) 911290f4213SJim Mattson return; 912290f4213SJim Mattson 91325cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].min = 91425cc1ea7SDapeng Mi (intel_gp_events[INTEL_REF_CYCLES_IDX].min * cnt.count) / tsc_delta; 91525cc1ea7SDapeng Mi intel_gp_events[INTEL_REF_CYCLES_IDX].max = 91625cc1ea7SDapeng Mi (intel_gp_events[INTEL_REF_CYCLES_IDX].max * cnt.count) / tsc_delta; 917290f4213SJim Mattson } 918290f4213SJim Mattson 91985c21181SLike Xu static void check_invalid_rdpmc_gp(void) 92085c21181SLike Xu { 92185c21181SLike Xu uint64_t val; 92285c21181SLike Xu 92385c21181SLike Xu report(rdpmc_safe(64, &val) == GP_VECTOR, 92485c21181SLike Xu "Expected #GP on RDPMC(64)"); 92585c21181SLike Xu } 92685c21181SLike Xu 927a9f8b16fSGleb Natapov int main(int ac, char **av) 928a9f8b16fSGleb Natapov { 92989126fa4SDapeng Mi int instruction_idx; 93089126fa4SDapeng Mi int branch_idx; 931*28437cdbSDapeng Mi int branch_miss_idx; 93289126fa4SDapeng Mi 933a9f8b16fSGleb Natapov setup_vm(); 9345a2cb3e6SLike Xu handle_irq(PMI_VECTOR, cnt_overflow); 935dcda215bSPaolo Bonzini buf = malloc(N*64); 936a9f8b16fSGleb Natapov 93785c21181SLike Xu check_invalid_rdpmc_gp(); 93885c21181SLike Xu 939b883751aSLike Xu if (pmu.is_intel) { 940414ee7d1SSean Christopherson if (!pmu.version) { 94103041e97SLike Xu report_skip("No Intel Arch PMU is detected!"); 94232b9603cSRadim Krčmář return report_summary(); 943a9f8b16fSGleb Natapov } 9447c648ce2SLike Xu gp_events = (struct pmu_event *)intel_gp_events; 9457c648ce2SLike Xu gp_events_size = sizeof(intel_gp_events)/sizeof(intel_gp_events[0]); 94689126fa4SDapeng Mi instruction_idx = INTEL_INSTRUCTIONS_IDX; 94789126fa4SDapeng Mi branch_idx = INTEL_BRANCHES_IDX; 948*28437cdbSDapeng Mi branch_miss_idx = INTEL_BRANCH_MISS_IDX; 949e0d0022fSDapeng Mi 950e0d0022fSDapeng Mi /* 951e0d0022fSDapeng Mi * For legacy Intel CPUS without clflush/clflushopt support, 952e0d0022fSDapeng Mi * there is no way to force to trigger a LLC miss, thus set 953e0d0022fSDapeng Mi * the minimum value to 0 to avoid false positives. 954e0d0022fSDapeng Mi */ 955e0d0022fSDapeng Mi if (!this_cpu_has(X86_FEATURE_CLFLUSH)) 956e0d0022fSDapeng Mi gp_events[INTEL_LLC_MISSES_IDX].min = 0; 957e0d0022fSDapeng Mi 958b883751aSLike Xu report_prefix_push("Intel"); 959290f4213SJim Mattson set_ref_cycle_expectations(); 960b883751aSLike Xu } else { 961b883751aSLike Xu gp_events_size = sizeof(amd_gp_events)/sizeof(amd_gp_events[0]); 962b883751aSLike Xu gp_events = (struct pmu_event *)amd_gp_events; 96389126fa4SDapeng Mi instruction_idx = AMD_INSTRUCTIONS_IDX; 96489126fa4SDapeng Mi branch_idx = AMD_BRANCHES_IDX; 965*28437cdbSDapeng Mi branch_miss_idx = AMD_BRANCH_MISS_IDX; 966b883751aSLike Xu report_prefix_push("AMD"); 967b883751aSLike Xu } 968*28437cdbSDapeng Mi adjust_events_range(gp_events, instruction_idx, branch_idx, branch_miss_idx); 969290f4213SJim Mattson 970414ee7d1SSean Christopherson printf("PMU version: %d\n", pmu.version); 971414ee7d1SSean Christopherson printf("GP counters: %d\n", pmu.nr_gp_counters); 972414ee7d1SSean Christopherson printf("GP counter width: %d\n", pmu.gp_counter_width); 973414ee7d1SSean Christopherson printf("Mask length: %d\n", pmu.gp_counter_mask_length); 974414ee7d1SSean Christopherson printf("Fixed counters: %d\n", pmu.nr_fixed_counters); 975414ee7d1SSean Christopherson printf("Fixed counter width: %d\n", pmu.fixed_counter_width); 9760ef1f6a8SPaolo Bonzini 9779c07c92bSDapeng Mi fixed_counters_num = MIN(pmu.nr_fixed_counters, ARRAY_SIZE(fixed_events)); 9789c07c92bSDapeng Mi if (pmu.nr_fixed_counters > ARRAY_SIZE(fixed_events)) 9799c07c92bSDapeng Mi report_info("Fixed counters number %d > defined fixed events %u. " 9809c07c92bSDapeng Mi "Please update test case.", pmu.nr_fixed_counters, 9819c07c92bSDapeng Mi (uint32_t)ARRAY_SIZE(fixed_events)); 9829c07c92bSDapeng Mi 9835a2cb3e6SLike Xu apic_write(APIC_LVTPC, PMI_VECTOR); 984a9f8b16fSGleb Natapov 985afa714b2SPaolo Bonzini check_counters(); 98620cf9147SJim Mattson 987879e7f07SLike Xu if (pmu_has_full_writes()) { 988cda64e80SLike Xu pmu.msr_gp_counter_base = MSR_IA32_PMC0; 989cda64e80SLike Xu 99022f2901aSLike Xu report_prefix_push("full-width writes"); 99122f2901aSLike Xu check_counters(); 99222f2901aSLike Xu check_gp_counters_write_width(); 993d7714e16SLike Xu report_prefix_pop(); 99422f2901aSLike Xu } 995a9f8b16fSGleb Natapov 996b883751aSLike Xu if (!pmu.is_intel) { 997b883751aSLike Xu report_prefix_push("K7"); 998b883751aSLike Xu pmu.nr_gp_counters = AMD64_NUM_COUNTERS; 999b883751aSLike Xu pmu.msr_gp_counter_base = MSR_K7_PERFCTR0; 1000b883751aSLike Xu pmu.msr_gp_event_select_base = MSR_K7_EVNTSEL0; 1001b883751aSLike Xu check_counters(); 1002b883751aSLike Xu report_prefix_pop(); 1003b883751aSLike Xu } 1004b883751aSLike Xu 1005f3cdd159SJan Kiszka return report_summary(); 1006a9f8b16fSGleb Natapov } 1007