Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8240829f authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Greg Kroah-Hartman
Browse files

powerpc/64s/exception: Fix machine check no-loss idle wakeup



[ Upstream commit 8a5054d8cbbe03c68dcb0957c291c942132e4101 ]

The architecture allows for machine check exceptions to cause idle
wakeups which resume at the 0x200 address which has to return via
the idle wakeup code, but the early machine check handler is run
first.

The case of a no state-loss sleep is broken because the early
handler uses non-volatile register r1 , which is needed for the wakeup
protocol, but it is not restored.

Fix this by loading r1 from the MCE exception frame before returning
to the idle wakeup code. Also update the comment which has become
stale since the idle rewrite in C.

This crash was found and fix confirmed with a machine check injection
test in qemu powernv model (which is not upstream in qemu yet).

Fixes: 10d91611 ("powerpc/64s: Reimplement book3s idle code in C")
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200508043408.886394-2-npiggin@gmail.com


Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent b1bc8753
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -1090,17 +1090,19 @@ EXC_COMMON_BEGIN(machine_check_idle_common)
	bl	machine_check_queue_event

	/*
	 * We have not used any non-volatile GPRs here, and as a rule
	 * most exception code including machine check does not.
	 * Therefore PACA_NAPSTATELOST does not need to be set. Idle
	 * wakeup will restore volatile registers.
	 * GPR-loss wakeups are relatively straightforward, because the
	 * idle sleep code has saved all non-volatile registers on its
	 * own stack, and r1 in PACAR1.
	 *
	 * Load the original SRR1 into r3 for pnv_powersave_wakeup_mce.
	 * For no-loss wakeups the r1 and lr registers used by the
	 * early machine check handler have to be restored first. r2 is
	 * the kernel TOC, so no need to restore it.
	 *
	 * Then decrement MCE nesting after finishing with the stack.
	 */
	ld	r3,_MSR(r1)
	ld	r4,_LINK(r1)
	ld	r1,GPR1(r1)

	lhz	r11,PACA_IN_MCE(r13)
	subi	r11,r11,1
@@ -1109,7 +1111,7 @@ EXC_COMMON_BEGIN(machine_check_idle_common)
	mtlr	r4
	rlwinm	r10,r3,47-31,30,31
	cmpwi	cr1,r10,2
	bltlr	cr1	/* no state loss, return to idle caller */
	bltlr	cr1	/* no state loss, return to idle caller with r3=SRR1 */
	b	idle_return_gpr_loss
#endif