Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/mips Handle gas/gcc generating a break/trap 6 for i...



details:   https://anonhg.NetBSD.org/src/rev/6c44f8c707a8
branches:  trunk
changeset: 981609:6c44f8c707a8
user:      simonb <simonb%NetBSD.org@localhost>
date:      Wed Mar 17 11:05:37 2021 +0000

description:
Handle gas/gcc generating a break/trap 6 for integer overflow and
break/trap 7 for integer divide by zero and setting the SIGFPE
si_code of FPE_INTOVF or FPE_INTDIV respectively.  The break/trap
6/7 seems to have existed since the early days of MIPS but not
well documented anywhere.

Fixes ATF lib/libc/gen/t_siginfo::sigfpe_int .

diffstat:

 sys/arch/mips/include/cpuregs.h |   4 +-
 sys/arch/mips/mips/trap.c       |  71 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 66 insertions(+), 9 deletions(-)

diffs (147 lines):

diff -r ed171e115d05 -r 6c44f8c707a8 sys/arch/mips/include/cpuregs.h
--- a/sys/arch/mips/include/cpuregs.h   Wed Mar 17 08:13:29 2021 +0000
+++ b/sys/arch/mips/include/cpuregs.h   Wed Mar 17 11:05:37 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cpuregs.h,v 1.109 2020/08/22 03:41:33 simonb Exp $     */
+/*     $NetBSD: cpuregs.h,v 1.110 2021/03/17 11:05:37 simonb Exp $     */
 
 /*
  * Copyright (c) 2009 Miodrag Vallat.
@@ -679,6 +679,8 @@
 #define        MIPS_BREAK_INSTR        0x0000000d
 #define        MIPS_BREAK_VAL_MASK     0x03ff0000
 #define        MIPS_BREAK_VAL_SHIFT    16
+#define        MIPS_BREAK_INTOVERFLOW    6 /* used by gas to indicate int overflow */
+#define        MIPS_BREAK_INTDIVZERO     7 /* used by gas/gcc to indicate int div by zero */
 #define        MIPS_BREAK_KDB_VAL      512
 #define        MIPS_BREAK_SSTEP_VAL    513
 #define        MIPS_BREAK_BRKPT_VAL    514
diff -r ed171e115d05 -r 6c44f8c707a8 sys/arch/mips/mips/trap.c
--- a/sys/arch/mips/mips/trap.c Wed Mar 17 08:13:29 2021 +0000
+++ b/sys/arch/mips/mips/trap.c Wed Mar 17 11:05:37 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: trap.c,v 1.258 2021/03/13 17:14:11 skrll Exp $ */
+/*     $NetBSD: trap.c,v 1.259 2021/03/17 11:05:37 simonb Exp $        */
 
 /*
  * Copyright (c) 1988 University of Utah.
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.258 2021/03/13 17:14:11 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.259 2021/03/17 11:05:37 simonb Exp $");
 
 #include "opt_cputype.h"       /* which mips CPU levels do we support? */
 #include "opt_ddb.h"
@@ -159,7 +159,6 @@
 trap(uint32_t status, uint32_t cause, vaddr_t vaddr, vaddr_t pc,
     struct trapframe *tf)
 {
-       int type;
        struct lwp * const l = curlwp;
        struct proc * const p = curproc;
        struct trapframe * const utf = l->l_md.md_utf;
@@ -168,6 +167,9 @@
        ksiginfo_t ksi;
        extern void fswintrberr(void);
        void *onfault;
+       InstFmt insn;
+       uint32_t instr;
+       int type;
        int rv = 0;
 
        KSI_INIT_TRAP(&ksi);
@@ -547,21 +549,46 @@
                goto dopanic;
 #endif
        case T_BREAK+T_USER: {
-               uint32_t instr;
-
                /* compute address of break instruction */
                vaddr_t va = pc + (cause & MIPS_CR_BR_DELAY ? sizeof(int) : 0);
 
                /* read break instruction */
                instr = mips_ufetch32((void *)va);
+               insn.word = instr;
 
                if (l->l_md.md_ss_addr != va || instr != MIPS_BREAK_SSTEP) {
+                       bool advance_pc = false;
+
                        ksi.ksi_trap = type & ~T_USER;
                        ksi.ksi_signo = SIGTRAP;
                        ksi.ksi_addr = (void *)va;
                        ksi.ksi_code = TRAP_TRACE;
-                       /* we broke, skip it to avoid infinite loop */
-                       if (instr == MIPS_BREAK_INSTR)
+
+                       if ((insn.JType.op == OP_SPECIAL) &&
+                           (insn.RType.func == OP_BREAK)) {
+                               int code = (insn.RType.rs << 5) | insn.RType.rt;
+                               switch (code) {
+                               case 0:
+                                       /* we broke, skip it to avoid infinite loop */
+                                       advance_pc = true;
+                                       break;
+                               case MIPS_BREAK_INTOVERFLOW:
+                                       ksi.ksi_signo = SIGFPE;
+                                       ksi.ksi_code = FPE_INTOVF;
+                                       advance_pc = true;
+                                       break;
+                               case MIPS_BREAK_INTDIVZERO:
+                                       ksi.ksi_signo = SIGFPE;
+                                       ksi.ksi_code = FPE_INTDIV;
+                                       advance_pc = true;
+                                       break;
+                               default:
+                                       /* do nothing */
+                                       break;
+                               }
+                       }
+
+                       if (advance_pc)
                                tf->tf_regs[_R_PC] += 4;
                        break;
                }
@@ -627,12 +654,40 @@
                userret(l);
                return; /* GEN */
        case T_OVFLOW+T_USER:
-       case T_TRAP+T_USER:
+       case T_TRAP+T_USER: {
+               /* compute address of trap/faulting instruction */
+               vaddr_t va = pc + (cause & MIPS_CR_BR_DELAY ? sizeof(int) : 0);
+               bool advance_pc = false;
+
+               /* read break instruction */
+               instr = mips_ufetch32((void *)va);
+               insn.word = instr;
+
                ksi.ksi_trap = type & ~T_USER;
                ksi.ksi_signo = SIGFPE;
                ksi.ksi_addr = (void *)(intptr_t)pc /*utf->tf_regs[_R_PC]*/;
                ksi.ksi_code = FPE_FLTOVF; /* XXX */
+
+               if ((insn.JType.op == OP_SPECIAL) &&
+                   (insn.RType.func == OP_TEQ)) {
+                       int code = (insn.RType.rd << 5) | insn.RType.shamt;
+                       switch (code) {
+                       case MIPS_BREAK_INTOVERFLOW:
+                               ksi.ksi_code = FPE_INTOVF;
+                               advance_pc = true;
+                               break;
+                       case MIPS_BREAK_INTDIVZERO:
+                               ksi.ksi_code = FPE_INTDIV;
+                               advance_pc = true;
+                               break;
+                       }
+               }
+
+               /* XXX when else do we advance the PC? */
+               if (advance_pc)
+                       tf->tf_regs[_R_PC] += 4;
                break; /* SIGNAL */
+        }
        }
        utf->tf_regs[_R_CAUSE] = cause;
        utf->tf_regs[_R_BADVADDR] = vaddr;



Home | Main Index | Thread Index | Old Index