aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S24
-rw-r--r--arch/powerpc/kernel/signal_64.c13
2 files changed, 35 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 48da0f5d2f7f..b82586c53560 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -734,7 +734,29 @@ EXC_REAL(program_check, 0x700, 0x100)
734EXC_VIRT(program_check, 0x4700, 0x100, 0x700) 734EXC_VIRT(program_check, 0x4700, 0x100, 0x700)
735TRAMP_KVM(PACA_EXGEN, 0x700) 735TRAMP_KVM(PACA_EXGEN, 0x700)
736EXC_COMMON_BEGIN(program_check_common) 736EXC_COMMON_BEGIN(program_check_common)
737 EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) 737 /*
738 * It's possible to receive a TM Bad Thing type program check with
739 * userspace register values (in particular r1), but with SRR1 reporting
740 * that we came from the kernel. Normally that would confuse the bad
741 * stack logic, and we would report a bad kernel stack pointer. Instead
742 * we switch to the emergency stack if we're taking a TM Bad Thing from
743 * the kernel.
744 */
745 li r10,MSR_PR /* Build a mask of MSR_PR .. */
746 oris r10,r10,0x200000@h /* .. and SRR1_PROGTM */
747 and r10,r10,r12 /* Mask SRR1 with that. */
748 srdi r10,r10,8 /* Shift it so we can compare */
749 cmpldi r10,(0x200000 >> 8) /* .. with an immediate. */
750 bne 1f /* If != go to normal path. */
751
752 /* SRR1 had PR=0 and SRR1_PROGTM=1, so use the emergency stack */
753 andi. r10,r12,MSR_PR; /* Set CR0 correctly for label */
754 /* 3 in EXCEPTION_PROLOG_COMMON */
755 mr r10,r1 /* Save r1 */
756 ld r1,PACAEMERGSP(r13) /* Use emergency stack */
757 subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */
758 b 3f /* Jump into the macro !! */
7591: EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)
738 bl save_nvgprs 760 bl save_nvgprs
739 RECONCILE_IRQ_STATE(r10, r11) 761 RECONCILE_IRQ_STATE(r10, r11)
740 addi r3,r1,STACK_FRAME_OVERHEAD 762 addi r3,r1,STACK_FRAME_OVERHEAD
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index c83c115858c1..b2c002993d78 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -452,9 +452,20 @@ static long restore_tm_sigcontexts(struct task_struct *tsk,
452 if (MSR_TM_RESV(msr)) 452 if (MSR_TM_RESV(msr))
453 return -EINVAL; 453 return -EINVAL;
454 454
455 /* pull in MSR TM from user context */ 455 /* pull in MSR TS bits from user context */
456 regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK); 456 regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
457 457
458 /*
459 * Ensure that TM is enabled in regs->msr before we leave the signal
460 * handler. It could be the case that (a) user disabled the TM bit
461 * through the manipulation of the MSR bits in uc_mcontext or (b) the
462 * TM bit was disabled because a sufficient number of context switches
463 * happened whilst in the signal handler and load_tm overflowed,
464 * disabling the TM bit. In either case we can end up with an illegal
465 * TM state leading to a TM Bad Thing when we return to userspace.
466 */
467 regs->msr |= MSR_TM;
468
458 /* pull in MSR LE from user context */ 469 /* pull in MSR LE from user context */
459 regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE); 470 regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
460 471