On Wed, Aug 31, 2022 at 9:21 AM Aaron Lewis <aaronlewis@xxxxxxxxxx> wrote: > > When building a list of filter events, it can sometimes be a challenge > to fit all the events needed to adequately restrict the guest into the > limited space available in the pmu event filter. This stems from the > fact that the pmu event filter requires each raw event (i.e. event > select + unit mask) be listed, when the intention might be to restrict > the event select all together, regardless of it's unit mask. Instead > of increasing the number of filter events in the pmu event filter, add > a new encoding that is able to do a more generalized match on the unit > mask. > > Introduce masked events as a new encoding that the pmu event filter > understands in addition to raw events. A masked event has the fields: > mask, match, and exclude. When filtering based on these events, the > mask is applied to the guest's unit mask to see if it matches the match > value (i.e. unit_mask & mask == match). The exclude bit can then be > used to exclude events from that match. E.g. for a given event select, > if it's easier to say which unit mask values shouldn't be filtered, a > masked event can be set up to match all possible unit mask values, then > another masked event can be set up to match the unit mask values that > shouldn't be filtered. > > Userspace can query to see if this feature exists by looking for the > capability, KVM_CAP_PMU_EVENT_MASKED_EVENTS. > > This feature is enabled by setting the flags field in the pmu event > filter to KVM_PMU_EVENT_FLAG_MASKED_EVENTS. > > Events can be encoded by using KVM_PMU_EVENT_ENCODE_MASKED_ENTRY(). > > It is an error to have a bit set outside the valid bits for a masked > event, and calls to KVM_SET_PMU_EVENT_FILTER will return -EINVAL in > such cases, including the high bits (11:8) of the event select if > called on Intel. > > Signed-off-by: Aaron Lewis <aaronlewis@xxxxxxxxxx> > --- > Documentation/virt/kvm/api.rst | 81 ++++++++++++++++-- > arch/x86/include/uapi/asm/kvm.h | 28 ++++++ > arch/x86/kvm/pmu.c | 145 +++++++++++++++++++++++++++----- > arch/x86/kvm/pmu.h | 32 +++++-- > arch/x86/kvm/x86.c | 1 + > include/uapi/linux/kvm.h | 1 + > 6 files changed, 255 insertions(+), 33 deletions(-) > > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst > index abd7c32126ce..e7783e41c590 100644 > --- a/Documentation/virt/kvm/api.rst > +++ b/Documentation/virt/kvm/api.rst > @@ -5027,7 +5027,13 @@ using this ioctl. > :Architectures: x86 > :Type: vm ioctl > :Parameters: struct kvm_pmu_event_filter (in) > -:Returns: 0 on success, -1 on error > +:Returns: 0 on success, > + -EFAULT args[0] cannot be accessed. > + -EINVAL args[0] contains invalid data in the filter or filter events. > + Note: event validation is only done for modes where > + the flags field is non-zero. > + -E2BIG nevents is too large. > + -ENOMEM not enough memory to allocate the filter. I assume that the ioctl returns -1 on error, but that errno is set to one of the errors listed above (in its positive form). So... :Returns: 0 on success, -1 on error Errors: ====== ============================================ EFAULT args[0] cannot be accessed EINVAL args[0] contains invalid data in the filter or filter events E2BIG nevents is too large EBUSY not enough memory to allocate the filter ====== ============================================ > @@ -647,7 +719,34 @@ static void convert_to_filter_events(struct kvm_pmu_event_filter *filter) > for (i = 0; i < filter->nevents; i++) { > u64 e = filter->events[i]; > > - filter->events[i] = encode_filter_entry(e); > + filter->events[i] = encode_filter_entry(e, filter->flags); > + } > +} > + > +/* > + * Sort will order the list by exclude, then event select. This function will > + * then index the sublists of event selects such that when a search is done on > + * the list, the head of the event select sublist is returned. This simpilfies Nit: simplifies With the documentation changes, Reviewed-by: Jim Mattson <jmattson@xxxxxxxxxx>