Interrupt Vector Table Architecture
Interrupt Descriptor Table (IDT)
In x86 protected mode (32/64-bit), the IDT replaces the real-mode IVT, providing more flexible interrupt management through Gate Descriptors.
IDT Structure:
- 256 gate descriptors (vectors 0–255)
- Each descriptor is 8 bytes (in 32-bit mode) or 16 bytes (in 64-bit mode)
- Stored in linear address space of memory
- Located by the IDTR register
Location:
Set by the operating system kernel, typically in a fixed memory region (e.g., idt_table in Linux).
Size:
256 interrupt vectors (0–255), each pointing to an 8-byte (32-bit) or 16-byte (64-bit) gate descriptor.
Gate Types:
- Task Gate: Used for task switching (rare; modern systems prefer interrupt gates).
- Interrupt Gate: Disables interrupt nesting (clears the interrupt flag
IFduring handling). - Trap Gate: Allows interrupt nesting (preserves the
IFflag during handling).
Loading IDTR:
lidt [idtr_struct] ; Load IDT base address and limit
IDT Gate Descriptor Types:
| Type | Value | Description |
|---|---|---|
| Task Gate | 0x5 | Task switching |
| Interrupt Gate | 0xE | Interrupt handling |
| Trap Gate | 0xF | Exception handling |
Key Fields of a 32-bit Gate Descriptor:
| Field | Length | Description |
|---|---|---|
| Segment Selector | 16 bits | Points to a segment in GDT/LDT, determining code segment privilege. |
| Offset (low 16 bits) | 16 bits | Low 16 bits of the interrupt handler entry address. |
| P (Present bit) | 1 bit | 1 = valid, 0 = invalid (access triggers an exception). |
| DPL (Descriptor Privilege Level) | 2 bits | Privilege level (0–3) of the handler; restricts who can invoke it. |
| Segment Present Bit | 1 bit | Indicates whether the segment is present in memory (usually 1 in modern systems). |
| D/B (Default Operation Size) | 1 bit | 1 = 32-bit operands, 0 = 16-bit (default 1 in 32-bit mode). |
| G (Granularity) | 1 bit | 1 = offset aligned to 4-byte boundaries (32-bit mode); 0 = byte-aligned (rare). |
| Offset (high 16 bits) | 16 bits | High 16 bits of the interrupt handler entry address (32-bit mode). |
Example: IDT Initialization in Linux
The Linux kernel initializes the IDT at boot via the setup_idt() function, setting a gate descriptor for each vector. For example, the timer interrupt (IRQ0) corresponds to vector 0x20, whose gate descriptor points to the timer_interrupt handler.
Interrupt Vector Table (IVT)
In real mode (16-bit), the IVT is a 1KB region at memory addresses 0x00000–0x003FF, directly storing 256 interrupt vectors as segment:offset pairs (2 bytes each).
IVT Structure
- Interrupt Vector: Each interrupt number (0–255) maps to a 4-byte entry (segment + offset).
- Default Handlers: BIOS initializes the IVT at startup. Examples:
- Interrupt 0x00 (divide error) →
divide_errorhandler. - Interrupt 0x10 (video services) → BIOS video routines.
- Interrupt 0x00 (divide error) →
Real-Mode IVT Characteristics:
- Fixed at memory address 0x0000:0x0000
- Each entry is 4 bytes (segment:offset)
- Supports interrupts 0–255
IVT Initialization Example:
; Set handler for interrupt 0 (divide-by-zero exception)
mov word [0x00], handler_offset
mov word [0x02], handler_segment
Interrupt Handling Mechanism
Interrupt handling is the core process for responding to asynchronous events, involving four stages: hardware trigger, CPU response, kernel processing, and return to the original program.
Hardware Interrupt Architecture
PIC (Programmable Interrupt Controller)
- Master PIC (IRQ0–7): Maps to interrupt vectors 08h–0Fh
- Slave PIC (IRQ8–15): Maps to interrupt vectors 70h–77h
- Cascaded: IRQ2 of the master PIC connects to the slave PIC
APIC (Advanced Programmable Interrupt Controller) Features
- Supports 24+ interrupt lines
- Distributes interrupts across multiple processors
- Enables Message Signaled Interrupts (MSI)
IRQ to Interrupt Vector Mapping:
- IRQ0 → INT 08h (timer)
- IRQ1 → INT 09h (keyboard)
- IRQ8 → INT 70h (real-time clock)
- …
Hardware Interrupt System: Peripheral “Help Signals”
Hardware interrupts are requests sent by peripherals (e.g., keyboard, disk) to the CPU via an interrupt controller (e.g., 8259A PIC, APIC).
Interrupt Request (IRQ) Triggering
- Edge-Triggered: Triggered on signal transition (e.g., low-to-high on key release).
- Level-Triggered: Triggered while signal remains high/low (e.g., disk data ready).
Role of Interrupt Controllers
- PIC (Programmable Interrupt Controller): The 8259A is the classic x86 real-mode controller that aggregates peripheral IRQs and sends them to the CPU’s
INTRpin. - APIC (Advanced Programmable Interrupt Controller): Modern x86 multi-processor interrupt controller supporting distributed routing (e.g., local APIC receives requests from I/O APIC).
Interrupt Handling Flow
Protected Mode Interrupt Handling Steps
- CPU saves context (SS, ESP, EFLAGS, CS, EIP, Error Code)
- Looks up gate descriptor in IDT
- Performs privilege check (CPL vs. DPL)
- Switches to kernel stack
- Executes interrupt service routine (ISR)
- Returns via
IRET
Context Save (Context Save)
- Flags Register (EFLAGS/RFLAGS): Saves current state (e.g., interrupt flag
IF, direction flagDF). - CS:EIP/RIP: Saves code segment and instruction pointer (return address).
- General-Purpose Registers (EAX/EBX/…): Saved by the kernel as needed.
Interrupt Acknowledge
- Real Mode: CPU sends
INTApulses; peripheral places vector number on data bus; CPU uses it to index IVT. - Protected Mode: CPU uses
IDTR(which holds IDT base and limit) to locate the IDT, fetches the gate descriptor, validates privilege, then jumps.
Interrupt Service Routine (ISR)
- Kernel Execution: Runs in kernel mode (Ring 0), with access to hardware and global data.
- Interrupt Nesting Control: Interrupt gates clear
IF(CLI) to prevent nesting; trap gates preserveIF.
Context Restore
Restores general-purpose registers, flags, CS:EIP/RIP, then executes IRET.
Interrupt Handler Template:
; 32-bit interrupt handler template
section .text
global _irq_handler
_irq_handler:
pusha ; Save general-purpose registers
push ds
push es
push fs
push gs
mov ax, 0x10 ; Kernel data segment selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call irq_handler_c ; Call C handler
pop gs
pop fs
pop es
pop ds
popa ; Restore general-purpose registers
add esp, 4 ; Skip error code (if present)
iret ; Return from interrupt
Exception Handling Mechanism
Exceptions are errors detected during program execution (e.g., divide-by-zero, illegal memory access), triggered by CPU hardware or software. Their handling resembles interrupts but is more urgent.
Exception Classification
x86 defines 20 predefined exceptions (vectors 0–19). Common types include:
| Vector | Name | Trigger Condition |
|---|---|---|
| 0 | Divide Error | Division by zero or signed overflow |
| 4 | Overflow | Arithmetic result exceeds data type range (e.g., 127+1 in 8-bit signed) |
| 13 | General Protection Fault | Unauthorized segment access (e.g., kernel accessing user memory) |
| 14 | Page Fault | Accessed page not in memory (requires loading or swapping) |
| 21 | Alignment Check | Unaligned memory access (e.g., non-8-byte-aligned double on x86-64) |
Exception Categories:
- Fault: Recoverable (e.g., page fault); CPU state can be fixed; re-executes the faulting instruction.
- Trap: Reported after execution (e.g., debug breakpoint); EIP points to next instruction.
- Abort: Unrecoverable (e.g., hardware failure); terminates program.
Common Exception Handling
Page Fault (INT 0Eh)
Trigger Condition: Program accesses an unmapped virtual address (e.g., first access to unloaded code segment).
Handling Steps:
- CPU halts execution, saves context, jumps to page fault handler (IDT vector 14).
- Kernel inspects error via CR2 register (holds faulting address) to distinguish page-not-present vs. access-violation.
- If page-not-present: loads page from disk (swap), updates page tables. If access violation: terminates process (sends
SIGSEGV). - Flushes TLB, re-executes the faulting instruction.
Divide-by-Zero Exception (INT 00h):
; Divide-by-zero exception handler example
_divide_error:
push error_message
call print_string
jmp halt_system
error_message db "Divide by Zero Error!", 0
Page Fault Handler Framework:
; Page fault handler skeleton
_page_fault:
; Get fault address from CR2
mov eax, cr2
; Check if access is valid
test [page_table], eax
jz _kill_process
; Allocate physical page and update page table
call alloc_page
mov [page_table], eax
; Resume execution
add esp, 4 ; Skip error code
iret
Software Interrupt Mechanism
Software interrupts are explicitly triggered by programs to implement system calls (user-to-kernel transitions) or custom event handling.
System Call Implementation
System calls (e.g., open, read) let user programs request kernel services via software interrupts.
x86 System Call Methods
- 32-bit: Use
int 0x80;eax= syscall number;ebx,ecx, etc. = arguments. - 64-bit: Use
syscall(faster);rax= syscall number;rdi,rsi, etc. = arguments.
Example: Linux write System Call (64-bit)
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count) {
return syscall(SYS_write, fd, buf, count); // glibc wrapper
}
At the assembly level, syscall:
- Saves user registers to kernel stack.
- Switches to Ring 0.
- Jumps to kernel handler (e.g.,
sys_write).
Windows System Calls
Uses NT system calls via ntdll.dll (Nt* functions), ultimately using syscall, but with different interfaces (e.g., NtReadFile ≈ Linux read).
Traditional int 0x80 Method:
; Linux system call example
mov eax, 4 ; sys_write
mov ebx, 1 ; stdout
mov ecx, msg ; buffer address
mov edx, len ; length
int 0x80
section .data
msg db "Hello", 0x0A
len equ $ - msg
Fast syscall Method:
; x86_64 syscall example
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
mov rsi, msg ; buffer address
mov rdx, len ; length
syscall
; Syscall numbers defined in arch/x86/entry/syscalls/syscall_64.tbl
Custom Interrupt Handling
Developers can implement custom interrupt handlers by setting interrupt vectors or using signals.
Linux Signal-Based Custom Handling
Register a signal handler (e.g., for SIGALRM) via sigaction:
#include <signal.h>
#include <unistd.h>
void alarm_handler(int sig) {
printf("Alarm triggered!");
}
int main() {
struct sigaction sa;
sa.sa_handler = alarm_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL); // Register SIGALRM handler
alarm(5); // Trigger SIGALRM in 5 seconds
pause(); // Wait for signal
return 0;
}
Custom Hardware Interrupt in Kernel (Linux)
Use request_irq in a kernel module to register a handler for a specific IRQ:
#include <linux/interrupt.h>
irqreturn_t my_irq_handler(int irq, void *dev_id) {
printk(KERN_INFO "Custom IRQ %d triggered!", irq);
return IRQ_HANDLED;
}
static int __init my_init(void) {
int irq = 10; // Request IRQ10
request_irq(irq, my_irq_handler, IRQF_SHARED, "my_irq", NULL);
return 0;
}
Setting a Custom Software Interrupt:
; Set handler for INT 80h
mov word [idt + 80h*8], handler_offset
mov word [idt + 80h*8 + 2], handler_segment
mov word [idt + 80h*8 + 4], 0x8E00 ; 32-bit interrupt gate
; Interrupt handler
handler:
pusha
; Custom logic here
popa
iret
Advanced Interrupt Techniques
Interrupt Nesting and Priority
Modern systems support interrupt nesting, where a higher-priority interrupt can preempt a lower-priority one, controlled by IRQ priority.
APIC Priority Mechanism
- Each IRQ assigned priority 0–15 (0 = highest).
- CPU compares incoming priority with current:
- If incoming > current → allow nesting.
- If incoming ≤ current → defer until current ISR finishes.
Example: Keyboard (IRQ1) vs. Timer (IRQ0)
Timer interrupts usually have higher priority. If a timer ISR is running when a keyboard interrupt arrives, the keyboard ISR is deferred.
PIC Priority Order:
IRQ0 (highest) → IRQ7 (lowest)
IRQ8 → IRQ15
APIC Priority Control:
; Set Task Priority Register (TPR)
mov al, 0x10 ; Set priority threshold
out 0xF0, al ; APIC_TPR port
Interrupt Masking and Control
Interrupt Masking disables interrupts via CLI (clears IF), protecting critical sections (e.g., kernel data structure updates).
Use Cases:
- Kernel critical sections (e.g., modifying scheduler queues)
- Real-time tasks (prevent low-priority interrupt interference)
Risks:
Long masking causes system unresponsiveness (e.g., keyboard lag). Minimize duration (e.g., use spin_lock instead of long CLI).
PIC Mask Register Operations:
; Mask IRQ2
in al, 0x21 ; Read master PIC mask
or al, 0x04 ; Set bit 2
out 0x21, al ; Write back
; Enable slave PIC IRQ8
in al, 0xA1 ; Read slave PIC mask
and al, 0xFE ; Clear bit 0
out 0xA1, al ; Write back
Local APIC Control:
; Mask LINT0 interrupt
mov edx, 0x00000800 ; APIC_LVT_LINT0
mov eax, [edx]
or eax, 0x00010000 ; Set mask bit
mov [edx], eax
Debugging and Exception Analysis
Exception Diagnosis Techniques
Common Exception Symptoms:
- Segmentation Fault: Illegal memory access (e.g., null pointer dereference).
- Double Fault: Exception during exception handling (e.g., page fault handler accesses invalid memory).
- Machine Check Exception: Hardware errors (e.g., memory corruption, CPU cache failure).
Diagnostic Tools and Methods:
- GDB Debugging:
info registers→ view register statex/10i $pc→ disassemble current instructionsbt→ show call stack
- Kernel Logs (
dmesg): Linux logs exception details (e.g., fault address, vector number). - Core Dumps: Memory snapshots on crash; analyze with
gdb core.
IDT Debugging Example:
; Dump IDT entry information
dump_idt_entry:
mov eax, [idt + ecx*8] ; Fetch gate descriptor
mov ebx, [idt + ecx*8 + 4] ; High part
; Parse and display descriptor...
Page Fault Analysis:
; Add diagnostics in _page_fault
_page_fault:
mov eax, cr2 ; Faulting address
mov ebx, [page_tables]
test ebx, eax
jnz .valid_address
; Log illegal access
call log_fault_address
Performance Optimization Tips
Interrupt Latency Optimization:
- Minimize ISR code size
- Use fast system calls (
syscall) - Batch interrupts (e.g., NAPI in networking)
Interrupt Load Balancing:
; Enable interrupt load balancing in APIC
mov edx, 0xFEE00320 ; APIC_ICR high
mov eax, [edx]
and eax, 0x00FFFFFF ; Clear destination field
or eax, 0x01000000 ; Set broadcast mode
mov [edx], eax
By deeply understanding these mechanisms, you can:
- Develop reliable kernel-level software
- Implement efficient interrupt handlers
- Diagnose complex system faults
- Optimize system responsiveness
- Build secure exception handling frameworks



