[RFC PATCH v1] x86/split_lock: Provide KVM helper to log guest bus lock exits

Manali Shukla
2026-03-24T12:40:21Z

Bus locks monopolize the memory bus for thousands of cycles, stalling
all CPUs and degrading system performance for every workload on the
system. Cloud providers running multiple VMs need a way to identify
which guest is responsible, so the offending VM can be flagged.

Bus lock VMEXITs on AMD are fault-style, i.e. the vCPU's RIP points to
the offending instruction at the time of the exit. Log guest's linear
RIP and vCPU info to give operators the data needed to attribute the bus
lock to a specific VM and instruction. Keep policy enforcement to
userspace via KVM_EXIT_X86_BUS_LOCK and let userspace implement
throttling or other mitigations.

Reuse current->reported_split_lock to limit the warning to the once per
vCPU thread. Note that, current->reported_split_lock tracks the vCPU
thread, not the individual guest process, i.e. the warning fires once
per vCPU for the lifetime of thread regardless of how many distinct
guest processes trigger bus locks on that vCPU.

----
The intent is purely observational — give hypervisor owners
visibility into which guest is generating bus locks so they can act
accordingly. No policy enforcement is done in the kernel. Suggestions
on the approach are welcome.

Suggested-by: Nikunj A Dadhania <nikunj@amd.com>
Signed-off-by: Manali Shukla <manali.shukla@amd.com>
---
arch/x86/include/asm/cpu.h | 2 ++
arch/x86/kernel/cpu/bus_lock.c | 19 +++++++++++++++++++
arch/x86/kvm/svm/svm.c | 1 +
3 files changed, 22 insertions(+)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index ad235dda1ded..4ac5011e10b2 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -29,6 +29,7 @@ unsigned int x86_stepping(unsigned int sig);
extern void __init sld_setup(struct cpuinfo_x86 *c);
extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
extern bool handle_guest_split_lock(unsigned long ip);
+extern void handle_guest_bus_lock(unsigned long ip);
extern void handle_bus_lock(struct pt_regs *regs);
void split_lock_init(void);
void bus_lock_init(void);
@@ -44,6 +45,7 @@ static inline bool handle_guest_split_lock(unsigned long ip)
return false;
}

+static inline void handle_guest_bus_lock(unsigned long ip) {}
static inline void handle_bus_lock(struct pt_regs *regs) {}
static inline void split_lock_init(void) {}
static inline void bus_lock_init(void) {}
diff --git a/arch/x86/kernel/cpu/bus_lock.c b/arch/x86/kernel/cpu/bus_lock.c
index fb166662bc0d..a6d231410535 100644
--- a/arch/x86/kernel/cpu/bus_lock.c
+++ b/arch/x86/kernel/cpu/bus_lock.c
@@ -292,6 +292,25 @@ bool handle_guest_split_lock(unsigned long ip)
}
EXPORT_SYMBOL_FOR_KVM(handle_guest_split_lock);

+void handle_guest_bus_lock(unsigned long ip)
+{
+ /*
+ * Log bus lock exit when called from KVM exit handlers. Policy
+ * enforcement is delegated to userspace via KVM_EXIT_X86_BUS_LOCK.
+ * Let userspace implement throttling or other mitigations.
+ *
+ * Only log when split lock detection is active to respect system-wide
+ * bus lock detection policy. Use the reported_split_lock flag to
+ * prevent log spam from the same vCPU.
+ */
+ if (sld_state != sld_off && !current->reported_split_lock) {
+ pr_warn_ratelimited("%s/%d buslock at rip: 0x%lx\n",
+ current->comm, current->pid, ip);
+ current->reported_split_lock = 1;
+ }
+}
+EXPORT_SYMBOL_FOR_KVM(handle_guest_bus_lock);
+
void bus_lock_init(void)
{
u64 val;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index d98fbc0e58e8..bb8efd877876 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3258,6 +3258,7 @@ static int bus_lock_exit(struct kvm_vcpu *vcpu)
vcpu->arch.cui_linear_rip = kvm_get_linear_rip(vcpu);
vcpu->arch.complete_userspace_io = complete_userspace_buslock;

+ handle_guest_bus_lock(vcpu->arch.cui_linear_rip);
if (is_guest_mode(vcpu))
svm->nested.last_bus_lock_rip = vcpu->arch.cui_linear_rip;

--
2.43.0