RFC: WIP, Patch: bullet-proofing the system reset exception vector

linas at austin.ibm.com linas at austin.ibm.com
Thu Mar 11 11:19:45 EST 2004


Request for comment/ work in progress ...

The patch below tries to 'bullet-proof' the system-reset and machine-check
exceptions so that even if the system is fairly badly hosed, one might
still be able to invoke the kernel debugger.   Its not a perfect patch,
it doesn't solve all problems; I'm mostly trying to test the waters to
see if anyone is interested, or thinks this is a good idea or waste of
time (well, all of *my* ideas are *good* ideas :-) but maybe someone
has a better idea), or if anyone has special requests.

To be more precise, this patch attempts to handle a system-reset
exception, even if the exception pointer and/or the kernel stack
pointer is corrupted.  I'm fighting a hard hang due to a corrupted
stack pointer, have to use cpuctl to debug and thats no fun.  I'll
probably be doing more hacking on this over the next few days, possibly.

--linas

-------------- next part --------------
===== head.S 1.55 vs edited =====
--- 1.55/arch/ppc64/kernel/head.S	Sun Feb 29 20:24:55 2004
+++ edited/head.S	Wed Mar 10 14:55:27 2004
@@ -200,6 +200,13 @@
 #define EX_CCR   	60
 #define EX_TRAP   	60

+#if 0
+/* the stack pointer must start with 0xc000 or else its error */
+	rldicl	r21,r21,16,48    /* top sixteen bits right justified */
+	cmpli	crf3,1,r21,0xc000      /* compare to 0xc000 */
+	beq	crf3,
+#endif
+
 #define EXCEPTION_PROLOG_PSERIES(n,label)                                \
 	mtspr   SPRG2,r20;              /* use SPRG2 as scratch reg   */ \
 	mtspr   SPRG1,r21;              /* save r21                   */ \
@@ -234,6 +241,48 @@
 	mfcr    r23;                    /* save CR in r23             */ \
 	rfid

+/* This exception prolog is almost identical to that above, except
+ * that it makes the paranoid assumption that the paca exception
+ * stack pointer may be corrpted.  It is meant to be used for the
+ * SystemReset Exception, so that the 'little yellow button' will
+ * suceed in starting the debugger even if low-level subsystems
+ * are corrupted. */
+#define EXCEPTION_PROLOG_NMI_PSERIES(n,label)                       \
+	mtspr   SPRG2,r20;              /* use SPRG2 as scratch reg   */ \
+	mtspr   SPRG1,r21;              /* save r21                   */ \
+	mfspr   r20,SPRG3;              /* get paca virt addr         */ \
+	LOADADDR(r21,emergency_stack);     /* get exception stack ptr    */ \
+	addi    r21,r21,8;      \
+	std	r22,EX_R22(r21);	/* Save r22 in exc. frame     */ \
+	ld      r22,PACAEXCSP(r20);     /* get old exception stack ptr    */ \
+	std	r22,-8(r21);	/* Save old paca stack pointer where we can find it */ \
+	li	r22,n;                  /* Save the ex # in exc. frame*/ \
+	stw	r22,EX_TRAP(r21);	/*                            */ \
+	std	r23,EX_R23(r21);	/* Save r23 in exc. frame     */ \
+	mfspr   r22,SRR0;               /* EA of interrupted instr    */ \
+	std	r22,EX_SRR0(r21);	/* Save SRR0 in exc. frame    */ \
+	mfspr   r23,SRR1;               /* machine state at interrupt */ \
+	std	r23,EX_SRR1(r21);	/* Save SRR1 in exc. frame    */ \
+                                                                         \
+	mfspr   r23,DAR;                /* Save DAR in exc. frame      */ \
+	std	r23,EX_DAR(r21);	                                  \
+	mfspr	r23,DSISR;		/* Save DSISR in exc. frame    */ \
+	stw	r23,EX_DSISR(r21);	                                  \
+	mfspr	r23,SPRG2;		/* Save r20 in exc. frame      */ \
+	std	r23,EX_R20(r21);	                                  \
+                                                                         \
+	clrrdi  r22,r20,60;             /* Get 0xc part of the vaddr  */ \
+	ori	r22,r22,(label)@l;      /* add in the vaddr offset    */ \
+		                        /*   assumes *_common < 16b   */ \
+	mfmsr   r23;                                                     \
+	rotldi  r23,r23,4;                                               \
+	ori     r23,r23,0x32B;          /* Set IR, DR, RI, SF, ISF, HV*/ \
+	rotldi  r23,r23,60;             /* for generic handlers       */ \
+	mtspr   SRR0,r22;                                                \
+	mtspr   SRR1,r23;                                                \
+	mfcr    r23;                    /* save CR in r23             */ \
+	rfid
+
 /*
  * This is the start of the interrupt handlers for iSeries
  * This code runs with relocation on.
@@ -315,6 +364,54 @@
 	ld      r2,PACATOC(r20);	                                  \
 	mr	r13,r20

+/* More or less the same as "EXCEPTION_PROLOG_COMMON" except that
+ * we assume that r1 is corrupt, and that PACAKSAVE(r20) is
+ * corrupt, and so we use the known-good 'emergency stack' r21
+ * as the kernel stack.  Also sets paca to use 'paranoid_exception_stack'
+ * for future excpetions.
+ */
+#define EXCEPTION_PROLOG_BULLETPROOF                                 \
+	mfspr	r22,SPRG1;		/* Save r21 in exc. frame      */ \
+	std	r22,EX_R21(r21);	                                  \
+	LOADADDR(r22,paranoid_exception_stack); /* start a new except stack */ \
+	std     r22,PACAEXCSP(r20);     /* use this new stack in future */ \
+	mr      r22,r1;                 /* Save r1                     */ \
+	mr      r1,r21;                 /* use the emergency stack     */ \
+	subi    r1,r1,INT_FRAME_SIZE;   /* alloc frame on emergency stack */ \
+   std     r22,GPR1(r1);           /* save r1 in stackframe       */ \
+	std     0,0(r1);                /* dead-end stack chain pointer    */ \
+	std     r23,_CCR(r1);           /* save CR in stackframe       */ \
+	ld	r22,EX_R20(r21);	/* move r20 to stackframe      */ \
+	std	r22,GPR20(r1);		                                  \
+	ld	r23,EX_R21(r21);	/* move r21 to stackframe      */ \
+	std	r23,GPR21(r1);		                                  \
+	ld	r22,EX_R22(r21);	/* move r22 to stackframe      */ \
+	std	r22,GPR22(r1);		                                  \
+	ld	r23,EX_R23(r21);	/* move r23 to stackframe      */ \
+	std	r23,GPR23(r1);		                                  \
+	mflr    r22;                    /* save LR in stackframe       */ \
+	std     r22,_LINK(r1);                                            \
+	mfctr   r23;                    /* save CTR in stackframe      */ \
+	std     r23,_CTR(r1);                                             \
+	mfspr   r22,XER;                /* save XER in stackframe      */ \
+	std     r22,_XER(r1);                                             \
+	ld	r23,EX_DAR(r21);	/* move DAR to stackframe      */ \
+	std	r23,_DAR(r1);		                                  \
+	lwz     r22,EX_DSISR(r21);	/* move DSISR to stackframe    */ \
+	std	r22,_DSISR(r1);		                                  \
+	lbz	r22,PACAPROCENABLED(r20);                                 \
+	std	r22,SOFTE(r1);		                                  \
+	ld	r22,EX_SRR0(r21);	/* get SRR0 from exc. frame    */ \
+	ld	r23,EX_SRR1(r21);	/* get SRR1 from exc. frame    */ \
+	LOADADDR(r21,paranoid_exception_stack);     /* reset a new exception stack ptr    */ \
+	std     r21,PACAEXCSP(r20);                                       \
+	SAVE_GPR(0, r1);                /* save r0 in stackframe       */ \
+	SAVE_8GPRS(2, r1);              /* save r2 - r13 in stackframe */ \
+	SAVE_4GPRS(10, r1);                                               \
+	/* XXX TOC may be corrupted, fixme/workaround.... */ \
+	ld      r2,PACATOC(r20);	                                  \
+	mr	r13,r20
+
 /*
  * Note: code which follows this uses cr0.eq (set if from kernel),
  * r1, r22 (SRR0), and r23 (SRR1).
@@ -329,6 +426,12 @@
 label##_Pseries:				\
 	EXCEPTION_PROLOG_PSERIES( n, label##_common )

+#define NMI_EXCEPTION_PSERIES(n, label )	\
+	. = n;					\
+	.globl label##_Pseries;			\
+label##_Pseries:				\
+	EXCEPTION_PROLOG_NMI_PSERIES( n, label##_common )
+
 #define STD_EXCEPTION_ISERIES( n, label )	\
 	.globl label##_Iseries;			\
 label##_Iseries:				\
@@ -368,6 +471,17 @@
 	bl      hdlr;                           \
 	b       .ret_from_except

+#define BULLETPROOF_EXCEPTION_COMMON( trap, label, hdlr )	\
+	.globl label##_common;			\
+label##_common:					\
+	EXCEPTION_PROLOG_BULLETPROOF;		\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;	\
+	li	r20,0;				\
+	li	r6,trap;			\
+	bl      .save_remaining_regs;           \
+	bl      hdlr;                           \
+	b       .ret_from_except
+
 /*
  * Start of pSeries system interrupt routines
  */
@@ -375,8 +489,8 @@
 	.globl __start_interrupts
 __start_interrupts:

-	STD_EXCEPTION_PSERIES( 0x100, SystemReset )
-	STD_EXCEPTION_PSERIES( 0x200, MachineCheck )
+	NMI_EXCEPTION_PSERIES( 0x100, SystemReset )
+	NMI_EXCEPTION_PSERIES( 0x200, MachineCheck )
 	STD_EXCEPTION_PSERIES( 0x300, DataAccess )
 	STD_EXCEPTION_PSERIES( 0x380, DataAccessSLB )
 	STD_EXCEPTION_PSERIES( 0x400, InstructionAccess )
@@ -575,10 +689,10 @@
 	. = 0x8000
 	.globl SystemReset_FWNMI
 SystemReset_FWNMI:
-	EXCEPTION_PROLOG_PSERIES(0x100, SystemReset_common)
+	EXCEPTION_PROLOG_NMI_PSERIES(0x100, SystemReset_common)
 	.globl MachineCheck_FWNMI
 MachineCheck_FWNMI:
-	EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common)
+	EXCEPTION_PROLOG_NMI_PSERIES(0x200, MachineCheck_common)

 	/*
 	 * Space for the initial segment table
@@ -596,8 +710,8 @@

 /*** Common interrupt handlers ***/

-	STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
-	STD_EXCEPTION_COMMON( 0x200, MachineCheck, .MachineCheckException )
+	BULLETPROOF_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
+	BULLETPROOF_EXCEPTION_COMMON( 0x200, MachineCheck, .MachineCheckException )
 	STD_EXCEPTION_COMMON( 0x900, Decrementer, .timer_interrupt )
 	STD_EXCEPTION_COMMON( 0xa00, Trap_0a, .UnknownException )
 	STD_EXCEPTION_COMMON( 0xb00, Trap_0b, .UnknownException )
@@ -2178,6 +2292,19 @@
 stab_array:
         .space	4096 * 48

+/* System Reset Exception (emergency) stack */
+	.globl	emergency_stack
+emergency_stack:
+	.space 8192
+
+/* Alternate exception stack to use after emergency exception.
+ * We use this so that we can take additional exceptions without
+ * having to assume that the paca exception stack is uncorrupted.
+ */
+	.globl	paranoid_exception_stack
+paranoid_exception_stack:
+	.space 4096
+
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
  * Used to pass parameters into the kernel like root=/dev/sda1, etc.


More information about the Linuxppc64-dev mailing list