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