From patchwork Wed Jul 10 04:51:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13728866 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 709794206C for ; Wed, 10 Jul 2024 04:36:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586169; cv=none; b=p2/cY4GW3Dsh1ZTnXkhAV2+2HQIJdb2OGqvS1/XgrmW4P0BGSY3vlXjGJozUZqIBFs/5UZ5sqGuWbXla52C8aFFnT3Kl0mkDieiQXwBZ9jskZ0MW5b2ZKQ8JVfBHOp3kIu+5To7LOHpTiWWY79LfAsuMe/PHUAUpOOuyCrdcxsw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586169; c=relaxed/simple; bh=4Gl90JTr0DPqZym9GzC30MAvpGMWS2nNyp9RK7fmVl8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=GoDF8dD/Np99tCYaEyyY2I/OKkeppXxfB4IJ2pSre/egb0+sgRCnOCsyj2aVkpR3Ak/GsuDffMfXnoxa8iV16C4gMxANtrTpo3BMRuor9JNmv6OsXT2+dunwpcS16QzbnFtE6TcANs2UAbuypfbHZAg3ir27YccNSS4/vlm4nno= 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=Te9/Gh5o; arc=none smtp.client-ip=198.175.65.11 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="Te9/Gh5o" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586166; x=1752122166; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4Gl90JTr0DPqZym9GzC30MAvpGMWS2nNyp9RK7fmVl8=; b=Te9/Gh5ogBvZWaSm8zuds5ARtMAeNV7quQmGpJSvy3Brs3UBR0mzQwv7 AQnWUg7VfuOUY0I2JxbM0bG9TKCNz0u+t73hsxz7EMz4+MA8zTWdLaRIF Qz4XLpU+Y5nvtslkGWQ/X80RxP5BXQ6YI5p5TNWb9TepM75j5k2aeuucV CvCivIbU+Rmd4xUULqwwebHLL5SFiqFT0Bc4KnrQJTGEqeiSHVBsgtezE BuTakY/hEx1ag7rdes3mxtVo0J0XtTNKTJvj46fJgZ7jy/tL+23CYPvKJ KxFk3yh33EZdorob3ezXCA/GK+EIsU+7OiYYNoc4oPI4BZFEw0vy4be4k g==; X-CSE-ConnectionGUID: gD9udg56T6ylxtGTDJrCJQ== X-CSE-MsgGUID: HJoZgc9iRKORF25YLENFmg== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473769" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473769" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jul 2024 21:36:02 -0700 X-CSE-ConnectionGUID: txlL5t2VTgSFRIUWInVasg== X-CSE-MsgGUID: VaM4LmLvSeWe8mHnhi/OOQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="79238121" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.36]) by fmviesa001.fm.intel.com with ESMTP; 09 Jul 2024 21:35:57 -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, Zhenyu Wang , Dapeng Mi , Yuan Yao , Xiong Zhang , Mingwei Zhang , Jim Mattson , Zhao Liu Subject: [RFC 1/5] qapi/qom: Introduce kvm-pmu-filter object Date: Wed, 10 Jul 2024 12:51:13 +0800 Message-Id: <20240710045117.3164577-2-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240710045117.3164577-1-zhao1.liu@intel.com> References: <20240710045117.3164577-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 --- MAINTAINERS | 1 + accel/kvm/kvm-pmu.c | 143 +++++++++++++++++++++++++++++++++++++++ accel/kvm/meson.build | 1 + include/sysemu/kvm-pmu.h | 29 ++++++++ qapi/kvm.json | 119 ++++++++++++++++++++++++++++++++ qapi/meson.build | 1 + qapi/qapi-schema.json | 1 + qapi/qom.json | 3 + 8 files changed, 298 insertions(+) create mode 100644 accel/kvm/kvm-pmu.c create mode 100644 include/sysemu/kvm-pmu.h create mode 100644 qapi/kvm.json diff --git a/MAINTAINERS b/MAINTAINERS index 6725913c8b3a..8c36c04a3eb2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -439,6 +439,7 @@ F: accel/kvm/ F: accel/stubs/kvm-stub.c F: include/hw/kvm/ F: include/sysemu/kvm*.h +F: qapi/kvm.json F: scripts/kvm/kvm_flightrecorder ARM KVM CPUs diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c new file mode 100644 index 000000000000..483d1bdf4807 --- /dev/null +++ b/accel/kvm/kvm-pmu.c @@ -0,0 +1,143 @@ +/* + * 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 "sysemu/kvm-pmu.h" + +static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + KVMPMUFilterEventList *node; + KVMPMUFilterEventVariantList *head = NULL; + KVMPMUFilterEventVariantList **tail = &head; + + for (node = filter->events; node; node = node->next) { + KVMPMUFilterEventVariant *str_event; + KVMPMUFilterEvent *event = node->value; + + str_event = g_new(KVMPMUFilterEventVariant, 1); + str_event->action = event->action; + str_event->format = event->format; + + switch (event->format) { + case KVM_PMU_EVENT_FMT_RAW: + str_event->u.raw.code = g_strdup_printf("0x%lx", + event->u.raw.code); + break; + default: + g_assert_not_reached(); + } + + QAPI_LIST_APPEND(tail, str_event); + } + + visit_type_KVMPMUFilterEventVariantList(v, name, &head, errp); + qapi_free_KVMPMUFilterEventVariantList(head); +} + +static void kvm_pmu_filter_set_event(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + KVMPMUFilterEventVariantList *list, *node; + KVMPMUFilterEventList *head = NULL, *old_head; + KVMPMUFilterEventList **tail = &head; + int ret, nevents = 0; + + if (!visit_type_KVMPMUFilterEventVariantList(v, name, &list, errp)) { + return; + } + + for (node = list; node; node = node->next) { + KVMPMUFilterEvent *event = g_new(KVMPMUFilterEvent, 1); + KVMPMUFilterEventVariant *str_event = node->value; + + event->action = str_event->action; + event->format = str_event->format; + + switch (str_event->format) { + case KVM_PMU_EVENT_FMT_RAW: + ret = qemu_strtou64(str_event->u.raw.code, NULL, + 0, &event->u.raw.code); + if (ret < 0) { + error_setg(errp, + "Invalid %s PMU event (code: %s): %s. " + "The code must be a uint64 string.", + KVMPMUEventEncodeFmt_str(str_event->format), + str_event->u.raw.code, strerror(-ret)); + g_free(event); + goto fail; + } + break; + default: + g_assert_not_reached(); + } + + nevents++; + QAPI_LIST_APPEND(tail, event); + } + + old_head = filter->events; + filter->events = head; + filter->nevents = nevents; + + qapi_free_KVMPMUFilterEventVariantList(list); + qapi_free_KVMPMUFilterEventList(old_head); + return; + +fail: + qapi_free_KVMPMUFilterEventList(head); +} + +static void +kvm_pmu_filter_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add(oc, "events", + "KVMPMUFilterEvent", + kvm_pmu_filter_get_event, + kvm_pmu_filter_set_event, + NULL, NULL); + object_class_property_set_description(oc, "events", + "KVM PMU event list"); +} + +static void kvm_pmu_filter_instance_init(Object *obj) +{ + KVMPMUFilter *filter = KVM_PMU_FILTER(obj); + + filter->nevents = 0; +} + +static const TypeInfo kvm_pmu_filter_info = { + .parent = TYPE_OBJECT, + .name = TYPE_KVM_PMU_FILTER, + .class_init = kvm_pmu_filter_class_init, + .instance_size = sizeof(KVMPMUFilter), + .instance_init = kvm_pmu_filter_instance_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void +kvm_pmu_event_register_type(void) +{ + type_register_static(&kvm_pmu_filter_info); +} + +type_init(kvm_pmu_event_register_type); 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/sysemu/kvm-pmu.h b/include/sysemu/kvm-pmu.h new file mode 100644 index 000000000000..4707759761f1 --- /dev/null +++ b/include/sysemu/kvm-pmu.h @@ -0,0 +1,29 @@ +/* + * 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; + + 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..0619da83c123 --- /dev/null +++ b/qapi/kvm.json @@ -0,0 +1,119 @@ +# -*- Mode: Python -*- +# vim: filetype=python + +## +# = KVM based feature API +## + +## +# @KVMPMUFilterAction: +# +# Actions that KVM PMU filter supports. +# +# @deny: disable the PMU event/counter in KVM PMU filter +# +# @allow: enable the PMU event/counter in KVM PMU filter +# +# Since 9.1 +## +{ 'enum': 'KVMPMUFilterAction', + 'prefix': 'KVM_PMU_FILTER_ACTION', + 'data': ['allow', 'deny'] } + +## +# @KVMPMUEventEncodeFmt: +# +# Encoding formats of PMU event that QEMU/KVM supports. +# +# @raw: the encoded event code that KVM can directly consume. +# +# Since 9.1 +## +{ 'enum': 'KVMPMUEventEncodeFmt', + 'prefix': 'KVM_PMU_EVENT_FMT', + 'data': ['raw'] } + +## +# @KVMPMURawEvent: +# +# Raw PMU event code. +# +# @code: the raw value that has been encoded, and QEMU could deliver +# to KVM directly. +# +# Since 9.1 +## +{ 'struct': 'KVMPMURawEvent', + 'data': { 'code': 'uint64' } } + +## +# @KVMPMUFilterEvent: +# +# PMU event filtered by KVM. +# +# @action: action that KVM PMU filter will take. +# +# @format: PMU event format. +# +# Since 9.1 +## +{ 'union': 'KVMPMUFilterEvent', + 'base': { 'action': 'KVMPMUFilterAction', + 'format': 'KVMPMUEventEncodeFmt' }, + 'discriminator': 'format', + 'data': { 'raw': 'KVMPMURawEvent' } } + +## +# @KVMPMUFilterProperty: +# +# Property of KVM PMU Filter. +# +# @events: the KVMPMUFilterEvent list. +# +# Since 9.1 +## +{ 'struct': 'KVMPMUFilterProperty', + 'data': { '*events': ['KVMPMUFilterEvent'] } } + +## +# @KVMPMURawEventVariant: +# +# The variant of KVMPMURawEvent with the string, rather than the +# numeric value. +# +# @code: the raw value that has been encoded, and QEMU could deliver +# to KVM directly. This field is a uint64 string. +# +# Since 9.1 +## +{ 'struct': 'KVMPMURawEventVariant', + 'data': { 'code': 'str' } } + +## +# @KVMPMUFilterEventVariant: +# +# The variant of KVMPMUFilterEvent. +# +# @action: action that KVM PMU filter will take. +# +# @format: PMU event format. +# +# Since 9.1 +## +{ 'union': 'KVMPMUFilterEventVariant', + 'base': { 'action': 'KVMPMUFilterAction', + 'format': 'KVMPMUEventEncodeFmt' }, + 'discriminator': 'format', + 'data': { 'raw': 'KVMPMURawEventVariant' } } + +## +# @KVMPMUFilterPropertyVariant: +# +# The variant of KVMPMUFilterProperty. +# +# @events: the KVMPMUFilterEventVariant list. +# +# Since 9.1 +## +{ 'struct': 'KVMPMUFilterPropertyVariant', + 'data': { '*events': ['KVMPMUFilterEventVariant'] } } 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 92b0fea76cb1..40175a97b4dd 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) @@ -1057,6 +1058,7 @@ 'if': 'CONFIG_LINUX' }, 'iommufd', 'iothread', + 'kvm-pmu-filter', 'main-loop', { 'name': 'memory-backend-epc', 'if': 'CONFIG_LINUX' }, @@ -1131,6 +1133,7 @@ 'if': 'CONFIG_LINUX' }, 'iommufd': 'IOMMUFDProperties', 'iothread': 'IothreadProperties', + 'kvm-pmu-filter': 'KVMPMUFilterPropertyVariant', 'main-loop': 'MainLoopProperties', 'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties', 'if': 'CONFIG_LINUX' }, From patchwork Wed Jul 10 04:51:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13728867 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 62F8E4EB51 for ; Wed, 10 Jul 2024 04:36:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586170; cv=none; b=PjXofd8iCJibdbPRZuokRcTW0OuRr5AJk8IDumoVCygI+L+bcoBaz7mrAAn4IR7O32xk5GaqUIHuY2B0medMlVcXRkuoqhxg6M+zjBXSjaRNwza0nKSRcSfEFhDNicRqxMx9X1p+0KRrs1LQbb2mUoNDbq9ZqQoyDqFuYSud2Xc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586170; c=relaxed/simple; bh=qMy1GX3+etGOKvBzHp/xRoSoF1eAUO1DrwJq/x8rfjk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=P+Pr7rxZK50CPsJ/cbYsyZ54NBHR/FAKtNXgaiD/X6snGm75Ho4yRCnf641hR1av3JXOOMJbKuvr7bqW35n9/4auboq06qJhSKTADjHHU7UqpudhUXQAYD/4JoxczsdNc0tZFsTPtUVwVZyfB1q52+0HCkLrJ1LIW1HAcPJp8vs= 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=S1+rp/VA; arc=none smtp.client-ip=198.175.65.11 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="S1+rp/VA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586168; x=1752122168; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qMy1GX3+etGOKvBzHp/xRoSoF1eAUO1DrwJq/x8rfjk=; b=S1+rp/VAnfsLoaxHv8Ib0oifjs7ENMHzkySwYFrJ6JiTcTvqk366ISMQ KLuLfv9T8roTqnE8BiciPN6zjLHKQv0YiqIpwWbF7zinC/kQlOuEkFAgr Chb8Ej6efiCVpG/RJJHdb401r34clHsxuwgf7Jq0PjDYn0fvs7lpRZ+19 oMKvlBUGjufX36+8HBcm/Uc90WqF8Zu10XE0V+ciRQBQVqNsMvDf2cxPm EiKguPWpas76wN7haD0gYUxQ3u51tbZvzK/GCync+X4wD+nesf++MHwyt GKeXEROT8ybELK8kC2XiU8EZ2HW9bMLbf+cgM26u3XD4ZZtCa464bQHbP Q==; X-CSE-ConnectionGUID: aHbblsEdRGyiFbtGAGX57w== X-CSE-MsgGUID: 3/ojS+BFS2+/mPipGUM/4g== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473791" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473791" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jul 2024 21:36:07 -0700 X-CSE-ConnectionGUID: eNip1eA/Qs2LWBMAurq/uQ== X-CSE-MsgGUID: 9l7NAIsHSfCngVDXlgJPxw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="79238163" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.36]) by fmviesa001.fm.intel.com with ESMTP; 09 Jul 2024 21:36:02 -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, Zhenyu Wang , Dapeng Mi , Yuan Yao , Xiong Zhang , Mingwei Zhang , Jim Mattson , Zhao Liu Subject: [RFC 2/5] i386/kvm: Support initial KVM PMU filter Date: Wed, 10 Jul 2024 12:51:14 +0800 Message-Id: <20240710045117.3164577-3-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240710045117.3164577-1-zhao1.liu@intel.com> References: <20240710045117.3164577-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 --- include/sysemu/kvm_int.h | 2 + target/i386/kvm/kvm.c | 144 +++++++++++++++++++++++++++++++++++++ target/i386/kvm/kvm_i386.h | 1 + 3 files changed, 147 insertions(+) diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h index 3f3d13f81669..9ab566cb4494 100644 --- a/include/sysemu/kvm_int.h +++ b/include/sysemu/kvm_int.h @@ -14,6 +14,7 @@ #include "qemu/accel.h" #include "qemu/queue.h" #include "sysemu/kvm.h" +#include "sysemu/kvm-pmu.h" typedef struct KVMSlot { @@ -124,6 +125,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 becca2efa5b4..e9bf79782316 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -30,6 +30,7 @@ #include "sysemu/sysemu.h" #include "sysemu/hw_accel.h" #include "sysemu/kvm_int.h" +#include "sysemu/kvm-pmu.h" #include "sysemu/runstate.h" #include "kvm_i386.h" #include "../confidential-guest.h" @@ -2806,6 +2807,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + if (s->pmu_filter) { + bool r; + + r = kvm_filter_pmu_event(s); + if (!r) { + error_report("Could not set KVM PMU filter"); + exit(1); + } + } + return 0; } @@ -5363,6 +5374,91 @@ static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run) assert(false); } +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 bool 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)); + + /* + * Currently, kvm-pmu-filter only supports configuring the same + * action for PMU events. + */ + switch (filter->events->value->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 true; +fail: + g_free(kvm_filter); + return false; +} + +bool 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 false; + } + + if (!kvm_install_pmu_event_filter(s)) { + return false; + } + + return true; +} + static bool has_sgx_provisioning; static bool __kvm_enable_sgx_provisioning(KVMState *s) @@ -5958,6 +6054,46 @@ 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; + KVMPMUFilterAction action; + + if (!filter->nevents) { + error_setg(errp, + "Empty KVM PMU filter."); + return; + } + + action = KVM_PMU_FILTER_ACTION__MAX; + 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; + } + + if (action == KVM_PMU_FILTER_ACTION__MAX) { + action = event->action; + } else if (action != event->action) { + /* TODO: Support events with different actions if necessary. */ + error_setg(errp, + "Only support PMU events with the same action"); + return; + } + + events = events->next; + } +} + void kvm_arch_accel_class_init(ObjectClass *oc) { object_class_property_add_enum(oc, "notify-vmexit", "NotifyVMexitOption", @@ -5997,6 +6133,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) diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index 34fc60774b86..5cdc7106424d 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -76,6 +76,7 @@ typedef struct kvm_msr_handlers { bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr, QEMUWRMSRHandler *wrmsr); +bool kvm_filter_pmu_event(KVMState *s); #endif /* CONFIG_KVM */ From patchwork Wed Jul 10 04:51:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13728868 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 3E4B252F62 for ; Wed, 10 Jul 2024 04:36:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586175; cv=none; b=O1DQbNkswOY5QkoKX90ZqakC48uEp8B7wZOTUejbdST2y7e2uysIRc7XyHXKDTQaJiqLUreeTh3ENnbQ9CFHk3GahSOYaQATSzH+c25pscuBPtcb55pFxwfSPwZMo94CNbbwnqXjJLcKs2keskP5bJavjnPNRqPe1ANiNokhp/k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586175; c=relaxed/simple; bh=il1oqspy53sUEFgjjMRnGbdzD5ZqcNCxcsioWrvP064=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=lYE9JQb7hUDx+IUQUZP5caRiwSAXZZjc21fSbcHYT87R2SUhGVHMVDIcRe1RXCQpIsJvVYKjlTMMxeiPniN68FtlFPUAqil8jTykpVjTSdtJQshaD3usXmgHnaR7QrbjTSdy+B458QFlf0X0iwCEL1sUTE1BIZ7rhLVGQGyoNeM= 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=FdMpW9MH; arc=none smtp.client-ip=198.175.65.11 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="FdMpW9MH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586173; x=1752122173; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=il1oqspy53sUEFgjjMRnGbdzD5ZqcNCxcsioWrvP064=; b=FdMpW9MHN3qYnxMhQt+gB+uVo/Ca/iHDVfrvZ6F8+5fp6ew0v7aGt+Nb gkI9pbfgBawrIpge355eao0P8o7LGg9NzzAqJYBMBUGQQfu4exTdj5HX3 o4AbuullQnix2As8Gsba+fgN2t1854ttl7ySWRP9+T4yHJtzm0/ePCWNH kGzeEr5NFMPHyLuI2keePtqdyYe0ejObwtEygSsTueH9ABhRM7a3jtiLY z6jyZ5Ccw9hRGgofOnNR78didkMxZClXdRcQF8ErIQ0UWwCxNsqGRr069 XwOyu1rBt3lR0wZcNBcBrHeBUoIKJzStyvgGCawlIJ+Aftai9KydblUZ7 A==; X-CSE-ConnectionGUID: Pc/rAuHkRpKOm1yyr7f+Ug== X-CSE-MsgGUID: 30XsKGL3TuOtKXr5qnm92A== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473796" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473796" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jul 2024 21:36:12 -0700 X-CSE-ConnectionGUID: XUATnMDHTsqI9za+FGvJzw== X-CSE-MsgGUID: FNhK2+48SASyPAGhC9c+wg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="79238185" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.36]) by fmviesa001.fm.intel.com with ESMTP; 09 Jul 2024 21:36:08 -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, Zhenyu Wang , Dapeng Mi , Yuan Yao , Xiong Zhang , Mingwei Zhang , Jim Mattson , Zhao Liu Subject: [RFC 3/5] i386/kvm: Support event with select&umask format in KVM PMU filter Date: Wed, 10 Jul 2024 12:51:15 +0800 Message-Id: <20240710045117.3164577-4-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240710045117.3164577-1-zhao1.liu@intel.com> References: <20240710045117.3164577-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 --- accel/kvm/kvm-pmu.c | 62 ++++++++++++++++++++++++++++++++++++++++ include/sysemu/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 483d1bdf4807..51d3fba5a72a 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -17,6 +17,8 @@ #include "qom/object_interfaces.h" #include "sysemu/kvm-pmu.h" +#define UINT12_MAX (4095) + static void kvm_pmu_filter_get_event(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -38,6 +40,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(); } @@ -83,6 +91,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/sysemu/kvm-pmu.h b/include/sysemu/kvm-pmu.h index 4707759761f1..707f33d604fd 100644 --- a/include/sysemu/kvm-pmu.h +++ b/include/sysemu/kvm-pmu.h @@ -26,4 +26,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 0619da83c123..0d759884c229 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 9.1 ## { '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 9.1 +## +{ 'struct': 'KVMPMUX86DefalutEvent', + 'data': { 'select': 'uint16', + 'umask': 'uint8' } } + ## # @KVMPMUFilterEvent: # @@ -61,7 +82,8 @@ 'base': { 'action': 'KVMPMUFilterAction', 'format': 'KVMPMUEventEncodeFmt' }, 'discriminator': 'format', - 'data': { 'raw': 'KVMPMURawEvent' } } + 'data': { 'raw': 'KVMPMURawEvent', + 'x86-default': 'KVMPMUX86DefalutEvent' } } ## # @KVMPMUFilterProperty: @@ -89,6 +111,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 9.1 +## +{ 'struct': 'KVMPMUX86DefalutEventVariant', + 'data': { 'select': 'str', + 'umask': 'str' } } + ## # @KVMPMUFilterEventVariant: # @@ -104,7 +143,8 @@ 'base': { 'action': 'KVMPMUFilterAction', '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 e9bf79782316..391531c036a6 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5393,6 +5393,10 @@ 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(); } @@ -6073,6 +6077,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 Jul 10 04:51:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13728869 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 86DFE53804 for ; Wed, 10 Jul 2024 04:36:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586180; cv=none; b=Nuz1KVX8zt84wylbcHe/3aOw3dMifzF06GLda4jVAJ/Ux+91OA7WhYGBzxhN6ynRlqcswiB1B02ZOs+nPsZOeiyvM1h+QmMQA8LiCrSyBpwgaU2FkqomsvPUnMO3xceIATbA1MmnN9NT8nT3VXoEKWxI/BcXIrL0mVCMFsftgjE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586180; c=relaxed/simple; bh=COv/wxh7LoZnCJkoFwP3rD91fqQddYuwNXRcw9JrnaY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=NN1QGDRX//NQzVleLHaUCJB3txSqliZeBPm9E1qGivAhmREUeqdBSLWnYLydcPf69DslCDBQCG21MYSkpMVb02dTHfsPWa2uXullW5l3+wNDYrV21eF8za2j/VZEPItp8Zr4Wpz1l73ab3roL7SeNL0SKdOxhSwvvT0ZAVi47YQ= 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=FfSL3R8w; arc=none smtp.client-ip=198.175.65.11 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="FfSL3R8w" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586178; x=1752122178; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=COv/wxh7LoZnCJkoFwP3rD91fqQddYuwNXRcw9JrnaY=; b=FfSL3R8wXBLPH6fX0vpJacPHdMdZ1LgmUaFN6hFI5cX/o0OyVzAKyVom r9sY1CXf1YYMmDpXb3ui88p0Xxyl5n1gS8YIC7SMd2JQIALrOx0PcL2yu cRMOFNUTlWS+axfgLLQ6ozv6d4LsYEqyOJQ7yuGBTdebJkklnbui654S5 Et7M/qdN7LgCbfoQKnO1XvWZ975Wf3jh2/5gum8wPJTedeIj73b7vSFW/ HL71V7L5PMJxEaTeS+neTS21cR/N/dxaon5Pb6CJaPL8m7H8q7cGNOVq4 0CILWdB3xADcbr60olzHnc/0svrVqD1m9mpjFilR2BbTYl7CpoN8C2qct Q==; X-CSE-ConnectionGUID: aThTDcVCRW6VFXhfd8KWPg== X-CSE-MsgGUID: 4wuKGvS0SoGXil2L5KD6Zg== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473812" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473812" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jul 2024 21:36:18 -0700 X-CSE-ConnectionGUID: Ut4ZFwZWRJORPKf2PD8ZPA== X-CSE-MsgGUID: 4gBlVdnnQgqUHIvPHWt6kA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="79238210" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.36]) by fmviesa001.fm.intel.com with ESMTP; 09 Jul 2024 21:36:13 -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, Zhenyu Wang , Dapeng Mi , Yuan Yao , Xiong Zhang , Mingwei Zhang , Jim Mattson , Zhao Liu Subject: [RFC 4/5] i386/kvm: Support event with masked entry format in KVM PMU filter Date: Wed, 10 Jul 2024 12:51:16 +0800 Message-Id: <20240710045117.3164577-5-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240710045117.3164577-1-zhao1.liu@intel.com> References: <20240710045117.3164577-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 --- 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 51d3fba5a72a..7a1720c68f8f 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -46,6 +46,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(); } @@ -145,6 +155,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 0d759884c229..f4e8854fa6c6 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 9.1 ## { '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 9.1 +## +{ 'struct': 'KVMPMUX86MaskedEntry', + 'data': { 'select': 'uint16', + 'match': 'uint8', + 'mask': 'uint8', + 'exclude': 'bool' } } + ## # @KVMPMUFilterEvent: # @@ -83,7 +120,8 @@ 'format': 'KVMPMUEventEncodeFmt' }, 'discriminator': 'format', 'data': { 'raw': 'KVMPMURawEvent', - 'x86-default': 'KVMPMUX86DefalutEvent' } } + 'x86-default': 'KVMPMUX86DefalutEvent', + 'x86-masked-entry': 'KVMPMUX86MaskedEntry' } } ## # @KVMPMUFilterProperty: @@ -128,6 +166,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 9.1 +## +{ 'struct': 'KVMPMUX86MaskedEntryVariant', + 'data': { 'select': 'str', + 'match': 'str', + 'mask': 'str', + 'exclude': 'bool' } } + ## # @KVMPMUFilterEventVariant: # @@ -144,7 +205,8 @@ '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 391531c036a6..396a93efe745 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5397,6 +5397,13 @@ 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(); } @@ -5432,6 +5439,21 @@ static bool 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; } @@ -6064,6 +6086,7 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, KVMPMUFilter *filter = KVM_PMU_FILTER(child); KVMPMUFilterEventList *events = filter->events; KVMPMUFilterAction action; + uint32_t base_flag; if (!filter->nevents) { error_setg(errp, @@ -6071,13 +6094,22 @@ 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; action = KVM_PMU_FILTER_ACTION__MAX; 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, @@ -6086,6 +6118,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; + } + if (action == KVM_PMU_FILTER_ACTION__MAX) { action = event->action; } else if (action != event->action) { From patchwork Wed Jul 10 04:51:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhao Liu X-Patchwork-Id: 13728870 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 3D5295A0F5 for ; Wed, 10 Jul 2024 04:36:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586186; cv=none; b=OoiwKZBXXgLgBe6GrzhCnCmfqt7xem/m5fU4T23CfZ5PQC/x1gIeNxJRtEmFyHBXMV84Sk5uD6Oia8vnljAnneRvw8QTFH2Go672aW/80TclBYZPcgioHqVEgp3TQjkJsNlWINYo16Tzf3G7y9qlZvaJ9b7UvL1QbLiN7A0Wmjk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1720586186; c=relaxed/simple; bh=6+OseQGpk2ndz6OpN+ZaTOVJXSOpCJ52+KKHCCTwnuA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=JpdaFnsJ2ztzX1drAjv3z7ufID4iauj6C0di+E/KNCTFMUuEmtZRITj5/EkK9A07qs2frvIyIRKCCjhPmAbuvMv+KyrMl3ajDKPGrs6AfFm7J0zAnOPXJY38IZcohL62B19KX3+KJBdZ9+qlAoBh82UVgQ9mb1IiZJETeHyV5Yg= 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=PLiSFBft; arc=none smtp.client-ip=198.175.65.11 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="PLiSFBft" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586184; x=1752122184; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=6+OseQGpk2ndz6OpN+ZaTOVJXSOpCJ52+KKHCCTwnuA=; b=PLiSFBftbaSmXtc4XIakB4nY5K+T5Af0a+eqWsU9Qm/sl44KfbhF+vUc hVowLMePgCg+fsK0rL8OsyjuQpAA/u47Xd1iTEE9qhIB3R9YRDe6ryXS9 aG4OyzWruH4uK+JHzeVSns1e+9lkiBu6+2wGFk2s8Hevhh93MsKQqgc7s pkO1uS0wUYp9xnPoPVdQTNCnmJ+IbqMMiCUARJ38AUE+AtW1eDa/75xbk HLufUYiWPbAcw6N3lJjIru62a+93j/71KrpuAYFDUDF7LkiJ+XS11k2uD OaxdplbBOOI0LfvdzNMB4HduVwphWeMG9si0FVMlSL0FYJ8/G9SLsT2v8 g==; X-CSE-ConnectionGUID: eIOecysWS8uLW5J7I/4TVQ== X-CSE-MsgGUID: 3FatIveWSca6oXMUMwhZ/g== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473824" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473824" Received: from fmviesa001.fm.intel.com ([10.60.135.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jul 2024 21:36:24 -0700 X-CSE-ConnectionGUID: Po2f5o8xT3y+ievXVp6YYg== X-CSE-MsgGUID: LAxQ+A8ZQT+k+mRhg5v6ug== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="79238239" Received: from liuzhao-optiplex-7080.sh.intel.com ([10.239.160.36]) by fmviesa001.fm.intel.com with ESMTP; 09 Jul 2024 21:36:18 -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, Zhenyu Wang , Dapeng Mi , Yuan Yao , Xiong Zhang , Mingwei Zhang , Jim Mattson , Zhao Liu Subject: [RFC 5/5] i386/kvm: Support fixed counter in KVM PMU filter Date: Wed, 10 Jul 2024 12:51:17 +0800 Message-Id: <20240710045117.3164577-6-zhao1.liu@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240710045117.3164577-1-zhao1.liu@intel.com> References: <20240710045117.3164577-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 --- accel/kvm/kvm-pmu.c | 71 ++++++++++++++++++++++++++++++++++++++++ include/sysemu/kvm-pmu.h | 1 + qapi/kvm.json | 36 +++++++++++++++++++- target/i386/kvm/kvm.c | 69 +++++++++++++++++++++++++------------- 4 files changed, 153 insertions(+), 24 deletions(-) diff --git a/accel/kvm/kvm-pmu.c b/accel/kvm/kvm-pmu.c index 7a1720c68f8f..bad76482f426 100644 --- a/accel/kvm/kvm-pmu.c +++ b/accel/kvm/kvm-pmu.c @@ -256,6 +256,68 @@ 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->action = filter->x86_fixed_counter->action; + 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); + new_counter->action = str_counter->action; + + 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) { @@ -266,6 +328,15 @@ 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/sysemu/kvm-pmu.h b/include/sysemu/kvm-pmu.h index 707f33d604fd..e74a6a665565 100644 --- a/include/sysemu/kvm-pmu.h +++ b/include/sysemu/kvm-pmu.h @@ -24,6 +24,7 @@ struct KVMPMUFilter { uint32_t nevents; KVMPMUFilterEventList *events; + KVMPMUX86FixedCounter *x86_fixed_counter; }; /* diff --git a/qapi/kvm.json b/qapi/kvm.json index f4e8854fa6c6..fe9a9ec940be 100644 --- a/qapi/kvm.json +++ b/qapi/kvm.json @@ -123,6 +123,21 @@ 'x86-default': 'KVMPMUX86DefalutEvent', 'x86-masked-entry': 'KVMPMUX86MaskedEntry' } } +## +# @KVMPMUX86FixedCounter: +# +# x86 fixed counter that KVM PMU filter supports. +# +# @action: action that KVM PMU filter will take. +# +# @bitmap: x86 fixed counter bitmap. +# +# Since 9.1 +## +{ 'struct': 'KVMPMUX86FixedCounter', + 'data': { 'action': 'KVMPMUFilterAction', + 'bitmap': 'uint32' } } + ## # @KVMPMUFilterProperty: # @@ -208,6 +223,22 @@ 'x86-default': 'KVMPMUX86DefalutEventVariant', 'x86-masked-entry': 'KVMPMUX86MaskedEntryVariant' } } +## +# @KVMPMUX86FixedCounterVariant: +# +# The variant of KVMPMUX86FixedCounter with the string, rather than +# the numeric value. +# +# @action: action that KVM PMU filter will take. +# +# @bitmap: x86 fixed counter bitmap. This field is a uint32 string. +# +# Since 9.1 +## +{ 'struct': 'KVMPMUX86FixedCounterVariant', + 'data': { 'action': 'KVMPMUFilterAction', + 'bitmap': 'str' } } + ## # @KVMPMUFilterPropertyVariant: # @@ -215,7 +246,10 @@ # # @events: the KVMPMUFilterEventVariant list. # +# @x86-fixed-counter: enablement bitmap of x86 fixed counters. +# # Since 9.1 ## { 'struct': 'KVMPMUFilterPropertyVariant', - 'data': { '*events': ['KVMPMUFilterEventVariant'] } } + 'data': { '*events': ['KVMPMUFilterEventVariant'], + '*x86-fixed-counter': 'KVMPMUX86FixedCounterVariant' } } diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 396a93efe745..b350c4123ea2 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -5419,6 +5419,7 @@ static bool kvm_install_pmu_event_filter(KVMState *s) { struct kvm_pmu_event_filter *kvm_filter; KVMPMUFilter *filter = s->pmu_filter; + KVMPMUFilterAction action; int ret; kvm_filter = g_malloc0(sizeof(struct kvm_pmu_event_filter) + @@ -5426,9 +5427,14 @@ static bool kvm_install_pmu_event_filter(KVMState *s) /* * Currently, kvm-pmu-filter only supports configuring the same - * action for PMU events. + * action for PMU fixed-counters/events. */ - switch (filter->events->value->action) { + if (filter->x86_fixed_counter) { + action = filter->x86_fixed_counter->action; + } else { + action = filter->events->value->action; + } + switch (action) { case KVM_PMU_FILTER_ACTION_ALLOW: kvm_filter->action = KVM_PMU_EVENT_ALLOW; break; @@ -5439,23 +5445,29 @@ static bool 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); @@ -6088,17 +6100,24 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, KVMPMUFilterAction action; 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; + } + action = KVM_PMU_FILTER_ACTION__MAX; + if (filter->x86_fixed_counter) { + action = filter->x86_fixed_counter->action; + } + while (events) { KVMPMUFilterEvent *event = events->value; uint32_t flag; @@ -6128,9 +6147,13 @@ static void kvm_arch_check_pmu_filter(const Object *obj, const char *name, if (action == KVM_PMU_FILTER_ACTION__MAX) { action = event->action; } else if (action != event->action) { - /* TODO: Support events with different actions if necessary. */ + /* + * TODO: Support fixed-counters/events with different actions + * if necessary. + */ error_setg(errp, - "Only support PMU events with the same action"); + "Only support PMU fixed-counters/events " + "with the same action"); return; }