Fix the code reconstructing s87_tw (full tag word) from fx_sw (abridged tag word) to correctly represent all register states. The previous code only distinguished between empty/non-empty registers, and assigned 'regular value' to all non-empty registers. The new code explicitly distinguishes the two other tag word values: empty and special. --- sys/arch/x86/x86/fpu.c | 28 ++++++++++++++++++++------ tests/lib/libc/sys/t_ptrace_x86_wait.h | 2 -- 2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/sys/arch/x86/x86/fpu.c b/sys/arch/x86/x86/fpu.c index d89c78dcef47..c580f34b0615 100644 --- a/sys/arch/x86/x86/fpu.c +++ b/sys/arch/x86/x86/fpu.c @@ -668,7 +668,7 @@ fpu_sigreset(struct lwp *l) static void process_xmm_to_s87(const struct fxsave *sxmm, struct save87 *s87) { - unsigned int tag, ab_tag; + unsigned int tag, ab_tag, st; const struct fpaccfx *fx_reg; struct fpacc87 *s87_reg; int i; @@ -723,12 +723,28 @@ process_xmm_to_s87(const struct fxsave *sxmm, struct save87 *s87) return; } + /* For ST(i), i = fpu_reg - top, we start with fpu_reg=7. */ + st = 7 - ((sxmm->fx_sw >> 11) & 7); tag = 0; - /* Separate bits of abridged tag word with zeros */ - for (i = 0x80; i != 0; tag <<= 1, i >>= 1) - tag |= ab_tag & i; - /* Replicate and invert so that 0 => 0b11 and 1 => 0b00 */ - s87->s87_tw = (tag | tag >> 1) ^ 0xffff; + for (i = 0x80; i != 0; i >>= 1) { + tag <<= 2; + if (ab_tag & i) { + unsigned int exp; + /* Non-empty - we need to check ST(i) */ + fx_reg = &sxmm->fx_87_ac[st]; + exp = fx_reg->r.f87_exp_sign & 0x7fff; + if (exp == 0) { + if (fx_reg->r.f87_mantissa == 0) + tag |= 1; /* Zero */ + else + tag |= 2; /* Denormal */ + } else if (exp == 0x7fff) + tag |= 2; /* Infinity or NaN */ + } else + tag |= 3; /* Empty */ + st = (st - 1) & 7; + } + s87->s87_tw = tag; } static void diff --git a/tests/lib/libc/sys/t_ptrace_x86_wait.h b/tests/lib/libc/sys/t_ptrace_x86_wait.h index d7e93fde55a3..6067066a36c1 100644 --- a/tests/lib/libc/sys/t_ptrace_x86_wait.h +++ b/tests/lib/libc/sys/t_ptrace_x86_wait.h @@ -3367,10 +3367,8 @@ x86_register_test(enum x86_test_regset regset, enum x86_test_registers regs, expected_fpu.cw); ATF_CHECK_EQ(fpr.fstate.s87_sw, expected_fpu.sw); -#if 0 /* TODO: translation from FXSAVE is broken */ ATF_CHECK_EQ(fpr.fstate.s87_tw, expected_fpu.tw); -#endif ATF_CHECK_EQ(fpr.fstate.s87_opcode, expected_fpu.opcode); ATF_CHECK_EQ(fpr.fstate.s87_ip.fa_32.fa_off, -- 2.28.0