diff options
| -rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 24 | ||||
| -rw-r--r-- | arch/powerpc/kernel/signal_64.c | 13 |
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) | |||
| 734 | EXC_VIRT(program_check, 0x4700, 0x100, 0x700) | 734 | EXC_VIRT(program_check, 0x4700, 0x100, 0x700) |
| 735 | TRAMP_KVM(PACA_EXGEN, 0x700) | 735 | TRAMP_KVM(PACA_EXGEN, 0x700) |
| 736 | EXC_COMMON_BEGIN(program_check_common) | 736 | EXC_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 !! */ | ||
| 759 | 1: 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 | ||
