|
@@ -156,7 +156,11 @@ machine_check_pSeries_1:
|
|
|
HMT_MEDIUM_PPR_DISCARD
|
|
|
SET_SCRATCH0(r13) /* save r13 */
|
|
|
EXCEPTION_PROLOG_0(PACA_EXMC)
|
|
|
+BEGIN_FTR_SECTION
|
|
|
+ b machine_check_pSeries_early
|
|
|
+FTR_SECTION_ELSE
|
|
|
b machine_check_pSeries_0
|
|
|
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
|
|
|
|
|
|
. = 0x300
|
|
|
.globl data_access_pSeries
|
|
@@ -405,6 +409,64 @@ denorm_exception_hv:
|
|
|
|
|
|
.align 7
|
|
|
/* moved from 0x200 */
|
|
|
+machine_check_pSeries_early:
|
|
|
+BEGIN_FTR_SECTION
|
|
|
+ EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
|
|
|
+ /*
|
|
|
+ * Register contents:
|
|
|
+ * R13 = PACA
|
|
|
+ * R9 = CR
|
|
|
+ * Original R9 to R13 is saved on PACA_EXMC
|
|
|
+ *
|
|
|
+ * Switch to mc_emergency stack and handle re-entrancy (though we
|
|
|
+ * currently don't test for overflow). Save MCE registers srr1,
|
|
|
+ * srr0, dar and dsisr and then set ME=1
|
|
|
+ *
|
|
|
+ * We use paca->in_mce to check whether this is the first entry or
|
|
|
+ * nested machine check. We increment paca->in_mce to track nested
|
|
|
+ * machine checks.
|
|
|
+ *
|
|
|
+ * If this is the first entry then set stack pointer to
|
|
|
+ * paca->mc_emergency_sp, otherwise r1 is already pointing to
|
|
|
+ * stack frame on mc_emergency stack.
|
|
|
+ *
|
|
|
+ * NOTE: We are here with MSR_ME=0 (off), which means we risk a
|
|
|
+ * checkstop if we get another machine check exception before we do
|
|
|
+ * rfid with MSR_ME=1.
|
|
|
+ */
|
|
|
+ mr r11,r1 /* Save r1 */
|
|
|
+ lhz r10,PACA_IN_MCE(r13)
|
|
|
+ cmpwi r10,0 /* Are we in nested machine check */
|
|
|
+ bne 0f /* Yes, we are. */
|
|
|
+ /* First machine check entry */
|
|
|
+ ld r1,PACAMCEMERGSP(r13) /* Use MC emergency stack */
|
|
|
+0: subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */
|
|
|
+ addi r10,r10,1 /* increment paca->in_mce */
|
|
|
+ sth r10,PACA_IN_MCE(r13)
|
|
|
+ std r11,GPR1(r1) /* Save r1 on the stack. */
|
|
|
+ std r11,0(r1) /* make stack chain pointer */
|
|
|
+ mfspr r11,SPRN_SRR0 /* Save SRR0 */
|
|
|
+ std r11,_NIP(r1)
|
|
|
+ mfspr r11,SPRN_SRR1 /* Save SRR1 */
|
|
|
+ std r11,_MSR(r1)
|
|
|
+ mfspr r11,SPRN_DAR /* Save DAR */
|
|
|
+ std r11,_DAR(r1)
|
|
|
+ mfspr r11,SPRN_DSISR /* Save DSISR */
|
|
|
+ std r11,_DSISR(r1)
|
|
|
+ std r9,_CCR(r1) /* Save CR in stackframe */
|
|
|
+ /* Save r9 through r13 from EXMC save area to stack frame. */
|
|
|
+ EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
|
|
|
+ mfmsr r11 /* get MSR value */
|
|
|
+ ori r11,r11,MSR_ME /* turn on ME bit */
|
|
|
+ ori r11,r11,MSR_RI /* turn on RI bit */
|
|
|
+ ld r12,PACAKBASE(r13) /* get high part of &label */
|
|
|
+ LOAD_HANDLER(r12, machine_check_handle_early)
|
|
|
+ mtspr SPRN_SRR0,r12
|
|
|
+ mtspr SPRN_SRR1,r11
|
|
|
+ rfid
|
|
|
+ b . /* prevent speculative execution */
|
|
|
+END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
|
|
|
+
|
|
|
machine_check_pSeries:
|
|
|
.globl machine_check_fwnmi
|
|
|
machine_check_fwnmi:
|
|
@@ -712,6 +774,55 @@ machine_check_common:
|
|
|
bl .machine_check_exception
|
|
|
b .ret_from_except
|
|
|
|
|
|
+#define MACHINE_CHECK_HANDLER_WINDUP \
|
|
|
+ /* Clear MSR_RI before setting SRR0 and SRR1. */\
|
|
|
+ li r0,MSR_RI; \
|
|
|
+ mfmsr r9; /* get MSR value */ \
|
|
|
+ andc r9,r9,r0; \
|
|
|
+ mtmsrd r9,1; /* Clear MSR_RI */ \
|
|
|
+ /* Move original SRR0 and SRR1 into the respective regs */ \
|
|
|
+ ld r9,_MSR(r1); \
|
|
|
+ mtspr SPRN_SRR1,r9; \
|
|
|
+ ld r3,_NIP(r1); \
|
|
|
+ mtspr SPRN_SRR0,r3; \
|
|
|
+ ld r9,_CTR(r1); \
|
|
|
+ mtctr r9; \
|
|
|
+ ld r9,_XER(r1); \
|
|
|
+ mtxer r9; \
|
|
|
+ ld r9,_LINK(r1); \
|
|
|
+ mtlr r9; \
|
|
|
+ REST_GPR(0, r1); \
|
|
|
+ REST_8GPRS(2, r1); \
|
|
|
+ REST_GPR(10, r1); \
|
|
|
+ ld r11,_CCR(r1); \
|
|
|
+ mtcr r11; \
|
|
|
+ /* Decrement paca->in_mce. */ \
|
|
|
+ lhz r12,PACA_IN_MCE(r13); \
|
|
|
+ subi r12,r12,1; \
|
|
|
+ sth r12,PACA_IN_MCE(r13); \
|
|
|
+ REST_GPR(11, r1); \
|
|
|
+ REST_2GPRS(12, r1); \
|
|
|
+ /* restore original r1. */ \
|
|
|
+ ld r1,GPR1(r1)
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Handle machine check early in real mode. We come here with
|
|
|
+ * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack.
|
|
|
+ */
|
|
|
+ .align 7
|
|
|
+ .globl machine_check_handle_early
|
|
|
+machine_check_handle_early:
|
|
|
+BEGIN_FTR_SECTION
|
|
|
+ std r0,GPR0(r1) /* Save r0 */
|
|
|
+ EXCEPTION_PROLOG_COMMON_3(0x200)
|
|
|
+ bl .save_nvgprs
|
|
|
+ addi r3,r1,STACK_FRAME_OVERHEAD
|
|
|
+ bl .machine_check_early
|
|
|
+ /* Deliver the machine check to host kernel in V mode. */
|
|
|
+ MACHINE_CHECK_HANDLER_WINDUP
|
|
|
+ b machine_check_pSeries
|
|
|
+END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
|
|
|
+
|
|
|
STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ)
|
|
|
STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt)
|
|
|
STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt)
|