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