mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
KVM: arm64: Refuse to run VCPU if the PMU doesn't match the physical CPU
Userspace can assign a PMU to a VCPU with the KVM_ARM_VCPU_PMU_V3_SET_PMU device ioctl. If the VCPU is scheduled on a physical CPU which has a different PMU, the perf events needed to emulate a guest PMU won't be scheduled in and the guest performance counters will stop counting. Treat it as an userspace error and refuse to run the VCPU in this situation. Suggested-by: Marc Zyngier <maz@kernel.org> Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220127161759.53553-7-alexandru.elisei@arm.com
This commit is contained in:
parent
6ee7fca2a4
commit
583cda1b0e
@ -131,7 +131,11 @@ if a PMU event filter is already present.
|
|||||||
|
|
||||||
Note that KVM will not make any attempts to run the VCPU on the physical CPUs
|
Note that KVM will not make any attempts to run the VCPU on the physical CPUs
|
||||||
associated with the PMU specified by this attribute. This is entirely left to
|
associated with the PMU specified by this attribute. This is entirely left to
|
||||||
userspace.
|
userspace. However, attempting to run the VCPU on a physical CPU not supported
|
||||||
|
by the PMU will fail and KVM_RUN will return with
|
||||||
|
exit_reason = KVM_EXIT_FAIL_ENTRY and populate the fail_entry struct by setting
|
||||||
|
hardare_entry_failure_reason field to KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED and
|
||||||
|
the cpu field to the processor id.
|
||||||
|
|
||||||
2. GROUP: KVM_ARM_VCPU_TIMER_CTRL
|
2. GROUP: KVM_ARM_VCPU_TIMER_CTRL
|
||||||
=================================
|
=================================
|
||||||
|
@ -131,6 +131,8 @@ struct kvm_arch {
|
|||||||
unsigned long *pmu_filter;
|
unsigned long *pmu_filter;
|
||||||
struct arm_pmu *arm_pmu;
|
struct arm_pmu *arm_pmu;
|
||||||
|
|
||||||
|
cpumask_var_t supported_cpus;
|
||||||
|
|
||||||
u8 pfr0_csv2;
|
u8 pfr0_csv2;
|
||||||
u8 pfr0_csv3;
|
u8 pfr0_csv3;
|
||||||
|
|
||||||
@ -436,6 +438,7 @@ struct kvm_vcpu_arch {
|
|||||||
#define KVM_ARM64_DEBUG_STATE_SAVE_SPE (1 << 12) /* Save SPE context if active */
|
#define KVM_ARM64_DEBUG_STATE_SAVE_SPE (1 << 12) /* Save SPE context if active */
|
||||||
#define KVM_ARM64_DEBUG_STATE_SAVE_TRBE (1 << 13) /* Save TRBE context if active */
|
#define KVM_ARM64_DEBUG_STATE_SAVE_TRBE (1 << 13) /* Save TRBE context if active */
|
||||||
#define KVM_ARM64_FP_FOREIGN_FPSTATE (1 << 14)
|
#define KVM_ARM64_FP_FOREIGN_FPSTATE (1 << 14)
|
||||||
|
#define KVM_ARM64_ON_UNSUPPORTED_CPU (1 << 15) /* Physical CPU not in supported_cpus */
|
||||||
|
|
||||||
#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
|
#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
|
||||||
KVM_GUESTDBG_USE_SW_BP | \
|
KVM_GUESTDBG_USE_SW_BP | \
|
||||||
@ -454,6 +457,15 @@ struct kvm_vcpu_arch {
|
|||||||
#define vcpu_has_ptrauth(vcpu) false
|
#define vcpu_has_ptrauth(vcpu) false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define vcpu_on_unsupported_cpu(vcpu) \
|
||||||
|
((vcpu)->arch.flags & KVM_ARM64_ON_UNSUPPORTED_CPU)
|
||||||
|
|
||||||
|
#define vcpu_set_on_unsupported_cpu(vcpu) \
|
||||||
|
((vcpu)->arch.flags |= KVM_ARM64_ON_UNSUPPORTED_CPU)
|
||||||
|
|
||||||
|
#define vcpu_clear_on_unsupported_cpu(vcpu) \
|
||||||
|
((vcpu)->arch.flags &= ~KVM_ARM64_ON_UNSUPPORTED_CPU)
|
||||||
|
|
||||||
#define vcpu_gp_regs(v) (&(v)->arch.ctxt.regs)
|
#define vcpu_gp_regs(v) (&(v)->arch.ctxt.regs)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -414,6 +414,9 @@ struct kvm_arm_copy_mte_tags {
|
|||||||
#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS
|
#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS
|
||||||
#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED
|
#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED
|
||||||
|
|
||||||
|
/* run->fail_entry.hardware_entry_failure_reason codes. */
|
||||||
|
#define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __ARM_KVM_H__ */
|
#endif /* __ARM_KVM_H__ */
|
||||||
|
@ -150,6 +150,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out_free_stage2_pgd;
|
goto out_free_stage2_pgd;
|
||||||
|
|
||||||
|
if (!zalloc_cpumask_var(&kvm->arch.supported_cpus, GFP_KERNEL))
|
||||||
|
goto out_free_stage2_pgd;
|
||||||
|
cpumask_copy(kvm->arch.supported_cpus, cpu_possible_mask);
|
||||||
|
|
||||||
kvm_vgic_early_init(kvm);
|
kvm_vgic_early_init(kvm);
|
||||||
|
|
||||||
/* The maximum number of VCPUs is limited by the host's GIC model */
|
/* The maximum number of VCPUs is limited by the host's GIC model */
|
||||||
@ -176,6 +180,7 @@ vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
|
|||||||
void kvm_arch_destroy_vm(struct kvm *kvm)
|
void kvm_arch_destroy_vm(struct kvm *kvm)
|
||||||
{
|
{
|
||||||
bitmap_free(kvm->arch.pmu_filter);
|
bitmap_free(kvm->arch.pmu_filter);
|
||||||
|
free_cpumask_var(kvm->arch.supported_cpus);
|
||||||
|
|
||||||
kvm_vgic_destroy(kvm);
|
kvm_vgic_destroy(kvm);
|
||||||
|
|
||||||
@ -411,6 +416,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
|||||||
if (vcpu_has_ptrauth(vcpu))
|
if (vcpu_has_ptrauth(vcpu))
|
||||||
vcpu_ptrauth_disable(vcpu);
|
vcpu_ptrauth_disable(vcpu);
|
||||||
kvm_arch_vcpu_load_debug_state_flags(vcpu);
|
kvm_arch_vcpu_load_debug_state_flags(vcpu);
|
||||||
|
|
||||||
|
if (!cpumask_test_cpu(smp_processor_id(), vcpu->kvm->arch.supported_cpus))
|
||||||
|
vcpu_set_on_unsupported_cpu(vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
||||||
@ -423,6 +431,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
|||||||
kvm_vgic_put(vcpu);
|
kvm_vgic_put(vcpu);
|
||||||
kvm_vcpu_pmu_restore_host(vcpu);
|
kvm_vcpu_pmu_restore_host(vcpu);
|
||||||
|
|
||||||
|
vcpu_clear_on_unsupported_cpu(vcpu);
|
||||||
vcpu->cpu = -1;
|
vcpu->cpu = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,6 +805,14 @@ static bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu, int *ret)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely(vcpu_on_unsupported_cpu(vcpu))) {
|
||||||
|
run->exit_reason = KVM_EXIT_FAIL_ENTRY;
|
||||||
|
run->fail_entry.hardware_entry_failure_reason = KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED;
|
||||||
|
run->fail_entry.cpu = smp_processor_id();
|
||||||
|
*ret = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return kvm_request_pending(vcpu) ||
|
return kvm_request_pending(vcpu) ||
|
||||||
need_new_vmid_gen(&vcpu->arch.hw_mmu->vmid) ||
|
need_new_vmid_gen(&vcpu->arch.hw_mmu->vmid) ||
|
||||||
xfer_to_guest_mode_work_pending();
|
xfer_to_guest_mode_work_pending();
|
||||||
|
@ -968,6 +968,7 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
kvm->arch.arm_pmu = arm_pmu;
|
kvm->arch.arm_pmu = arm_pmu;
|
||||||
|
cpumask_copy(kvm->arch.supported_cpus, &arm_pmu->supported_cpus);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user