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: 1958703 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=SpGrJ6JL; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WJlSx2mLYz1xqj for ; Wed, 10 Jul 2024 14:37:21 +1000 (AEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sRP3u-0005o9-L3; Wed, 10 Jul 2024 00:36:14 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP3s-0005du-1T; Wed, 10 Jul 2024 00:36:12 -0400 Received: from mgamail.intel.com ([198.175.65.11]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP3p-0006tm-OD; Wed, 10 Jul 2024 00:36:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586169; x=1752122169; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=4Gl90JTr0DPqZym9GzC30MAvpGMWS2nNyp9RK7fmVl8=; b=SpGrJ6JLZscttymiIfh9SPg68FtfKUISVEzk9lv5TYKvivBOo6P80V9S Gzi1gA7J8RIFuBxICK4qvV/P0tOMH9GFVCr7e3iGuG7ZLcJRxh4wVc+EA REe0jb1YrJZLiRFz2HJns1iAP5G9sH/RsuGVXbSQsMDvOi+E6Vx5JC4vX EQuY2s68VPHpL4id4ZlxvFsZlxlA/HnQfvW/97OvaV+K/L3lkw9hR8CRr hJf8rAYlHKrc9c5yEuKiEziQITacNzcbUm5gQ9DbPQiK8gxQcUb6jobKI 5cRxFTarbi1BDIU29rwTbipClcYZ5lNGGysxPNkVbIK0kRyPafEn4zP+N Q==; X-CSE-ConnectionGUID: nX4qN33cSFi0AA4n37/71A== X-CSE-MsgGUID: E8R7l8RLRnqkwaq4IfuMdg== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473765" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473765" 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:01 -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> MIME-Version: 1.0 Received-SPF: pass client-ip=198.175.65.11; envelope-from=zhao1.liu@intel.com; helo=mgamail.intel.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.144, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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: 1958705 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=m4XXwj9F; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WJlTR4rwJz1xqj for ; Wed, 10 Jul 2024 14:37:47 +1000 (AEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sRP3v-0005qg-En; Wed, 10 Jul 2024 00:36:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP3t-0005jJ-HR; Wed, 10 Jul 2024 00:36:13 -0400 Received: from mgamail.intel.com ([198.175.65.11]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP3r-0006sb-JP; Wed, 10 Jul 2024 00:36:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586171; x=1752122171; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qMy1GX3+etGOKvBzHp/xRoSoF1eAUO1DrwJq/x8rfjk=; b=m4XXwj9FpifoJLW6CLq4gDEanKR9D5lnCJuodY5r5qvduxK9Apev7A5d 9A84RevmIO4Z2msxUzbsp8lLtaB4CQR+EDSrhkdhUuWD9BP9arskOwQt+ biX167hjmyHaZVuBYOilrlGtGbEsXtAZh55jMh/rpPoL9xSBU3LofPh82 aTGw7yIghvEUb8Cd7aY28aofXZFScjjHfalk3sdiPU0G/lMuXvU6K8Q8C c4tOdcGBp/ahPIh/6Zqr4ZSJvdvACFlJkegQbXNKCtfGfBkSOFRpVAezx aioHOo7LtTO644BkVTDNnD5TqhZRGzSZGH3+imOVYUtEVoC50aRHavTes w==; X-CSE-ConnectionGUID: itlenDkPQaCBhXhe93dP+Q== X-CSE-MsgGUID: rXev+ZknT7uj8/nNwdmjaQ== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473790" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473790" 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> MIME-Version: 1.0 Received-SPF: pass client-ip=198.175.65.11; envelope-from=zhao1.liu@intel.com; helo=mgamail.intel.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.144, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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: 1958701 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=FdMpW9MH; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WJlSr5v1cz20MK for ; Wed, 10 Jul 2024 14:37:16 +1000 (AEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sRP3x-0005yM-5R; Wed, 10 Jul 2024 00:36:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP3v-0005tO-SL; Wed, 10 Jul 2024 00:36:15 -0400 Received: from mgamail.intel.com ([198.175.65.11]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP3t-0006tm-RO; Wed, 10 Jul 2024 00:36:15 -0400 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: YrjsECkISjGgqr5xWz8kVA== X-CSE-MsgGUID: pSY3Z0OGTqyyj/biRPQZJw== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473798" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473798" 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> MIME-Version: 1.0 Received-SPF: pass client-ip=198.175.65.11; envelope-from=zhao1.liu@intel.com; helo=mgamail.intel.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.144, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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: 1958704 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=StF1Kprm; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WJlT06NhNz1xqj for ; Wed, 10 Jul 2024 14:37:24 +1000 (AEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sRP43-0006PH-Sa; Wed, 10 Jul 2024 00:36:23 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP42-0006IX-9x; Wed, 10 Jul 2024 00:36:22 -0400 Received: from mgamail.intel.com ([198.175.65.11]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP40-0006xI-4h; Wed, 10 Jul 2024 00:36:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586180; x=1752122180; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=COv/wxh7LoZnCJkoFwP3rD91fqQddYuwNXRcw9JrnaY=; b=StF1Kprm3kxcwcrvFC2Hrc6c1jx2Tj/Qfv+vh+I1LNAEpOCFXSSR91Xf +YmNqOGLam+VvByV+QC2t6TjvMDHjgU9wk/gAUxGyHzwUf9fnrDdRVQdn u/IoQe0WPmO40HlxjUsYdp9eztE9zdZSrsnX89wpkZLEmLy3T0qljVwpO g3Dbd6rYCmU005lbYa6tJ7TmvZ8NTe4/n5opFUWWZf7ruDdachfLU0E13 fZcOG6Z4d3+25v71yolLnVtxVtE7Y4CICki949ATbRuwu8t0gbZ/cVR3W Vz0QJKA2JpQwdnvYZuEI5zVk8omsBWWEvIkytcRMirlJV7Lhi711oXzeD w==; X-CSE-ConnectionGUID: GyPgJX0WSTWJCWywN+CDlw== X-CSE-MsgGUID: v79vVDa9S+uuPyk13hGZCA== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473811" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473811" 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> MIME-Version: 1.0 Received-SPF: pass client-ip=198.175.65.11; envelope-from=zhao1.liu@intel.com; helo=mgamail.intel.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.144, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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: 1958702 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=fEf07K3r; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WJlSr5nGhz1xqj for ; Wed, 10 Jul 2024 14:37:16 +1000 (AEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sRP49-0006jn-0S; Wed, 10 Jul 2024 00:36:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP47-0006ff-VX; Wed, 10 Jul 2024 00:36:27 -0400 Received: from mgamail.intel.com ([198.175.65.11]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sRP45-0006xI-QK; Wed, 10 Jul 2024 00:36:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1720586185; x=1752122185; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=6+OseQGpk2ndz6OpN+ZaTOVJXSOpCJ52+KKHCCTwnuA=; b=fEf07K3rDEjO3+QbK2QZRZU3+3TkCpoNz6384TLwVIKjgJGsfYW0z9y9 96YYHez1ye7ZjAWAq2QJE73K7ojD4lFxAGE3wkSo2wPoG76SDvAhG3kiJ kkITkx9OiDEtaF5nkHV7IPj8OfGN/ofpsKTWa9hdU9qJX4tzp7Gogwe7R u2/swzXb7of+Vpy03bE72p9PNBVtnbfJZXOZ2zrp2PUvxk5MzEVFMmuKJ KsFhaVA2XDaG2wPDToNHyDQrIG7avoVwXc7v9K+h5ZM/VJEXXcjYPSwF+ UCvB3VUz8d1emTldxZDHrCqk/UibVhqdYqg3CLNZAlPE0zmwMz+jy33gA g==; X-CSE-ConnectionGUID: BsgYmSPJSmC0Ok+1o24E2A== X-CSE-MsgGUID: OFDDy1qjQB6QYdiTjms+0w== X-IronPort-AV: E=McAfee;i="6700,10204,11128"; a="28473826" X-IronPort-AV: E=Sophos;i="6.09,197,1716274800"; d="scan'208";a="28473826" 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> MIME-Version: 1.0 Received-SPF: pass client-ip=198.175.65.11; envelope-from=zhao1.liu@intel.com; helo=mgamail.intel.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.144, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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; }