Skip to content

Commit 3e51822

Browse files
Dapeng Misean-jc
authored andcommitted
KVM: x86/pmu: Start stubbing in mediated PMU support
Introduce enable_mediated_pmu as a global variable, with the intent of exposing it to userspace a vendor module parameter, to control and reflect mediated vPMU support. Wire up the perf plumbing to create+release a mediated PMU, but defer exposing the parameter to userspace until KVM support for a mediated PMUs is fully landed. To (a) minimize compatibility issues, (b) to give userspace a chance to opt out of the restrictive side-effects of perf_create_mediated_pmu(), and (c) to avoid adding new dependencies between enabling an in-kernel irqchip and a mediated vPMU, defer "creating" a mediated PMU in perf until the first vCPU is created. Regarding userspace compatibility, an alternative solution would be to make the mediated PMU fully opt-in, e.g. to avoid unexpected failure due to perf_create_mediated_pmu() failing. Ironically, that approach creates an even bigger compatibility issue, as turning on enable_mediated_pmu would silently break VMMs that don't utilize KVM_CAP_PMU_CAPABILITY (well, silently until the guest tried to access PMU assets). Regarding an in-kernel irqchip, create a mediated PMU if and only if the VM has an in-kernel local APIC, as the mediated PMU will take a hard dependency on forwarding PMIs to the guest without bouncing through host userspace. Silently "drop" the PMU instead of rejecting KVM_CREATE_VCPU, as KVM's existing vPMU support doesn't function correctly if the local APIC is emulated by userspace, e.g. PMIs will never be delivered. I.e. it's far, far more likely that rejecting KVM_CREATE_VCPU would cause problems, e.g. for tests or userspace daemons that just want to probe basic KVM functionality. Note! Deliberately make mediated PMU creation "sticky", i.e. don't unwind it on failure to create a vCPU. Practically speaking, there's no harm to having a VM with a mediated PMU and no vCPUs. To avoid an "impossible" VM setup, reject KVM_CAP_PMU_CAPABILITY if a mediated PMU has been created, i.e. don't let userspace disable PMU support after failed vCPU creation (with PMU support enabled). Defer vendor specific requirements and constraints to the future. Suggested-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> Co-developed-by: Mingwei Zhang <mizhang@google.com> Signed-off-by: Mingwei Zhang <mizhang@google.com> Tested-by: Xudong Hao <xudong.hao@intel.com> Co-developed-by: Sean Christopherson <seanjc@google.com> Tested-by: Manali Shukla <manali.shukla@amd.com> Link: https://patch.msgid.link/20251206001720.468579-17-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 4b24910 commit 3e51822

5 files changed

Lines changed: 48 additions & 2 deletions

File tree

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,7 @@ struct kvm_arch {
14841484

14851485
bool bus_lock_detection_enabled;
14861486
bool enable_pmu;
1487+
bool created_mediated_pmu;
14871488

14881489
u32 notify_window;
14891490
u32 notify_vmexit_flags;

arch/x86/kvm/pmu.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
135135
enable_pmu = false;
136136
}
137137

138+
if (!enable_pmu || !enable_mediated_pmu || !kvm_host_pmu.mediated ||
139+
!pmu_ops->is_mediated_pmu_supported(&kvm_host_pmu))
140+
enable_mediated_pmu = false;
141+
138142
if (!enable_pmu) {
139143
memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap));
140144
return;

arch/x86/kvm/pmu.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ struct kvm_pmu_ops {
3737
void (*deliver_pmi)(struct kvm_vcpu *vcpu);
3838
void (*cleanup)(struct kvm_vcpu *vcpu);
3939

40+
bool (*is_mediated_pmu_supported)(struct x86_pmu_capability *host_pmu);
41+
4042
const u64 EVENTSEL_EVENT;
4143
const int MAX_NR_GP_COUNTERS;
4244
const int MIN_NR_GP_COUNTERS;
@@ -58,6 +60,11 @@ static inline bool kvm_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu)
5860
return pmu->version > 1;
5961
}
6062

63+
static inline bool kvm_vcpu_has_mediated_pmu(struct kvm_vcpu *vcpu)
64+
{
65+
return enable_mediated_pmu && vcpu_to_pmu(vcpu)->version;
66+
}
67+
6168
/*
6269
* KVM tracks all counters in 64-bit bitmaps, with general purpose counters
6370
* mapped to bits 31:0 and fixed counters mapped to 63:32, e.g. fixed counter 0

arch/x86/kvm/x86.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ bool __read_mostly enable_pmu = true;
183183
EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_pmu);
184184
module_param(enable_pmu, bool, 0444);
185185

186+
/* Enable/disabled mediated PMU virtualization. */
187+
bool __read_mostly enable_mediated_pmu;
188+
EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_mediated_pmu);
189+
186190
bool __read_mostly eager_page_split = true;
187191
module_param(eager_page_split, bool, 0644);
188192

@@ -6854,7 +6858,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
68546858
break;
68556859

68566860
mutex_lock(&kvm->lock);
6857-
if (!kvm->created_vcpus) {
6861+
if (!kvm->created_vcpus && !kvm->arch.created_mediated_pmu) {
68586862
kvm->arch.enable_pmu = !(cap->args[0] & KVM_PMU_CAP_DISABLE);
68596863
r = 0;
68606864
}
@@ -12641,8 +12645,13 @@ static int sync_regs(struct kvm_vcpu *vcpu)
1264112645
return 0;
1264212646
}
1264312647

12648+
#define PERF_MEDIATED_PMU_MSG \
12649+
"Failed to enable mediated vPMU, try disabling system wide perf events and nmi_watchdog.\n"
12650+
1264412651
int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
1264512652
{
12653+
int r;
12654+
1264612655
if (kvm_check_tsc_unstable() && kvm->created_vcpus)
1264712656
pr_warn_once("SMP vm created on host with unstable TSC; "
1264812657
"guest TSC will not be reliable\n");
@@ -12653,7 +12662,29 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
1265312662
if (id >= kvm->arch.max_vcpu_ids)
1265412663
return -EINVAL;
1265512664

12656-
return kvm_x86_call(vcpu_precreate)(kvm);
12665+
/*
12666+
* Note, any actions done by .vcpu_create() must be idempotent with
12667+
* respect to creating multiple vCPUs, and therefore are not undone if
12668+
* creating a vCPU fails (including failure during pre-create).
12669+
*/
12670+
r = kvm_x86_call(vcpu_precreate)(kvm);
12671+
if (r)
12672+
return r;
12673+
12674+
if (enable_mediated_pmu && kvm->arch.enable_pmu &&
12675+
!kvm->arch.created_mediated_pmu) {
12676+
if (irqchip_in_kernel(kvm)) {
12677+
r = perf_create_mediated_pmu();
12678+
if (r) {
12679+
pr_warn_ratelimited(PERF_MEDIATED_PMU_MSG);
12680+
return r;
12681+
}
12682+
kvm->arch.created_mediated_pmu = true;
12683+
} else {
12684+
kvm->arch.enable_pmu = false;
12685+
}
12686+
}
12687+
return 0;
1265712688
}
1265812689

1265912690
int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
@@ -13319,6 +13350,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
1331913350
__x86_set_memory_region(kvm, TSS_PRIVATE_MEMSLOT, 0, 0);
1332013351
mutex_unlock(&kvm->slots_lock);
1332113352
}
13353+
if (kvm->arch.created_mediated_pmu)
13354+
perf_release_mediated_pmu();
1332213355
kvm_destroy_vcpus(kvm);
1332313356
kvm_free_msr_filter(srcu_dereference_check(kvm->arch.msr_filter, &kvm->srcu, 1));
1332413357
#ifdef CONFIG_KVM_IOAPIC

arch/x86/kvm/x86.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ extern struct kvm_caps kvm_caps;
470470
extern struct kvm_host_values kvm_host;
471471

472472
extern bool enable_pmu;
473+
extern bool enable_mediated_pmu;
473474

474475
/*
475476
* Get a filtered version of KVM's supported XCR0 that strips out dynamic

0 commit comments

Comments
 (0)