Commit 30cd8604 authored by Eric Hankland's avatar Eric Hankland Committed by Paolo Bonzini

KVM: x86: Add fixed counters to PMU filter

Updates KVM_CAP_PMU_EVENT_FILTER so it can also whitelist or blacklist
fixed counters.
Signed-off-by: default avatarEric Hankland <ehankland@google.com>
[No need to check padding fields for zero. - Paolo]
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 88dddc11
...@@ -4090,17 +4090,22 @@ Parameters: struct kvm_pmu_event_filter (in) ...@@ -4090,17 +4090,22 @@ Parameters: struct kvm_pmu_event_filter (in)
Returns: 0 on success, -1 on error Returns: 0 on success, -1 on error
struct kvm_pmu_event_filter { struct kvm_pmu_event_filter {
__u32 action; __u32 action;
__u32 nevents; __u32 nevents;
__u64 events[0]; __u32 fixed_counter_bitmap;
__u32 flags;
__u32 pad[4];
__u64 events[0];
}; };
This ioctl restricts the set of PMU events that the guest can program. This ioctl restricts the set of PMU events that the guest can program.
The argument holds a list of events which will be allowed or denied. The argument holds a list of events which will be allowed or denied.
The eventsel+umask of each event the guest attempts to program is compared The eventsel+umask of each event the guest attempts to program is compared
against the events field to determine whether the guest should have access. against the events field to determine whether the guest should have access.
This only affects general purpose counters; fixed purpose counters can The events field only controls general purpose counters; fixed purpose
be disabled by changing the perfmon CPUID leaf. counters are controlled by the fixed_counter_bitmap.
No flags are defined yet, the field must be zero.
Valid values for 'action': Valid values for 'action':
#define KVM_PMU_EVENT_ALLOW 0 #define KVM_PMU_EVENT_ALLOW 0
......
...@@ -435,9 +435,12 @@ struct kvm_nested_state { ...@@ -435,9 +435,12 @@ struct kvm_nested_state {
/* for KVM_CAP_PMU_EVENT_FILTER */ /* for KVM_CAP_PMU_EVENT_FILTER */
struct kvm_pmu_event_filter { struct kvm_pmu_event_filter {
__u32 action; __u32 action;
__u32 nevents; __u32 nevents;
__u64 events[0]; __u32 fixed_counter_bitmap;
__u32 flags;
__u32 pad[4];
__u64 events[0];
}; };
#define KVM_PMU_EVENT_ALLOW 0 #define KVM_PMU_EVENT_ALLOW 0
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include "lapic.h" #include "lapic.h"
#include "pmu.h" #include "pmu.h"
/* This keeps the total size of the filter under 4k. */ /* This is enough to filter the vast majority of currently defined events. */
#define KVM_PMU_EVENT_FILTER_MAX_EVENTS 63 #define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300
/* NOTE: /* NOTE:
* - Each perf counter is defined as "struct kvm_pmc"; * - Each perf counter is defined as "struct kvm_pmc";
...@@ -206,12 +206,24 @@ void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx) ...@@ -206,12 +206,24 @@ void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx)
{ {
unsigned en_field = ctrl & 0x3; unsigned en_field = ctrl & 0x3;
bool pmi = ctrl & 0x8; bool pmi = ctrl & 0x8;
struct kvm_pmu_event_filter *filter;
struct kvm *kvm = pmc->vcpu->kvm;
pmc_stop_counter(pmc); pmc_stop_counter(pmc);
if (!en_field || !pmc_is_enabled(pmc)) if (!en_field || !pmc_is_enabled(pmc))
return; return;
filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu);
if (filter) {
if (filter->action == KVM_PMU_EVENT_DENY &&
test_bit(idx, (ulong *)&filter->fixed_counter_bitmap))
return;
if (filter->action == KVM_PMU_EVENT_ALLOW &&
!test_bit(idx, (ulong *)&filter->fixed_counter_bitmap))
return;
}
pmc_reprogram_counter(pmc, PERF_TYPE_HARDWARE, pmc_reprogram_counter(pmc, PERF_TYPE_HARDWARE,
kvm_x86_ops->pmu_ops->find_fixed_event(idx), kvm_x86_ops->pmu_ops->find_fixed_event(idx),
!(en_field & 0x2), /* exclude user */ !(en_field & 0x2), /* exclude user */
...@@ -385,6 +397,9 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp) ...@@ -385,6 +397,9 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
tmp.action != KVM_PMU_EVENT_DENY) tmp.action != KVM_PMU_EVENT_DENY)
return -EINVAL; return -EINVAL;
if (tmp.flags != 0)
return -EINVAL;
if (tmp.nevents > KVM_PMU_EVENT_FILTER_MAX_EVENTS) if (tmp.nevents > KVM_PMU_EVENT_FILTER_MAX_EVENTS)
return -E2BIG; return -E2BIG;
...@@ -406,8 +421,8 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp) ...@@ -406,8 +421,8 @@ int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp)
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
synchronize_srcu_expedited(&kvm->srcu); synchronize_srcu_expedited(&kvm->srcu);
r = 0; r = 0;
cleanup: cleanup:
kfree(filter); kfree(filter);
return r; return r;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment