powerpc: Save register r9-r13 values accurately on interrupt with bad stack
authorPaul Mackerras <paulus@samba.org>
Sun, 1 May 2011 19:46:44 +0000 (19:46 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 4 May 2011 05:19:27 +0000 (15:19 +1000)
When we take an interrupt or exception from kernel mode and the stack
pointer is obviously not a kernel address (i.e. the top bit is 0), we
switch to an emergency stack, save register values and panic.  However,
on 64-bit server machines, we don't actually save the values of r9 - r13
at the time of the interrupt, but rather values corrupted by the
exception entry code for r12-r13, and nothing at all for r9-r11.

This fixes it by passing a pointer to the register save area in the paca
through to the bad_stack code in r3.  The register values are saved in
one of the paca register save areas (depending on which exception this
is).  Using the pointer in r3, the bad_stack code now retrieves the
saved values of r9 - r13 and stores them in the exception frame on the
emergency stack.  This also stores the normal exception frame marker
("regshere") in the exception frame.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/kernel/exceptions-64s.S

index d6b4849..96ccef1 100644 (file)
        beq-    1f;                                                        \
        ld      r1,PACAKSAVE(r13);      /* kernel stack to use          */ \
 1:     cmpdi   cr1,r1,0;               /* check if r1 is in userspace  */ \
-       bge-    cr1,2f;                 /* abort if it is               */ \
-       b       3f;                                                        \
-2:     li      r1,(n);                 /* will be reloaded later       */ \
+       blt+    cr1,3f;                 /* abort if it is               */ \
+       li      r1,(n);                 /* will be reloaded later       */ \
        sth     r1,PACA_TRAP_SAVE(r13);                                    \
+       std     r3,area+EX_R3(r13);                                        \
+       addi    r3,r13,area;            /* r3 -> where regs are saved*/    \
        b       bad_stack;                                                 \
 3:     std     r9,_CCR(r1);            /* save CR in stackframe        */ \
        std     r11,_NIP(r1);           /* save SRR0 in stackframe      */ \
index 226cc8c..27ca8b7 100644 (file)
@@ -461,9 +461,20 @@ bad_stack:
        std     r12,_XER(r1)
        SAVE_GPR(0,r1)
        SAVE_GPR(2,r1)
-       SAVE_4GPRS(3,r1)
-       SAVE_2GPRS(7,r1)
-       SAVE_10GPRS(12,r1)
+       ld      r10,EX_R3(r3)
+       std     r10,GPR3(r1)
+       SAVE_GPR(4,r1)
+       SAVE_4GPRS(5,r1)
+       ld      r9,EX_R9(r3)
+       ld      r10,EX_R10(r3)
+       SAVE_2GPRS(9,r1)
+       ld      r9,EX_R11(r3)
+       ld      r10,EX_R12(r3)
+       ld      r11,EX_R13(r3)
+       std     r9,GPR11(r1)
+       std     r10,GPR12(r1)
+       std     r11,GPR13(r1)
+       SAVE_8GPRS(14,r1)
        SAVE_10GPRS(22,r1)
        lhz     r12,PACA_TRAP_SAVE(r13)
        std     r12,_TRAP(r1)
@@ -472,6 +483,9 @@ bad_stack:
        li      r12,0
        std     r12,0(r11)
        ld      r2,PACATOC(r13)
+       ld      r11,exception_marker@toc(r2)
+       std     r12,RESULT(r1)
+       std     r11,STACK_FRAME_OVERHEAD-16(r1)
 1:     addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .kernel_bad_stack
        b       1b