From 28466ae036394c142aea0e66a93086e5e7542c48 Mon Sep 17 00:00:00 2001 From: Marcel Moolenaar Date: Tue, 20 Jan 2004 03:29:24 +0000 Subject: [PATCH] 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. --- sys/ia64/ia64/trap.c | 47 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c index 8e7025b1349..41ddaedcf5a 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: