All of lore.kernel.org
 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 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.