Commit 65722736 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc/64s/interrupt: Fix clear of PACA_IRQS_HARD_DIS when returning to soft-masked context



Commit a4cb3651 ("powerpc/64s/interrupt: Fix lost interrupts when
returning to soft-masked context") fixed the problem of pending irqs
being cleared when clearing the HARD_DIS bit, but then it didn't clear
the bit at all. This change clears HARD_DIS without affecting other bits
in the mask.

When an interrupt hits in a soft-masked section that has MSR[EE]=1, it
can hard disable and set PACA_IRQS_HARD_DIS, which must be cleared when
returning to the EE=1 caller (unless it was set due to a MUST_HARD_MASK
interrupt becoming pending). Failure to clear this leaves the
returned-to context running with MSR[EE]=1 and PACA_IRQS_HARD_DIS, which
confuses irq assertions and could be dangerous for code that might test
the flag.

This was observed in a hash MMU kernel where a kernel hash fault hits in
a local_irqs_disabled region that has EE=1. The hash fault also runs
with EE=1, then as it returns, a decrementer hits in the restart section
and the irq restart code hard-masks which sets the PACA_IRQ_HARD_DIS
flag, which is not clear when the original context is returned to.

Reported-by: default avatarSachin Sant <sachinp@linux.ibm.com>
Fixes: a4cb3651 ("powerpc/64s/interrupt: Fix lost interrupts when returning to soft-masked context")
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Tested-by: default avatarSachin Sant <sachinp@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20221022052207.471328-1-npiggin@gmail.com
parent dc398a08
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -532,15 +532,24 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel)
	 * Returning to soft-disabled context.
	 * Check if a MUST_HARD_MASK interrupt has become pending, in which
	 * case we need to disable MSR[EE] in the return context.
	 *
	 * The MSR[EE] check catches among other things the short incoherency
	 * in hard_irq_disable() between clearing MSR[EE] and setting
	 * PACA_IRQ_HARD_DIS.
	 */
	ld	r12,_MSR(r1)
	andi.	r10,r12,MSR_EE
	beq	.Lfast_kernel_interrupt_return_\srr\() // EE already disabled
	lbz	r11,PACAIRQHAPPENED(r13)
	andi.	r10,r11,PACA_IRQ_MUST_HARD_MASK
	beq	.Lfast_kernel_interrupt_return_\srr\() // No HARD_MASK pending
	bne	1f // HARD_MASK is pending
	// No HARD_MASK pending, clear possible HARD_DIS set by interrupt
	andi.	r11,r11,(~PACA_IRQ_HARD_DIS)@l
	stb	r11,PACAIRQHAPPENED(r13)
	b	.Lfast_kernel_interrupt_return_\srr\()


	/* Must clear MSR_EE from _MSR */
1:	/* Must clear MSR_EE from _MSR */
#ifdef CONFIG_PPC_BOOK3S
	li	r10,0
	/* Clear valid before changing _MSR */