From patchwork Wed Jan 22 09:05:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13947018 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 00FFA1C3C0B for ; Wed, 22 Jan 2025 08:46:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535574; cv=none; b=ZB66EMl0ZgClms789ukwJTQL8UiM5lBqYP7rvnzJcN5kfaQ7hOT83MNfS9OidSD2fWbuYPaVm6Hyea0wyLB+HOOSWXCOsYolfHIEDpH8LV16GgyaaoT2v/UnPiPUf/zpRSAMmJWoQ/pSz1bywCmcSNZxIkx9HNr9OGki874lr30= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535574; c=relaxed/simple; bh=HP1zZWGiw1yE/RZYTSNmKOwsJodBHoq6Uwf30q0PM8c=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ASAYQwsQnwLgAzvk7wDDThzIPsOEc+2aSOeZxPXcHyGksafS6JLzVEw0eSfsd7ONOEQuZCg35FsoF6ZHohbw73MYqtOPn5RZ7juMJHH4fVpkIKhZa4INrHr9k0jwsZJ25gE43iGNWxfxvFhNwpg2MEeh/dUdF1G0ftaaK0RDtjI= 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=hvgppxuy; arc=none smtp.client-ip=198.175.65.9 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="hvgppxuy" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1737535573; x=1769071573; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HP1zZWGiw1yE/RZYTSNmKOwsJodBHoq6Uwf30q0PM8c=; b=hvgppxuyElZs9NCeT206eu3t6vrfAcek5pOrgp9jsVak32Mg+5aZSjQb 6ZnGCbjl4eCY3cGFrz2MkeaAlxG/fvPD8B908WIOcFPef55Msen09NLLr /EPBj9Ft9HRsgjGfrfHhKI9cp4gpVT/KCPzpoaQQZVprOeHGodTEHwA++ v69uOYedty+4oMEPe3CaLjrZEIR+B2ewYClE1O1XvTWRFUwPSQKpPq00x Q+XRKPFeIntg9LWjoGov3YeGKGKJbDZi9A1gRX3Uy/SEzGn78VIr2MKNH eCOcsHF9kYwZ3pgKiUwMnMFxu1HmfyWoQq0YtrzNG0dffHaVHPcjBmj2d Q==; X-CSE-ConnectionGUID: RwLto7ygSg6RYIb/0+48DQ== X-CSE-MsgGUID: p+kG/WJzQz2xEZyYDFL0kA== X-IronPort-AV: E=McAfee;i="6700,10204,11322"; a="60451546" X-IronPort-AV: E=Sophos;i="6.13,224,1732608000"; d="scan'208";a="60451546" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jan 2025 00:46:13 -0800 X-CSE-ConnectionGUID: xyizYcnKT1aXiu9Q3we+jw== X-CSE-MsgGUID: mMCxGChuQ8KsZox6WG6UNw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="112049682" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by orviesa003.jf.intel.com with ESMTP; 22 Jan 2025 00:46:08 -0800 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: [RFC v2 1/5] qapi/qom: Introduce kvm-pmu-filter object Date: Wed, 22 Jan 2025 17:05:13 +0800 Message-Id: <20250122090517.294083-2-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250122090517.294083-1-zhao1.liu@intel.com> References: <20250122090517.294083-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. 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 --- 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 10.0. --- MAINTAINERS | 1 + accel/kvm/kvm-pmu.c | 164 +++++++++++++++++++++++++++++++++++++++ accel/kvm/meson.build | 1 + include/system/kvm-pmu.h | 30 +++++++ qapi/kvm.json | 116 +++++++++++++++++++++++++++ qapi/meson.build | 1 + qapi/qapi-schema.json | 1 + qapi/qom.json | 3 + 8 files changed, 317 insertions(+) create mode 100644 accel/kvm/kvm-pmu.c create mode 100644 include/system/kvm-pmu.h create mode 100644 qapi/kvm.json diff --git a/MAINTAINERS b/MAINTAINERS index 846b81e3ec03..21adc1c10607 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -440,6 +440,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 diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c new file mode 100644 index 000000000000..4d0d4e7a452b --- /dev/null +++ b/accel/kvm/kvm-pmu.c @@ -0,0 +1,164 @@ +/* + * QEMU KVM PMU Abstractions + * + * Copyright (C) 2024 Intel Corporation. + * + * Author: Zhao Liu + * + * 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 "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); + 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->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->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_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", "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); + + /* Initial state, 0 events allowed. */ + 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..b09f70d3a370 --- /dev/null +++ b/include/system/kvm-pmu.h @@ -0,0 +1,30 @@ +/* + * QEMU KVM PMU Abstraction Header + * + * Copyright (C) 2024 Intel Corporation. + * + * Authors: + * Zhao Liu + * + * 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; + + KVMPMUFilterAction action; + uint32_t nevents; + KVMPMUFilterEventList *events; +}; + +#endif /* KVM_PMU_H */ diff --git a/qapi/kvm.json b/qapi/kvm.json new file mode 100644 index 000000000000..d51aeeba7cd8 --- /dev/null +++ b/qapi/kvm.json @@ -0,0 +1,116 @@ +# -*- 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 10.0 +## +{ '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 10.0 +## +{ '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 10.0 +## +{ 'struct': 'KVMPMURawEvent', + 'data': { 'code': 'uint64' } } + +## +# @KVMPMUFilterEvent: +# +# PMU event filtered by KVM. +# +# @format: PMU event format. +# +# Since 10.0 +## +{ 'union': 'KVMPMUFilterEvent', + 'base': { 'format': 'KVMPMUEventEncodeFmt' }, + 'discriminator': 'format', + 'data': { 'raw': 'KVMPMURawEvent' } } + +## +# @KVMPMUFilterProperty: +# +# Property of KVM PMU Filter. +# +# @events: the KVMPMUFilterEvent list. +# +# Since 10.0 +## +{ '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 10.0 +## +{ 'struct': 'KVMPMURawEventVariant', + 'data': { 'code': 'str' } } + +## +# @KVMPMUFilterEventVariant: +# +# The variant of KVMPMUFilterEvent. +# +# @format: PMU event format. +# +# Since 10.0 +## +{ 'union': 'KVMPMUFilterEventVariant', + 'base': { 'format': 'KVMPMUEventEncodeFmt' }, + 'discriminator': 'format', + 'data': { 'raw': 'KVMPMURawEventVariant' } } + +## +# @KVMPMUFilterPropertyVariant: +# +# The variant of KVMPMUFilterProperty. +# +# @action: action that KVM PMU filter will take. +# +# @events: the KVMPMUFilterEventVariant list. +# +# Since 10.0 +## +{ 'struct': 'KVMPMUFilterPropertyVariant', + 'data': { 'action': 'KVMPMUFilterAction', + '*events': ['KVMPMUFilterEventVariant'] } } diff --git a/qapi/meson.build b/qapi/meson.build index e7bc54e5d047..856439c76b67 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 b1581988e4eb..742818d16e45 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -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' } diff --git a/qapi/qom.json b/qapi/qom.json index 28ce24cd8d08..c75ec4b21e95 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': 'KVMPMUFilterPropertyVariant', 'main-loop': 'MainLoopProperties', 'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties', 'if': 'CONFIG_LINUX' }, From patchwork Wed Jan 22 09:05:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13947019 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 9DFF9188721 for ; Wed, 22 Jan 2025 08:46:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535579; cv=none; b=TQ3EihVpor9uB7krGu5+NwzAG3057oj0UOu6eWl1fOeSrlY5EsGrciemlCaklTI+gYDsCk/5qWM3INNamCIBcuoTPASEKwG5EEHoPIWz+o7p/zCw1TVfH6x7Z32xVKhs4yCV26/mXckfQMnu0Qku87W/ovKeITyaQPfFqU57fqE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535579; c=relaxed/simple; bh=VMFyzU7rJ0ERY+XN36rgAcSEcfJLdF/jbMtrra/GTKA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=fbVgMp1d/DGwEHa5wkXx31RRIsmB5L0ZB4+PiC0WV+1eW5e8aCzU91L31960Rw+/IeymizxwBmY342oHIVFpBHokckN5f47hHvCulgyNmHQDKRZdinMbJuR8e18Bt8sFOimYdfOBXWpq1Ub+Q4kQkOWADCzHu5ZBB0tHCWkcBg4= 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=fRl2YDjM; arc=none smtp.client-ip=198.175.65.9 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="fRl2YDjM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1737535578; x=1769071578; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VMFyzU7rJ0ERY+XN36rgAcSEcfJLdF/jbMtrra/GTKA=; b=fRl2YDjMSKqIeuv1/omSOm2tVi9r9hArsXQ8mWvuL+mOQXjdk3gZIoBU lB+3x0ta14/cFoEwZdXXh5okRIok78DtYFsOKwynKYNtqZ9SJ9/ZjGNOJ /gc5UEh2ZJ+mxTpdpKT8Dx6nTS0KCm4A5D+nOkoyWIF8EmUhxcAQWyc1W N673nZbRiEf4PxvQMVIIkyGZjT4CprzSFqR/PLzKms2CjT1r6+i1jTjmh SdMJys1Q4pGllw9w1CN6Pa18wzm1RBAaHcOhCEn8BVb8FrrDMRCqV0OIC Gk+sU9AqVZRd9ykDm+x6M6Glei6YvsIZxiusmdlFiLpgMR2YqmmPkNtJO g==; X-CSE-ConnectionGUID: QyY8lamYQcWKtQKqzdMUzA== X-CSE-MsgGUID: RWlOPk9PQsi8aslW6jwnFQ== X-IronPort-AV: E=McAfee;i="6700,10204,11322"; a="60451559" X-IronPort-AV: E=Sophos;i="6.13,224,1732608000"; d="scan'208";a="60451559" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jan 2025 00:46:17 -0800 X-CSE-ConnectionGUID: fA1qO0UsTNWEBq4maCd8bQ== X-CSE-MsgGUID: bO2kWi3pSM6t8TGjTKIFOw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="112049753" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by orviesa003.jf.intel.com with ESMTP; 22 Jan 2025 00:46:13 -0800 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: [RFC v2 2/5] i386/kvm: Support basic KVM PMU filter Date: Wed, 22 Jan 2025 17:05:14 +0800 Message-Id: <20250122090517.294083-3-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250122090517.294083-1-zhao1.liu@intel.com> References: <20250122090517.294083-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 --- Changes since 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 + target/i386/kvm/kvm.c | 123 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) 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/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 6c749d4ee812..b82adbed50f4 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,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + 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 +5952,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_FMT_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 +6623,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_FMT_RAW: + break; + default: + error_setg(errp, + "Unsupported PMU event format %s.", + KVMPMUEventEncodeFmt_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 +6691,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 Jan 22 09:05:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13947020 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 C944D188721 for ; Wed, 22 Jan 2025 08:46:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535584; cv=none; b=PzhUg+OnRjDk/trKf/LKDbP2iP2+rc/4yz/jeVrTP8u6NXZrfc4AXIBgkIK3h3L6s7Seeeex4kPtU+HD1xBaWjIiaHJP6iaaY+kIq8+POWpBir9DtQ4uCUV3HqqSZybnnag6GwTCJYwM04CAUqXNdVbJNJjUk4r7ELp/tSDnL8c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535584; c=relaxed/simple; bh=ECviX94xj1MV2LXTaHe4lkd20iyrsoewh1cwlHBtoeQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=u4lccTjuV+dmCJtyfqmTMR2pTIzwXd3FMH1IiZod/mNW8FYIJRnwxDFiibT4ufEGUKVIpOIyNy4jGFO1ixvH4I91+irdVA2LmxgMU02RUAfEPc8AceUHWKKzbLykJ27iMEQqazPACmDaUC+F3WS3pbkCBN+2i8lfm2nZ0z+Wq+U= 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=Z/fii6Tc; arc=none smtp.client-ip=198.175.65.9 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="Z/fii6Tc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1737535583; x=1769071583; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ECviX94xj1MV2LXTaHe4lkd20iyrsoewh1cwlHBtoeQ=; b=Z/fii6TcQNwBIJHgJydvLs6Nl+DHVlui8pY+qflypP0fWoozanRPwKk9 6FiYaqv2wmetBHof00lhRz/gJ3o8pRNv+8370e/57pIiKXc0QIe1HEY+t OSGuNh8aqqnN3O/1DbIbVJlqHPMtgt9/XBBWVgKMduAmMwSEGVfR1P8qe ER9KzBnGhtI2W3vvglKI+MUPZtKh8z9iT4sIiX+75uFsTZ3uvQOsnPYY7 fz+RJOMn78YuTe5179aawD086w5rG9tiYdRfS2EA9yy4Q3Lyzg3ZOUJHS 5IhRcNoTNj1h6Zaru5LJoWcChS/zr6mT0ULAAq6ujVe1e0iwuDrPvQSzp A==; X-CSE-ConnectionGUID: bmMMjeHFTKqVea0s9QK7lg== X-CSE-MsgGUID: U4tgqdQ7Qs61qYvUuN9K/w== X-IronPort-AV: E=McAfee;i="6700,10204,11322"; a="60451575" X-IronPort-AV: E=Sophos;i="6.13,224,1732608000"; d="scan'208";a="60451575" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jan 2025 00:46:23 -0800 X-CSE-ConnectionGUID: pDSkkKfhRPWinRBdf/uitA== X-CSE-MsgGUID: CRjnXgP2QpKKNi/NIuNzZw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="112049828" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by orviesa003.jf.intel.com with ESMTP; 22 Jan 2025 00:46:18 -0800 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: [RFC v2 3/5] i386/kvm: Support event with select & umask format in KVM PMU filter Date: Wed, 22 Jan 2025 17:05:15 +0800 Message-Id: <20250122090517.294083-4-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250122090517.294083-1-zhao1.liu@intel.com> References: <20250122090517.294083-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 --- Changes since RFC v1: * Bump up the supported QAPI version to 10.0. --- accel/kvm/kvm-pmu.c | 62 ++++++++++++++++++++++++++++++++++++++++ include/system/kvm-pmu.h | 13 +++++++++ qapi/kvm.json | 46 +++++++++++++++++++++++++++-- target/i386/kvm/kvm.c | 5 ++++ 4 files changed, 123 insertions(+), 3 deletions(-) diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c index 4d0d4e7a452b..cbd32e8e21f8 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -17,6 +17,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) { @@ -54,6 +56,12 @@ static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name, str_event->u.raw.code = g_strdup_printf("0x%lx", event->u.raw.code); break; + case KVM_PMU_EVENT_FMT_X86_DEFAULT: + str_event->u.x86_default.select = + g_strdup_printf("0x%x", event->u.x86_default.select); + str_event->u.x86_default.umask = + g_strdup_printf("0x%x", event->u.x86_default.umask); + break; default: g_assert_not_reached(); } @@ -98,6 +106,60 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name, goto fail; } break; + case KVM_PMU_EVENT_FMT_X86_DEFAULT: { + uint64_t select, umask; + + ret = qemu_strtou64(str_event->u.x86_default.select, NULL, + 0, &select); + if (ret < 0) { + error_setg(errp, + "Invalid %s PMU event (select: %s): %s. " + "The select must be a " + "12-bit unsigned number string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_default.select, + strerror(-ret)); + g_free(event); + goto fail; + } + if (select > UINT12_MAX) { + error_setg(errp, + "Invalid %s PMU event (select: %s): " + "Numerical result out of range. " + "The select must be a " + "12-bit unsigned number string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_default.select); + g_free(event); + goto fail; + } + event->u.x86_default.select = select; + + ret = qemu_strtou64(str_event->u.x86_default.umask, NULL, + 0, &umask); + if (ret < 0) { + error_setg(errp, + "Invalid %s PMU event (umask: %s): %s. " + "The umask must be a uint8 string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_default.umask, + strerror(-ret)); + g_free(event); + goto fail; + } + if (umask > UINT8_MAX) { + error_setg(errp, + "Invalid %s PMU event (umask: %s): " + "Numerical result out of range. " + "The umask must be a uint8 string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_default.umask); + g_free(event); + goto fail; + } + event->u.x86_default.umask = umask; + break; + } default: g_assert_not_reached(); } diff --git a/include/system/kvm-pmu.h b/include/system/kvm-pmu.h index b09f70d3a370..63402f75cfdc 100644 --- a/include/system/kvm-pmu.h +++ b/include/system/kvm-pmu.h @@ -27,4 +27,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 d51aeeba7cd8..93b869e3f90c 100644 --- a/qapi/kvm.json +++ b/qapi/kvm.json @@ -27,11 +27,13 @@ # # @raw: the encoded event code that KVM can directly consume. # +# @x86-default: standard x86 encoding format with select and umask. +# # Since 10.0 ## { 'enum': 'KVMPMUEventEncodeFmt', 'prefix': 'KVM_PMU_EVENT_FMT', - 'data': ['raw'] } + 'data': ['raw', 'x86-default'] } ## # @KVMPMURawEvent: @@ -46,6 +48,25 @@ { 'struct': 'KVMPMURawEvent', 'data': { 'code': 'uint64' } } +## +# @KVMPMUX86DefalutEvent: +# +# x86 PMU event encoding with select and umask. +# raw_event = ((select & 0xf00UL) << 24) | \ +# (select) & 0xff) | \ +# ((umask) & 0xff) << 8) +# +# @select: x86 PMU event select field, which is a 12-bit unsigned +# number. +# +# @umask: x86 PMU event umask field. +# +# Since 10.0 +## +{ 'struct': 'KVMPMUX86DefalutEvent', + 'data': { 'select': 'uint16', + 'umask': 'uint8' } } + ## # @KVMPMUFilterEvent: # @@ -58,7 +79,8 @@ { 'union': 'KVMPMUFilterEvent', 'base': { 'format': 'KVMPMUEventEncodeFmt' }, 'discriminator': 'format', - 'data': { 'raw': 'KVMPMURawEvent' } } + 'data': { 'raw': 'KVMPMURawEvent', + 'x86-default': 'KVMPMUX86DefalutEvent' } } ## # @KVMPMUFilterProperty: @@ -86,6 +108,23 @@ { 'struct': 'KVMPMURawEventVariant', 'data': { 'code': 'str' } } +## +# @KVMPMUX86DefalutEventVariant: +# +# The variant of KVMPMUX86DefalutEvent with the string, rather than +# the numeric value. +# +# @select: x86 PMU event select field. This field is a 12-bit +# unsigned number string. +# +# @umask: x86 PMU event umask field. This field is a uint8 string. +# +# Since 10.0 +## +{ 'struct': 'KVMPMUX86DefalutEventVariant', + 'data': { 'select': 'str', + 'umask': 'str' } } + ## # @KVMPMUFilterEventVariant: # @@ -98,7 +137,8 @@ { 'union': 'KVMPMUFilterEventVariant', 'base': { 'format': 'KVMPMUEventEncodeFmt' }, 'discriminator': 'format', - 'data': { 'raw': 'KVMPMURawEventVariant' } } + 'data': { 'raw': 'KVMPMURawEventVariant', + 'x86-default': 'KVMPMUX86DefalutEventVariant' } } ## # @KVMPMUFilterPropertyVariant: diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index b82adbed50f4..bab58761417a 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5970,6 +5970,10 @@ static bool kvm_config_pmu_event(KVMPMUFilter *filter, case KVM_PMU_EVENT_FMT_RAW: code = event->u.raw.code; break; + case KVM_PMU_EVENT_FMT_X86_DEFAULT: + code = X86_PMU_RAW_EVENT(event->u.x86_default.select, + event->u.x86_default.umask); + break; default: g_assert_not_reached(); } @@ -6640,6 +6644,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, switch (event->format) { case KVM_PMU_EVENT_FMT_RAW: + case KVM_PMU_EVENT_FMT_X86_DEFAULT: break; default: error_setg(errp, From patchwork Wed Jan 22 09:05:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13947021 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 10A991537D4 for ; Wed, 22 Jan 2025 08:46:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535589; cv=none; b=QIprYbY0AGow3bcBPt9/L6Zjvod0/nWTmHigQK6FSRocjFzCrhKTuX0TGStf4LZ0O7ersNd23MWuHu6VAwVVFsjVJfUbacB8fI066e6qcw7NjqGVKbKKKc1HEBSsOeMOO6vpUh67kB+HSrhTxXRcNbCDrP/N9JPrc2kaJ67wdiE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535589; c=relaxed/simple; bh=0Zj1pK2FHXf1BvAq4W768QzuPxnMz2DRuJqlcMCtTe0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=WTNrIxH/xclviNeOtVcn2i+tkJUwSISCusTaPYLIE7SADY07Lb3BLTnp7+IH0rXi7L4rwck8uxSlmbn3LqzMvQaCT0O22QAqe7+wFrWOLJxmxGKFkkuTi5wRJFLPEIEueVBNjz1SerY7rl1xCcj7X7Iiulf5jLmeYgNTnR9AIbE= 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=KcCQPSVQ; arc=none smtp.client-ip=198.175.65.9 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="KcCQPSVQ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1737535588; x=1769071588; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0Zj1pK2FHXf1BvAq4W768QzuPxnMz2DRuJqlcMCtTe0=; b=KcCQPSVQXG2SKBYshT629UAZ5XWf2YDt20pQtxH+R4hI1P2ylYZfDxMt ewi4GFuJk1YjTczhhgwPzFoHRwM8IZTfN128yvbg48MSQ4/bQ7kcLH3ab oj4CbnLYJCJTi3elq8/i9lHtBzRkwZtZ2A4A1510icSbyCp8CuPxJexbL pkw5fPfVRYGKYbEJF2XBrAWxicL8yVsun7wq3Tlp9sZTNr1q2auRmWaHy aE0UaLUHZmCFeDU74QB8kzAKvNtfKUap1HwpxRpWkyz+45EC4gcwDJqnR L+9nkmU+4sT/1bd+X8XIxBT0FHIrLzqzV8Q4EGSSgu77X6ps1C8P7ZVS9 g==; X-CSE-ConnectionGUID: thuRuuD0SOapVoVP7ZoN9Q== X-CSE-MsgGUID: nO4fMh/zRz2l81WDGAw9pA== X-IronPort-AV: E=McAfee;i="6700,10204,11322"; a="60451590" X-IronPort-AV: E=Sophos;i="6.13,224,1732608000"; d="scan'208";a="60451590" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jan 2025 00:46:28 -0800 X-CSE-ConnectionGUID: 9iOaAaR8SoSnqJLZfdS3gg== X-CSE-MsgGUID: WRTm5araTDWKtHiVkDMGcA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="112049932" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by orviesa003.jf.intel.com with ESMTP; 22 Jan 2025 00:46:23 -0800 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: [RFC v2 4/5] i386/kvm: Support event with masked entry format in KVM PMU filter Date: Wed, 22 Jan 2025 17:05:16 +0800 Message-Id: <20250122090517.294083-5-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250122090517.294083-1-zhao1.liu@intel.com> References: <20250122090517.294083-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 --- Changes since RFC v1: * Bump up the supported QAPI version to 10.0. --- accel/kvm/kvm-pmu.c | 91 +++++++++++++++++++++++++++++++++++++++++++ qapi/kvm.json | 68 ++++++++++++++++++++++++++++++-- target/i386/kvm/kvm.c | 39 +++++++++++++++++++ 3 files changed, 195 insertions(+), 3 deletions(-) diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c index cbd32e8e21f8..9d68cd15e477 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -62,6 +62,16 @@ static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name, str_event->u.x86_default.umask = g_strdup_printf("0x%x", event->u.x86_default.umask); break; + case KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY: + str_event->u.x86_masked_entry.select = + g_strdup_printf("0x%x", event->u.x86_masked_entry.select); + str_event->u.x86_masked_entry.match = + g_strdup_printf("0x%x", event->u.x86_masked_entry.match); + str_event->u.x86_masked_entry.mask = + g_strdup_printf("0x%x", event->u.x86_masked_entry.mask); + str_event->u.x86_masked_entry.exclude = + event->u.x86_masked_entry.exclude; + break; default: g_assert_not_reached(); } @@ -160,6 +170,87 @@ static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name, event->u.x86_default.umask = umask; break; } + case KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY: { + uint64_t select, match, mask; + + ret = qemu_strtou64(str_event->u.x86_masked_entry.select, + NULL, 0, &select); + if (ret < 0) { + error_setg(errp, + "Invalid %s PMU event (select: %s): %s. " + "The select must be a " + "12-bit unsigned number string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_masked_entry.select, + strerror(-ret)); + g_free(event); + goto fail; + } + if (select > UINT12_MAX) { + error_setg(errp, + "Invalid %s PMU event (select: %s): " + "Numerical result out of range. " + "The select must be a " + "12-bit unsigned number string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_masked_entry.select); + g_free(event); + goto fail; + } + event->u.x86_masked_entry.select = select; + + ret = qemu_strtou64(str_event->u.x86_masked_entry.match, + NULL, 0, &match); + if (ret < 0) { + error_setg(errp, + "Invalid %s PMU event (match: %s): %s. " + "The match must be a uint8 string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_masked_entry.match, + strerror(-ret)); + g_free(event); + goto fail; + } + if (match > UINT8_MAX) { + error_setg(errp, + "Invalid %s PMU event (match: %s): " + "Numerical result out of range. " + "The match must be a uint8 string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_masked_entry.match); + g_free(event); + goto fail; + } + event->u.x86_masked_entry.match = match; + + ret = qemu_strtou64(str_event->u.x86_masked_entry.mask, + NULL, 0, &mask); + if (ret < 0) { + error_setg(errp, + "Invalid %s PMU event (mask: %s): %s. " + "The mask must be a uint8 string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_masked_entry.mask, + strerror(-ret)); + g_free(event); + goto fail; + } + if (mask > UINT8_MAX) { + error_setg(errp, + "Invalid %s PMU event (mask: %s): " + "Numerical result out of range. " + "The mask must be a uint8 string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.x86_masked_entry.mask); + g_free(event); + goto fail; + } + event->u.x86_masked_entry.mask = mask; + + event->u.x86_masked_entry.exclude = + str_event->u.x86_masked_entry.exclude; + break; + } default: g_assert_not_reached(); } diff --git a/qapi/kvm.json b/qapi/kvm.json index 93b869e3f90c..a673e499e7ea 100644 --- a/qapi/kvm.json +++ b/qapi/kvm.json @@ -29,11 +29,14 @@ # # @x86-default: 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.0 ## { 'enum': 'KVMPMUEventEncodeFmt', 'prefix': 'KVM_PMU_EVENT_FMT', - 'data': ['raw', 'x86-default'] } + 'data': ['raw', 'x86-default', 'x86-masked-entry'] } ## # @KVMPMURawEvent: @@ -67,6 +70,40 @@ 'data': { 'select': 'uint16', 'umask': 'uint8' } } +## +# @KVMPMUX86MaskedEntry: +# +# x86 PMU events encoding in KVM masked entry format. +# +# Encoding layout: +# Bits Description +# ---- ----------- +# 7:0 event select (low bits) +# 15:8 (umask) match +# 31:16 unused +# 35:32 event select (high bits) +# 36:54 unused +# 55 exclude bit +# 63:56 (umask) mask +# +# Events are selected by (umask & mask == match) +# +# @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.0 +## +{ 'struct': 'KVMPMUX86MaskedEntry', + 'data': { 'select': 'uint16', + 'match': 'uint8', + 'mask': 'uint8', + 'exclude': 'bool' } } + ## # @KVMPMUFilterEvent: # @@ -80,7 +117,8 @@ 'base': { 'format': 'KVMPMUEventEncodeFmt' }, 'discriminator': 'format', 'data': { 'raw': 'KVMPMURawEvent', - 'x86-default': 'KVMPMUX86DefalutEvent' } } + 'x86-default': 'KVMPMUX86DefalutEvent', + 'x86-masked-entry': 'KVMPMUX86MaskedEntry' } } ## # @KVMPMUFilterProperty: @@ -125,6 +163,29 @@ 'data': { 'select': 'str', 'umask': 'str' } } +## +# @KVMPMUX86MaskedEntryVariant: +# +# The variant of KVMPMUX86MaskedEntry with the string, rather than +# the numeric value. +# +# @select: x86 PMU event select. This field is a 12-bit unsigned +# number string. +# +# @match: umask match. This field is a uint8 string. +# +# @mask: umask mask. This field is a uint8 string. +# +# @exclude: Whether the matched events are excluded. +# +# Since 10.0 +## +{ 'struct': 'KVMPMUX86MaskedEntryVariant', + 'data': { 'select': 'str', + 'match': 'str', + 'mask': 'str', + 'exclude': 'bool' } } + ## # @KVMPMUFilterEventVariant: # @@ -138,7 +199,8 @@ 'base': { 'format': 'KVMPMUEventEncodeFmt' }, 'discriminator': 'format', 'data': { 'raw': 'KVMPMURawEventVariant', - 'x86-default': 'KVMPMUX86DefalutEventVariant' } } + 'x86-default': 'KVMPMUX86DefalutEventVariant', + 'x86-masked-entry': 'KVMPMUX86MaskedEntryVariant' } } ## # @KVMPMUFilterPropertyVariant: diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index bab58761417a..97b94c331271 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5974,6 +5974,13 @@ static bool kvm_config_pmu_event(KVMPMUFilter *filter, code = X86_PMU_RAW_EVENT(event->u.x86_default.select, event->u.x86_default.umask); break; + case KVM_PMU_EVENT_FMT_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(); } @@ -6005,6 +6012,21 @@ static int kvm_install_pmu_event_filter(KVMState *s) g_assert_not_reached(); } + /* + * The check in kvm_arch_check_pmu_filter() ensures masked entry + * format won't be mixed with other formats. + */ + kvm_filter->flags = filter->events->value->format == + KVM_PMU_EVENT_FMT_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; } @@ -6632,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, @@ -6639,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_FMT_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_FMT_RAW: case KVM_PMU_EVENT_FMT_X86_DEFAULT: + flag = 0; + break; + case KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY: + flag = KVM_PMU_EVENT_FLAG_MASKED_EVENTS; break; default: error_setg(errp, @@ -6653,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 Jan 22 09:05:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13947022 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.9]) (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 CFBA11C3C1F for ; Wed, 22 Jan 2025 08:46:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535594; cv=none; b=mTsLRqTAqX7Be8+Cm4NKzGnz6MCeylSa8UfO5PejXo/LCwOgfpxsUrk7F4uBH+9PGRrzat0Lo10fJjS5q3pkRKam32P929QzT0o/c8F0NngqgIZ+vEGJwqUERszXgwfR40Y1gJkN6PB2M4s2UDjo5jdjA8pt802nUt8Bg2OzSAM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737535594; c=relaxed/simple; bh=tx3RGOKpgLyLZ7GXDq98/4kQnth6yPo3Tpolx+oTmh8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FpdZ0OucluCn7ysP2xIL1qu4tig7Vf3qg9iy27vgLsn+ZItUYnmHwwDhwrW/p47SdRGWogL6p93QtsuB+exdIZj69HeV6gKcoNhFdDkNMGJFAGYK1zeHKjIsFqBfGymq9C9XWDOhDEQfczCORqti47+3HS56rdQNQaYkJRLn9oI= 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=MJVDnUgO; arc=none smtp.client-ip=198.175.65.9 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="MJVDnUgO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1737535593; x=1769071593; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=tx3RGOKpgLyLZ7GXDq98/4kQnth6yPo3Tpolx+oTmh8=; b=MJVDnUgOBm3fiOCxClubxmJu/7ogMmeBc6IEQjciGvbMMGVKw1F/oDLu OFh8DhumYilt0O/Yzb+FgcDGpCd4ui99G4O4HM7OtK8pWERhbvtjORX5d Qe7fN2SOOKi/IhTZyMhgbRv7EfvuqbIbiUep/L3tVztFXBR+BzS/NawPV oz+y3dD0DANN/IuelDUdIyo6eQvnOgTRZ4+GBrjBqdIO5VSGbUoSl4T2d AHlQJd9bhuSvI3HBbTZYLIikbHAf/Mp7W10L+9MfzVXfMIN8fSL9BLIsm XbYDBh0an4SGLgpJN016/cEU0HGQFU+ckyBU1IhraGkPk3ByouG5xTH7B A==; X-CSE-ConnectionGUID: 7gbg7otdRr6m5N3gQT8k4w== X-CSE-MsgGUID: 4FXk4QSYSHW09Fy0vfoG7Q== X-IronPort-AV: E=McAfee;i="6700,10204,11322"; a="60451601" X-IronPort-AV: E=Sophos;i="6.13,224,1732608000"; d="scan'208";a="60451601" Received: from orviesa003.jf.intel.com ([10.64.159.143]) by orvoesa101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jan 2025 00:46:33 -0800 X-CSE-ConnectionGUID: wzwRvwuNTkGoUHIrSuVrPg== X-CSE-MsgGUID: WmOy/5HuR/WwhfHG2pABlw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="112050019" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.39]) by orviesa003.jf.intel.com with ESMTP; 22 Jan 2025 00:46:28 -0800 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: [RFC v2 5/5] i386/kvm: Support fixed counter in KVM PMU filter Date: Wed, 22 Jan 2025 17:05:17 +0800 Message-Id: <20250122090517.294083-6-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250122090517.294083-1-zhao1.liu@intel.com> References: <20250122090517.294083-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 --- 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 10.0. --- accel/kvm/kvm-pmu.c | 69 ++++++++++++++++++++++++++++++++++++++++ include/system/kvm-pmu.h | 1 + qapi/kvm.json | 30 ++++++++++++++++- target/i386/kvm/kvm.c | 47 ++++++++++++++++----------- 4 files changed, 127 insertions(+), 20 deletions(-) diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c index 9d68cd15e477..b5e6f430632f 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -271,6 +271,66 @@ 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); + KVMPMUX86FixedCounterVariant *str_counter; + + str_counter = g_new(KVMPMUX86FixedCounterVariant, 1); + str_counter->bitmap = g_strdup_printf("0x%x", + filter->x86_fixed_counter->bitmap); + + visit_type_KVMPMUX86FixedCounterVariant(v, name, &str_counter, errp); + qapi_free_KVMPMUX86FixedCounterVariant(str_counter); +} + +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); + KVMPMUX86FixedCounterVariant *str_counter; + KVMPMUX86FixedCounter *new_counter, *old_counter; + uint64_t bitmap; + int ret; + + old_counter = filter->x86_fixed_counter; + if (!visit_type_KVMPMUX86FixedCounterVariant(v, name, + &str_counter, errp)) { + return; + } + + new_counter = g_new(KVMPMUX86FixedCounter, 1); + + ret = qemu_strtou64(str_counter->bitmap, NULL, + 0, &bitmap); + if (ret < 0) { + error_setg(errp, + "Invalid x86 fixed counter (bitmap: %s): %s. " + "The bitmap must be a uint32 string.", + str_counter->bitmap, strerror(-ret)); + g_free(new_counter); + goto fail; + } + if (bitmap > UINT32_MAX) { + error_setg(errp, + "Invalid x86 fixed counter (bitmap: %s): " + "Numerical result out of range. " + "The bitmap must be a uint32 string.", + str_counter->bitmap); + g_free(new_counter); + goto fail; + } + new_counter->bitmap = bitmap; + filter->x86_fixed_counter = new_counter; + qapi_free_KVMPMUX86FixedCounter(old_counter); + +fail: + qapi_free_KVMPMUX86FixedCounterVariant(str_counter); +} + static void kvm_pmu_filter_class_init(ObjectClass *oc, void *data) { object_class_property_add_enum(oc, "action", "KVMPMUFilterAction", @@ -286,6 +346,15 @@ 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", + "KVMPMUX86FixedCounter", + 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 63402f75cfdc..1a1da37b6304 100644 --- a/include/system/kvm-pmu.h +++ b/include/system/kvm-pmu.h @@ -25,6 +25,7 @@ struct KVMPMUFilter { KVMPMUFilterAction action; uint32_t nevents; KVMPMUFilterEventList *events; + KVMPMUX86FixedCounter *x86_fixed_counter; }; /* diff --git a/qapi/kvm.json b/qapi/kvm.json index a673e499e7ea..31447dfeffb0 100644 --- a/qapi/kvm.json +++ b/qapi/kvm.json @@ -120,6 +120,18 @@ 'x86-default': 'KVMPMUX86DefalutEvent', 'x86-masked-entry': 'KVMPMUX86MaskedEntry' } } +## +# @KVMPMUX86FixedCounter: +# +# x86 fixed counter that KVM PMU filter supports. +# +# @bitmap: x86 fixed counter bitmap. +# +# Since 10.0 +## +{ 'struct': 'KVMPMUX86FixedCounter', + 'data': { 'bitmap': 'uint32' } } + ## # @KVMPMUFilterProperty: # @@ -202,6 +214,19 @@ 'x86-default': 'KVMPMUX86DefalutEventVariant', 'x86-masked-entry': 'KVMPMUX86MaskedEntryVariant' } } +## +# @KVMPMUX86FixedCounterVariant: +# +# The variant of KVMPMUX86FixedCounter with the string, rather than +# the numeric value. +# +# @bitmap: x86 fixed counter bitmap. This field is a uint32 string. +# +# Since 10.0 +## +{ 'struct': 'KVMPMUX86FixedCounterVariant', + 'data': { 'bitmap': 'str' } } + ## # @KVMPMUFilterPropertyVariant: # @@ -211,8 +236,11 @@ # # @events: the KVMPMUFilterEventVariant list. # +# @x86-fixed-counter: enablement bitmap of x86 fixed counters. +# # Since 10.0 ## { 'struct': 'KVMPMUFilterPropertyVariant', 'data': { 'action': 'KVMPMUFilterAction', - '*events': ['KVMPMUFilterEventVariant'] } } + '*events': ['KVMPMUFilterEventVariant'], + '*x86-fixed-counter': 'KVMPMUX86FixedCounterVariant' } } diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 97b94c331271..56094361cb8f 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -6012,23 +6012,29 @@ static int kvm_install_pmu_event_filter(KVMState *s) g_assert_not_reached(); } - /* - * The check in kvm_arch_check_pmu_filter() ensures masked entry - * format won't be mixed with other formats. - */ - kvm_filter->flags = filter->events->value->format == - KVM_PMU_EVENT_FMT_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->bitmap; } - if (!kvm_config_pmu_event(filter, kvm_filter)) { - goto fail; + if (filter->nevents) { + /* + * The check in kvm_arch_check_pmu_filter() ensures masked entry + * format won't be mixed with other formats. + */ + kvm_filter->flags = filter->events->value->format == + KVM_PMU_EVENT_FMT_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_FMT_X86_MASKED_ENTRY ? - KVM_PMU_EVENT_FLAG_MASKED_EVENTS : 0; + base_flag = 0; + if (filter->nevents && + events->value->format == KVM_PMU_EVENT_FMT_X86_MASKED_ENTRY) { + base_flag = KVM_PMU_EVENT_FLAG_MASKED_EVENTS; + } + while (events) { KVMPMUFilterEvent *event = events->value; uint32_t flag;