|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 09/30] x86emul: APX_F REX2 testing
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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |