Last modified: Mon Jun 29 08:08:50 UTC+0200 2026 © A. Tarpai
Automatic Stack Switch with GATE control descriptors
This analysis came from..
I want interrupts run on their own stack - and not on the interrupted program
Maybe I exactly fiddle with SP.. then an interrupt occurs. Not good, CPU starts pushing data.. destroying my memory area. Or in deep recursive call and stack is almost full..
Without CPU hardware support this is not possible (unless we disable interrupts for the whole operation, which is not a good idea either). Intel processors can do this – but only when the interrupted program runs on lesser privilege.
Code Privilege level change
It's possible to CALL to higher privilege level code through a CALL GATE or enter higher privilege level code via exception or interrupt. Matching RETF/IRET will return to lower privilege level:
CALL GATE RETF
INTERRUPT GATE IRET
--> 0 0 --\
1 ----/---> 1 1 ---\----> 1
2 ---/----> 2 2 ----\---> 2
3 --/ --> 3
to higher privilege to lower privilege
It's not possible to CALL to lower privilege level or return to higher privilege level.
Note that JMP and the INT n instruction cannot change privilege level.
These transitions involve automatic stack-switch.
HW Stack Switch
CPU can invoke routines to run on a separate, isolated stack.
CALL GATE RETF
INTERRUPT GATE IRET
--> 0 0 --\
1 ----/---> 1 1 ---\----> 1
2 ---/----> 2 2 ----\---> 2
3 --/ --> 3
| | | | | |
+------------+ +------------+ TSS +------------+
| | | SS | <-- SS:SP | |
+------------+ +------------+ +------------+
| | | SP | | |
+------------+ +------------+ +------------+
| | | .. | | |
+------------+ .. +------------+
| | <-- SP | .. | | | <-- SP
+------------+ +------------+ +------------+
| | | CS | | |
+------------+
Lower | IP | Lower
Privilege +------------+ Privilege
STACK | | STACK
Higher
Privilege
STACK
.. is copied optional parameters (CALL GATE) or FLAGS (INTERRUPT GATE)
Works only through GATE (INTERRUPT or CALL), when target code is more privileged and non-conforming (C=0). New SS:SP read from the TSS structure – pointed by the Task Register (TR).
The matching RETF/IRET will recognize a lower privilege CS SELECTOR on stack and returns with stack switch by popping SS:SP.
Code transfer through CALL GATE mechanism
CALL GATE-SELECTOR:offset (offset is ignored)
CALL GATE
current SELECTOR DESCRIPTOR CODE DESCRIPTOR
CPU CS in instr IN MEMORY IN MEMORY
+--------------+ +--------------+
15 0 15 0 | idx |T| * | | BASE/LIMIT |
+------------+ +------------+ +--------------+ +--------------+
| idx |T|CPL| | idx |T|RPL| ---> |P|DPL|0| ... | ---> |P|DPL|1| X C |
+--------------+ +--------------+
| OFFSET | | |
1. 2.
DPL >= CPL DPL = CPL --> SAME PRIVILEGE TRANSFER
DPL >= RPL DPL < CPL C=1 --> SAME PRIVILEGE TRANSFER
DPL < CPL C=0 --> MORE PRIVILEGE TRANSFER
| |
| |
| |
^ | |
| | LOAD CS |
| | from GATE |
| | |
| | |
| | |
+-----------------------------------+ | CACHE
| DESCRIPTOR
^ Set CPL to DPL |
| MORE PRIVILEGE TRANSFER |
| |
+-------------+------+------+------+------+------+ |
|P|DPL|S| ... | BASE 23..0 | LIMIT 15..0 | <----------------+
+-------------+------+------+------+------+------+
* In GATE DESCRIPTORS the Code Selector RPL is ignored
1. Protection at GATE-LEVEL:
Cannot access more priv GATE at all.
Both CPL and RPL checked. Eg. doesn't help to set RPL 0, when CPL is 3.
But fine to use less priv - like data segment
else #GP(call gate selector)
2. Protection at CODE TRANSITION
Cannot enter to less priv at all
else #GP(code segment selector)
But allowed to call to MORE PRIV using GATE:
new SS:SP from TSS.. stack-switch.. copy parameters.. (non-conforming only)
Conforming is simply CALL TO SAME PRIVILEGE
CALL GATE TO SAME PRIVILEGE:
- Load CS:IP from gate
- Load code segment descriptor into CS-cache
- CPL unchanged (also for conforming higher target)
CALL GATE TO MORE PRIVILEGE:
- Stack Switch. Higher priv SS:SP read from TSS.
- Load CS:IP from gate
- Load code segment descriptor into CS-cache
- Set CPL to code/stack segment DPL (all equal)
Code transfer through INTERRUPT GATE mechanism
Similar to CALL and as if Selector from vector number has RPL=0 (shifting by 3).
But software- and hardware interrupts are handled differently:
INTERRUPT GATE
current SELECTOR DESCRIPTOR CODE DESCRIPTOR
CPU CS from vector IN MEMORY IN MEMORY
+--------------+ +--------------+
15 0 15 0 | idx |T| * | | BASE/LIMIT |
+------------+ +------------+ +--------------+ +--------------+
| idx |T|CPL| | idx |0| 0 | ---> |P|DPL|0| ... | ---> |P|DPL|1| X C |
+--------------+ +--------------+
| OFFSET | | |
1. 2.
INT n --> DPL >= CPL DPL = CPL --> SAME PRIVILEGE TRANSFER
DPL < CPL C=1 --> SAME PRIVILEGE TRANSFER
1. 2.
EXC and INTR --> DPL ignored DPL = CPL --> SAME PRIVILEGE TRANSFER
DPL < CPL C=1 --> SAME PRIVILEGE TRANSFER
DPL < CPL C=0 --> MORE PRIVILEGE TRANSFER
* In GATE DESCRIPTORS the Code Selector RPL is ignored
1. GATE-LEVEL protection
- The DPL of the INTERRUPT GATE controls access to interrupts ONLY with the INT n and INT3 instructions.
- For exceptions and external interrupts, the CPL of the program is ignored while accessing the IDT.
2. CODE TRANSITION protection
- The INT instructions can transfer code to SAME PRIVILEGE only
- Only exceptions and interrupts through the INTR pin can transfer code to higher privilege (with stack switch)
- Still cannot enter a lower Privilege level handler routine
Return to lower privilege code with stack switch
The RETF and IRET instructions recognize the lower privilege CS SELECTOR on stack: and will pop SS:SP resulting in stack switch.
RETF N pops N bytes from both stacks. This should match the 0..31 WORD/DWORD number in the 16/32-bit CALL GATE Descriptor.