From nobody Thu Apr 2 04:37:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 B6BCF38C2BC; Thu, 26 Mar 2026 03:12:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494751; cv=none; b=TehOJJdwuFuROiYrV+Zfdxg50GMWIic4/R1JHtG11sInupctRN2sG3DS8kwOIDY9jNMp5XHdBfKDWX8+53Qa/zR7t2WynlxTDeOyurPAjmv6PLNYmPXaLlnetBmXVx+Ri3TlzjWFAqBYuuLW/R2PlO3A9qEYUefgt1ksCYlaI3o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494751; c=relaxed/simple; bh=TcgrzSZpv1N3EQ2sJcjdoz7K5gTllPG2CxppLL34jpo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Dhprx01Vl3Z1b81XqdcDzoCQ2HUlSHyhafBwn4rQHS1lJ0T407MX7nd16P1wozryoIU3DX6MZBrb9Dvtd9iHpC7vZk4unPvl0p4TgEKHPAfysCpWHoENG0GJuRLgW4X2k/zZljcbd/UWcRMYNQDyoCZJguW/utVXQzsnjofTfo0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=H/DfdY+H; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="H/DfdY+H" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 62027C2BCB0; Thu, 26 Mar 2026 03:12:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774494751; bh=TcgrzSZpv1N3EQ2sJcjdoz7K5gTllPG2CxppLL34jpo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=H/DfdY+HpwdkzsytrXSc2RSrSn58j4nDMDTAJ5bdA8lNXtboX2dNeS6cIJsF62Z0T ZCBn3gT9Tpr4Z648pS0bZWiBN4KJWCIFUqaK2oAtmg3+ZdADz4mndklcoNyVi77/cQ bNO2OQfkRFOWNo2hVtjEoj7/2ZGXLOMleqv6xMsC+R1FDVwTcSoI1adsUCUO1LxAeS nVMLgeBk81EzO5z5QP9cLP9MuBGXaEKxK/68eTGKGuLNr5l7mqZKvDitaGSX6OleJz WxKf/0et5tDK0NI5HRWrFjmzsne0jX8fUvq5aoxQFCLSvIusgJjmAXdIDpMCyxSA6h d5MLxbBXAm4Dw== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , Jim Mattson , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed Subject: [PATCH v4 1/6] KVM: x86: Move enable_pmu/enable_mediated_pmu to pmu.h and pmu.c Date: Thu, 26 Mar 2026 03:11:45 +0000 Message-ID: <20260326031150.3774017-2-yosry@kernel.org> X-Mailer: git-send-email 2.53.0.1018.g2bb0e51243-goog In-Reply-To: <20260326031150.3774017-1-yosry@kernel.org> References: <20260326031150.3774017-1-yosry@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The declaration and definition of enable_pmu/enable_mediated_pmu semantically belongs in pmu.h and pmu.c, and more importantly, pmu.h uses enable_mediated_pmu and relies on the caller including x86.h. There is already precedence for other module params defined outside of x86.c, so move enable_pmu/enable_mediated_pmu to pmu.c. No functional change intended. Signed-off-by: Yosry Ahmed --- arch/x86/kvm/pmu.c | 10 ++++++++++ arch/x86/kvm/pmu.h | 3 +++ arch/x86/kvm/x86.c | 9 --------- arch/x86/kvm/x86.h | 3 --- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index e218352e34231..d6ac3c55fce55 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include "x86.h" @@ -33,6 +34,15 @@ static struct x86_pmu_capability __read_mostly kvm_host_= pmu; struct x86_pmu_capability __read_mostly kvm_pmu_cap; EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_pmu_cap); =20 +/* Enable/disable PMU virtualization */ +bool __read_mostly enable_pmu =3D true; +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_pmu); +module_param(enable_pmu, bool, 0444); + +/* Enable/disabled mediated PMU virtualization. */ +bool __read_mostly enable_mediated_pmu; +EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_mediated_pmu); + struct kvm_pmu_emulated_event_selectors { u64 INSTRUCTIONS_RETIRED; u64 BRANCH_INSTRUCTIONS_RETIRED; diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 0925246731cb1..b1f2418e960ac 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -53,6 +53,9 @@ struct kvm_pmu_ops { const u32 MSR_STRIDE; }; =20 +extern bool enable_pmu; +extern bool enable_mediated_pmu; + void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops); =20 void kvm_handle_guest_mediated_pmi(void); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0b5d48e75b657..0a5fd473a24e1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -182,15 +182,6 @@ module_param(force_emulation_prefix, int, 0644); int __read_mostly pi_inject_timer =3D -1; module_param(pi_inject_timer, bint, 0644); =20 -/* Enable/disable PMU virtualization */ -bool __read_mostly enable_pmu =3D true; -EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_pmu); -module_param(enable_pmu, bool, 0444); - -/* Enable/disabled mediated PMU virtualization. */ -bool __read_mostly enable_mediated_pmu; -EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_mediated_pmu); - bool __read_mostly eager_page_split =3D true; module_param(eager_page_split, bool, 0644); =20 diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 44a28d343d407..48f3e8c0dc30d 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -480,9 +480,6 @@ fastpath_t handle_fastpath_invd(struct kvm_vcpu *vcpu); extern struct kvm_caps kvm_caps; extern struct kvm_host_values kvm_host; =20 -extern bool enable_pmu; -extern bool enable_mediated_pmu; - void kvm_setup_xss_caps(void); =20 /* --=20 2.53.0.1018.g2bb0e51243-goog From nobody Thu Apr 2 04:37:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 33D623921C8; Thu, 26 Mar 2026 03:12:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494752; cv=none; b=V/d1xEmCIWnyo1tWj5uylSmTGI3ZUfc+XMf3hvrc5xMpZjWHMZK0dsk5DieTdi8t9OS314v9S3sMEdxjY7ONd83Bzx410n2Ph0hLi/Sh/WZ9igar3YnIp2duQkKmogo5rO1jp0SlMOGCFS9/G3um8OWEQKWvLGb1t6JONexMIr8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494752; c=relaxed/simple; bh=qDXb6RRNHKcex5f0LtzcegwbG5/8saeewaxBaYEyuQ8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=i/bRBio3SiZQWuJa26f/PhTNJm/7Sg9+9t6tfSlH0K23WnjiRyUkO+dlHfV5r4F/VMBRN46BaPrtKyq6MXHUsSsx44gj1cU8U0DghFNF0iQunMuMZj8CQsOWkt2j8v2Np2rqNmT9kfruipUYdNp8qoLTnbl0ZJEGZegfhviirJw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OhzfU2LT; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OhzfU2LT" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BDFF8C2BCB2; Thu, 26 Mar 2026 03:12:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774494752; bh=qDXb6RRNHKcex5f0LtzcegwbG5/8saeewaxBaYEyuQ8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OhzfU2LTCfYt1KI2YSzGKlHdtqHbJPKdKfaQSxEt0yMTCJGmGrdy3EQUyj740Pn1Z vfidCb9lkfziguRSL+RK/Vc+M7soq5+reGYL083uX86UJJrHKhJOVjrqjxRjRPgoMP ML/fJX1d1YUN80AA/nnqWqo6SHA5+RDM8aYFPUmvoh+r9fexUaYu2BaN4RvONa3wnb DdRcKfOyoO5PdRW9GrljEjcTUb1I+87qGLWRO7e5cEHPrxReu7IdjSN0hroVNgEWE3 jFlloiVPJEGBrahLRDafAJLZ/WJG0YDiTWvoQFzdw1FZov+caWkW4S8i1v1SxYJ1BB KIjuXFr4QiVGg== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , Jim Mattson , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed Subject: [PATCH v4 2/6] KVM: x86: Move guest_mode helpers to x86.h Date: Thu, 26 Mar 2026 03:11:46 +0000 Message-ID: <20260326031150.3774017-3-yosry@kernel.org> X-Mailer: git-send-email 2.53.0.1018.g2bb0e51243-goog In-Reply-To: <20260326031150.3774017-1-yosry@kernel.org> References: <20260326031150.3774017-1-yosry@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move enter_guest_mode(), leave_guest_mode(), and is_guest_mode() to x86.h. This is more semantically appropriate to keep kvm_cache_regs.h for register helpers, and more importantly it allows for expanding these helpers without including more headers into kvm_cache_regs.h, keeping it as much as possible a leaf header. No functional change intended. Signed-off-by: Yosry Ahmed --- arch/x86/kvm/kvm_cache_regs.h | 23 ----------------------- arch/x86/kvm/x86.h | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h index 8ddb01191d6f6..8682ef54a8c9b 100644 --- a/arch/x86/kvm/kvm_cache_regs.h +++ b/arch/x86/kvm/kvm_cache_regs.h @@ -223,27 +223,4 @@ static inline u64 kvm_read_edx_eax(struct kvm_vcpu *vc= pu) | ((u64)(kvm_rdx_read(vcpu) & -1u) << 32); } =20 -static inline void enter_guest_mode(struct kvm_vcpu *vcpu) -{ - vcpu->arch.hflags |=3D HF_GUEST_MASK; - vcpu->stat.guest_mode =3D 1; -} - -static inline void leave_guest_mode(struct kvm_vcpu *vcpu) -{ - vcpu->arch.hflags &=3D ~HF_GUEST_MASK; - - if (vcpu->arch.load_eoi_exitmap_pending) { - vcpu->arch.load_eoi_exitmap_pending =3D false; - kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu); - } - - vcpu->stat.guest_mode =3D 0; -} - -static inline bool is_guest_mode(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.hflags & HF_GUEST_MASK; -} - #endif diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 48f3e8c0dc30d..f1c29ac306917 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -148,6 +148,29 @@ static inline unsigned int __shrink_ple_window(unsigne= d int val, void kvm_service_local_tlb_flush_requests(struct kvm_vcpu *vcpu); int kvm_check_nested_events(struct kvm_vcpu *vcpu); =20 +static inline void enter_guest_mode(struct kvm_vcpu *vcpu) +{ + vcpu->arch.hflags |=3D HF_GUEST_MASK; + vcpu->stat.guest_mode =3D 1; +} + +static inline void leave_guest_mode(struct kvm_vcpu *vcpu) +{ + vcpu->arch.hflags &=3D ~HF_GUEST_MASK; + + if (vcpu->arch.load_eoi_exitmap_pending) { + vcpu->arch.load_eoi_exitmap_pending =3D false; + kvm_make_request(KVM_REQ_LOAD_EOI_EXITMAP, vcpu); + } + + vcpu->stat.guest_mode =3D 0; +} + +static inline bool is_guest_mode(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.hflags & HF_GUEST_MASK; +} + /* Forcibly leave the nested mode in cases like a vCPU reset */ static inline void kvm_leave_nested(struct kvm_vcpu *vcpu) { --=20 2.53.0.1018.g2bb0e51243-goog From nobody Thu Apr 2 04:37:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 87A3E3932C6; Thu, 26 Mar 2026 03:12:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494752; cv=none; b=OnG/9twRFck37iccr0Qq0NjsD/eftZVbxhssCIx9yeLfDcHmNUajrrkLWyx+/1m3RIhRawu104CfbePSUqqT+NeUhuodd2d4+Fzx8Yxd+fBOWBXXhYdIJaPAiN8wUiq91PMw88nxE+gJs0/HCbPYjHJBvwwE3nNXtEsh+q5gbOM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494752; c=relaxed/simple; bh=53QaIKDk7fN2Ew8/rOTS7tu4uaix84f/2x/Yx6CWKOs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YFYJYbG4YLcFFe+W5WCBT59wkCygkCtjxmEO+3tesWyMfVtJVKXLiM/+PltK2JMLBs0O50yRyiAnNXlPOoqYjIWbjuVVfC6oTYdWbrcVFct7npCw3TY1L8j1BxNZOR0g2z8wjk5iRuAwnoghF0kULwgPJxhRRUlMS9VcD26RuSk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pZn8vwOb; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pZn8vwOb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 26002C2BCB4; Thu, 26 Mar 2026 03:12:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774494752; bh=53QaIKDk7fN2Ew8/rOTS7tu4uaix84f/2x/Yx6CWKOs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pZn8vwOb/i6G3QnJfKP1r6rO/frFGWu7iNe8gAVwnCXX0Lxyt80xFyVAjiWhkNLJ5 85EUvaIPTwKZyaPwRiIWnz8+RTbW55LBMsN6veIZ1BE+BHdDlkX3z9eXd36YgFbl2F Yn7ByzcLVuQOyOjGUkB5Wiq3RKN1BwD8fNfUV78T6SDAPfysTo1m7E2N/qLPB08dD4 gl8GX+QcUe/7dLEhZ+nbRRrWPQFUHdGaHBv3p3/KkxBZJkcKH2OXnTzMrXRkT+NtNE JGfHOfS2mDqIHM8FMmFDL8vOn1ATXX8tWguuoKNbpc214qzfZV3ksEeuklHd0PCuQd dwOUaX+IBrI2Q== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , Jim Mattson , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed Subject: [PATCH v4 3/6] KVM: x86/pmu: Disable counters based on Host-Only/Guest-Only bits in SVM Date: Thu, 26 Mar 2026 03:11:47 +0000 Message-ID: <20260326031150.3774017-4-yosry@kernel.org> X-Mailer: git-send-email 2.53.0.1018.g2bb0e51243-goog In-Reply-To: <20260326031150.3774017-1-yosry@kernel.org> References: <20260326031150.3774017-1-yosry@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Introduce a per-vendor PMU callback for reprogramming counters with a mediated PMU, and register a callback on AMD to disable a counter based on the vCPU's setting of Host-Only or Guest-Only EVENT_SELECT bits (if EFER.SVME is set). In other words, disable the counter if Host-Only and guest_mode() or Guest-Only and !guest_mode(). kvm_mediated_pmu_refresh_event_filter() ensures that ARCH_PERFMON_EVENTSEL_ENABLE is set for any enabled counters before mediated_reprogram_counter() callback, and kvm_mediated_pmu_load() writes the updated value of eventsel_hw to the appropriate MSR after the counters are reprogrammed through KVM_REQ_PMU. Note that the behavior is equivalent if both bits are cleared or if both bits are set, events are counted regardless of host/guest state (from L1's perspective), so KVM should always keep the counter enabled unless only one of the bits is set. It's a bit unnatural to check if both bits are set or cleared, then check EFER.SVME, then go back to checking the set bit. This ordering will be needed by following changes that will track counters with only one Host-Only/Guest-Only bit set regardless of EFER.SVME. Host-Only and Guest-Only bits are currently reserved, so this change is a noop, but the bits will be allowed with mediated PMU in a following change when fully supported. Originally-by: Jim Mattson Signed-off-by: Yosry Ahmed --- arch/x86/include/asm/kvm-x86-pmu-ops.h | 1 + arch/x86/include/asm/perf_event.h | 2 ++ arch/x86/kvm/pmu.c | 1 + arch/x86/kvm/pmu.h | 1 + arch/x86/kvm/svm/pmu.c | 29 ++++++++++++++++++++++++++ 5 files changed, 34 insertions(+) diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/= kvm-x86-pmu-ops.h index d5452b3433b7d..11ce0012b8301 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -27,6 +27,7 @@ KVM_X86_PMU_OP_OPTIONAL(cleanup) KVM_X86_PMU_OP_OPTIONAL(write_global_ctrl) KVM_X86_PMU_OP(mediated_load) KVM_X86_PMU_OP(mediated_put) +KVM_X86_PMU_OP_OPTIONAL(mediated_reprogram_counter) #endif =20 #undef KVM_X86_PMU_OP diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_= event.h index ff5acb8b199b0..5961c002b28eb 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -60,6 +60,8 @@ #define AMD64_EVENTSEL_INT_CORE_ENABLE (1ULL << 36) #define AMD64_EVENTSEL_GUESTONLY (1ULL << 40) #define AMD64_EVENTSEL_HOSTONLY (1ULL << 41) +#define AMD64_EVENTSEL_HOST_GUEST_MASK \ + (AMD64_EVENTSEL_HOSTONLY | AMD64_EVENTSEL_GUESTONLY) =20 #define AMD64_EVENTSEL_INT_CORE_SEL_SHIFT 37 #define AMD64_EVENTSEL_INT_CORE_SEL_MASK \ diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index d6ac3c55fce55..e35d598f809a2 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -559,6 +559,7 @@ static int reprogram_counter(struct kvm_pmc *pmc) =20 if (kvm_vcpu_has_mediated_pmu(pmu_to_vcpu(pmu))) { kvm_mediated_pmu_refresh_event_filter(pmc); + kvm_pmu_call(mediated_reprogram_counter)(pmc); return 0; } =20 diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index b1f2418e960ac..bdbe0456049d0 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -40,6 +40,7 @@ struct kvm_pmu_ops { bool (*is_mediated_pmu_supported)(struct x86_pmu_capability *host_pmu); void (*mediated_load)(struct kvm_vcpu *vcpu); void (*mediated_put)(struct kvm_vcpu *vcpu); + void (*mediated_reprogram_counter)(struct kvm_pmc *pmc); void (*write_global_ctrl)(u64 global_ctrl); =20 const u64 EVENTSEL_EVENT; diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 7aa298eeb0721..60931dfd624b2 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -260,6 +260,34 @@ static void amd_mediated_pmu_put(struct kvm_vcpu *vcpu) wrmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, pmu->global_status); } =20 +static void amd_mediated_pmu_handle_host_guest_bits(struct kvm_pmc *pmc) +{ + struct kvm_vcpu *vcpu =3D pmc->vcpu; + u64 host_guest_bits; + + if (!(pmc->eventsel & ARCH_PERFMON_EVENTSEL_ENABLE)) + return; + + /* Count all events if both bits are cleared or both bits are set */ + host_guest_bits =3D pmc->eventsel & AMD64_EVENTSEL_HOST_GUEST_MASK; + if (hweight64(host_guest_bits) !=3D 1) + return; + + /* Host-Only and Guest-Only are ignored if EFER.SVME =3D=3D 0 */ + if (!(vcpu->arch.efer & EFER_SVME)) + return; + + if (!!(host_guest_bits & AMD64_EVENTSEL_GUESTONLY) =3D=3D is_guest_mode(v= cpu)) + return; + + pmc->eventsel_hw &=3D ~ARCH_PERFMON_EVENTSEL_ENABLE; +} + +static void amd_mediated_pmu_reprogram_counter(struct kvm_pmc *pmc) +{ + amd_mediated_pmu_handle_host_guest_bits(pmc); +} + struct kvm_pmu_ops amd_pmu_ops __initdata =3D { .rdpmc_ecx_to_pmc =3D amd_rdpmc_ecx_to_pmc, .msr_idx_to_pmc =3D amd_msr_idx_to_pmc, @@ -273,6 +301,7 @@ struct kvm_pmu_ops amd_pmu_ops __initdata =3D { .is_mediated_pmu_supported =3D amd_pmu_is_mediated_pmu_supported, .mediated_load =3D amd_mediated_pmu_load, .mediated_put =3D amd_mediated_pmu_put, + .mediated_reprogram_counter =3D amd_mediated_pmu_reprogram_counter, =20 .EVENTSEL_EVENT =3D AMD64_EVENTSEL_EVENT, .MAX_NR_GP_COUNTERS =3D KVM_MAX_NR_AMD_GP_COUNTERS, --=20 2.53.0.1018.g2bb0e51243-goog From nobody Thu Apr 2 04:37:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 D4B273939CD; Thu, 26 Mar 2026 03:12:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494752; cv=none; b=gSpc1ZkuN4rHaiG6e0For4KktuMIpUC6Kf7mExnpRHlSEFXv5Fe+wvchcYFI5hymQNKi+G4yzt3Sd0ozCxX3OUDUHNVGAXHWQqqYgJLk8rXIBt/euzRZogi84mrZd389crdldcAZIxU1GHjDOrNo7Y+kXznf94HsPhztlBrtgow= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494752; c=relaxed/simple; bh=la1WaIfCaF2/MggGDt7wbuSsGkHH2X29eUAojHCz++c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BnM90kOcKiT2dQ0fNCVBsmg+VjklTE/6YzAYtrEafBOhmbzwGzCpUbf6ZfoszLf9JKC87yCFUi/uLZkcV/Wo38DN9+X0iCj7gBucbode7wddoiT8Z8gssdvQ9kh/AE5+FI21TPmihb1LXw8HN7X9g5qwmzDvhsyNs+CvFUjAHQ8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=q1HxAGRV; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="q1HxAGRV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 823E9C2BCB1; Thu, 26 Mar 2026 03:12:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774494752; bh=la1WaIfCaF2/MggGDt7wbuSsGkHH2X29eUAojHCz++c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=q1HxAGRVaDEjq8OkBiIxOOiCuTAg4fxAIka0NEvejD65vfPpZmeigFyD/sURXXmqP 8qqKH6X1szexGxPWIJs/Jb4MW6mSovTdKYVOtMu+wBHYyzCas2nB97Xnj8ExP1Y0/J KIKCrEy2YYhT6Hoe2O0AFAXdAswPY6H7wx2K1Vy1fy97EtQDqe+eXUGoQ5Gvt+9FUW Ipw7ugmjd3abal+XDIG4MUGL4Os/Ite+x0E2pPfDbc8kscDNaRIzojOxudlsOxVYBZ yvXxxd1uwtWQ6myFgytXUUZdBQ7EiEKzjXuDF0ruYUTmy7eaZCzvVGbmSB7Vw2Jrbe srKymrlxIYaGw== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , Jim Mattson , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed Subject: [PATCH v4 4/6] KVM: x86/pmu: Re-evaluate Host-Only/Guest-Only on nested SVM transitions Date: Thu, 26 Mar 2026 03:11:48 +0000 Message-ID: <20260326031150.3774017-5-yosry@kernel.org> X-Mailer: git-send-email 2.53.0.1018.g2bb0e51243-goog In-Reply-To: <20260326031150.3774017-1-yosry@kernel.org> References: <20260326031150.3774017-1-yosry@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Reprogram all counters on nested transitions for the mediated PMU, to re-evaluate Host-Only and Guest-Only bits and enable/disable the PMU counters accordingly. For example, if Host-Only is set and Guest-Only is cleared, a counter should be disabled when entering guest mode and enabled when exiting guest mode. Having one of Host-Only and Guest-Only set is only effective when EFER.SVME is set, so also trigger counter reprogramming when EFER.SVME is toggled. Track counters with one of Host-Only and Guest-Only set as counters requiring reprogramming on nested transitions in a bitmap. Use the bitmap to only request KVM_PMU_REQ if some counters need reprogramming, and only reprogram the counters that actually need it. Track such counters even if EFER.SVME is cleared, such that if/when EFER.SVME is set, KVM can reprogram those counters and enable/disable them appropriately. Otherwise, toggling EFER.SVME would need to reprogram all counters and use a different code path than kvm_pmu_handle_nested_transition(). Signed-off-by: Yosry Ahmed --- arch/x86/include/asm/kvm_host.h | 6 ++++++ arch/x86/kvm/pmu.c | 1 + arch/x86/kvm/pmu.h | 13 +++++++++++++ arch/x86/kvm/svm/pmu.c | 13 ++++++++++++- arch/x86/kvm/svm/svm.c | 1 + arch/x86/kvm/x86.h | 5 +++++ 6 files changed, 38 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index d3bdc98281339..b2f8710838372 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -594,6 +594,12 @@ struct kvm_pmu { DECLARE_BITMAP(pmc_counting_instructions, X86_PMC_IDX_MAX); DECLARE_BITMAP(pmc_counting_branches, X86_PMC_IDX_MAX); =20 + /* + * Whether or not PMU counters need to be reprogrammed on transitions + * between L1 and L2 (or when nesting enablement is toggled). + */ + DECLARE_BITMAP(pmc_needs_nested_reprogram, X86_PMC_IDX_MAX); + u64 ds_area; u64 pebs_enable; u64 pebs_enable_rsvd; diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index e35d598f809a2..a7b38c104d067 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -932,6 +932,7 @@ static void kvm_pmu_reset(struct kvm_vcpu *vcpu) pmu->need_cleanup =3D false; =20 bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX); + bitmap_zero(pmu->pmc_needs_nested_reprogram, X86_PMC_IDX_MAX); =20 kvm_for_each_pmc(pmu, pmc, i, pmu->all_valid_pmc_idx) { pmc_stop_counter(pmc); diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index bdbe0456049d0..fb73806d3bfa0 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -248,6 +248,19 @@ static inline bool kvm_pmu_is_fastpath_emulation_allow= ed(struct kvm_vcpu *vcpu) X86_PMC_IDX_MAX); } =20 +static inline void kvm_pmu_handle_nested_transition(struct kvm_vcpu *vcpu) +{ + struct kvm_pmu *pmu =3D vcpu_to_pmu(vcpu); + + if (bitmap_empty(pmu->pmc_needs_nested_reprogram, X86_PMC_IDX_MAX)) + return; + + BUILD_BUG_ON(sizeof(pmu->pmc_needs_nested_reprogram) !=3D sizeof(atomic64= _t)); + atomic64_or(*(s64 *)pmu->pmc_needs_nested_reprogram, + &vcpu_to_pmu(vcpu)->__reprogram_pmi); + kvm_make_request(KVM_REQ_PMU, vcpu); +} + void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu); void kvm_pmu_handle_event(struct kvm_vcpu *vcpu); int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 60931dfd624b2..cc1eabb0ad15f 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -262,17 +262,28 @@ static void amd_mediated_pmu_put(struct kvm_vcpu *vcp= u) =20 static void amd_mediated_pmu_handle_host_guest_bits(struct kvm_pmc *pmc) { + struct kvm_pmu *pmu =3D pmc_to_pmu(pmc); struct kvm_vcpu *vcpu =3D pmc->vcpu; u64 host_guest_bits; =20 + __clear_bit(pmc->idx, pmu->pmc_needs_nested_reprogram); + if (!(pmc->eventsel & ARCH_PERFMON_EVENTSEL_ENABLE)) return; =20 - /* Count all events if both bits are cleared or both bits are set */ + /* + * If both bits are cleared or both bits are set, count all events. + * Otherwise, the counter enablement should be re-evaluated on every + * nested transition. Track which counters need to be re-evaluated even + * if EFER.SVME =3D=3D 0, such that the counters are correctly reprogramm= ed + * on nested transitions after EFER.SVME is set. + */ host_guest_bits =3D pmc->eventsel & AMD64_EVENTSEL_HOST_GUEST_MASK; if (hweight64(host_guest_bits) !=3D 1) return; =20 + __set_bit(pmc->idx, pmu->pmc_needs_nested_reprogram); + /* Host-Only and Guest-Only are ignored if EFER.SVME =3D=3D 0 */ if (!(vcpu->arch.efer & EFER_SVME)) return; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index d2ca226871c2f..1ac00d2cba0ab 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -261,6 +261,7 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) set_exception_intercept(svm, GP_VECTOR); } =20 + kvm_pmu_handle_nested_transition(vcpu); kvm_make_request(KVM_REQ_RECALC_INTERCEPTS, vcpu); } =20 diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index f1c29ac306917..966e4138308f6 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -9,6 +9,7 @@ #include "kvm_cache_regs.h" #include "kvm_emulate.h" #include "cpuid.h" +#include "pmu.h" =20 #define KVM_MAX_MCE_BANKS 32 =20 @@ -152,6 +153,8 @@ static inline void enter_guest_mode(struct kvm_vcpu *vc= pu) { vcpu->arch.hflags |=3D HF_GUEST_MASK; vcpu->stat.guest_mode =3D 1; + + kvm_pmu_handle_nested_transition(vcpu); } =20 static inline void leave_guest_mode(struct kvm_vcpu *vcpu) @@ -164,6 +167,8 @@ static inline void leave_guest_mode(struct kvm_vcpu *vc= pu) } =20 vcpu->stat.guest_mode =3D 0; + + kvm_pmu_handle_nested_transition(vcpu); } =20 static inline bool is_guest_mode(struct kvm_vcpu *vcpu) --=20 2.53.0.1018.g2bb0e51243-goog From nobody Thu Apr 2 04:37:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 45344395242; Thu, 26 Mar 2026 03:12:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494753; cv=none; b=fNJNZ3vkK7RwMWf3vJWAGsKVMrCwVweKMu/UGWU2k+dkvxKGodfXlRr5flgndPSXmJc303cP3g3fhup7PIk8OCxl/ABWU3129Dm0D7WyCKTACEiTgKYoBU8S8axpQTrEF4OXdFApcW/ybLk4MAKZQpYEV/yd+0FA99TGz9+SrZE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494753; c=relaxed/simple; bh=CoszQ3TdgQ1r2712RQT7zIQRT8HfDyPtetdGGniT0sE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=e+hHryPr0mcDUsjWTRUC6SbBOqIdcsG4Eg8VZh8gg4AFoKCLjBZGNGGS1YJVv7Hh8nLk14u0S93UcUNuDeRZ0Z8Es0rg3jNXA5zVZfSe0p0UlH3BpoDOmV34WkIkLkyeqlCLXdyhOh9BCZTnXSDePvwIx24R8FyDPgCknpcPlT0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FWbe+oxJ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FWbe+oxJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DE2DDC2BC9E; Thu, 26 Mar 2026 03:12:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774494753; bh=CoszQ3TdgQ1r2712RQT7zIQRT8HfDyPtetdGGniT0sE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FWbe+oxJKd86xyipvXFq2hagY0Xrq+T2h6VlUm+kvdKZ2jEhwTYe2LQZMw5vgicXC i073RQcDQHyvyx1Gsclt1/pI2ufv5lDhn8aa1eMrn+aAymnBI7hT85KKS7EwIHt/ee t9Q0QOw3uhb035AuuC/kXUGl1r8Lt+RDzTDeGOCHizlMOAbC8tG70RYTL9jFd9lBiK 7h73gHuHh/NcnFDh2n8tUo3tWzeorcyv9E+s+3uCI781ddIknTdME3JnCqR/kJDMj+ i62Fqfjx5ABFX7WUGLSmcIhWkX+5Cl4LaM8E/G+38MSJ4WlHyIWhKidBjbOQBwGcbl u2y8yAhsCFDNw== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , Jim Mattson , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed Subject: [PATCH v4 5/6] KVM: x86/pmu: Allow Host-Only/Guest-Only bits with nSVM and mediated PMU Date: Thu, 26 Mar 2026 03:11:49 +0000 Message-ID: <20260326031150.3774017-6-yosry@kernel.org> X-Mailer: git-send-email 2.53.0.1018.g2bb0e51243-goog In-Reply-To: <20260326031150.3774017-1-yosry@kernel.org> References: <20260326031150.3774017-1-yosry@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jim Mattson Now that KVM correctly handles Host-Only and Guest-Only bits in the event selector MSRs, allow the guest to set them if the vCPU advertises SVM and uses the mediated PMU. Signed-off-by: Jim Mattson Signed-off-by: Yosry Ahmed --- arch/x86/kvm/svm/pmu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index cc1eabb0ad15f..3c04e8da24d33 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -207,7 +207,11 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu) } =20 pmu->counter_bitmask[KVM_PMC_GP] =3D BIT_ULL(48) - 1; + pmu->reserved_bits =3D 0xfffffff000280000ull; + if (guest_cpu_cap_has(vcpu, X86_FEATURE_SVM) && kvm_vcpu_has_mediated_pmu= (vcpu)) + pmu->reserved_bits &=3D ~AMD64_EVENTSEL_HOST_GUEST_MASK; + pmu->raw_event_mask =3D AMD64_RAW_EVENT_MASK; /* not applicable to AMD; but clean them to prevent any fall out */ pmu->counter_bitmask[KVM_PMC_FIXED] =3D 0; --=20 2.53.0.1018.g2bb0e51243-goog From nobody Thu Apr 2 04:37:13 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 C3B3E396B8B; Thu, 26 Mar 2026 03:12:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494753; cv=none; b=PiC9l+knhpxlGuw0mjl+A7VnjTk/ld37xRavdyhAD008fkxQ7AO8QKsuzODuHCUP2Mqpbn5OsnQkAClLb4pNharPYBn2/W8BHtgf/ZQb/VoN5HDxAyLKdDRqIhZ1MG259T2F7G6T62ZOGaXnYhUIpgpClLWCjeQnBDk03MI5iQs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774494753; c=relaxed/simple; bh=9x6ZHeTmvd8fNhSBTKWSMIP/96D/CY1ahn+LcSJ18ys=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UmLbOBvdgnurJitb2CvaEyKhvMqcWFcjF9lNCInmgjsmBFQ/gWsYDqhPYnz1qdaGuG8cen27tVBcCSXVXRdsUoqUpRb/ePj8iq/5w0nPqG5a3OIaaE91f0j36d8QdVzZ2VUlQ+9e7OMjji8wjqlZSHrI1MqOEAI6jwggB+Hqht8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=E6L2nVm1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="E6L2nVm1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46ECCC4CEF7; Thu, 26 Mar 2026 03:12:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1774494753; bh=9x6ZHeTmvd8fNhSBTKWSMIP/96D/CY1ahn+LcSJ18ys=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E6L2nVm1nfQGfP0ja7E82JJkfMetsYyjTlZiBhDV4ww6JUgmKURFZU/rx26cQ50q+ rpz8dNjniKczwc4DwE9gYrE2uaxnDT+p+i9tfxNbU9NofpJWNrvQFHJP9FUizUTDSh 91Hu/4suCuNhUC4l912zCjIqVEqFkkYW8ecKhuexzWix8j1jZ4qCAU9UwDyE6tlU2a 3WdmR41yzKoTxIzHBMMW0CsaGOhymiVANken2YRAAyrle44AvSHRCjl7fSxu3JU3ME fsG1ldkCz6oMsLDuY/Wm6UPCztF7wFPER7JvQlgJNVtlOX3wytx7+qg8TOLOyQBuGq FInl19a509+wg== From: Yosry Ahmed To: Sean Christopherson Cc: Paolo Bonzini , Jim Mattson , kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Yosry Ahmed Subject: [PATCH v4 6/6] KVM: selftests: Add svm_pmu_host_guest_test for Host-Only/Guest-Only bits Date: Thu, 26 Mar 2026 03:11:50 +0000 Message-ID: <20260326031150.3774017-7-yosry@kernel.org> X-Mailer: git-send-email 2.53.0.1018.g2bb0e51243-goog In-Reply-To: <20260326031150.3774017-1-yosry@kernel.org> References: <20260326031150.3774017-1-yosry@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jim Mattson Add a selftest to verify KVM correctly virtualizes the AMD PMU Host-Only (bit 41) and Guest-Only (bit 40) event selector bits across all relevant SVM state transitions. The test programs 4 PMCs simultaneously with all combinations of the Host-Only and Guest-Only bits, then verifies correct counting behavior: 1. SVME=3D0: all counters count (Host-Only/Guest-Only bits ignored) 2. Set SVME=3D1: Host-Only and neither/both count; Guest-Only stops 3. VMRUN to L2: Guest-Only and neither/both count; Host-Only stops 4. VMEXIT to L1: Host-Only and neither/both count; Guest-Only stops 5. Clear SVME=3D0: all counters count (bits ignored again) Signed-off-by: Jim Mattson Signed-off-by: Yosry Ahmed --- tools/testing/selftests/kvm/Makefile.kvm | 1 + tools/testing/selftests/kvm/include/x86/pmu.h | 6 + .../selftests/kvm/include/x86/processor.h | 2 + .../kvm/x86/svm_pmu_host_guest_test.c | 199 ++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/svm_pmu_host_guest_test= .c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 3d372d78a2756..9418c45291231 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -116,6 +116,7 @@ TEST_GEN_PROGS_x86 +=3D x86/svm_nested_invalid_vmcb12_g= pa TEST_GEN_PROGS_x86 +=3D x86/svm_nested_shutdown_test TEST_GEN_PROGS_x86 +=3D x86/svm_nested_soft_inject_test TEST_GEN_PROGS_x86 +=3D x86/svm_lbr_nested_state +TEST_GEN_PROGS_x86 +=3D x86/svm_pmu_host_guest_test TEST_GEN_PROGS_x86 +=3D x86/tsc_scaling_sync TEST_GEN_PROGS_x86 +=3D x86/sync_regs_test TEST_GEN_PROGS_x86 +=3D x86/ucna_injection_test diff --git a/tools/testing/selftests/kvm/include/x86/pmu.h b/tools/testing/= selftests/kvm/include/x86/pmu.h index 72575eadb63a0..af9b279c78df4 100644 --- a/tools/testing/selftests/kvm/include/x86/pmu.h +++ b/tools/testing/selftests/kvm/include/x86/pmu.h @@ -38,6 +38,12 @@ #define ARCH_PERFMON_EVENTSEL_INV BIT_ULL(23) #define ARCH_PERFMON_EVENTSEL_CMASK GENMASK_ULL(31, 24) =20 +/* + * These are AMD-specific bits. + */ +#define AMD64_EVENTSEL_GUESTONLY BIT_ULL(40) +#define AMD64_EVENTSEL_HOSTONLY BIT_ULL(41) + /* RDPMC control flags, Intel only. */ #define INTEL_RDPMC_METRICS BIT_ULL(29) #define INTEL_RDPMC_FIXED BIT_ULL(30) diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/te= sting/selftests/kvm/include/x86/processor.h index d8634a760a609..4cc1ba8752347 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -19,6 +19,8 @@ #include "kvm_util.h" #include "ucall_common.h" =20 +#define __stack_aligned__ __aligned(16) + extern bool host_cpu_is_intel; extern bool host_cpu_is_amd; extern bool host_cpu_is_hygon; diff --git a/tools/testing/selftests/kvm/x86/svm_pmu_host_guest_test.c b/to= ols/testing/selftests/kvm/x86/svm_pmu_host_guest_test.c new file mode 100644 index 0000000000000..a08c03a40d4f6 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/svm_pmu_host_guest_test.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KVM nested SVM PMU Host-Only/Guest-Only test + * + * Copyright (C) 2026, Google LLC. + * + * Test that KVM correctly virtualizes the AMD PMU Host-Only (bit 41) and + * Guest-Only (bit 40) event selector bits across all SVM state + * transitions. + * + * Programs 4 PMCs simultaneously with all combinations of Host-Only and + * Guest-Only bits, then verifies correct counting behavior through: + * 1. SVME=3D0: all counters count (Host-Only/Guest-Only bits ignored) + * 2. Set SVME=3D1: Host-Only and neither/both count; Guest-Only stops + * 3. VMRUN to L2: Guest-Only and neither/both count; Host-Only stops + * 4. VMEXIT to L1: Host-Only and neither/both count; Guest-Only stops + * 5. Clear SVME=3D0: all counters count (bits ignored again) + */ +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "svm_util.h" +#include "pmu.h" + +#define L2_GUEST_STACK_SIZE 255 + +#define EVENTSEL_RETIRED_INSNS (ARCH_PERFMON_EVENTSEL_OS | \ + ARCH_PERFMON_EVENTSEL_USR | \ + ARCH_PERFMON_EVENTSEL_ENABLE | \ + AMD_ZEN_INSTRUCTIONS_RETIRED) + +/* PMC configurations: index corresponds to Host-Only | Guest-Only bits */ +#define PMC_NEITHER 0 /* Neither bit set */ +#define PMC_GUESTONLY 1 /* Guest-Only bit set */ +#define PMC_HOSTONLY 2 /* Host-Only bit set */ +#define PMC_BOTH 3 /* Both bits set */ +#define NR_PMCS 4 + +/* Bitmasks for which PMCs should be counting in each state */ +#define COUNTS_ALL (BIT(PMC_NEITHER) | BIT(PMC_GUESTONLY) | \ + BIT(PMC_HOSTONLY) | BIT(PMC_BOTH)) +#define COUNTS_L1 (BIT(PMC_NEITHER) | BIT(PMC_HOSTONLY) | BIT(PMC_BOTH)) +#define COUNTS_L2 (BIT(PMC_NEITHER) | BIT(PMC_GUESTONLY) | BIT(PMC_BOTH)) + +#define LOOP_INSNS 1000 + +static __always_inline void run_instruction_loop(void) +{ + unsigned int i; + + for (i =3D 0; i < LOOP_INSNS; i++) + __asm__ __volatile__("nop"); +} + +static __always_inline void read_counters(uint64_t *counts) +{ + int i; + + for (i =3D 0; i < NR_PMCS; i++) + counts[i] =3D rdmsr(MSR_F15H_PERF_CTR + 2 * i); +} + +static __always_inline void run_and_measure(uint64_t *deltas) +{ + uint64_t before[NR_PMCS], after[NR_PMCS]; + int i; + + read_counters(before); + run_instruction_loop(); + read_counters(after); + + for (i =3D 0; i < NR_PMCS; i++) + deltas[i] =3D after[i] - before[i]; +} + +static void assert_pmc_counts(uint64_t *deltas, unsigned int expected_coun= ting) +{ + int i; + + for (i =3D 0; i < NR_PMCS; i++) { + if (expected_counting & BIT(i)) + GUEST_ASSERT_NE(deltas[i], 0); + else + GUEST_ASSERT_EQ(deltas[i], 0); + } +} + +struct test_data { + uint64_t l2_deltas[NR_PMCS]; + bool l2_done; +}; + +static struct test_data *test_data; + +static void l2_guest_code(void) +{ + run_and_measure(test_data->l2_deltas); + test_data->l2_done =3D true; + vmmcall(); +} + +static void l1_guest_code(struct svm_test_data *svm, struct test_data *dat= a) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE] __stack_aligned__; + struct vmcb *vmcb =3D svm->vmcb; + uint64_t deltas[NR_PMCS]; + uint64_t eventsel; + int i; + + test_data =3D data; + + /* Program 4 PMCs with all combinations of Host-Only/Guest-Only bits */ + for (i =3D 0; i < NR_PMCS; i++) { + eventsel =3D EVENTSEL_RETIRED_INSNS; + if (i & PMC_GUESTONLY) + eventsel |=3D AMD64_EVENTSEL_GUESTONLY; + if (i & PMC_HOSTONLY) + eventsel |=3D AMD64_EVENTSEL_HOSTONLY; + wrmsr(MSR_F15H_PERF_CTL + 2 * i, eventsel); + wrmsr(MSR_F15H_PERF_CTR + 2 * i, 0); + } + + /* Step 1: SVME=3D0 - Host-Only/Guest-Only bits ignored; all count */ + wrmsr(MSR_EFER, rdmsr(MSR_EFER) & ~EFER_SVME); + run_and_measure(deltas); + assert_pmc_counts(deltas, COUNTS_ALL); + + /* Step 2: Set SVME=3D1 - In L1 "host mode"; Guest-Only stops */ + wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SVME); + run_and_measure(deltas); + assert_pmc_counts(deltas, COUNTS_L1); + + /* Step 3: VMRUN to L2 - In "guest mode"; Host-Only stops */ + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + vmcb->control.intercept &=3D ~(1ULL << INTERCEPT_MSR_PROT); + + run_guest(vmcb, svm->vmcb_gpa); + + GUEST_ASSERT_EQ(vmcb->control.exit_code, SVM_EXIT_VMMCALL); + GUEST_ASSERT(data->l2_done); + assert_pmc_counts(data->l2_deltas, COUNTS_L2); + + /* Step 4: After VMEXIT to L1 - Back in "host mode"; Guest-Only stops */ + run_and_measure(deltas); + assert_pmc_counts(deltas, COUNTS_L1); + + /* Step 5: Clear SVME - Host-Only/Guest-Only bits ignored; all count */ + wrmsr(MSR_EFER, rdmsr(MSR_EFER) & ~EFER_SVME); + run_and_measure(deltas); + assert_pmc_counts(deltas, COUNTS_ALL); + + GUEST_DONE(); +} + +int main(int argc, char *argv[]) +{ + vm_vaddr_t svm_gva, data_gva; + struct test_data *data_hva; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + struct ucall uc; + + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM)); + TEST_REQUIRE(kvm_is_pmu_enabled()); + TEST_REQUIRE(get_kvm_amd_param_bool("enable_mediated_pmu")); + TEST_REQUIRE(host_cpu_is_amd && kvm_cpu_family() >=3D 0x17); + + vm =3D vm_create_with_one_vcpu(&vcpu, l1_guest_code); + + vcpu_alloc_svm(vm, &svm_gva); + + data_gva =3D vm_vaddr_alloc_page(vm); + data_hva =3D addr_gva2hva(vm, data_gva); + memset(data_hva, 0, sizeof(*data_hva)); + + vcpu_args_set(vcpu, 2, svm_gva, data_gva); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_DONE: + break; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + } + + kvm_vm_free(vm); + return 0; +} --=20 2.53.0.1018.g2bb0e51243-goog