* [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2
@ 2026-07-24 19:50 Shivansh Dhiman
2026-07-24 19:50 ` [PATCH 1/7] KVM: SVM: Add VMCB fields for LBR v2 virtualization Shivansh Dhiman
` (6 more replies)
0 siblings, 7 replies; 13+ messages in thread
From: Shivansh Dhiman @ 2026-07-24 19:50 UTC (permalink / raw)
To: seanjc, pbonzini, tglx, mingo
Cc: kvm, x86, yosry, jmattson, thomas.lendacky, nikunj.dadhania,
sandipan.das, santosh.shukla, shivansh.dhiman
This series adds SVM support for virtualizing AMD's Last Branch Record
Extension v2 (LbrExtV2) in KVM.
LbrExtV2, introduced on Zen 4, is a branch sampling facility providing a
16-entry stack of last-taken branches via dedicated MSRs:
* MSR 0xC000010E - Last Branch Stack Select (LBR_SELECT)
* MSR 0xC000010F - Debug Extension Control (DBG_EXTN_CFG)
* MSR 0xC0010300..0xC001031F - 16 LBR FROM/TO MSR pairs
AMD hardware extends the VMCB save area with fields for these MSRs. When
V_LBR (VMCB.MISC_CTL2.LBR_VIRTUALIZATION_ENABLE) is set, the CPU saves and
restores the guest's LbrExtV2 state on VMRUN/#VMEXIT, letting the guest
use LBR v2 without being intercepted.
V_LBR is enabled lazily, i.e, LBR virtualization is enabled only when
guest flips the DbgExtnCfg.LBRv2En (bit 6) to record branches. This is done
to prevent MSR save/restore cost during VMRUN/#VMEXIT cycles when V_LBR
is disabled. The dependent LBR and PMC freeze-on-PMI feature is added on top.
Testing must be done by first disabling NMI watchdog on the host machine, and
enabling the Mediated PMU framework.
$ echo 0 | sudo tee /proc/sys/kernel/nmi_watchdog
$ sudo modprobe kvm_amd enable_mediated_pmu=1
Regards,
Shivansh
---
Sandipan Das (1):
KVM: SVM: Add VMCB fields for LBR v2 virtualization
Shivansh Dhiman (6):
KVM: SVM: Add capability for LbrExtV2
KVM: SVM: Emulate guest accesses to LBR v2 MSRs
KVM: SVM: Enable hardware-assisted LBR v2 virtualization
KVM: SVM: Advertise LbrExtV2 to userspace
KVM: SVM: Add LBR/PMC freeze support
KVM: x86: Use SCATTERED_F() for PERFMON_V2
arch/x86/events/core.c | 1 +
arch/x86/include/asm/perf_event.h | 1 +
arch/x86/include/asm/svm.h | 16 +++-
arch/x86/kvm/cpuid.c | 9 +-
arch/x86/kvm/reverse_cpuid.h | 6 +-
arch/x86/kvm/svm/svm.c | 140 +++++++++++++++++++++++++++++-
arch/x86/kvm/svm/svm.h | 7 +-
7 files changed, 172 insertions(+), 8 deletions(-)
base-commit: 50406d35f5635e1cc523e61409d57e851b5f5df8
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/7] KVM: SVM: Add VMCB fields for LBR v2 virtualization
2026-07-24 19:50 [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2 Shivansh Dhiman
@ 2026-07-24 19:50 ` Shivansh Dhiman
2026-07-24 20:08 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 2/7] KVM: SVM: Add capability for LbrExtV2 Shivansh Dhiman
` (5 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Shivansh Dhiman @ 2026-07-24 19:50 UTC (permalink / raw)
To: seanjc, pbonzini, tglx, mingo
Cc: kvm, x86, yosry, jmattson, thomas.lendacky, nikunj.dadhania,
sandipan.das, santosh.shukla, shivansh.dhiman
From: Sandipan Das <sandipan.das@amd.com>
Define the new VMCB fields that will be used to save and restore the
state of the following Last Branch Record Extension Version 2 (LbrExtV2)
related MSRs.
* Last Branch Stack Select (MSR 0xc000010e)
* Debug Extension Control (MSR 0xc000010f)
* LBR v2 Branch FROM (MSRs 0xc0010300..0xc001031e)
* LBR v2 Branch To (MSRs 0xc0010301..0xc001031f)
Signed-off-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Shivansh Dhiman <shivansh.dhiman@amd.com>
---
arch/x86/include/asm/svm.h | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index aa63431ba92c..fbcf6c4dbb92 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -368,8 +368,15 @@ struct vmcb_save_area {
u64 br_to;
u64 last_excp_from;
u64 last_excp_to;
- u8 reserved_0x298[72];
+ u64 dbg_extn_cfg;
+ u8 reserved_0x2a0[64];
u64 spec_ctrl; /* Guest version of SPEC_CTRL at 0x2E0 */
+ u8 reserved_0x2e8[904];
+ struct {
+ u64 lbr_stack_from;
+ u64 lbr_stack_to;
+ } __packed lbr[16];
+ u64 lbr_select;
} __packed;
/* Save area definition for SEV-ES and SEV-SNP guests */
@@ -552,7 +559,7 @@ struct vmcb {
};
} __packed;
-#define EXPECTED_VMCB_SAVE_AREA_SIZE 744
+#define EXPECTED_VMCB_SAVE_AREA_SIZE 1912
#define EXPECTED_GHCB_SAVE_AREA_SIZE 1032
#define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1648
#define EXPECTED_VMCB_CONTROL_AREA_SIZE 1024
@@ -577,7 +584,8 @@ static inline void __unused_size_checks(void)
BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0xd8);
BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x180);
BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x248);
- BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x298);
+ BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x2a0);
+ BUILD_BUG_RESERVED_OFFSET(vmcb_save_area, 0x2e8);
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0xc8);
BUILD_BUG_RESERVED_OFFSET(sev_es_save_area, 0xcc);
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/7] KVM: SVM: Add capability for LbrExtV2
2026-07-24 19:50 [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2 Shivansh Dhiman
2026-07-24 19:50 ` [PATCH 1/7] KVM: SVM: Add VMCB fields for LBR v2 virtualization Shivansh Dhiman
@ 2026-07-24 19:50 ` Shivansh Dhiman
2026-07-24 19:50 ` [PATCH 3/7] KVM: SVM: Emulate guest accesses to LBR v2 MSRs Shivansh Dhiman
` (4 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Shivansh Dhiman @ 2026-07-24 19:50 UTC (permalink / raw)
To: seanjc, pbonzini, tglx, mingo
Cc: kvm, x86, yosry, jmattson, thomas.lendacky, nikunj.dadhania,
sandipan.das, santosh.shukla, shivansh.dhiman
Define the LbrExtV2 KVM feature (CPUID 0x80000022.EAX[1]) and plumb the
host LBR stack depth out of the core PMU driver, so KVM can later report
the depth the hardware actually supports rather than assuming a value.
Signed-off-by: Sandipan Das <sandipan.das@amd.com>
Co-developed-by: Shivansh Dhiman <shivansh.dhiman@amd.com>
Signed-off-by: Shivansh Dhiman <shivansh.dhiman@amd.com>
---
arch/x86/events/core.c | 1 +
arch/x86/include/asm/perf_event.h | 1 +
arch/x86/kvm/reverse_cpuid.h | 2 ++
3 files changed, 4 insertions(+)
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 4b9e105309c6..4acbca1a88a1 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -3138,6 +3138,7 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap)
cap->bit_width_fixed = cap->num_counters_fixed ? x86_pmu.cntval_bits : 0;
cap->events_mask = (unsigned int)x86_pmu.events_maskl;
cap->events_mask_len = x86_pmu.events_mask_len;
+ cap->num_branches_lbr = x86_pmu.lbr_nr;
cap->pebs_ept = x86_pmu.pebs_ept;
cap->mediated = !!(pmu.capabilities & PERF_PMU_CAP_MEDIATED_VPMU);
}
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 1eb13673e889..f18cf0986e12 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -306,6 +306,7 @@ struct x86_pmu_capability {
int bit_width_fixed;
unsigned int events_mask;
int events_mask_len;
+ int num_branches_lbr;
unsigned int pebs_ept :1;
unsigned int mediated :1;
};
diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h
index 657f5f743ed9..b4abd839af1d 100644
--- a/arch/x86/kvm/reverse_cpuid.h
+++ b/arch/x86/kvm/reverse_cpuid.h
@@ -71,6 +71,7 @@
/* CPUID level 0x80000022 (EAX) */
#define KVM_X86_FEATURE_PERFMON_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 0)
+#define KVM_X86_FEATURE_AMD_LBR_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 1)
/* CPUID level 0x80000021 (ECX) */
#define KVM_X86_FEATURE_TSA_SQ_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 1)
@@ -146,6 +147,7 @@ static __always_inline u32 __feature_translate(int x86_feature)
KVM_X86_TRANSLATE_FEATURE(SGX_EDECCSSA);
KVM_X86_TRANSLATE_FEATURE(CONSTANT_TSC);
KVM_X86_TRANSLATE_FEATURE(PERFMON_V2);
+ KVM_X86_TRANSLATE_FEATURE(AMD_LBR_V2);
KVM_X86_TRANSLATE_FEATURE(RRSBA_CTRL);
KVM_X86_TRANSLATE_FEATURE(BHI_CTRL);
KVM_X86_TRANSLATE_FEATURE(TSA_SQ_NO);
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/7] KVM: SVM: Emulate guest accesses to LBR v2 MSRs
2026-07-24 19:50 [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2 Shivansh Dhiman
2026-07-24 19:50 ` [PATCH 1/7] KVM: SVM: Add VMCB fields for LBR v2 virtualization Shivansh Dhiman
2026-07-24 19:50 ` [PATCH 2/7] KVM: SVM: Add capability for LbrExtV2 Shivansh Dhiman
@ 2026-07-24 19:50 ` Shivansh Dhiman
2026-07-24 20:13 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 4/7] KVM: SVM: Enable hardware-assisted LBR v2 virtualization Shivansh Dhiman
` (3 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Shivansh Dhiman @ 2026-07-24 19:50 UTC (permalink / raw)
To: seanjc, pbonzini, tglx, mingo
Cc: kvm, x86, yosry, jmattson, thomas.lendacky, nikunj.dadhania,
sandipan.das, santosh.shukla, shivansh.dhiman
Back the LBR v2 MSRs with their VMCB save-area fields in
svm_{get,set}_msr(). This is required when guest accesses to these
MSRs are intercepted. This allows the guest to retain the values
of these MSRs on VMRUN/#VMEXIT cycle when vLBR is disabled.
Signed-off-by: Shivansh Dhiman <shivansh.dhiman@amd.com>
---
arch/x86/include/asm/svm.h | 2 ++
arch/x86/kvm/svm/svm.c | 68 ++++++++++++++++++++++++++++++++++++++
arch/x86/kvm/svm/svm.h | 2 ++
3 files changed, 72 insertions(+)
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index fbcf6c4dbb92..f3bc97bc6aca 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -253,6 +253,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
#define SVM_TSC_RATIO_MAX 0x000000ffffffffffULL
#define SVM_TSC_RATIO_DEFAULT 0x0100000000ULL
+#define SVM_LBR_V2_STACK_SIZE 16
+
/* AVIC */
#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFFULL)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index ef69a51ab27f..13ac62604ca0 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -744,6 +744,12 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
svm->lbr_msrs_intercepted = intercept;
}
+static bool svm_lbrv2_supported(struct kvm_vcpu *vcpu)
+{
+ return guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_LBR_V2) &&
+ kvm_vcpu_has_mediated_pmu(vcpu);
+}
+
void svm_vcpu_free_msrpm(void *msrpm)
{
__free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE));
@@ -2787,6 +2793,19 @@ static u64 *svm_vmcb_lbr(struct vcpu_svm *svm, u32 msr)
return &svm->vmcb->save.br_from;
}
+static u64 *svm_vmcb_lbrv2(struct vcpu_svm *svm, u32 msr)
+{
+ u32 offset = msr - MSR_AMD_SAMP_BR_FROM;
+ u32 idx = offset >> 1;
+
+ if (WARN_ON_ONCE(idx >= SVM_LBR_V2_STACK_SIZE))
+ return &svm->vmcb->save.lbr[0].lbr_stack_from;
+
+ if (offset & 1)
+ return &svm->vmcb->save.lbr[idx].lbr_stack_to;
+ return &svm->vmcb->save.lbr[idx].lbr_stack_from;
+}
+
static bool sev_es_prevent_msr_access(struct kvm_vcpu *vcpu,
struct msr_data *msr_info)
{
@@ -2882,6 +2901,21 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_IA32_LASTINTTOIP:
msr_info->data = lbrv ? *svm_vmcb_lbr(svm, msr_info->index) : 0;
break;
+ case MSR_AMD_DBG_EXTN_CFG:
+ if (!svm_lbrv2_supported(vcpu))
+ return KVM_MSR_RET_UNSUPPORTED;
+ msr_info->data = svm->vmcb->save.dbg_extn_cfg;
+ break;
+ case MSR_AMD64_LBR_SELECT:
+ if (!svm_lbrv2_supported(vcpu))
+ return KVM_MSR_RET_UNSUPPORTED;
+ msr_info->data = svm->vmcb->save.lbr_select;
+ break;
+ case MSR_AMD_SAMP_BR_FROM ... MSR_AMD_SAMP_BR_FROM + 31:
+ if (!svm_lbrv2_supported(vcpu))
+ return KVM_MSR_RET_UNSUPPORTED;
+ msr_info->data = *svm_vmcb_lbrv2(svm, msr_info->index);
+ break;
case MSR_VM_HSAVE_PA:
msr_info->data = svm->nested.hsave_msr;
break;
@@ -3181,6 +3215,40 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
*svm_vmcb_lbr(svm, ecx) = data;
vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
break;
+ case MSR_AMD_DBG_EXTN_CFG:
+ if (!svm_lbrv2_supported(vcpu))
+ return KVM_MSR_RET_UNSUPPORTED;
+
+ if (data & DBG_EXTN_CFG_RESERVED_BITS)
+ return 1;
+
+ if (svm->vmcb->save.dbg_extn_cfg == data)
+ break;
+
+ svm->vmcb->save.dbg_extn_cfg = data;
+ vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
+ svm_update_lbrv(vcpu);
+ break;
+ case MSR_AMD64_LBR_SELECT:
+ if (!svm_lbrv2_supported(vcpu))
+ return KVM_MSR_RET_UNSUPPORTED;
+
+ if (data & LBR_SELECT_RESERVED_BITS)
+ return 1;
+
+ if (svm->vmcb->save.lbr_select == data)
+ break;
+
+ svm->vmcb->save.lbr_select = data;
+ vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
+ break;
+ case MSR_AMD_SAMP_BR_FROM ... MSR_AMD_SAMP_BR_FROM + 31:
+ if (!svm_lbrv2_supported(vcpu))
+ return KVM_MSR_RET_UNSUPPORTED;
+
+ *svm_vmcb_lbrv2(svm, ecx) = data;
+ vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
+ break;
case MSR_VM_HSAVE_PA:
/*
* Old kernels did not validate the value written to
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 716be21fba33..f62bf19024cc 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -784,6 +784,8 @@ BUILD_SVM_MSR_BITMAP_HELPERS(void, clear, __clear)
BUILD_SVM_MSR_BITMAP_HELPERS(void, set, __set)
#define DEBUGCTL_RESERVED_BITS (~DEBUGCTLMSR_LBR)
+#define DBG_EXTN_CFG_RESERVED_BITS (~DBG_EXTN_CFG_LBRV2EN)
+#define LBR_SELECT_RESERVED_BITS (~GENMASK_ULL(8, 0))
/* svm.c */
extern bool dump_invalid_vmcb;
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 4/7] KVM: SVM: Enable hardware-assisted LBR v2 virtualization
2026-07-24 19:50 [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2 Shivansh Dhiman
` (2 preceding siblings ...)
2026-07-24 19:50 ` [PATCH 3/7] KVM: SVM: Emulate guest accesses to LBR v2 MSRs Shivansh Dhiman
@ 2026-07-24 19:50 ` Shivansh Dhiman
2026-07-24 20:17 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 5/7] KVM: SVM: Advertise LbrExtV2 to userspace Shivansh Dhiman
` (2 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Shivansh Dhiman @ 2026-07-24 19:50 UTC (permalink / raw)
To: seanjc, pbonzini, tglx, mingo
Cc: kvm, x86, yosry, jmattson, thomas.lendacky, nikunj.dadhania,
sandipan.das, santosh.shukla, shivansh.dhiman
Enable V_LBR so hardware saves and restores the guest's LBR v2 state in
the VMCB, and pass the LBR v2 MSRs through (by disabling interception)
to the guest while it is set. V_LBR is enabled lazily, only once the
guest turns on branch recording, just like legacy LBR keys off DEBUGCTL.
Co-developed-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Shivansh Dhiman <shivansh.dhiman@amd.com>
---
arch/x86/kvm/svm/svm.c | 46 ++++++++++++++++++++++++++++++++++++++++--
arch/x86/kvm/svm/svm.h | 1 +
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 13ac62604ca0..04e386b838d3 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -750,6 +750,41 @@ static bool svm_lbrv2_supported(struct kvm_vcpu *vcpu)
kvm_vcpu_has_mediated_pmu(vcpu);
}
+static bool svm_lbrv2_active(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ return svm_lbrv2_supported(vcpu) &&
+ (svm->vmcb->save.dbg_extn_cfg & DBG_EXTN_CFG_LBRV2EN);
+}
+
+static void svm_recalc_lbrv2_msr_intercepts(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ bool intercept = !svm_lbrv2_active(vcpu);
+ int i;
+
+ if (intercept == svm->lbrv2_msrs_intercepted)
+ return;
+
+ for (i = 0; i < 32; i++)
+ svm_set_intercept_for_msr(vcpu, MSR_AMD_SAMP_BR_FROM + i, MSR_TYPE_RW, intercept);
+
+ svm_set_intercept_for_msr(vcpu, MSR_AMD64_LBR_SELECT, MSR_TYPE_RW, intercept);
+
+ /*
+ * DBG_EXTN_CFG stays permanently intercepted for non-SEV-ES guests so
+ * KVM can observe LBRV2EN and lazily toggle V_LBR. SEV-ES+ guests must
+ * delegate LBR virtualization to the processor (per the APM), where
+ * intercepting LBR MSRs can be fatal, so toggle it with the rest. See
+ * commit b7e4be0a224f ("KVM: SEV-ES: Delegate LBR virtualization to the
+ * processor").
+ */
+ if (is_sev_es_guest(vcpu))
+ svm_set_intercept_for_msr(vcpu, MSR_AMD_DBG_EXTN_CFG, MSR_TYPE_RW, intercept);
+
+ svm->lbrv2_msrs_intercepted = intercept;
+}
+
void svm_vcpu_free_msrpm(void *msrpm)
{
__free_pages(virt_to_page(msrpm), get_order(MSRPM_SIZE));
@@ -805,8 +840,10 @@ static void svm_recalc_msr_intercepts(struct kvm_vcpu *vcpu)
svm_disable_intercept_for_msr(vcpu, MSR_SYSCALL_MASK, MSR_TYPE_RW);
#endif
- if (lbrv)
+ if (lbrv) {
svm_recalc_lbr_msr_intercepts(vcpu);
+ svm_recalc_lbrv2_msr_intercepts(vcpu);
+ }
if (cpu_feature_enabled(X86_FEATURE_IBPB))
svm_set_intercept_for_msr(vcpu, MSR_IA32_PRED_CMD, MSR_TYPE_W,
@@ -874,6 +911,7 @@ void svm_enable_lbrv(struct kvm_vcpu *vcpu)
{
__svm_enable_lbrv(vcpu);
svm_recalc_lbr_msr_intercepts(vcpu);
+ svm_recalc_lbrv2_msr_intercepts(vcpu);
}
static void __svm_disable_lbrv(struct kvm_vcpu *vcpu)
@@ -886,9 +924,11 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
bool current_enable_lbrv = svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR;
+
bool enable_lbrv = (svm->vmcb->save.dbgctl & DEBUGCTLMSR_LBR) ||
(is_guest_mode(vcpu) && guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
- (svm->nested.ctl.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR));
+ (svm->nested.ctl.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR)) ||
+ svm_lbrv2_active(vcpu);
if (enable_lbrv && !current_enable_lbrv)
__svm_enable_lbrv(vcpu);
@@ -902,6 +942,7 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu)
* do, so always recalculate the intercepts here.
*/
svm_recalc_lbr_msr_intercepts(vcpu);
+ svm_recalc_lbrv2_msr_intercepts(vcpu);
}
void disable_nmi_singlestep(struct vcpu_svm *svm)
@@ -1347,6 +1388,7 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu)
svm->x2avic_msrs_intercepted = true;
svm->lbr_msrs_intercepted = true;
+ svm->lbrv2_msrs_intercepted = true;
svm->vmcb01.ptr = page_address(vmcb01_page);
svm->vmcb01.pa = __sme_set(page_to_pfn(vmcb01_page) << PAGE_SHIFT);
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index f62bf19024cc..01dae3828a7a 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -363,6 +363,7 @@ struct vcpu_svm {
bool avic_irq_window;
bool x2avic_msrs_intercepted;
bool lbr_msrs_intercepted;
+ bool lbrv2_msrs_intercepted;
/* Guest GIF value, used when vGIF is not enabled */
bool guest_gif;
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 5/7] KVM: SVM: Advertise LbrExtV2 to userspace
2026-07-24 19:50 [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2 Shivansh Dhiman
` (3 preceding siblings ...)
2026-07-24 19:50 ` [PATCH 4/7] KVM: SVM: Enable hardware-assisted LBR v2 virtualization Shivansh Dhiman
@ 2026-07-24 19:50 ` Shivansh Dhiman
2026-07-24 20:06 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 6/7] KVM: SVM: Add LBR/PMC freeze support Shivansh Dhiman
2026-07-24 19:50 ` [PATCH 7/7] KVM: x86: Use SCATTERED_F() for PERFMON_V2 Shivansh Dhiman
6 siblings, 1 reply; 13+ messages in thread
From: Shivansh Dhiman @ 2026-07-24 19:50 UTC (permalink / raw)
To: seanjc, pbonzini, tglx, mingo
Cc: kvm, x86, yosry, jmattson, thomas.lendacky, nikunj.dadhania,
sandipan.das, santosh.shukla, shivansh.dhiman
Now that LBR v2 is fully virtualized, advertise it and report the LBR
stack depth in CPUID. Gate the advertisement on LBR virtualization, the
mediated PMU, PerfMonV2 and a 16-entry host stack, so KVM never exposes a
configuration it cannot faithfully virtualize, and drop the feature for a
vCPU whose CPUID is set with an unsupported stack size.
Co-developed-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Sandipan Das <sandipan.das@amd.com>
Signed-off-by: Shivansh Dhiman <shivansh.dhiman@amd.com>
---
arch/x86/kvm/cpuid.c | 6 ++++++
arch/x86/kvm/svm/svm.c | 22 ++++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 2698fa42cd97..d450a5b2499d 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -1267,6 +1267,7 @@ void kvm_initialize_cpu_caps(void)
kvm_cpu_cap_init(CPUID_8000_0022_EAX,
F(PERFMON_V2),
+ SCATTERED_F(AMD_LBR_V2),
);
if (!static_cpu_has_bug(X86_BUG_NULL_SEG))
@@ -1883,6 +1884,11 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
cpuid_entry_override(entry, CPUID_8000_0022_EAX);
ebx.split.num_core_pmc = kvm_pmu_cap.num_counters_gp;
+
+ if (kvm_cpu_cap_has(X86_FEATURE_AMD_LBR_V2))
+ ebx.split.lbr_v2_stack_sz =
+ min(kvm_pmu_cap.num_branches_lbr, SVM_LBR_V2_STACK_SIZE);
+
entry->ebx = ebx.full;
break;
}
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 04e386b838d3..4b84498e93be 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -4820,6 +4820,20 @@ static bool svm_has_emulated_msr(struct kvm *kvm, u32 index)
return true;
}
+static int cpuid_query_lbrv2_stack_size(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *entry;
+
+ entry = kvm_find_cpuid_entry(vcpu, 0x80000000);
+ if (!entry || entry->eax < 0x80000022)
+ goto not_found;
+ entry = kvm_find_cpuid_entry(vcpu, 0x80000022);
+ if (entry)
+ return (entry->ebx >> 4) & 0x3f;
+not_found:
+ return 0;
+}
+
static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -4846,6 +4860,10 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
if (guest_cpuid_is_intel_compatible(vcpu))
guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
+ if (guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_LBR_V2) &&
+ cpuid_query_lbrv2_stack_size(vcpu) != SVM_LBR_V2_STACK_SIZE)
+ guest_cpu_cap_clear(vcpu, X86_FEATURE_AMD_LBR_V2);
+
if (is_sev_guest(vcpu))
sev_vcpu_after_set_cpuid(svm);
}
@@ -5692,6 +5710,10 @@ static __init void svm_set_cpu_caps(void)
if (kvm_pmu_cap.version != 2 ||
!kvm_cpu_cap_has(X86_FEATURE_PERFCTR_CORE))
kvm_cpu_cap_clear(X86_FEATURE_PERFMON_V2);
+
+ if (!lbrv || !enable_mediated_pmu ||
+ !kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2))
+ kvm_cpu_cap_clear(X86_FEATURE_AMD_LBR_V2);
}
/* CPUID 0x8000001F (SME/SEV features) */
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 6/7] KVM: SVM: Add LBR/PMC freeze support
2026-07-24 19:50 [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2 Shivansh Dhiman
` (4 preceding siblings ...)
2026-07-24 19:50 ` [PATCH 5/7] KVM: SVM: Advertise LbrExtV2 to userspace Shivansh Dhiman
@ 2026-07-24 19:50 ` Shivansh Dhiman
2026-07-24 20:13 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 7/7] KVM: x86: Use SCATTERED_F() for PERFMON_V2 Shivansh Dhiman
6 siblings, 1 reply; 13+ messages in thread
From: Shivansh Dhiman @ 2026-07-24 19:50 UTC (permalink / raw)
To: seanjc, pbonzini, tglx, mingo
Cc: kvm, x86, yosry, jmattson, thomas.lendacky, nikunj.dadhania,
sandipan.das, santosh.shukla, shivansh.dhiman
Add support for the LBR and PMC freeze-on-PMI feature (CPUID
0x80000022.EAX[2]). This feature is very often used with LBRv2. Permit
the guest to enable freezing via DEBUGCTL only when the feature is
advertised to it, and advertise it accordingly.
Signed-off-by: Shivansh Dhiman <shivansh.dhiman@amd.com>
---
arch/x86/kvm/cpuid.c | 1 +
arch/x86/kvm/reverse_cpuid.h | 6 ++++--
arch/x86/kvm/svm/svm.c | 4 ++++
arch/x86/kvm/svm/svm.h | 4 +++-
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index d450a5b2499d..03501b3145eb 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -1268,6 +1268,7 @@ void kvm_initialize_cpu_caps(void)
kvm_cpu_cap_init(CPUID_8000_0022_EAX,
F(PERFMON_V2),
SCATTERED_F(AMD_LBR_V2),
+ SCATTERED_F(AMD_LBR_PMC_FREEZE),
);
if (!static_cpu_has_bug(X86_BUG_NULL_SEG))
diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h
index b4abd839af1d..9a58f91eb173 100644
--- a/arch/x86/kvm/reverse_cpuid.h
+++ b/arch/x86/kvm/reverse_cpuid.h
@@ -70,8 +70,9 @@
#define KVM_X86_FEATURE_CONSTANT_TSC KVM_X86_FEATURE(CPUID_8000_0007_EDX, 8)
/* CPUID level 0x80000022 (EAX) */
-#define KVM_X86_FEATURE_PERFMON_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 0)
-#define KVM_X86_FEATURE_AMD_LBR_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 1)
+#define KVM_X86_FEATURE_PERFMON_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 0)
+#define KVM_X86_FEATURE_AMD_LBR_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 1)
+#define KVM_X86_FEATURE_AMD_LBR_PMC_FREEZE KVM_X86_FEATURE(CPUID_8000_0022_EAX, 2)
/* CPUID level 0x80000021 (ECX) */
#define KVM_X86_FEATURE_TSA_SQ_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 1)
@@ -148,6 +149,7 @@ static __always_inline u32 __feature_translate(int x86_feature)
KVM_X86_TRANSLATE_FEATURE(CONSTANT_TSC);
KVM_X86_TRANSLATE_FEATURE(PERFMON_V2);
KVM_X86_TRANSLATE_FEATURE(AMD_LBR_V2);
+ KVM_X86_TRANSLATE_FEATURE(AMD_LBR_PMC_FREEZE);
KVM_X86_TRANSLATE_FEATURE(RRSBA_CTRL);
KVM_X86_TRANSLATE_FEATURE(BHI_CTRL);
KVM_X86_TRANSLATE_FEATURE(TSA_SQ_NO);
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 4b84498e93be..3ec91c1c58dc 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3236,6 +3236,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
data &= ~DEBUGCTLMSR_BTF;
}
+ if ((data & DEBUGCTL_LBR_PMC_FREEZE_BITS) &&
+ !guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_LBR_PMC_FREEZE))
+ return 1;
+
if (data & DEBUGCTL_RESERVED_BITS)
return 1;
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 01dae3828a7a..105a71d69d68 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -784,7 +784,9 @@ BUILD_SVM_MSR_BITMAP_HELPERS(bool, test, test)
BUILD_SVM_MSR_BITMAP_HELPERS(void, clear, __clear)
BUILD_SVM_MSR_BITMAP_HELPERS(void, set, __set)
-#define DEBUGCTL_RESERVED_BITS (~DEBUGCTLMSR_LBR)
+#define DEBUGCTL_LBR_PMC_FREEZE_BITS (DEBUGCTLMSR_FREEZE_LBRS_ON_PMI | \
+ DEBUGCTLMSR_FREEZE_PERFMON_ON_PMI)
+#define DEBUGCTL_RESERVED_BITS (~(DEBUGCTLMSR_LBR | DEBUGCTL_LBR_PMC_FREEZE_BITS))
#define DBG_EXTN_CFG_RESERVED_BITS (~DBG_EXTN_CFG_LBRV2EN)
#define LBR_SELECT_RESERVED_BITS (~GENMASK_ULL(8, 0))
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 7/7] KVM: x86: Use SCATTERED_F() for PERFMON_V2
2026-07-24 19:50 [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2 Shivansh Dhiman
` (5 preceding siblings ...)
2026-07-24 19:50 ` [PATCH 6/7] KVM: SVM: Add LBR/PMC freeze support Shivansh Dhiman
@ 2026-07-24 19:50 ` Shivansh Dhiman
6 siblings, 0 replies; 13+ messages in thread
From: Shivansh Dhiman @ 2026-07-24 19:50 UTC (permalink / raw)
To: seanjc, pbonzini, tglx, mingo
Cc: kvm, x86, yosry, jmattson, thomas.lendacky, nikunj.dadhania,
sandipan.das, santosh.shukla, shivansh.dhiman
PERFMON_V2 is a scattered feature, so enumerate it with SCATTERED_F()
instead of F(). No functional change intended.
Signed-off-by: Shivansh Dhiman <shivansh.dhiman@amd.com>
---
arch/x86/kvm/cpuid.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 03501b3145eb..51b691f91442 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -1266,7 +1266,7 @@ void kvm_initialize_cpu_caps(void)
);
kvm_cpu_cap_init(CPUID_8000_0022_EAX,
- F(PERFMON_V2),
+ SCATTERED_F(PERFMON_V2),
SCATTERED_F(AMD_LBR_V2),
SCATTERED_F(AMD_LBR_PMC_FREEZE),
);
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 5/7] KVM: SVM: Advertise LbrExtV2 to userspace
2026-07-24 19:50 ` [PATCH 5/7] KVM: SVM: Advertise LbrExtV2 to userspace Shivansh Dhiman
@ 2026-07-24 20:06 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-24 20:06 UTC (permalink / raw)
To: Shivansh Dhiman; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] KVM fails to gate the advertisement of AMD_LBR_V2 on a 16-entry host stack, violating the KVM CPUID API contract and causing a guest #GP upon PMU usage.
--
--- Patch [5]: [PATCH 5/7] KVM: SVM: Advertise LbrExtV2 to userspace ---
commit 9dead9faa6c004cfaa9aa0580ca255569674a36b
Author: Shivansh Dhiman <shivansh.dhiman@amd.com>
KVM: SVM: Advertise LbrExtV2 to userspace
This commit advertises AMD LBR v2 to userspace and reports the LBR stack
depth in CPUID. It aims to gate this advertisement on LBR virtualization,
the mediated PMU, PerfMonV2, and a 16-entry host stack.
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 2698fa42cd971..d450a5b2499d9 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
[ ... ]
> @@ -1883,6 +1884,11 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
> cpuid_entry_override(entry, CPUID_8000_0022_EAX);
>
> ebx.split.num_core_pmc = kvm_pmu_cap.num_counters_gp;
> +
> + if (kvm_cpu_cap_has(X86_FEATURE_AMD_LBR_V2))
> + ebx.split.lbr_v2_stack_sz =
> + min(kvm_pmu_cap.num_branches_lbr, SVM_LBR_V2_STACK_SIZE);
> +
[Severity: Medium]
If the host has kvm_pmu_cap.num_branches_lbr < 16, will this advertise an
unsupported stack size to userspace?
The commit message indicates the advertisement should be gated on a 16-entry
host stack, but it appears the host stack size is not checked before
X86_FEATURE_AMD_LBR_V2 is set.
> entry->ebx = ebx.full;
> break;
> }
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 04e386b838d38..4b84498e93be7 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
[ ... ]
> @@ -4846,6 +4860,10 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
> if (guest_cpuid_is_intel_compatible(vcpu))
> guest_cpu_cap_clear(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);
>
> + if (guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_LBR_V2) &&
> + cpuid_query_lbrv2_stack_size(vcpu) != SVM_LBR_V2_STACK_SIZE)
> + guest_cpu_cap_clear(vcpu, X86_FEATURE_AMD_LBR_V2);
> +
[Severity: Medium]
If userspace configures the vCPU with the advertised CPUID (where stack size
is less than 16), will this silently drop the feature internally?
If the internal capability is cleared but the guest-visible CPUID remains set,
would the guest receive a fatal #GP when attempting to access the LBR MSRs
that it thinks are supported?
> if (is_sev_guest(vcpu))
> sev_vcpu_after_set_cpuid(svm);
> }
> @@ -5692,6 +5710,10 @@ static __init void svm_set_cpu_caps(void)
> if (kvm_pmu_cap.version != 2 ||
> !kvm_cpu_cap_has(X86_FEATURE_PERFCTR_CORE))
> kvm_cpu_cap_clear(X86_FEATURE_PERFMON_V2);
> +
> + if (!lbrv || !enable_mediated_pmu ||
> + !kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2))
> + kvm_cpu_cap_clear(X86_FEATURE_AMD_LBR_V2);
[Severity: Medium]
Should there be an additional check here for the host stack size?
If kvm_pmu_cap.num_branches_lbr != SVM_LBR_V2_STACK_SIZE, it seems
X86_FEATURE_AMD_LBR_V2 is not cleared. This appears to lead to the issues
mentioned above where KVM advertises a configuration it cannot faithfully
virtualize.
> }
>
> /* CPUID 0x8000001F (SME/SEV features) */
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724195040.630468-1-shivansh.dhiman@amd.com?part=5
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/7] KVM: SVM: Add VMCB fields for LBR v2 virtualization
2026-07-24 19:50 ` [PATCH 1/7] KVM: SVM: Add VMCB fields for LBR v2 virtualization Shivansh Dhiman
@ 2026-07-24 20:08 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-24 20:08 UTC (permalink / raw)
To: Shivansh Dhiman; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The `svm_get_nested_state` function writes out-of-bounds to userspace memory if `user_data_size` is exactly `sizeof(struct kvm_nested_state)`.
--
--- Patch [1]: [PATCH 1/7] KVM: SVM: Add VMCB fields for LBR v2 virtualization ---
commit 91df21ca3dd4f3f8277b9ddd8eb84059e0bca6d1
Author: Sandipan Das <sandipan.das@amd.com>
KVM: SVM: Add VMCB fields for LBR v2 virtualization
Define the new VMCB fields that will be used to save and restore the
state of the Last Branch Record Extension Version 2 (LbrExtV2) related
MSRs.
> diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
> index aa63431ba92c3..fbcf6c4dbb92a 100644
> --- a/arch/x86/include/asm/svm.h
> +++ b/arch/x86/include/asm/svm.h
> @@ -552,7 +559,7 @@ struct vmcb {
> };
> } __packed;
>
> -#define EXPECTED_VMCB_SAVE_AREA_SIZE 744
> +#define EXPECTED_VMCB_SAVE_AREA_SIZE 1912
> #define EXPECTED_GHCB_SAVE_AREA_SIZE 1032
> #define EXPECTED_SEV_ES_SAVE_AREA_SIZE 1648
[ ... ]
[Severity: High]
This is a pre-existing issue, but can svm_get_nested_state() write
out-of-bounds to userspace memory if user_data_size is exactly
sizeof(struct kvm_nested_state)?
When user_data_size == kvm_state.size, this initial check evaluates to false:
arch/x86/kvm/svm/nested.c:svm_get_nested_state() {
...
if (user_data_size < kvm_state.size)
goto out;
...
}
The function then proceeds, expanding kvm_state.size, but never re-checks if
the user-provided buffer is large enough before clearing the memory:
arch/x86/kvm/svm/nested.c:svm_get_nested_state() {
...
if (clear_user(user_vmcb, KVM_STATE_NESTED_SVM_VMCB_SIZE))
return -EFAULT;
...
}
Can this corrupt the VMM's memory by writing 4096 bytes past the end of the
user's 120-byte allocation if a VMM dynamically probes the required size?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724195040.630468-1-shivansh.dhiman@amd.com?part=1
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/7] KVM: SVM: Emulate guest accesses to LBR v2 MSRs
2026-07-24 19:50 ` [PATCH 3/7] KVM: SVM: Emulate guest accesses to LBR v2 MSRs Shivansh Dhiman
@ 2026-07-24 20:13 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-24 20:13 UTC (permalink / raw)
To: Shivansh Dhiman; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] LBRv2 emulation ignores the `lbrv` module parameter, allowing guest LBRv2 usage even when LBR Virtualization is globally disabled.
- [High] The newly added LBR v2 MSRs are missing from KVM's list of saveable MSRs, causing them to be silently dropped during live migration.
- [High] Missing nested SVM state synchronization for LBRv2 fields causes state corruption and cross-tenant information leaks between L2 guests.
--
--- Patch [3]: [PATCH 3/7] KVM: SVM: Emulate guest accesses to LBR v2 MSRs ---
commit ea17366da9bcd5ccfa5c4c9307a6f68cda7d1255
Author: Shivansh Dhiman <shivansh.dhiman@amd.com>
KVM: SVM: Emulate guest accesses to LBR v2 MSRs
Back the LBR v2 MSRs with their VMCB save-area fields in
svm_{get,set}_msr(). This is required when guest accesses to these
MSRs are intercepted. This allows the guest to retain the values
of these MSRs on VMRUN/#VMEXIT cycle when vLBR is disabled.
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index ef69a51ab27f9..13ac62604ca05 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
[ ... ]
> @@ -744,6 +744,12 @@ static void svm_recalc_lbr_msr_intercepts(struct kvm_vcpu *vcpu)
> svm->lbr_msrs_intercepted = intercept;
> }
>
> +static bool svm_lbrv2_supported(struct kvm_vcpu *vcpu)
> +{
> + return guest_cpu_cap_has(vcpu, X86_FEATURE_AMD_LBR_V2) &&
> + kvm_vcpu_has_mediated_pmu(vcpu);
> +}
[Severity: High]
Does this capability check need to respect the global lbrv module parameter?
Unlike the legacy LBR logic which explicitly checks lbrv, this function only
checks the X86_FEATURE_AMD_LBR_V2 capability.
Could this allow a local guest to bypass the host administrator's explicit
disablement of LBR Virtualization (when loaded with lbrv=0) by directly
accessing LBRv2 MSRs?
[ ... ]
> @@ -2882,6 +2901,21 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> case MSR_IA32_LASTINTTOIP:
> msr_info->data = lbrv ? *svm_vmcb_lbr(svm, msr_info->index) : 0;
> break;
> + case MSR_AMD_DBG_EXTN_CFG:
> + if (!svm_lbrv2_supported(vcpu))
> + return KVM_MSR_RET_UNSUPPORTED;
> + msr_info->data = svm->vmcb->save.dbg_extn_cfg;
> + break;
[Severity: High]
Are these new LBR v2 MSRs missing from KVM's list of saveable MSRs?
Because the new LBRv2 MSRs (MSR_AMD_DBG_EXTN_CFG, MSR_AMD64_LBR_SELECT, and
the MSR_AMD_SAMP_BR_FROM array) are omitted from msrs_to_save_base in
arch/x86/kvm/msrs.c, they won't be returned to the VMM by
KVM_GET_MSR_INDEX_LIST.
Will this cause the LBRv2 state to be silently dropped during live migration?
[ ... ]
> @@ -3181,6 +3215,40 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
> *svm_vmcb_lbr(svm, ecx) = data;
> vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
> break;
> + case MSR_AMD_DBG_EXTN_CFG:
> + if (!svm_lbrv2_supported(vcpu))
> + return KVM_MSR_RET_UNSUPPORTED;
> +
> + if (data & DBG_EXTN_CFG_RESERVED_BITS)
> + return 1;
> +
> + if (svm->vmcb->save.dbg_extn_cfg == data)
> + break;
> +
> + svm->vmcb->save.dbg_extn_cfg = data;
> + vmcb_mark_dirty(svm->vmcb, VMCB_LBR);
> + svm_update_lbrv(vcpu);
> + break;
[Severity: High]
Does nested SVM state synchronization need to be updated for these new LBRv2
fields?
Looking at nested virtualization, L2 guest state is synchronized using
svm_copy_lbrs() in arch/x86/kvm/svm/svm.h, which is called during
nested_vmcb02_prepare_save().
Because svm_copy_lbrs() was not updated to copy the new dbg_extn_cfg,
lbr_select, and lbr array fields, vmcb02 can retain a previous L2 guest's
branch records. When a new L2 guest reads its MSRs, it could observe the prior
L2 guest's execution trace.
Additionally, upon nested_svm_vmexit(), wouldn't L2 modifications be dropped
because they aren't copied back to L1's vmcb12?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724195040.630468-1-shivansh.dhiman@amd.com?part=3
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 6/7] KVM: SVM: Add LBR/PMC freeze support
2026-07-24 19:50 ` [PATCH 6/7] KVM: SVM: Add LBR/PMC freeze support Shivansh Dhiman
@ 2026-07-24 20:13 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-24 20:13 UTC (permalink / raw)
To: Shivansh Dhiman; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] KVM incorrectly advertises AMD_LBR_PMC_FREEZE to the guest even when prerequisite features (mediated PMU or LBR virtualization) are disabled, leading to broken PMU state.
- [High] An L1 hypervisor can bypass CPUID capability checks and enable LBR/PMC freeze bits for L2 by injecting them via VMCB12's DEBUGCTL.
--
--- Patch [6]: [PATCH 6/7] KVM: SVM: Add LBR/PMC freeze support ---
commit 8a4ef61c23eb3f96d674c17183bad9ad198a18dd
Author: Shivansh Dhiman <shivansh.dhiman@amd.com>
KVM: SVM: Add LBR/PMC freeze support
This commit adds support for the LBR and PMC freeze-on-PMI feature.
It updates CPUID initialization and allows the guest to set the
corresponding bits in DEBUGCTL if the feature is advertised.
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index d450a5b2499d9..03501b3145eb0 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -1268,6 +1268,7 @@ void kvm_initialize_cpu_caps(void)
> kvm_cpu_cap_init(CPUID_8000_0022_EAX,
> F(PERFMON_V2),
> SCATTERED_F(AMD_LBR_V2),
> + SCATTERED_F(AMD_LBR_PMC_FREEZE),
> );
[Severity: High]
Will this feature remain advertised to the guest even when prerequisite
features like mediated PMU or LBR virtualization are disabled?
Looking at svm_hardware_setup() in arch/x86/kvm/svm/svm.c,
X86_FEATURE_AMD_LBR_V2 is dynamically cleared when prerequisites are missing:
if (!lbrv || !enable_mediated_pmu ||
!kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2))
kvm_cpu_cap_clear(X86_FEATURE_AMD_LBR_V2);
If X86_FEATURE_AMD_LBR_PMC_FREEZE is not cleared similarly, a guest might
see the feature in CPUID and attempt to use it. If the host administrator
configured KVM with lbrv=0, svm_set_msr() silently ignores writes to
MSR_IA32_DEBUGCTLMSR without injecting a #GP, which could break guest PMU
functionality.
[ ... ]
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 01dae3828a7aa..105a71d69d68a 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -784,7 +784,9 @@ BUILD_SVM_MSR_BITMAP_HELPERS(bool, test, test)
> BUILD_SVM_MSR_BITMAP_HELPERS(void, clear, __clear)
> BUILD_SVM_MSR_BITMAP_HELPERS(void, set, __set)
>
> -#define DEBUGCTL_RESERVED_BITS (~DEBUGCTLMSR_LBR)
> +#define DEBUGCTL_LBR_PMC_FREEZE_BITS (DEBUGCTLMSR_FREEZE_LBRS_ON_PMI | \
> + DEBUGCTLMSR_FREEZE_PERFMON_ON_PMI)
> +#define DEBUGCTL_RESERVED_BITS (~(DEBUGCTLMSR_LBR | DEBUGCTL_LBR_PMC_FREEZE_BITS))
[Severity: High]
Does modifying this macro globally allow an L1 hypervisor to bypass CPUID
capability checks for its L2 guest?
In arch/x86/kvm/svm/nested.c:nested_vmcb02_prepare_save(), VMCB12's dbgctl
is masked directly against DEBUGCTL_RESERVED_BITS:
vmcb02->save.dbgctl &= ~DEBUGCTL_RESERVED_BITS;
By unreserving the freeze bits globally here, an unprivileged L1 hypervisor
with LBRV enabled could write DEBUGCTL_LBR_PMC_FREEZE_BITS into its
vmcb12->save.dbgctl. Since KVM copies this to L2's VMCB without checking if
L1 actually possesses the X86_FEATURE_AMD_LBR_PMC_FREEZE capability, this
appears to allow a nested capability bypass.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724195040.630468-1-shivansh.dhiman@amd.com?part=6
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 4/7] KVM: SVM: Enable hardware-assisted LBR v2 virtualization
2026-07-24 19:50 ` [PATCH 4/7] KVM: SVM: Enable hardware-assisted LBR v2 virtualization Shivansh Dhiman
@ 2026-07-24 20:17 ` sashiko-bot
0 siblings, 0 replies; 13+ messages in thread
From: sashiko-bot @ 2026-07-24 20:17 UTC (permalink / raw)
To: Shivansh Dhiman; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] LBRv2 MSRs and MSR_AMD_DBG_EXTN_CFG are incorrectly intercepted for SEV-ES guests, causing a fatal hardware VMRUN error and exposing a KVM_BUG_ON to host userspace.
- [High] Nested SVM breaks LBRv2 virtualization due to missing state copying in `svm_copy_lbrs` and missing MSRPM pass-through in KVM's merge array.
- [High] The patch fails to enumerate AMD LBRv2 in KVM's supported CPUID capabilities, rendering the feature undiscoverable.
- [High] The new LBRv2 MSRs are not added to KVM's MSR save/restore lists, breaking live migration.
- [High] LBRv2 virtualization bypasses the global `lbrv` module parameter, allowing guests to enable hardware LBR virtualization even when administrators have explicitly disabled it.
--
--- Patch [4]: [PATCH 4/7] KVM: SVM: Enable hardware-assisted LBR v2 virtualization ---
commit ee1a6e59c9c7f66112084e471f36296d11c1b93d
Author: Shivansh Dhiman <shivansh.dhiman@amd.com>
Subject: KVM: SVM: Enable hardware-assisted LBR v2 virtualization
This patch enables hardware-assisted LBR v2 virtualization in KVM for AMD SVM.
It enables V_LBR to save and restore the guest's LBR v2 state in the VMCB,
and lazily disables interception of the LBR v2 MSRs when the guest enables
branch recording.
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 13ac62604ca05..04e386b838d38 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -750,6 +750,41 @@ static bool svm_lbrv2_supported(struct kvm_vcpu *vcpu)
> kvm_vcpu_has_mediated_pmu(vcpu);
> }
[Severity: High]
Is the F(AMD_LBR_V2) capability missing from kvm_cpu_cap_init()?
It appears F(AMD_LBR_V2) is missing from the initializers in
kvm_cpu_cap_init(CPUID_8000_0022_EAX) in arch/x86/kvm/cpuid.c. Since KVM
explicitly masks the host CPUID against registered capabilities, KVM will not
report AMD_LBR_V2 as supported, making the feature undiscoverable by standard
userspace VMMs.
>
> +static bool svm_lbrv2_active(struct kvm_vcpu *vcpu)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> + return svm_lbrv2_supported(vcpu) &&
> + (svm->vmcb->save.dbg_extn_cfg & DBG_EXTN_CFG_LBRV2EN);
> +}
> +
> +static void svm_recalc_lbrv2_msr_intercepts(struct kvm_vcpu *vcpu)
> +{
> + struct vcpu_svm *svm = to_svm(vcpu);
> + bool intercept = !svm_lbrv2_active(vcpu);
> + int i;
> +
> + if (intercept == svm->lbrv2_msrs_intercepted)
> + return;
> +
> + for (i = 0; i < 32; i++)
> + svm_set_intercept_for_msr(vcpu, MSR_AMD_SAMP_BR_FROM + i, MSR_TYPE_RW, intercept);
> +
> + svm_set_intercept_for_msr(vcpu, MSR_AMD64_LBR_SELECT, MSR_TYPE_RW, intercept);
> +
> + /*
> + * DBG_EXTN_CFG stays permanently intercepted for non-SEV-ES guests so
> + * KVM can observe LBRV2EN and lazily toggle V_LBR. SEV-ES+ guests must
> + * delegate LBR virtualization to the processor (per the APM), where
> + * intercepting LBR MSRs can be fatal, so toggle it with the rest. See
> + * commit b7e4be0a224f ("KVM: SEV-ES: Delegate LBR virtualization to the
> + * processor").
> + */
> + if (is_sev_es_guest(vcpu))
> + svm_set_intercept_for_msr(vcpu, MSR_AMD_DBG_EXTN_CFG, MSR_TYPE_RW, intercept);
> +
> + svm->lbrv2_msrs_intercepted = intercept;
> +}
[Severity: High]
Can this logic incorrectly force the interception of MSR_AMD_DBG_EXTN_CFG and
LBRv2 MSRs for SEV-ES guests?
For SEV-ES guests, KVM's shadow copy of dbg_extn_cfg is always 0. Consequently,
svm_lbrv2_active() evaluates to false, causing svm_recalc_lbrv2_msr_intercepts()
to set intercept = true.
As documented in commit b7e4be0a224f, intercepting LBR MSRs when V_LBR is
enabled triggers a fatal hardware VMRUN consistency check failure.
Additionally, because MSR_AMD_DBG_EXTN_CFG is intercepted, host userspace can
write to it. Writing a value with LBRv2 disabled invokes svm_update_lbrv(),
which then attempts to disable LBRV and hits a KVM_BUG_ON(is_sev_es_guest(vcpu))
in __svm_disable_lbrv().
[ ... ]
> @@ -886,9 +924,11 @@ void svm_update_lbrv(struct kvm_vcpu *vcpu)
> {
> struct vcpu_svm *svm = to_svm(vcpu);
> bool current_enable_lbrv = svm->vmcb->control.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR;
> +
> bool enable_lbrv = (svm->vmcb->save.dbgctl & DEBUGCTLMSR_LBR) ||
> (is_guest_mode(vcpu) && guest_cpu_cap_has(vcpu, X86_FEATURE_LBRV) &&
> - (svm->nested.ctl.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR));
> + (svm->nested.ctl.misc_ctl2 & SVM_MISC2_ENABLE_V_LBR)) ||
> + svm_lbrv2_active(vcpu);
>
> if (enable_lbrv && !current_enable_lbrv)
> __svm_enable_lbrv(vcpu);
[Severity: High]
Are we bypassing the global lbrv module parameter restriction here?
Legacy LBR virtualization correctly gates enablement behind the global lbrv
parameter.
Because svm_lbrv2_active() checks only the guest state, if a guest sets
LBRV2EN, enable_lbrv evaluates to true. This unconditionally enables hardware
LBR virtualization via __svm_enable_lbrv(), even when administrators have
explicitly disabled it with the lbrv parameter.
[ ... ]
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index f62bf19024cc0..01dae3828a7aa 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -363,6 +363,7 @@ struct vcpu_svm {
> bool avic_irq_window;
> bool x2avic_msrs_intercepted;
> bool lbr_msrs_intercepted;
> + bool lbrv2_msrs_intercepted;
>
> /* Guest GIF value, used when vGIF is not enabled */
> bool guest_gif;
[Severity: High]
Will the omission of the new LBRv2 fields from svm_copy_lbrs() and merge_msrs
break nested SVM?
For nested SVM, svm_copy_lbrs() in arch/x86/kvm/svm/svm.h copies legacy LBR
state but omits the new LBRv2 fields, leading to state loss across nested
transitions.
Furthermore, the new LBRv2 MSRs are absent from the merge_msrs array in
arch/x86/kvm/svm/nested.c, which defeats hardware acceleration by breaking
MSRPM pass-through for L2.
[Severity: High]
Are there missing entries in the MSR save/restore lists required for live
migration?
The new LBRv2 MSRs are missing from msrs_to_save_base or msrs_to_save_pmu
in arch/x86/kvm/msrs.c. Without these entries, they will not be included in
KVM_GET_MSR_INDEX_LIST, which leads to silent data loss of hardware state
across live migrations.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260724195040.630468-1-shivansh.dhiman@amd.com?part=4
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-07-24 20:17 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24 19:50 [PATCH 0/7] KVM: SVM: Add support for AMD LBR Extension v2 Shivansh Dhiman
2026-07-24 19:50 ` [PATCH 1/7] KVM: SVM: Add VMCB fields for LBR v2 virtualization Shivansh Dhiman
2026-07-24 20:08 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 2/7] KVM: SVM: Add capability for LbrExtV2 Shivansh Dhiman
2026-07-24 19:50 ` [PATCH 3/7] KVM: SVM: Emulate guest accesses to LBR v2 MSRs Shivansh Dhiman
2026-07-24 20:13 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 4/7] KVM: SVM: Enable hardware-assisted LBR v2 virtualization Shivansh Dhiman
2026-07-24 20:17 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 5/7] KVM: SVM: Advertise LbrExtV2 to userspace Shivansh Dhiman
2026-07-24 20:06 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 6/7] KVM: SVM: Add LBR/PMC freeze support Shivansh Dhiman
2026-07-24 20:13 ` sashiko-bot
2026-07-24 19:50 ` [PATCH 7/7] KVM: x86: Use SCATTERED_F() for PERFMON_V2 Shivansh Dhiman
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.