IF PE 0 THEN
GOTO REAL-ADDRESS-MODE; ELSE (* PE 1 *)
IF (VM 1 and IOPL 3 AND INT n) THEN
#GP(0); (* Bit 0 of error code is 0 because INT n *)
INT n/INTO/INT 3Call to Interrupt Procedure
Vol. 2A
3-515
INSTRUCTION SET REFERENCE, A-M
ELSE (* Protected mode, IA-32e mode, or virtual-8086 mode interrupt *) IF (IA32_EFER.LMA 0)
THEN (* Protected mode, or virtual-8086 mode interrupt *) GOTO PROTECTED-MODE;
ELSE (* IA-32e mode interrupt *) GOTO IA-32e-MODE;
FI; FI;
FI; REAL-ADDRESS-MODE:
IF ((vector_number « 2) + 3) is not within IDT limit THEN #GP; FI;
IF stack not large enough for a 6-byte return information THEN #SS; FI;
Push (EFLAGS[15:0]);
IF  0; (* Clear interrupt flag *)
TF  0; (* Clear trap flag *)
AC  0; (* Clear AC flag *)
Push(CS);
Push(IP);
(* No error codes are pushed in real-address mode*)
CS  IDT(Descriptor (vector_number « 2), selector));
EIP  IDT(Descriptor (vector_number « 2), offset)); (* 16 bit offset AND 0000FFFFH *)
END; PROTECTED-MODE:
IF ((vector_number « 3) + 7) is not within IDT limits
or selected IDT descriptor is not an interrupt-, trap-, or task-gate type
THEN #GP(error_code(vector_number,1,EXT)); FI;
(* idt operand to error_code set because vector is used *) IF software interrupt (* Generated by INT n, INT3, or INTO *)
THEN
IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *)
THEN #GP(error_code(vector_number,1,0)); FI;
(* idt operand to error_code set because vector is used *)
(* ext operand to error_code is 0 because INT n, INT3, or INTO*)
FI;
IF gate not present
THEN #NP(error_code(vector_number,1,EXT)); FI;
(* idt operand to error_code set because vector is used *)
IF task gate (* Specified in the selected interrupt table descriptor *)
THEN GOTO TASK-GATE;
ELSE GOTO TRAP-OR-INTERRUPT-GATE; (* PE = 1, trap/interrupt gate *) FI;
3-516 Vol. 2A INT n/INTO/INT 3Call to Interrupt Procedure

END; IA-32e-MODE:
IF INTO and CS.L = 1 (64-bit mode) THEN #UD;
FI;
IF ((vector_number « 4) + 15) is not in IDT limits
or selected IDT descriptor is not an interrupt-, or trap-gate type
THEN #GP(error_code(vector_number,1,EXT));
(* idt operand to error_code set because vector is used *) FI;
IF software interrupt (* Generated by INT n, INT 3, or INTO *) THEN
IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *)
THEN #GP(error_code(vector_number,1,0));
(* idt operand to error_code set because vector is used *)
(* ext operand to error_code is 0 because INT n, INT3, or INTO*)
FI; FI;
IF gate not present
THEN #NP(error_code(vector_number,1,EXT));
(* idt operand to error_code set because vector is used *)
FI;
GOTO TRAP-OR-INTERRUPT-GATE; (* Trap/interrupt gate *) END;
TASK-GATE: (* PE = 1, task gate *)
Read TSS selector in task gate (IDT descriptor);
IF local/global bit is set to local or index not within GDT limits THEN #GP(error_code(TSS selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *)
Access TSS descriptor in GDT;
IF TSS descriptor specifies that the TSS is busy (low-order 5 bits set to 00001)
THEN #GP(TSS selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) IF TSS not present
THEN #NP(TSS selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) SWITCH-TASKS (with nesting) to TSS;
IF interrupt caused by fault with error code THEN
FI;
IF stack limit does not allow push of error code THEN #SS(EXT); FI;
Push(error code);
INT n/INTO/INT 3Call to Interrupt Procedure
Vol. 2A
3-517
INSTRUCTION SET REFERENCE, A-M

INSTRUCTION SET REFERENCE, A-M
IF EIP not within code segment limit THEN #GP(EXT); FI;
END; TRAP-OR-INTERRUPT-GATE:
Read new code-segment selector for trap or interrupt gate (IDT descriptor); IF new code-segment selector is NULL
THEN #GP(EXT); FI; (* Error code contains NULL selector *)
IF new code-segment selector is not within its descriptor table limits
THEN #GP(error_code(new code-segment selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *)
Read descriptor referenced by new code-segment selector;
IF descriptor does not indicate a code segment or new code-segment DPL > CPL
THEN #GP(error_code(new code-segment selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) IF new code-segment descriptor is not present,
THEN #NP(error_code(new code-segment selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) IF new code segment is non-conforming with DPL < CPL
THEN
IF VM = 0
THEN
GOTO INTER-PRIVILEGE-LEVEL-INTERRUPT;
(* PE = 1, VM = 0, interrupt or trap gate, nonconforming code segment, DPL < CPL *)
ELSE (* VM = 1 *)
IF new code-segment DPL  0
THEN #GP(error_code(new code-segment selector,0,EXT));
(* idt operand to error_code is 0 because selector is used *) GOTO INTERRUPT-FROM-VIRTUAL-8086-MODE; FI;
(* PE = 1, interrupt or trap gate, DPL < CPL, VM = 1 *)
FI;
ELSE (* PE = 1, interrupt or trap gate, DPL  CPL *)
IF VM = 1
THEN #GP(error_code(new code-segment selector,0,EXT)); (* idt operand to error_code is 0 because selector is used *)
IF new code segment is conforming or new code-segment DPL = CPL THEN
FI; FI;
GOTO INTRA-PRIVILEGE-LEVEL-INTERRUPT;
ELSE (* PE = 1, interrupt or trap gate, nonconforming code segment, DPL > CPL *)
#GP(error_code(new code-segment selector,0,EXT));
(* idt operand to error_code is 0 because selector is used *)
3-518 Vol. 2A INT n/INTO/INT 3Call to Interrupt Procedure

END; INTER-PRIVILEGE-LEVEL-INTERRUPT:
(* PE = 1, interrupt or trap gate, non-conforming code segment, DPL < CPL *) IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *)
THEN
(* Identify stack-segment selector for new privilege level in current TSS *)
IF current TSS is 32-bit THEN
TSSstackAddress  (new code-segment DPL « 3) + 4; IF (TSSstackAddress + 5) > current TSS limit
THEN #TS(error_code(current TSS selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) NewSS  2 bytes loaded from (TSS base + TSSstackAddress + 4); NewESP  4 bytes loaded from (TSS base + TSSstackAddress);
ELSE (* current TSS is 16-bit *)
TSSstackAddress  (new code-segment DPL « 2) + 2 IF (TSSstackAddress + 3) > current TSS limit
THEN #TS(error_code(current TSS selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) NewSS  2 bytes loaded from (TSS base + TSSstackAddress + 2); NewESP  2 bytes loaded from (TSS base + TSSstackAddress);
INSTRUCTION SET REFERENCE, A-M
FI;
IF NewSS is NULL
THEN #TS(EXT); FI;
IF NewSS index is not within its descriptor-table limits or NewSS RPL  new code-segment DPL
THEN #TS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) Read new stack-segment descriptor for NewSS in GDT or LDT;
IF new stack-segment DPL  new code-segment DPL
or new stack-segment Type does not indicate writable data segment
THEN #TS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) IF NewSS is not present
THEN #SS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) ELSE (* IA-32e mode *)
IF IDT-gate IST = 0
THEN TSSstackAddress  (new code-segment DPL « 3) + 4; ELSE TSSstackAddress  (IDT gate IST « 3) + 28;
FI;
IF (TSSstackAddress + 7) > current TSS limit
THEN #TS(error_code(current TSS selector,0,EXT); FI;
INT n/INTO/INT 3Call to Interrupt Procedure
Vol. 2A
3-519

INSTRUCTION SET REFERENCE, A-M
(* idt operand to error_code is 0 because selector is used *)
NewRSP 8 bytes loaded from (current TSS base + TSSstackAddress); NewSS new code-segment DPL; (* NULL selector with RPL = new CPL *)
FI;
IF IDT gate is 32-bit
THEN
IF new stack does not have room for 24 bytes (error code pushed) or 20 bytes (no error code pushed)
THEN #SS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *)
FI ELSE
IF IDT gate is 16-bit THEN
IF new stack does not have room for 12 bytes (error code pushed) or 10 bytes (no error code pushed);
THEN #SS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) ELSE (* 64-bit IDT gate*)
IF StackAddress is non-canonical
THEN #SS(EXT); FI; (* Error code contains NULL selector *)
FI; FI;
IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *) THEN
IF instruction pointer from IDT gate is not within new code-segment limits THEN #GP(EXT); FI; (* Error code contains NULL selector *)
ESP NewESP;
SS NewSS; (* Segment descriptor information also loaded *) ELSE (* IA-32e mode *)
IF instruction pointer from IDT gate contains a non-canonical address THEN #GP(EXT); FI; (* Error code contains NULL selector *)
RSP NewRSP & FFFFFFFFFFFFFFF0H; SS NewSS;
FI;
IF IDT gate is 32-bit
THEN
CS:EIP  Gate(CS:EIP); (* Segment descriptor information also loaded *)
ELSE
IF IDT gate 16-bit
THEN
CS:IP Gate(CS:IP);
(* Segment descriptor information also loaded *)
3-520 Vol. 2A INT n/INTO/INT 3Call to Interrupt Procedure

ELSE (* 64-bit IDT gate *)
CS:RIP  Gate(CS:RIP);
(* Segment descriptor information also loaded *)
IF IDT gate is 32-bit THEN
Push(far pointer to old stack);
(* Old SS and ESP, 3 words padded to 4 *) Push(EFLAGS);
Push(far pointer to return instruction);
(* Old CS and EIP, 3 words padded to 4 *) Push(ErrorCode); (* If needed, 4 bytes *)
ELSE
IF IDT gate 16-bit
FI; FI;
THEN
Push(far pointer to old stack);
(* Old SS and SP, 2 words *) Push(EFLAGS(15-0]);
Push(far pointer to return instruction); (* Old CS and IP, 2 words *) Push(ErrorCode); (* If needed, 2 bytes *)
ELSE (* 64-bit IDT gate *)
Push(far pointer to old stack);
(* Old SS and SP, each an 8-byte push *) Push(RFLAGS); (* 8-byte push *) Push(far pointer to return instruction); (* Old CS and RIP, each an 8-byte push *) Push(ErrorCode); (* If needed, 8-bytes *)
CPL  new code-segment DPL; CS(RPL)  CPL;
IF IDT gate is interrupt gate
THEN IF  0 (* Interrupt flag set to 0, interrupts disabled *); FI; TF  0;
VM 0; RF  0; NT  0;
END; INTERRUPT-FROM-VIRTUAL-8086-MODE:
(* Identify stack-segment selector for privilege level 0 in current TSS *) IF current TSS is 32-bit
INT n/INTO/INT 3Call to Interrupt Procedure
Vol. 2A
3-521
INSTRUCTION SET REFERENCE, A-M
FI; FI;

INSTRUCTION SET REFERENCE, A-M
THEN
IF TSS limit < 9
THEN #TS(error_code(current TSS selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) NewSS  2 bytes loaded from (current TSS base + 8);
NewESP  4 bytes loaded from (current TSS base + 4);
ELSE (* current TSS is 16-bit *) IF TSS limit < 5
THEN #TS(error_code(current TSS selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) NewSS  2 bytes loaded from (current TSS base + 4);
NewESP  2 bytes loaded from (current TSS base + 2);
FI;
IF NewSS is NULL
THEN #TS(EXT); FI; (* Error code contains NULL selector *) IF NewSS index is not within its descriptor table limits
or NewSS RPL  0
THEN #TS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *)
Read new stack-segment descriptor for NewSS in GDT or LDT;
IF new stack-segment DPL  0 or stack segment does not indicate writable data segment
THEN #TS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) IF new stack segment not present
THEN #SS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) IF IDT gate is 32-bit
THEN
IF new stack does not have room for 40 bytes (error code pushed) or 36 bytes (no error code pushed)
THEN #SS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) ELSE (* IDT gate is 16-bit)
IF new stack does not have room for 20 bytes (error code pushed) or 18 bytes (no error code pushed)
THEN #SS(error_code(NewSS,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *)
FI;
IF instruction pointer from IDT gate is not within new code-segment limits
THEN #GP(EXT); FI; (* Error code contains NULL selector *) tempEFLAGS  EFLAGS;
VM 0;
TF 0;
3-522 Vol. 2A
INT n/INTO/INT 3Call to Interrupt Procedure

RF  0;
NT  0;
IF service through interrupt gate
THEN IF = 0; FI; TempSS  SS;
INSTRUCTION SET REFERENCE, A-M
TempESP  ESP;
SS  NewSS;
ESP  NewESP;
(* Following pushes are 16 bits for 16-bit IDT gates and 32 bits for 32-bit IDT gates; Segment selector pushes in 32-bit mode are padded to two words *)
Push(GS); Push(FS); Push(DS); Push(ES); Push(TempSS); Push(TempESP); Push(TempEFlags); Push(CS); Push(EIP);
GS 0; (* Segment registers made NULL, invalid for use in protected mode *) FS 0;
DS 0;
ES 0;
CS:IP
IF OperandSize = 32
Gate(CS); (* Segment descriptor information also loaded *)
THEN
EIP  Gate(instruction pointer);
ELSE (* OperandSize is 16 *)
EIP  Gate(instruction pointer) AND 0000FFFFH;
FI;
(* Start execution of new routine in Protected Mode *) END;
INTRA-PRIVILEGE-LEVEL-INTERRUPT:
(* PE = 1, DPL = CPL or conforming segment *) IF IA32_EFER.LMA = 1 (* IA-32e mode *)
IF IDT-descriptor IST  0 THEN
TSSstackAddress  (IDT-descriptor IST « 3) + 28; IF (TSSstackAddress + 7) > TSS limit
THEN #TS(error_code(current TSS selector,0,EXT)); FI;
(* idt operand to error_code is 0 because selector is used *) NewRSP  8 bytes loaded from (current TSS base + TSSstackAddress);
FI;
INT n/INTO/INT 3Call to Interrupt Procedure Vol. 2A 3-523

INSTRUCTION SET REFERENCE, A-M
IF 32-bit gate (* implies IA32_EFER.LMA = 0 *) THEN
IF current stack does not have room for 16 bytes (error code pushed) or 12 bytes (no error code pushed)
THEN #SS(EXT); FI; (* Error code contains NULL selector *) ELSE IF 16-bit gate (* implies IA32_EFER.LMA = 0 *)
IF current stack does not have room for 8 bytes (error code pushed) or 6 bytes (no error code pushed)
THEN #SS(EXT); FI; (* Error code contains NULL selector *) ELSE (* IA32_EFER.LMA = 1, 64-bit gate*)
IF NewRSP contains a non-canonical address
THEN #SS(EXT); (* Error code contains NULL selector *)
FI; FI;
IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *) THEN
IF instruction pointer from IDT gate is not within new code-segment limit THEN #GP(EXT); FI; (* Error code contains NULL selector *)
ELSE
IF instruction pointer from IDT gate contains a non-canonical address
THEN #GP(EXT); FI; (* Error code contains NULL selector *) RSP NewRSP & FFFFFFFFFFFFFFF0H;
FI;
IF IDT gate is 32-bit (* implies IA32_EFER.LMA = 0 *)
THEN
Push (EFLAGS);
Push (far pointer to return instruction); (* 3 words padded to 4 *) CS:EIP  Gate(CS:EIP); (* Segment descriptor information also loaded *) Push (ErrorCode); (* If any *)
ELSE
IF IDT gate is 16-bit (* implies IA32_EFER.LMA = 0 *)
THEN
Push (FLAGS);
Push (far pointer to return location); (* 2 words *) CS:IP  Gate(CS:IP);
(* Segment descriptor information also loaded *) Push (ErrorCode); (* If any *)
ELSE (* IA32_EFER.LMA = 1, 64-bit gate*) Push(far pointer to old stack);
(* Old SS and SP, each an 8-byte push *) Push(RFLAGS); (* 8-byte push *) Push(far pointer to return instruction); (* Old CS and RIP, each an 8-byte push *)
3-524 Vol. 2A INT n/INTO/INT 3Call to Interrupt Procedure

INSTRUCTION SET REFERENCE, A-M
Push(ErrorCode); (* If needed, 8 bytes *)
CS:RIP  GATE(CS:RIP);
(* Segment descriptor information also loaded *)
FI; FI;
CS(RPL) CPL;
IF IDT gate is interrupt gate
THEN IF  0; FI; (* Interrupt flag set to 0; interrupts disabled *) TF  0;
NT  0; VM 0; RF  0;
END;