Unverified Commit 68f14388 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!7537 [OLK-6.6] irqchip/gic-v3: Fix one race condition due to NMI withdraw

Merge Pull Request from: @liujie-248683921 
 
The introduce of FEAT_NMI/FEAT_GICv3_NMI will cause a race problem that
we may handle the normal interrupt in interrupt disabled context due to
the withdraw of NMI interrupt. The flow will be like below:

[interrupt disabled]
<- normal interrupt pending, for example timer interrupt
<- NMI occurs, ISR_EL1.nmi = 1
do_el1_interrupt()
<- NMI withdraw, ISR_EL1.nmi = 0
ISR_EL1.nmi = 0, not an NMI interrupt
gic_handle_irq()
__gic_handle_irq_from_irqson()
irqnr = gic_read_iar() <- Oops, ack and handle an normal interrupt
in interrupt disabled context!

Fix this by checking the interrupt status in __gic_handle_irq_from_irqson()
and ignore the interrupt if we're in interrupt disabled context.

Fixes: 0408b5bc ("irqchip/gic-v3: Implement FEAT_GICv3_NMI support") 
 
Link:https://gitee.com/openeuler/kernel/pulls/7537

 

Reviewed-by: default avatarZhang Peng <zhangpeng362@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 30c56343 62660229
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -865,6 +865,28 @@ static void __gic_handle_irq_from_irqson(struct pt_regs *regs)
	bool is_nmi;
	u32 irqnr;

	/*
	 * We should enter here with interrupts disabled, otherwise we may met
	 * a race here with FEAT_NMI/FEAT_GICv3_NMI:
	 *
	 * [interrupt disabled]
	 *                   <- normal interrupt pending, for example timer interrupt
	 *                   <- NMI occurs, ISR_EL1.nmi = 1
	 * do_el1_interrupt()
	 *                   <- NMI withdraw, ISR_EL1.nmi = 0
	 *   ISR_EL1.nmi = 0, not an NMI interrupt
	 *   gic_handle_irq()
	 *     __gic_handle_irq_from_irqson()
	 *       irqnr = gic_read_iar() <- Oops, ack and handle an normal interrupt
	 *                                 in interrupt disabled context!
	 *
	 * So if we met this case here, just return from the interrupt context.
	 * Since the interrupt is still pending, we can handle it once the
	 * interrupt re-enabled and it'll not be missing.
	 */
	if (!interrupts_enabled(regs))
		return;

	irqnr = gic_read_iar();

	is_nmi = gic_rpr_is_nmi_prio();