https://elixir.bootlin.com/linux/latest/source/include/linux/hardirq.h#L120
#define __nmi_enter() \
do { \
lockdep_off(); \
arch_nmi_enter(); \
BUG_ON(in_nmi() == NMI_MASK); \
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
} while (0)
Why enter_nmi
is:
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET);
why not just:
__preempt_count_add(NMI_OFFSET);
NMI is part of hardirq?
Linux is using bit masks to isolate preempt, softirq, hardirq, and nmi interrupts. Looking at the code where this is mapped out, we find they stack on top of each other.
The lowest 8 bits are for preempt mask, above that another 8 for software irq. Stacked on top of that is hardware irq and finally the nmi mask.
NMI_OFFSET + HARDIRQ_OFFSET = 1048576 + 65536 = 1114112 = 100010000000000000000
We have the offset now. This will be used to allow nested NMI interrupts. Each new NMI can be identified by adding one to this offset to go to the next.
NMI are hardware interrupts, but not all hardware interrupts are NMI.
The core api entry documentation is a guide to kernel hackers.