8
8
* counters (PMCR_EL0.N) that userspace sets, if the guest can access
9
9
* those counters, and if the guest is prevented from accessing any
10
10
* other counters.
11
+ * It also checks if the userspace accesses to the PMU regsisters honor the
12
+ * PMCR.N value that's set for the guest.
11
13
* This test runs only when KVM_CAP_ARM_PMU_V3 is supported on the host.
12
14
*/
13
15
#include <kvm_util.h>
20
22
/* The max number of the PMU event counters (excluding the cycle counter) */
21
23
#define ARMV8_PMU_MAX_GENERAL_COUNTERS (ARMV8_PMU_MAX_COUNTERS - 1)
22
24
25
+ /* The cycle counter bit position that's common among the PMU registers */
26
+ #define ARMV8_PMU_CYCLE_IDX 31
27
+
23
28
struct vpmu_vm {
24
29
struct kvm_vm * vm ;
25
30
struct kvm_vcpu * vcpu ;
@@ -28,6 +33,13 @@ struct vpmu_vm {
28
33
29
34
static struct vpmu_vm vpmu_vm ;
30
35
36
+ struct pmreg_sets {
37
+ uint64_t set_reg_id ;
38
+ uint64_t clr_reg_id ;
39
+ };
40
+
41
+ #define PMREG_SET (set , clr ) {.set_reg_id = set, .clr_reg_id = clr}
42
+
31
43
static uint64_t get_pmcr_n (uint64_t pmcr )
32
44
{
33
45
return (pmcr >> ARMV8_PMU_PMCR_N_SHIFT ) & ARMV8_PMU_PMCR_N_MASK ;
@@ -39,6 +51,15 @@ static void set_pmcr_n(uint64_t *pmcr, uint64_t pmcr_n)
39
51
* pmcr |= (pmcr_n << ARMV8_PMU_PMCR_N_SHIFT );
40
52
}
41
53
54
+ static uint64_t get_counters_mask (uint64_t n )
55
+ {
56
+ uint64_t mask = BIT (ARMV8_PMU_CYCLE_IDX );
57
+
58
+ if (n )
59
+ mask |= GENMASK (n - 1 , 0 );
60
+ return mask ;
61
+ }
62
+
42
63
/* Read PMEVTCNTR<n>_EL0 through PMXEVCNTR_EL0 */
43
64
static inline unsigned long read_sel_evcntr (int sel )
44
65
{
@@ -541,6 +562,68 @@ static void run_access_test(uint64_t pmcr_n)
541
562
destroy_vpmu_vm ();
542
563
}
543
564
565
+ static struct pmreg_sets validity_check_reg_sets [] = {
566
+ PMREG_SET (SYS_PMCNTENSET_EL0 , SYS_PMCNTENCLR_EL0 ),
567
+ PMREG_SET (SYS_PMINTENSET_EL1 , SYS_PMINTENCLR_EL1 ),
568
+ PMREG_SET (SYS_PMOVSSET_EL0 , SYS_PMOVSCLR_EL0 ),
569
+ };
570
+
571
+ /*
572
+ * Create a VM, and check if KVM handles the userspace accesses of
573
+ * the PMU register sets in @validity_check_reg_sets[] correctly.
574
+ */
575
+ static void run_pmregs_validity_test (uint64_t pmcr_n )
576
+ {
577
+ int i ;
578
+ struct kvm_vcpu * vcpu ;
579
+ uint64_t set_reg_id , clr_reg_id , reg_val ;
580
+ uint64_t valid_counters_mask , max_counters_mask ;
581
+
582
+ test_create_vpmu_vm_with_pmcr_n (pmcr_n , false);
583
+ vcpu = vpmu_vm .vcpu ;
584
+
585
+ valid_counters_mask = get_counters_mask (pmcr_n );
586
+ max_counters_mask = get_counters_mask (ARMV8_PMU_MAX_COUNTERS );
587
+
588
+ for (i = 0 ; i < ARRAY_SIZE (validity_check_reg_sets ); i ++ ) {
589
+ set_reg_id = validity_check_reg_sets [i ].set_reg_id ;
590
+ clr_reg_id = validity_check_reg_sets [i ].clr_reg_id ;
591
+
592
+ /*
593
+ * Test if the 'set' and 'clr' variants of the registers
594
+ * are initialized based on the number of valid counters.
595
+ */
596
+ vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (set_reg_id ), & reg_val );
597
+ TEST_ASSERT ((reg_val & (~valid_counters_mask )) == 0 ,
598
+ "Initial read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n" ,
599
+ KVM_ARM64_SYS_REG (set_reg_id ), reg_val );
600
+
601
+ vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (clr_reg_id ), & reg_val );
602
+ TEST_ASSERT ((reg_val & (~valid_counters_mask )) == 0 ,
603
+ "Initial read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n" ,
604
+ KVM_ARM64_SYS_REG (clr_reg_id ), reg_val );
605
+
606
+ /*
607
+ * Using the 'set' variant, force-set the register to the
608
+ * max number of possible counters and test if KVM discards
609
+ * the bits for unimplemented counters as it should.
610
+ */
611
+ vcpu_set_reg (vcpu , KVM_ARM64_SYS_REG (set_reg_id ), max_counters_mask );
612
+
613
+ vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (set_reg_id ), & reg_val );
614
+ TEST_ASSERT ((reg_val & (~valid_counters_mask )) == 0 ,
615
+ "Read of set_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n" ,
616
+ KVM_ARM64_SYS_REG (set_reg_id ), reg_val );
617
+
618
+ vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (clr_reg_id ), & reg_val );
619
+ TEST_ASSERT ((reg_val & (~valid_counters_mask )) == 0 ,
620
+ "Read of clr_reg: 0x%llx has unimplemented counters enabled: 0x%lx\n" ,
621
+ KVM_ARM64_SYS_REG (clr_reg_id ), reg_val );
622
+ }
623
+
624
+ destroy_vpmu_vm ();
625
+ }
626
+
544
627
/*
545
628
* Create a guest with one vCPU, and attempt to set the PMCR_EL0.N for
546
629
* the vCPU to @pmcr_n, which is larger than the host value.
@@ -575,8 +658,10 @@ int main(void)
575
658
TEST_REQUIRE (kvm_has_cap (KVM_CAP_ARM_PMU_V3 ));
576
659
577
660
pmcr_n = get_pmcr_n_limit ();
578
- for (i = 0 ; i <= pmcr_n ; i ++ )
661
+ for (i = 0 ; i <= pmcr_n ; i ++ ) {
579
662
run_access_test (i );
663
+ run_pmregs_validity_test (i );
664
+ }
580
665
581
666
for (i = pmcr_n + 1 ; i < ARMV8_PMU_MAX_COUNTERS ; i ++ )
582
667
run_error_test (i );
0 commit comments