summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2007-12-08 18:39:51 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2007-12-08 18:39:51 +0000
commitd436addf2cf49ebd1f390455dd0992329069d373 (patch)
treec2f7115448d5e4f6840eb26bd097d167ff6644e5 /sys
parentaf09b4aef208a3f14afa115006e61273a8640324 (diff)
Better siginfo fault codes for floating point exceptions on 88110, with
more work in progress to handle these exceptions correctly, and document a new undocumented and evil chip bug while there.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/aviion/include/fpu.h3
-rw-r--r--sys/arch/luna88k/include/fpu.h3
-rw-r--r--sys/arch/m88k/include/fpu.h40
-rw-r--r--sys/arch/m88k/m88k/m88110_fp.S195
-rw-r--r--sys/arch/m88k/m88k/trap.c56
-rw-r--r--sys/arch/mvme88k/include/fpu.h3
6 files changed, 277 insertions, 23 deletions
diff --git a/sys/arch/aviion/include/fpu.h b/sys/arch/aviion/include/fpu.h
new file mode 100644
index 00000000000..fa7b95f0fab
--- /dev/null
+++ b/sys/arch/aviion/include/fpu.h
@@ -0,0 +1,3 @@
+/* $OpenBSD: fpu.h,v 1.1 2007/12/08 18:39:49 miod Exp $ */
+/* public domain */
+#include <m88k/fpu.h>
diff --git a/sys/arch/luna88k/include/fpu.h b/sys/arch/luna88k/include/fpu.h
new file mode 100644
index 00000000000..8493e1b3c62
--- /dev/null
+++ b/sys/arch/luna88k/include/fpu.h
@@ -0,0 +1,3 @@
+/* $OpenBSD: fpu.h,v 1.1 2007/12/08 18:39:50 miod Exp $ */
+/* public domain */
+#include <m88k/fpu.h>
diff --git a/sys/arch/m88k/include/fpu.h b/sys/arch/m88k/include/fpu.h
new file mode 100644
index 00000000000..1fd6c9e643d
--- /dev/null
+++ b/sys/arch/m88k/include/fpu.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: fpu.h,v 1.1 2007/12/08 18:39:50 miod Exp $ */
+
+/*
+ * Copyright (c) 2007, Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice, this permission notice, and the disclaimer below
+ * appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _M88K_FPU_H_
+#define _M88K_FPU_H_
+
+/* FPECR bits */
+#define FPECR_FIOV 0x80
+#define FPECR_FUNIMP 0x40
+#define FPECR_FPRV 0x20
+#define FPECR_FROP 0x10
+#define FPECR_FDVZ 0x08
+#define FPECR_FUNF 0x04
+#define FPECR_FOVF 0x02
+#define FPECR_FINX 0x01
+
+/* FPSR and FPCR exception bits */
+#define FPSR_EFINV 0x10
+#define FPSR_EFDVZ 0x08
+#define FPSR_EFUNF 0x04
+#define FPSR_EFOVF 0x02
+#define FPSR_EFINX 0x01
+
+#endif /* _M88K_FPU_H_ */
diff --git a/sys/arch/m88k/m88k/m88110_fp.S b/sys/arch/m88k/m88k/m88110_fp.S
index 430a74d28a2..bd4116747b1 100644
--- a/sys/arch/m88k/m88k/m88110_fp.S
+++ b/sys/arch/m88k/m88k/m88110_fp.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: m88110_fp.S,v 1.3 2007/12/02 21:32:08 miod Exp $ */
+/* $OpenBSD: m88110_fp.S,v 1.4 2007/12/08 18:39:50 miod Exp $ */
/*
* Copyright (c) 2007, Miodrag Vallat.
@@ -96,15 +96,137 @@ ASLOCAL(m88110_funimp)
bb1 PSR_FPU_DISABLE_BIT, r5, _ASM_LABEL(m88110_fpeflt)
/*
+ * If this is a kernel fault, we were probably trying to reissue
+ * a previously-faulting instruction.
+ * Just return without altering the fpecr, the ``caller'' will
+ * check it afterwards.
+ */
+ bb1 PSR_SUPERVISOR_MODE_BIT, r5, _ASM_LABEL(m88110_fp_return_noreset)
+
+ /*
* We should check the faulting instruction here.
- * This can be:
+ *
+ * According to the documentation, this can be:
* - fsqrt (unimplemented)
* - any valid fp instruction operating on an odd register pair
* - any bogus fp instruction.
+ *
+ * However, real life shows that the 88110 will conveniently only
+ * flag the ``unimplemented instruction'' exception bit, regardless
+ * of the real exception cause. In this case, the fpsr register is
+ * correctly populated. But since bits in it are sticky... we can
+ * not trust its value )-:
+ *
+ * Because of this, we need to sort out real unimplemented opcodes
+ * from incorrectly reported exceptions.
+ * We will only handle odd register pairs for instructions issued
+ * in user mode (since the kernel will not issue any fp instructions
+ * except in this file).
*/
- /* XXX TBD */
+#ifdef notyet
+ /* Fetch the offending instruction */
+ ld r6, r30, EF_EXIP * 4
+ ld.usr r2, r6, r0
+
+ /*
+ * Check the instruction format. All triadic floating point
+ * instruction are built this way:
+ *
+ * 100001 | D | S1 | X | opcode | T1 | T2 | TD | S2
+ *
+ * with:
+ * D (bits 25-21) = destination register
+ * S1 (bits 20-16) = source 1 register
+ * X (bit 15) = extended register file
+ * T1 (bits 10-9), T2 (bits 8-7), TD (bits 6-5) = size of the
+ * respective registers (00 = single, 01 = double, 10 = X)
+ * S1 (bits 4-0) = source 2 register
+ *
+ * flt is slightly different, in that the X bit is bit 9 (in T1).
+ *
+ * Note that we currently do not support the extended register
+ * file, so instructions referring to the X registers will not
+ * be processed. This includes all forms of the mov instruction.
+ */
+
+ extu r3, r2, 6<26>
+ cmp r4, r3, 0x21 /* 10 0001 */
+ bcnd ne0, r4, _ASM_LABEL(m88110_bad_opcode)
+
+ /*
+ * Extract the 4-bit opcode and check for the XRF bit.
+ */
+ extu r5, r2, 4<11> /* opcode */
+ cmp r4, r5, 0x04 /* flt */
+ bcnd eq0, r4, _ASM_LABEL(m88110_check_flt)
+
+ bb1 15, r2, _ASM_LABEL(m88110_bad_opcode)
+
+ /* For fcmp, we do not want to check TD. */
+ cmp r4, r5, 0x07 /* fcmp/fcmpu */
+ bcnd eq0, r4, _ASM_LABEL(m88110_check_t1)
+
+ /*
+ * Check TD and RD. If TD is 01 and RD is not even,
+ * this is indeed an odd-register pair exception.
+ */
+ extu r6, r2, 2<5>
+ cmp r7, r6, 0x01
+ bcnd ne0, r7, _ASM_LABEL(m88110_check_t1)
+
+ bb1 21, r2, _ASM_LABEL(m88110_odd_reg)
+
+ASLOCAL(m88110_check_t1)
+ /*
+ * Check T1 and R1. If T1 is 01 and R1 is not even,
+ * this is indeed an odd-register pair exception.
+ */
+ extu r6, r2, 2<9>
+ cmp r7, r6, 0x01
+ bcnd ne0, r7, _ASM_LABEL(m88110_check_t2)
+
+ bb1 16, r2, _ASM_LABEL(m88110_odd_reg)
+ASLOCAL(m88110_check_t2)
+ /*
+ * Check T2 and R2. If T2 is 01 and R2 is not even,
+ * this is indeed an odd-register pair exception.
+ */
+ extu r6, r2, 2<7>
+ cmp r7, r6, 0x01
+ bcnd ne0, r7, _ASM_LABEL(m88110_bad_opcode)
+
+ bb1 0, r2, _ASM_LABEL(m88110_odd_reg)
+
+ br _ASM_LABEL(m88110_bad_opcode)
+
+ASLOCAL(m88110_check_flt)
+ /*
+ * For flt, we only want to check TD. But we also want
+ * to bail out if operating on XRF.
+ */
+ bb1 9, r2, _ASM_LABEL(m88110_bad_opcode)
+
+ /*
+ * Check TD and RD. If TD is 01 and RD is not even,
+ * this is indeed an odd-register pair exception.
+ */
+ extu r6, r2, 2<5>
+ cmp r7, r6, 0x01
+ bcnd ne0, r7, _ASM_LABEL(m88110_bad_opcode)
+
+ bb1 21, r2, _ASM_LABEL(m88110_odd_reg)
+
+ASLOCAL(m88110_bad_opcode)
+ /*
+ * This is not an odd-register pair exception.
+ *
+ * We should check for an fsqrt instruction and emulate it.
+ * However since the compiler will not produce it, we can
+ * skip emulating it for now...
+ */
+#endif
br _ASM_LABEL(m88110_fpeflt)
/*
@@ -230,10 +352,77 @@ ASLOCAL(m88110_finx)
addu r31, r31, 16
ASLOCAL(m88110_fpeflt)
+ /*
+ * Do not call trap() if the exception comes from kernel mode.
+ */
+ ld r5, r30, EF_EPSR * 4
+ bb1 PSR_SUPERVISOR_MODE_BIT, r5, _ASM_LABEL(m88110_fp_return)
+
or r2, r0, T_FPEPFLT
bsr.n _C_LABEL(m88110_trap)
or r3, r0, r30
+ASLOCAL(m88110_fp_return)
+ /*
+ * Reset the exception cause register
+ */
+ fstcr r0, FPECR
+
+ASLOCAL(m88110_fp_return_noreset)
ld r1, r31, 0
jmp.n r1
addu r31, r31, 16
+
+#ifdef notyet
+/*
+ * Odd-numbered register pair emulation.
+ *
+ * On entry:
+ * r2 = faulting instruction
+ * r5 = instruction sub opcode (bits 14-11)
+ * r30 = exception frame
+ *
+ * We'll issue a similar instruction using only even-numbered register pairs,
+ * update the exception frame registers with the result, and skip the
+ * emulated instruction.
+ */
+ASLOCAL(m88110_odd_reg)
+ or.u r10, r0, hi16(_ASM_LABEL(m88110_odd_table))
+ or r10, r10, lo16(_ASM_LABEL(m88110_odd_table))
+ ld r9, r10 [r5]
+ jmp r9
+
+ASLOCAL(m88110_odd_table)
+ .word _ASM_LABEL(m88110_odd_fmul)
+ .word _ASM_LABEL(m88110_odd_fcvt)
+ .word _ASM_LABEL(m88110_bad_opcode)
+ .word _ASM_LABEL(m88110_bad_opcode)
+
+ .word _ASM_LABEL(m88110_odd_flt)
+ .word _ASM_LABEL(m88110_odd_fadd)
+ .word _ASM_LABEL(m88110_odd_fsub)
+ .word _ASM_LABEL(m88110_odd_fcmp)
+
+ .word _ASM_LABEL(m88110_bad_opcode)
+ .word _ASM_LABEL(m88110_odd_int)
+ .word _ASM_LABEL(m88110_odd_nint)
+ .word _ASM_LABEL(m88110_odd_trnc)
+
+ .word _ASM_LABEL(m88110_bad_opcode)
+ .word _ASM_LABEL(m88110_bad_opcode)
+ .word _ASM_LABEL(m88110_odd_fdiv)
+ .word _ASM_LABEL(m88110_bad_opcode)
+
+ASLOCAL(m88110_odd_fmul)
+ASLOCAL(m88110_odd_fcvt)
+ASLOCAL(m88110_odd_flt)
+ASLOCAL(m88110_odd_fadd)
+ASLOCAL(m88110_odd_fsub)
+ASLOCAL(m88110_odd_fcmp)
+ASLOCAL(m88110_odd_int)
+ASLOCAL(m88110_odd_nint)
+ASLOCAL(m88110_odd_trnc)
+ASLOCAL(m88110_odd_fdiv)
+ /* XXX TBD */
+ br _ASM_LABEL(m88110_fp_return)
+#endif
diff --git a/sys/arch/m88k/m88k/trap.c b/sys/arch/m88k/m88k/trap.c
index 67fcba101fe..b174e004e77 100644
--- a/sys/arch/m88k/m88k/trap.c
+++ b/sys/arch/m88k/m88k/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.58 2007/12/04 05:42:48 miod Exp $ */
+/* $OpenBSD: trap.c,v 1.59 2007/12/08 18:39:50 miod Exp $ */
/*
* Copyright (c) 2004, Miodrag Vallat.
* Copyright (c) 1998 Steve Murphree, Jr.
@@ -59,18 +59,19 @@
#include <uvm/uvm_extern.h>
-#include <machine/asm_macro.h> /* enable/disable interrupts */
+#include <machine/asm_macro.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#ifdef M88100
-#include <machine/m88100.h> /* DMT_xxx */
-#include <machine/m8820x.h> /* CMMU_PFSR_xxx */
+#include <machine/m88100.h>
+#include <machine/m8820x.h>
#endif
#ifdef M88110
#include <machine/m88110.h>
#endif
-#include <machine/pcb.h> /* FIP_E, etc. */
-#include <machine/psl.h> /* FIP_E, etc. */
+#include <machine/fpu.h>
+#include <machine/pcb.h>
+#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/db_machdep.h>
@@ -236,7 +237,7 @@ m88100_trap(u_int type, struct trapframe *frame)
type += T_USER;
p->p_md.md_tf = frame; /* for ptrace/signals */
}
- fault_type = 0;
+ fault_type = SI_NOINFO;
fault_code = 0;
fault_addr = frame->tf_sxip & XIP_ADDR;
@@ -573,7 +574,7 @@ user_fault:
return;
if (sig) {
- sv.sival_int = fault_addr;
+ sv.sival_ptr = (void *)fault_addr;
KERNEL_PROC_LOCK(p);
trapsignal(p, sig, fault_code, fault_type, sv);
KERNEL_PROC_UNLOCK(p);
@@ -613,7 +614,7 @@ m88110_trap(u_int type, struct trapframe *frame)
if ((p = curproc) == NULL)
p = &proc0;
- fault_type = 0;
+ fault_type = SI_NOINFO;
fault_code = 0;
fault_addr = frame->tf_exip & XIP_ADDR;
@@ -728,16 +729,6 @@ m88110_trap(u_int type, struct trapframe *frame)
m88110_skip_insn(frame);
splx(s);
return;
-#if 0
- case T_ILLFLT:
- s = splhigh();
- set_psr((psr = get_psr()) & ~PSR_IND);
- ddb_error_trap(type == T_ILLFLT ? "unimplemented opcode" :
- "error fault", (db_regs_t*)frame);
- set_psr(psr);
- splx(s);
- return;
-#endif /* 0 */
#endif /* DDB */
case T_ILLFLT:
printf("Unimplemented opcode!\n");
@@ -1002,6 +993,8 @@ m88110_user_fault:
}
break;
case T_PRIVINFLT+T_USER:
+ fault_type = ILL_PRVREG;
+ /* FALLTHROUGH */
case T_ILLFLT+T_USER:
#ifndef DDB
case T_KDB_BREAK:
@@ -1032,6 +1025,29 @@ m88110_user_fault:
break;
case T_FPEPFLT+T_USER:
sig = SIGFPE;
+
+ if (frame->tf_fpecr & FPECR_FUNIMP) {
+ if (frame->tf_epsr & PSR_SFD1)
+ fault_type = FPE_FLTINV;
+ } else if (frame->tf_fpecr & FPECR_FIOV)
+ fault_type = FPE_FLTSUB;
+ else if (frame->tf_fpecr & FPECR_FROP)
+ fault_type = FPE_FLTINV;
+ else if (frame->tf_fpecr & FPECR_FDVZ)
+ fault_type = FPE_INTDIV;
+ else if (frame->tf_fpecr & FPECR_FUNF) {
+ if (frame->tf_fpsr & FPSR_EFUNF)
+ fault_type = FPE_FLTUND;
+ else if (frame->tf_fpsr & FPSR_EFINX)
+ fault_type = FPE_FLTRES;
+ } else if (frame->tf_fpecr & FPECR_FOVF) {
+ if (frame->tf_fpsr & FPSR_EFOVF)
+ fault_type = FPE_FLTOVF;
+ else if (frame->tf_fpsr & FPSR_EFINX)
+ fault_type = FPE_FLTRES;
+ } else if (frame->tf_fpecr & FPECR_FINX)
+ fault_type = FPE_FLTRES;
+
/* skip trap instruction */
m88110_skip_insn(frame);
break;
@@ -1104,7 +1120,7 @@ m88110_user_fault:
if (sig) {
deliver:
- sv.sival_int = fault_addr;
+ sv.sival_ptr = (void *)fault_addr;
KERNEL_PROC_LOCK(p);
trapsignal(p, sig, fault_code, fault_type, sv);
KERNEL_PROC_UNLOCK(p);
diff --git a/sys/arch/mvme88k/include/fpu.h b/sys/arch/mvme88k/include/fpu.h
new file mode 100644
index 00000000000..8493e1b3c62
--- /dev/null
+++ b/sys/arch/mvme88k/include/fpu.h
@@ -0,0 +1,3 @@
+/* $OpenBSD: fpu.h,v 1.1 2007/12/08 18:39:50 miod Exp $ */
+/* public domain */
+#include <m88k/fpu.h>