[RFC PATCH v2 33/45] arm64: irq: Report FEAT_NMI masking local IRQs
Vladimir Murzin
vladimir.murzin at arm.com
Mon Jul 27 09:34:41 PDT 2026
From: Ada Couprie Diaz <ada.coupriediaz at arm.com>
As we clear SCTLR_EL1.SPINTMASK when enabling FEAT_NMI, ALLINT masks
IRQs and FIQs regardless of superpriority.
Update irqflags.h and `regs_irqs_disabled()` to take it into account,
so we properly keep track of the local IRQ masking state.
We have documentation at the top of irqflags.h which explains the DAIF
masking. Since the additional masking with NMIs is related and also
covers the IF in DAIF, extend the comment to note what's going on
with NMIs.
Co-developed-by: Mark Brown <broonie at kernel.org>
Signed-off-by: Mark Brown <broonie at kernel.org>
Signed-off-by: Ada Couprie Diaz <ada.coupriediaz at arm.com>
Signed-off-by: Vladimir Murzin <vladimir.murzin at arm.com>
---
arch/arm64/include/asm/irqflags.h | 17 +++++++++++++++++
arch/arm64/include/asm/ptrace.h | 3 +++
2 files changed, 20 insertions(+)
diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h
index c719b7e2912e..9115cdc9d517 100644
--- a/arch/arm64/include/asm/irqflags.h
+++ b/arch/arm64/include/asm/irqflags.h
@@ -20,6 +20,16 @@
* always masked and unmasked together, and have no side effects for other
* flags. Keeping to this order makes it easier for entry.S to know which
* exceptions should be unmasked.
+ *
+ * With the addition of the FEAT_NMI extension we gain an additional
+ * class of superpriority IRQ/FIQ which is separately masked with a
+ * choice of modes controlled by SCTLR_ELn.{SPINTMASK,NMI}.
+ * Linux sets SPINTMASK to 0 and NMI to 1 which results in ALLINT.ALLINT
+ * masking both superpriority interrupts and IRQ/FIQ regardless of the
+ * I and F settings. Since these superpriority interrupts are being
+ * used as NMIs we do not include them in the interrupt masking here,
+ * anything that requires that NMIs be masked needs to explicitly do so,
+ * but we do check for ALLINT masking IRQs/FIQs.
*/
/*
@@ -104,6 +114,9 @@ static __always_inline unsigned long arch_local_save_flags(void)
{
arm64_exc_hwstate_t hwstate = { .daif = read_sysreg(daif) };
+ if (system_uses_nmi())
+ hwstate.allint = read_sysreg_s(SYS_ALLINT);
+
if (system_uses_irq_prio_masking())
hwstate.pmr = read_sysreg_s(SYS_ICC_PMR_EL1);
@@ -117,6 +130,10 @@ static __always_inline bool arch_irqs_disabled_flags(unsigned long flags)
if (hwstate.daif & PSR_I_BIT)
return true;
+ /* SCTLR_EL1.SPINTMASK is clear, so ALLINT masks *all* IRQs/FIQs. */
+ if (system_uses_nmi())
+ return !!(hwstate.allint & ALLINT_ALLINT);
+
if (system_uses_irq_prio_masking()) {
WARN_ON_ONCE(IS_ENABLED(CONFIG_DEBUG_IRQFLAGS) &&
hwstate.pmr != GIC_PRIO_IRQOFF &&
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index cf7e51b8ef0b..16ba164b890e 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -206,6 +206,9 @@ static __always_inline bool regs_irqs_disabled(const struct pt_regs *regs)
if (regs->pstate & PSR_I_BIT)
return true;
+ if (system_uses_nmi())
+ return !!(regs->pstate & PSR_ALLINT_BIT);
+
if (system_uses_irq_prio_masking()) {
WARN_ON_ONCE(IS_ENABLED(CONFIG_DEBUG_IRQFLAGS) &&
regs->pmr != GIC_PRIO_IRQOFF &&
--
2.34.1
More information about the linux-arm-kernel
mailing list