NetBSD-Bugs archive

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

port-mips/44639: MIPS FP exception caused by BDslot insn isn't handled properly



>Number:         44639
>Category:       port-mips
>Synopsis:       MIPS FP exception caused by BDslot insn isn't handled properly
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    port-mips-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Feb 26 10:10:01 +0000 2011
>Originator:     Izumi Tsutsui
>Release:        NetBSD 5.99.46
>Organization:
>Environment:
System: NetBSD 5.99.46 around 20110225
Architecture: mipsel/mipseb
Machine: cobalt, ews4800mips, probably all mips3 machines
>Description:
Before the second matt-nb5-mips64 merge,
MachFPTrap() takes cause value passed from trap()
and it checks branch delay bit in it to fetch
an instruction that causes the exception.

After the merge, MachFPTrap() is renamed to mips_fpu_trap()
and it no longer takes cause value. It loads the cause value
from trapframe in curlwp passed from trap() instead.
But CAUSE in trapframe doesn't reflect actual cause status
which should be fetched in the exception handler.

So, if the exception is caused by instruction in BDslot,
branch delay bit check doesn't work and mips_fpu_trap()
fetches branch instruction instead of the actual FP instruction.
Then it won't emulate the FP instruction and returns SIGILL.

>How-To-Repeat:
atf-run(1) in /usr/tests/lib/libc/ieeefp.

t_subnormal float test gets SIGILL, and in that case
mips_fpuillinst() is called with branch opcode:
---
 :
tp-start: t_subnormal, 2
tc-start: test_double
tc-end: test_double, passed
tc-start: test_float
mips_fpuillinst(1000ffe2,0x7dfa1f24)
---

Instructions around 0x7dfa1f24 are:
---
7dfa1f20: c4606928      lwc1    $f0,26920(v1)
7dfa1f24: 1000ffe2      b       0x7dfa1eb0
7dfa1f28: 46001302      mul.s   $f12,$f2,$f0
---
The exception is caused by mul.s in BDslot.

>Fix:
Pass cause value from trap() to mips_fpu_trap() seems to fix the problem.

But no idea how to pass cause value from cpu_intr() to mips_fpu_intr()
because cpu_intr() no longer takes cause.



Home | Main Index | Thread Index | Old Index