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.
Unified · Split
| @@ -131,7 +131,11 @@ if a PMU event filter is already present. · 130 unmodified lines | |||
| 131 | 131 | ||
| 132 | Note that KVM will not make any attempts to run the VCPU on the physical CPUs | 132 | Note that KVM will not make any attempts to run the VCPU on the physical CPUs |
| 133 | associated with the PMU specified by this attribute. This is entirely left to | 133 | associated with the PMU specified by this attribute. This is entirely left to |
| 134 | userspace. | 134 | userspace. However, attempting to run the VCPU on a physical CPU not supported |
| 135 | by the PMU will fail and KVM_RUN will return with | ||
| 136 | exit_reason = KVM_EXIT_FAIL_ENTRY and populate the fail_entry struct by setting | ||
| 137 | hardare_entry_failure_reason field to KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED and | ||
| 138 | the cpu field to the processor id. | ||
| 135 | 139 | ||
| 136 | 2. GROUP: KVM_ARM_VCPU_TIMER_CTRL | 140 | 2. GROUP: KVM_ARM_VCPU_TIMER_CTRL |
| 137 | ================================= | 141 | ================================= |
| @@ -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) false | 457 | #define vcpu_has_ptrauth(vcpu) false |
| 455 | #endif | 458 | #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 | /* |
| @@ -414,6 +414,9 @@ struct kvm_arm_copy_mte_tags { · 413 unmodified lines | |||
| 414 | #define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS | 414 | #define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS |
| 415 | #define KVM_PSCI_RET_DENIED PSCI_RET_DENIED | 415 | #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 | #endif | 420 | #endif |
| 418 | 421 | ||
| 419 | #endif /* __ARM_KVM_H__ */ | 422 | #endif /* __ARM_KVM_H__ */ |
| @@ -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 | |||
| 176 | void kvm_arch_destroy_vm(struct kvm *kvm) | 180 | void 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 | ||
| 416 | void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | 424 | void 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(); |
| @@ -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 | } |