KVM: x86: Provide per VM capability for disabling PMU virtualization

Add a new capability, KVM_CAP_PMU_CAPABILITY, that takes a bitmask of
settings/features to allow userspace to configure PMU virtualization on
a per-VM basis.  For now, support a single flag, KVM_PMU_CAP_DISABLE,
to allow disabling PMU virtualization for a VM even when KVM is configured
with enable_pmu=true a module level.

To keep KVM simple, disallow changing VM's PMU configuration after vCPUs
have been created.

Signed-off-by: David Dunn <daviddunn@google.com>
Message-Id: <20220223225743.2703915-2-daviddunn@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
David Dunn 2022-02-23 22:57:41 +00:00 committed by Paolo Bonzini
parent 925088781e
commit ba7bb663f5
7 changed files with 50 additions and 2 deletions

View File

@ -7643,3 +7643,25 @@ The argument to KVM_ENABLE_CAP is also a bitmask, and must be a subset
of the result of KVM_CHECK_EXTENSION. KVM will forward to userspace of the result of KVM_CHECK_EXTENSION. KVM will forward to userspace
the hypercalls whose corresponding bit is in the argument, and return the hypercalls whose corresponding bit is in the argument, and return
ENOSYS for the others. ENOSYS for the others.
8.35 KVM_CAP_PMU_CAPABILITY
---------------------------
:Capability KVM_CAP_PMU_CAPABILITY
:Architectures: x86
:Type: vm
:Parameters: arg[0] is bitmask of PMU virtualization capabilities.
:Returns 0 on success, -EINVAL when arg[0] contains invalid bits
This capability alters PMU virtualization in KVM.
Calling KVM_CHECK_EXTENSION for this capability returns a bitmask of
PMU virtualization capabilities that can be adjusted on a VM.
The argument to KVM_ENABLE_CAP is also a bitmask and selects specific
PMU virtualization capabilities to be applied to the VM. This can
only be invoked on a VM prior to the creation of VCPUs.
At this time, KVM_PMU_CAP_DISABLE is the only capability. Setting
this capability will disable PMU virtualization for that VM. Usermode
should adjust CPUID leaf 0xA to reflect that the PMU is disabled.

View File

@ -1147,6 +1147,7 @@ struct kvm_arch {
bool exception_payload_enabled; bool exception_payload_enabled;
bool bus_lock_detection_enabled; bool bus_lock_detection_enabled;
bool enable_pmu;
/* /*
* If exit_on_emulation_error is set, and the in-kernel instruction * If exit_on_emulation_error is set, and the in-kernel instruction
* emulator fails to emulate an instruction, allow userspace * emulator fails to emulate an instruction, allow userspace

View File

@ -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); struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu);
if (!enable_pmu) if (!vcpu->kvm->arch.enable_pmu)
return NULL; return NULL;
switch (msr) { switch (msr) {

View File

@ -487,7 +487,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
pmu->reserved_bits = 0xffffffff00200000ull; pmu->reserved_bits = 0xffffffff00200000ull;
entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); entry = kvm_find_cpuid_entry(vcpu, 0xa, 0);
if (!entry || !enable_pmu) if (!entry || !vcpu->kvm->arch.enable_pmu)
return; return;
eax.full = entry->eax; eax.full = entry->eax;
edx.full = entry->edx; edx.full = entry->edx;

View File

@ -110,6 +110,8 @@ static u64 __read_mostly cr4_reserved_bits = CR4_RESERVED_BITS;
#define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE) #define KVM_EXIT_HYPERCALL_VALID_MASK (1 << KVM_HC_MAP_GPA_RANGE)
#define KVM_CAP_PMU_VALID_MASK KVM_PMU_CAP_DISABLE
#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \ #define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \
KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK) KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
@ -4330,6 +4332,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
if (r < sizeof(struct kvm_xsave)) if (r < sizeof(struct kvm_xsave))
r = sizeof(struct kvm_xsave); r = sizeof(struct kvm_xsave);
break; break;
case KVM_CAP_PMU_CAPABILITY:
r = enable_pmu ? KVM_CAP_PMU_VALID_MASK : 0;
break;
} }
default: default:
break; break;
@ -6004,6 +6009,18 @@ split_irqchip_unlock:
kvm->arch.exit_on_emulation_error = cap->args[0]; kvm->arch.exit_on_emulation_error = cap->args[0];
r = 0; r = 0;
break; break;
case KVM_CAP_PMU_CAPABILITY:
r = -EINVAL;
if (!enable_pmu || (cap->args[0] & ~KVM_CAP_PMU_VALID_MASK))
break;
mutex_lock(&kvm->lock);
if (!kvm->created_vcpus) {
kvm->arch.enable_pmu = !(cap->args[0] & KVM_PMU_CAP_DISABLE);
r = 0;
}
mutex_unlock(&kvm->lock);
break;
default: default:
r = -EINVAL; r = -EINVAL;
break; break;
@ -11586,6 +11603,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
kvm->arch.guest_can_read_msr_platform_info = true; kvm->arch.guest_can_read_msr_platform_info = true;
kvm->arch.enable_pmu = enable_pmu;
#if IS_ENABLED(CONFIG_HYPERV) #if IS_ENABLED(CONFIG_HYPERV)
spin_lock_init(&kvm->arch.hv_root_tdp_lock); spin_lock_init(&kvm->arch.hv_root_tdp_lock);

View File

@ -1142,6 +1142,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_SYS_ATTRIBUTES 209 #define KVM_CAP_SYS_ATTRIBUTES 209
#define KVM_CAP_PPC_AIL_MODE_3 210 #define KVM_CAP_PPC_AIL_MODE_3 210
#define KVM_CAP_S390_MEM_OP_EXTENSION 211 #define KVM_CAP_S390_MEM_OP_EXTENSION 211
#define KVM_CAP_PMU_CAPABILITY 212
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
@ -1978,6 +1979,8 @@ struct kvm_dirty_gfn {
#define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0)
#define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1)
#define KVM_PMU_CAP_DISABLE (1 << 0)
/** /**
* struct kvm_stats_header - Header of per vm/vcpu binary statistics data. * struct kvm_stats_header - Header of per vm/vcpu binary statistics data.
* @flags: Some extra information for header, always 0 for now. * @flags: Some extra information for header, always 0 for now.

View File

@ -1135,6 +1135,8 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_XSAVE2 208 #define KVM_CAP_XSAVE2 208
#define KVM_CAP_SYS_ATTRIBUTES 209 #define KVM_CAP_SYS_ATTRIBUTES 209
#define KVM_CAP_PPC_AIL_MODE_3 210 #define KVM_CAP_PPC_AIL_MODE_3 210
#define KVM_CAP_S390_MEM_OP_EXTENSION 211
#define KVM_CAP_PMU_CAPABILITY 212
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
@ -1971,6 +1973,8 @@ struct kvm_dirty_gfn {
#define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0)
#define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1)
#define KVM_PMU_CAP_DISABLE (1 << 0)
/** /**
* struct kvm_stats_header - Header of per vm/vcpu binary statistics data. * struct kvm_stats_header - Header of per vm/vcpu binary statistics data.
* @flags: Some extra information for header, always 0 for now. * @flags: Some extra information for header, always 0 for now.