History

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.

Alexandru Elisei committed 4 years ago

Commit 583cda11 parent 6ee7fca5 files · +38 −1Browse files

Unified · Split

5 files
  1. Documentation/virt/kvm/devices/vcpu.rst +5 −1
  2. arch/arm64/include/asm/kvm_host.h +12 −0
  3. arch/arm64/include/uapi/asm/kvm.h +3 −0
  4. arch/arm64/kvm/arm.c +17 −0
  5. arch/arm64/kvm/pmu-emul.c +1 −0
Documentation/virt/kvm/devices/vcpu.rst+5−1
@@ -131,7 +131,11 @@ if a PMU event filter is already present. · 130 unmodified lines
131 131
132Note that KVM will not make any attempts to run the VCPU on the physical CPUs132Note that KVM will not make any attempts to run the VCPU on the physical CPUs
133associated with the PMU specified by this attribute. This is entirely left to133associated with the PMU specified by this attribute. This is entirely left to
134userspace.134userspace. However, attempting to run the VCPU on a physical CPU not supported
135by the PMU will fail and KVM_RUN will return with
136exit_reason = KVM_EXIT_FAIL_ENTRY and populate the fail_entry struct by setting
137hardare_entry_failure_reason field to KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED and
138the cpu field to the processor id.
135 139
1362. GROUP: KVM_ARM_VCPU_TIMER_CTRL1402. GROUP: KVM_ARM_VCPU_TIMER_CTRL
137=================================141=================================
arch/arm64/include/asm/kvm_host.h+12−0
@@ -131,6 +131,8 @@ struct kvm_arch { · 130 unmodified lines
131 unsigned long *pmu_filter;131 unsigned long *pmu_filter;
132 struct arm_pmu *arm_pmu;132 struct arm_pmu *arm_pmu;
133 133
134 cpumask_var_t supported_cpus;
135
134 u8 pfr0_csv2;136 u8 pfr0_csv2;
135 u8 pfr0_csv3;137 u8 pfr0_csv3;
136 138
@@ -436,6 +438,7 @@ struct kvm_vcpu_arch { · 299 unmodified lines
436#define KVM_ARM64_DEBUG_STATE_SAVE_SPE (1 << 12) /* Save SPE context if active */438#define KVM_ARM64_DEBUG_STATE_SAVE_SPE (1 << 12) /* Save SPE context if active */
437#define KVM_ARM64_DEBUG_STATE_SAVE_TRBE (1 << 13) /* Save TRBE context if active */439#define KVM_ARM64_DEBUG_STATE_SAVE_TRBE (1 << 13) /* Save TRBE context if active */
438#define KVM_ARM64_FP_FOREIGN_FPSTATE (1 << 14)440#define KVM_ARM64_FP_FOREIGN_FPSTATE (1 << 14)
441#define KVM_ARM64_ON_UNSUPPORTED_CPU (1 << 15) /* Physical CPU not in supported_cpus */
439 442
440#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \443#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
441 KVM_GUESTDBG_USE_SW_BP | \444 KVM_GUESTDBG_USE_SW_BP | \
@@ -454,6 +457,15 @@ struct kvm_vcpu_arch { · 12 unmodified lines
454#define vcpu_has_ptrauth(vcpu) false457#define vcpu_has_ptrauth(vcpu) false
455#endif458#endif
456 459
460#define vcpu_on_unsupported_cpu(vcpu) \
461 ((vcpu)->arch.flags & KVM_ARM64_ON_UNSUPPORTED_CPU)
462
463#define vcpu_set_on_unsupported_cpu(vcpu) \
464 ((vcpu)->arch.flags |= KVM_ARM64_ON_UNSUPPORTED_CPU)
465
466#define vcpu_clear_on_unsupported_cpu(vcpu) \
467 ((vcpu)->arch.flags &= ~KVM_ARM64_ON_UNSUPPORTED_CPU)
468
457#define vcpu_gp_regs(v) (&(v)->arch.ctxt.regs)469#define vcpu_gp_regs(v) (&(v)->arch.ctxt.regs)
458 470
459/*471/*
arch/arm64/include/uapi/asm/kvm.h+3−0
@@ -414,6 +414,9 @@ struct kvm_arm_copy_mte_tags { · 413 unmodified lines
414#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS414#define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS
415#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED415#define KVM_PSCI_RET_DENIED PSCI_RET_DENIED
416 416
417/* run->fail_entry.hardware_entry_failure_reason codes. */
418#define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0)
419
417#endif420#endif
418 421
419#endif /* __ARM_KVM_H__ */422#endif /* __ARM_KVM_H__ */
arch/arm64/kvm/arm.c+17−0
@@ -150,6 +150,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) · 149 unmodified lines
150 if (ret)150 if (ret)
151 goto out_free_stage2_pgd;151 goto out_free_stage2_pgd;
152 152
153 if (!zalloc_cpumask_var(&kvm->arch.supported_cpus, GFP_KERNEL))
154 goto out_free_stage2_pgd;
155 cpumask_copy(kvm->arch.supported_cpus, cpu_possible_mask);
156
153 kvm_vgic_early_init(kvm);157 kvm_vgic_early_init(kvm);
154 158
155 /* The maximum number of VCPUs is limited by the host's GIC model */159 /* 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) · 20 unmodified lines
176void kvm_arch_destroy_vm(struct kvm *kvm)180void kvm_arch_destroy_vm(struct kvm *kvm)
177{181{
178 bitmap_free(kvm->arch.pmu_filter);182 bitmap_free(kvm->arch.pmu_filter);
183 free_cpumask_var(kvm->arch.supported_cpus);
179 184
180 kvm_vgic_destroy(kvm);185 kvm_vgic_destroy(kvm);
181 186
@@ -411,6 +416,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) · 229 unmodified lines
411 if (vcpu_has_ptrauth(vcpu))416 if (vcpu_has_ptrauth(vcpu))
412 vcpu_ptrauth_disable(vcpu);417 vcpu_ptrauth_disable(vcpu);
413 kvm_arch_vcpu_load_debug_state_flags(vcpu);418 kvm_arch_vcpu_load_debug_state_flags(vcpu);
419
420 if (!cpumask_test_cpu(smp_processor_id(), vcpu->kvm->arch.supported_cpus))
421 vcpu_set_on_unsupported_cpu(vcpu);
414}422}
415 423
416void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)424void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -423,6 +431,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) · 6 unmodified lines
423 kvm_vgic_put(vcpu);431 kvm_vgic_put(vcpu);
424 kvm_vcpu_pmu_restore_host(vcpu);432 kvm_vcpu_pmu_restore_host(vcpu);
425 433
434 vcpu_clear_on_unsupported_cpu(vcpu);
426 vcpu->cpu = -1;435 vcpu->cpu = -1;
427}436}
428 437
@@ -796,6 +805,14 @@ static bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu, int *ret) · 367 unmodified lines
796 }805 }
797 }806 }
798 807
808 if (unlikely(vcpu_on_unsupported_cpu(vcpu))) {
809 run->exit_reason = KVM_EXIT_FAIL_ENTRY;
810 run->fail_entry.hardware_entry_failure_reason = KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED;
811 run->fail_entry.cpu = smp_processor_id();
812 *ret = 0;
813 return true;
814 }
815
799 return kvm_request_pending(vcpu) ||816 return kvm_request_pending(vcpu) ||
800 need_new_vmid_gen(&vcpu->arch.hw_mmu->vmid) ||817 need_new_vmid_gen(&vcpu->arch.hw_mmu->vmid) ||
801 xfer_to_guest_mode_work_pending();818 xfer_to_guest_mode_work_pending();
arch/arm64/kvm/pmu-emul.c+1−0
@@ -968,6 +968,7 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id) · 967 unmodified lines
968 }968 }
969 969
970 kvm->arch.arm_pmu = arm_pmu;970 kvm->arch.arm_pmu = arm_pmu;
971 cpumask_copy(kvm->arch.supported_cpus, &arm_pmu->supported_cpus);
971 ret = 0;972 ret = 0;
972 break;973 break;
973 }974 }