Last modified: Mon Jun 22 15:36:51 UTC+0200 2026 © A. Tarpai
The IDT interrupt call mechanism
IDT: Interrupt Descriptor Table
Little simplified, without protection details, access right- and limit checks.
IDT system architecture (since 286) _______________________________________________ | CPU | MEMORY | | | +--------------+ | (1) IDT | | IDTR | --------------->---- | ----------------------> +---------+ | +--------------+ linear address | | | | of descriptor table | | | | +--------------+ | (3) GDT/LDT +---------+ Handler | | GDTR/LDTR | --------------->---- | --> +---------+ | CS:IP | JUMP address | +--------------+ linear address | | | | AR | --------> ... | of descriptor table | | | +---------+ (5) ... | | +---------+ | CS:EIP | ... | | | LIMIT | | AR | ... | | /|BASE ATTR| +---------+ ... | | / +---------+ | | IRET (6) | | / | | | | | | / | | +---------+ | |/ +---------+ | ... | | | | | | /| | | DESCRIPTOR | (4)/ | +---------+ TABLE OF | / | | ... | "INTERRUPT GATES" | PE=1: FETCH / | | SEGMENT / | DESCRIPTOR | REGISTERS / | TABLE | / | | | | - | / | | +--------+ +----------+----------+------+ | | | CS | - | BASE | LIMIT | ATTR | | | +--------+ +----------+----------+------+ | | | | - | | | (2) | |_______________________________________________|
When PE=1 and interrupt vector has been received:
- Interrupt Handler address is fetched from a GATE DESCRIPTOR in memory. It contains a FAR address with CSIP (286 Gate) or CSEIP (386 Gate), where CS is a Selector. CPU register IDTR points to this table, vector number is the index.
The size of gate (286-type = 16 bits; 386-type = 32 bits) determines WORD- or DWORD stack frame for push(!) – see below. - CS Selector from GATE written into CS register
- Results in SEGMENT DESCRIPTOR fetch from GLOBAL- or LOCAL TABLE.
- CS DESCRIPTOR CACHE values are loaded.
- Execution transfer to handler code.
The size of gate (286-type = 16 bits; 386-type = 32 bits) determines IP- (with EIP HI zero) or EIP load from GATE. - IRET operand-size determines WORD- or DWORD stack pop – and should match GATE format.
16/32-variations for PE = 1 mechanism: it is completely possible to mix 16/32-bit interrupted- and handler code watching these rules.
Debugging 16/32-bit CPU interrupt stack frame PE=1
What determines the CPU interrupt stack frame format when PE=1?
This was debugged in boot block code.
Surprisingly, it is the GATE DESCRIPTOR 16/32-bit format, i.e. 286/386 format. The interrupted- or handler code D-bit has no effect.
Note. When PE = 0, all push by CPU is 16-bit and there is nothing we can do about this. See IVT Emulation.
CPU interrupt stack frame:
PE = 1 AND 286 Gate PE = 1 AND 386 Gate
31 0 31 0
| | <-- ESP | | <-- ESP
+---------+---------+ +---------+---------+
| FLAGS CS | | EFLAGS |
+---------+---------+ +---------+---------+
| IP | | <-- ESP - 6 | CS |
+---------+---------+ +---------+---------+
| | | EIP | <-- ESP - 12
+---------+---------+ +---------+---------+
| | | |
CPU pushes 3 WORDS (6 bytes) CPU pushes 3 DWORDS (12 bytes)
16-bit PUSH: EIP HI lost!
| |
| |
v v
+---------+---------+ +---------+---------+
| 0 0 0 0 IP | EIP | | EIP
+---------+---------+ +---------+---------+
Transfer to GATE CS:IP (<64K) Transfer to GATE CS:EIP
Handler should return Handler should return
with 16-bit IRET: with 32-bit IRET:
IRET when D=0 or IRETW when D=1 IRET when D=1 or IRETD when D=0
Makes a little sense: old 286 interrupt handlers are 16-bit code and return with 16-bit IRET. This made it possible to reuse 286 OS code on the 386.
Tested (GitHub): change Gate type to 0x6 from 0xE: CPU made 16-bit stack frame and handler should return with 16-bit IRET.