KVM_SET_PMU_EVENT_FILTER of x86 KVM supports masked events mode, which accepts masked entry format event to flexibly represent a group of PMU events.
Support masked entry format in kvm-pmu-filter object and handle this in i386 kvm codes. Signed-off-by: Zhao Liu <zhao1....@intel.com> Tested-by: Yi Lai <yi1....@intel.com> --- Changes since RFC v2: * Drop hexadecimal variants and support numeric version in QAPI directly. (Daniel) * Add Tested-by from Yi. * Add documentation in qemu-options.hx. * QAPI style fix: - KVMPMU* stuff -> KvmPmu*. * Bump up the supported QAPI version to v10.1. Changes since RFC v1: * Bump up the supported QAPI version to v10.0. --- accel/kvm/kvm-pmu.c | 14 ++++++++++++++ qapi/kvm.json | 29 +++++++++++++++++++++++++++-- qemu-options.hx | 13 +++++++++++++ target/i386/kvm/kvm.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c index fa73ef428e59..9205907d1779 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -71,6 +71,20 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name, /* No need to check the range of umask since it's uint8_t. */ break; } + case KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY: { + if (event->u.x86_masked_entry.select > UINT12_MAX) { + error_setg(errp, + "Parameter 'select' out of range (%d).", + UINT12_MAX); + goto fail; + } + + /* + * No need to check the range of match or mask fields since + * they're both uint8_t. + */ + break; + } default: g_assert_not_reached(); } diff --git a/qapi/kvm.json b/qapi/kvm.json index cb151ca82e5c..1b523e058731 100644 --- a/qapi/kvm.json +++ b/qapi/kvm.json @@ -38,10 +38,13 @@ # # @x86-select-umask: standard x86 encoding format with select and umask. # +# @x86-masked-entry: KVM's masked entry format for x86, which could +# mask bunch of events. +# # Since 10.1 ## { 'enum': 'KvmPmuEventFormat', - 'data': ['raw', 'x86-select-umask'] } + 'data': ['raw', 'x86-select-umask', 'x86-masked-entry'] } ## # @KvmPmuRawEvent: @@ -70,6 +73,27 @@ 'data': { 'select': 'uint16', 'umask': 'uint8' } } +## +# @KvmPmuX86MaskedEntry: +# +# x86 PMU events encoding in KVM masked entry format. +# +# @select: x86 PMU event select, which is a 12-bit unsigned number. +# +# @match: umask match. +# +# @mask: umask mask. +# +# @exclude: whether the matched events are excluded. +# +# Since 10.1 +## +{ 'struct': 'KvmPmuX86MaskedEntry', + 'data': { 'select': 'uint16', + 'match': 'uint8', + 'mask': 'uint8', + 'exclude': 'bool' } } + ## # @KvmPmuFilterEvent: # @@ -83,7 +107,8 @@ 'base': { 'format': 'KvmPmuEventFormat' }, 'discriminator': 'format', 'data': { 'raw': 'KvmPmuRawEvent', - 'x86-select-umask': 'KvmPmuX86SelectUmaskEvent' } } + 'x86-select-umask': 'KvmPmuX86SelectUmaskEvent', + 'x86-masked-entry': 'KvmPmuX86MaskedEntry' } } ## # @KvmPmuFilterProperties: diff --git a/qemu-options.hx b/qemu-options.hx index 5dcce067d8dd..bb89198971e0 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -6183,6 +6183,19 @@ SRST ``{"format":"x86-select-umask","select":event_select,"umask":event_umask}`` Specify the single x86 PMU event with select and umask fields. + ``{"format":"x86-masked-entry","select":event_select,"mask":entry_mask,"match":entry_match,"exclude":exclude}`` + Configure a set of x86 PMU events that share the same + ``select`` field. The events are determined by a formula + that checks if an event's umask is included: + + :: + + event_umask & entry_mask == entry_match + + The "exclude" parameter controls whether to exclude the + events selected based on the above formula, under the given + "select" field. + An example KVM PMU filter object would look like: .. parsed-literal:: diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 0d36ccf250ed..8786501e9c7e 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5978,6 +5978,13 @@ static bool kvm_config_pmu_event(KVMPMUFilter *filter, code = X86_PMU_RAW_EVENT(event->u.x86_select_umask.select, event->u.x86_select_umask.umask); break; + case KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY: + code = KVM_PMU_ENCODE_MASKED_ENTRY( + event->u.x86_masked_entry.select, + event->u.x86_masked_entry.mask, + event->u.x86_masked_entry.match, + event->u.x86_masked_entry.exclude ? 1 : 0); + break; default: g_assert_not_reached(); } @@ -6009,6 +6016,17 @@ static int kvm_install_pmu_event_filter(KVMState *s) g_assert_not_reached(); } + kvm_filter->flags = filter->events->value->format == + KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY ? + KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0; + + if (kvm_filter->flags == KVM_PMU_EVENT_FLAG_MASKED_EVENTS && + !kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_MASKED_EVENTS)) { + error_report("Masked entry format of PMU event " + "is not supported by Host."); + goto fail; + } + if (!kvm_config_pmu_event(filter, kvm_filter)) { goto fail; } @@ -6636,6 +6654,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, { KVMPMUFilter *filter = KVM_PMU_FILTER(child); KvmPmuFilterEventList *events = filter->events; + uint32_t base_flag; if (!filter->nevents) { error_setg(errp, @@ -6643,12 +6662,21 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, return; } + /* Pick the first event's flag as the base one. */ + base_flag = events->value->format == + KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY ? + KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0; while (events) { KvmPmuFilterEvent *event = events->value; + uint32_t flag; switch (event->format) { case KVM_PMU_EVENT_FORMAT_RAW: case KVM_PMU_EVENT_FORMAT_X86_SELECT_UMASK: + flag = 0; + break; + case KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY: + flag = KVM_PMU_EVENT_FLAG_MASKED_EVENTS; break; default: error_setg(errp, @@ -6657,6 +6685,13 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, return; } + if (flag != base_flag) { + error_setg(errp, + "Masked entry format cannot be mixed with " + "other formats."); + return; + } + events = events->next; } } -- 2.34.1