Skip to content
Henk-Jan Lebbink edited this page Jun 4, 2026 · 1 revision

ERETU — Event Return to User

Opcode Instruction Op/ En 64-Bit Mode Compat/ Leg Mode Description
F3 0F 01 CA ERETU ZO Valid Valid Event return for events occurring in ring 3.

Instruction Operand Encoding

Op/En Operand 1 Operand 2 Operand 3 Operand 4
ZO N/A N/A N/A N/A

Description

ERETU returns from an event handler, establishing the state based on the contents of the stack (typically, that which was in effect before FRED event delivery). ERETU can be executed only if CPL = 0, and it changes CPL to 3. For this reason, ERETU is used to return from handling events that occurred while CPL = 3.

ERETU takes no explicit arguments; its operation depends on the contents of the regular stack.

Execution of ERETU causes an invalid-opcode exception (#UD) if FRED transitions are not enabled or if CPL > 0. For this reason, ERETU can be executed only in 64-bit mode.

ERETU establishes new values of CS and SS in one of three different ways:

  • If the values popped from the stack correspond to the values of IA32_STAR[63:48] + 16 and IA32_STAR[63:48] + 8, respectively, CS and SS are loaded with standard values for operation in 64-bit mode (similar those established by the 64-bit form of SYSCALL).

  • If the values popped from the stack correspond to the values of IA32_STAR[63:48] and IA32_STAR[63:48] + 8, respectively, CS and SS are loaded with standard values for operation in compatibility mode (similar those established by the 32-bit form of SYSCALL).

  • Otherwise, CS and SS are loaded from the GDT or LDT using the selectors popped from the stack (similar to the manner used by the 64-bit form of IRET).

For further details see the Operation section below and Section 8.4.2, “ERETU (Event Return to User),” in the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3.

Instruction ordering. Instructions following execution of ERETU may be fetched from memory before earlier instructions complete execution, but they will not execute (even speculatively) until all instructions prior to ERETU have completed execution (the later instructions may execute before data stored by the earlier instructions have become globally visible).

Operation

IF CR4.FRED = 0 OR CS.L = 0 OR CPL > 0
    THEN #UD;
FI;
IF CSL > 0
    THEN #GP(0);
FI;
// pop old state from regular stack and check it
RSPRSP + 8;
                        // skip over error code so that RSP references the return state
pop8B newRIP;
pop8B tempCS;
pop8B newRFLAGS;
pop8B newRSP;
pop8B tempSS;
IF tempCS & FFFFFFFF_FFFF0003H3 OR
                            // enforce return to ring 3
    newRFLAGS & FFFFFFFF_FFC2B02AH2 OR // enforce bit 1 set; IOPL, VM, reserved bits clear
    tempSS & FFF80003H3
                            // do not check bits 63:32
        THEN #GP(0);
FI;
pend_DBtempSS[17];
NMI_unblocktempSS[18];
IF tempCS[15:0] = IA32_STAR[63:48] + 16 AND tempSS[15:0] = IA32_STAR[63:48] + 8
    THEN
                            // Return to ring 3 in standard 64-bit configuration
        // set newCS to standard values used ring 3 in 64-bit mode
            newCS.selectortempCS[15:0];
            newCS.base0;
            newCS.limitFFFFFH;
            newCS.type11;
            newCS.S1;
            newCS.DPL3;
            newCS.P1;
            newCS.L1;
            newCS.D0;
            newCS.G1;
            newCS.unusable0;
        // set newSS to standard values for ring 3
            newSS.selectortempSS[15:0];
            newSS.base0;
            newSS.limitFFFFFH;
            newSS.type3;
            newSS.S1;
            newSS.DPL3;
            newSS.P1;
            newSS.B1;
            newSS.G1;
            newSS.unusable0;
ELSIF tempCS[15:0] = IA32_STAR[63:48] AND tempSS[15:0] = IA32_STAR[63:48] + 8
    THEN
        // set newCS to standard values used ring 3 in compatibility mode
            newCS.selectortempCS[15:0];
            newCS.base0;
            newCS.limitFFFFFH;
            newCS.type11;
            newCS.S1;
            newCS.DPL3;
            newCS.P1;
            newCS.L0;
            newCS.D1;
            newCS.G1;
            newCS.unusable0;
        // set newSS to standard values for ring 3
            newSS.selectortempSS[15:0];
            newSS.base0;
            newSS.limitFFFFFH;
            newSS.type3;
            newSS.S1;
            newSS.DPL3;
            newSS.P1;
            newSS.B1;
            newSS.G1;
            newSS.unusable0;
    ELSE
        load newCS using tempCS[15:0];
                            // load each as is done by IRET, including
        load newSS using tempSS[15:0];
                            // checks that may lead to a fault
FI;
IF newCS.L = 1
    THEN
            // return to 64-bit mode
        IF newRIP is not paging canonical
            THEN #GP(0);
        FI;
    ELSE
            // return to compatibility mode
        newRIP[63:32] ← 0;
        IF newRIP is not within newCSs limit (based on limit field and G bit)
            // newRIP is always within the limit with standard values for ring 3 in compatibility mode
            THEN #GP(0);
        FI;
        newRSP[63:32] ← 0;
FI;
// If user shadow stacks are enabled, check new SSP value on return to compatibility mode
IF CR4.CET = 1 AND IA32_U_CET.SH_STK_EN = 1 AND newCS.L = 0 AND IA32_PL3_SSP[63:32] ≠ 0
    THEN #GP(0);
FI;
// If supervisor shadow stacks are enabled, compare SSP to the FRED SSP MSR for stack level 0
IF CR4.CET = 1 AND IA32_S_CET.SH_STK_EN = 1 AND IA32_FRED_SSP0SSP
    THEN #CP(FAR-RET/IRET);
FI;
// update registers for return state
RIPnewRIP;
RFLAGSnewRFLAGS;
                            // ERETU can set RFLAGS.RF to 1
RSPnewRSP;
                            // load all 64 bits regardless of new mode
CSnewCS;
                            // selector and descriptor
SSnewSS;
                            // selector and descriptor
CPL3;
// swap GS.base and IA32_KERNEL_GS_BASE
tempGSBGS.base;
GS.baseIA32_KERNEL_GS_BASE;
IA32_KERNEL_GS_BASEtempGSB;
IF CR4.CET = 1 AND IA32_U_CET.SH_STK_EN = 1
    THEN SSPIA32_PL3_SSP;
FI;
// update event-related state
IF NMI_unblock = 1
    THEN unblock NMIs;
FI;
IF pend_DB = 1 AND RFLAGS.TF =1
    THEN pend a single-step debug exception (#DB) to be delivered after ERETU;
FI;

Flags Affected

All defined flags and fields in the RFLAGS register are potentially modified except for the VM flag.

Protected Mode Exceptions

#UD The ERETU instruction is not recognized in protected mode.

Real-Address Mode Exceptions

#UD The ERETU instruction is not recognized in real-address mode.

Virtual-8086 Mode Exceptions

#UD The ERETU instruction is not recognized in virtual-8086 mode.

Compatibility Mode Exceptions

#UD The ERETU instruction is not recognized in compatibility mode.

64-Bit Mode Exceptions

#UD If CR4.FRED = 0. If CPL > 0. If the LOCK prefix is used.

#GP(0) If CSL > 0. If the return is to 64-bit mode and the RIP image on the stack is not paging canonical. If the return is to compatibility mode and the low 32 bits of the RIP image on the stack is not within the CS.limit being established. If the RFLAGS image on the stack sets reserved bits or the VM bit (or fails to set bit 1). If bits 13:12 of the RFLAGS image on the stack (corresponding to IOPL) are not zero. If the value of bits 1:0 of the CS image on the stack (the target CPL) is not 3. If the value of bits 63:16 of the CS image on the stack is not zero. If the value of bits 1:0 of the SS image on the stack (the target CPL) is not 3. If the SS image on the stack sets undefined bits (bits 31:19). If the return is to compatibility mode and would load SSP with a value that sets any of bits 63:32. If ERETU is loading CS and SS from descriptor tables (see Operation section) and either of the following apply:

  • If the value of bits 15:2 of the CS image on the stack is 0.

  • If the value of bits 15:2 of the SS image on the stack is 0.

#GP(selector) If ERETU is loading CS and SS from descriptor tables (see Operation section) and any of the following apply:

  • A segment selector index is outside its descriptor table limits.

  • A segment descriptor memory address is not paging canonical.

  • The segment descriptor for CS does not indicate that it is a code segment.

  • The segment descriptor for CS has both the D-bit and L-bit set.

  • The segment descriptor for CS is non-conforming and its DPL is not 3.

  • The segment descriptor for SS does not indicate that it is a writable data segment.

  • The DPL of the segment descriptor for SS is not 3.

#SS(0) If an ordinary stack access would use an address that is not paging canonical or would cause a LASS violation.

#CP(FAR-RET/IRET)If the value in SSP differs from that in IA32_FRED_SSP0.


Source: Intel® 64 and IA-32 Architectures Software Developer's Manual, Combined Volumes (Order Number 325462-091US, March 2026)
Generated: 7-6-2026

Clone this wiki locally