Operation
IF PE = 0
THEN GOTO REAL_ADDRESS_MODE:;
ELSE GOTO PROTECTED_MODE;
FI;
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 Pop(); EFLAGS Pop();
ELSE (* Instruction = IRET *)
FLAGS Pop();
FI;
END;
PROTECTED_MODE:
IF VM = 1 (* Virtual mode:PE=1, VM=1 *)
THEN GOTO STACK_RETURN_FROM_V86; (* PE=1, VM=1 *)
ELSE
IF NT=1
THEN GOTO TASK_RETURN; (* PE=1, VM=1, NT=1 *)
ELSE
IF VM=1 in flags image on stack
THEN GOTO STACK_RETURN_TO_V86; (* PE=1, VM=1 in flags
inage *)
ELSE GOTO STACK_RETURN; (* PE=1, VM=0 in flags image *)
FI;
FI;
FI;
STACK_RETURN_FROM_V86:
IF IOPL=3 (* Virtual mode: PE=1, VM=1, IOPL=3 *)
THEN
IF OperandSize = 16
IP Pop();(* 16-bit pops *)
CS Pop();
FLAGS Pop();
ELSE (* OperandSize = 32 *)
EIP Pop(); (* 32-bit pops *)
CS Pop();
EFLAGS Pop(); (*VM,IOPL,VIP,and VIF EFLAG bits are not modified by
IRETD*)
FI;
ELSE #GP(0); (* trap to virtual-8086 monitor: PE=1, VM=1, IOPL<3 *)
FI;
END;
STACK_RETURN_TO_V86: (* Interrupted procedure was in V86 mode:
PE=1, VM=1 in flags image *)
IF top 36 bytes of stack not within limits
THEN #SS(0);
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 *)
TempESP Pop();
TempSS Pop();
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 *)
SS:ESP TempSS:TempESP;
(* Resume processing in Virtual 8086 mode *)
END;
TASK-RETURN: (* PE=1, VM=1, NT=1 *)
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);
END;
STACK-RETURN: (* PE=1, VM=0 in flags image *)
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-OTHER-LEVEL;
FI;
RETURN-SAME-LEVEL: (* PE=1, VM=0 in flags image, RPL=CPL *)
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); (* PE=1, VM=0 in flags image,
RPL=CPL,non-conforming,DPL<> CPL *)
FI;
IF conforming
THEN IF DPL>CPL
#GP(Return selector); (* PE=1, VM=0 in flags image,
RPL=CPL,conforming,DPL>CPL *)
Segment must be present, else #NP(Return selector);
Instruction pointer must be within code segment boundaries, else #GP(0);
FI;
IF OperandSize=32 put comments here
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;
END;
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;
END:
[Back: Description]
[Next: Flags Affected]