diff mbox series

[kvm-unit-tests,2/2] x86/debug: Add a split-lock #AC / bus-lock #DB testcase

Message ID 20250221204148.2171418-3-seanjc@google.com (mailing list archive)
State New
Headers show
Series x86: Add split/bus lock smoke test | expand

Commit Message

Sean Christopherson Feb. 21, 2025, 8:41 p.m. UTC
Add a testcase to the debug test to verify that a split-lock in the guest
does NOT result in an #AC or #DB (and that the test isn't killed).  While
KVM may run the guest with split-lock #AC enabled, KVM should never inject
an #AC into the guest.  And Bus Lock Detect/Trap should flat out never be
enabled while KVM is running the guest.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=219787
Link: https://lore.kernel.org/all/bug-219787-28872@https.bugzilla.kernel.org%2F
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 x86/debug.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)
diff mbox series

Patch

diff --git a/x86/debug.c b/x86/debug.c
index f493567c..09f06ef5 100644
--- a/x86/debug.c
+++ b/x86/debug.c
@@ -10,6 +10,7 @@ 
  */
 #include <asm/debugreg.h>
 
+#include "atomic.h"
 #include "libcflat.h"
 #include "processor.h"
 #include "desc.h"
@@ -81,6 +82,12 @@  static void handle_ud(struct ex_regs *regs)
 	got_ud = 1;
 }
 
+static bool got_ac;
+static void handle_ac(struct ex_regs *regs)
+{
+	got_ac = true;
+}
+
 typedef unsigned long (*db_test_fn)(void);
 typedef void (*db_report_fn)(unsigned long, const char *);
 
@@ -409,6 +416,41 @@  static noinline unsigned long singlestep_with_sti_hlt(void)
 	return start_rip;
 }
 
+static noinline uint64_t bus_lock(uint64_t magic)
+{
+	uint8_t buffer[128] __attribute__((aligned(64))) = { };
+	atomic64_t *val = (atomic64_t *)&buffer[60];
+
+	atomic64_cmpxchg(val, 0, magic);
+	return READ_ONCE(*(uint64_t *)val);
+}
+
+static void bus_lock_test(void)
+{
+	const uint64_t magic = 0xdeadbeefdeadbeefull;
+	bool bus_lock_db = false;
+	uint64_t val;
+
+	/*
+	 * Generate a bus lock (via a locked access that splits cache lines)
+	 * in CPL0 and again in CPL3 (Bus Lock Detect only affects CPL3), and
+	 * verify that no #AC or #DB is generated (the relevant features are
+	 * not enabled).
+	 */
+	val = bus_lock(magic);
+	report(!got_ac && !n && val == magic,
+	       "CPL0 Split Lock #AC = %u (#DB = %u), val = %lx (wanted %lx)",
+	       got_ac, n, val, magic);
+
+	val = run_in_user((usermode_func)bus_lock, DB_VECTOR, magic, 0, 0, 0, &bus_lock_db);
+	report(!bus_lock_db && val == magic,
+	       "CPL3 Bus Lock #DB = %u, val = %lx (wanted %lx)",
+	       bus_lock_db, val, magic);
+
+	n = 0;
+	got_ac = false;
+}
+
 int main(int ac, char **av)
 {
 	unsigned long cr4;
@@ -416,6 +458,9 @@  int main(int ac, char **av)
 	handle_exception(DB_VECTOR, handle_db);
 	handle_exception(BP_VECTOR, handle_bp);
 	handle_exception(UD_VECTOR, handle_ud);
+	handle_exception(AC_VECTOR, handle_ac);
+
+	bus_lock_test();
 
 	/*
 	 * DR4 is an alias for DR6 (and DR5 aliases DR7) if CR4.DE is NOT set,