From: Sandipan Das <sandipan.das@amd.com>
To: <kvm@vger.kernel.org>
Cc: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Jim Mattson <jmattson@google.com>, Yosry Ahmed <yosry@kernel.org>,
Maxim Levitsky <mlevitsk@redhat.com>,
Dapeng Mi <dapeng1.mi@linux.intel.com>,
Zide Chen <zide.chen@intel.com>,
Tom Lendacky <thomas.lendacky@amd.com>,
"Nikunj A . Dadhania" <nikunj@amd.com>,
"Manali Shukla" <manali.shukla@amd.com>,
Sandipan Das <sandipan.das@amd.com>
Subject: [PATCH 0/8] KVM: Add support for hardware-switched mediated PMU
Date: Mon, 10 Aug 2026 15:44:48 +0530 [thread overview]
Message-ID: <cover.1786345201.git.sandipan.das@amd.com> (raw)
Mediated PMU currently saves and restores the guest PMU state in
software on every world switch. On Zen 5 and later processors, it is
possible to offload this to the hardware, which automatically saves and
restores the guest counter state to and from a vendor save area (VMCB)
during world switches. This feature is called PMC virtualization and
detailed information about it can be found in Volume 2 of the AMD64
Architecture Programmer's Manual under Section 15.39.
This series extends the mediated PMU framework with a hardware-switched
mode and adds the AMD (SVM) implementation, including nested support.
Performance
-----------
The difference in the world switch overhead between software-switched
and hardware-switched modes is measured with the x86/vmexit test from
kvm-unit-tests on a system with an AMD EPYC 9755 processor. The values
are in cycles per operation (lower is better), averaged over 5 runs.
------------------------------------------------------------------------
test sw-switched hw-switched gain
------------------------------------------------------------------------
cpuid 5333 2592 +51.4%
vmcall 15858 7619 +52.0%
wbinvd 5256 2517 +52.1%
invd 1857 2147 -15.6%
mov_from_cr8 18 18 0.0%
mov_to_cr8 157 156 +0.6%
inl_from_pmtimer 25934 21176 +18.3%
inl_from_qemu 25881 21156 +18.3%
inl_from_kernel 5521 2772 +49.8%
outl_to_kernel 5522 2778 +49.7%
mov_dr 114 114 0.0%
self_ipi_sti_nop 1020 1015 +0.5%
ipi self_ipi_sti_nop 310 307 +1.0%
eoi self_ipi_sti_nop 242 241 +0.4%
self_ipi_sti_hlt 2714 2704 +0.4%
ipi self_ipi_sti_hlt 310 307 +1.0%
eoi self_ipi_sti_hlt 242 240 +0.8%
self_ipi_tpr 1272 1263 +0.7%
ipi self_ipi_tpr 309 307 +0.6%
eoi self_ipi_tpr 241 240 +0.4%
self_ipi_tpr_sti_nop 1304 1295 +0.7%
ipi self_ipi_tpr_sti_nop 309 307 +0.6%
eoi self_ipi_tpr_sti_nop 242 241 +0.4%
self_ipi_tpr_sti_hlt 3003 2991 +0.4%
ipi self_ipi_tpr_sti_hlt 309 307 +0.6%
eoi self_ipi_tpr_sti_hlt 242 240 +0.8%
x2apic_self_ipi_sti_nop 899 895 +0.4%
ipi x2apic_self_ipi_sti_nop 191 190 +0.5%
eoi x2apic_self_ipi_sti_nop 242 241 +0.4%
x2apic_self_ipi_sti_hlt 2592 2587 +0.2%
ipi x2apic_self_ipi_sti_hlt 191 190 +0.5%
eoi x2apic_self_ipi_sti_hlt 242 241 +0.4%
x2apic_self_ipi_tpr 1159 1151 +0.7%
ipi x2apic_self_ipi_tpr 193 193 0.0%
eoi x2apic_self_ipi_tpr 241 240 +0.4%
x2apic_self_ipi_tpr_sti_nop 1189 1180 +0.8%
ipi x2apic_self_ipi_tpr_sti_nop 193 193 0.0%
eoi x2apic_self_ipi_tpr_sti_nop 242 241 +0.4%
x2apic_self_ipi_tpr_sti_hlt 2887 2875 +0.4%
ipi x2apic_self_ipi_tpr_sti_hlt 194 192 +1.0%
eoi x2apic_self_ipi_tpr_sti_hlt 242 239 +1.2%
ple_round_robin 19 19 0.0%
wr_kernel_gs_base 73 73 0.0%
wr_ibpb_msr 563 557 +1.1%
wr_tsc_adjust_msr 5352 2603 +51.4%
rd_tsc_adjust_msr 5330 2586 +51.5%
toggle_cr0_wp 11319 5810 +48.7%
toggle_cr4_pge 11743 6242 +46.8%
mmio-no-eventfd:pci-mem 31890 26835 +15.9%
mmio-wildcard-eventfd:pci-mem 6461 3666 +43.3%
mmio-datamatch-eventfd:pci-mem 6449 3671 +43.1%
portio-no-eventfd:pci-io 25218 21455 +14.9%
portio-wildcard-eventfd:pci-io 5512 2774 +49.7%
portio-datamatch-eventfd:pci-io 5524 2780 +49.7%
------------------------------------------------------------------------
The largest gains are for wbinvd (+52.1%), vmcall (+52.0%), and cpuid
(+51.4%), followed by the TSC-adjust MSR accesses (~+51%), the
kernel-handled port I/O paths (~+50%), and the control-register toggles
(~+47-49%). The wildcard and datamatch MMIO / port-I/O paths improve by
~+43-50%, while the slower no-eventfd MMIO / port-I/O and pmtimer/qemu
port-I/O paths improve by ~+15-18%.
The only meaningful regression is invd (-15.6%). The self-IPI and EOI
subtests move by at most 1.2% and wr_kernel_gs_base is unchanged, all
within run-to-run noise.
Design
------
* The entity responsible for switching the guest PMU state is tracked
per-VM via a new set of mediated PMU capability flags in kvm_arch.
In software-switched mode the state resides in struct kvm_pmu; in
hardware-switched mode it resides in the vendor save area.
* Event filtering, instruction emulation, and intercepted RDPMC still
need the state in struct kvm_pmu, so new vendor state-sync PMU ops
synchronize specific MSRs between struct kvm_pmu and the vendor
save area on demand.
* On SVM, the feature depends on VNMI for guest PMI delivery and is
controlled by the new "vpmc" kvm_amd module parameter, enabled by
default when the host supports it and mediated PMU is enabled.
Limitations
-----------
* Not supported for SEV-ES and SEV-SNP guests: the guest PMU state
resides in an encrypted VMSA that is inaccessible to the event
filtering logic.
* With VNMI and no AVIC, overflow interrupts are always delivered as
NMIs because the APIC is emulated and the LVTPC is ignored. This
shows up as expected behavioral differences in the x86/pmu test of
kvm-unit-tests.
Overview
--------
Patches 1-3 extend the mediated PMU framework with hardware-switched
mode: the capability flags, the vendor state-sync ops, and the generic
support. Patches 4-6 add the SVM enablement: the PerfCtrVirt feature
bit, the VMCB save-area fields, and the SVM implementation. Patch 7
adds nested (nSVM) support to use the feature with L2 guests. Patch 8
explicitly disables the feature for SEV-ES and SEV-SNP guests.
Tested with kvm-unit-tests (KUT) and perf fuzzer. KUT's x86/pmu test
requires patching to accept overflow interrupts as NMIs (limitation
because of VNMI ignoring the LVTPC). It is recommended to apply the
following patches before testing.
https://lore.kernel.org/kvm/3bfbf15c22652ba00cf4a16fe9e0a3bfe7071f97.1784096302.git.sandipan.das@amd.com/
https://lore.kernel.org/kvm/b075ec13e95167da1f2229626713c91d291bb75b.1784097178.git.sandipan.das@amd.com/
https://lore.kernel.org/all/106bc3a4660653cb7750f3ae07a4dbca42c2762c.1786356229.git.sandipan.das@amd.com/
base-commit: 6cf46b37b0356b3408f8ba949e10462cc71b533d
(tag: kvm-x86-next-2026.08.07)
Previous versions can be found at:
rfc: https://lore.kernel.org/kvm/cover.1762960531.git.sandipan.das@amd.com/
Changes in v1:
* Introduce mediated PMU capabilities for hardware PMU virtualization
features instead of perf PMU capabilities.
* Make VNMI a hard requirement since AVIC can be inhibited.
* Introduce new PMU ops to access VMCB PMU state instead of relying
on host-initiated {get,set}_msr() ops.
* Make VMCB PMU state accessible via KVM_{GET,SET}_MSRS for migration.
* Implement support for nested SVM.
* Disable support for SEV-ES and SEV-SNP guests explicitly.
Sandipan Das (8):
KVM: x86/pmu: Add mediated PMU capability flags
KVM: x86/pmu: Add PMU ops for vendor state sync
KVM: x86/pmu: Add support for hardware-switched PMU
x86/cpufeatures: Add PerfCtrVirt feature bit
KVM: SVM: Add VMCB fields for PMC virtualization
KVM: SVM: Add support for hardware-switched PMU
KVM: nSVM: Add support for hardware-switched PMU
KVM: SEV: Disallow the use of hardware-switched PMU
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/include/asm/kvm-x86-pmu-ops.h | 3 +
arch/x86/include/asm/kvm_host.h | 11 +++
arch/x86/include/asm/svm.h | 13 ++-
arch/x86/kvm/cpuid.c | 1 +
arch/x86/kvm/pmu.c | 102 +++++++++++++++++----
arch/x86/kvm/pmu.h | 29 ++++++
arch/x86/kvm/svm/nested.c | 45 +++++++++-
arch/x86/kvm/svm/pmu.c | 117 +++++++++++++++++++++++++
arch/x86/kvm/svm/sev.c | 3 +
arch/x86/kvm/svm/svm.c | 58 +++++++++++-
arch/x86/kvm/svm/svm.h | 19 ++++
arch/x86/kvm/vmx/pmu_intel.c | 2 +
arch/x86/kvm/vmx/vmx.c | 3 +-
arch/x86/kvm/x86.c | 2 +
15 files changed, 384 insertions(+), 25 deletions(-)
--
2.53.0
next reply other threads:[~2026-08-10 10:15 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-10 10:14 Sandipan Das [this message]
2026-08-10 10:14 ` [PATCH 1/8] KVM: x86/pmu: Add mediated PMU capability flags Sandipan Das
2026-08-10 10:29 ` sashiko-bot
2026-08-10 10:14 ` [PATCH 2/8] KVM: x86/pmu: Add PMU ops for vendor state sync Sandipan Das
2026-08-10 10:29 ` sashiko-bot
2026-08-10 10:14 ` [PATCH 3/8] KVM: x86/pmu: Add support for hardware-switched PMU Sandipan Das
2026-08-10 10:36 ` sashiko-bot
2026-08-10 10:14 ` [PATCH 4/8] x86/cpufeatures: Add PerfCtrVirt feature bit Sandipan Das
2026-08-10 10:24 ` sashiko-bot
2026-08-10 10:14 ` [PATCH 5/8] KVM: SVM: Add VMCB fields for PMC virtualization Sandipan Das
2026-08-10 10:14 ` [PATCH 6/8] KVM: SVM: Add support for hardware-switched PMU Sandipan Das
2026-08-10 10:57 ` sashiko-bot
2026-08-10 10:14 ` [PATCH 7/8] KVM: nSVM: " Sandipan Das
2026-08-10 10:54 ` sashiko-bot
2026-08-10 10:14 ` [PATCH 8/8] KVM: SEV: Disallow the use of " Sandipan Das
2026-08-10 10:40 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cover.1786345201.git.sandipan.das@amd.com \
--to=sandipan.das@amd.com \
--cc=dapeng1.mi@linux.intel.com \
--cc=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=manali.shukla@amd.com \
--cc=mlevitsk@redhat.com \
--cc=nikunj@amd.com \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=thomas.lendacky@amd.com \
--cc=yosry@kernel.org \
--cc=zide.chen@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox