Introduce the kvm-pmu-filter object and support the PMU event with raw format.
The raw format, as a native PMU event code representation, can be used for several architectures. 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) * Define three-level sections with new accelerator.json. (Markus) * QAPI style fixes: - KVMPMU* stuff -> KvmPmu*. - KVMPMUFilterProperty -> KVMPMUFilterProperties. - KVMPMUEventEncodeFmt -> KvmPmuEventFormat. - drop prefix in KvmPmuFilterAction and KvmPmuEventFormat. * Bump up the supported QAPI version to v10.1. * Add Tested-by from Yi. Changes since RFC v1: * Make "action" as a global (per filter object) item, not a per-event parameter. (Dapeng) * Bump up the supported QAPI version to v10.0. --- MAINTAINERS | 2 + accel/kvm/kvm-pmu.c | 114 +++++++++++++++++++++++++++++++++++++++ accel/kvm/meson.build | 1 + include/system/kvm-pmu.h | 35 ++++++++++++ qapi/accelerator.json | 14 +++++ qapi/kvm.json | 84 +++++++++++++++++++++++++++++ qapi/meson.build | 1 + qapi/qapi-schema.json | 1 + qapi/qom.json | 3 ++ 9 files changed, 255 insertions(+) create mode 100644 accel/kvm/kvm-pmu.c create mode 100644 include/system/kvm-pmu.h create mode 100644 qapi/accelerator.json create mode 100644 qapi/kvm.json diff --git a/MAINTAINERS b/MAINTAINERS index d54b5578f883..3ca551025fb8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -434,6 +434,7 @@ F: accel/kvm/ F: accel/stubs/kvm-stub.c F: include/hw/kvm/ F: include/system/kvm*.h +F: qapi/kvm.json F: scripts/kvm/kvm_flightrecorder ARM KVM CPUs @@ -503,6 +504,7 @@ F: accel/Makefile.objs F: accel/stubs/Makefile.objs F: cpu-common.c F: cpu-target.c +F: qapi/accelerator.c F: system/cpus.c Apple Silicon HVF CPUs diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c new file mode 100644 index 000000000000..22f749bf9183 --- /dev/null +++ b/accel/kvm/kvm-pmu.c @@ -0,0 +1,114 @@ +/* + * QEMU KVM PMU Related Abstractions + * + * Copyright (C) 2025 Intel Corporation. + * + * Author: Zhao Liu <zhao1....@intel.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" + +#include "qapi/error.h" +#include "qapi/qapi-visit-kvm.h" +#include "qemu/cutils.h" +#include "qom/object_interfaces.h" +#include "system/kvm-pmu.h" + +static void kvm_pmu_filter_set_action(Object *obj, int value, + Error **errp G_GNUC_UNUSED) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + + filter->action = value; +} + +static int kvm_pmu_filter_get_action(Object *obj, + Error **errp G_GNUC_UNUSED) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + + return filter->action; +} + +static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + + visit_type_KvmPmuFilterEventList(v, name, &filter->events, errp); +} + +static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + KvmPmuFilterEventList *head = NULL, *old_head, *node; + int nevents = 0; + + old_head = filter->events; + if (!visit_type_KvmPmuFilterEventList(v, name, &head, errp)) { + return; + } + + for (node = head; node; node = node->next) { + switch (node->value->format) { + case KVM_PMU_EVENT_FORMAT_RAW: + break; + default: + g_assert_not_reached(); + } + + nevents++; + } + + filter->nevents = nevents; + filter->events = head; + qapi_free_KvmPmuFilterEventList(old_head); + return; +} + +static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_enum(oc, "action", "KvmPmuFilterAction", + &KvmPmuFilterAction_lookup, + kvm_pmu_filter_get_action, + kvm_pmu_filter_set_action); + object_class_property_set_description(oc, "action", + "KVM PMU event action"); + + object_class_property_add(oc, "events", "KvmPmuFilterEventList", + kvm_pmu_filter_get_event, + kvm_pmu_filter_set_event, + NULL, NULL); + object_class_property_set_description(oc, "events", + "KVM PMU event list"); +} + +static void kvm_pmu_filter_instance_init(Object *obj) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + + filter->action = KVM_PMU_FILTER_ACTION_ALLOW; + filter->nevents = 0; +} + +static const TypeInfo kvm_pmu_filter_info = { + .parent = TYPE_OBJECT, + .name = TYPE_KVM_PMU_FILTER, + .class_init = kvm_pmu_filter_class_init, + .instance_size = sizeof(KVMPMUFilter), + .instance_init = kvm_pmu_filter_instance_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void kvm_pmu_event_register_type(void) +{ + type_register_static(&kvm_pmu_filter_info); +} + +type_init(kvm_pmu_event_register_type); diff --git a/accel/kvm/meson.build b/accel/kvm/meson.build index 397a1fe1fd1e..dfab2854f3a8 100644 --- a/accel/kvm/meson.build +++ b/accel/kvm/meson.build @@ -2,6 +2,7 @@ kvm_ss = ss.source_set() kvm_ss.add(files( 'kvm-all.c', 'kvm-accel-ops.c', + 'kvm-pmu.c', )) specific_ss.add_all(when: 'CONFIG_KVM', if_true: kvm_ss) diff --git a/include/system/kvm-pmu.h b/include/system/kvm-pmu.h new file mode 100644 index 000000000000..818fa309c191 --- /dev/null +++ b/include/system/kvm-pmu.h @@ -0,0 +1,35 @@ +/* + * QEMU KVM PMU Related Abstraction Header + * + * Copyright (C) 2025 Intel Corporation. + * + * Author: Zhao Liu <zhao1....@intel.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef KVM_PMU_H +#define KVM_PMU_H + +#include "qapi/qapi-types-kvm.h" +#include "qom/object.h" + +#define TYPE_KVM_PMU_FILTER "kvm-pmu-filter" +OBJECT_DECLARE_SIMPLE_TYPE(KVMPMUFilter, KVM_PMU_FILTER) + +/** + * KVMPMUFilter: + * @action: action that KVM PMU filter will take for selected PMU events. + * @nevents: number of PMU event entries listed in @events + * @events: list of PMU event entries. A PMU event entry may represent one + * event or multiple events due to its format. + */ +struct KVMPMUFilter { + Object parent_obj; + + KvmPmuFilterAction action; + uint32_t nevents; + KvmPmuFilterEventList *events; +}; + +#endif /* KVM_PMU_H */ diff --git a/qapi/accelerator.json b/qapi/accelerator.json new file mode 100644 index 000000000000..1fe0d64be113 --- /dev/null +++ b/qapi/accelerator.json @@ -0,0 +1,14 @@ +# -*- Mode: Python -*- +# vim: filetype=python +# +# Copyright (C) 2025 Intel Corporation. +# +# Author: Zhao Liu <zhao1....@intel.com> +# +# SPDX-License-Identifier: GPL-2.0-or-later + +## +# = Accelerators +## + +{ 'include': 'kvm.json' } diff --git a/qapi/kvm.json b/qapi/kvm.json new file mode 100644 index 000000000000..1861d86a9726 --- /dev/null +++ b/qapi/kvm.json @@ -0,0 +1,84 @@ +# -*- Mode: Python -*- +# vim: filetype=python +# +# Copyright (C) 2025 Intel Corporation. +# +# Author: Zhao Liu <zhao1....@intel.com> +# +# SPDX-License-Identifier: GPL-2.0-or-later + +## +# == KVM +## + +## +# === PMU stuff (KVM related) +## + +## +# @KvmPmuFilterAction: +# +# Actions that KVM PMU filter supports. +# +# @deny: disable the PMU event/counter in KVM PMU filter. +# +# @allow: enable the PMU event/counter in KVM PMU filter. +# +# Since 10.1 +## +{ 'enum': 'KvmPmuFilterAction', + 'data': ['allow', 'deny'] } + +## +# @KvmPmuEventFormat: +# +# Encoding formats of PMU event that QEMU/KVM supports. +# +# @raw: the encoded event code that KVM can directly consume. +# +# Since 10.1 +## +{ 'enum': 'KvmPmuEventFormat', + 'data': ['raw'] } + +## +# @KvmPmuRawEvent: +# +# Raw PMU event code. +# +# @code: the raw value that has been encoded, and QEMU could deliver +# to KVM directly. +# +# Since 10.1 +## +{ 'struct': 'KvmPmuRawEvent', + 'data': { 'code': 'uint64' } } + +## +# @KvmPmuFilterEvent: +# +# PMU event filtered by KVM. +# +# @format: PMU event format. +# +# Since 10.1 +## +{ 'union': 'KvmPmuFilterEvent', + 'base': { 'format': 'KvmPmuEventFormat' }, + 'discriminator': 'format', + 'data': { 'raw': 'KvmPmuRawEvent' } } + +## +# @KvmPmuFilterProperties: +# +# Properties of KVM PMU Filter. +# +# @action: action that KVM PMU filter will take for selected PMU events. +# +# @events: list of selected PMU events. +# +# Since 10.1 +## +{ 'struct': 'KvmPmuFilterProperties', + 'data': { 'action': 'KvmPmuFilterAction', + '*events': ['KvmPmuFilterEvent'] } } diff --git a/qapi/meson.build b/qapi/meson.build index eadde4db307f..dba27ebc7489 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -37,6 +37,7 @@ qapi_all_modules = [ 'error', 'introspect', 'job', + 'kvm', 'machine-common', 'machine', 'machine-target', diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index c41c01eb2ab9..c7fed7940af7 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -66,6 +66,7 @@ { 'include': 'compat.json' } { 'include': 'control.json' } { 'include': 'introspect.json' } +{ 'include': 'accelerator.json' } { 'include': 'qom.json' } { 'include': 'qdev.json' } { 'include': 'machine-common.json' } diff --git a/qapi/qom.json b/qapi/qom.json index 28ce24cd8d08..517f4c06c260 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -8,6 +8,7 @@ { 'include': 'block-core.json' } { 'include': 'common.json' } { 'include': 'crypto.json' } +{ 'include': 'kvm.json' } ## # = QEMU Object Model (QOM) @@ -1108,6 +1109,7 @@ 'if': 'CONFIG_LINUX' }, 'iommufd', 'iothread', + 'kvm-pmu-filter', 'main-loop', { 'name': 'memory-backend-epc', 'if': 'CONFIG_LINUX' }, @@ -1183,6 +1185,7 @@ 'if': 'CONFIG_LINUX' }, 'iommufd': 'IOMMUFDProperties', 'iothread': 'IothreadProperties', + 'kvm-pmu-filter': 'KvmPmuFilterProperties', 'main-loop': 'MainLoopProperties', 'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties', 'if': 'CONFIG_LINUX' }, -- 2.34.1