diff options
author | marcel <marcel@FreeBSD.org> | 2004-01-20 03:29:24 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2004-01-20 03:29:24 +0000 |
commit | 1bf3c3e6434fdf234bfa5471a146508c48e6f7f4 (patch) | |
tree | 5f1c75d46b03c6888460627028a211c317fbf3d4 /sys/ia64 | |
parent | d62dc6465aca86888b49930251fe69c6ff0ae096 (diff) | |
download | FreeBSD-src-1bf3c3e6434fdf234bfa5471a146508c48e6f7f4.zip FreeBSD-src-1bf3c3e6434fdf234bfa5471a146508c48e6f7f4.tar.gz |
Fix handling of FP traps:
o For traps, the cr.iip register points to the next instruction to
execute on interrupt return (modulo slot). Since we need to get
the bundle of the instruction that caused the FP fault/trap, make
sure we fetch the previous bundle if the next instruction is in
fact the first in a bundle.
o When we call the FPSWA handler, we need to tell it whether it's
a trap or a fault (first argument). This was hardcoded to mean a
fault.
Also, for FP faults, when a fault is converted to a trap, adjust the
cr.iip and cr.ipsr registers to point to the next instruction. This
makes sure that the SIGFPE handler gets a consistent state.
Diffstat (limited to 'sys/ia64')
-rw-r--r-- | sys/ia64/ia64/trap.c | 47 |
1 files changed, 23 insertions, 24 deletions
diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c index 8e7025b..41ddaed 100644 --- a/sys/ia64/ia64/trap.c +++ b/sys/ia64/ia64/trap.c @@ -666,6 +666,7 @@ trap(int vector, struct trapframe *tf) FP_STATE fp_state; FPSWA_RET fpswa_ret; FPSWA_BUNDLE bundle; + char *ip; /* Always fatal in kernel. Should never happen. */ if (!user) @@ -677,7 +678,11 @@ trap(int vector, struct trapframe *tf) break; } - error = copyin((void *)(tf->tf_special.iip), &bundle, 16); + ip = (char *)tf->tf_special.iip; + if (vector == IA64_VEC_FLOATING_POINT_TRAP && + (tf->tf_special.psr & IA64_PSR_RI) == 0) + ip -= 16; + error = copyin(ip, &bundle, 16); if (error) { sig = SIGBUS; /* EFAULT, basically */ ucode = 0; /* exception summary */ @@ -699,15 +704,20 @@ trap(int vector, struct trapframe *tf) ia64_enable_highfp(); /* The docs are unclear. Is Fpswa reentrant? */ - fpswa_ret = fpswa_interface->Fpswa(1, &bundle, - &tf->tf_special.psr, &tf->tf_special.fpsr, - &tf->tf_special.isr, &tf->tf_special.pr, - &tf->tf_special.cfm, &fp_state); + fpswa_ret = fpswa_interface->Fpswa( + (vector == IA64_VEC_FLOATING_POINT_FAULT) ? 1 : 0, + &bundle, &tf->tf_special.psr, &tf->tf_special.fpsr, + &tf->tf_special.isr, &tf->tf_special.pr, + &tf->tf_special.cfm, &fp_state); ia64_disable_highfp(); - if (fpswa_ret.status == 0) { - /* fixed. update ipsr and iip to next insn */ + /* + * Update ipsr and iip to next instruction. We only + * have to do that for faults. + */ + if (vector == IA64_VEC_FLOATING_POINT_FAULT && + (fpswa_ret.status == 0 || (fpswa_ret.status & 2))) { int ei; ei = (tf->tf_special.isr >> 41) & 0x03; @@ -721,30 +731,19 @@ trap(int vector, struct trapframe *tf) tf->tf_special.psr &= ~IA64_ISR_EI; tf->tf_special.iip += 0x10; } + } + + if (fpswa_ret.status == 0) { goto out; } else if (fpswa_ret.status == -1) { printf("FATAL: FPSWA err1 %lx, err2 %lx, err3 %lx\n", fpswa_ret.err1, fpswa_ret.err2, fpswa_ret.err3); panic("fpswa fatal error on fp fault"); - } else if (fpswa_ret.status > 0) { -#if 0 - if (fpswa_ret.status & 1) { - /* - * New exception needs to be raised. - * If set then the following bits also apply: - * & 2 -> fault was converted to a trap - * & 4 -> SIMD caused the exception - */ - sig = SIGFPE; - ucode = 0; /* exception summary */ - break; - } -#endif + } else { sig = SIGFPE; - ucode = 0; /* exception summary */ + ucode = 0; /* XXX exception summary */ break; - } else - panic("bad fpswa return code %lx", fpswa_ret.status); + } } case IA64_VEC_IA32_EXCEPTION: |