@@ -439,6 +439,7 @@ F: accel/kvm/
F: accel/stubs/kvm-stub.c
F: include/hw/kvm/
F: include/sysemu/kvm*.h
+F: qapi/kvm.json
F: scripts/kvm/kvm_flightrecorder
ARM KVM CPUs
new file mode 100644
@@ -0,0 +1,143 @@
+/*
+ * QEMU KVM PMU Abstractions
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qapi/error.h"
+#include "qapi/qapi-visit-kvm.h"
+#include "qemu/cutils.h"
+#include "qom/object_interfaces.h"
+#include "sysemu/kvm-pmu.h"
+
+static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+ KVMPMUFilterEventList *node;
+ KVMPMUFilterEventVariantList *head = NULL;
+ KVMPMUFilterEventVariantList **tail = &head;
+
+ for (node = filter->events; node; node = node->next) {
+ KVMPMUFilterEventVariant *str_event;
+ KVMPMUFilterEvent *event = node->value;
+
+ str_event = g_new(KVMPMUFilterEventVariant, 1);
+ str_event->action = event->action;
+ str_event->format = event->format;
+
+ switch (event->format) {
+ case KVM_PMU_EVENT_FMT_RAW:
+ str_event->u.raw.code = g_strdup_printf("0x%lx",
+ event->u.raw.code);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ QAPI_LIST_APPEND(tail, str_event);
+ }
+
+ visit_type_KVMPMUFilterEventVariantList(v, name, &head, errp);
+ qapi_free_KVMPMUFilterEventVariantList(head);
+}
+
+static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ KVMPMUFilter *filter = KVM_PMU_FILTER(obj);
+ KVMPMUFilterEventVariantList *list, *node;
+ KVMPMUFilterEventList *head = NULL, *old_head;
+ KVMPMUFilterEventList **tail = &head;
+ int ret, nevents = 0;
+
+ if (!visit_type_KVMPMUFilterEventVariantList(v, name, &list, errp)) {
+ return;
+ }
+
+ for (node = list; node; node = node->next) {
+ KVMPMUFilterEvent *event = g_new(KVMPMUFilterEvent, 1);
+ KVMPMUFilterEventVariant *str_event = node->value;
+
+ event->action = str_event->action;
+ event->format = str_event->format;
+
+ switch (str_event->format) {
+ case KVM_PMU_EVENT_FMT_RAW:
+ ret = qemu_strtou64(str_event->u.raw.code, NULL,
+ 0, &event->u.raw.code);
+ if (ret < 0) {
+ error_setg(errp,
+ "Invalid %s PMU event (code: %s): %s. "
+ "The code must be a uint64 string.",
+ KVMPMUEventEncodeFmt_str(str_event->format),
+ str_event->u.raw.code, strerror(-ret));
+ g_free(event);
+ goto fail;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ nevents++;
+ QAPI_LIST_APPEND(tail, event);
+ }
+
+ old_head = filter->events;
+ filter->events = head;
+ filter->nevents = nevents;
+
+ qapi_free_KVMPMUFilterEventVariantList(list);
+ qapi_free_KVMPMUFilterEventList(old_head);
+ return;
+
+fail:
+ qapi_free_KVMPMUFilterEventList(head);
+}
+
+static void
+kvm_pmu_filter_class_init(ObjectClass *oc, void *data)
+{
+ object_class_property_add(oc, "events",
+ "KVMPMUFilterEvent",
+ 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->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);
@@ -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)
new file mode 100644
@@ -0,0 +1,29 @@
+/*
+ * QEMU KVM PMU Abstraction Header
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Authors:
+ * Zhao Liu <zhao1.liu@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#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)
+
+struct KVMPMUFilter {
+ Object parent_obj;
+
+ uint32_t nevents;
+ KVMPMUFilterEventList *events;
+};
+
+#endif /* KVM_PMU_H */
new file mode 100644
@@ -0,0 +1,119 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+
+##
+# = KVM based feature API
+##
+
+##
+# @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 9.1
+##
+{ 'enum': 'KVMPMUFilterAction',
+ 'prefix': 'KVM_PMU_FILTER_ACTION',
+ 'data': ['allow', 'deny'] }
+
+##
+# @KVMPMUEventEncodeFmt:
+#
+# Encoding formats of PMU event that QEMU/KVM supports.
+#
+# @raw: the encoded event code that KVM can directly consume.
+#
+# Since 9.1
+##
+{ 'enum': 'KVMPMUEventEncodeFmt',
+ 'prefix': 'KVM_PMU_EVENT_FMT',
+ 'data': ['raw'] }
+
+##
+# @KVMPMURawEvent:
+#
+# Raw PMU event code.
+#
+# @code: the raw value that has been encoded, and QEMU could deliver
+# to KVM directly.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMURawEvent',
+ 'data': { 'code': 'uint64' } }
+
+##
+# @KVMPMUFilterEvent:
+#
+# PMU event filtered by KVM.
+#
+# @action: action that KVM PMU filter will take.
+#
+# @format: PMU event format.
+#
+# Since 9.1
+##
+{ 'union': 'KVMPMUFilterEvent',
+ 'base': { 'action': 'KVMPMUFilterAction',
+ 'format': 'KVMPMUEventEncodeFmt' },
+ 'discriminator': 'format',
+ 'data': { 'raw': 'KVMPMURawEvent' } }
+
+##
+# @KVMPMUFilterProperty:
+#
+# Property of KVM PMU Filter.
+#
+# @events: the KVMPMUFilterEvent list.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUFilterProperty',
+ 'data': { '*events': ['KVMPMUFilterEvent'] } }
+
+##
+# @KVMPMURawEventVariant:
+#
+# The variant of KVMPMURawEvent with the string, rather than the
+# numeric value.
+#
+# @code: the raw value that has been encoded, and QEMU could deliver
+# to KVM directly. This field is a uint64 string.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMURawEventVariant',
+ 'data': { 'code': 'str' } }
+
+##
+# @KVMPMUFilterEventVariant:
+#
+# The variant of KVMPMUFilterEvent.
+#
+# @action: action that KVM PMU filter will take.
+#
+# @format: PMU event format.
+#
+# Since 9.1
+##
+{ 'union': 'KVMPMUFilterEventVariant',
+ 'base': { 'action': 'KVMPMUFilterAction',
+ 'format': 'KVMPMUEventEncodeFmt' },
+ 'discriminator': 'format',
+ 'data': { 'raw': 'KVMPMURawEventVariant' } }
+
+##
+# @KVMPMUFilterPropertyVariant:
+#
+# The variant of KVMPMUFilterProperty.
+#
+# @events: the KVMPMUFilterEventVariant list.
+#
+# Since 9.1
+##
+{ 'struct': 'KVMPMUFilterPropertyVariant',
+ 'data': { '*events': ['KVMPMUFilterEventVariant'] } }
@@ -37,6 +37,7 @@ qapi_all_modules = [
'error',
'introspect',
'job',
+ 'kvm',
'machine-common',
'machine',
'machine-target',
@@ -64,6 +64,7 @@
{ 'include': 'compat.json' }
{ 'include': 'control.json' }
{ 'include': 'introspect.json' }
+{ 'include': 'kvm.json' }
{ 'include': 'qom.json' }
{ 'include': 'qdev.json' }
{ 'include': 'machine-common.json' }
@@ -8,6 +8,7 @@
{ 'include': 'block-core.json' }
{ 'include': 'common.json' }
{ 'include': 'crypto.json' }
+{ 'include': 'kvm.json' }
##
# = QEMU Object Model (QOM)
@@ -1057,6 +1058,7 @@
'if': 'CONFIG_LINUX' },
'iommufd',
'iothread',
+ 'kvm-pmu-filter',
'main-loop',
{ 'name': 'memory-backend-epc',
'if': 'CONFIG_LINUX' },
@@ -1131,6 +1133,7 @@
'if': 'CONFIG_LINUX' },
'iommufd': 'IOMMUFDProperties',
'iothread': 'IothreadProperties',
+ 'kvm-pmu-filter': 'KVMPMUFilterPropertyVariant',
'main-loop': 'MainLoopProperties',
'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties',
'if': 'CONFIG_LINUX' },
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. Considering that PMU event related fields are commonly used in hexadecimal, define KVMPMURawEventVariant, KVMPMUFilterEventVariant, and KVMPMUFilterPropertyVariant in kvm.json to support hexadecimal number strings in JSON. Additionally, define the corresponding numeric versions of KVMPMURawEvent, KVMPMUFilterEvent, and KVMPMUFilterProperty in kvm.json. This allows to handle numeric values more effectively and take advantage of the qapi helpers. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- MAINTAINERS | 1 + accel/kvm/kvm-pmu.c | 143 +++++++++++++++++++++++++++++++++++++++ accel/kvm/meson.build | 1 + include/sysemu/kvm-pmu.h | 29 ++++++++ qapi/kvm.json | 119 ++++++++++++++++++++++++++++++++ qapi/meson.build | 1 + qapi/qapi-schema.json | 1 + qapi/qom.json | 3 + 8 files changed, 298 insertions(+) create mode 100644 accel/kvm/kvm-pmu.c create mode 100644 include/sysemu/kvm-pmu.h create mode 100644 qapi/kvm.json