From: Oliver Upton Date: Mon, 30 Oct 2023 20:24:07 +0000 (+0000) Subject: Merge branch kvm-arm64/pmu_pmcr_n into kvmarm/next X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=123f42f0ad6815014f54d0cc6eb9039c46ee2907;p=linux.git Merge branch kvm-arm64/pmu_pmcr_n into kvmarm/next * kvm-arm64/pmu_pmcr_n: : User-defined PMC limit, courtesy Raghavendra Rao Ananta : : Certain VMMs may want to reserve some PMCs for host use while running a : KVM guest. This was a bit difficult before, as KVM advertised all : supported counters to the guest. Userspace can now limit the number of : advertised PMCs by writing to PMCR_EL0.N, as KVM's sysreg and PMU : emulation enforce the specified limit for handling guest accesses. KVM: selftests: aarch64: vPMU test for validating user accesses KVM: selftests: aarch64: vPMU register test for unimplemented counters KVM: selftests: aarch64: vPMU register test for implemented counters KVM: selftests: aarch64: Introduce vpmu_counter_access test tools: Import arm_pmuv3.h KVM: arm64: PMU: Allow userspace to limit PMCR_EL0.N for the guest KVM: arm64: Sanitize PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR} before first run KVM: arm64: Add {get,set}_user for PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR} KVM: arm64: PMU: Set PMCR_EL0.N for vCPU based on the associated PMU KVM: arm64: PMU: Add a helper to read a vCPU's PMCR_EL0 KVM: arm64: Select default PMU in KVM_ARM_VCPU_INIT handler KVM: arm64: PMU: Introduce helpers to set the guest's PMU Signed-off-by: Oliver Upton --- 123f42f0ad6815014f54d0cc6eb9039c46ee2907 diff --cc arch/arm64/kvm/arm.c index c6cad400490f9,f6307afc5036b..317964bad1e16 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@@ -1315,10 -1225,24 +1314,25 @@@ static bool kvm_vcpu_init_changed(struc { unsigned long features = init->features[0]; - return !bitmap_equal(vcpu->arch.features, &features, KVM_VCPU_MAX_FEATURES); + return !bitmap_equal(vcpu->kvm->arch.vcpu_features, &features, + KVM_VCPU_MAX_FEATURES); } + static int kvm_setup_vcpu(struct kvm_vcpu *vcpu) + { + struct kvm *kvm = vcpu->kvm; + int ret = 0; + + /* + * When the vCPU has a PMU, but no PMU is set for the guest + * yet, set the default one. + */ + if (kvm_vcpu_has_pmu(vcpu) && !kvm->arch.arm_pmu) + ret = kvm_arm_set_default_pmu(kvm); + + return ret; + } + static int __kvm_vcpu_set_target(struct kvm_vcpu *vcpu, const struct kvm_vcpu_init *init) { @@@ -1329,17 -1253,25 +1343,21 @@@ mutex_lock(&kvm->arch.config_lock); if (test_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags) && - !bitmap_equal(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES)) + kvm_vcpu_init_changed(vcpu, init)) goto out_unlock; - bitmap_copy(vcpu->arch.features, &features, KVM_VCPU_MAX_FEATURES); + bitmap_copy(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES); + ret = kvm_setup_vcpu(vcpu); + if (ret) + goto out_unlock; + /* Now we know what it is, we can reset it. */ - ret = kvm_reset_vcpu(vcpu); - if (ret) { - bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES); - goto out_unlock; - } + kvm_reset_vcpu(vcpu); - bitmap_copy(kvm->arch.vcpu_features, &features, KVM_VCPU_MAX_FEATURES); set_bit(KVM_ARCH_FLAG_VCPU_FEATURES_CONFIGURED, &kvm->arch.flags); vcpu_set_flag(vcpu, VCPU_INITIALIZED); + ret = 0; out_unlock: mutex_unlock(&kvm->arch.config_lock); return ret; diff --cc include/kvm/arm_pmu.h index 4df71290b676b,abb1e8215ca8d..4b9d8fb393a84 --- a/include/kvm/arm_pmu.h +++ b/include/kvm/arm_pmu.h @@@ -101,8 -101,10 +101,11 @@@ void kvm_vcpu_pmu_resync_el0(void) }) u8 kvm_arm_pmu_get_pmuver_limit(void); +u64 kvm_pmu_evtyper_mask(struct kvm *kvm); + int kvm_arm_set_default_pmu(struct kvm *kvm); + u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm); + u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu); #else struct kvm_pmu { }; @@@ -173,12 -176,23 +177,27 @@@ static inline u8 kvm_arm_pmu_get_pmuver { return 0; } +static inline u64 kvm_pmu_evtyper_mask(struct kvm *kvm) +{ + return 0; +} static inline void kvm_vcpu_pmu_resync_el0(void) {} + static inline int kvm_arm_set_default_pmu(struct kvm *kvm) + { + return -ENODEV; + } + + static inline u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm) + { + return 0; + } + + static inline u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu) + { + return 0; + } + #endif #endif