summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2019-06-28 02:33:18 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2019-07-02 07:39:49 -0400
commit0a882e28468f48ab3d9a36dde0a5723ea29ed1ed (patch)
treeb8ae0e8f2a399a1030014b6ad6bdce4edc1695ab
parentf30a5e68f026f3214a9392391537adaa79996b24 (diff)
powerpc/64s/exception: remove bad stack branch
The bad stack test in interrupt handlers has a few problems. For performance it is taken in the common case, which is a fetch bubble and a waste of i-cache. For code development and maintainence, it requires yet another stack frame setup routine, and that constrains all exception handlers to follow the same register save pattern which inhibits future optimisation. Remove the test/branch and replace it with a trap. Teach the program check handler to use the emergency stack for this case. This does not result in quite so nice a message, however the SRR0 and SRR1 of the crashed interrupt can be seen in r11 and r12, as is the original r1 (adjusted by INT_FRAME_SIZE). These are the most important parts to debugging the issue. The original r9-12 and cr0 is lost, which is the main downside. kernel BUG at linux/arch/powerpc/kernel/exceptions-64s.S:847! Oops: Exception in kernel mode, sig: 5 [#1] BE SMP NR_CPUS=2048 NUMA PowerNV Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted NIP: c000000000009108 LR: c000000000cadbcc CTR: c0000000000090f0 REGS: c0000000fffcbd70 TRAP: 0700 Not tainted MSR: 9000000000021032 <SF,HV,ME,IR,DR,RI> CR: 28222448 XER: 20040000 CFAR: c000000000009100 IRQMASK: 0 GPR00: 000000000000003d fffffffffffffd00 c0000000018cfb00 c0000000f02b3166 GPR04: fffffffffffffffd 0000000000000007 fffffffffffffffb 0000000000000030 GPR08: 0000000000000037 0000000028222448 0000000000000000 c000000000ca8de0 GPR12: 9000000002009032 c000000001ae0000 c000000000010a00 0000000000000000 GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 GPR20: c0000000f00322c0 c000000000f85200 0000000000000004 ffffffffffffffff GPR24: fffffffffffffffe 0000000000000000 0000000000000000 000000000000000a GPR28: 0000000000000000 0000000000000000 c0000000f02b391c c0000000f02b3167 NIP [c000000000009108] decrementer_common+0x18/0x160 LR [c000000000cadbcc] .vsnprintf+0x3ec/0x4f0 Call Trace: Instruction dump: 996d098a 994d098b 38610070 480246ed 48005518 60000000 38200000 718a4000 7c2a0b78 3821fd00 41c20008 e82d0970 <0981fd00> f92101a0 f9610170 f9810178 Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/exception-64s.h7
-rw-r--r--arch/powerpc/include/asm/paca.h2
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S96
-rw-r--r--arch/powerpc/xmon/xmon.c2
5 files changed, 22 insertions, 87 deletions
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 40d114e69cbe..a77cdb07b152 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -48,13 +48,6 @@
48 */ 48 */
49#define MAX_MCE_DEPTH 4 49#define MAX_MCE_DEPTH 4
50 50
51/*
52 * EX_R3 is only used by the bad_stack handler. bad_stack reloads and
53 * saves DAR from SPRN_DAR, and EX_DAR is not used. So EX_R3 can overlap
54 * with EX_DAR.
55 */
56#define EX_R3 EX_DAR
57
58#ifdef __ASSEMBLY__ 51#ifdef __ASSEMBLY__
59 52
60#define STF_ENTRY_BARRIER_SLOT \ 53#define STF_ENTRY_BARRIER_SLOT \
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 62f27e0aef7c..a2f713034ed3 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -170,7 +170,9 @@ struct paca_struct {
170 u64 kstack; /* Saved Kernel stack addr */ 170 u64 kstack; /* Saved Kernel stack addr */
171 u64 saved_r1; /* r1 save for RTAS calls or PM or EE=0 */ 171 u64 saved_r1; /* r1 save for RTAS calls or PM or EE=0 */
172 u64 saved_msr; /* MSR saved here by enter_rtas */ 172 u64 saved_msr; /* MSR saved here by enter_rtas */
173#ifdef CONFIG_PPC_BOOK3E
173 u16 trap_save; /* Used when bad stack is encountered */ 174 u16 trap_save; /* Used when bad stack is encountered */
175#endif
174 u8 irq_soft_mask; /* mask for irq soft masking */ 176 u8 irq_soft_mask; /* mask for irq soft masking */
175 u8 irq_happened; /* irq happened while soft-disabled */ 177 u8 irq_happened; /* irq happened while soft-disabled */
176 u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ 178 u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8e02444e9d3d..524a7bba0ee5 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -270,7 +270,9 @@ int main(void)
270 OFFSET(ACCOUNT_STARTTIME_USER, paca_struct, accounting.starttime_user); 270 OFFSET(ACCOUNT_STARTTIME_USER, paca_struct, accounting.starttime_user);
271 OFFSET(ACCOUNT_USER_TIME, paca_struct, accounting.utime); 271 OFFSET(ACCOUNT_USER_TIME, paca_struct, accounting.utime);
272 OFFSET(ACCOUNT_SYSTEM_TIME, paca_struct, accounting.stime); 272 OFFSET(ACCOUNT_SYSTEM_TIME, paca_struct, accounting.stime);
273#ifdef CONFIG_PPC_BOOK3E
273 OFFSET(PACA_TRAP_SAVE, paca_struct, trap_save); 274 OFFSET(PACA_TRAP_SAVE, paca_struct, trap_save);
275#endif
274 OFFSET(PACA_SPRG_VDSO, paca_struct, sprg_vdso); 276 OFFSET(PACA_SPRG_VDSO, paca_struct, sprg_vdso);
275#else /* CONFIG_PPC64 */ 277#else /* CONFIG_PPC64 */
276#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 278#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index b7c15a2df4a0..c73e909470e3 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -411,14 +411,8 @@ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \
411 subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \ 411 subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \
412 beq- 1f; \ 412 beq- 1f; \
413 ld r1,PACAKSAVE(r13); /* kernel stack to use */ \ 413 ld r1,PACAKSAVE(r13); /* kernel stack to use */ \
4141: cmpdi cr1,r1,-INT_FRAME_SIZE; /* check if r1 is in userspace */ \ 4141: tdgei r1,-INT_FRAME_SIZE; /* trap if r1 is in userspace */ \
415 blt+ cr1,3f; /* abort if it is */ \ 415 EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,0; \
416 li r1,(trap); /* will be reloaded later */ \
417 sth r1,PACA_TRAP_SAVE(r13); \
418 std r3,area+EX_R3(r13); \
419 addi r3,r13,area; /* r3 -> where regs are saved*/ \
420 RESTORE_CTR(r1, area); \
421 b bad_stack; \
4223: EXCEPTION_PROLOG_COMMON_1(); \ 4163: EXCEPTION_PROLOG_COMMON_1(); \
423 kuap_save_amr_and_lock r9, r10, cr1, cr0; \ 417 kuap_save_amr_and_lock r9, r10, cr1, cr0; \
424 beq 4f; /* if from kernel mode */ \ 418 beq 4f; /* if from kernel mode */ \
@@ -428,7 +422,6 @@ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \
428 EXCEPTION_PROLOG_COMMON_3(trap); \ 422 EXCEPTION_PROLOG_COMMON_3(trap); \
429 ACCOUNT_STOLEN_TIME 423 ACCOUNT_STOLEN_TIME
430 424
431
432/* 425/*
433 * Exception where stack is already set in r1, r1 is saved in r10. 426 * Exception where stack is already set in r1, r1 is saved in r10.
434 * PPR save and CPU accounting is not done (for some reason). 427 * PPR save and CPU accounting is not done (for some reason).
@@ -1453,21 +1446,25 @@ EXC_COMMON_BEGIN(program_check_common)
1453 * we switch to the emergency stack if we're taking a TM Bad Thing from 1446 * we switch to the emergency stack if we're taking a TM Bad Thing from
1454 * the kernel. 1447 * the kernel.
1455 */ 1448 */
1456 li r10,MSR_PR /* Build a mask of MSR_PR .. */ 1449
1457 oris r10,r10,0x200000@h /* .. and SRR1_PROGTM */ 1450 andi. r10,r12,MSR_PR
1458 and r10,r10,r12 /* Mask SRR1 with that. */ 1451 bne 2f /* If userspace, go normal path */
1459 srdi r10,r10,8 /* Shift it so we can compare */ 1452
1460 cmpldi r10,(0x200000 >> 8) /* .. with an immediate. */ 1453 andis. r10,r12,(SRR1_PROGTM)@h
1461 bne 1f /* If != go to normal path. */ 1454 bne 1f /* If TM, emergency */
1462 1455
1463 /* SRR1 had PR=0 and SRR1_PROGTM=1, so use the emergency stack */ 1456 cmpdi r1,-INT_FRAME_SIZE /* check if r1 is in userspace */
1464 andi. r10,r12,MSR_PR; /* Set CR0 correctly for label */ 1457 blt 2f /* normal path if not */
1458
1459 /* Use the emergency stack */
14601: andi. r10,r12,MSR_PR /* Set CR0 correctly for label */
1465 /* 3 in EXCEPTION_PROLOG_COMMON */ 1461 /* 3 in EXCEPTION_PROLOG_COMMON */
1466 mr r10,r1 /* Save r1 */ 1462 mr r10,r1 /* Save r1 */
1467 ld r1,PACAEMERGSP(r13) /* Use emergency stack */ 1463 ld r1,PACAEMERGSP(r13) /* Use emergency stack */
1468 subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */ 1464 subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */
1469 b 3f /* Jump into the macro !! */ 1465 b 3f /* Jump into the macro !! */
14701: EXCEPTION_COMMON(PACA_EXGEN, 0x700) 14662:
1467 EXCEPTION_COMMON(PACA_EXGEN, 0x700)
1471 bl save_nvgprs 1468 bl save_nvgprs
1472 RECONCILE_IRQ_STATE(r10, r11) 1469 RECONCILE_IRQ_STATE(r10, r11)
1473 addi r3,r1,STACK_FRAME_OVERHEAD 1470 addi r3,r1,STACK_FRAME_OVERHEAD
@@ -2409,67 +2406,6 @@ handle_dabr_fault:
2409 b ret_from_except 2406 b ret_from_except
2410 2407
2411/* 2408/*
2412 * Here we have detected that the kernel stack pointer is bad.
2413 * R9 contains the saved CR, r13 points to the paca,
2414 * r10 contains the (bad) kernel stack pointer,
2415 * r11 and r12 contain the saved SRR0 and SRR1.
2416 * We switch to using an emergency stack, save the registers there,
2417 * and call kernel_bad_stack(), which panics.
2418 */
2419bad_stack:
2420 ld r1,PACAEMERGSP(r13)
2421 subi r1,r1,64+INT_FRAME_SIZE
2422 std r9,_CCR(r1)
2423 std r10,GPR1(r1)
2424 std r11,_NIP(r1)
2425 std r12,_MSR(r1)
2426 mfspr r11,SPRN_DAR
2427 mfspr r12,SPRN_DSISR
2428 std r11,_DAR(r1)
2429 std r12,_DSISR(r1)
2430 mflr r10
2431 mfctr r11
2432 mfxer r12
2433 std r10,_LINK(r1)
2434 std r11,_CTR(r1)
2435 std r12,_XER(r1)
2436 SAVE_GPR(0,r1)
2437 SAVE_GPR(2,r1)
2438 ld r10,EX_R3(r3)
2439 std r10,GPR3(r1)
2440 SAVE_GPR(4,r1)
2441 SAVE_4GPRS(5,r1)
2442 ld r9,EX_R9(r3)
2443 ld r10,EX_R10(r3)
2444 SAVE_2GPRS(9,r1)
2445 ld r9,EX_R11(r3)
2446 ld r10,EX_R12(r3)
2447 ld r11,EX_R13(r3)
2448 std r9,GPR11(r1)
2449 std r10,GPR12(r1)
2450 std r11,GPR13(r1)
2451BEGIN_FTR_SECTION
2452 ld r10,EX_CFAR(r3)
2453 std r10,ORIG_GPR3(r1)
2454END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
2455 SAVE_8GPRS(14,r1)
2456 SAVE_10GPRS(22,r1)
2457 lhz r12,PACA_TRAP_SAVE(r13)
2458 std r12,_TRAP(r1)
2459 addi r11,r1,INT_FRAME_SIZE
2460 std r11,0(r1)
2461 li r12,0
2462 std r12,0(r11)
2463 ld r2,PACATOC(r13)
2464 ld r11,exception_marker@toc(r2)
2465 std r12,RESULT(r1)
2466 std r11,STACK_FRAME_OVERHEAD-16(r1)
24671: addi r3,r1,STACK_FRAME_OVERHEAD
2468 bl kernel_bad_stack
2469 b 1b
2470_ASM_NOKPROBE_SYMBOL(bad_stack);
2471
2472/*
2473 * When doorbell is triggered from system reset wakeup, the message is 2409 * When doorbell is triggered from system reset wakeup, the message is
2474 * not cleared, so it would fire again when EE is enabled. 2410 * not cleared, so it would fire again when EE is enabled.
2475 * 2411 *
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index f1c4e1601b9d..f879e9fe9733 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -2454,7 +2454,9 @@ static void dump_one_paca(int cpu)
2454 DUMP(p, canary, "%#-*lx"); 2454 DUMP(p, canary, "%#-*lx");
2455#endif 2455#endif
2456 DUMP(p, saved_r1, "%#-*llx"); 2456 DUMP(p, saved_r1, "%#-*llx");
2457#ifdef CONFIG_PPC_BOOK3E
2457 DUMP(p, trap_save, "%#-*x"); 2458 DUMP(p, trap_save, "%#-*x");
2459#endif
2458 DUMP(p, irq_soft_mask, "%#-*x"); 2460 DUMP(p, irq_soft_mask, "%#-*x");
2459 DUMP(p, irq_happened, "%#-*x"); 2461 DUMP(p, irq_happened, "%#-*x");
2460#ifdef CONFIG_MMIOWB 2462#ifdef CONFIG_MMIOWB