From patchwork Wed Apr 9 08:26:45 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 14044293 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0427E25C6EB for ; Wed, 9 Apr 2025 08:06:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744185982; cv=none; b=MwFBViUZ/jU8kUAkB10IZ6ACMM9iC4d5y52EtO+kqzyUnX24Pj8+MqyyhVjxRVlnRnLESCyJ8A8hC5WD1qmR+FOq9PSVAvwkj7H1qfc303udIMts6SbW+yeUAafEvHE62neB/om9w3PBitx4fbcU5iuFxtZ22C+WwvAIyqjH1tE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744185982; c=relaxed/simple; bh=m7sVZ/4wIBYeTyDQv64Fe1AexRN6e7uu1A5Osea0uOI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iiETbNdGPnIjf4izmdL7C0VDX1RskD45NQ16v4sRsSeIlUtfU5Dclx+w3WbpIAIE8yD2xZT0p9qXHyGBhktPiT9KbZKaeECsgERvZBMMO6Vi8Veaqyo5f/Lm2qXqqWC0FF0InZdxlfH1msIFIJ5r11kBh2QvqTNTyAnU4aJv9R0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=BKG/vBTE; arc=none smtp.client-ip=192.198.163.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="BKG/vBTE" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744185980; x=1775721980; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=m7sVZ/4wIBYeTyDQv64Fe1AexRN6e7uu1A5Osea0uOI=; b=BKG/vBTECFEFd60wPx7GO2/sc6p4DtfB6uE0Rk3dghkU2oBamB5WkeWF xmJ+efMwGj0F65NUSmXaCUkkglscHFJd+MN8CKiX0/Mvgz0Xdm4UGHS/1 FmvuSP5MMDb5pYYlidujIgtOaVtU/1tyIc/A2kKCWYMaIPTTFF1yq/Vgr gDc4k1dk9VjXxCrU5xzBxo0TUcNSwJgfJQ+5qnenwoqtPEy09giXwB8Sk 2IYJJI1f0OmBbc0rhPeQhhrhQYTJeCijYnMFy730hwopxZ8quEFUYNgwA WeFBLWcHZn2HFepOBmCEBlp/u7tTsb4lNUhESf8SOzaROzfqwNN/13lfW A==; X-CSE-ConnectionGUID: m3uymQVgT4O5eio+kSvrhg== X-CSE-MsgGUID: /wSbFl1iSJ6Ri8KckxP1Hg== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="45810010" X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="45810010" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by fmvoesa108.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Apr 2025 01:06:19 -0700 X-CSE-ConnectionGUID: rtXBXcpMQCuYyqsQQC2Eng== X-CSE-MsgGUID: 82CxaB9nShGNx+eqY6YJ7A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="151702590" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by fmviesa002.fm.intel.com with ESMTP; 09 Apr 2025 01:06:14 -0700 From: Zhao Liu To: Paolo Bonzini , Eric Blake , Markus Armbruster , Michael Roth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eduardo Habkost , Marcelo Tosatti , Shaoqin Huang , Eric Auger , Peter Maydell , Laurent Vivier , Thomas Huth , Sebastian Ott , Gavin Shan Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org, qemu-arm@nongnu.org, Dapeng Mi , Yi Lai , Zhao Liu Subject: [PATCH 1/5] qapi/qom: Introduce kvm-pmu-filter object Date: Wed, 9 Apr 2025 16:26:45 +0800 Message-Id: <20250409082649.14733-2-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250409082649.14733-1-zhao1.liu@intel.com> References: <20250409082649.14733-1-zhao1.liu@intel.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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 Tested-by: Yi Lai --- 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 + * + * 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 + * + * 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 +# +# 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 +# +# 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' }, From patchwork Wed Apr 9 08:26:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 14044294 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F120D25A652 for ; Wed, 9 Apr 2025 08:06:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744185994; cv=none; b=nbaIAHKj5A8AV/ne3ffxF/KmHXtl59X1QaBkk6caeLMP4ZfyUgsStWw8TAbwuosuOnJEKhW9Oj8pFc2/gj56qx//FWFtLNRcfpwHgDfiU7+YnukyxZdzGGTluqYw6e2bJqxvhVi4VK9eZVrHz7jv1LVvddzbebs9mZzRP9GlwwU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744185994; c=relaxed/simple; bh=IooOrcGOLR5xKZ+Di0/EtLuoebHrm/6xV5IkllZH54w=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ebglvFbyAj8AlmCeMxAyi/N9f5y4oU9aFU69gcFfZQSqxhVJ8ReUtVKuBYpyiGYYgvvLFX8GHLbewk668DVVgQ6G6gSS8CHm0FmK1DZWgkOaBJ8wuiMte1ohiJuJi7FioHxKQfA9Mwp31fVddIlIMcEOtQOc7KNW5OKA1LS0gmU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=LARmQwdk; arc=none smtp.client-ip=192.198.163.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="LARmQwdk" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744185993; x=1775721993; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=IooOrcGOLR5xKZ+Di0/EtLuoebHrm/6xV5IkllZH54w=; b=LARmQwdk9s4FYAL4SqyEu8TuPPzU+Wr0ZsUJPqyqx09DDI+wg/W575oq Zup95y1ALD4W5jVoNwHI1l+wx0h7euVmkivKQtSpzA00OshpR97ZQkh0a Qmy8EetD4SY8TjBvywvMEaYX7qE7Zy2fcYQpXN2RatGHRCmsvGfwqHf6z wYCCo7s1rEmraCgtoQLwIvv/jbEHO1C3T5Rkg9rfkhwsCTAcW+5f2H70t nBEP/a/TVXQt0v6If71Ha+DJwpOrfIvmY7icExAvgtWWBzB7HBUj874ot sSX97Oo1X0sj4PHDT4gN6LJm/T1RvzF9zZhES1u749uErh5oZOezzOqt6 Q==; X-CSE-ConnectionGUID: ZsVx4Hx1QXqyQS6wpiOirg== X-CSE-MsgGUID: cUUdk9tDT8GjEoyTQCNKXw== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="45810033" X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="45810033" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by fmvoesa108.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Apr 2025 01:06:32 -0700 X-CSE-ConnectionGUID: rt3jFTj5SKKZ0sGxiRAkwA== X-CSE-MsgGUID: XrJzuMe3QeOsDHHyN8mciQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="151702615" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by fmviesa002.fm.intel.com with ESMTP; 09 Apr 2025 01:06:20 -0700 From: Zhao Liu To: Paolo Bonzini , Eric Blake , Markus Armbruster , Michael Roth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eduardo Habkost , Marcelo Tosatti , Shaoqin Huang , Eric Auger , Peter Maydell , Laurent Vivier , Thomas Huth , Sebastian Ott , Gavin Shan Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org, qemu-arm@nongnu.org, Dapeng Mi , Yi Lai , Zhao Liu Subject: [PATCH 2/5] i386/kvm: Support basic KVM PMU filter Date: Wed, 9 Apr 2025 16:26:46 +0800 Message-Id: <20250409082649.14733-3-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250409082649.14733-1-zhao1.liu@intel.com> References: <20250409082649.14733-1-zhao1.liu@intel.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Filter PMU events with raw format in i386 code. For i386, raw format indicates that the PMU event code is already encoded according to the KVM ioctl requirements, and can be delivered directly to KVM without additional encoding work. Signed-off-by: Zhao Liu Tested-by: Yi Lai --- Changes since RFC v2: * Add documentation in qemu-options.hx. * Add Tested-by from Yi. Changes since RFC v1: * Stop check whether per-event actions are the same, as "action" has been a global parameter. (Dapeng) * Make pmu filter related functions return int in target/i386/kvm/kvm.c. --- include/system/kvm_int.h | 2 + qemu-options.hx | 47 ++++++++++++++- target/i386/kvm/kvm.c | 127 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h index 4de6106869b0..743fed29b17b 100644 --- a/include/system/kvm_int.h +++ b/include/system/kvm_int.h @@ -17,6 +17,7 @@ #include "hw/boards.h" #include "hw/i386/topology.h" #include "io/channel-socket.h" +#include "system/kvm-pmu.h" typedef struct KVMSlot { @@ -166,6 +167,7 @@ struct KVMState uint16_t xen_gnttab_max_frames; uint16_t xen_evtchn_max_pirq; char *device; + KVMPMUFilter *pmu_filter; }; void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, diff --git a/qemu-options.hx b/qemu-options.hx index dc694a99a30a..51a7c61ce0b0 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -232,7 +232,8 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel, " eager-split-size=n (KVM Eager Page Split chunk size, default 0, disabled. ARM only)\n" " notify-vmexit=run|internal-error|disable,notify-window=n (enable notify VM exit and set notify window, x86 only)\n" " thread=single|multi (enable multi-threaded TCG)\n" - " device=path (KVM device path, default /dev/kvm)\n", QEMU_ARCH_ALL) + " device=path (KVM device path, default /dev/kvm)\n" + " pmu-filter=id (configure KVM PMU filter)\n", QEMU_ARCH_ALL) SRST ``-accel name[,prop=value[,...]]`` This is used to enable an accelerator. Depending on the target @@ -318,6 +319,10 @@ SRST option can be used to pass the KVM device to use via a file descriptor by setting the value to ``/dev/fdset/NN``. + ``pmu-filter=id`` + Sets the id of KVM PMU filter object. This option can be used to set + whitelist or blacklist of PMU events for Guest. + ERST DEF("smp", HAS_ARG, QEMU_OPTION_smp, @@ -6144,6 +6149,46 @@ SRST :: (qemu) qom-set /objects/iothread1 poll-max-ns 100000 + + ``-object '{"qom-type":"kvm-pmu-filter","id":id,"action":action,"events":[entry_list]}'`` + Create a kvm-pmu-filter object that configures KVM to filter + selected PMU events for Guest. + + This option must be written in JSON format to support ``events`` + JSON list. + + The ``action`` parameter sets the action that KVM will take for + the selected PMU events. It accepts ``allow`` or ``deny``. If + the action is set to ``allow``, all PMU events except the + selected ones will be disabled and blocked in the Guest. But if + the action is set to ``deny``, then only the selected events + will be denied, while all other events can be accessed normally + in the Guest. + + The ``events`` parameter accepts a list of PMU event entries in + JSON format. Event entries, based on different encoding formats, + have the following types: + + ``{"format":"raw","code":raw_code}`` + Encode the single PMU event with raw format. The ``code`` + parameter accepts raw code of a PMU event. For x86, the raw + code represents a combination of umask and event select: + + :: + + (((select & 0xf00UL) << 24) | \ + ((select) & 0xff) | \ + ((umask) & 0xff) << 8) + + An example KVM PMU filter object would look like: + + .. parsed-literal:: + + # |qemu_system| \\ + ... \\ + -accel kvm,pmu-filter=id \\ + -object '{"qom-type":"kvm-pmu-filter","id":"f0","action":"allow","events":[{"format":"raw","code":196}]}' \\ + ... ERST diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 6c749d4ee812..fa3a696654cb 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -34,6 +34,7 @@ #include "system/system.h" #include "system/hw_accel.h" #include "system/kvm_int.h" +#include "system/kvm-pmu.h" #include "system/runstate.h" #include "kvm_i386.h" #include "../confidential-guest.h" @@ -110,6 +111,7 @@ typedef struct { static void kvm_init_msrs(X86CPU *cpu); static int kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr, QEMUWRMSRHandler *wrmsr); +static int kvm_filter_pmu_event(KVMState *s); const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_INFO(SET_TSS_ADDR), @@ -3346,6 +3348,18 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + /* + * TODO: Move this chunk to kvm_arch_pre_create_vcpu() and check + * whether pmu is enabled there. + */ + if (s->pmu_filter) { + ret = kvm_filter_pmu_event(s); + if (ret < 0) { + error_report("Could not set KVM PMU filter"); + return ret; + } + } + return 0; } @@ -5942,6 +5956,82 @@ static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run) g_assert_not_reached(); } +static bool kvm_config_pmu_event(KVMPMUFilter *filter, + struct kvm_pmu_event_filter *kvm_filter) +{ + KvmPmuFilterEventList *events; + KvmPmuFilterEvent *event; + uint64_t code; + int idx = 0; + + kvm_filter->nevents = filter->nevents; + events = filter->events; + while (events) { + assert(idx < kvm_filter->nevents); + + event = events->value; + switch (event->format) { + case KVM_PMU_EVENT_FORMAT_RAW: + code = event->u.raw.code; + break; + default: + g_assert_not_reached(); + } + + kvm_filter->events[idx++] = code; + events = events->next; + } + + return true; +} + +static int kvm_install_pmu_event_filter(KVMState *s) +{ + struct kvm_pmu_event_filter *kvm_filter; + KVMPMUFilter *filter = s->pmu_filter; + int ret; + + kvm_filter = g_malloc0(sizeof(struct kvm_pmu_event_filter) + + filter->nevents * sizeof(uint64_t)); + + switch (filter->action) { + case KVM_PMU_FILTER_ACTION_ALLOW: + kvm_filter->action = KVM_PMU_EVENT_ALLOW; + break; + case KVM_PMU_FILTER_ACTION_DENY: + kvm_filter->action = KVM_PMU_EVENT_DENY; + break; + default: + g_assert_not_reached(); + } + + if (!kvm_config_pmu_event(filter, kvm_filter)) { + goto fail; + } + + ret = kvm_vm_ioctl(s, KVM_SET_PMU_EVENT_FILTER, kvm_filter); + if (ret) { + error_report("KVM_SET_PMU_EVENT_FILTER fails (%s)", strerror(-ret)); + goto fail; + } + + g_free(kvm_filter); + return 0; +fail: + g_free(kvm_filter); + return -EINVAL; +} + +static int kvm_filter_pmu_event(KVMState *s) +{ + if (!kvm_vm_check_extension(s, KVM_CAP_PMU_EVENT_FILTER)) { + error_report("KVM PMU filter is not supported by Host."); + return -1; + } + + return kvm_install_pmu_event_filter(s); +} + static bool has_sgx_provisioning; static bool __kvm_enable_sgx_provisioning(KVMState *s) @@ -6537,6 +6627,35 @@ static void kvm_arch_set_xen_evtchn_max_pirq(Object *obj, Visitor *v, s->xen_evtchn_max_pirq = value; } +static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, + Object *child, Error **errp) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(child); + KvmPmuFilterEventList *events = filter->events; + + if (!filter->nevents) { + error_setg(errp, + "Empty KVM PMU filter."); + return; + } + + while (events) { + KvmPmuFilterEvent *event = events->value; + + switch (event->format) { + case KVM_PMU_EVENT_FORMAT_RAW: + break; + default: + error_setg(errp, + "Unsupported PMU event format %s.", + KvmPmuEventFormat_str(events->value->format)); + return; + } + + events = events->next; + } +} + void kvm_arch_accel_class_init(ObjectClass *oc) { object_class_property_add_enum(oc, "notify-vmexit", "NotifyVMexitOption", @@ -6576,6 +6695,14 @@ void kvm_arch_accel_class_init(ObjectClass *oc) NULL, NULL); object_class_property_set_description(oc, "xen-evtchn-max-pirq", "Maximum number of Xen PIRQs"); + + object_class_property_add_link(oc, "pmu-filter", + TYPE_KVM_PMU_FILTER, + offsetof(KVMState, pmu_filter), + kvm_arch_check_pmu_filter, + OBJ_PROP_LINK_STRONG); + object_class_property_set_description(oc, "pmu-filter", + "Set the KVM PMU filter"); } void kvm_set_max_apic_id(uint32_t max_apic_id) From patchwork Wed Apr 9 08:26:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 14044295 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EBCB52405FD for ; Wed, 9 Apr 2025 08:06:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744186003; cv=none; b=eOVdh7Q6qy5bETQ7Lng+KXpTerC0bJ62lMj5rZm3SFrAVXnpa8MXG7g4nJR3AIsBxy+zft8cD/MNVFyazs/04qppEI9DR/xTEuOV9FkDc6YeP3KsIKT/ebhnF/WlIv8jf8Ti6KnDpm14ceempOPuZ7aAB+tUBDPJs8nW8Nl2Sag= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744186003; c=relaxed/simple; bh=UPJeKBU9B6lL8PCAg4txtntOoPDJJfc8C5kkR9P+OTA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=JsXsrUkX7aJPaUZL80XqXOWm1jip8KfTkUzd+0jxZKoAiEXR4ZnMtbYW3kIlws7fjLV4bfMTulD2rtS8Is1poDiX0OsVp1DM6k/nszr2ViQxzDYDr8BIp7+Y7A7yiOOyfeIWpepUHD4rN/xhfviuEjmKnfXSR+ktB2Qs7A8fQk4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=mEWYnK57; arc=none smtp.client-ip=192.198.163.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="mEWYnK57" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744186002; x=1775722002; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UPJeKBU9B6lL8PCAg4txtntOoPDJJfc8C5kkR9P+OTA=; b=mEWYnK57c76e47VX10zmt/Jfno3bG9lJKESopkSgs7UtcMWA5N1JwO5u TrZSSdCvQ/Yjv8jsNwTzNnr+2znCoMwYVFEnA3tgDAI9mAVeSVGiQT98r qEjD92yfb0wXgPrHB+vGuy9Ljdn2Bh97Dcixef2GlQiqsITixoEM2RMld TODIQ/uEuE4DD3Y1HtUbhe+ll2ommxl2n06AC1Es5G66Ps1gceaI2btbN X40pehji+InSQDtKMFLpojj0v5wA1s+IqjgOIeet+3r7TDqMEuuXZxlfQ S5O55MUigS8AUkj3ghR4++LQwJnVcfdcFoIMRjF4AySWUrASCwlZiDT2L g==; X-CSE-ConnectionGUID: sHiTK4o2Q9K+5JtmXQiA6Q== X-CSE-MsgGUID: 6vE1OosRQEOvhiFRSdwbVQ== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="45810047" X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="45810047" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by fmvoesa108.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Apr 2025 01:06:41 -0700 X-CSE-ConnectionGUID: pKtH7y0SQuKiBQWP5t4yMQ== X-CSE-MsgGUID: p6nLUmssSDqxwyFWnFhd/g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="151702631" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by fmviesa002.fm.intel.com with ESMTP; 09 Apr 2025 01:06:29 -0700 From: Zhao Liu To: Paolo Bonzini , Eric Blake , Markus Armbruster , Michael Roth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eduardo Habkost , Marcelo Tosatti , Shaoqin Huang , Eric Auger , Peter Maydell , Laurent Vivier , Thomas Huth , Sebastian Ott , Gavin Shan Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org, qemu-arm@nongnu.org, Dapeng Mi , Yi Lai , Zhao Liu Subject: [PATCH 3/5] i386/kvm: Support event with select & umask format in KVM PMU filter Date: Wed, 9 Apr 2025 16:26:47 +0800 Message-Id: <20250409082649.14733-4-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250409082649.14733-1-zhao1.liu@intel.com> References: <20250409082649.14733-1-zhao1.liu@intel.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The select&umask is the common way for x86 to identify the PMU event, so support this way as the "x86-default" format in kvm-pmu-filter object. Signed-off-by: Zhao Liu Tested-by: Yi Lai --- Changes since RFC v2: * Drop hexadecimal variants and support numeric version in QAPI directly. (Daniel) * Rename "x86-default" format to "x86-select-umask". (Markus) * 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 | 20 +++++++++++++++++++- include/system/kvm-pmu.h | 13 +++++++++++++ qapi/kvm.json | 21 +++++++++++++++++++-- qemu-options.hx | 3 +++ target/i386/kvm/kvm.c | 5 +++++ 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c index 22f749bf9183..fa73ef428e59 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -16,6 +16,8 @@ #include "qom/object_interfaces.h" #include "system/kvm-pmu.h" +#define UINT12_MAX (4095) + static void kvm_pmu_filter_set_action(Object *obj, int value, Error **errp G_GNUC_UNUSED) { @@ -53,9 +55,22 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name, } for (node = head; node; node = node->next) { - switch (node->value->format) { + KvmPmuFilterEvent *event = node->value; + + switch (event->format) { case KVM_PMU_EVENT_FORMAT_RAW: break; + case KVM_PMU_EVENT_FORMAT_X86_SELECT_UMASK: { + if (event->u.x86_select_umask.select > UINT12_MAX) { + error_setg(errp, + "Parameter 'select' out of range (%d).", + UINT12_MAX); + goto fail; + } + + /* No need to check the range of umask since it's uint8_t. */ + break; + } default: g_assert_not_reached(); } @@ -67,6 +82,9 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name, filter->events = head; qapi_free_KvmPmuFilterEventList(old_head); return; + +fail: + qapi_free_KvmPmuFilterEventList(head); } static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data) diff --git a/include/system/kvm-pmu.h b/include/system/kvm-pmu.h index 818fa309c191..6abc0d037aee 100644 --- a/include/system/kvm-pmu.h +++ b/include/system/kvm-pmu.h @@ -32,4 +32,17 @@ struct KVMPMUFilter { KvmPmuFilterEventList *events; }; +/* + * Stolen from Linux kernel (RAW_EVENT at tools/testing/selftests/kvm/include/ + * x86_64/pmu.h). + * + * Encode an eventsel+umask pair into event-select MSR format. Note, this is + * technically AMD's format, as Intel's format only supports 8 bits for the + * event selector, i.e. doesn't use bits 24:16 for the selector. But, OR-ing + * in '0' is a nop and won't clobber the CMASK. + */ +#define X86_PMU_RAW_EVENT(eventsel, umask) (((eventsel & 0xf00UL) << 24) | \ + ((eventsel) & 0xff) | \ + ((umask) & 0xff) << 8) + #endif /* KVM_PMU_H */ diff --git a/qapi/kvm.json b/qapi/kvm.json index 1861d86a9726..cb151ca82e5c 100644 --- a/qapi/kvm.json +++ b/qapi/kvm.json @@ -36,10 +36,12 @@ # # @raw: the encoded event code that KVM can directly consume. # +# @x86-select-umask: standard x86 encoding format with select and umask. +# # Since 10.1 ## { 'enum': 'KvmPmuEventFormat', - 'data': ['raw'] } + 'data': ['raw', 'x86-select-umask'] } ## # @KvmPmuRawEvent: @@ -54,6 +56,20 @@ { 'struct': 'KvmPmuRawEvent', 'data': { 'code': 'uint64' } } +## +# @KvmPmuX86SelectUmaskEvent: +# +# @select: x86 PMU event select field, which is a 12-bit unsigned +# number. +# +# @umask: x86 PMU event umask field. +# +# Since 10.1 +## +{ 'struct': 'KvmPmuX86SelectUmaskEvent', + 'data': { 'select': 'uint16', + 'umask': 'uint8' } } + ## # @KvmPmuFilterEvent: # @@ -66,7 +82,8 @@ { 'union': 'KvmPmuFilterEvent', 'base': { 'format': 'KvmPmuEventFormat' }, 'discriminator': 'format', - 'data': { 'raw': 'KvmPmuRawEvent' } } + 'data': { 'raw': 'KvmPmuRawEvent', + 'x86-select-umask': 'KvmPmuX86SelectUmaskEvent' } } ## # @KvmPmuFilterProperties: diff --git a/qemu-options.hx b/qemu-options.hx index 51a7c61ce0b0..5dcce067d8dd 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -6180,6 +6180,9 @@ SRST ((select) & 0xff) | \ ((umask) & 0xff) << 8) + ``{"format":"x86-select-umask","select":event_select,"umask":event_umask}`` + Specify the single x86 PMU event with select and umask fields. + 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 fa3a696654cb..0d36ccf250ed 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5974,6 +5974,10 @@ static bool kvm_config_pmu_event(KVMPMUFilter *filter, case KVM_PMU_EVENT_FORMAT_RAW: code = event->u.raw.code; break; + case KVM_PMU_EVENT_FORMAT_X86_SELECT_UMASK: + code = X86_PMU_RAW_EVENT(event->u.x86_select_umask.select, + event->u.x86_select_umask.umask); + break; default: g_assert_not_reached(); } @@ -6644,6 +6648,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, switch (event->format) { case KVM_PMU_EVENT_FORMAT_RAW: + case KVM_PMU_EVENT_FORMAT_X86_SELECT_UMASK: break; default: error_setg(errp, From patchwork Wed Apr 9 08:26:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 14044296 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A15F225A62C for ; Wed, 9 Apr 2025 08:06:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744186005; cv=none; b=WZHY2BbPbVdbOAnzF5dczGc6EnaYsPHhDk05gmSfKQQGEnhYLWNWE5EY4U7pxiAJXG4A1ZWPOfMqtHK+lw9pMVjA93OnBYbt6NE25KxzmRXeVtkkL92Li4RaK86ccG9SLYFnWyUcTxiPUQi3fJyNYfc6jp2eiJP/rLFtcsr7EhA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744186005; c=relaxed/simple; bh=gPWi6WAm1QJcGhcg000exTZdLrq/PcWVzv1PHwkLj9U=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YDLshJNwYc4OmbN5UweJ4bVSoGV0Q0LRUnVn1JArYkNCHume73HjR6igvVO4ncHHB/PZzzBf3eIB+0yaGLhS15itqw48nPwKe3OkQpKhqwrg+HyDbhB58uv+0kWWXzMmNDyILIHwZZ69gP8I16SsOCL6n2DMNRkBqfufiCyZb2M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=VS9mDCmM; arc=none smtp.client-ip=192.198.163.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="VS9mDCmM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744186003; x=1775722003; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=gPWi6WAm1QJcGhcg000exTZdLrq/PcWVzv1PHwkLj9U=; b=VS9mDCmMe9ZwKjyxI/a8V8Hji+r8+pags/SkYEDS+nZGs60N8gO/UPGu fypkvWWLHfzMBW7FN4XSYZ3/mWRfaS2FjSZs9kOHH6PeLgrHG+pM1CW5H R5EF1BoyP0JeH4gaz8Iw3rwPlZ5HZYWhQYwfou9nXGEW5Nm1ftCfIgvpu zPhRy9Fk7rcEW/W87HTvbZjDX7rpsVilx6JdhefoaP/B76Ljy5nTxHedu imHqu7vqsaOMxWYoC+b91pQ1/1MHfcFJFIyjbAPjxm7R0kSxpGfaeZfV8 iYmJLZkDhX0aV3jWLbjw2eEYZPxlYvZTpZMAZK0+Gelo/AzIjShV9zcLw Q==; X-CSE-ConnectionGUID: arhGI4xNRU+Y6lNPY4x7gQ== X-CSE-MsgGUID: cOPuUj8PRfGn7qtspHhbEA== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="45810053" X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="45810053" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by fmvoesa108.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Apr 2025 01:06:41 -0700 X-CSE-ConnectionGUID: cFIbbdPkQxO2qtm/wJUIkw== X-CSE-MsgGUID: PWZY0nrHTyWDhy+kTpVPfg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="151702666" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by fmviesa002.fm.intel.com with ESMTP; 09 Apr 2025 01:06:34 -0700 From: Zhao Liu To: Paolo Bonzini , Eric Blake , Markus Armbruster , Michael Roth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eduardo Habkost , Marcelo Tosatti , Shaoqin Huang , Eric Auger , Peter Maydell , Laurent Vivier , Thomas Huth , Sebastian Ott , Gavin Shan Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org, qemu-arm@nongnu.org, Dapeng Mi , Yi Lai , Zhao Liu Subject: [PATCH 4/5] i386/kvm: Support event with masked entry format in KVM PMU filter Date: Wed, 9 Apr 2025 16:26:48 +0800 Message-Id: <20250409082649.14733-5-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250409082649.14733-1-zhao1.liu@intel.com> References: <20250409082649.14733-1-zhao1.liu@intel.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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 Tested-by: Yi Lai --- 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; } } From patchwork Wed Apr 9 08:26:49 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 14044297 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1F37525A65E for ; Wed, 9 Apr 2025 08:06:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744186005; cv=none; b=jZ5UQzvYVRl1ghx0/RMwBWf9ieqzybDaw2vPl6Gp5KL7o7qzoDgiSec6bkjMctJerSb7V7JdLBbNC9y2YaFUXcK5LL6UYPZBFbdverikP2a1E0FNkmbO6fNkS22t53EjLnX3Tm5J2WQ8xT4Tn706tD/tOQjSTn9sKYMdINedCAw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744186005; c=relaxed/simple; bh=y/Ah2gIgHbe+sK/IOChNaZznI5EZIF+55b+SG00yUgU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Li06zBnLkqwQVF3Xq6uf8i9zsFMGFpqCj44I5zw6MAEOalaptj/xRbJM+rc992n+5RogcJaRXmhkjf8hCjjoYbvnPBEWFb6XJ0Tc+6j2BazisFjdUB/P8PZQobDtA5uhMHydXzEhiVQqlMA1brfCYhVwhJ26pLSfPy83UZd+3Uk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Q7sgayTs; arc=none smtp.client-ip=192.198.163.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Q7sgayTs" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1744186004; x=1775722004; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=y/Ah2gIgHbe+sK/IOChNaZznI5EZIF+55b+SG00yUgU=; b=Q7sgayTs31vVSE7e35pJ5/cQg0jAl9uih689PT5qLYXlxwm7m/Rdc2/n gIvQv23tfk1KG8BD3vzaARlk86rX1fkSXYlZ7mdU1g2g01ZKDNtqvgd3s m510FGlkKE4H400Z282W3S2voPRnWlAlMZjHqJENliYxXYGRLQ5HR0Jqi VbTth91bJKgr7UXz0dPfuJ2++lZppK4ifU0N7EvRWHyhEeLdA3KOazjVW mPyTswqNeGTwifxgjOn/AQyKmDp4Fp3+8NnkWC5C2Jt7yIhEJSLHmp+UW Zq/r220sJ/GKEW8Q4wP6XGpoHW7t5IIGVaZZzKyoH6K8Kj05tErMJpNHH g==; X-CSE-ConnectionGUID: KzfK3yPTTYO2Escts37gcQ== X-CSE-MsgGUID: 4CF4RmjGSIeqrXXfI/DAGQ== X-IronPort-AV: E=McAfee;i="6700,10204,11397"; a="45810063" X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="45810063" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by fmvoesa108.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Apr 2025 01:06:43 -0700 X-CSE-ConnectionGUID: I97O+6i8RBm4yuoI5EFM2Q== X-CSE-MsgGUID: eesw//O1SlG3FcXwB6y7cg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.15,200,1739865600"; d="scan'208";a="151702674" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by fmviesa002.fm.intel.com with ESMTP; 09 Apr 2025 01:06:38 -0700 From: Zhao Liu To: Paolo Bonzini , Eric Blake , Markus Armbruster , Michael Roth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eduardo Habkost , Marcelo Tosatti , Shaoqin Huang , Eric Auger , Peter Maydell , Laurent Vivier , Thomas Huth , Sebastian Ott , Gavin Shan Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org, qemu-arm@nongnu.org, Dapeng Mi , Yi Lai , Zhao Liu Subject: [PATCH 5/5] i386/kvm: Support fixed counter in KVM PMU filter Date: Wed, 9 Apr 2025 16:26:49 +0800 Message-Id: <20250409082649.14733-6-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250409082649.14733-1-zhao1.liu@intel.com> References: <20250409082649.14733-1-zhao1.liu@intel.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 KVM_SET_PMU_EVENT_FILTER of x86 KVM allows user to configure x86 fixed function counters by a bitmap. Add the support of x86-fixed-counter in kvm-pmu-filter object and handle this in i386 kvm codes. Signed-off-by: Zhao Liu Tested-by: Yi Lai --- Changes since RFC v2: * Drop KVMPMUX86FixedCounter structure and use uint32_t to represent bitmap in QAPI directly. * Add Tested-by from Yi. * Add documentation in qemu-options.hx. * Bump up the supported QAPI version to v10.1. Changes since RFC v1: * Make "action" as a global (per filter object) item, not a per-counter parameter. (Dapeng) * Bump up the supported QAPI version to v10.0. --- accel/kvm/kvm-pmu.c | 31 +++++++++++++++++++++++++++++++ include/system/kvm-pmu.h | 5 ++++- qapi/kvm.json | 6 +++++- qemu-options.hx | 6 +++++- target/i386/kvm/kvm.c | 39 ++++++++++++++++++++++++--------------- 5 files changed, 69 insertions(+), 18 deletions(-) diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c index 9205907d1779..509d69d9c515 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -101,6 +101,29 @@ fail: qapi_free_KvmPmuFilterEventList(head); } +static void kvm_pmu_filter_get_fixed_counter(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + + visit_type_uint32(v, name, &filter->x86_fixed_counter, errp); +} + +static void kvm_pmu_filter_set_fixed_counter(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + uint32_t counter; + + if (!visit_type_uint32(v, name, &counter, errp)) { + return; + } + + filter->x86_fixed_counter = counter; +} + static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data) { object_class_property_add_enum(oc, "action", "KvmPmuFilterAction", @@ -116,6 +139,14 @@ static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data) NULL, NULL); object_class_property_set_description(oc, "events", "KVM PMU event list"); + + object_class_property_add(oc, "x86-fixed-counter", "uint32_t", + kvm_pmu_filter_get_fixed_counter, + kvm_pmu_filter_set_fixed_counter, + NULL, NULL); + object_class_property_set_description(oc, "x86-fixed-counter", + "Enablement bitmap of " + "x86 PMU fixed counter"); } static void kvm_pmu_filter_instance_init(Object *obj) diff --git a/include/system/kvm-pmu.h b/include/system/kvm-pmu.h index 6abc0d037aee..5238b2b4dcc7 100644 --- a/include/system/kvm-pmu.h +++ b/include/system/kvm-pmu.h @@ -19,10 +19,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(KVMPMUFilter, KVM_PMU_FILTER) /** * KVMPMUFilter: - * @action: action that KVM PMU filter will take for selected PMU events. + * @action: action that KVM PMU filter will take for selected PMU events + * and counters. * @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. + * @x86_fixed_counter: bitmap of x86 fixed counter. */ struct KVMPMUFilter { Object parent_obj; @@ -30,6 +32,7 @@ struct KVMPMUFilter { KvmPmuFilterAction action; uint32_t nevents; KvmPmuFilterEventList *events; + uint32_t x86_fixed_counter; }; /* diff --git a/qapi/kvm.json b/qapi/kvm.json index 1b523e058731..5374c8340e5a 100644 --- a/qapi/kvm.json +++ b/qapi/kvm.json @@ -115,7 +115,10 @@ # # Properties of KVM PMU Filter. # -# @action: action that KVM PMU filter will take for selected PMU events. +# @action: action that KVM PMU filter will take for selected PMU events +# and counters. +# +# @x86-fixed-counter: enablement bitmap of x86 fixed counters. # # @events: list of selected PMU events. # @@ -123,4 +126,5 @@ ## { 'struct': 'KvmPmuFilterProperties', 'data': { 'action': 'KvmPmuFilterAction', + '*x86-fixed-counter': 'uint32', '*events': ['KvmPmuFilterEvent'] } } diff --git a/qemu-options.hx b/qemu-options.hx index bb89198971e0..eadfb69c8876 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -6150,7 +6150,7 @@ SRST (qemu) qom-set /objects/iothread1 poll-max-ns 100000 - ``-object '{"qom-type":"kvm-pmu-filter","id":id,"action":action,"events":[entry_list]}'`` + ``-object '{"qom-type":"kvm-pmu-filter","id":id,"x86-fixed-counter":bitmap,"action":action,"events":[entry_list]}'`` Create a kvm-pmu-filter object that configures KVM to filter selected PMU events for Guest. @@ -6165,6 +6165,10 @@ SRST will be denied, while all other events can be accessed normally in the Guest. + The ``x86-fixed-counter`` parameter sets a bitmap of x86 fixed + counters, and ``action`` will also take effect on the selected + fixed counters. + The ``events`` parameter accepts a list of PMU event entries in JSON format. Event entries, based on different encoding formats, have the following types: diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 8786501e9c7e..8b916dbb5d6f 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -6016,19 +6016,25 @@ 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 (filter->x86_fixed_counter) { + kvm_filter->fixed_counter_bitmap = filter->x86_fixed_counter; } - if (!kvm_config_pmu_event(filter, kvm_filter)) { - goto fail; + if (filter->nevents) { + 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; + } } ret = kvm_vm_ioctl(s, KVM_SET_PMU_EVENT_FILTER, kvm_filter); @@ -6656,16 +6662,19 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, KvmPmuFilterEventList *events = filter->events; uint32_t base_flag; - if (!filter->nevents) { + if (!filter->x86_fixed_counter && !filter->nevents) { error_setg(errp, "Empty KVM PMU filter."); 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; + base_flag = 0; + if (filter->nevents && + events->value->format == KVM_PMU_EVENT_FORMAT_X86_MASKED_ENTRY) { + base_flag = KVM_PMU_EVENT_FLAG_MASKED_EVENTS; + } + while (events) { KvmPmuFilterEvent *event = events->value; uint32_t flag;