FP emulator patch

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

 



There has been some reports regarding FP emulator failures, which the
attached patch should solve.
The patch include a fix for emulation of instructions in a COP1
delay-slot, a fix for FP context switching and some additional stuff ,
which was needed to pass our torture test.

Ralf could you please apply this patch.

/Carsten


--
_    _ ____  ___   Carsten Langgaard   Mailto:carstenl@mips.com
|\  /|||___)(___   MIPS Denmark        Direct: +45 4486 5527
| \/ |||    ____)  Lautrupvang 4B      Switch: +45 4486 5555
  TECHNOLOGIES     2750 Ballerup       Fax...: +45 4486 5556
                   Denmark             http://www.mips.com


Index: linux/arch/mips/kernel/signal.c
===================================================================
RCS file: /cvs/linux/arch/mips/kernel/signal.c,v
retrieving revision 1.36
diff -u -r1.36 signal.c
--- linux/arch/mips/kernel/signal.c	2001/06/18 22:43:35	1.36
+++ linux/arch/mips/kernel/signal.c	2001/08/15 12:33:38
@@ -220,6 +220,8 @@
 
 	err |= __get_user(owned_fp, &sc->sc_ownedfp);
 	if (owned_fp) {
+		if (last_task_used_math && (last_task_used_math != current))
+			last_task_used_math->thread.cp0_status &= ~ST0_CU1;
 		err |= restore_fp_context(sc);
 		last_task_used_math = current;
 	}
@@ -353,12 +355,11 @@
 	owned_fp = (current == last_task_used_math);
 	err |= __put_user(owned_fp, &sc->sc_ownedfp);
 
-	if (current->used_math) {	/* fp is active.  */
+	if (owned_fp) { /* fp is active.  */
 		set_cp0_status(ST0_CU1);
 		err |= save_fp_context(sc);
 		last_task_used_math = NULL;
 		regs->cp0_status &= ~ST0_CU1;
-		current->used_math = 0;
 	}
 
 	return err;
@@ -375,6 +376,13 @@
 	/* Default to using normal stack */
 	sp = regs->regs[29];
 
+	/* 
+	 * FPU emulator may have it's own trampoline active just
+	 * above the user stack, 16-bytes before the next lowest
+	 * 16 byte boundary.  Try to avoid trashing it.
+	 */
+	sp -= 32;
+
 	/* This is the X/Open sanctioned signal stack switching.  */
 	if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
                 sp = current->sas_ss_sp + current->sas_ss_size;
@@ -435,7 +443,7 @@
 
 #if DEBUG_SIG
 	printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n",
-	       current->comm, current->pid, frame, regs->cp0_epc, frame->code);
+	       current->comm, current->pid, frame, regs->cp0_epc, frame->sf_code);
 #endif
         return;
 
Index: linux/arch/mips/kernel/unaligned.c
===================================================================
RCS file: /cvs/linux/arch/mips/kernel/unaligned.c,v
retrieving revision 1.12
diff -u -r1.12 unaligned.c
--- linux/arch/mips/kernel/unaligned.c	2001/07/11 22:05:11	1.12
+++ linux/arch/mips/kernel/unaligned.c	2001/08/15 12:33:38
@@ -365,15 +365,12 @@
 		return;
 	}
 
-	die_if_kernel ("Unhandled kernel unaligned access", regs);
 	send_sig(SIGSEGV, current, 1);
 	return;
 sigbus:
-	die_if_kernel ("Unhandled kernel unaligned access", regs);
 	send_sig(SIGBUS, current, 1);
 	return;
 sigill:
-	die_if_kernel ("Unhandled kernel unaligned access or invalid instruction", regs);
 	send_sig(SIGILL, current, 1);
 	return;
 }
@@ -391,11 +388,10 @@
 	 * of the CPU after executing the instruction
 	 * in the delay slot of an emulated branch.
 	 */
+	/* Terminate if exception was recognized as a delay slot return */
+	if(do_dsemulret(regs)) return;
 
-	if ((unsigned long)regs->cp0_epc == current->thread.dsemul_aerpc) {
-		do_dsemulret(regs);
-		return;
-	}
+	/* Otherwise handle as normal */
 
 	/*
 	 * Did we catch a fault trying to load an instruction?
@@ -417,7 +413,6 @@
 	return;
 
 sigbus:
-	die_if_kernel ("Kernel unaligned instruction access", regs);
 	force_sig(SIGBUS, current);
 
 	return;
Index: linux/arch/mips/math-emu/cp1emu.c
===================================================================
RCS file: /cvs/linux/arch/mips/math-emu/cp1emu.c,v
retrieving revision 1.7
diff -u -r1.7 cp1emu.c
--- linux/arch/mips/math-emu/cp1emu.c	2001/08/02 21:55:26	1.7
+++ linux/arch/mips/math-emu/cp1emu.c	2001/08/15 12:33:38
@@ -6,7 +6,7 @@
  * http://www.algor.co.uk
  *
  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 2000  MIPS Technologies, Inc.
+ * Copyright (C) 2000-2001  MIPS Technologies, Inc.
  *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
@@ -273,7 +273,10 @@
 			fpuemuprivate.stats.errors++;
 			return SIGBUS;
 		}
+		/* __computer_return_epc() will have updated cp0_epc */
 		contpc = REG_TO_VA xcp->cp0_epc;
+		/* In order not to confuse ptrace() et al, tweak context */
+		xcp->cp0_epc = VA_TO_REG emulpc - 4;
 	} else {
 		emulpc = REG_TO_VA xcp->cp0_epc;
 		contpc = REG_TO_VA xcp->cp0_epc + 4;
@@ -753,29 +756,73 @@
  *  execution of delay-slot instruction execution.
  */
 
+* Instruction inserted following delay slot instruction to force trap */
+
+#define AdELOAD 0x8c000001     /* lw $0,1($0) */
+
+/* Instruction inserted following the AdELOAD to further tag the sequence */
+
+#define BD_COOKIE 0x0000bd36 /* tne $0,$0 with baggage */
+
 int do_dsemulret(struct pt_regs *xcp)
 {
+	unsigned long *pinst;
+	unsigned long stackitem;
+	int err = 0;
+
+	/* See if this trap was deliberate. First check the instruction */
+
+	pinst = (unsigned long *) REG_TO_VA(xcp->cp0_epc);
+
+	/* 
+	 * If we can't even access the area, something is very
+	 * wrong, but we'll leave that to the default handling
+	 */
+	if (verify_area(VERIFY_READ, pinst, sizeof(unsigned long) * 3))
+		return 0;
+
+	/* Is the instruction pointed to by the EPC an AdELOAD? */
+	stackitem = mips_get_word(xcp, pinst, &err);
+	if (err || (stackitem != AdELOAD)) return 0;
+	/* Is the following memory word the BD_COOKIE? */
+	stackitem = mips_get_word(xcp, pinst+1, &err);
+	if (err || (stackitem != BD_COOKIE)) return 0;
+	
+	/* 
+	 * At this point, we are satisfied that it's a BD emulation 
+	 * trap.  Yes, a user might have deliberately put two
+	 * malformed and useless instructions in a row in his program,
+	 * in which case he's in for a nasty surprise - the
+	 * next instruction will be treated as a continuation
+	 * address!  Alas, this seems to be the only way that
+	 * we can handle signals, recursion, and longjmps()
+	 * in the context of emulating the branch delay instruction.
+	 */
+
 #ifdef DSEMUL_TRACE
 	printk("desemulret\n");
 #endif
+
+	/* Fetch the Saved EPC to Resume */
+ 
+	stackitem = mips_get_word(xcp, pinst+2, &err);
+	if (err) {
+		/* This is not a good situation to be in */
+		fpuemuprivate.stats.errors++;
+		force_sig(SIGBUS, current);
+		return(1);
+	}
+ 
 	/* Set EPC to return to post-branch instruction */
-	xcp->cp0_epc = current->thread.dsemul_epc;
-	/*
-	 * Clear the state that got us here.
-	 */
-	current->thread.dsemul_aerpc = (unsigned long) 0;
+	xcp->cp0_epc = stackitem;
 
-	return 0;
+	return 1;
 }
 
-
-#define AdELOAD 0x8c000001	/* lw $0,1($0) */
-
 static int
 mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc)
 {
 	mips_instruction *dsemul_insns;
-	mips_instruction forcetrap;
 	extern asmlinkage void handle_dsemulret(void);
 
 	if (ir == 0) {		/* a nop is easy */
@@ -791,13 +838,22 @@
 	 * and put a trap after it which we can catch and jump to 
 	 * the required address any alternative apart from full 
 	 * instruction emulation!!.
+	 * 
+	 * Algorithmics used a system call instruction, and
+	 * borrowed that vector.  MIPS/Linux version is a bit
+	 * more heavyweight in the interests of portability and
+	 * multiprocessor support.  We flag the thread for special
+	 * handling in the unaligned access handler and force an
+	 * address error excpetion.
 	 */
-	dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3);
-	dsemul_insns -= 3;	/* Two instructions, plus one for luck ;-) */
+
+	/* Ensure that the two instructions are in the same cache line */
+	dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~0xf);
+	dsemul_insns -= 4;      /* Retain 16-byte alignment */
 
 	/* Verify that the stack pointer is not competely insane */
 	if (verify_area(VERIFY_WRITE, dsemul_insns,
-	                sizeof(mips_instruction) * 2))
+	                sizeof(mips_instruction) * 4))
 		return SIGBUS;
 
 	if (mips_put_word(xcp, &dsemul_insns[0], ir)) {
@@ -805,29 +861,22 @@
 		return SIGBUS;
 	}
 
-	/* 
-	 * Algorithmics used a system call instruction, and
-	 * borrowed that vector.  MIPS/Linux version is a bit
-	 * more heavyweight in the interests of portability and
-	 * multiprocessor support.  We flag the thread for special
-	 * handling in the unaligned access handler and force an
-	 * address error excpetion.
-	 */
+	if (mips_put_word(xcp, &dsemul_insns[1], (mips_instruction)AdELOAD)) {
+		fpuemuprivate.stats.errors++;
+		return (SIGBUS);
+	}
 
-	/* If one is *really* paranoid, one tests for a bad stack pointer */
-	if ((xcp->regs[29] & 0x3) == 0x3)
-		forcetrap = AdELOAD - 1;
-	else
-		forcetrap = AdELOAD;
+	if (mips_put_word(xcp, &dsemul_insns[2], 
+			  (mips_instruction)BD_COOKIE)) {
+		fpuemuprivate.stats.errors++;
+		return (SIGBUS);
+	}
 
-	if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) {
+	if (mips_put_word(xcp, &dsemul_insns[3], (mips_instruction)cpc)) {
 		fpuemuprivate.stats.errors++;
 		return (SIGBUS);
 	}
 
-	/* Set thread state to catch and handle the exception */
-	current->thread.dsemul_epc = (unsigned long) cpc;
-	current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1];
 	xcp->cp0_epc = VA_TO_REG & dsemul_insns[0];
 	flush_cache_sigtramp((unsigned long) dsemul_insns);
 
Index: linux/arch/mips/math-emu/kernel_linkage.c
===================================================================
RCS file: /cvs/linux/arch/mips/math-emu/kernel_linkage.c,v
retrieving revision 1.3
diff -u -r1.3 kernel_linkage.c
--- linux/arch/mips/math-emu/kernel_linkage.c	2001/01/13 18:17:58	1.3
+++ linux/arch/mips/math-emu/kernel_linkage.c	2001/08/15 12:33:38
@@ -3,7 +3,7 @@
  *  arch/mips/math_emu/kernel_linkage.c
  *
  *  Kevin D. Kissell, kevink@mips and Carsten Langgaard, carstenl@mips.com
- *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *  Copyright (C) 2000-2001 MIPS Technologies, Inc.  All rights reserved.
  *
  * ########################################################################
  *
@@ -45,7 +45,7 @@
  
 	if (first) {
 		first = 0;
-		printk("Algorithmics/MIPS FPU Emulator v1.4\n");
+		printk("Algorithmics/MIPS FPU Emulator v1.5\n");
 	}
 
 	current->thread.fpu.soft.sr = 0;
Index: linux/arch/mips/tools/offset.c
===================================================================
RCS file: /cvs/linux/arch/mips/tools/offset.c,v
retrieving revision 1.16
diff -u -r1.16 offset.c
--- linux/arch/mips/tools/offset.c	2000/12/10 07:56:02	1.16
+++ linux/arch/mips/tools/offset.c	2001/08/15 12:33:39
@@ -121,10 +121,6 @@
 	       thread.irix_trampoline);
 	offset("#define THREAD_OLDCTX  ", struct task_struct, \
 	       thread.irix_oldctx);
-	offset("#define THREAD_DSEEPC  ", struct task_struct, \
-	       thread.dsemul_epc);
-	offset("#define THREAD_DSEAERPC ", struct task_struct, \
-	       thread.dsemul_aerpc);
 	linefeed;
 }
 
Index: linux/include/asm-mips/processor.h
===================================================================
RCS file: /cvs/linux/include/asm-mips/processor.h,v
retrieving revision 1.37
diff -u -r1.37 processor.h
--- linux/include/asm-mips/processor.h	2001/07/23 00:17:39	1.37
+++ linux/include/asm-mips/processor.h	2001/08/15 12:33:42
@@ -151,21 +151,6 @@
 	mm_segment_t current_ds;
 	unsigned long irix_trampoline;  /* Wheee... */
 	unsigned long irix_oldctx;
-
-	/*
-	 * These are really only needed if the full FPU emulator is configured.
-	 * Would be made conditional on MIPS_FPU_EMULATOR if it weren't for the
-	 * fact that having offset.h rebuilt differently for different config
-	 * options would be asking for trouble.
-	 *
-	 * Saved EPC during delay-slot emulation (see math-emu/cp1emu.c)
-	 */
-	unsigned long dsemul_epc;
-
-	/*
-	 * Pointer to instruction used to induce address error
-	 */
-	unsigned long dsemul_aerpc;
 };
 
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
@@ -195,11 +180,6 @@
 	 * For now the default is to fix address errors \
 	 */ \
 	MF_FIXADE, { 0 }, 0, 0, \
-	/* \
-	 * dsemul_epc and dsemul_aerpc should never be used uninitialized, \
-	 * but... \
-	 */ \
-	0 ,0 \
 }
 
 #ifdef __KERNEL__
@@ -235,8 +215,8 @@
  * Do necessary setup to start up a newly executed thread.
  */
 #define start_thread(regs, new_pc, new_sp) do {				\
-	/* New thread looses kernel privileges. */			\
-	regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU)) | KU_USER;\
+	/* New thread loses kernel and FPU privileges. */               \
+        regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU|ST0_CU1)) | KU_USER;\
 	regs->cp0_epc = new_pc;						\
 	regs->regs[29] = new_sp;					\
 	current->thread.current_ds = USER_DS;				\

[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux