Module Name: src Committed By: simonb Date: Wed Mar 17 11:05:37 UTC 2021
Modified Files: src/sys/arch/mips/include: cpuregs.h src/sys/arch/mips/mips: trap.c Log Message: 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 . To generate a diff of this commit: cvs rdiff -u -r1.109 -r1.110 src/sys/arch/mips/include/cpuregs.h cvs rdiff -u -r1.258 -r1.259 src/sys/arch/mips/mips/trap.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/mips/include/cpuregs.h diff -u src/sys/arch/mips/include/cpuregs.h:1.109 src/sys/arch/mips/include/cpuregs.h:1.110 --- src/sys/arch/mips/include/cpuregs.h:1.109 Sat Aug 22 03:41:33 2020 +++ src/sys/arch/mips/include/cpuregs.h Wed Mar 17 11:05:37 2021 @@ -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 Index: src/sys/arch/mips/mips/trap.c diff -u src/sys/arch/mips/mips/trap.c:1.258 src/sys/arch/mips/mips/trap.c:1.259 --- src/sys/arch/mips/mips/trap.c:1.258 Sat Mar 13 17:14:11 2021 +++ src/sys/arch/mips/mips/trap.c Wed Mar 17 11:05:37 2021 @@ -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 @@ void 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 @@ trap(uint32_t status, uint32_t cause, va 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 @@ trap(uint32_t status, uint32_t cause, va 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 @@ trap(uint32_t status, uint32_t cause, va 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;