Module Name:    src
Committed By:   isaki
Date:           Mon Jan  6 07:34:24 UTC 2025

Modified Files:
        src/sys/arch/m68k/fpe: fpu_emulate.c fpu_fscale.c

Log Message:
m68k/fpe: Avoid an illegal mod/reg before decoding it.
This also works for machines with FPU.
If the kernel defines FPU_EMULATE, even illegal FPU instructions in the real
6888x machines, the FPE will be executed by F line exception.  So the FPE
must raise SIGILL appropriately for these.


To generate a diff of this commit:
cvs rdiff -u -r1.48 -r1.49 src/sys/arch/m68k/fpe/fpu_emulate.c
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/m68k/fpe/fpu_fscale.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/m68k/fpe/fpu_emulate.c
diff -u src/sys/arch/m68k/fpe/fpu_emulate.c:1.48 src/sys/arch/m68k/fpe/fpu_emulate.c:1.49
--- src/sys/arch/m68k/fpe/fpu_emulate.c:1.48	Sat Dec 28 12:23:51 2024
+++ src/sys/arch/m68k/fpe/fpu_emulate.c	Mon Jan  6 07:34:24 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_emulate.c,v 1.48 2024/12/28 12:23:51 isaki Exp $	*/
+/*	$NetBSD: fpu_emulate.c,v 1.49 2025/01/06 07:34:24 isaki Exp $	*/
 
 /*
  * Copyright (c) 1995 Gordon W. Ross
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_emulate.c,v 1.48 2024/12/28 12:23:51 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_emulate.c,v 1.49 2025/01/06 07:34:24 isaki Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -338,10 +338,28 @@ fpu_emul_fmovmcr(struct fpemu *fe, struc
 	int reglist;
 	int regcount;
 	int fpu_to_mem;
+	int modreg;
 	uint32_t tmp[3];
 
 	/* move to/from control registers */
 	reglist = (insn->is_word1 & 0x1c00) >> 10;
+	/* Bit 13 selects direction (FPU to/from Mem) */
+	fpu_to_mem = insn->is_word1 & 0x2000;
+
+	/* Check an illegal mod/reg. */
+	modreg = insn->is_opcode & 077;
+	if (fpu_to_mem) {
+		/* PCrel, #imm are illegal. */
+		if (modreg >= 072) {
+			return SIGILL;
+		}
+	} else {
+		/* All mod/reg can be specified. */
+		if (modreg >= 075) {
+			return SIGILL;
+		}
+	}
+
 	/*
 	 * If reglist is 0b000, treat it as FPIAR.  This is not specification
 	 * but the behavior described in the 6888x user's manual.
@@ -357,7 +375,7 @@ fpu_emul_fmovmcr(struct fpemu *fe, struc
 		regcount = 1;
 	}
 	insn->is_datasize = regcount * 4;
-	sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
+	sig = fpu_decode_ea(frame, insn, &insn->is_ea, modreg);
 	if (sig)
 		return sig;
 
@@ -377,8 +395,6 @@ fpu_emul_fmovmcr(struct fpemu *fe, struc
 		}
 	}
 
-	/* Bit 13 selects direction (FPU to/from Mem) */
-	fpu_to_mem = insn->is_word1 & 0x2000;
 	if (fpu_to_mem) {
 		uint32_t *s = &tmp[0];
 
@@ -432,6 +448,7 @@ fpu_emul_fmovm(struct fpemu *fe, struct 
 	struct fpframe *fpf = fe->fe_fpframe;
 	int word1, sig;
 	int reglist, regmask, regnum;
+	int modreg;
 	int fpu_to_mem, order;
 	/* int w1_post_incr; */
 	int *fpregs;
@@ -458,8 +475,22 @@ fpu_emul_fmovm(struct fpemu *fe, struct 
 	}
 	reglist &= 0xFF;
 
-	/* Get effective address. (modreg=opcode&077) */
-	sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
+	/* Check an illegal mod/reg. */
+	modreg = insn->is_opcode & 077;
+	if (fpu_to_mem) {
+		/* Dn, An, (An)+, PCrel, #imm are illegal. */
+		if (modreg < 020 || (modreg >> 3) == 3 || modreg >= 072) {
+			return SIGILL;
+		}
+	} else {
+		/* Dn, An, -(An), #imm are illegal. */
+		if (modreg < 020 || (modreg >> 3) == 4 || modreg >= 074) {
+			return SIGILL;
+		}
+	}
+
+	/* Get effective address. */
+	sig = fpu_decode_ea(frame, insn, &insn->is_ea, modreg);
 	if (sig)
 		return sig;
 
@@ -571,6 +602,7 @@ fpu_emul_arith(struct fpemu *fe, struct 
 	struct fpn *res;
 	int word1, sig = 0;
 	int regnum, format;
+	int modreg;
 	int discard_result = 0;
 	uint32_t buf[3];
 #ifdef DEBUG_FPE
@@ -624,13 +656,26 @@ fpu_emul_arith(struct fpemu *fe, struct 
 			return sig;
 		}
 
-		/* Get effective address. (modreg=opcode&077) */
-		sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
+		/* Check an illegal mod/reg. */
+		modreg = insn->is_opcode & 077;
+		if ((modreg >> 3) == 1/*An*/ || modreg >= 075) {
+			return SIGILL;
+		}
+
+		/* Get effective address. */
+		sig = fpu_decode_ea(frame, insn, &insn->is_ea, modreg);
 		if (sig) {
 			DPRINTF(("%s: error in fpu_decode_ea\n", __func__));
 			return sig;
 		}
 
+		if (insn->is_ea.ea_flags == EA_DIRECT &&
+		    insn->is_datasize > 4) {
+			DPRINTF(("%s: attempted to fetch dbl/ext from reg\n",
+			    __func__));
+			return SIGILL;
+		}
+
 		DUMP_INSN(insn);
 
 #ifdef DEBUG_FPE

Index: src/sys/arch/m68k/fpe/fpu_fscale.c
diff -u src/sys/arch/m68k/fpe/fpu_fscale.c:1.16 src/sys/arch/m68k/fpe/fpu_fscale.c:1.17
--- src/sys/arch/m68k/fpe/fpu_fscale.c:1.16	Tue Mar 26 11:30:20 2013
+++ src/sys/arch/m68k/fpe/fpu_fscale.c	Mon Jan  6 07:34:24 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_fscale.c,v 1.16 2013/03/26 11:30:20 isaki Exp $	*/
+/*	$NetBSD: fpu_fscale.c,v 1.17 2025/01/06 07:34:24 isaki Exp $	*/
 
 /*
  * Copyright (c) 1995 Ken Nakata
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_fscale.c,v 1.16 2013/03/26 11:30:20 isaki Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_fscale.c,v 1.17 2025/01/06 07:34:24 isaki Exp $");
 
 #include <sys/types.h>
 #include <sys/signal.h>
@@ -54,6 +54,7 @@ fpu_emul_fscale(struct fpemu *fe, struct
 	uint32_t *fpregs;
 	int word1, sig;
 	int regnum, format;
+	int modreg;
 	int scale, sign, exp;
 	uint32_t m0, m1;
 	uint32_t buf[3], fpsr;
@@ -109,6 +110,12 @@ fpu_emul_fscale(struct fpemu *fe, struct
 			return sig;
 		}
 
+		/* Check an illegal mod/reg. */
+		modreg = insn->is_opcode & 077;
+		if ((modreg >> 3) == 1/*An*/ || modreg >= 075) {
+			return SIGILL;
+		}
+
 		/* Get effective address. (modreg=opcode&077) */
 		sig = fpu_decode_ea(frame, insn, &insn->is_ea, insn->is_opcode);
 		if (sig) {
@@ -118,6 +125,15 @@ fpu_emul_fscale(struct fpemu *fe, struct
 			return sig;
 		}
 
+		if (insn->is_ea.ea_flags == EA_DIRECT &&
+		    insn->is_datasize > 4) {
+#if DEBUG_FPE
+			printf("%s: attempted to fetch dbl/ext from reg\n",
+			    __func__);
+#endif
+			return SIGILL;
+		}
+
 #if DEBUG_FPE
 		printf("fpu_emul_fscale: addr mode = ");
 		flags = insn->is_ea.ea_flags;

Reply via email to