]> xenbits.xensource.com Git - people/pauldu/linux.git/commitdiff
KVM: arm64: Select default PMU in KVM_ARM_VCPU_INIT handler
authorReiji Watanabe <reijiw@google.com>
Fri, 20 Oct 2023 21:40:42 +0000 (21:40 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Tue, 24 Oct 2023 22:59:29 +0000 (22:59 +0000)
Future changes to KVM's sysreg emulation will rely on having a valid PMU
instance to determine the number of implemented counters (PMCR_EL0.N).
This is earlier than when userspace is expected to modify the vPMU
device attributes, where the default is selected today.

Select the default PMU when handling KVM_ARM_VCPU_INIT such that it is
available in time for sysreg emulation.

Reviewed-by: Sebastian Ott <sebott@redhat.com>
Co-developed-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Link: https://lore.kernel.org/r/20231020214053.2144305-3-rananta@google.com
[Oliver: rewrite changelog]
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/arm.c
arch/arm64/kvm/pmu-emul.c
include/kvm/arm_pmu.h

index 4866b3f7b4ea3847d885e00cfac47a4d7abf9da3..0771c42d02e448800dc3fae2116da20a60dc6e96 100644 (file)
@@ -1229,6 +1229,21 @@ static bool kvm_vcpu_init_changed(struct kvm_vcpu *vcpu,
        return !bitmap_equal(vcpu->arch.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)
 {
@@ -1244,6 +1259,10 @@ static int __kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
 
        bitmap_copy(vcpu->arch.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) {
index fb9817bdfeb57a8a3b1093e11290aaefa5f41c39..1eb02765dd14bd8b64de456268c02a24f506a862 100644 (file)
@@ -717,10 +717,9 @@ static struct arm_pmu *kvm_pmu_probe_armpmu(void)
         * It is still necessary to get a valid cpu, though, to probe for the
         * default PMU instance as userspace is not required to specify a PMU
         * type. In order to uphold the preexisting behavior KVM selects the
-        * PMU instance for the core where the first call to the
-        * KVM_ARM_VCPU_PMU_V3_CTRL attribute group occurs. A dependent use case
-        * would be a user with disdain of all things big.LITTLE that affines
-        * the VMM to a particular cluster of cores.
+        * PMU instance for the core during vcpu init. A dependent use
+        * case would be a user with disdain of all things big.LITTLE that
+        * affines the VMM to a particular cluster of cores.
         *
         * In any case, userspace should just do the sane thing and use the UAPI
         * to select a PMU type directly. But, be wary of the baggage being
@@ -893,7 +892,7 @@ static void kvm_arm_set_pmu(struct kvm *kvm, struct arm_pmu *arm_pmu)
  * where vCPUs can be scheduled on any core but the guest
  * counters could stop working.
  */
-static int kvm_arm_set_default_pmu(struct kvm *kvm)
+int kvm_arm_set_default_pmu(struct kvm *kvm)
 {
        struct arm_pmu *arm_pmu = kvm_pmu_probe_armpmu();
 
@@ -946,13 +945,6 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
        if (vcpu->arch.pmu.created)
                return -EBUSY;
 
-       if (!kvm->arch.arm_pmu) {
-               int ret = kvm_arm_set_default_pmu(kvm);
-
-               if (ret)
-                       return ret;
-       }
-
        switch (attr->attr) {
        case KVM_ARM_VCPU_PMU_V3_IRQ: {
                int __user *uaddr = (int __user *)(long)attr->addr;
index 31029f4f7be851d684c9500c243b59e979e6df67..b80c75d80886be8d32c5a7fa1f0f56e5cb149660 100644 (file)
@@ -101,6 +101,7 @@ void kvm_vcpu_pmu_resync_el0(void);
 })
 
 u8 kvm_arm_pmu_get_pmuver_limit(void);
+int kvm_arm_set_default_pmu(struct kvm *kvm);
 
 #else
 struct kvm_pmu {
@@ -174,6 +175,11 @@ static inline u8 kvm_arm_pmu_get_pmuver_limit(void)
 }
 static inline void kvm_vcpu_pmu_resync_el0(void) {}
 
+static inline int kvm_arm_set_default_pmu(struct kvm *kvm)
+{
+       return -ENODEV;
+}
+
 #endif
 
 #endif