[RFC PATCH 00/36] arm64: Add support for FEAT_NMI

Jinjie Ruan ruanjinjie at huawei.com
Tue Jul 14 02:00:11 PDT 2026



On 7/14/2026 4:37 PM, Jinjie Ruan wrote:
> Hi, Vladimir,
> 
> On QEMU, if the CPU supports FEAT_NMI but gic-version=2, the kernel
> panic as following:
> 
> [    0.000000] CPU features: detected: HCRX_EL2 register
> [    0.000000] CPU features: detected: Non-maskable Interrupts
> [    0.000000] CPU features: kernel page table isolation forced ON by KASLR
> [    0.000000] CPU features: detected: Kernel page table isolation (KPTI)
> [    0.000000] CPU features: detected: ARM erratum 845719
> [    0.000000] alternatives: applying boot alternatives
> [    0.000000] Kernel command line: root=/dev/vda rw console=ttyAMA0
> kgdboc=ttyAMA0,115200 earlycon preempt=full irqchip.gicv3_pseudo_nmi=0 0
> [    0.000000] Unknown kernel command line parameters "preempt=full",
> will be passed to user space.
> [    0.000000] printk: log buffer data + meta data: 131072 + 458752 =
> 589824 bytes
> [    0.000000] Dentry cache hash table entries: 1048576 (order: 11,
> 8388608 bytes, linear)
> [    0.000000] Inode-cache hash table entries: 524288 (order: 10,
> 4194304 bytes, linear)
> [    0.000000] software IO TLB: area num 8.
> [    0.000000] software IO TLB: mapped [mem
> 0x00000000e4000000-0x00000000e8000000] (64MB)
> [    0.000000] Fallback order for Node 0: 0
> [    0.000000] Built 1 zonelists, mobility grouping on.  Total pages:
> 3145728
> [    0.000000] Policy zone: Normal
> [    0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
> [    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
> [    0.000000] Running RCU self tests
> [    0.000000] Running RCU synchronous self tests
> [    0.000000] rcu: Preemptible hierarchical RCU implementation.
> [    0.000000] rcu:     RCU event tracing is enabled.
> [    0.000000] rcu:     RCU lockdep checking is enabled.
> [    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=512 to
> nr_cpu_ids=8.
> [    0.000000]  Trampoline variant of Tasks RCU enabled.
> [    0.000000]  Tracing variant of Tasks RCU enabled.
> [    0.000000] rcu: RCU calculated value of scheduler-enlistment delay
> is 25 jiffies.
> [    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=8
> [    0.000000] Running RCU synchronous self tests
> [    0.000000] RCU Tasks: Setting shift to 3 and lim to 1
> rcu_task_cb_adjust=1 rcu_task_cpu_ids=8.
> [    0.000000] NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
> [    0.000000] Root IRQ handler: gic_handle_irq
> [    0.000000] ------------[ cut here ]------------
> [    0.000000] Could not request IRQ 4 as NMI, err=-22
> [    0.000000] WARNING: arch/arm64/kernel/smp.c:1103 at
> set_smp_ipi_range_percpu+0x2c0/0x31c, CPU#0: swapper/0/0
> [    0.000000] Modules linked in:
> [    0.000000] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted
> 7.2.0-rc1-00036-g6fbe132d3a74-dirty #353 PREEMPT
> [    0.000000] Hardware name: linux,dummy-virt (DT)
> [    0.000000] pstate: 600000c5 (nZCv daIF -ALLINT -PAN -UAO -TCO -DIT
> -SSBS BTYPE=--)
> [    0.000000] pc : set_smp_ipi_range_percpu+0x2c0/0x31c
> [    0.000000] lr : set_smp_ipi_range_percpu+0x2c0/0x31c
> [    0.000000] sp : ffffffdadd5d3b90
> [    0.000000] x29: ffffffdadd5d3b90 x28: 0000000000102200 x27:
> ffffffdadc1e49a0
> [    0.000000] x26: ffffff82fe7a7008 x25: 0000000000000008 x24:
> 0000000000000004
> [    0.000000] x23: ffffffdadd5e4078 x22: ffffffdadc9340c8 x21:
> ffffffdadc92c470
> [    0.000000] x20: 0000000000000003 x19: ffffffdadd5e02b0 x18:
> 00000000ffffffff
> [    0.000000] x17: 20313d7473756a64 x16: 615f62635f6b7361 x15:
> ffffffdb5d5d37b7
> [    0.000000] x14: 0000000000000000 x13: ffffffdadd60aaa8 x12:
> 0000000000000041
> [    0.000000] x11: 00000000000000c3 x10: ffffffdadd67aa90 x9 :
> ffffffdadd60aaa8
> [    0.000000] x8 : 3ffffffffffff000 x7 : 0000000000000001 x6 :
> 0000000000000001
> [    0.000000] x5 : ffffffdadd662aa8 x4 : 0000000000000000 x3 :
> 0000000000000000
> [    0.000000] x2 : 0000000000000000 x1 : 0000000000000000 x0 :
> ffffffdadd5eb780
> [    0.000000] Call trace:
> [    0.000000]  set_smp_ipi_range_percpu+0x2c0/0x31c (P)
> [    0.000000]  __gic_init_bases+0x138/0x148
> [    0.000000]  gic_of_init+0x88/0x3ec
> [    0.000000]  of_irq_init+0x1bc/0x458
> [    0.000000]  irqchip_init+0x18/0x40
> [    0.000000]  init_IRQ+0xa8/0x218
> [    0.000000]  start_kernel+0x550/0xa98
> [    0.000000]  __primary_switched+0x88/0x90
> [    0.000000] Kernel panic - not syncing: kernel: panic_on_warn set ...
> [    0.000000] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted
> 7.2.0-rc1-00036-g6fbe132d3a74-dirty #353 PREEMPT
> [    0.000000] Hardware name: linux,dummy-virt (DT)
> [    0.000000] Call trace:
> [    0.000000]  show_stack+0x18/0x24 (C)
> [    0.000000]  dump_stack_lvl+0x18c/0x1d4
> [    0.000000]  dump_stack+0x18/0x24
> [    0.000000]  vpanic+0x590/0x594
> [    0.000000]  do_panic_on_target_cpu+0x0/0x1c
> [    0.000000]  check_panic_on_warn+0x8c/0x9c
> [    0.000000]  __warn+0xa0/0x2cc
> [    0.000000]  __report_bug+0xe0/0x19c
> [    0.000000]  report_bug+0x50/0x10c
> [    0.000000]  bug_brk_handler+0x24/0x70
> [    0.000000]  call_el1_break_hook+0x6c/0xc8
> [    0.000000]  do_el1_brk64+0x24/0x4c
> [    0.000000]  el1_brk64+0x38/0x64
> [    0.000000]  el1h_64_sync_handler+0xa8/0x134
> [    0.000000]  el1h_64_sync+0x80/0x84
> [    0.000000]  set_smp_ipi_range_percpu+0x2c0/0x31c (P)
> [    0.000000]  __gic_init_bases+0x138/0x148
> [    0.000000]  gic_of_init+0x88/0x3ec
> [    0.000000]  of_irq_init+0x1bc/0x458
> [    0.000000]  irqchip_init+0x18/0x40
> [    0.000000]  init_IRQ+0xa8/0x218
> [    0.000000]  start_kernel+0x550/0xa98
> [    0.000000]  __primary_switched+0x88/0x90
> [    0.000000] ---[ end Kernel panic - not syncing: kernel:
> panic_on_warn set ... ]---

Hi Vladimir,

Even if PE supports FEAT_NMI, the GIC may not be able to generate a
super-priority interrupt.

The following patch can fix it, we should use
gic_supports_v3_3_nmi() instead of system_uses_nmi() in
ipi_should_be_nmi() because the GIC.

One more small suggestion: gic_data.has_nmi is a very important piece of
information, and we should print it out, as some versions of GICv3
hardware may not support FEAT_GICv3_NMI.

Best regards,
Jinjie

--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -1035,7 +1035,7 @@ static void smp_cross_call(const struct cpumask
*target, unsigned int ipinr)

 static bool ipi_should_be_nmi(enum ipi_msg_type ipi)
 {
-       if (!system_uses_nmi() && !system_uses_irq_prio_masking())
+       if (!gic_supports_v3_3_nmi() && !system_uses_irq_prio_masking())
                return false;

        switch (ipi) {
 /*
@@ -2124,6 +2126,8 @@ static int __init gic_init_bases(phys_addr_t
dist_phys_base,

        gic_data.has_rss = !!(typer & GICD_TYPER_RSS);
        gic_data.has_nmi = !!(typer & GICD_TYPER_NMI);
+       pr_info("GICv3 Non-maskable interrupt property %s supported\n",
+               gic_data.has_nmi ? "is" : "not");

        if (typer & GICD_TYPER_MBIS) {
                err = mbi_init(handle, gic_data.domain);
diff --git a/include/linux/irqchip/arm-gic-v3.h
b/include/linux/irqchip/arm-gic-v3.h
index ebccd76cadda..6bf73e7b9600 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -661,6 +661,7 @@ static inline bool gic_enable_sre(void)
        return !!(val & ICC_SRE_EL1_SRE);
 }

+bool gic_supports_v3_3_nmi(void);
 #endif


> 
> 
> On 7/9/2026 8:12 PM, Vladimir Murzin wrote:
>> FEAT_NMI provides an architected mechanism for supporting non-maskable
>> interrupts (NMIs) and less-masked interrupts (LMIs).
>>
>> Since we already support pseudo-NMIs via priority masking, introducing
>> another flavour of NMI on top of the existing infrastructure could
>> easily become messy, making the code harder to follow and reason
>> about.
>>
>> To avoid that, this series first makes room for the new NMI "tenant"
>> by restructuring the existing exception masking logic.
>>
>> The main idea is to separate the logical view of exception state from
>> its hardware representation. To achieve this, we introduce logical
>> exception contexts that can be mapped onto the corresponding hardware
>> state. This naturally consolidates the hardware-specific handling into
>> a small number of places, while allowing the rest of the code to
>> operate purely in terms of logical exception contexts.
>>
>> Since this restructuring is non-trivial and carries a risk of subtle
>> behavioural changes, the series adds extensive debug checks to verify
>> that the hardware state always matches the expected logical state.
>>
>> With this restructuring in place, wiring FEAT_NMI into the new
>> framework becomes much more manageable.
>>
>> This work would not have been possible without the contributions of
>> Ada Couprie Diaz, Mark Brown, and Lorenzo Pieralisi - please credit
>> them for everything that works well. Any remaining bugs or issues are
>> entirely my own.
>>
>> I'd especially appreciate feedback on the overall approach. Please
>> don't hesitate to bikeshed the naming or other details - improving
>> clarity is one of the main goals of this series. Of course, technical
>> review is more than welcome as well.
>>
>> The series would also benefit from extensive testing on real hardware
>> (without NMI, with pseudo-NMI, and with FEAT_NMI), as most of the
>> testing so far has been done on QEMU and FVP.
>>
>> P.S.
>> I'm aware that Jinjie Ruan has a similar series on the mailing
>> list. I'm very open to collaborating and aligning our efforts if that
>> makes sense.
>>
>> Thanks
>> Vladimir
>>
>> Ada Couprie Diaz (19):
>>   arm64: debug: don't mask DAIF for mdscr_write()
>>   arm64: hibernate: mask DAIF before restoring hibernated kernel
>>   arm64: suspend: rely on daif helpers to handle PMR
>>   arm64: irq: introduce a helper for GIC priority initialization
>>   arm64: entry: mask DAIF before returning from C EL1 handlers
>>   irqchip/gic-v3: make the unmasking of pseudo-NMIs explicit when
>>     handling IRQs
>>   arm64: irqflags: introduce arm64-specific irqflags type
>>   arm64: irqflags: save and use both DAIF and PMR
>>   arm64: interrupts: introduce interrupt masking helpers for entry code
>>   arm64: entry: replace DAIF helpers with entry helpers
>>   arm64: interrupts: introduce generic interrupt masking helpers
>>   arm64: replace local_daif helpers
>>   arm64: cpuidle: use new helpers to bypass interrupt priority masking
>>   arm64: remove daifflags.h
>>   arm64: gicv3: remove GIC_PRIO_PSR_I_SET
>>   arm64: ptrace: Add PSR_ALLINT_BIT
>>   arm64: cpufeature: Detect PE support for FEAT_NMI
>>   arm64: nmi: Manage masking for superpriority interrupts
>>   arm64: irq: Report FEAT_NMI masking local IRQs
>>
>> Lorenzo Pieralisi (1):
>>   irqchip/gic-v3: Implement FEAT_GICv3_NMI support
>>
>> Mark Brown (5):
>>   arm64: booting: Document boot requirements for FEAT_NMI
>>   arm64: sysreg: Add definitions for immediate versions of MSR ALLINT
>>   arm64: idreg: Add an override for FEAT_NMI
>>   arm64: nmi: Add handling of superpriority interrupts as NMIs
>>   arm64: nmi: Add Kconfig for NMI
>>
>> Vladimir Murzin (11):
>>   arm64: ptrace: Remove INIT_PSTATE_EL2
>>   arm64: suspend: Initialize PMR on resume
>>   arm64: process: Use helper to check exception state
>>   arm64: cpufeature: Remove system_has_prio_mask_debugging()
>>   arm64: irqflags: Switch to CONFIG_DEBUG_IRQFLAGS
>>   arm64: Kconfig: Remove CONFIG_ARM64_DEBUG_PRIORITY_MASKING
>>   efi/runtime-wrappers: Permit architectures to override IRQ flags
>>     checks
>>   arm64/efi: Implement override for IRQ flags checks
>>   arm64: suspend: Always initialise PSTATE.ALLINT
>>   arm64/efi: Add ALLINT to IRQ flags checks
>>   arm64: kprobes: Disable NMIs
>>
>>  Documentation/arch/arm64/booting.rst          |   6 +
>>  arch/arm/include/asm/arch_gicv3.h             |   6 +-
>>  arch/arm64/Kconfig                            |  29 +-
>>  arch/arm64/include/asm/arch_gicv3.h           |   7 +-
>>  arch/arm64/include/asm/assembler.h            |  24 +-
>>  arch/arm64/include/asm/cpucaps.h              |   2 +
>>  arch/arm64/include/asm/cpufeature.h           |  14 +-
>>  arch/arm64/include/asm/cpuidle.h              |  14 +-
>>  arch/arm64/include/asm/daifflags.h            | 144 --------
>>  arch/arm64/include/asm/efi.h                  |  42 ++-
>>  arch/arm64/include/asm/entry-common.h         |  10 +-
>>  .../include/asm/interrupts/common_flags.h     | 248 ++++++++++++++
>>  arch/arm64/include/asm/interrupts/entry.h     | 116 +++++++
>>  arch/arm64/include/asm/interrupts/masking.h   | 176 ++++++++++
>>  arch/arm64/include/asm/irqflags.h             | 148 ++++-----
>>  arch/arm64/include/asm/kvm_host.h             |   1 -
>>  arch/arm64/include/asm/mmu_context.h          |   1 -
>>  arch/arm64/include/asm/ptrace.h               |  17 +-
>>  arch/arm64/include/asm/sysreg.h               |   2 +
>>  arch/arm64/include/uapi/asm/ptrace.h          |   1 +
>>  arch/arm64/kernel/acpi.c                      |  15 +-
>>  arch/arm64/kernel/cpufeature.c                |  68 +++-
>>  arch/arm64/kernel/debug-monitors.c            |   4 -
>>  arch/arm64/kernel/entry-common.c              | 311 ++++++++++++------
>>  arch/arm64/kernel/entry.S                     |  18 +-
>>  arch/arm64/kernel/hibernate.c                 |  23 +-
>>  arch/arm64/kernel/irq.c                       |   9 +-
>>  arch/arm64/kernel/machine_kexec.c             |   4 +-
>>  arch/arm64/kernel/pi/idreg-override.c         |   1 +
>>  arch/arm64/kernel/probes/kprobes.c            |  24 +-
>>  arch/arm64/kernel/process.c                   |  24 +-
>>  arch/arm64/kernel/setup.c                     |   4 +-
>>  arch/arm64/kernel/signal.c                    |   1 -
>>  arch/arm64/kernel/smp.c                       |  18 +-
>>  arch/arm64/kernel/suspend.c                   |  26 +-
>>  arch/arm64/kernel/traps.c                     |   1 -
>>  arch/arm64/kvm/hyp/nvhe/switch.c              |   2 +-
>>  arch/arm64/kvm/hyp/vgic-v3-sr.c               |   7 +-
>>  arch/arm64/kvm/hyp/vhe/switch.c               |  12 +-
>>  arch/arm64/mm/fault.c                         |   1 -
>>  arch/arm64/mm/mmu.c                           |   7 +-
>>  arch/arm64/mm/proc.S                          |   7 +
>>  arch/arm64/tools/cpucaps                      |   2 +
>>  drivers/firmware/efi/runtime-wrappers.c       |  32 +-
>>  drivers/irqchip/irq-gic-v3.c                  | 127 +++++--
>>  include/linux/irqchip/arm-gic-v3-prio.h       |   8 -
>>  include/linux/irqchip/arm-gic-v3.h            |   4 +
>>  47 files changed, 1247 insertions(+), 521 deletions(-)
>>  delete mode 100644 arch/arm64/include/asm/daifflags.h
>>  create mode 100644 arch/arm64/include/asm/interrupts/common_flags.h
>>  create mode 100644 arch/arm64/include/asm/interrupts/entry.h
>>  create mode 100644 arch/arm64/include/asm/interrupts/masking.h
>>
> 




More information about the linux-arm-kernel mailing list