Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/tests/lib/libc/sys Add tests for x87 FPU registers
details: https://anonhg.NetBSD.org/src/rev/f122264b6acf
branches: trunk
changeset: 976940:f122264b6acf
user: mgorny <mgorny%NetBSD.org@localhost>
date: Fri Oct 09 17:43:30 2020 +0000
description:
Add tests for x87 FPU registers
Reviewed by kamil
diffstat:
tests/lib/libc/sys/t_ptrace_x86_wait.h | 353 +++++++++++++++++++++++++++++++-
1 files changed, 338 insertions(+), 15 deletions(-)
diffs (truncated from 552 to 300 lines):
diff -r 3e8350939d87 -r f122264b6acf tests/lib/libc/sys/t_ptrace_x86_wait.h
--- a/tests/lib/libc/sys/t_ptrace_x86_wait.h Fri Oct 09 17:43:07 2020 +0000
+++ b/tests/lib/libc/sys/t_ptrace_x86_wait.h Fri Oct 09 17:43:30 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_x86_wait.h,v 1.26 2020/10/09 17:43:07 mgorny Exp $ */
+/* $NetBSD: t_ptrace_x86_wait.h,v 1.27 2020/10/09 17:43:30 mgorny Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -2186,6 +2186,21 @@
uint32_t u32;
};
+struct x86_test_fpu_registers {
+ struct {
+ uint64_t mantissa;
+ uint16_t sign_exp;
+ } __aligned(16) st[8];
+
+ uint16_t cw;
+ uint16_t sw;
+ uint16_t tw;
+ uint8_t tw_abridged;
+ uint16_t opcode;
+ union fp_addr ip;
+ union fp_addr dp;
+};
+
enum x86_test_regset {
TEST_GPREGS,
TEST_FPREGS,
@@ -2201,6 +2216,7 @@
GPREGS_64,
GPREGS_64_R8,
/* TEST_FPREGS/TEST_XMMREGS */
+ FPREGS_FPU,
FPREGS_MM,
FPREGS_XMM,
/* TEST_XSTATE */
@@ -2419,6 +2435,79 @@
#endif
}
+static __inline void get_fpu_regs(struct x86_test_fpu_registers *out)
+{
+ struct save87 fsave;
+ struct fxsave fxsave;
+
+ __CTASSERT(sizeof(out->st[0]) == 16);
+
+ __asm__ __volatile__(
+ "finit\n\t"
+ "int3\n\t"
+#if defined(__x86_64__)
+ "fxsave64 %2\n\t"
+#else
+ "fxsave %2\n\t"
+#endif
+ "fnstenv %1\n\t"
+ "fnclex\n\t"
+ "fstpt 0x00(%0)\n\t"
+ "fstpt 0x10(%0)\n\t"
+ "fstpt 0x20(%0)\n\t"
+ "fstpt 0x30(%0)\n\t"
+ "fstpt 0x40(%0)\n\t"
+ "fstpt 0x50(%0)\n\t"
+ "fstpt 0x60(%0)\n\t"
+ "fstpt 0x70(%0)\n\t"
+ :
+ : "a"(out->st), "m"(fsave), "m"(fxsave)
+ : "st", "memory"
+ );
+
+ FORKEE_ASSERT(fsave.s87_cw == fxsave.fx_cw);
+ FORKEE_ASSERT(fsave.s87_sw == fxsave.fx_sw);
+
+ /* fsave contains full tw */
+ out->cw = fsave.s87_cw;
+ out->sw = fsave.s87_sw;
+ out->tw = fsave.s87_tw;
+ out->tw_abridged = fxsave.fx_tw;
+ out->opcode = fxsave.fx_opcode;
+ out->ip = fxsave.fx_ip;
+ out->dp = fxsave.fx_dp;
+}
+
+/* used as single-precision float */
+uint32_t x86_test_zero = 0;
+
+static __inline void set_fpu_regs(const struct x86_test_fpu_registers *data)
+{
+ __CTASSERT(sizeof(data->st[0]) == 16);
+
+ __asm__ __volatile__(
+ "finit\n\t"
+ "fldcw %1\n\t"
+ /* load on stack in reverse order to make it easier to read */
+ "fldt 0x70(%0)\n\t"
+ "fldt 0x60(%0)\n\t"
+ "fldt 0x50(%0)\n\t"
+ "fldt 0x40(%0)\n\t"
+ "fldt 0x30(%0)\n\t"
+ "fldt 0x20(%0)\n\t"
+ "fldt 0x10(%0)\n\t"
+ "fldt 0x00(%0)\n\t"
+ /* free st7 */
+ "ffree %%st(7)\n\t"
+ /* this should trigger a divide-by-zero */
+ "fdivs (%2)\n\t"
+ "int3\n\t"
+ :
+ : "a"(&data->st), "m"(data->cw), "b"(&x86_test_zero)
+ : "st"
+ );
+}
+
__attribute__((target("mmx")))
static __inline void get_mm_regs(union x86_test_register out[])
{
@@ -2712,6 +2801,54 @@
0x262524232221201F, 0x2E2D2C2B2A292827, }},
};
+ const struct x86_test_fpu_registers expected_fpu = {
+ .st = {
+ {0x8000000000000000, 0x4000}, /* +2.0 */
+ {0x3f00000000000000, 0x0000}, /* 1.654785e-4932 */
+ {0x0000000000000000, 0x0000}, /* +0 */
+ {0x0000000000000000, 0x8000}, /* -0 */
+ {0x8000000000000000, 0x7fff}, /* +inf */
+ {0x8000000000000000, 0xffff}, /* -inf */
+ {0xc000000000000000, 0xffff}, /* nan */
+ /* st(7) will be freed to test tag word better */
+ {0x0000000000000000, 0x0000}, /* +0 */
+ },
+ /* 0000 0011 0111 1011
+ * PU OZDI -- unmask divide-by-zero exc.
+ * RR --------- reserved
+ * PC ------------ 64-bit precision
+ * RC -------------- round to nearest
+ * I ----------------- allow interrupts (unused)
+ */
+ .cw = 0x037b,
+ /* 1000 0000 1000 0100
+ * SPU OZDI -- divide-by-zero exception
+ * I ---------- interrupt (exception handling)
+ * C CCC ------------ condition codes
+ * TO P --------------- top register is 0
+ * B -------------------- FPU is busy
+ */
+ .sw = 0x8084,
+ /* 1110 1010 0101 1000
+ * R7R6 R5R4 R3R2 R1R0
+ * nz -- non-zero (+2.0)
+ * sp ---- special (denormal)
+ * zrzr ------- zeroes
+ * sp spsp ------------ specials (NaN + infinities)
+ * em ------------------- empty register
+ */
+ .tw = 0xea58,
+ /* 0111 1111 -- registers 0 to 6 are used */
+ .tw_abridged = 0x7f,
+ /* FDIV */
+ .opcode = 0x0033,
+ /* random bits for IP/DP write test
+ * keep it below 48 bits since it can be truncated
+ */
+ .ip = {.fa_64 = 0x00000a9876543210},
+ .dp = {.fa_64 = 0x0000056789abcdef},
+ };
+
bool need_32 = false, need_64 = false, need_cpuid = false;
switch (regs) {
@@ -2723,6 +2860,8 @@
case GPREGS_64_R8:
need_64 = true;
break;
+ case FPREGS_FPU:
+ break;
case FPREGS_MM:
case FPREGS_XMM:
case FPREGS_YMM:
@@ -2768,6 +2907,7 @@
case GPREGS_32_EBP_ESP:
case GPREGS_64:
case GPREGS_64_R8:
+ case FPREGS_FPU:
__unreachable();
}
}
@@ -2776,6 +2916,7 @@
SYSCALL_REQUIRE((child = fork()) != -1);
if (child == 0) {
union x86_test_register vals[16] __aligned(32);
+ struct x86_test_fpu_registers vals_fpu;
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -2797,6 +2938,9 @@
case GPREGS_64_R8:
set_gp64_r8_regs(expected);
break;
+ case FPREGS_FPU:
+ set_fpu_regs(&expected_fpu);
+ break;
case FPREGS_MM:
set_mm_regs(expected);
break;
@@ -2822,6 +2966,9 @@
case GPREGS_64_R8:
get_gp64_r8_regs(vals);
break;
+ case FPREGS_FPU:
+ get_fpu_regs(&vals_fpu);
+ break;
case FPREGS_MM:
get_mm_regs(vals);
break;
@@ -2871,6 +3018,47 @@
FORKEE_ASSERT(!memcmp(&vals[7].u64,
&expected[7].u64, sizeof(vals->u64)));
break;
+ case FPREGS_FPU:
+ FORKEE_ASSERT(vals_fpu.cw == expected_fpu.cw);
+ FORKEE_ASSERT(vals_fpu.sw == expected_fpu.sw);
+ FORKEE_ASSERT(vals_fpu.tw == expected_fpu.tw);
+ FORKEE_ASSERT(vals_fpu.tw_abridged
+ == expected_fpu.tw_abridged);
+ FORKEE_ASSERT(vals_fpu.ip.fa_64
+ == expected_fpu.ip.fa_64);
+ FORKEE_ASSERT(vals_fpu.dp.fa_64
+ == expected_fpu.dp.fa_64);
+
+ FORKEE_ASSERT(vals_fpu.st[0].sign_exp
+ == expected_fpu.st[0].sign_exp);
+ FORKEE_ASSERT(vals_fpu.st[0].mantissa
+ == expected_fpu.st[0].mantissa);
+ FORKEE_ASSERT(vals_fpu.st[1].sign_exp
+ == expected_fpu.st[1].sign_exp);
+ FORKEE_ASSERT(vals_fpu.st[1].mantissa
+ == expected_fpu.st[1].mantissa);
+ FORKEE_ASSERT(vals_fpu.st[2].sign_exp
+ == expected_fpu.st[2].sign_exp);
+ FORKEE_ASSERT(vals_fpu.st[2].mantissa
+ == expected_fpu.st[2].mantissa);
+ FORKEE_ASSERT(vals_fpu.st[3].sign_exp
+ == expected_fpu.st[3].sign_exp);
+ FORKEE_ASSERT(vals_fpu.st[3].mantissa
+ == expected_fpu.st[3].mantissa);
+ FORKEE_ASSERT(vals_fpu.st[4].sign_exp
+ == expected_fpu.st[4].sign_exp);
+ FORKEE_ASSERT(vals_fpu.st[4].mantissa
+ == expected_fpu.st[4].mantissa);
+ FORKEE_ASSERT(vals_fpu.st[5].sign_exp
+ == expected_fpu.st[5].sign_exp);
+ FORKEE_ASSERT(vals_fpu.st[5].mantissa
+ == expected_fpu.st[5].mantissa);
+ FORKEE_ASSERT(vals_fpu.st[6].sign_exp
+ == expected_fpu.st[6].sign_exp);
+ FORKEE_ASSERT(vals_fpu.st[6].mantissa
+ == expected_fpu.st[6].mantissa);
+ /* st(7) is left empty == undefined */
+ break;
case FPREGS_XMM:
FORKEE_ASSERT(!memcmp(&vals[0].xmm,
&expected[0].xmm, sizeof(vals->xmm)));
@@ -2959,6 +3147,7 @@
if (regset == TEST_XSTATE) {
switch (regs) {
+ case FPREGS_FPU:
case FPREGS_MM:
xst_flags |= XCR0_X87;
break;
@@ -2980,16 +3169,19 @@
switch (regmode) {
case TEST_GETREGS:
case TEST_SETREGS:
- switch (regset) {
- case TEST_GPREGS:
- ATF_REQUIRE(regs < FPREGS_MM);
+ if (regset == TEST_GPREGS || regs == FPREGS_FPU) {
DPRINTF("Call GETREGS for the child process\n");
SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0)
!= -1);
+ }
+
+ switch (regset) {
+ case TEST_GPREGS:
+ /* already handled above */
break;
case TEST_XMMREGS:
#if defined(__i386__)
- ATF_REQUIRE(regs >= FPREGS_MM && regs < FPREGS_YMM);
+ ATF_REQUIRE(regs >= FPREGS_FPU && regs < FPREGS_YMM);
DPRINTF("Call GETXMMREGS for the child process\n");
SYSCALL_REQUIRE(ptrace(PT_GETXMMREGS, child, &xmm, 0)
!= -1);
@@ -3000,17 +3192,17 @@
Home |
Main Index |
Thread Index |
Old Index