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;

Reply via email to