@@ -404,6 +404,331 @@ static bool use_amd_pmu(void)
404
404
is_zen3 (family , model ));
405
405
}
406
406
407
+ /*
408
+ * "MEM_INST_RETIRED.ALL_LOADS", "MEM_INST_RETIRED.ALL_STORES", and
409
+ * "MEM_INST_RETIRED.ANY" from https://perfmon-events.intel.com/
410
+ * supported on Intel Xeon processors:
411
+ * - Sapphire Rapids, Ice Lake, Cascade Lake, Skylake.
412
+ */
413
+ #define MEM_INST_RETIRED 0xD0
414
+ #define MEM_INST_RETIRED_LOAD EVENT(MEM_INST_RETIRED, 0x81)
415
+ #define MEM_INST_RETIRED_STORE EVENT(MEM_INST_RETIRED, 0x82)
416
+ #define MEM_INST_RETIRED_LOAD_STORE EVENT(MEM_INST_RETIRED, 0x83)
417
+
418
+ static bool supports_event_mem_inst_retired (void )
419
+ {
420
+ uint32_t eax , ebx , ecx , edx ;
421
+
422
+ cpuid (1 , & eax , & ebx , & ecx , & edx );
423
+ if (x86_family (eax ) == 0x6 ) {
424
+ switch (x86_model (eax )) {
425
+ /* Sapphire Rapids */
426
+ case 0x8F :
427
+ /* Ice Lake */
428
+ case 0x6A :
429
+ /* Skylake */
430
+ /* Cascade Lake */
431
+ case 0x55 :
432
+ return true;
433
+ }
434
+ }
435
+
436
+ return false;
437
+ }
438
+
439
+ /*
440
+ * "LS Dispatch", from Processor Programming Reference
441
+ * (PPR) for AMD Family 17h Model 01h, Revision B1 Processors,
442
+ * Preliminary Processor Programming Reference (PPR) for AMD Family
443
+ * 17h Model 31h, Revision B0 Processors, and Preliminary Processor
444
+ * Programming Reference (PPR) for AMD Family 19h Model 01h, Revision
445
+ * B1 Processors Volume 1 of 2.
446
+ */
447
+ #define LS_DISPATCH 0x29
448
+ #define LS_DISPATCH_LOAD EVENT(LS_DISPATCH, BIT(0))
449
+ #define LS_DISPATCH_STORE EVENT(LS_DISPATCH, BIT(1))
450
+ #define LS_DISPATCH_LOAD_STORE EVENT(LS_DISPATCH, BIT(2))
451
+
452
+ #define INCLUDE_MASKED_ENTRY (event_select , mask , match ) \
453
+ KVM_PMU_ENCODE_MASKED_ENTRY(event_select, mask, match, false)
454
+ #define EXCLUDE_MASKED_ENTRY (event_select , mask , match ) \
455
+ KVM_PMU_ENCODE_MASKED_ENTRY(event_select, mask, match, true)
456
+
457
+ struct perf_counter {
458
+ union {
459
+ uint64_t raw ;
460
+ struct {
461
+ uint64_t loads :22 ;
462
+ uint64_t stores :22 ;
463
+ uint64_t loads_stores :20 ;
464
+ };
465
+ };
466
+ };
467
+
468
+ static uint64_t masked_events_guest_test (uint32_t msr_base )
469
+ {
470
+ uint64_t ld0 , ld1 , st0 , st1 , ls0 , ls1 ;
471
+ struct perf_counter c ;
472
+ int val ;
473
+
474
+ /*
475
+ * The acutal value of the counters don't determine the outcome of
476
+ * the test. Only that they are zero or non-zero.
477
+ */
478
+ ld0 = rdmsr (msr_base + 0 );
479
+ st0 = rdmsr (msr_base + 1 );
480
+ ls0 = rdmsr (msr_base + 2 );
481
+
482
+ __asm__ __volatile__("movl $0, %[v];"
483
+ "movl %[v], %%eax;"
484
+ "incl %[v];"
485
+ : [v ]"+m" (val ) :: "eax" );
486
+
487
+ ld1 = rdmsr (msr_base + 0 );
488
+ st1 = rdmsr (msr_base + 1 );
489
+ ls1 = rdmsr (msr_base + 2 );
490
+
491
+ c .loads = ld1 - ld0 ;
492
+ c .stores = st1 - st0 ;
493
+ c .loads_stores = ls1 - ls0 ;
494
+
495
+ return c .raw ;
496
+ }
497
+
498
+ static void intel_masked_events_guest_code (void )
499
+ {
500
+ uint64_t r ;
501
+
502
+ for (;;) {
503
+ wrmsr (MSR_CORE_PERF_GLOBAL_CTRL , 0 );
504
+
505
+ wrmsr (MSR_P6_EVNTSEL0 + 0 , ARCH_PERFMON_EVENTSEL_ENABLE |
506
+ ARCH_PERFMON_EVENTSEL_OS | MEM_INST_RETIRED_LOAD );
507
+ wrmsr (MSR_P6_EVNTSEL0 + 1 , ARCH_PERFMON_EVENTSEL_ENABLE |
508
+ ARCH_PERFMON_EVENTSEL_OS | MEM_INST_RETIRED_STORE );
509
+ wrmsr (MSR_P6_EVNTSEL0 + 2 , ARCH_PERFMON_EVENTSEL_ENABLE |
510
+ ARCH_PERFMON_EVENTSEL_OS | MEM_INST_RETIRED_LOAD_STORE );
511
+
512
+ wrmsr (MSR_CORE_PERF_GLOBAL_CTRL , 0x7 );
513
+
514
+ r = masked_events_guest_test (MSR_IA32_PMC0 );
515
+
516
+ GUEST_SYNC (r );
517
+ }
518
+ }
519
+
520
+ static void amd_masked_events_guest_code (void )
521
+ {
522
+ uint64_t r ;
523
+
524
+ for (;;) {
525
+ wrmsr (MSR_K7_EVNTSEL0 , 0 );
526
+ wrmsr (MSR_K7_EVNTSEL1 , 0 );
527
+ wrmsr (MSR_K7_EVNTSEL2 , 0 );
528
+
529
+ wrmsr (MSR_K7_EVNTSEL0 , ARCH_PERFMON_EVENTSEL_ENABLE |
530
+ ARCH_PERFMON_EVENTSEL_OS | LS_DISPATCH_LOAD );
531
+ wrmsr (MSR_K7_EVNTSEL1 , ARCH_PERFMON_EVENTSEL_ENABLE |
532
+ ARCH_PERFMON_EVENTSEL_OS | LS_DISPATCH_STORE );
533
+ wrmsr (MSR_K7_EVNTSEL2 , ARCH_PERFMON_EVENTSEL_ENABLE |
534
+ ARCH_PERFMON_EVENTSEL_OS | LS_DISPATCH_LOAD_STORE );
535
+
536
+ r = masked_events_guest_test (MSR_K7_PERFCTR0 );
537
+
538
+ GUEST_SYNC (r );
539
+ }
540
+ }
541
+
542
+ static struct perf_counter run_masked_events_test (struct kvm_vcpu * vcpu ,
543
+ const uint64_t masked_events [],
544
+ const int nmasked_events )
545
+ {
546
+ struct kvm_pmu_event_filter * f ;
547
+ struct perf_counter r ;
548
+
549
+ f = create_pmu_event_filter (masked_events , nmasked_events ,
550
+ KVM_PMU_EVENT_ALLOW ,
551
+ KVM_PMU_EVENT_FLAG_MASKED_EVENTS );
552
+ r .raw = test_with_filter (vcpu , f );
553
+ free (f );
554
+
555
+ return r ;
556
+ }
557
+
558
+ /* Matches KVM_PMU_EVENT_FILTER_MAX_EVENTS in pmu.c */
559
+ #define MAX_FILTER_EVENTS 300
560
+ #define MAX_TEST_EVENTS 10
561
+
562
+ #define ALLOW_LOADS BIT(0)
563
+ #define ALLOW_STORES BIT(1)
564
+ #define ALLOW_LOADS_STORES BIT(2)
565
+
566
+ struct masked_events_test {
567
+ uint64_t intel_events [MAX_TEST_EVENTS ];
568
+ uint64_t intel_event_end ;
569
+ uint64_t amd_events [MAX_TEST_EVENTS ];
570
+ uint64_t amd_event_end ;
571
+ const char * msg ;
572
+ uint32_t flags ;
573
+ };
574
+
575
+ /*
576
+ * These are the test cases for the masked events tests.
577
+ *
578
+ * For each test, the guest enables 3 PMU counters (loads, stores,
579
+ * loads + stores). The filter is then set in KVM with the masked events
580
+ * provided. The test then verifies that the counters agree with which
581
+ * ones should be counting and which ones should be filtered.
582
+ */
583
+ const struct masked_events_test test_cases [] = {
584
+ {
585
+ .intel_events = {
586
+ INCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0xFF , 0x81 ),
587
+ },
588
+ .amd_events = {
589
+ INCLUDE_MASKED_ENTRY (LS_DISPATCH , 0xFF , BIT (0 )),
590
+ },
591
+ .msg = "Only allow loads." ,
592
+ .flags = ALLOW_LOADS ,
593
+ }, {
594
+ .intel_events = {
595
+ INCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0xFF , 0x82 ),
596
+ },
597
+ .amd_events = {
598
+ INCLUDE_MASKED_ENTRY (LS_DISPATCH , 0xFF , BIT (1 )),
599
+ },
600
+ .msg = "Only allow stores." ,
601
+ .flags = ALLOW_STORES ,
602
+ }, {
603
+ .intel_events = {
604
+ INCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0xFF , 0x83 ),
605
+ },
606
+ .amd_events = {
607
+ INCLUDE_MASKED_ENTRY (LS_DISPATCH , 0xFF , BIT (2 )),
608
+ },
609
+ .msg = "Only allow loads + stores." ,
610
+ .flags = ALLOW_LOADS_STORES ,
611
+ }, {
612
+ .intel_events = {
613
+ INCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0x7C , 0 ),
614
+ EXCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0xFF , 0x83 ),
615
+ },
616
+ .amd_events = {
617
+ INCLUDE_MASKED_ENTRY (LS_DISPATCH , ~(BIT (0 ) | BIT (1 )), 0 ),
618
+ },
619
+ .msg = "Only allow loads and stores." ,
620
+ .flags = ALLOW_LOADS | ALLOW_STORES ,
621
+ }, {
622
+ .intel_events = {
623
+ INCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0x7C , 0 ),
624
+ EXCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0xFF , 0x82 ),
625
+ },
626
+ .amd_events = {
627
+ INCLUDE_MASKED_ENTRY (LS_DISPATCH , 0xF8 , 0 ),
628
+ EXCLUDE_MASKED_ENTRY (LS_DISPATCH , 0xFF , BIT (1 )),
629
+ },
630
+ .msg = "Only allow loads and loads + stores." ,
631
+ .flags = ALLOW_LOADS | ALLOW_LOADS_STORES
632
+ }, {
633
+ .intel_events = {
634
+ INCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0xFE , 0x82 ),
635
+ },
636
+ .amd_events = {
637
+ INCLUDE_MASKED_ENTRY (LS_DISPATCH , 0xF8 , 0 ),
638
+ EXCLUDE_MASKED_ENTRY (LS_DISPATCH , 0xFF , BIT (0 )),
639
+ },
640
+ .msg = "Only allow stores and loads + stores." ,
641
+ .flags = ALLOW_STORES | ALLOW_LOADS_STORES
642
+ }, {
643
+ .intel_events = {
644
+ INCLUDE_MASKED_ENTRY (MEM_INST_RETIRED , 0x7C , 0 ),
645
+ },
646
+ .amd_events = {
647
+ INCLUDE_MASKED_ENTRY (LS_DISPATCH , 0xF8 , 0 ),
648
+ },
649
+ .msg = "Only allow loads, stores, and loads + stores." ,
650
+ .flags = ALLOW_LOADS | ALLOW_STORES | ALLOW_LOADS_STORES
651
+ },
652
+ };
653
+
654
+ static int append_test_events (const struct masked_events_test * test ,
655
+ uint64_t * events , int nevents )
656
+ {
657
+ const uint64_t * evts ;
658
+ int i ;
659
+
660
+ evts = use_intel_pmu () ? test -> intel_events : test -> amd_events ;
661
+ for (i = 0 ; i < MAX_TEST_EVENTS ; i ++ ) {
662
+ if (evts [i ] == 0 )
663
+ break ;
664
+
665
+ events [nevents + i ] = evts [i ];
666
+ }
667
+
668
+ return nevents + i ;
669
+ }
670
+
671
+ static bool bool_eq (bool a , bool b )
672
+ {
673
+ return a == b ;
674
+ }
675
+
676
+ static void run_masked_events_tests (struct kvm_vcpu * vcpu , uint64_t * events ,
677
+ int nevents )
678
+ {
679
+ int ntests = ARRAY_SIZE (test_cases );
680
+ struct perf_counter c ;
681
+ int i , n ;
682
+
683
+ for (i = 0 ; i < ntests ; i ++ ) {
684
+ const struct masked_events_test * test = & test_cases [i ];
685
+
686
+ /* Do any test case events overflow MAX_TEST_EVENTS? */
687
+ assert (test -> intel_event_end == 0 );
688
+ assert (test -> amd_event_end == 0 );
689
+
690
+ n = append_test_events (test , events , nevents );
691
+
692
+ c = run_masked_events_test (vcpu , events , n );
693
+ TEST_ASSERT (bool_eq (c .loads , test -> flags & ALLOW_LOADS ) &&
694
+ bool_eq (c .stores , test -> flags & ALLOW_STORES ) &&
695
+ bool_eq (c .loads_stores ,
696
+ test -> flags & ALLOW_LOADS_STORES ),
697
+ "%s loads: %u, stores: %u, loads + stores: %u" ,
698
+ test -> msg , c .loads , c .stores , c .loads_stores );
699
+ }
700
+ }
701
+
702
+ static void add_dummy_events (uint64_t * events , int nevents )
703
+ {
704
+ int i ;
705
+
706
+ for (i = 0 ; i < nevents ; i ++ ) {
707
+ int event_select = i % 0xFF ;
708
+ bool exclude = ((i % 4 ) == 0 );
709
+
710
+ if (event_select == MEM_INST_RETIRED ||
711
+ event_select == LS_DISPATCH )
712
+ event_select ++ ;
713
+
714
+ events [i ] = KVM_PMU_ENCODE_MASKED_ENTRY (event_select , 0 ,
715
+ 0 , exclude );
716
+ }
717
+ }
718
+
719
+ static void test_masked_events (struct kvm_vcpu * vcpu )
720
+ {
721
+ int nevents = MAX_FILTER_EVENTS - MAX_TEST_EVENTS ;
722
+ uint64_t events [MAX_FILTER_EVENTS ];
723
+
724
+ /* Run the test cases against a sparse PMU event filter. */
725
+ run_masked_events_tests (vcpu , events , 0 );
726
+
727
+ /* Run the test cases against a dense PMU event filter. */
728
+ add_dummy_events (events , MAX_FILTER_EVENTS );
729
+ run_masked_events_tests (vcpu , events , nevents );
730
+ }
731
+
407
732
static int run_filter_test (struct kvm_vcpu * vcpu , const uint64_t * events ,
408
733
int nevents , uint32_t flags )
409
734
{
@@ -432,15 +757,15 @@ static void test_filter_ioctl(struct kvm_vcpu *vcpu)
432
757
r = run_filter_test (vcpu , & e , 1 , KVM_PMU_EVENT_FLAG_MASKED_EVENTS );
433
758
TEST_ASSERT (r != 0 , "Invalid PMU Event Filter is expected to fail" );
434
759
435
- e = KVM_PMU_EVENT_ENCODE_MASKED_ENTRY (0xff , 0xff , 0xff , 0xf );
760
+ e = KVM_PMU_ENCODE_MASKED_ENTRY (0xff , 0xff , 0xff , 0xf );
436
761
r = run_filter_test (vcpu , & e , 1 , KVM_PMU_EVENT_FLAG_MASKED_EVENTS );
437
762
TEST_ASSERT (r == 0 , "Valid PMU Event Filter is failing" );
438
763
}
439
764
440
765
int main (int argc , char * argv [])
441
766
{
442
767
void (* guest_code )(void );
443
- struct kvm_vcpu * vcpu ;
768
+ struct kvm_vcpu * vcpu , * vcpu2 = NULL ;
444
769
struct kvm_vm * vm ;
445
770
446
771
TEST_REQUIRE (kvm_has_cap (KVM_CAP_PMU_EVENT_FILTER ));
@@ -465,6 +790,15 @@ int main(int argc, char *argv[])
465
790
test_not_member_deny_list (vcpu );
466
791
test_not_member_allow_list (vcpu );
467
792
793
+ if (use_intel_pmu () &&
794
+ supports_event_mem_inst_retired () &&
795
+ kvm_cpu_property (X86_PROPERTY_PMU_NR_GP_COUNTERS ) >= 3 )
796
+ vcpu2 = vm_vcpu_add (vm , 2 , intel_masked_events_guest_code );
797
+ else if (use_amd_pmu ())
798
+ vcpu2 = vm_vcpu_add (vm , 2 , amd_masked_events_guest_code );
799
+
800
+ if (vcpu2 )
801
+ test_masked_events (vcpu2 );
468
802
test_filter_ioctl (vcpu );
469
803
470
804
kvm_vm_free (vm );
0 commit comments