Search code examples
linuxinterruptnmi

Why __nmi_enter() defined __preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET);


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?


Solution

  • How does Linux know what type of interrupt a specific one is?

    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.

    So what is NMI_OFFSET + HARDIRQ_OFFSET doing?

    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 is part of hardirq?

    NMI are hardware interrupts, but not all hardware interrupts are NMI.

    Where can I read more?

    The core api entry documentation is a guide to kernel hackers.