diff options
| -rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 24 |
1 files changed, 23 insertions, 1 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 |
