This patch series includes some improvement to Machine check handler
for pSeries. Patch 1 fixes a buffer overrun issue if rtas extended error
log size is greater than RTAS_ERROR_LOG_MAX.
Patch 2 fixes an issue where machine check handler crashes
kernel while accessing vmalloc-ed buffer while in nmi context.
Patch 3 fixes endain bug while restoring of r3 in MCE handler.
Patch 5 implements a real mode mce handler and flushes the SLBs on SLB error.
Patch 6 display's the MCE error details on console.
Patch 7 saves and dumps the SLB contents on SLB MCE errors to improve the
debugability.
Patch 8 consolidates mce early real mode handling code.
Change in V6:
- Introduce patch 8 to consolidate early real mode handling code.
- Address Nick's comment on erroneous hunk.
Change in V5:
- Use min_t instead of max_t.
- Fix an issue reported by kbuild test robot and address review comments.
Change in V4:
- Flush the SLBs in real mode mce handler to handle SLB errors for entry 0.
- Allocate buffers per cpu to hold rtas error log and old slb contents.
- Defer the logging of rtas error log to irq work queue.
Change in V3:
- Moved patch 5 to patch 2
Change in V2:
- patch 3: Display additional info (NIP and task info) in MCE error details.
- patch 5: Fix endain bug while restoring of r3 in MCE handler.
---
Mahesh Salgaonkar (8):
powerpc/pseries: Avoid using the size greater than RTAS_ERROR_LOG_MAX.
powerpc/pseries: Defer the logging of rtas error to irq work queue.
powerpc/pseries: Fix endainness while restoring of r3 in MCE handler.
powerpc/pseries: Define MCE error event section.
powerpc/pseries: flush SLB contents on SLB MCE errors.
powerpc/pseries: Display machine check error details.
powerpc/pseries: Dump the SLB contents on SLB MCE errors.
powernv/pseries: consolidate code for mce early handling.
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 8 +
arch/powerpc/include/asm/machdep.h | 1
arch/powerpc/include/asm/paca.h | 4
arch/powerpc/include/asm/rtas.h | 116 ++++++++++++
arch/powerpc/kernel/exceptions-64s.S | 18 +-
arch/powerpc/kernel/mce.c | 16 +-
arch/powerpc/mm/slb.c | 63 +++++++
arch/powerpc/platforms/pseries/pseries.h | 1
arch/powerpc/platforms/pseries/ras.c | 242 +++++++++++++++++++++++--
arch/powerpc/platforms/pseries/setup.c | 27 +++
10 files changed, 471 insertions(+), 25 deletions(-)
--
Signature
From: Mahesh Salgaonkar <redacted>
The global mce data buffer that used to copy rtas error log is of 2048
(RTAS_ERROR_LOG_MAX) bytes in size. Before the copy we read
extended_log_length from rtas error log header, then use max of
extended_log_length and RTAS_ERROR_LOG_MAX as a size of data to be copied.
Ideally the platform (phyp) will never send extended error log with
size > 2048. But if that happens, then we have a risk of buffer overrun
and corruption. Fix this by using min_t instead.
Fixes: d368514c3097 ("powerpc: Fix corruption when grabbing FWNMI data")
Reported-by: Michal Suchanek <redacted>
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/platforms/pseries/ras.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Mahesh Salgaonkar <redacted>
rtas_log_buf is a buffer to hold RTAS event data that are communicated
to kernel by hypervisor. This buffer is then used to pass RTAS event
data to user through proc fs. This buffer is allocated from vmalloc
(non-linear mapping) area.
On Machine check interrupt, register r3 points to RTAS extended event
log passed by hypervisor that contains the MCE event. The pseries
machine check handler then logs this error into rtas_log_buf. The
rtas_log_buf is a vmalloc-ed (non-linear) buffer we end up taking up a
page fault (vector 0x300) while accessing it. Since machine check
interrupt handler runs in NMI context we can not afford to take any
page fault. Page faults are not honored in NMI context and causes
kernel panic. Apart from that, as Nick pointed out, pSeries_log_error()
also takes a spin_lock while logging error which is not safe in NMI
context. It may endup in deadlock if we get another MCE before releasing
the lock. Fix this by deferring the logging of rtas error to irq work queue.
Current implementation uses two different buffers to hold rtas error log
depending on whether extended log is provided or not. This makes bit
difficult to identify which buffer has valid data that needs to logged
later in irq work. Simplify this using single buffer, one per paca, and
copy rtas log to it irrespective of whether extended log is provided or
not. Allocate this buffer below RMA region so that it can be accessed
in real mode mce handler.
Fixes: b96672dd840f ("powerpc: Machine check interrupt is a non-maskable interrupt")
Cc: stable@vger.kernel.org
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/include/asm/paca.h | 3 ++
arch/powerpc/platforms/pseries/ras.c | 47 ++++++++++++++++++++++----------
arch/powerpc/platforms/pseries/setup.c | 16 +++++++++++
3 files changed, 51 insertions(+), 15 deletions(-)
@@ -251,6 +251,9 @@ struct paca_struct {void*rfi_flush_fallback_area;u64l1d_flush_size;#endif+#ifdef CONFIG_PPC_PSERIES+u8*mce_data_buf;/* buffer to hold per cpu rtas errlog */+#endif /* CONFIG_PPC_PSERIES */}____cacheline_aligned;externvoidcopy_mm_to_paca(structmm_struct*mm);
@@ -349,7 +356,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)staticstructrtas_error_log*fwnmi_get_errinfo(structpt_regs*regs){unsignedlong*savep;-structrtas_error_log*h,*errhdr=NULL;+structrtas_error_log*h;/* Mask top two bits */regs->gpr[3]&=~(0x3UL<<62);
@@ -362,22 +369,20 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)savep=__va(regs->gpr[3]);regs->gpr[3]=savep[0];/* restore original r3 */-/* If it isn't an extended log we can use the per cpu 64bit buffer */h=(structrtas_error_log*)&savep[1];+/* Use the per cpu buffer from paca to store rtas error log */+memset(local_paca->mce_data_buf,0,RTAS_ERROR_LOG_MAX);if(!rtas_error_extended(h)){-memcpy(this_cpu_ptr(&mce_data_buf),h,sizeof(__u64));-errhdr=(structrtas_error_log*)this_cpu_ptr(&mce_data_buf);+memcpy(local_paca->mce_data_buf,h,sizeof(__u64));}else{intlen,error_log_length;error_log_length=8+rtas_error_extended_log_length(h);len=min_t(int,error_log_length,RTAS_ERROR_LOG_MAX);-memset(global_mce_data_buf,0,RTAS_ERROR_LOG_MAX);-memcpy(global_mce_data_buf,h,len);-errhdr=(structrtas_error_log*)global_mce_data_buf;+memcpy(local_paca->mce_data_buf,h,len);}-returnerrhdr;+return(structrtas_error_log*)local_paca->mce_data_buf;}/* Call this when done with the data returned by FWNMI_get_errinfo.
@@ -422,6 +427,17 @@ int pSeries_system_reset_exception(struct pt_regs *regs)return0;/* need to perform reset */}+/*+*ProcessMCErtaserrlogevent.+*/+staticvoidmce_process_errlog_event(structirq_work*work)+{+structrtas_error_log*err;++err=fwnmi_get_errlog();+log_error((char*)err,ERR_TYPE_RTAS_LOG,0);+}+/**Seeifwecanrecoverfromamachinecheckexception.*Thisisonlycalledonpower4(orabove)andonlyvia
@@ -466,7 +482,8 @@ static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err)recovered=1;}-log_error((char*)err,ERR_TYPE_RTAS_LOG,0);+/* Queue irq work to log this rtas event later. */+irq_work_queue(&mce_errlog_process_work);returnrecovered;}
From: Mahesh Salgaonkar <redacted>
During Machine Check interrupt on pseries platform, register r3 points
RTAS extended event log passed by hypervisor. Since hypervisor uses r3
to pass pointer to rtas log, it stores the original r3 value at the
start of the memory (first 8 bytes) pointed by r3. Since hypervisor
stores this info and rtas log is in BE format, linux should make
sure to restore r3 value in correct endian format.
Without this patch when MCE handler, after recovery, returns to code that
that caused the MCE may end up with Data SLB access interrupt for invalid
address followed by kernel panic or hang.
[ 62.878965] Severe Machine check interrupt [Recovered]
[ 62.878968] NIP [d00000000ca301b8]: init_module+0x1b8/0x338 [bork_kernel]
[ 62.878969] Initiator: CPU
[ 62.878970] Error type: SLB [Multihit]
[ 62.878971] Effective address: d00000000ca70000
cpu 0xa: Vector: 380 (Data SLB Access) at [c0000000fc7775b0]
pc: c0000000009694c0: vsnprintf+0x80/0x480
lr: c0000000009698e0: vscnprintf+0x20/0x60
sp: c0000000fc777830
msr: 8000000002009033
dar: a803a30c000000d0
current = 0xc00000000bc9ef00
paca = 0xc00000001eca5c00 softe: 3 irq_happened: 0x01
pid = 8860, comm = insmod
[c0000000fc7778b0] c0000000009698e0 vscnprintf+0x20/0x60
[c0000000fc7778e0] c00000000016b6c4 vprintk_emit+0xb4/0x4b0
[c0000000fc777960] c00000000016d40c vprintk_func+0x5c/0xd0
[c0000000fc777980] c00000000016cbb4 printk+0x38/0x4c
[c0000000fc7779a0] d00000000ca301c0 init_module+0x1c0/0x338 [bork_kernel]
[c0000000fc777a40] c00000000000d9c4 do_one_initcall+0x54/0x230
[c0000000fc777b00] c0000000001b3b74 do_init_module+0x8c/0x248
[c0000000fc777b90] c0000000001b2478 load_module+0x12b8/0x15b0
[c0000000fc777d30] c0000000001b29e8 sys_finit_module+0xa8/0x110
[c0000000fc777e30] c00000000000b204 system_call+0x58/0x6c
--- Exception: c00 (System Call) at 00007fff8bda0644
SP (7fffdfbfe980) is in userspace
This patch fixes this issue.
Fixes: a08a53ea4c97 ("powerpc/le: Enable RTAS events support")
Cc: stable@vger.kernel.org
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/platforms/pseries/ras.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -367,7 +367,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)}savep=__va(regs->gpr[3]);-regs->gpr[3]=savep[0];/* restore original r3 */+regs->gpr[3]=be64_to_cpu(savep[0]);/* restore original r3 */h=(structrtas_error_log*)&savep[1];/* Use the per cpu buffer from paca to store rtas error log */
From: Mahesh Salgaonkar <redacted>
On pseries, the machine check error details are part of RTAS extended
event log passed under Machine check exception section. This patch adds
the definition of rtas MCE event section and related helper
functions.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/include/asm/rtas.h | 111 +++++++++++++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
From: Mahesh Salgaonkar <redacted>
On pseries, as of today system crashes if we get a machine check
exceptions due to SLB errors. These are soft errors and can be fixed by
flushing the SLBs so the kernel can continue to function instead of
system crash. We do this in real mode before turning on MMU. Otherwise
we would run into nested machine checks. This patch now fetches the
rtas error log in real mode and flushes the SLBs on SLB errors.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1
arch/powerpc/include/asm/machdep.h | 1
arch/powerpc/kernel/exceptions-64s.S | 42 +++++++++++++++++++++
arch/powerpc/kernel/mce.c | 16 +++++++-
arch/powerpc/mm/slb.c | 6 +++
arch/powerpc/platforms/pseries/pseries.h | 1
arch/powerpc/platforms/pseries/ras.c | 51 +++++++++++++++++++++++++
arch/powerpc/platforms/pseries/setup.c | 1
8 files changed, 116 insertions(+), 3 deletions(-)
@@ -108,6 +108,7 @@ struct machdep_calls {/* Early exception handlers called in realmode */int(*hmi_exception_early)(structpt_regs*regs);+int(*machine_check_early)(structpt_regs*regs);/* Called during machine check exception to retrive fixup address. */bool(*mce_check_early_recovery)(structpt_regs*regs);
@@ -427,6 +427,35 @@ int pSeries_system_reset_exception(struct pt_regs *regs)return0;/* need to perform reset */}+staticintmce_handle_error(structrtas_error_log*errp)+{+structpseries_errorlog*pseries_log;+structpseries_mc_errorlog*mce_log;+intdisposition=rtas_error_disposition(errp);+uint8_terror_type;++if(!rtas_error_extended(errp))+gotoout;++pseries_log=get_pseries_errorlog(errp,PSERIES_ELOG_SECT_ID_MCE);+if(pseries_log==NULL)+gotoout;++mce_log=(structpseries_mc_errorlog*)pseries_log->data;+error_type=rtas_mc_error_type(mce_log);++if((disposition==RTAS_DISP_NOT_RECOVERED)&&+(error_type==PSERIES_MC_ERROR_TYPE_SLB)){+/* Store the old slb content someplace. */+slb_flush_and_rebolt_realmode();+disposition=RTAS_DISP_FULLY_RECOVERED;+rtas_set_disposition_recovered(errp);+}++out:+returndisposition;+}+/**ProcessMCErtaserrlogevent.*/
@@ -503,11 +532,31 @@ int pSeries_machine_check_exception(struct pt_regs *regs)structrtas_error_log*errp;if(fwnmi_active){-errp=fwnmi_get_errinfo(regs);fwnmi_release_errinfo();+errp=fwnmi_get_errlog();if(errp&&recover_mce(regs,errp))return1;}return0;}++intpSeries_machine_check_realmode(structpt_regs*regs)+{+structrtas_error_log*errp;+intdisposition;++if(fwnmi_active){+errp=fwnmi_get_errinfo(regs);+/*+*Calltofwnmi_release_errinfo()inrealmodecauseskernel+*topanic.Hencewewillcallitassoonaswegointo+*virtualmode.+*/+disposition=mce_handle_error(errp);+if(disposition==RTAS_DISP_FULLY_RECOVERED)+return1;+}++return0;+}
From: Mahesh Salgaonkar <redacted>
Now that other platforms also implements real mode mce handler,
lets consolidate the code by sharing existing powernv machine check
early code. Rename machine_check_powernv_early to
machine_check_common_early and reuse the code.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/kernel/exceptions-64s.S | 56 +++++++---------------------------
1 file changed, 11 insertions(+), 45 deletions(-)
@@ -253,6 +253,7 @@ struct paca_struct {#endif#ifdef CONFIG_PPC_PSERIESu8*mce_data_buf;/* buffer to hold per cpu rtas errlog */+structslb_entry*mce_faulty_slbs;#endif /* CONFIG_PPC_PSERIES */}____cacheline_aligned;
@@ -575,7 +579,11 @@ static int mce_handle_error(struct rtas_error_log *errp)if((disposition==RTAS_DISP_NOT_RECOVERED)&&(error_type==PSERIES_MC_ERROR_TYPE_SLB)){-/* Store the old slb content someplace. */+/*+*Storetheoldslbcontentinpacabeforeflushing.Print+*thiswhenwegotovirtualmode.+*/+slb_save_contents(local_paca->mce_faulty_slbs);slb_flush_and_rebolt_realmode();disposition=RTAS_DISP_FULLY_RECOVERED;rtas_set_disposition_recovered(errp);
@@ -130,6 +133,13 @@ static void __init fwnmi_init(void)paca_ptrs[i]->mce_data_buf=mce_data_buf+(RTAS_ERROR_LOG_MAX*i);}++/* Allocate per cpu slb area to save old slb contents during MCE */+size=sizeof(structslb_entry)*mmu_slb_size*nr_cpus;+slb_ptr=__va(memblock_alloc_base(size,sizeof(structslb_entry),+ppc64_rma_size));+for_each_possible_cpu(i)+paca_ptrs[i]->mce_faulty_slbs=slb_ptr+(mmu_slb_size*i);}staticvoidpseries_8259_cascade(structirq_desc*desc)
From: Mahesh Salgaonkar <redacted>
Now that other platforms also implements real mode mce handler,
lets consolidate the code by sharing existing powernv machine check
early code. Rename machine_check_powernv_early to
machine_check_common_early and reuse the code.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/kernel/exceptions-64s.S | 56 +++++++---------------------------
1 file changed, 11 insertions(+), 45 deletions(-)
@@ -564,7 +528,9 @@ EXC_COMMON_BEGIN(machine_check_handle_early) 9: /* Deliver the machine check to host kernel in V mode. */ MACHINE_CHECK_HANDLER_WINDUP- b machine_check_pSeries+ SET_SCRATCH0(r13) /* save r13 */+ EXCEPTION_PROLOG_0(PACA_EXMC)+ b machine_check_pSeries_0
I'm not sure that's quite right. You're missing out testing the result
of the early handler call? Is this buggy in existing code too? We
should be testing that result in all cases, shouldn't we? But it doesn't
seem like we are.
Thanks,
Nick
From: Mahesh Salgaonkar <redacted>
Now that other platforms also implements real mode mce handler,
lets consolidate the code by sharing existing powernv machine check
early code. Rename machine_check_powernv_early to
machine_check_common_early and reuse the code.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/kernel/exceptions-64s.S | 56
+++++++--------------------------- 1 file changed, 11
insertions(+), 45 deletions(-)
diff --git a/arch/powerpc/kernel/exceptions-64s.S
b/arch/powerpc/kernel/exceptions-64s.S index
0038596b7906..3e877ec55d50 100644 ---
a/arch/powerpc/kernel/exceptions-64s.S +++
b/arch/powerpc/kernel/exceptions-64s.S @@ -243,14 +243,13 @@
EXC_REAL_BEGIN(machine_check, 0x200, 0x100)
SET_SCRATCH0(r13) /* save r13 */
EXCEPTION_PROLOG_0(PACA_EXMC) BEGIN_FTR_SECTION
- b machine_check_powernv_early
+ b machine_check_common_early
FTR_SECTION_ELSE
b machine_check_pSeries_0
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
EXC_REAL_END(machine_check, 0x200, 0x100)
EXC_VIRT_NONE(0x4200, 0x100)
-TRAMP_REAL_BEGIN(machine_check_powernv_early)
-BEGIN_FTR_SECTION
+TRAMP_REAL_BEGIN(machine_check_common_early)
EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
/*
* Register contents:
@@ -306,7 +305,9 @@ BEGIN_FTR_SECTION /* Save r9 through r13 from EXMC save area to stack frame.
*/ EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
mfmsr r11 /* get MSR value */
+BEGIN_FTR_SECTION
ori r11,r11,MSR_ME /* turn on ME bit
*/ +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
ori r11,r11,MSR_RI /* turn on RI bit
*/ LOAD_HANDLER(r12, machine_check_handle_early)
1: mtspr SPRN_SRR0,r12
*/ b 1b
b . /* prevent speculative execution */
-END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
TRAMP_REAL_BEGIN(machine_check_pSeries)
.globl machine_check_fwnmi
@@ -333,7 +333,7 @@ machine_check_fwnmi: SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_0(PACA_EXMC) BEGIN_FTR_SECTION- b machine_check_pSeries_early+ b machine_check_common_early END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE) machine_check_pSeries_0: EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200)
@@ -346,45 +346,6 @@ machine_check_pSeries_0: TRAMP_KVM_SKIP(PACA_EXMC, 0x200)-TRAMP_REAL_BEGIN(machine_check_pSeries_early)-BEGIN_FTR_SECTION- EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)- mr r10,r1 /* Save r1 */- ld r1,PACAMCEMERGSP(r13) /* Use MC emergency
stack */
- subi r1,r1,INT_FRAME_SIZE /* alloc stack
frame */
- mfspr r11,SPRN_SRR0 /* Save SRR0 */
- mfspr r12,SPRN_SRR1 /* Save SRR1 */
- EXCEPTION_PROLOG_COMMON_1()
- EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
- EXCEPTION_PROLOG_COMMON_3(0x200)
- addi r3,r1,STACK_FRAME_OVERHEAD
- BRANCH_LINK_TO_FAR(machine_check_early) /* Function call
ABI */ -
- /* 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
- REST_GPR(11, r1)
- REST_2GPRS(12, r1)
- /* restore original r1. */
- ld r1,GPR1(r1)
- SET_SCRATCH0(r13) /* save r13 */
- EXCEPTION_PROLOG_0(PACA_EXMC)
- b machine_check_pSeries_0
-END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE)
-
EXC_COMMON_BEGIN(machine_check_common)
/*
* Machine check is different because we use a different
@@ -483,6 +444,9 @@ EXC_COMMON_BEGIN(machine_check_handle_early) bl machine_check_early std r3,RESULT(r1) /* Save result */ ld r12,_MSR(r1)+BEGIN_FTR_SECTION+ bne 9f /* pSeries: continue
to V mode. */ +END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE)
Should this be "b 9f" ? Although...
quoted
#ifdef CONFIG_PPC_P7_NAP
/*
@@ -564,7 +528,9 @@ EXC_COMMON_BEGIN(machine_check_handle_early) 9: /* Deliver the machine check to host kernel in V mode. */ MACHINE_CHECK_HANDLER_WINDUP- b machine_check_pSeries+ SET_SCRATCH0(r13) /* save r13 */+ EXCEPTION_PROLOG_0(PACA_EXMC)+ b machine_check_pSeries_0
I'm not sure that's quite right. You're missing out testing the result
of the early handler call? Is this buggy in existing code too? We
should be testing that result in all cases, shouldn't we? But it
doesn't seem like we are.
At least for the pSeries case the result of realmode handler is stored
in the MCE log data. Both the real and virtual part of the handler
should be called in any case. They do different and independent things.
Thanks
Michal
From: Mahesh Salgaonkar <redacted>
On pseries, as of today system crashes if we get a machine check
exceptions due to SLB errors. These are soft errors and can be fixed
by flushing the SLBs so the kernel can continue to function instead of
system crash. We do this in real mode before turning on MMU. Otherwise
we would run into nested machine checks. This patch now fetches the
rtas error log in real mode and flushes the SLBs on SLB errors.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1
arch/powerpc/include/asm/machdep.h | 1
arch/powerpc/kernel/exceptions-64s.S | 42
+++++++++++++++++++++ arch/powerpc/kernel/mce.c
| 16 +++++++- arch/powerpc/mm/slb.c | 6
@@ -488,9 +488,21 @@ long machine_check_early(struct pt_regs *regs){longhandled=0;-__this_cpu_inc(irq_stat.mce_exceptions);+/*+*ForpSerieswecountmcewhenwegointovirtualmode
machine
+ * check handler. Hence skip it. Also, We can't access per
cpu
+ * variables in real mode for LPAR.
+ */
+ if (early_cpu_has_feature(CPU_FTR_HVMODE))
+ __this_cpu_inc(irq_stat.mce_exceptions);
Maybe we could simplify the condition
if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !cpu_has_feature(CPU_FTR_HVMODE))
in machine_check instead?
Thanks
Michal
From: Mahesh Salgaonkar <redacted>
On pseries, as of today system crashes if we get a machine check
exceptions due to SLB errors. These are soft errors and can be fixed by
flushing the SLBs so the kernel can continue to function instead of
system crash. We do this in real mode before turning on MMU. Otherwise
we would run into nested machine checks. This patch now fetches the
rtas error log in real mode and flushes the SLBs on SLB errors.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1
arch/powerpc/include/asm/machdep.h | 1
arch/powerpc/kernel/exceptions-64s.S | 42 +++++++++++++++++++++
arch/powerpc/kernel/mce.c | 16 +++++++-
arch/powerpc/mm/slb.c | 6 +++
arch/powerpc/platforms/pseries/pseries.h | 1
arch/powerpc/platforms/pseries/ras.c | 51 +++++++++++++++++++++++++
arch/powerpc/platforms/pseries/setup.c | 1
8 files changed, 116 insertions(+), 3 deletions(-)
@@ -108,6 +108,7 @@ struct machdep_calls {/* Early exception handlers called in realmode */int(*hmi_exception_early)(structpt_regs*regs);+int(*machine_check_early)(structpt_regs*regs);/* Called during machine check exception to retrive fixup address. */bool(*mce_check_early_recovery)(structpt_regs*regs);
I think this should do something more like flush_and_reload_slb from
powernv machine check code. We are real mode so should invalidate all
SLBs.
It happens I also need very similar code (without the initial
invalidate) for implementing idle wakeup code in C, so we should move
that function and variants into mm/slb.c IMO.
Thanks,
Nick
From: Mahesh Salgaonkar <redacted>
=20
Now that other platforms also implements real mode mce handler,
lets consolidate the code by sharing existing powernv machine check
early code. Rename machine_check_powernv_early to
machine_check_common_early and reuse the code.
=20
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/kernel/exceptions-64s.S | 56
+++++++--------------------------- 1 file changed, 11
insertions(+), 45 deletions(-)
=20
diff --git a/arch/powerpc/kernel/exceptions-64s.S
b/arch/powerpc/kernel/exceptions-64s.S index
0038596b7906..3e877ec55d50 100644 ---
a/arch/powerpc/kernel/exceptions-64s.S +++
b/arch/powerpc/kernel/exceptions-64s.S @@ -243,14 +243,13 @@
EXC_REAL_BEGIN(machine_check, 0x200, 0x100)
SET_SCRATCH0(r13) /* save r13 */
EXCEPTION_PROLOG_0(PACA_EXMC) BEGIN_FTR_SECTION
- b machine_check_powernv_early
+ b machine_check_common_early
FTR_SECTION_ELSE
b machine_check_pSeries_0
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
EXC_REAL_END(machine_check, 0x200, 0x100)
EXC_VIRT_NONE(0x4200, 0x100)
-TRAMP_REAL_BEGIN(machine_check_powernv_early)
-BEGIN_FTR_SECTION
+TRAMP_REAL_BEGIN(machine_check_common_early)
EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
/*
* Register contents:
@@ -306,7 +305,9 @@ BEGIN_FTR_SECTION /* Save r9 through r13 from EXMC save area to stack frame.
*/ EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
mfmsr r11 /* get MSR value */
+BEGIN_FTR_SECTION
ori r11,r11,MSR_ME /* turn on ME bit
*/ +END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
ori r11,r11,MSR_RI /* turn on RI bit
*/ LOAD_HANDLER(r12, machine_check_handle_early)
1: mtspr SPRN_SRR0,r12
*/ b 1b
b . /* prevent speculative execution */
-END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
=20
TRAMP_REAL_BEGIN(machine_check_pSeries)
.globl machine_check_fwnmi
@@ -333,7 +333,7 @@ machine_check_fwnmi: SET_SCRATCH0(r13) /* save r13 */ EXCEPTION_PROLOG_0(PACA_EXMC) BEGIN_FTR_SECTION- b machine_check_pSeries_early+ b machine_check_common_early END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE) machine_check_pSeries_0: EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200)
@@ -346,45 +346,6 @@ machine_check_pSeries_0:
=20
TRAMP_KVM_SKIP(PACA_EXMC, 0x200)
=20
-TRAMP_REAL_BEGIN(machine_check_pSeries_early)
-BEGIN_FTR_SECTION
- EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
- mr r10,r1 /* Save r1 */
- ld r1,PACAMCEMERGSP(r13) /* Use MC emergency
stack */
- subi r1,r1,INT_FRAME_SIZE /* alloc stack
frame */
- mfspr r11,SPRN_SRR0 /* Save SRR0 */
- mfspr r12,SPRN_SRR1 /* Save SRR1 */
- EXCEPTION_PROLOG_COMMON_1()
- EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
- EXCEPTION_PROLOG_COMMON_3(0x200)
- addi r3,r1,STACK_FRAME_OVERHEAD
- BRANCH_LINK_TO_FAR(machine_check_early) /* Function call
ABI */ -
- /* 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
- REST_GPR(11, r1)
- REST_2GPRS(12, r1)
- /* restore original r1. */
- ld r1,GPR1(r1)
- SET_SCRATCH0(r13) /* save r13 */
- EXCEPTION_PROLOG_0(PACA_EXMC)
- b machine_check_pSeries_0
-END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE)
-
EXC_COMMON_BEGIN(machine_check_common)
/*
* Machine check is different because we use a different
@@ -483,6 +444,9 @@ EXC_COMMON_BEGIN(machine_check_handle_early) bl machine_check_early std r3,RESULT(r1) /* Save result */ ld r12,_MSR(r1)+BEGIN_FTR_SECTION+ bne 9f /* pSeries: continue
to V mode. */ +END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE) =20
=20
Should this be "b 9f" ? Although...
=20
quoted
=20
#ifdef CONFIG_PPC_P7_NAP
/*
@@ -564,7 +528,9 @@ EXC_COMMON_BEGIN(machine_check_handle_early) 9: /* Deliver the machine check to host kernel in V mode. */ MACHINE_CHECK_HANDLER_WINDUP- b machine_check_pSeries+ SET_SCRATCH0(r13) /* save r13 */+ EXCEPTION_PROLOG_0(PACA_EXMC)+ b machine_check_pSeries_0 =20
=20
I'm not sure that's quite right. You're missing out testing the result
of the early handler call? Is this buggy in existing code too? We
should be testing that result in all cases, shouldn't we? But it
doesn't seem like we are. =20
=20
At least for the pSeries case the result of realmode handler is stored
in the MCE log data. Both the real and virtual part of the handler
should be called in any case. They do different and independent things.
Hmm, well the return code of the function in the powernv case is put
into regs->result which is missing here, but I guess it gets picked
up again when the pseries code is consolidated back with powernv.
But... maybe that result is not actually used anywhere though. I
guess that's okay, maybe we should just make it return void though.
We want to avoid the case of going to virtual mode if we have errors
in the SLB or TLB that causes a recursive MCE, but the recursion
limit will eventually catch that and checkstop us which might be
the sanest option.
Thanks,
Nick
From: Mahesh Salgaonkar <redacted>
On pseries, as of today system crashes if we get a machine check
exceptions due to SLB errors. These are soft errors and can be fixed by
flushing the SLBs so the kernel can continue to function instead of
system crash. We do this in real mode before turning on MMU. Otherwise
we would run into nested machine checks. This patch now fetches the
rtas error log in real mode and flushes the SLBs on SLB errors.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1
arch/powerpc/include/asm/machdep.h | 1
arch/powerpc/kernel/exceptions-64s.S | 42 +++++++++++++++++++++
arch/powerpc/kernel/mce.c | 16 +++++++-
arch/powerpc/mm/slb.c | 6 +++
arch/powerpc/platforms/pseries/pseries.h | 1
arch/powerpc/platforms/pseries/ras.c | 51 +++++++++++++++++++++++++
arch/powerpc/platforms/pseries/setup.c | 1
8 files changed, 116 insertions(+), 3 deletions(-)
@@ -108,6 +108,7 @@ struct machdep_calls {/* Early exception handlers called in realmode */int(*hmi_exception_early)(structpt_regs*regs);+int(*machine_check_early)(structpt_regs*regs);/* Called during machine check exception to retrive fixup address. */bool(*mce_check_early_recovery)(structpt_regs*regs);
I think this should do something more like flush_and_reload_slb from
powernv machine check code. We are real mode so should invalidate all
SLBs.
Yes, and I think even powernv code should use this one instead. But that
can be a separate patch.
It happens I also need very similar code (without the initial
invalidate) for implementing idle wakeup code in C, so we should move
that function and variants into mm/slb.c IMO.
From: Mahesh Salgaonkar <redacted>
On pseries, as of today system crashes if we get a machine check
exceptions due to SLB errors. These are soft errors and can be fixed by
flushing the SLBs so the kernel can continue to function instead of
system crash. We do this in real mode before turning on MMU. Otherwise
we would run into nested machine checks. This patch now fetches the
rtas error log in real mode and flushes the SLBs on SLB errors.
Signed-off-by: Mahesh Salgaonkar <redacted>
---
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 1
arch/powerpc/include/asm/machdep.h | 1
arch/powerpc/kernel/exceptions-64s.S | 42 +++++++++++++++++++++
arch/powerpc/kernel/mce.c | 16 +++++++-
arch/powerpc/mm/slb.c | 6 +++
arch/powerpc/platforms/pseries/pseries.h | 1
arch/powerpc/platforms/pseries/ras.c | 51 +++++++++++++++++++++++++
arch/powerpc/platforms/pseries/setup.c | 1
8 files changed, 116 insertions(+), 3 deletions(-)
@@ -108,6 +108,7 @@ struct machdep_calls {/* Early exception handlers called in realmode */int(*hmi_exception_early)(structpt_regs*regs);+int(*machine_check_early)(structpt_regs*regs);/* Called during machine check exception to retrive fixup address. */bool(*mce_check_early_recovery)(structpt_regs*regs);
I think this should do something more like flush_and_reload_slb from
powernv machine check code. We are real mode so should invalidate all
SLBs.
Yes, and I think even powernv code should use this one instead. But that
can be a separate patch.
Well I've already got one written for the idle code, so I'll split that
out and send that to powerpc next first, so both our patches can use it.
quoted
It happens I also need very similar code (without the initial
invalidate) for implementing idle wakeup code in C, so we should move
that function and variants into mm/slb.c IMO.
So, you looking for only rebolt part ?
Yes it's already flushed after we come back from deep idle state, so
no need for another flush.
Thanks,
Nick
From: Michael Ellerman <hidden> Date: 2018-08-08 14:25:43
On Wed, 2018-07-04 at 17:57:02 UTC, Mahesh J Salgaonkar wrote:
From: Mahesh Salgaonkar <redacted>
The global mce data buffer that used to copy rtas error log is of 2048
(RTAS_ERROR_LOG_MAX) bytes in size. Before the copy we read
extended_log_length from rtas error log header, then use max of
extended_log_length and RTAS_ERROR_LOG_MAX as a size of data to be copied.
Ideally the platform (phyp) will never send extended error log with
size > 2048. But if that happens, then we have a risk of buffer overrun
and corruption. Fix this by using min_t instead.
Fixes: d368514c3097 ("powerpc: Fix corruption when grabbing FWNMI data")
Reported-by: Michal Suchanek <redacted>
Signed-off-by: Mahesh Salgaonkar <redacted>
From: Michael Ellerman <hidden> Date: 2018-08-08 16:45:31
On Wed, 2018-07-04 at 17:57:21 UTC, Mahesh J Salgaonkar wrote:
From: Mahesh Salgaonkar <redacted>
rtas_log_buf is a buffer to hold RTAS event data that are communicated
to kernel by hypervisor. This buffer is then used to pass RTAS event
data to user through proc fs. This buffer is allocated from vmalloc
(non-linear mapping) area.
On Machine check interrupt, register r3 points to RTAS extended event
log passed by hypervisor that contains the MCE event. The pseries
machine check handler then logs this error into rtas_log_buf. The
rtas_log_buf is a vmalloc-ed (non-linear) buffer we end up taking up a
page fault (vector 0x300) while accessing it. Since machine check
interrupt handler runs in NMI context we can not afford to take any
page fault. Page faults are not honored in NMI context and causes
kernel panic. Apart from that, as Nick pointed out, pSeries_log_error()
also takes a spin_lock while logging error which is not safe in NMI
context. It may endup in deadlock if we get another MCE before releasing
the lock. Fix this by deferring the logging of rtas error to irq work queue.
Current implementation uses two different buffers to hold rtas error log
depending on whether extended log is provided or not. This makes bit
difficult to identify which buffer has valid data that needs to logged
later in irq work. Simplify this using single buffer, one per paca, and
copy rtas log to it irrespective of whether extended log is provided or
not. Allocate this buffer below RMA region so that it can be accessed
in real mode mce handler.
Fixes: b96672dd840f ("powerpc: Machine check interrupt is a non-maskable interrupt")
Cc: stable@vger.kernel.org
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Mahesh Salgaonkar <redacted>