Interrupt Basics and the Interrupt Vector Table
Understand how the 8086 responds to events — the interrupt system that connects software to hardware
Open interactive version (quiz + challenge)Real-world analogy
What is it?
An interrupt is a mechanism that causes the 8086 to suspend its current program, save the flags, CS, and IP on the stack, and jump to an Interrupt Service Routine (ISR) identified by a type number (0-255). The Interrupt Vector Table (IVT) occupies the first 1024 bytes of memory (0000:0000 to 0000:03FF) and contains 256 four-byte entries, each holding the CS:IP address of an ISR. IRET returns from the ISR by restoring IP, CS, and FLAGS.
Real-world relevance
The interrupt system is the backbone of all I/O in computing. Every keystroke generates a hardware interrupt. Every disk read completes via an interrupt. Your OS scheduler uses a timer interrupt to switch between processes. Modern x86 systems still use an evolved version of this same IVT concept (the IDT — Interrupt Descriptor Table). Understanding interrupts is essential for OS development, driver writing, and embedded systems.
Key points
- What is an Interrupt? — An interrupt is a signal that causes the CPU to stop its current work, save its state, and execute a specific routine called an Interrupt Service Routine (ISR) or handler. After the ISR completes, the CPU resumes the interrupted program exactly where it left off.
- Interrupt Type Number — Each interrupt has a type number from 0 to 255. This number identifies which ISR to call. Some are fixed by Intel (0 = divide error, 1 = single-step, 2 = NMI, 4 = overflow). Others are assigned by the system (21h = DOS services, 10h = BIOS video).
- The Interrupt Vector Table (IVT) — The IVT occupies the first 1024 bytes of memory at physical address 00000h to 003FFh. It contains 256 entries (vectors), one per interrupt type. Each vector is 4 bytes: 2 bytes for the offset (IP) and 2 bytes for the segment (CS) of the ISR.
- Vector Address Calculation — To find the vector for interrupt type N, multiply N by 4. The result is the memory address where the 4-byte vector (IP:CS) is stored. Vector for INT 21h: 21h x 4 = 84h, so the ISR address is at 0000:0084.
- How INT n Works (Step by Step) — When the CPU executes INT n: (1) Push FLAGS onto stack, (2) Clear IF and TF (disable interrupts and single-step), (3) Push CS, (4) Push IP, (5) Load CS:IP from IVT entry n*4. The ISR now runs. IRET reverses the process.
- IRET — Interrupt Return — IRET is the ISR's return instruction. It pops IP, CS, and FLAGS from the stack (in that order), restoring the exact state before the interrupt. Regular RET only pops IP (or IP+CS for far). IRET additionally restores the flags, including IF.
- Dedicated Interrupts (0-4) — Intel reserves types 0-4 for specific CPU conditions: Type 0 (divide error — DIV overflow), Type 1 (single-step — TF=1), Type 2 (NMI — non-maskable hardware), Type 3 (breakpoint — special 1-byte INT 3), Type 4 (INTO — overflow flag set).
- Reading an IVT Entry — You can read any IVT entry by pointing a segment register to 0000h and reading the offset and segment at type*4. This reveals where any interrupt handler lives in memory.
- Setting a Custom IVT Entry — To install your own ISR, write your handler's CS:IP into the appropriate IVT slot. Disable interrupts (CLI) while modifying the IVT to prevent a half-updated vector from being used. Re-enable with STI after.
- IVT in Context — System Boot — During boot, the BIOS initializes the IVT with pointers to BIOS service routines (INT 10h for video, INT 13h for disk, INT 16h for keyboard). DOS then adds its own entries (INT 21h for DOS services). Programs can hook (redirect) these vectors to intercept or extend system calls.
Code example
; Program: Read and display the INT 21h vector from the IVT
; Then install a custom INT 60h handler and invoke it
.MODEL SMALL
.STACK 100h
.DATA
msg1 DB 'INT 21h vector: $'
msg2 DB 0Dh, 0Ah, 'Custom INT 60h called!$'
msg3 DB 0Dh, 0Ah, 'Calling INT 60h...$'
hexch DB '0123456789ABCDEF'
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
; --- Read INT 21h vector from IVT ---
MOV AH, 09h
LEA DX, msg1
INT 21h
XOR AX, AX
MOV ES, AX ; ES = 0000 (IVT segment)
MOV BX, 84h ; INT 21h: type 21h * 4 = 84h
MOV DX, ES:[BX+2] ; segment of INT 21h handler
CALL print_hex_word ; display segment
MOV AH, 02h
MOV DL, ':'
INT 21h ; print colon separator
MOV DX, ES:[BX] ; offset of INT 21h handler
CALL print_hex_word ; display offset
; --- Install custom INT 60h handler ---
CLI ; disable interrupts
MOV WORD PTR ES:[180h], OFFSET my_int60
MOV WORD PTR ES:[182h], CS
STI ; re-enable
; --- Invoke our custom interrupt ---
MOV AH, 09h
LEA DX, msg3
INT 21h
INT 60h ; calls our handler!
MOV AH, 4Ch
INT 21h
MAIN ENDP
; Custom ISR for INT 60h
my_int60 PROC FAR
PUSH AX
PUSH DX
PUSH DS
MOV AX, @DATA
MOV DS, AX
MOV AH, 09h
LEA DX, msg2
INT 21h
POP DS
POP DX
POP AX
IRET ; return from interrupt
my_int60 ENDP
; Print DX as 4-digit hex
print_hex_word PROC NEAR
PUSH CX
PUSH BX
MOV CX, 4 ; 4 hex digits
LEA BX, hexch
hex_loop:
ROL DX, 4 ; rotate top nibble to bottom
MOV AL, DL
AND AL, 0Fh ; isolate nibble
XLAT ; AL = hexch[AL]
PUSH DX
MOV DL, AL
MOV AH, 02h
INT 21h
POP DX
LOOP hex_loop
POP BX
POP CX
RET
print_hex_word ENDP
END MAINLine-by-line walkthrough
- 1. XOR AX, AX / MOV ES, AX — point ES to segment 0000h where the IVT resides
- 2. MOV BX, 84h — INT 21h is type 33 decimal (21h). Vector address = 33 * 4 = 132 = 84h
- 3. MOV DX, ES:[BX+2] — read the segment part of the INT 21h vector from IVT offset 86h
- 4. MOV DX, ES:[BX] — read the offset part of the INT 21h vector from IVT offset 84h
- 5. CLI — disable interrupts before modifying the IVT. Without this, a timer interrupt could fire while we have written only half the vector
- 6. MOV WORD PTR ES:[180h], OFFSET my_int60 — write our handler's offset into the INT 60h vector (60h * 4 = 180h)
- 7. MOV WORD PTR ES:[182h], CS — write the current code segment as the INT 60h handler's segment
- 8. STI — re-enable interrupts. The new vector is now complete and safe to use
- 9. INT 60h — triggers our custom interrupt. CPU pushes FLAGS/CS/IP, loads CS:IP from IVT[180h], and jumps to my_int60
- 10. IRET in my_int60 — pops IP, CS, and FLAGS from the stack, returning to the instruction after INT 60h
Spot the bug
; Install custom INT 60h handler
MOV ES, 0
MOV WORD PTR ES:[180h], OFFSET handler
MOV WORD PTR ES:[182h], CS
INT 60h
handler PROC FAR
MOV AH, 09h
LEA DX, msg
INT 21h
RET
handler ENDPNeed a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- Interrupt Vector Table in 8086 (GeeksforGeeks)
- x86 Interrupt System (Wikipedia)
- 8086 Interrupts Explained (YouTube)
- IVT and ISR Programming (OSDev Wiki)