[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 09/30] x86emul: APX_F REX2 testing


  • To: "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Jan Beulich <jbeulich@xxxxxxxx>
  • Date: Wed, 11 Nov 2026 15:24:18 +0100
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=google header.d=suse.com header.i="@suse.com" header.h="Content-Transfer-Encoding:Content-Type:In-Reply-To:Autocrypt:Content-Language:References:Cc:To:From:Subject:User-Agent:MIME-Version:Date:Message-ID"
  • Autocrypt: addr=jbeulich@xxxxxxxx; keydata= xsDiBFk3nEQRBADAEaSw6zC/EJkiwGPXbWtPxl2xCdSoeepS07jW8UgcHNurfHvUzogEq5xk hu507c3BarVjyWCJOylMNR98Yd8VqD9UfmX0Hb8/BrA+Hl6/DB/eqGptrf4BSRwcZQM32aZK 7Pj2XbGWIUrZrd70x1eAP9QE3P79Y2oLrsCgbZJfEwCgvz9JjGmQqQkRiTVzlZVCJYcyGGsD /0tbFCzD2h20ahe8rC1gbb3K3qk+LpBtvjBu1RY9drYk0NymiGbJWZgab6t1jM7sk2vuf0Py O9Hf9XBmK0uE9IgMaiCpc32XV9oASz6UJebwkX+zF2jG5I1BfnO9g7KlotcA/v5ClMjgo6Gl MDY4HxoSRu3i1cqqSDtVlt+AOVBJBACrZcnHAUSuCXBPy0jOlBhxPqRWv6ND4c9PH1xjQ3NP nxJuMBS8rnNg22uyfAgmBKNLpLgAGVRMZGaGoJObGf72s6TeIqKJo/LtggAS9qAUiuKVnygo 3wjfkS9A3DRO+SpU7JqWdsveeIQyeyEJ/8PTowmSQLakF+3fote9ybzd880fSmFuIEJldWxp Y2ggPGpiZXVsaWNoQHN1c2UuY29tPsJgBBMRAgAgBQJZN5xEAhsDBgsJCAcDAgQVAggDBBYC AwECHgECF4AACgkQoDSui/t3IH4J+wCfQ5jHdEjCRHj23O/5ttg9r9OIruwAn3103WUITZee e7Sbg12UgcQ5lv7SzsFNBFk3nEQQCACCuTjCjFOUdi5Nm244F+78kLghRcin/awv+IrTcIWF hUpSs1Y91iQQ7KItirz5uwCPlwejSJDQJLIS+QtJHaXDXeV6NI0Uef1hP20+y8qydDiVkv6l IreXjTb7DvksRgJNvCkWtYnlS3mYvQ9NzS9PhyALWbXnH6sIJd2O9lKS1Mrfq+y0IXCP10eS FFGg+Av3IQeFatkJAyju0PPthyTqxSI4lZYuJVPknzgaeuJv/2NccrPvmeDg6Coe7ZIeQ8Yj t0ARxu2xytAkkLCel1Lz1WLmwLstV30g80nkgZf/wr+/BXJW/oIvRlonUkxv+IbBM3dX2OV8 AmRv1ySWPTP7AAMFB/9PQK/VtlNUJvg8GXj9ootzrteGfVZVVT4XBJkfwBcpC/XcPzldjv+3 HYudvpdNK3lLujXeA5fLOH+Z/G9WBc5pFVSMocI71I8bT8lIAzreg0WvkWg5V2WZsUMlnDL9 mpwIGFhlbM3gfDMs7MPMu8YQRFVdUvtSpaAs8OFfGQ0ia3LGZcjA6Ik2+xcqscEJzNH+qh8V m5jjp28yZgaqTaRbg3M/+MTbMpicpZuqF4rnB0AQD12/3BNWDR6bmh+EkYSMcEIpQmBM51qM EKYTQGybRCjpnKHGOxG0rfFY1085mBDZCH5Kx0cl0HVJuQKC+dV2ZY5AqjcKwAxpE75MLFkr wkkEGBECAAkFAlk3nEQCGwwACgkQoDSui/t3IH7nnwCfcJWUDUFKdCsBH/E5d+0ZnMQi+G0A nAuWpQkjM1ASeQwSHEeAWPgskBQL
  • Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Teddy Astie <teddy.astie@xxxxxxxxxx>, Roger Pau Monné <roger@xxxxxxxxxxxxxx>
  • Delivery-date: Wed, 11 Nov 2026 14:24:22 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Re-use the blowfish code for this, by replacing uses of %r8, %r9, and
%r10-%r15 with %r18, %r19, and %r20-%r25 respectively.

At the same time consume fuzzing input to prefill the eGPR-s when
accessible.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
SDE: -future (9.38.0 or later)
---
load_egpr() doesn't strictly need the __builtin_constant_p() dependency.
I coded it up to make sure previous open-coding of the logic would be
replaced by binary-identical code. If we want to keep it, check_egpr()
may want to gain an equivalent alternative.

--- a/tools/fuzz/x86_instruction_emulator/fuzz-emul.c
+++ b/tools/fuzz/x86_instruction_emulator/fuzz-emul.c
@@ -1031,6 +1031,56 @@ int LLVMFuzzerTestOneInput(const uint8_t
 
     disable_hooks(&ctxt);
 
+    if ( cpu_has_apx_f )
+    {
+        uint64_t egpr[16];
+
+        /* Pre-seed the eGPR-s if enough input data is available. */
+        if ( input_avail(&state, sizeof(egpr)) )
+        {
+            input_read(&state, egpr, sizeof(egpr));
+
+            /*
+             * These are "mov %0, %%r<N>" encoded with hand-crafted REX2
+             * prefixes.  The arrangement is such that no REX prefix would
+             * be emitted, as that would conflict with the REX2 we want.
+             */
+            asm volatile ( ".byte 0xd5, 0x48; mov      (%0), %%eax"
+                           :: "R" (egpr), "m" (egpr[0]) );
+            asm volatile ( ".byte 0xd5, 0x48; mov     8(%0), %%ecx"
+                           :: "R" (egpr), "m" (egpr[1]) );
+            asm volatile ( ".byte 0xd5, 0x48; mov 0x2*8(%0), %%edx"
+                           :: "R" (egpr), "m" (egpr[2]) );
+            asm volatile ( ".byte 0xd5, 0x48; mov 0x3*8(%0), %%ebx"
+                           :: "R" (egpr), "m" (egpr[3]) );
+            asm volatile ( ".byte 0xd5, 0x48; mov 0x4*8(%0), %%esp"
+                           :: "R" (egpr), "m" (egpr[4]) );
+            asm volatile ( ".byte 0xd5, 0x48; mov 0x5*8(%0), %%ebp"
+                           :: "R" (egpr), "m" (egpr[5]) );
+            asm volatile ( ".byte 0xd5, 0x48; mov 0x6*8(%0), %%esi"
+                           :: "R" (egpr), "m" (egpr[6]) );
+            asm volatile ( ".byte 0xd5, 0x48; mov 0x7*8(%0), %%edi"
+                           :: "R" (egpr), "m" (egpr[7]) );
+
+            asm volatile ( ".byte 0xd5, 0x4c; mov 0x8*8(%0), %%eax"
+                           :: "R" (egpr), "m" (egpr[8]) );
+            asm volatile ( ".byte 0xd5, 0x4c; mov 0x9*8(%0), %%ecx"
+                           :: "R" (egpr), "m" (egpr[9]) );
+            asm volatile ( ".byte 0xd5, 0x4c; mov 0xa*8(%0), %%edx"
+                           :: "R" (egpr), "m" (egpr[10]) );
+            asm volatile ( ".byte 0xd5, 0x4c; mov 0xb*8(%0), %%ebx"
+                           :: "R" (egpr), "m" (egpr[11]) );
+            asm volatile ( ".byte 0xd5, 0x4c; mov 0xc*8(%0), %%esp"
+                           :: "R" (egpr), "m" (egpr[12]) );
+            asm volatile ( ".byte 0xd5, 0x4c; mov 0xd*8(%0), %%ebp"
+                           :: "R" (egpr), "m" (egpr[13]) );
+            asm volatile ( ".byte 0xd5, 0x4c; mov 0xe*8(%0), %%esi"
+                           :: "R" (egpr), "m" (egpr[14]) );
+            asm volatile ( ".byte 0xd5, 0x4c; mov 0xf*8(%0), %%edi"
+                           :: "R" (egpr), "m" (egpr[15]) );
+        }
+    }
+
     do {
         /* FIXME: Until we actually implement SIGFPE handling properly */
         setup_fpu_exception_handler();
--- a/tools/tests/x86_emulator/Makefile
+++ b/tools/tests/x86_emulator/Makefile
@@ -40,6 +40,7 @@ else
 
 blowfish-cflags := ""
 blowfish-cflags-x86_32 := "-mno-accumulate-outgoing-args -Dstatic="
+blowfish-cflags-x86_64 := "-DREX2 -Dstatic="
 
 3dnow-vecs := 8
 3dnow-ints :=
@@ -265,7 +266,7 @@ $(TARGET): $(OBJS)
 
 .PHONY: clean
 clean:
-       rm -rf $(TARGET) *.o *~ core *.bin x86_emulate
+       rm -rf $(TARGET) *.o *~ core *.bin blowfish.s x86_emulate
        rm -rf $(addsuffix .h,$(TESTCASES)) $(addsuffix -opmask.h,$(OPMASK))
        rm -rf $(addsuffix .c,$(filter-out blowfish,$(TESTCASES)))
 
--- a/tools/tests/x86_emulator/test_x86_emulator.c
+++ b/tools/tests/x86_emulator/test_x86_emulator.c
@@ -57,6 +57,80 @@ static bool blowfish_check_regs(const st
     return regs->eax == 2 && regs->edx == 1;
 }
 
+#ifdef __x86_64__
+# ifdef __APX_F__
+#  error "Needs re-work with APX_F available to the compiler"
+# endif
+# define load_egpr(reg, val) do { \
+    BUILD_BUG_ON(!((reg) & 0x10)); \
+    if ( !__builtin_constant_p(val) ) \
+        /* mov %rax, %r\reg */ \
+        asm volatile ( ".byte 0xd5, 0x18 | %c[rex_b]\n\t" \
+                       ".byte 0x89, 0xc0 | %c[rm]" \
+                       :: [rm] "i" ((reg) & 7), \
+                          [rex_b] "i" ((bool)((reg) & 8)), \
+                          "a" ((val) + 0UL) ); \
+    else if ( (val) <= 0xffffffffUL ) \
+        /* mov $ui32, %r\reg */ \
+        asm volatile ( ".byte 0xd5, 0x10 | %c[rex_b]\n\t" \
+                       ".byte 0xb8 | %c[r]\n\t" \
+                       ".long %P[v]" \
+                       :: [r] "i" ((reg) & 7), \
+                          [rex_b] "i" ((bool)((reg) & 8)), \
+                          [v] "i" ((val) + 0UL) ); \
+    else \
+        /* mov $ui64, %r\reg */ \
+        asm volatile ( ".byte 0xd5, 0x18 | %c[rex_b]\n\t" \
+                       ".byte 0xb8 | %c[r]\n\t" \
+                       ".quad %P[v]" \
+                       :: [r] "i" ((reg) & 7), \
+                          [rex_b] "i" ((bool)((reg) & 8)), \
+                          [v] "i" ((val) + 0UL) ); \
+} while ( false )
+
+# define check_egpr(reg, val) ({ \
+    bool zf; \
+    BUILD_BUG_ON(!((reg) & 0x10)); \
+    /* cmp %rax, %r\reg */ \
+    asm ( ".byte 0xd5, 0x18 | %c[rex_b]\n\t" \
+          ".byte 0x39, 0xc0 | %c[rm]\n\t" \
+          "sete %[res]" \
+          : [res] "=qm" (zf) \
+          : [rm] "i" ((reg) & 7), \
+            [rex_b] "i" ((bool)((reg) & 8)), \
+            "a" ((val) + 0UL) ); \
+    zf; \
+})
+
+static void blowfish_rex2_set_regs(struct cpu_user_regs *regs)
+{
+    /*
+     * %r12...%r15 are preserved as per the ABI.  The REX2 test blob has them
+     * replaced by %r22...%r25, which therefore take the same (preserved) role.
+     * Seed them with recognizable values, for blowfish_rex2_check_regs() to
+     * check.
+     */
+    load_egpr(22, 0x16000016);
+    load_egpr(23, 0x17000017);
+    load_egpr(24, 0x18000018);
+    load_egpr(25, 0x19000019);
+}
+
+static bool blowfish_rex2_check_regs(const struct cpu_user_regs *regs)
+{
+    return blowfish_check_regs(regs) &&
+           check_egpr(22, 0x16000016) &&
+           check_egpr(23, 0x17000017) &&
+           check_egpr(24, 0x18000018) &&
+           check_egpr(25, 0x19000019);
+}
+
+static bool check_apx_f(void)
+{
+    return cpu_has_apx_f;
+}
+#endif /* __x86_64__ */
+
 static bool simd_check__3dnow(void)
 {
     return cpu_has_3dnow_ext && cpu_has_sse;
@@ -303,6 +377,13 @@ static const struct {
       .check_regs = blowfish_check_regs }
 #ifdef __x86_64__
     BLOWFISH(64, blowfish, ),
+    { .code = blowfish_x86_64_DREX2,
+      .size = sizeof(blowfish_x86_64_DREX2),
+      .bitness = 64,
+      .name = "blowfish (REX2)",
+      .check_cpu = check_apx_f,
+      .set_regs = blowfish_rex2_set_regs,
+      .check_regs = blowfish_rex2_check_regs },
 #endif
     BLOWFISH(32, blowfish, ),
     BLOWFISH(32, blowfish (push), _mno_accumulate_outgoing_args),
--- a/tools/tests/x86_emulator/testcase.mk
+++ b/tools/tests/x86_emulator/testcase.mk
@@ -23,13 +23,29 @@ endif
 
 endif
 
+# For now don't assume an APX_F-capable compiler. Hand-craft eGPR uses instead.
+# In an attempt to have the compiler make more use of %r8 ... %r15, prevent it
+# from using %rbx and %rbp.  We can't also disallow %rax, %rcx, %rdx, %rsi, and
+# %rdi, as those are the hard-wired operands of certain insns.  Since the blob
+# is self-contained, we can then exchange %r8 ... %r15 to become %r18 ... %r25.
+CFLAGS-REX2 := -fomit-frame-pointer -ffixed-rbx -ffixed-rbp
+SED-REX2 := -e 's,%r1,%r2,g' -e 's,%r8,%r18,g' -e 's,%r9,%r19,g'
+
 LDFLAGS_DIRECT += $(shell { $(LD) -v --warn-rwx-segments; } >/dev/null 2>&1 && 
echo --no-warn-rwx-segments)
 
 .PHONY: all
 all: $(TESTCASE).bin
 
 %.bin: %.c
+ifeq ($(filter -DREX2,$($(TESTCASE)-cflags)),)
        $(CC) $(filter-out -M% .%,$(CFLAGS)) -c $<
+else
+       rm -f $*.o
+       $(CC) $(filter-out -M% .%,$(CFLAGS)) $(CFLAGS-REX2) -S $< -o $*.s
+       sed $(SED-REX2) -i $*.s
+       $(AS) -o $*.o $*.s
+       rm -f $*.s
+endif
        $(LD) $(LDFLAGS_DIRECT) -N -Ttext 0x100000 -o $*.tmp $*.o
        $(OBJCOPY) -O binary -R .note.gnu.property $*.tmp $@
        rm -f $*.tmp




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.