Opcode Instruction Clocks Description
CF IRET 22,pm=38 Interrupt return (far return and pop
flags)
CF IRET pm=82 Interrupt return to lesser privilege
CF IRET ts Interrupt return, different task (NT = 1)
CF IRETD 22,pm=38 Interrupt return (far return and pop
flags)
CF IRETD pm=82 Interrupt return to lesser privilege
CF IRETD pm=60 Interrupt return to V86 mode
CF IRETD ts Interrupt return, different task (NT = 1)
Note
Values of ts are given by the following table:
New Task
Old Task 386 TSS 386 TSS 286 TSS
VM = 0 VM = 1
386
TSS VM=0 275 224 271
286
TSS 265 214 232
IF PE = 0
THEN (* Real-address mode *)
IF OperandSize = 32 (* Instruction = IRETD *)
THEN EIP := Pop();
ELSE (* Instruction = IRET *)
IP := Pop();
FI;
CS := Pop();
IF OperandSize = 32 (* Instruction = IRETD *)
THEN EFLAGS := Pop();
ELSE (* Instruction = IRET *)
FLAGS := Pop();
FI;
ELSE (* Protected mode *)
IF VM = 1
THEN #GP(0);
ELSE
IF NT = 1
THEN GOTO TASK-RETURN;
ELSE
IF VM = 1 in flags image on stack
THEN GO TO STACK-RETURN-TO-V86;
ELSE GOTO STACK-RETURN;
FI;
FI;
FI;
FI;STACK-RETURN-TO-V86: (* Interrupted procedure was in V86 mode *)
IF return CS selector RPL < > 3
THEN #GP(Return selector);
FI;
IF top 36 bytes of stack not within limits
THEN #SS(0);
FI;
Examine return CS selector and associated descriptor:
IF selector is null, THEN #GP(0); FI;
IF selector index not within its descriptor table limits;
THEN #GP(Return selector);
FI;
IF AR byte does not indicate code segment
THEN #GP(Return selector);
FI;
IF code segment DPL not = 3;
THEN #GP(Return selector);
FI;
IF code segment not present
THEN #NP(Return selector);
FI;
Examine return SS selector and associated descriptor:
IF selector is null THEN #GP(0); FI;
IF selector index not within its descriptor table limits
THEN #GP(SS selector);
FI;
IF selector RPL not = RPL of return CS selector
THEN #GP(SS selector);
FI;
IF AR byte does not indicate a writable data segment
THEN #GP(SS selector);
FI;
IF stack segment DPL not = RPL of return CS selector
THEN #GP(SS selector);
FI;
IF SS not present
THEN #NP(SS selector);
FI;
IF instruction pointer not within code segment limit THEN #GP(0);
FI;
EFLAGS := SS:[eSP + 8]; (* Sets VM in interrupted routine *)
EIP := Pop();
CS := Pop(); (* CS behaves as in 8086, due to VM = 1 *)
throwaway := Pop(); (* pop away EFLAGS already read *)
ES := Pop(); (* pop 2 words; throw away high-order word *)
DS := Pop(); (* pop 2 words; throw away high-order word *)
FS := Pop(); (* pop 2 words; throw away high-order word *)
GS := Pop(); (* pop 2 words; throw away high-order word *)
IF CS.RPL > CPL
THEN
TempESP := Pop();
TempSS := Pop();
SS:ESP := TempSS:TempESP;
FI;
(* Resume execution in Virtual 8086 mode *)
TASK-RETURN:
Examine Back Link Selector in TSS addressed by the current task
register:
Must specify global in the local/global bit, else #TS(new TSS
selector);
Index must be within GDT limits, else #TS(new TSS selector);
AR byte must specify TSS, else #TS(new TSS selector);
New TSS must be busy, else #TS(new TSS selector);
TSS must be present, else #NP(new TSS selector);
SWITCH-TASKS without nesting to TSS specified by back link selector;
Mark the task just abandoned as NOT BUSY;
Instruction pointer must be within code segment limit ELSE #GP(0);
STACK-RETURN:
IF OperandSize=32
THEN Third word on stack must be within stack limits, else #SS(0);
ELSE Second word on stack must be within stack limits, else #SS(0);
FI;
Return CS selector RPL must be >= CPL, else #GP(Return selector);
IF return selector RPL = CPL
THEN GOTO RETURN-SAME-LEVEL;
ELSE GOTO RETURN-OUTER-LEVEL;
FI;
RETURN-SAME-LEVEL:
IF OperandSize=32
THEN
Top 12 bytes on stack must be within limits, else #SS(0);
Return CS selector (at eSP+4) must be non-null, else #GP(0);
ELSE
Top 6 bytes on stack must be within limits, else #SS(0);
Return CS selector (at eSP+2) must be non-null, else #GP(0);
FI;
Selector index must be within its descriptor table limits, else #GP
(Return selector);
AR byte must indicate code segment, else #GP(Return selector);
IF non-conforming
THEN code segment DPL must = CPL;
ELSE #GP(Return selector);
FI;
IF conforming
THEN code segment DPL must be <= CPL, else #GP(Return selector);
Segment must be present, else #NP(Return selector);
Instruction pointer must be within code segment boundaries, else #GP(0);
FI;
IF OperandSize=32
THEN
Load CS:EIP from stack;
Load CS-register with new code segment descriptor;
Load EFLAGS with third doubleword from stack;
Increment eSP by 12;
ELSE
Load CS-register with new code segment descriptor;
Load FLAGS with third word on stack;
Increment eSP by 6;
FI;
RETURN-OUTER-LEVEL:
IF OperandSize=32
THEN Top 20 bytes on stack must be within limits, else #SS(0);
ELSE Top 10 bytes on stack must be within limits, else #SS(0);
FI;
Examine return CS selector and associated descriptor:
Selector must be non-null, else #GP(0);
Selector index must be within its descriptor table limits;
ELSE #GP(Return selector);
AR byte must indicate code segment, else #GP(Return selector);
IF non-conforming
THEN code segment DPL must = CS selector RPL;
ELSE #GP(Return selector);
FI;
IF conforming
THEN code segment DPL must be > CPL;
ELSE #GP(Return selector);
FI;
Segment must be present, else #NP(Return selector);
Examine return SS selector and associated descriptor:
Selector must be non-null, else #GP(0);
Selector index must be within its descriptor table limits
ELSE #GP(SS selector);
Selector RPL must equal the RPL of the return CS selector
ELSE #GP(SS selector);
AR byte must indicate a writable data segment, else #GP(SS selector);
Stack segment DPL must equal the RPL of the return CS selector
ELSE #GP(SS selector);
SS must be present, else #NP(SS selector);
Instruction pointer must be within code segment limit ELSE #GP(0);
IF OperandSize=32
THEN
Load CS:EIP from stack;
Load EFLAGS with values at (eSP+8);
ELSE
Load CS:IP from stack;
Load FLAGS with values at (eSP+4);
FI;
Load SS:eSP from stack;
Set CPL to the RPL of the return CS selector;
Load the CS register with the CS descriptor;
Load the SS register with the SS descriptor;
FOR each of ES, FS, GS, and DS
DO;
IF the current value of the register is not valid for the outer level;
THEN zero the register and clear the valid flag;
FI;
To be valid, the register setting must satisfy the following
properties:
Selector index must be within descriptor table limits;
AR byte must indicate data or readable code segment;
IF segment is data or non-conforming code,
THEN DPL must be >= CPL, or DPL must be >= RPL;
OD;
In Protected Mode, the action of IRET depends on the setting of the nested task flag (NT) bit in the flag register. When popping the new flag image from the stack, the IOPL bits in the flag register are changed only when CPL equals 0.
If NT equals 0, IRET returns from an interrupt procedure without a task switch. The code returned to must be equally or less privileged than the interrupt routine (as indicated by the RPL bits of the CS selector popped from the stack). If the destination code is less privileged, IRET also pops the stack pointer and SS from the stack.
If NT equals 1, IRET reverses the operation of a CALL or INT that caused a task switch. The updated state of the task executing IRET is saved in its task state segment. If the task is reentered later, the code that follows IRET is executed.
up:
Chapter 17 -- 80386 Instruction Set
prev: INT/INTO Call to Interrupt Procedure
next: Jcc Jump if Condition is Met