Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 456d3d42 authored by David S. Miller's avatar David S. Miller
Browse files

sparc64: Fix several bugs in quad floating point emulation.



UltraSPARC-T2 and later do not use the fp_exception_other trap and do
not set the floating point trap type field in the %fsr at all when you
try to execute an unimplemented FPU operation.

Instead, it uses the illegal_instruction trap and it leaves the
floating point trap type field clear.

So we should not validate the %fsr trap type field when do_mathemu()
is invoked from the illegal instruction handler.

Also, the floating point trap type field is 3 bits, not 4 bits.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 07acfc2a
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -2054,7 +2054,7 @@ void do_fpieee(struct pt_regs *regs)
	do_fpe_common(regs);
}

extern int do_mathemu(struct pt_regs *, struct fpustate *);
extern int do_mathemu(struct pt_regs *, struct fpustate *, bool);

void do_fpother(struct pt_regs *regs)
{
@@ -2068,7 +2068,7 @@ void do_fpother(struct pt_regs *regs)
	switch ((current_thread_info()->xfsr[0] & 0x1c000)) {
	case (2 << 14): /* unfinished_FPop */
	case (3 << 14): /* unimplemented_FPop */
		ret = do_mathemu(regs, f);
		ret = do_mathemu(regs, f, false);
		break;
	}
	if (ret)
@@ -2308,10 +2308,12 @@ void do_illegal_instruction(struct pt_regs *regs)
			} else {
				struct fpustate *f = FPUSTATE;

				/* XXX maybe verify XFSR bits like
				 * XXX do_fpother() does?
				/* On UltraSPARC T2 and later, FPU insns which
				 * are not implemented in HW signal an illegal
				 * instruction trap and do not set the FP Trap
				 * Trap in the %fsr to unimplemented_FPop.
				 */
				if (do_mathemu(regs, f))
				if (do_mathemu(regs, f, true))
					return;
			}
		}
+14 −6
Original line number Diff line number Diff line
@@ -163,7 +163,7 @@ typedef union {
	u64 q[2];
} *argp;

int do_mathemu(struct pt_regs *regs, struct fpustate *f)
int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap)
{
	unsigned long pc = regs->tpc;
	unsigned long tstate = regs->tstate;
@@ -218,7 +218,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
			case FSQRTS: {
				unsigned long x = current_thread_info()->xfsr[0];

				x = (x >> 14) & 0xf;
				x = (x >> 14) & 0x7;
				TYPE(x,1,1,1,1,0,0);
				break;
			}
@@ -226,7 +226,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
			case FSQRTD: {
				unsigned long x = current_thread_info()->xfsr[0];

				x = (x >> 14) & 0xf;
				x = (x >> 14) & 0x7;
				TYPE(x,2,1,2,1,0,0);
				break;
			}
@@ -357,9 +357,17 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
	if (type) {
		argp rs1 = NULL, rs2 = NULL, rd = NULL;
		
		freg = (current_thread_info()->xfsr[0] >> 14) & 0xf;
		if (freg != (type >> 9))
		/* Starting with UltraSPARC-T2, the cpu does not set the FP Trap
		 * Type field in the %fsr to unimplemented_FPop.  Nor does it
		 * use the fp_exception_other trap.  Instead it signals an
		 * illegal instruction and leaves the FP trap type field of
		 * the %fsr unchanged.
		 */
		if (!illegal_insn_trap) {
			int ftt = (current_thread_info()->xfsr[0] >> 14) & 0x7;
			if (ftt != (type >> 9))
				goto err;
		}
		current_thread_info()->xfsr[0] &= ~0x1c000;
		freg = ((insn >> 14) & 0x1f);
		switch (type & 0x3) {