Module Name:    src
Committed By:   jdc
Date:           Thu Aug  9 06:52:14 UTC 2012

Modified Files:
        src/sys/arch/powerpc/booke [netbsd-6]: genassym.cf trap_subr.S
        src/sys/arch/powerpc/include [netbsd-6]: frame.h

Log Message:
Pull up revisions:
  src/sys/arch/powerpc/booke/genassym.cf revision 1.9
  src/sys/arch/powerpc/booke/trap_subr.S revision 1.8
  src/sys/arch/powerpc/include/frame.h revision 1.25
(requested by matt in ticket #461).

Fix a problem where the kernel could randomly reset due to a watchdog event.
When an exception happens, the srr0 (exception PC) was being saved in the
normal location of the current callframe.  This was fine except when the
routine was in its prologue after it had saved LR but had not yet updated the
stack pointer or when the routine was in its epilogue after it has restored
the stack pointer but not yet loaded the LR.  In either case this would cause
the LR to be corrupted (either running the routine forever or by branching
to itself forever).  Now we save and restore the contents of that memory
location so the corruption can't happen.


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.8.8.1 src/sys/arch/powerpc/booke/genassym.cf
cvs rdiff -u -r1.6 -r1.6.8.1 src/sys/arch/powerpc/booke/trap_subr.S
cvs rdiff -u -r1.23 -r1.23.8.1 src/sys/arch/powerpc/include/frame.h

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/powerpc/booke/genassym.cf
diff -u src/sys/arch/powerpc/booke/genassym.cf:1.8 src/sys/arch/powerpc/booke/genassym.cf:1.8.8.1
--- src/sys/arch/powerpc/booke/genassym.cf:1.8	Wed Jun 29 06:06:04 2011
+++ src/sys/arch/powerpc/booke/genassym.cf	Thu Aug  9 06:52:14 2012
@@ -1,4 +1,4 @@
-#	$NetBSD: genassym.cf,v 1.8 2011/06/29 06:06:04 matt Exp $
+#	$NetBSD: genassym.cf,v 1.8.8.1 2012/08/09 06:52:14 jdc Exp $
 
 #-
 # Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
@@ -61,6 +61,7 @@ define	FRAME_MCSR	offsetof(struct ktrapf
 define	FRAME_MCAR	offsetof(struct ktrapframe, ktf_tf.tf_mcar)
 define	FRAME_SPRG1	offsetof(struct ktrapframe, ktf_tf.tf_sprg1)
 define	FRAME_SPEFSCR	offsetof(struct ktrapframe, ktf_tf.tf_spefscr)
+define	FRAME_CFRAME_LR	offsetof(struct ktrapframe, ktf_cframe_lr)
 
 define	CI_SAVELIFO	offsetof(struct cpu_info, ci_savearea[0])
 define	CI_PMAP_SEGTAB	offsetof(struct cpu_info, ci_pmap_segtabs[0])

Index: src/sys/arch/powerpc/booke/trap_subr.S
diff -u src/sys/arch/powerpc/booke/trap_subr.S:1.6 src/sys/arch/powerpc/booke/trap_subr.S:1.6.8.1
--- src/sys/arch/powerpc/booke/trap_subr.S:1.6	Tue Jun 21 05:33:04 2011
+++ src/sys/arch/powerpc/booke/trap_subr.S	Thu Aug  9 06:52:14 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: trap_subr.S,v 1.6 2011/06/21 05:33:04 matt Exp $	*/
+/*	$NetBSD: trap_subr.S,v 1.6.8.1 2012/08/09 06:52:14 jdc Exp $	*/
 /*-
  * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -34,7 +34,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-RCSID("$NetBSD: trap_subr.S,v 1.6 2011/06/21 05:33:04 matt Exp $")
+RCSID("$NetBSD: trap_subr.S,v 1.6.8.1 2012/08/09 06:52:14 jdc Exp $")
 
 	.globl	_C_LABEL(sctrapexit), _C_LABEL(trapexit), _C_LABEL(intrcall)
 
@@ -137,14 +137,24 @@ RCSID("$NetBSD: trap_subr.S,v 1.6 2011/0
 /*
  * DDB expects to fetch the LR from the previous frame.  But it also
  * expects to be pointing at the instruction after the branch link.  Since
- * we didn't branch, we need to advance it by to fake out DDB.
+ * we didn't branch, we need to advance it by to fake out DDB.  But there's
+ * problem.  If the routine is in either its first or last two instructions
+ * (before or after its adjusted its stack pointer), we could possibly
+ * overwrite stored return address.  So that stored return address needs to
+ * saved and restored.
  */
-#ifdef DDB
+#if defined(DDB)
 #define FRAME_SAVE_SRR0_FOR_DDB						\
-	addi	%r30, %r30, 4;		/* ddb thinks its the next insn */ \
-	stw	%r30, FRAMELEN+SZREG(%r1); /* appease ddb stacktrace */
+	lwz	%r29, FRAMELEN+CFRAME_LR(%r1);	/* fetch old return address */\
+	stw	%r29, FRAME_CFRAME_LR(%r1);	/* save it */		 \
+	addi	%r30, %r30, 4;			/* point to s the next insn */ \
+	stw	%r30, FRAMELEN+CFRAME_LR(%r1)	/* appease ddb stacktrace */
+#define FRAME_RESTORE_RETURN_ADDRESS					\
+	lwz	%r3, FRAME_CFRAME_LR(%r1);	/* fetch old return address */ \
+	stw	%r3, FRAMELEN+CFRAME_LR(%r1)	/* restore it */
 #else
 #define FRAME_SAVE_SRR0_FOR_DDB
+#define FRAME_RESTORE_RETURN_ADDRESS
 #endif
 
 #ifdef PPC_HAVE_SPE
@@ -175,7 +185,6 @@ RCSID("$NetBSD: trap_subr.S,v 1.6 2011/0
 	addi	%r1, %r2, USPACE-CALLFRAMELEN;				\
 					/* start stack at top of it */	\
 1:									\
-	stw	%r30, CFRAME_LR(%r1);	/* save in previous callframe */ \
 	stwu	%r31, -FRAMELEN(%r1);	/* get space for trapframe */	\
 	stw	%r0, FRAME_R0(%r1);	/* save r0 */			\
 	stw	%r31, FRAME_R1(%r1);	/* save (saved) r1 */		\
@@ -203,6 +212,7 @@ RCSID("$NetBSD: trap_subr.S,v 1.6 2011/0
 	addi	tf, %r1, FRAME_TF	/* get address of trap frame */
 
 #define FRAME_EXC_EXIT(rfi, srr)					\
+	FRAME_RESTORE_RETURN_ADDRESS;	/* restore return address */	\
 	lmw	%r26, FRAME_LR(%r1);	/* get LR CR XER CTR SRR0/1 */	\
 	oris	%r31,%r31,PSL_CE@h;					\
 	mtspr	SPR_##srr##1, %r31;	/* restore SRR1 */		\
@@ -262,7 +272,6 @@ RCSID("$NetBSD: trap_subr.S,v 1.6 2011/0
 	mtcr	%r31;			/* user mode exception? */	\
 	mr	%r31, %r1;		/* save SP (SRR1 is safe in CR) */ \
 	get_intr_sp;			/* get kernel stack pointer */	\
-	stw	%r30, CFRAME_LR(%r1);	/* save in .. */		\
 	stwu	%r31, -FRAMELEN(%r1);	/* get space for trapframe */	\
 	stw	%r0, FRAME_R0(%r1);	/* save r0 */			\
 	stw	%r31, FRAME_R1(%r1);	/* save (saved) r1 */		\
@@ -294,6 +303,7 @@ RCSID("$NetBSD: trap_subr.S,v 1.6 2011/0
 	addi	%r3, %r1, FRAME_TF	/* only argument is trapframe */
 
 #define FRAME_INTR_XEXIT(rfi, srr)					\
+	FRAME_RESTORE_RETURN_ADDRESS;	/* restore return address */	\
 	lwz	%r8, FRAME_LR(%r1);	/* get LR */			\
 	lwz	%r9, FRAME_CR(%r1);	/* get CR */			\
 	lwz	%r10, FRAME_XER(%r1);	/* get XER */			\

Index: src/sys/arch/powerpc/include/frame.h
diff -u src/sys/arch/powerpc/include/frame.h:1.23 src/sys/arch/powerpc/include/frame.h:1.23.8.1
--- src/sys/arch/powerpc/include/frame.h:1.23	Mon Jun 20 07:31:18 2011
+++ src/sys/arch/powerpc/include/frame.h	Thu Aug  9 06:52:14 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: frame.h,v 1.23 2011/06/20 07:31:18 matt Exp $	*/
+/*	$NetBSD: frame.h,v 1.23.8.1 2012/08/09 06:52:14 jdc Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -113,6 +113,7 @@ struct ktrapframe {
 	register_t ktf_sp;
 	register_t ktf_lr;
 	struct trapframe ktf_tf;
+	register_t ktf_cframe_lr;	/* for DDB */
 };
 
 #if defined(_KERNEL) || defined(_LKM)

Reply via email to