88 * counters (PMCR_EL0.N) that userspace sets, if the guest can access
99 * those counters, and if the guest is prevented from accessing any
1010 * 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.
1113 * This test runs only when KVM_CAP_ARM_PMU_V3 is supported on the host.
1214 */
1315#include <kvm_util.h>
2022/* The max number of the PMU event counters (excluding the cycle counter) */
2123#define ARMV8_PMU_MAX_GENERAL_COUNTERS (ARMV8_PMU_MAX_COUNTERS - 1)
2224
25+ /* The cycle counter bit position that's common among the PMU registers */
26+ #define ARMV8_PMU_CYCLE_IDX 31
27+
2328struct vpmu_vm {
2429 struct kvm_vm * vm ;
2530 struct kvm_vcpu * vcpu ;
@@ -28,6 +33,13 @@ struct vpmu_vm {
2833
2934static struct vpmu_vm vpmu_vm ;
3035
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+
3143static uint64_t get_pmcr_n (uint64_t pmcr )
3244{
3345 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)
3951 * pmcr |= (pmcr_n << ARMV8_PMU_PMCR_N_SHIFT );
4052}
4153
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+
4263/* Read PMEVTCNTR<n>_EL0 through PMXEVCNTR_EL0 */
4364static inline unsigned long read_sel_evcntr (int sel )
4465{
@@ -541,6 +562,68 @@ static void run_access_test(uint64_t pmcr_n)
541562 destroy_vpmu_vm ();
542563}
543564
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+
544627/*
545628 * Create a guest with one vCPU, and attempt to set the PMCR_EL0.N for
546629 * the vCPU to @pmcr_n, which is larger than the host value.
@@ -575,8 +658,10 @@ int main(void)
575658 TEST_REQUIRE (kvm_has_cap (KVM_CAP_ARM_PMU_V3 ));
576659
577660 pmcr_n = get_pmcr_n_limit ();
578- for (i = 0 ; i <= pmcr_n ; i ++ )
661+ for (i = 0 ; i <= pmcr_n ; i ++ ) {
579662 run_access_test (i );
663+ run_pmregs_validity_test (i );
664+ }
580665
581666 for (i = pmcr_n + 1 ; i < ARMV8_PMU_MAX_COUNTERS ; i ++ )
582667 run_error_test (i );
0 commit comments