Message ID | 20220121002952.241015-2-daviddunn@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Provide VM capability to disable PMU virtualization for individual VMs | expand |
Hi David, Please modify the subject of this patch to follow the convention. On 21/1/2022 8:29 am, David Dunn wrote: > KVM_PMU_CONFIG_DISABLE can be used to disable PMU virtualization on How about using: case KVM_CAP_PMU_CAPABILITY #define KVM_CAP_PMU_DISABLE (1 << 0) #define KVM_CAP_PMU_MASK (KVM_CAP_PMU_DISABLE) > individual x86 VMs. PMU configuration must be done prior to creating > VCPUs. > > To enable future extension, KVM_CAP_PMU_CONFIG reports available > settings when queried via check_extension. Please help update the document in the Documentation/virt/kvm/api.rst > > Since KVM_GET_SUPPORTED_CPUID reports the maximal CPUID information > based on module parameters, usermode will need to adjust CPUID when > disabling PMU virtualization on individual VMs. For an irrational user space (set both pmu cpuid bits and KVM_CAP_PMU_DISABLE), how about we remove the relevant PMU cpuid bits in kvm_pmu_refresh() silently? > > Signed-off-by: David Dunn <daviddunn@google.com> > --- > arch/x86/include/asm/kvm_host.h | 1 + > arch/x86/kvm/svm/pmu.c | 2 +- > arch/x86/kvm/vmx/pmu_intel.c | 2 +- > arch/x86/kvm/x86.c | 12 ++++++++++++ > include/uapi/linux/kvm.h | 4 ++++ > tools/include/uapi/linux/kvm.h | 4 ++++ > 6 files changed, 23 insertions(+), 2 deletions(-) > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 682ad02a4e58..5cdcd4a7671b 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -1232,6 +1232,7 @@ struct kvm_arch { > hpa_t hv_root_tdp; > spinlock_t hv_root_tdp_lock; > #endif > + bool enable_pmu; > }; > > struct kvm_vm_stat { > diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c > index 5aa45f13b16d..d4de52409335 100644 > --- a/arch/x86/kvm/svm/pmu.c > +++ b/arch/x86/kvm/svm/pmu.c > @@ -101,7 +101,7 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, > { > struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu); > > - if (!enable_pmu) > + if (!vcpu->kvm->arch.enable_pmu) Compared to diff in the v1: - if (!enable_pmu) + if (!enable_pmu || !vcpu->kvm->arch.enable_pmu) Now I have come to appreciate the ingenious name. > return NULL; > > switch (msr) { > diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c > index 466d18fc0c5d..2c5868d77268 100644 > --- a/arch/x86/kvm/vmx/pmu_intel.c > +++ b/arch/x86/kvm/vmx/pmu_intel.c > @@ -487,7 +487,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) > pmu->reserved_bits = 0xffffffff00200000ull; > > entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); > - if (!entry || !enable_pmu) > + if (!entry || !vcpu->kvm->arch.enable_pmu) > return; > eax.full = entry->eax; > edx.full = entry->edx; > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 55518b7d3b96..42a98635bea5 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -4326,6 +4326,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) > if (r < sizeof(struct kvm_xsave)) > r = sizeof(struct kvm_xsave); > break; > + case KVM_CAP_PMU_CONFIG: > + r = enable_pmu ? KVM_PMU_CONFIG_VALID : 0; > + break; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 42a98635bea5..94481f92355d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4326,10 +4326,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) if (r < sizeof(struct kvm_xsave)) r = sizeof(struct kvm_xsave); break; + } case KVM_CAP_PMU_CONFIG: r = enable_pmu ? KVM_CAP_PMU_MASK : 0; break; - } default: break; } > } > default: > break; > @@ -5937,6 +5940,14 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, > kvm->arch.exit_on_emulation_error = cap->args[0]; > r = 0; > break; > + case KVM_CAP_PMU_CONFIG: > + r = -EINVAL; > + if (!enable_pmu || kvm->created_vcpus > 0 || > + cap->args[0] & ~KVM_PMU_CONFIG_VALID) > + break; > + kvm->arch.enable_pmu = !(cap->args[0] & KVM_PMU_CONFIG_DISABLE); > + r = 0; > + break; > default: > r = -EINVAL; > break; > @@ -11562,6 +11573,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) > raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); > > kvm->arch.guest_can_read_msr_platform_info = true; > + kvm->arch.enable_pmu = enable_pmu; > > #if IS_ENABLED(CONFIG_HYPERV) > spin_lock_init(&kvm->arch.hv_root_tdp_lock); > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 9563d294f181..57a1280fa43b 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -1133,6 +1133,7 @@ struct kvm_ppc_resize_hpt { > #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206 > #define KVM_CAP_VM_GPA_BITS 207 > #define KVM_CAP_XSAVE2 208 > +#define KVM_CAP_PMU_CONFIG 209 > > #ifdef KVM_CAP_IRQ_ROUTING > > @@ -1972,6 +1973,9 @@ struct kvm_dirty_gfn { > #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) > #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) > > +#define KVM_PMU_CONFIG_DISABLE (1 << 0) > +#define KVM_PMU_CONFIG_VALID (KVM_PMU_CONFIG_DISABLE) > + > /** > * struct kvm_stats_header - Header of per vm/vcpu binary statistics data. > * @flags: Some extra information for header, always 0 for now. > diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h > index 9563d294f181..57a1280fa43b 100644 > --- a/tools/include/uapi/linux/kvm.h > +++ b/tools/include/uapi/linux/kvm.h > @@ -1133,6 +1133,7 @@ struct kvm_ppc_resize_hpt { > #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206 > #define KVM_CAP_VM_GPA_BITS 207 > #define KVM_CAP_XSAVE2 208 > +#define KVM_CAP_PMU_CONFIG 209 > > #ifdef KVM_CAP_IRQ_ROUTING > > @@ -1972,6 +1973,9 @@ struct kvm_dirty_gfn { > #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) > #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) > > +#define KVM_PMU_CONFIG_DISABLE (1 << 0) > +#define KVM_PMU_CONFIG_VALID (KVM_PMU_CONFIG_DISABLE) > + > /** > * struct kvm_stats_header - Header of per vm/vcpu binary statistics data. > * @flags: Some extra information for header, always 0 for now.
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 682ad02a4e58..5cdcd4a7671b 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1232,6 +1232,7 @@ struct kvm_arch { hpa_t hv_root_tdp; spinlock_t hv_root_tdp_lock; #endif + bool enable_pmu; }; struct kvm_vm_stat { diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 5aa45f13b16d..d4de52409335 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -101,7 +101,7 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, { struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu); - if (!enable_pmu) + if (!vcpu->kvm->arch.enable_pmu) return NULL; switch (msr) { diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 466d18fc0c5d..2c5868d77268 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -487,7 +487,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->reserved_bits = 0xffffffff00200000ull; entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); - if (!entry || !enable_pmu) + if (!entry || !vcpu->kvm->arch.enable_pmu) return; eax.full = entry->eax; edx.full = entry->edx; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 55518b7d3b96..42a98635bea5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4326,6 +4326,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) if (r < sizeof(struct kvm_xsave)) r = sizeof(struct kvm_xsave); break; + case KVM_CAP_PMU_CONFIG: + r = enable_pmu ? KVM_PMU_CONFIG_VALID : 0; + break; } default: break; @@ -5937,6 +5940,14 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, kvm->arch.exit_on_emulation_error = cap->args[0]; r = 0; break; + case KVM_CAP_PMU_CONFIG: + r = -EINVAL; + if (!enable_pmu || kvm->created_vcpus > 0 || + cap->args[0] & ~KVM_PMU_CONFIG_VALID) + break; + kvm->arch.enable_pmu = !(cap->args[0] & KVM_PMU_CONFIG_DISABLE); + r = 0; + break; default: r = -EINVAL; break; @@ -11562,6 +11573,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); kvm->arch.guest_can_read_msr_platform_info = true; + kvm->arch.enable_pmu = enable_pmu; #if IS_ENABLED(CONFIG_HYPERV) spin_lock_init(&kvm->arch.hv_root_tdp_lock); diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 9563d294f181..57a1280fa43b 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1133,6 +1133,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206 #define KVM_CAP_VM_GPA_BITS 207 #define KVM_CAP_XSAVE2 208 +#define KVM_CAP_PMU_CONFIG 209 #ifdef KVM_CAP_IRQ_ROUTING @@ -1972,6 +1973,9 @@ struct kvm_dirty_gfn { #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) +#define KVM_PMU_CONFIG_DISABLE (1 << 0) +#define KVM_PMU_CONFIG_VALID (KVM_PMU_CONFIG_DISABLE) + /** * struct kvm_stats_header - Header of per vm/vcpu binary statistics data. * @flags: Some extra information for header, always 0 for now. diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 9563d294f181..57a1280fa43b 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -1133,6 +1133,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206 #define KVM_CAP_VM_GPA_BITS 207 #define KVM_CAP_XSAVE2 208 +#define KVM_CAP_PMU_CONFIG 209 #ifdef KVM_CAP_IRQ_ROUTING @@ -1972,6 +1973,9 @@ struct kvm_dirty_gfn { #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) +#define KVM_PMU_CONFIG_DISABLE (1 << 0) +#define KVM_PMU_CONFIG_VALID (KVM_PMU_CONFIG_DISABLE) + /** * struct kvm_stats_header - Header of per vm/vcpu binary statistics data. * @flags: Some extra information for header, always 0 for now.
KVM_PMU_CONFIG_DISABLE can be used to disable PMU virtualization on individual x86 VMs. PMU configuration must be done prior to creating VCPUs. To enable future extension, KVM_CAP_PMU_CONFIG reports available settings when queried via check_extension. Since KVM_GET_SUPPORTED_CPUID reports the maximal CPUID information based on module parameters, usermode will need to adjust CPUID when disabling PMU virtualization on individual VMs. Signed-off-by: David Dunn <daviddunn@google.com> --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm/pmu.c | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 2 +- arch/x86/kvm/x86.c | 12 ++++++++++++ include/uapi/linux/kvm.h | 4 ++++ tools/include/uapi/linux/kvm.h | 4 ++++ 6 files changed, 23 insertions(+), 2 deletions(-)