summaryrefslogtreecommitdiffstats
path: root/sys/ia64
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2004-01-20 03:29:24 +0000
committermarcel <marcel@FreeBSD.org>2004-01-20 03:29:24 +0000
commit1bf3c3e6434fdf234bfa5471a146508c48e6f7f4 (patch)
tree5f1c75d46b03c6888460627028a211c317fbf3d4 /sys/ia64
parentd62dc6465aca86888b49930251fe69c6ff0ae096 (diff)
downloadFreeBSD-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.c47
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:
OpenPOWER on IntegriCloud