Fundamentals 11 min read

Understanding CPU Interrupts and Their Initialization in the Linux Kernel

This article explains what CPU interrupts are, distinguishes synchronous and asynchronous types, describes the role of APIC controllers, and details the step‑by‑step initialization of the Interrupt Descriptor Table and related interrupt handling mechanisms in the Linux kernel.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Understanding CPU Interrupts and Their Initialization in the Linux Kernel

Interrupts are mechanisms that pause the CPU to handle urgent events, distinguishing between asynchronous (external hardware) and synchronous (exceptions) types.

Asynchronous interrupts are further divided into maskable and non‑maskable, while synchronous interrupts include faults, traps, and aborts.

Modern SMP systems use an Advanced Programmable Interrupt Controller (APIC), consisting of IO‑APIC and Local‑APIC, to aggregate many device signals onto the limited CPU interrupt pins.

Linux initializes interrupt handling during boot. After the BIOS and early boot stages, the kernel sets up an empty Interrupt Descriptor Table (IDT) with 256 entries and populates the first 32 exception vectors.

#define IDT_ENTRIES 256
gate_desc idt_table __page_aligned_bss;

Early IDT entries are filled by assembly code that creates a 9‑byte stub for each vector, pushing a dummy error code when needed and jumping to early_idt_handler_common .

ENTRY(early_idt_handler_array)
  .rept NUM_EXCEPTION_VECTORS
    .if ((EXCEPTION_ERRCODE_MASK >> i) & 1) == 0
      UNWIND_HINT_IRET_REGS
      pushq $0
    .else
      UNWIND_HINT_IRET_REGS offset=8
    .endif
    pushq $i
    jmp early_idt_handler_common
    i = i + 1
  .endr
END(early_idt_handler_array)

Subsequent stages replace or extend handlers: idt_setup_early_pf installs the page‑fault handler, idt_setup_traps registers the full set of exception handlers, and idt_setup_ist_traps assigns dedicated Interrupt Stack Table (IST) stacks for critical exceptions such as double‑fault and machine‑check.

static const __initconst struct idt_data ist_idts[] = {
    ISTG(X86_TRAP_DB,   debug,      IST_INDEX_DB),
    ISTG(X86_TRAP_NMI,  nmi,        IST_INDEX_NMI),
    ISTG(X86_TRAP_DF,   double_fault, IST_INDEX_DF),
#ifdef CONFIG_X86_MCE
    ISTG(X86_TRAP_MC,   &machine_check, IST_INDEX_MCE),
#endif
};

Linux also allocates separate kernel stacks for hard and soft interrupts (and IST stacks) to avoid stack overflow during nested faults.

void irq_ctx_init(int cpu) {
    // hardirq stack
    irqctx = (union irq_ctx *)&hardirq_stack[cpu * THREAD_SIZE];
    // softirq stack
    irqctx = (union irq_ctx *)&softirq_stack[cpu * THREAD_SIZE];
}

Finally, early_irq_init() and init_IRQ() complete the hardware‑interrupt setup.

Exception HandlingLinux KernelCPU architectureAPICinterruptsIDT
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.