Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Sairaj Kodilkar <sarunkod@amd.com>
To: <kvm@vger.kernel.org>
Cc: <pbonzini@redhat.com>, <vasant.hegde@amd.com>,
	<suravee.suthikulpanit@amd.com>,
	Sairaj Kodilkar <sarunkod@amd.com>
Subject: [kvm-unit-tests PATCH] x86/emulator64: Add CMPXCHG8B/CMPXCHG16B emulation tests
Date: Mon, 6 Jul 2026 11:51:53 +0530	[thread overview]
Message-ID: <20260706062153.346-1-sarunkod@amd.com> (raw)

Test KVM instruction emulation for cmpxchg8b/16b (0x0FC7)
with and without the LOCK prefix, and with the KVM fast-emulate
prefix (FEP) when available.  Cover both the compare-succeed (ZF=1) and
compare-fail (ZF=0) outcomes.

Signed-off-by: Sairaj Kodilkar <sarunkod@amd.com>
---
This patch is intended to validate the cmpxchg16b kernel patch[1], which is
required to support the AMD hardware accelerated vIOMMU.

The cmpxchg16b tests hangs (with emulation error) on the kernel which does
not have patch[1]. I am not sure what is the right approach to resolve this
issue, any suggestions on how to resolve this are welcomed.

[1] https://lore.kernel.org/all/20260306102047.29760-1-sarunkod@amd.com/

Base: 1da1819e49fc4938985edca67df669099b4c87a7
---
 x86/emulator64.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)

diff --git a/x86/emulator64.c b/x86/emulator64.c
index c4df5178147c..3d92053a06d8 100644
--- a/x86/emulator64.c
+++ b/x86/emulator64.c
@@ -245,6 +245,164 @@ static void test_xchg(void *mem)
 	       "xchg reg, r/m (4)");
 }
 
+static void test_cmpxchg8b_success(void *mem)
+{
+	u64 *memq = mem;
+	u64 rax, rbx, rcx, rdx;
+	u32 eax, ebx, ecx, edx;
+	u8 zf;
+
+#define LOCK_PREFIX "lock;"
+#define EMPTY ""
+
+#define TEST_CMPXCHG8B(fep, lock, report_str) do { \
+	asm volatile("mov $0x0123456789abcdef, %%rax\n\t" \
+		     "mov %%rax, (%[memq])\n\t" \
+		     "mov $0x01234567, %%edx\n\t" \
+		     "mov $0x89abcdef, %%eax\n\t" \
+		     "mov $0xfedcba98, %%ecx\n\t" \
+		     "mov $0x76543210, %%ebx\n\t" \
+		     fep lock "cmpxchg8b (%[memq])\n\t" \
+		     "mov %%eax, %[eax]\n\t" \
+		     "mov %%ebx, %[ebx]\n\t" \
+		     "mov %%ecx, %[ecx]\n\t" \
+		     "mov %%edx, %[edx]\n\t" \
+		     "sete %[zf]\n\t" \
+		     : [zf]"=qm"(zf), [eax]"=r"(eax), [ebx]"=r"(ebx), \
+		       [ecx]"=r"(ecx), [edx]"=r"(edx) \
+		     : [memq]"r"(memq) \
+		     : "memory", "eax", "ebx", "ecx", "edx", "cc"); \
+	report(memq[0] == 0xfedcba9876543210 && zf \
+	       && edx == 0x01234567 && eax == 0x89abcdef \
+	       && ecx == 0xfedcba98 && ebx == 0x76543210, \
+	       "cmpxchg8b  mem == edx:eax (" report_str ")"); \
+} while (0)
+
+#define TEST_CMPXCHG16B(fep, lock, report_str) do { \
+	asm volatile("mov $0x0123456789abcdef, %%rax\n\t" \
+		     "mov %%rax, (%[memq])\n\t" \
+		     "mov $0xfedcba9876543210, %%rax\n\t" \
+		     "mov %%rax, 8(%[memq])\n\t" \
+		     "mov $0xfedcba9876543210, %%rdx\n\t" \
+		     "mov $0x0123456789abcdef, %%rax\n\t" \
+		     "mov $0x0123456789abcdef, %%rcx\n\t" \
+		     "mov $0xfedcba9876543210, %%rbx\n\t" \
+		     fep lock "cmpxchg16b (%[memq])\n\t" \
+		     "mov %%rax, %[rax]\n\t" \
+		     "mov %%rbx, %[rbx]\n\t" \
+		     "mov %%rcx, %[rcx]\n\t" \
+		     "mov %%rdx, %[rdx]\n\t" \
+		     "sete %[zf]\n\t" \
+		     : [zf]"=qm"(zf), [rax]"=r"(rax), [rbx]"=r"(rbx), \
+		       [rcx]"=r"(rcx), [rdx]"=r"(rdx) \
+		     : [memq]"r"(memq) \
+		     : "memory", "rax", "rbx", "rcx", "rdx", "cc"); \
+	report(memq[0] == 0xfedcba9876543210 && memq[1] == 0x0123456789abcdef && zf \
+	       && rdx == 0xfedcba9876543210 && rax == 0x0123456789abcdef \
+	       && rcx == 0x0123456789abcdef && rbx == 0xfedcba9876543210, \
+	       "cmpxchg16b mem == rdx:rax (" report_str ")");  \
+} while (0)
+
+	TEST_CMPXCHG8B(EMPTY, EMPTY, "nofep, nolock");
+	TEST_CMPXCHG16B(EMPTY, EMPTY, "nofep, nolock");
+	TEST_CMPXCHG8B(EMPTY, LOCK_PREFIX, "nofep, lock");
+	TEST_CMPXCHG16B(EMPTY, LOCK_PREFIX, "nofep, lock");
+
+	if (!is_fep_available)
+		return;
+
+	memq = vmap(virt_to_phys(alloc_page()), PAGE_SIZE);
+
+	TEST_CMPXCHG8B(KVM_FEP, EMPTY, "fep, nolock");
+	TEST_CMPXCHG16B(KVM_FEP, EMPTY, "fep, nolock");
+	TEST_CMPXCHG8B(KVM_FEP, LOCK_PREFIX, "fep, lock");
+	TEST_CMPXCHG16B(KVM_FEP, LOCK_PREFIX, "fep, lock");
+
+#undef TEST_CMPXCHG8B
+#undef TEST_CMPXCHG16B
+#undef LOCK_PREFIX
+#undef EMPTY
+}
+
+static void test_cmpxchg8b_fail(void *mem)
+{
+	u64 *memq = mem;
+	u64 rax, rbx, rcx, rdx;
+	u32 eax, ebx, ecx, edx;
+	u8 zf;
+
+#define LOCK_PREFIX "lock;"
+#define EMPTY ""
+
+#define TEST_CMPXCHG8B(fep, lock, report_str) do { \
+	asm volatile("mov $0x0123456789abcdef, %%rax\n\t" \
+		     "mov %%rax, (%[memq])\n\t" \
+		     "mov $0xfedcba98, %%edx\n\t" \
+		     "mov $0x76543210, %%eax\n\t" \
+		     "mov $0x01234567, %%ecx\n\t" \
+		     "mov $0x89abcdef, %%ebx\n\t" \
+		     fep lock "cmpxchg8b (%[memq])\n\t" \
+		     "mov %%eax, %[eax]\n\t" \
+		     "mov %%ebx, %[ebx]\n\t" \
+		     "mov %%ecx, %[ecx]\n\t" \
+		     "mov %%edx, %[edx]\n\t" \
+		     "sete %[zf]\n\t" \
+		     : [zf]"=qm"(zf), [eax]"=r"(eax), [ebx]"=r"(ebx), \
+		       [ecx]"=r"(ecx), [edx]"=r"(edx) \
+		     : [memq]"r"(memq) \
+		     : "memory", "eax", "ebx", "ecx", "edx", "cc"); \
+	report(memq[0] == 0x0123456789abcdef && !zf \
+	       && edx == 0x01234567 && eax == 0x89abcdef \
+	       && ecx == 0x01234567 && ebx == 0x89abcdef, \
+	       "cmpxchg8b  mem != edx:eax (" report_str ")"); \
+} while (0)
+
+#define TEST_CMPXCHG16B(fep, lock, report_str) do { \
+	asm volatile("mov $0x0123456789abcdef, %%rax\n\t" \
+		     "mov %%rax, (%[memq])\n\t" \
+		     "mov $0xfedcba9876543210, %%rax\n\t" \
+		     "mov %%rax, 8(%[memq])\n\t" \
+		     "mov $0x0123456789abcdef, %%rdx\n\t" \
+		     "mov $0xfedcba9876543210, %%rax\n\t" \
+		     "mov $0x0123456789abcdef, %%rcx\n\t" \
+		     "mov $0xfedcba9876543210, %%rbx\n\t" \
+		     fep lock "cmpxchg16b (%[memq])\n\t" \
+		     "mov %%rax, %[rax]\n\t" \
+		     "mov %%rbx, %[rbx]\n\t" \
+		     "mov %%rcx, %[rcx]\n\t" \
+		     "mov %%rdx, %[rdx]\n\t" \
+		     "sete %[zf]\n\t" \
+		     : [zf]"=qm"(zf), [rax]"=r"(rax), [rbx]"=r"(rbx), \
+		       [rcx]"=r"(rcx), [rdx]"=r"(rdx) \
+		     : [memq]"r"(memq) \
+		     : "memory", "rax", "rbx", "rcx", "rdx", "cc"); \
+	report(memq[0] == 0x0123456789abcdef && memq[1] == 0xfedcba9876543210 && !zf \
+	       && rdx == 0xfedcba9876543210 && rax == 0x123456789abcdef \
+	       && rcx == 0x0123456789abcdef && rbx == 0xfedcba9876543210, \
+	       "cmpxchg16b mem != rdx:rax (" report_str ")"); \
+} while (0)
+
+	TEST_CMPXCHG8B(EMPTY, EMPTY, "nofep, nolock");
+	TEST_CMPXCHG16B(EMPTY, EMPTY, "nofep, nolock");
+	TEST_CMPXCHG8B(EMPTY, LOCK_PREFIX, "nofep, lock");
+	TEST_CMPXCHG16B(EMPTY, LOCK_PREFIX, "nofep, lock");
+
+	if (!is_fep_available)
+		return;
+
+	memq = vmap(virt_to_phys(alloc_page()), PAGE_SIZE);
+
+	TEST_CMPXCHG8B(KVM_FEP, EMPTY, "fep, nolock");
+	TEST_CMPXCHG16B(KVM_FEP, EMPTY, "fep, nolock");
+	TEST_CMPXCHG8B(KVM_FEP, LOCK_PREFIX, "fep, lock");
+	TEST_CMPXCHG16B(KVM_FEP, LOCK_PREFIX, "fep, lock");
+
+#undef TEST_CMPXCHG8B
+#undef TEST_CMPXCHG16B
+#undef LOCK_PREFIX
+#undef EMPTY
+}
+
 static void test_xadd(void *mem)
 {
 	unsigned long *memq = mem;
@@ -542,6 +700,9 @@ static void test_emulator_64(void *mem)
 	test_pop(mem);
 
 	test_xchg(mem);
+	test_cmpxchg8b_success(mem);
+	test_cmpxchg8b_fail(mem);
+
 	test_xadd(mem);
 
 	test_cr8();
-- 
2.34.1


                 reply	other threads:[~2026-07-06  6:22 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20260706062153.346-1-sarunkod@amd.com \
    --to=sarunkod@amd.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=suravee.suthikulpanit@amd.com \
    --cc=vasant.hegde@amd.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