diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2007-12-08 18:39:51 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2007-12-08 18:39:51 +0000 |
commit | d436addf2cf49ebd1f390455dd0992329069d373 (patch) | |
tree | c2f7115448d5e4f6840eb26bd097d167ff6644e5 /sys | |
parent | af09b4aef208a3f14afa115006e61273a8640324 (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.h | 3 | ||||
-rw-r--r-- | sys/arch/luna88k/include/fpu.h | 3 | ||||
-rw-r--r-- | sys/arch/m88k/include/fpu.h | 40 | ||||
-rw-r--r-- | sys/arch/m88k/m88k/m88110_fp.S | 195 | ||||
-rw-r--r-- | sys/arch/m88k/m88k/trap.c | 56 | ||||
-rw-r--r-- | sys/arch/mvme88k/include/fpu.h | 3 |
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> |