In fpu_emul_arith(), check lower 7 bits in word1 rather than only 6 bits

to check 040/060 FP instructions, and don't call fpu_implode() and
fpu_upd_fpsr() if no vaild emulated result is set otherwise these
functions cause NULL pointer dereference.

Fixes panics triggered by 040/060's FDADD instruction
(which has the same lower 6 bits with fscale instruction)
on 020/030 machines (even with 68881/68882) running kernels
with options FPU_EMULATE.
Problem reported by John Carr on port-sun3.

Should be pulled up to netbsd-4-0, netbsd-4 and netbsd-5.

XXX: m68k 4.0 packages binaries on ftp have this FDADD instruction.
This commit is contained in:
tsutsui 2009-01-20 14:57:21 +00:00
parent e80f4e9ccb
commit 7107680c9d

View File

@ -1,4 +1,4 @@
/* $NetBSD: fpu_emulate.c,v 1.27 2007/03/09 16:23:01 tsutsui Exp $ */
/* $NetBSD: fpu_emulate.c,v 1.28 2009/01/20 14:57:21 tsutsui Exp $ */
/*
* Copyright (c) 1995 Gordon W. Ross
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fpu_emulate.c,v 1.27 2007/03/09 16:23:01 tsutsui Exp $");
__KERNEL_RCSID(0, "$NetBSD: fpu_emulate.c,v 1.28 2009/01/20 14:57:21 tsutsui Exp $");
#include <sys/param.h>
#include <sys/types.h>
@ -753,8 +753,8 @@ fpu_emul_arith(fe, insn)
* pointer to the result.
*/
res = 0;
switch (word1 & 0x3f) {
res = NULL;
switch (word1 & 0x7f) {
case 0x00: /* fmove */
res = &fe->fe_f2;
break;
@ -910,7 +910,7 @@ fpu_emul_arith(fe, insn)
discard_result = 1;
break;
default:
default: /* possibly 040/060 instructions */
#ifdef DEBUG
printf("fpu_emul_arith: bad opcode=0x%x, word1=0x%x\n",
insn->is_opcode, insn->is_word1);
@ -918,8 +918,15 @@ fpu_emul_arith(fe, insn)
sig = SIGILL;
} /* switch (word1 & 0x3f) */
/* for sanity */
if (res == NULL)
sig = SIGILL;
if (!discard_result && sig == 0) {
fpu_implode(fe, res, FTYPE_EXT, &fpregs[regnum * 3]);
/* update fpsr according to the result of operation */
fpu_upd_fpsr(fe, res);
#if DEBUG_FPE
printf("fpu_emul_arith: %08x,%08x,%08x stored in FP%d\n",
fpregs[regnum*3], fpregs[regnum*3+1],
@ -937,9 +944,6 @@ fpu_emul_arith(fe, insn)
#endif
}
/* update fpsr according to the result of operation */
fpu_upd_fpsr(fe, res);
#if DEBUG_FPE
printf("fpu_emul_arith: FPSR = %08x, FPCR = %08x\n",
fe->fe_fpsr, fe->fe_fpcr);