1 2 #include "x86/msr.h" 3 #include "x86/processor.h" 4 #include "x86/apic-defs.h" 5 #include "x86/apic.h" 6 #include "x86/desc.h" 7 #include "x86/isr.h" 8 #include "alloc.h" 9 10 #include "libcflat.h" 11 #include <stdint.h> 12 13 #define FIXED_CNT_INDEX 32 14 15 /* Performance Counter Vector for the LVT PC Register */ 16 #define PMI_VECTOR 32 17 18 #define EVNSEL_EVENT_SHIFT 0 19 #define EVNTSEL_UMASK_SHIFT 8 20 #define EVNTSEL_USR_SHIFT 16 21 #define EVNTSEL_OS_SHIFT 17 22 #define EVNTSEL_EDGE_SHIFT 18 23 #define EVNTSEL_PC_SHIFT 19 24 #define EVNTSEL_INT_SHIFT 20 25 #define EVNTSEL_EN_SHIF 22 26 #define EVNTSEL_INV_SHIF 23 27 #define EVNTSEL_CMASK_SHIFT 24 28 29 #define EVNTSEL_EN (1 << EVNTSEL_EN_SHIF) 30 #define EVNTSEL_USR (1 << EVNTSEL_USR_SHIFT) 31 #define EVNTSEL_OS (1 << EVNTSEL_OS_SHIFT) 32 #define EVNTSEL_PC (1 << EVNTSEL_PC_SHIFT) 33 #define EVNTSEL_INT (1 << EVNTSEL_INT_SHIFT) 34 #define EVNTSEL_INV (1 << EVNTSEL_INV_SHIF) 35 36 #define N 1000000 37 38 // These values match the number of instructions and branches in the 39 // assembly block in check_emulated_instr(). 40 #define EXPECTED_INSTR 17 41 #define EXPECTED_BRNCH 5 42 43 typedef struct { 44 uint32_t ctr; 45 uint32_t config; 46 uint64_t count; 47 int idx; 48 } pmu_counter_t; 49 50 struct pmu_event { 51 const char *name; 52 uint32_t unit_sel; 53 int min; 54 int max; 55 } gp_events[] = { 56 {"core cycles", 0x003c, 1*N, 50*N}, 57 {"instructions", 0x00c0, 10*N, 10.2*N}, 58 {"ref cycles", 0x013c, 1*N, 30*N}, 59 {"llc references", 0x4f2e, 1, 2*N}, 60 {"llc misses", 0x412e, 1, 1*N}, 61 {"branches", 0x00c4, 1*N, 1.1*N}, 62 {"branch misses", 0x00c5, 0, 0.1*N}, 63 }, fixed_events[] = { 64 {"fixed 1", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N}, 65 {"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N}, 66 {"fixed 3", MSR_CORE_PERF_FIXED_CTR0 + 2, 0.1*N, 30*N} 67 }; 68 69 #define PMU_CAP_FW_WRITES (1ULL << 13) 70 static u64 gp_counter_base = MSR_IA32_PERFCTR0; 71 72 char *buf; 73 74 static inline void loop(void) 75 { 76 unsigned long tmp, tmp2, tmp3; 77 78 asm volatile("1: mov (%1), %2; add $64, %1; nop; nop; nop; nop; nop; nop; nop; loop 1b" 79 : "=c"(tmp), "=r"(tmp2), "=r"(tmp3): "0"(N), "1"(buf)); 80 81 } 82 83 volatile uint64_t irq_received; 84 85 static void cnt_overflow(isr_regs_t *regs) 86 { 87 irq_received++; 88 apic_write(APIC_EOI, 0); 89 } 90 91 static bool check_irq(void) 92 { 93 int i; 94 irq_received = 0; 95 irq_enable(); 96 for (i = 0; i < 100000 && !irq_received; i++) 97 asm volatile("pause"); 98 irq_disable(); 99 return irq_received; 100 } 101 102 static bool is_gp(pmu_counter_t *evt) 103 { 104 return evt->ctr < MSR_CORE_PERF_FIXED_CTR0 || 105 evt->ctr >= MSR_IA32_PMC0; 106 } 107 108 static int event_to_global_idx(pmu_counter_t *cnt) 109 { 110 return cnt->ctr - (is_gp(cnt) ? gp_counter_base : 111 (MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX)); 112 } 113 114 static struct pmu_event* get_counter_event(pmu_counter_t *cnt) 115 { 116 if (is_gp(cnt)) { 117 int i; 118 119 for (i = 0; i < sizeof(gp_events)/sizeof(gp_events[0]); i++) 120 if (gp_events[i].unit_sel == (cnt->config & 0xffff)) 121 return &gp_events[i]; 122 } else 123 return &fixed_events[cnt->ctr - MSR_CORE_PERF_FIXED_CTR0]; 124 125 return (void*)0; 126 } 127 128 static void global_enable(pmu_counter_t *cnt) 129 { 130 cnt->idx = event_to_global_idx(cnt); 131 132 wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_CTRL) | 133 (1ull << cnt->idx)); 134 } 135 136 static void global_disable(pmu_counter_t *cnt) 137 { 138 wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_CTRL) & 139 ~(1ull << cnt->idx)); 140 } 141 142 static void __start_event(pmu_counter_t *evt, uint64_t count) 143 { 144 evt->count = count; 145 wrmsr(evt->ctr, evt->count); 146 if (is_gp(evt)) 147 wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt), 148 evt->config | EVNTSEL_EN); 149 else { 150 uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 151 int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 152 uint32_t usrospmi = 0; 153 154 if (evt->config & EVNTSEL_OS) 155 usrospmi |= (1 << 0); 156 if (evt->config & EVNTSEL_USR) 157 usrospmi |= (1 << 1); 158 if (evt->config & EVNTSEL_INT) 159 usrospmi |= (1 << 3); // PMI on overflow 160 ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift); 161 wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl); 162 } 163 global_enable(evt); 164 apic_write(APIC_LVTPC, PMI_VECTOR); 165 } 166 167 static void start_event(pmu_counter_t *evt) 168 { 169 __start_event(evt, 0); 170 } 171 172 static void stop_event(pmu_counter_t *evt) 173 { 174 global_disable(evt); 175 if (is_gp(evt)) 176 wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt), 177 evt->config & ~EVNTSEL_EN); 178 else { 179 uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL); 180 int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4; 181 wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift)); 182 } 183 evt->count = rdmsr(evt->ctr); 184 } 185 186 static noinline void measure_many(pmu_counter_t *evt, int count) 187 { 188 int i; 189 for (i = 0; i < count; i++) 190 start_event(&evt[i]); 191 loop(); 192 for (i = 0; i < count; i++) 193 stop_event(&evt[i]); 194 } 195 196 static void measure_one(pmu_counter_t *evt) 197 { 198 measure_many(evt, 1); 199 } 200 201 static noinline void __measure(pmu_counter_t *evt, uint64_t count) 202 { 203 __start_event(evt, count); 204 loop(); 205 stop_event(evt); 206 } 207 208 static bool verify_event(uint64_t count, struct pmu_event *e) 209 { 210 // printf("%d <= %ld <= %d\n", e->min, count, e->max); 211 return count >= e->min && count <= e->max; 212 213 } 214 215 static bool verify_counter(pmu_counter_t *cnt) 216 { 217 return verify_event(cnt->count, get_counter_event(cnt)); 218 } 219 220 static void check_gp_counter(struct pmu_event *evt) 221 { 222 int nr_gp_counters = pmu_nr_gp_counters(); 223 pmu_counter_t cnt = { 224 .ctr = gp_counter_base, 225 .config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel, 226 }; 227 int i; 228 229 for (i = 0; i < nr_gp_counters; i++, cnt.ctr++) { 230 measure_one(&cnt); 231 report(verify_event(cnt.count, evt), "%s-%d", evt->name, i); 232 } 233 } 234 235 static void check_gp_counters(void) 236 { 237 int i; 238 239 for (i = 0; i < sizeof(gp_events)/sizeof(gp_events[0]); i++) 240 if (pmu_gp_counter_is_available(i)) 241 check_gp_counter(&gp_events[i]); 242 else 243 printf("GP event '%s' is disabled\n", 244 gp_events[i].name); 245 } 246 247 static void check_fixed_counters(void) 248 { 249 int nr_fixed_counters = pmu_nr_fixed_counters(); 250 pmu_counter_t cnt = { 251 .config = EVNTSEL_OS | EVNTSEL_USR, 252 }; 253 int i; 254 255 for (i = 0; i < nr_fixed_counters; i++) { 256 cnt.ctr = fixed_events[i].unit_sel; 257 measure_one(&cnt); 258 report(verify_event(cnt.count, &fixed_events[i]), "fixed-%d", i); 259 } 260 } 261 262 static void check_counters_many(void) 263 { 264 int nr_fixed_counters = pmu_nr_fixed_counters(); 265 int nr_gp_counters = pmu_nr_gp_counters(); 266 pmu_counter_t cnt[10]; 267 int i, n; 268 269 for (i = 0, n = 0; n < nr_gp_counters; i++) { 270 if (!pmu_gp_counter_is_available(i)) 271 continue; 272 273 cnt[n].ctr = gp_counter_base + n; 274 cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | 275 gp_events[i % ARRAY_SIZE(gp_events)].unit_sel; 276 n++; 277 } 278 for (i = 0; i < nr_fixed_counters; i++) { 279 cnt[n].ctr = fixed_events[i].unit_sel; 280 cnt[n].config = EVNTSEL_OS | EVNTSEL_USR; 281 n++; 282 } 283 284 measure_many(cnt, n); 285 286 for (i = 0; i < n; i++) 287 if (!verify_counter(&cnt[i])) 288 break; 289 290 report(i == n, "all counters"); 291 } 292 293 static uint64_t measure_for_overflow(pmu_counter_t *cnt) 294 { 295 __measure(cnt, 0); 296 /* 297 * To generate overflow, i.e. roll over to '0', the initial count just 298 * needs to be preset to the negative expected count. However, as per 299 * Intel's SDM, the preset count needs to be incremented by 1 to ensure 300 * the overflow interrupt is generated immediately instead of possibly 301 * waiting for the overflow to propagate through the counter. 302 */ 303 assert(cnt->count > 1); 304 return 1 - cnt->count; 305 } 306 307 static void check_counter_overflow(void) 308 { 309 int nr_gp_counters = pmu_nr_gp_counters(); 310 uint64_t overflow_preset; 311 int i; 312 pmu_counter_t cnt = { 313 .ctr = gp_counter_base, 314 .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */, 315 }; 316 overflow_preset = measure_for_overflow(&cnt); 317 318 /* clear status before test */ 319 wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_STATUS)); 320 321 report_prefix_push("overflow"); 322 323 for (i = 0; i < nr_gp_counters + 1; i++, cnt.ctr++) { 324 uint64_t status; 325 int idx; 326 327 cnt.count = overflow_preset; 328 if (gp_counter_base == MSR_IA32_PMC0) 329 cnt.count &= (1ull << pmu_gp_counter_width()) - 1; 330 331 if (i == nr_gp_counters) { 332 cnt.ctr = fixed_events[0].unit_sel; 333 cnt.count = measure_for_overflow(&cnt); 334 cnt.count &= (1ull << pmu_fixed_counter_width()) - 1; 335 } 336 337 if (i % 2) 338 cnt.config |= EVNTSEL_INT; 339 else 340 cnt.config &= ~EVNTSEL_INT; 341 idx = event_to_global_idx(&cnt); 342 __measure(&cnt, cnt.count); 343 report(cnt.count == 1, "cntr-%d", i); 344 status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); 345 report(status & (1ull << idx), "status-%d", i); 346 wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, status); 347 status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); 348 report(!(status & (1ull << idx)), "status clear-%d", i); 349 report(check_irq() == (i % 2), "irq-%d", i); 350 } 351 352 report_prefix_pop(); 353 } 354 355 static void check_gp_counter_cmask(void) 356 { 357 pmu_counter_t cnt = { 358 .ctr = gp_counter_base, 359 .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */, 360 }; 361 cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT); 362 measure_one(&cnt); 363 report(cnt.count < gp_events[1].min, "cmask"); 364 } 365 366 static void do_rdpmc_fast(void *ptr) 367 { 368 pmu_counter_t *cnt = ptr; 369 uint32_t idx = (uint32_t)cnt->idx | (1u << 31); 370 371 if (!is_gp(cnt)) 372 idx |= 1 << 30; 373 374 cnt->count = rdpmc(idx); 375 } 376 377 378 static void check_rdpmc(void) 379 { 380 int fixed_counter_width = pmu_fixed_counter_width(); 381 int nr_fixed_counters = pmu_nr_fixed_counters(); 382 u8 gp_counter_width = pmu_gp_counter_width(); 383 int nr_gp_counters = pmu_nr_gp_counters(); 384 uint64_t val = 0xff0123456789ull; 385 bool exc; 386 int i; 387 388 report_prefix_push("rdpmc"); 389 390 for (i = 0; i < nr_gp_counters; i++) { 391 uint64_t x; 392 pmu_counter_t cnt = { 393 .ctr = gp_counter_base + i, 394 .idx = i 395 }; 396 397 /* 398 * Without full-width writes, only the low 32 bits are writable, 399 * and the value is sign-extended. 400 */ 401 if (gp_counter_base == MSR_IA32_PERFCTR0) 402 x = (uint64_t)(int64_t)(int32_t)val; 403 else 404 x = (uint64_t)(int64_t)val; 405 406 /* Mask according to the number of supported bits */ 407 x &= (1ull << gp_counter_width) - 1; 408 409 wrmsr(gp_counter_base + i, val); 410 report(rdpmc(i) == x, "cntr-%d", i); 411 412 exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 413 if (exc) 414 report_skip("fast-%d", i); 415 else 416 report(cnt.count == (u32)val, "fast-%d", i); 417 } 418 for (i = 0; i < nr_fixed_counters; i++) { 419 uint64_t x = val & ((1ull << fixed_counter_width) - 1); 420 pmu_counter_t cnt = { 421 .ctr = MSR_CORE_PERF_FIXED_CTR0 + i, 422 .idx = i 423 }; 424 425 wrmsr(MSR_CORE_PERF_FIXED_CTR0 + i, x); 426 report(rdpmc(i | (1 << 30)) == x, "fixed cntr-%d", i); 427 428 exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt); 429 if (exc) 430 report_skip("fixed fast-%d", i); 431 else 432 report(cnt.count == (u32)x, "fixed fast-%d", i); 433 } 434 435 report_prefix_pop(); 436 } 437 438 static void check_running_counter_wrmsr(void) 439 { 440 uint64_t status; 441 uint64_t count; 442 pmu_counter_t evt = { 443 .ctr = gp_counter_base, 444 .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel, 445 }; 446 447 report_prefix_push("running counter wrmsr"); 448 449 start_event(&evt); 450 loop(); 451 wrmsr(gp_counter_base, 0); 452 stop_event(&evt); 453 report(evt.count < gp_events[1].min, "cntr"); 454 455 /* clear status before overflow test */ 456 wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, 457 rdmsr(MSR_CORE_PERF_GLOBAL_STATUS)); 458 459 start_event(&evt); 460 461 count = -1; 462 if (gp_counter_base == MSR_IA32_PMC0) 463 count &= (1ull << pmu_gp_counter_width()) - 1; 464 465 wrmsr(gp_counter_base, count); 466 467 loop(); 468 stop_event(&evt); 469 status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); 470 report(status & 1, "status"); 471 472 report_prefix_pop(); 473 } 474 475 static void check_emulated_instr(void) 476 { 477 uint64_t status, instr_start, brnch_start; 478 pmu_counter_t brnch_cnt = { 479 .ctr = MSR_IA32_PERFCTR0, 480 /* branch instructions */ 481 .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[5].unit_sel, 482 }; 483 pmu_counter_t instr_cnt = { 484 .ctr = MSR_IA32_PERFCTR0 + 1, 485 /* instructions */ 486 .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel, 487 }; 488 report_prefix_push("emulated instruction"); 489 490 wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, 491 rdmsr(MSR_CORE_PERF_GLOBAL_STATUS)); 492 493 start_event(&brnch_cnt); 494 start_event(&instr_cnt); 495 496 brnch_start = -EXPECTED_BRNCH; 497 instr_start = -EXPECTED_INSTR; 498 wrmsr(MSR_IA32_PERFCTR0, brnch_start); 499 wrmsr(MSR_IA32_PERFCTR0 + 1, instr_start); 500 // KVM_FEP is a magic prefix that forces emulation so 501 // 'KVM_FEP "jne label\n"' just counts as a single instruction. 502 asm volatile( 503 "mov $0x0, %%eax\n" 504 "cmp $0x0, %%eax\n" 505 KVM_FEP "jne label\n" 506 KVM_FEP "jne label\n" 507 KVM_FEP "jne label\n" 508 KVM_FEP "jne label\n" 509 KVM_FEP "jne label\n" 510 "mov $0xa, %%eax\n" 511 "cpuid\n" 512 "mov $0xa, %%eax\n" 513 "cpuid\n" 514 "mov $0xa, %%eax\n" 515 "cpuid\n" 516 "mov $0xa, %%eax\n" 517 "cpuid\n" 518 "mov $0xa, %%eax\n" 519 "cpuid\n" 520 "label:\n" 521 : 522 : 523 : "eax", "ebx", "ecx", "edx"); 524 525 wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); 526 527 stop_event(&brnch_cnt); 528 stop_event(&instr_cnt); 529 530 // Check that the end count - start count is at least the expected 531 // number of instructions and branches. 532 report(instr_cnt.count - instr_start >= EXPECTED_INSTR, 533 "instruction count"); 534 report(brnch_cnt.count - brnch_start >= EXPECTED_BRNCH, 535 "branch count"); 536 // Additionally check that those counters overflowed properly. 537 status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS); 538 report(status & 1, "branch counter overflow"); 539 report(status & 2, "instruction counter overflow"); 540 541 report_prefix_pop(); 542 } 543 544 static void check_counters(void) 545 { 546 if (is_fep_available()) 547 check_emulated_instr(); 548 549 check_gp_counters(); 550 check_fixed_counters(); 551 check_rdpmc(); 552 check_counters_many(); 553 check_counter_overflow(); 554 check_gp_counter_cmask(); 555 check_running_counter_wrmsr(); 556 } 557 558 static void do_unsupported_width_counter_write(void *index) 559 { 560 wrmsr(MSR_IA32_PMC0 + *((int *) index), 0xffffff0123456789ull); 561 } 562 563 static void check_gp_counters_write_width(void) 564 { 565 u64 val_64 = 0xffffff0123456789ull; 566 u64 val_32 = val_64 & ((1ull << 32) - 1); 567 u64 val_max_width = val_64 & ((1ull << pmu_gp_counter_width()) - 1); 568 int nr_gp_counters = pmu_nr_gp_counters(); 569 int i; 570 571 /* 572 * MSR_IA32_PERFCTRn supports 64-bit writes, 573 * but only the lowest 32 bits are valid. 574 */ 575 for (i = 0; i < nr_gp_counters; i++) { 576 wrmsr(MSR_IA32_PERFCTR0 + i, val_32); 577 assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 578 assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 579 580 wrmsr(MSR_IA32_PERFCTR0 + i, val_max_width); 581 assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 582 assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 583 584 wrmsr(MSR_IA32_PERFCTR0 + i, val_64); 585 assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 586 assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 587 } 588 589 /* 590 * MSR_IA32_PMCn supports writing values up to GP counter width, 591 * and only the lowest bits of GP counter width are valid. 592 */ 593 for (i = 0; i < nr_gp_counters; i++) { 594 wrmsr(MSR_IA32_PMC0 + i, val_32); 595 assert(rdmsr(MSR_IA32_PMC0 + i) == val_32); 596 assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32); 597 598 wrmsr(MSR_IA32_PMC0 + i, val_max_width); 599 assert(rdmsr(MSR_IA32_PMC0 + i) == val_max_width); 600 assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_max_width); 601 602 report(test_for_exception(GP_VECTOR, 603 do_unsupported_width_counter_write, &i), 604 "writing unsupported width to MSR_IA32_PMC%d raises #GP", i); 605 } 606 } 607 608 /* 609 * Per the SDM, reference cycles are currently implemented using the 610 * core crystal clock, TSC, or bus clock. Calibrate to the TSC 611 * frequency to set reasonable expectations. 612 */ 613 static void set_ref_cycle_expectations(void) 614 { 615 pmu_counter_t cnt = { 616 .ctr = MSR_IA32_PERFCTR0, 617 .config = EVNTSEL_OS | EVNTSEL_USR | gp_events[2].unit_sel, 618 }; 619 uint64_t tsc_delta; 620 uint64_t t0, t1, t2, t3; 621 622 /* Bit 2 enumerates the availability of reference cycles events. */ 623 if (!pmu_nr_gp_counters() || !pmu_gp_counter_is_available(2)) 624 return; 625 626 wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0); 627 628 t0 = fenced_rdtsc(); 629 start_event(&cnt); 630 t1 = fenced_rdtsc(); 631 632 /* 633 * This loop has to run long enough to dominate the VM-exit 634 * costs for playing with the PMU MSRs on start and stop. 635 * 636 * On a 2.6GHz Ice Lake, with the TSC frequency at 104 times 637 * the core crystal clock, this function calculated a guest 638 * TSC : ref cycles ratio of around 105 with ECX initialized 639 * to one billion. 640 */ 641 asm volatile("loop ." : "+c"((int){1000000000ull})); 642 643 t2 = fenced_rdtsc(); 644 stop_event(&cnt); 645 t3 = fenced_rdtsc(); 646 647 tsc_delta = ((t2 - t1) + (t3 - t0)) / 2; 648 649 if (!tsc_delta) 650 return; 651 652 gp_events[2].min = (gp_events[2].min * cnt.count) / tsc_delta; 653 gp_events[2].max = (gp_events[2].max * cnt.count) / tsc_delta; 654 } 655 656 static void check_invalid_rdpmc_gp(void) 657 { 658 uint64_t val; 659 660 report(rdpmc_safe(64, &val) == GP_VECTOR, 661 "Expected #GP on RDPMC(64)"); 662 } 663 664 int main(int ac, char **av) 665 { 666 setup_vm(); 667 handle_irq(PMI_VECTOR, cnt_overflow); 668 buf = malloc(N*64); 669 670 check_invalid_rdpmc_gp(); 671 672 if (!pmu_version()) { 673 report_skip("No Intel Arch PMU is detected!"); 674 return report_summary(); 675 } 676 677 if (pmu_version() == 1) { 678 report_skip("PMU version 1 is not supported."); 679 return report_summary(); 680 } 681 682 set_ref_cycle_expectations(); 683 684 printf("PMU version: %d\n", pmu_version()); 685 printf("GP counters: %d\n", pmu_nr_gp_counters()); 686 printf("GP counter width: %d\n", pmu_gp_counter_width()); 687 printf("Mask length: %d\n", pmu_gp_counter_mask_length()); 688 printf("Fixed counters: %d\n", pmu_nr_fixed_counters()); 689 printf("Fixed counter width: %d\n", pmu_fixed_counter_width()); 690 691 apic_write(APIC_LVTPC, PMI_VECTOR); 692 693 check_counters(); 694 695 if (this_cpu_perf_capabilities() & PMU_CAP_FW_WRITES) { 696 gp_counter_base = MSR_IA32_PMC0; 697 report_prefix_push("full-width writes"); 698 check_counters(); 699 check_gp_counters_write_width(); 700 report_prefix_pop(); 701 } 702 703 return report_summary(); 704 } 705