@@ -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
new file mode 100644
@@ -0,0 +1,114 @@
+/*
+ * QEMU KVM PMU Related Abstractions
+ *
+ * Copyright (C) 2025 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@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);
@@ -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,35 @@
+/*
+ * QEMU KVM PMU Related Abstraction Header
+ *
+ * Copyright (C) 2025 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@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 */
new file mode 100644
@@ -0,0 +1,14 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+#
+# Copyright (C) 2025 Intel Corporation.
+#
+# Author: Zhao Liu <zhao1.liu@intel.com>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+##
+# = Accelerators
+##
+
+{ 'include': 'kvm.json' }
new file mode 100644
@@ -0,0 +1,84 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+#
+# Copyright (C) 2025 Intel Corporation.
+#
+# Author: Zhao Liu <zhao1.liu@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'] } }
@@ -37,6 +37,7 @@ qapi_all_modules = [
'error',
'introspect',
'job',
+ 'kvm',
'machine-common',
'machine',
'machine-target',
@@ -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' }
@@ -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' },