aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/ia64/ia64/trap.c89
-rw-r--r--sys/ia64/include/ia64_cpu.h14
2 files changed, 37 insertions, 66 deletions
diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c
index 9b57912ab31e4..681c65826ba38 100644
--- a/sys/ia64/ia64/trap.c
+++ b/sys/ia64/ia64/trap.c
@@ -85,7 +85,7 @@ static void break_syscall(struct trapframe *tf);
static void ia32_syscall(struct trapframe *framep);
/*
- * EFI-Provided FPSWA interface (Floating Point SoftWare Assist
+ * EFI-Provided FPSWA interface (Floating Point SoftWare Assist)
*/
/* The function entry address */
@@ -401,27 +401,31 @@ trap(int vector, struct trapframe *framep)
goto dopanic;
}
- case IA64_VEC_FLOATING_POINT_FAULT: {
+ case IA64_VEC_FLOATING_POINT_FAULT:
+ /* FALLTHROUGH */
+
+ case IA64_VEC_FLOATING_POINT_TRAP: {
FP_STATE fp_state;
FPSWA_RET fpswa_ret;
FPSWA_BUNDLE bundle;
- /* Always fatal in kernel. Should never happen. */
+ /* Always fatal in kernel. Should never happen. */
if (!user)
goto dopanic;
+
if (fpswa_interface == NULL) {
i = SIGFPE;
ucode = 0;
break;
}
- mtx_lock(&Giant);
+
i = copyin((void *)(framep->tf_special.iip), &bundle, 16);
- mtx_unlock(&Giant);
if (i) {
- i = SIGBUS; /* EFAULT, basically */
- ucode = /*a0*/ 0; /* exception summary */
+ i = SIGBUS; /* EFAULT, basically */
+ ucode = 0; /* exception summary */
break;
}
+
/* f6-f15 are saved in exception_save */
fp_state.bitmask_low64 = 0xffc0; /* bits 6 - 15 */
fp_state.bitmask_high64 = 0x0;
@@ -429,11 +433,21 @@ trap(int vector, struct trapframe *framep)
fp_state.fp_low_volatile = &framep->tf_scratch_fp.fr6;
fp_state.fp_high_preserved = NULL;
fp_state.fp_high_volatile = NULL;
+
+ /*
+ * We have the high FP registers disabled while in the
+ * kernel. Enable them for the FPSWA handler only.
+ */
+ ia64_enable_highfp();
+
/* The docs are unclear. Is Fpswa reentrant? */
fpswa_ret = fpswa_interface->Fpswa(1, &bundle,
&framep->tf_special.psr, &framep->tf_special.fpsr,
&framep->tf_special.isr, &framep->tf_special.pr,
&framep->tf_special.cfm, &fp_state);
+
+ ia64_disable_highfp();
+
if (fpswa_ret.status == 0) {
/* fixed. update ipsr and iip to next insn */
int ei;
@@ -464,70 +478,15 @@ trap(int vector, struct trapframe *framep)
* & 4 -> SIMD caused the exception
*/
i = SIGFPE;
- ucode = /*a0*/ 0; /* exception summary */
+ ucode = 0; /* exception summary */
break;
}
#endif
i = SIGFPE;
- ucode = /*a0*/ 0; /* exception summary */
+ ucode = 0; /* exception summary */
break;
- } else {
- panic("bad fpswa return code %lx", fpswa_ret.status);
- }
- }
-
- case IA64_VEC_FLOATING_POINT_TRAP: {
- FP_STATE fp_state;
- FPSWA_RET fpswa_ret;
- FPSWA_BUNDLE bundle;
-
- /* Always fatal in kernel. Should never happen. */
- if (!user)
- goto dopanic;
- if (fpswa_interface == NULL) {
- i = SIGFPE;
- ucode = 0;
- break;
- }
- mtx_lock(&Giant);
- i = copyin((void *)(framep->tf_special.iip), &bundle, 16);
- mtx_unlock(&Giant);
- if (i) {
- i = SIGBUS; /* EFAULT, basically */
- ucode = /*a0*/ 0; /* exception summary */
- break;
- }
- /* f6-f15 are saved in exception_save */
- fp_state.bitmask_low64 = 0xffc0; /* bits 6 - 15 */
- fp_state.bitmask_high64 = 0x0;
- fp_state.fp_low_preserved = NULL;
- fp_state.fp_low_volatile = &framep->tf_scratch_fp.fr6;
- fp_state.fp_high_preserved = NULL;
- fp_state.fp_high_volatile = NULL;
- /* The docs are unclear. Is Fpswa reentrant? */
- fpswa_ret = fpswa_interface->Fpswa(0, &bundle,
- &framep->tf_special.psr, &framep->tf_special.fpsr,
- &framep->tf_special.isr, &framep->tf_special.pr,
- &framep->tf_special.cfm, &fp_state);
- if (fpswa_ret.status == 0) {
- /* fixed */
- /*
- * should we increment iip like the fault case?
- * or has fpswa done something like normalizing a
- * register so that we should just rerun it?
- */
- 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 trap");
- } else if (fpswa_ret.status > 0) {
- i = SIGFPE;
- ucode = /*a0*/ 0; /* exception summary */
- break;
- } else {
+ } else
panic("bad fpswa return code %lx", fpswa_ret.status);
- }
}
case IA64_VEC_DISABLED_FP: { /* High FP registers are disabled. */
diff --git a/sys/ia64/include/ia64_cpu.h b/sys/ia64/include/ia64_cpu.h
index 04f14dbd5181e..35f1f4fe7bf82 100644
--- a/sys/ia64/include/ia64_cpu.h
+++ b/sys/ia64/include/ia64_cpu.h
@@ -397,7 +397,19 @@ ia64_get_cpuid(int i)
return result;
}
-#endif
+static __inline void
+ia64_disable_highfp(void)
+{
+ __asm __volatile("ssm psr.dfh;; srlz.d");
+}
+
+static __inline void
+ia64_enable_highfp(void)
+{
+ __asm __volatile("rsm psr.dfh;; srlz.d");
+}
+
+#endif /* !LOCORE */
#endif /* _MACHINE_IA64_CPU_H_ */