Index: /trunk/src/VBox/VMM/PATM/PATM.cpp
===================================================================
--- /trunk/src/VBox/VMM/PATM/PATM.cpp	(revision 301)
+++ /trunk/src/VBox/VMM/PATM/PATM.cpp	(revision 302)
@@ -427,4 +427,5 @@
         pVM->patm.s.pfnHelperCallGC += delta;
         pVM->patm.s.pfnHelperRetGC  += delta;
+        pVM->patm.s.pfnHelperIretGC += delta;
         pVM->patm.s.pfnHelperJumpGC += delta;
 
Index: /trunk/src/VBox/VMM/PATM/PATMA.asm
===================================================================
--- /trunk/src/VBox/VMM/PATM/PATMA.asm	(revision 301)
+++ /trunk/src/VBox/VMM/PATM/PATMA.asm	(revision 302)
@@ -1094,5 +1094,5 @@
 
     test    dword [esp+12], X86_EFL_IF
-    jz      iret_fault
+    jz      iret_clearIF
 
     ; if interrupts are pending, then we must go back to the host context to handle them!
@@ -1151,4 +1151,56 @@
     mov     dword [ss:PATM_INTERRUPTFLAG], 1
     PATM_INT3
+
+iret_clearIF:
+    push    dword [esp+4]           ; eip to return to
+    pushfd
+    push    eax
+    push    PATM_FIXUP
+    DB      0E8h                    ; call
+    DD      PATM_IRET_FUNCTION
+    add     esp, 4                  ; pushed address of jump table
+
+    cmp     eax, 0
+    je      near iret_fault3
+
+    mov     dword [esp+12+4], eax   ; stored eip in iret frame
+    pop     eax
+    popfd
+    add     esp, 4                  ; pushed eip
+
+    ; always ring 0 return -> change to ring 1 (CS in iret frame)
+    or      dword [esp+8], 1
+
+	; This section must *always* be executed (!!)
+	; Extract the IOPL from the return flags, save them to our virtual flags and
+	; put them back to zero
+	push	eax
+	mov     eax, dword [esp+16]
+	and     eax, X86_EFL_IOPL
+	and     dword [ss:PATM_VMFLAGS], ~X86_EFL_IOPL
+	or      dword [ss:PATM_VMFLAGS], eax
+    pop		eax
+	and		dword [esp+12], ~X86_EFL_IOPL
+
+    ; Clear IF
+    and     dword [ss:PATM_VMFLAGS], ~X86_EFL_IF
+    popfd
+
+                                                ; the patched destination code will set PATM_INTERRUPTFLAG after the return!
+    iretd
+
+iret_fault3:
+    pop     eax
+    popfd
+    add     esp, 4                  ; pushed eip
+    jmp     iret_fault
+
+align   4
+PATMIretTable:
+    DW      PATM_MAX_JUMPTABLE_ENTRIES          ; nrSlots
+    DW      0                                   ; ulInsertPos
+    DD      0                                   ; cAddresses
+    RESB    PATCHJUMPTABLE_SIZE                 ; lookup slots
+    
 PATMIretEnd:
 ENDPROC     PATMIretReplacement
@@ -1162,7 +1214,7 @@
     DD      PATMIretEnd- PATMIretStart
 %ifdef PATM_LOG_IF_CHANGES
-    DD      17
+    DD      22
 %else
-    DD      16
+    DD      21
 %endif
     DD      PATM_INTERRUPTFLAG
@@ -1201,4 +1253,109 @@
     DD      0
     DD      PATM_INTERRUPTFLAG
+    DD      0
+    DD      PATM_FIXUP
+    DD      PATMIretTable - PATMIretStart
+    DD      PATM_IRET_FUNCTION
+    DD      0
+    DD      PATM_VMFLAGS
+    DD      0
+    DD      PATM_VMFLAGS
+    DD      0
+    DD      PATM_VMFLAGS
+    DD      0
+    DD      0ffffffffh
+
+
+;
+; global function for implementing 'iret' to code with IF cleared
+;
+; Caller is responsible for right stack layout
+;  + 16 original return address
+;  + 12 eflags
+;  +  8 eax
+;  +  4 Jump table address
+;( +  0 return address )
+;
+; @note assumes PATM_INTERRUPTFLAG is zero
+; @note assumes it can trash eax and eflags
+;
+; @returns eax=0 on failure
+;          otherwise return address in eax
+;
+; @note NEVER change this without bumping the SSM version
+align 16
+BEGINPROC   PATMIretFunction
+PATMIretFunction_Start:
+    push    ecx
+    push    edx
+    push    edi
+
+    ; Event order:
+    ; 1) Check if the return patch address can be found in the lookup table
+    ; 2) Query return patch address from the hypervisor
+
+    ; 1) Check if the return patch address can be found in the lookup table
+    mov     edx, dword [esp+12+16]  ; pushed target address
+
+    xor     eax, eax                ; default result -> nothing found
+    mov     edi, dword [esp+12+4]  ; jump table
+    mov     ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
+    cmp     ecx, 0
+    je      near PATMIretFunction_AskHypervisor
+
+PATMIretFunction_SearchStart:
+    cmp     [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx        ; edx = GC address to search for
+    je      near PATMIretFunction_SearchHit
+    inc     eax
+    cmp     eax, ecx
+    jl      near PATMIretFunction_SearchStart
+
+PATMIretFunction_AskHypervisor:
+    ; 2) Query return patch address from the hypervisor
+    ; @todo private ugly interface, since we have nothing generic at the moment
+    lock    or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
+    mov     eax, PATM_ACTION_LOOKUP_ADDRESS
+    mov     ecx, PATM_ACTION_MAGIC
+    mov     edi, dword [esp+12+4]               ; jump table address
+    mov     edx, dword [esp+12+16]              ; original return address
+    db      0fh, 0bh        ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
+    jmp     near PATMIretFunction_SearchEnd
+
+PATMIretFunction_SearchHit:
+    mov     eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8]        ; found a match!
+    ;@note can be zero, so the next check is required!!
+
+PATMIretFunction_SearchEnd:
+    cmp     eax, 0
+    jz      PATMIretFunction_Failure
+
+    add     eax, PATM_PATCHBASE
+
+    pop     edi
+    pop     edx
+    pop     ecx
+    ret
+
+PATMIretFunction_Failure:
+    ;signal error
+    xor     eax, eax
+    pop     edi
+    pop     edx
+    pop     ecx
+    ret
+
+PATMIretFunction_End:
+ENDPROC     PATMIretFunction
+
+GLOBALNAME PATMIretFunctionRecord
+    RTCCPTR_DEF PATMIretFunction_Start
+    DD      0
+    DD      0
+    DD      0
+    DD      PATMIretFunction_End - PATMIretFunction_Start
+    DD      2
+    DD      PATM_PENDINGACTION
+    DD      0
+    DD      PATM_PATCHBASE
     DD      0
     DD      0ffffffffh
Index: /trunk/src/VBox/VMM/PATM/PATMA.h
===================================================================
--- /trunk/src/VBox/VMM/PATM/PATMA.h	(revision 301)
+++ /trunk/src/VBox/VMM/PATM/PATMA.h	(revision 302)
@@ -65,4 +65,5 @@
 #define PATM_RETURN_FUNCTION                    0xF1ABCE08    /** Relative address of global PATM return function. */
 #define PATM_LOOKUP_AND_JUMP_FUNCTION           0xF1ABCE09    /** Relative address of global PATM lookup and jump function. */
+#define PATM_IRET_FUNCTION                      0xF1ABCE0A    /** Relative address of global PATM iret function. */
 
 // everything except IOPL, NT, IF, VM, VIF, VIP and RF
@@ -167,4 +168,5 @@
 extern PATCHASMRECORD PATMRetFunctionRecord;
 extern PATCHASMRECORD PATMLookupAndJumpRecord;
+extern PATCHASMRECORD PATMIretFunctionRecord;
 
 extern PATCHASMRECORD PATMStatsRecord;
Index: /trunk/src/VBox/VMM/PATM/PATMA.mac
===================================================================
--- /trunk/src/VBox/VMM/PATM/PATMA.mac	(revision 301)
+++ /trunk/src/VBox/VMM/PATM/PATMA.mac	(revision 302)
@@ -64,4 +64,5 @@
 %define PATM_RETURN_FUNCTION                    0xF1ABCE08   ; /** Relative address of global PATM return function. */
 %define PATM_LOOKUP_AND_JUMP_FUNCTION           0xF1ABCE09   ; /** Relative address of global PATM lookup and jump function. */
+%define PATM_IRET_FUNCTION                      0xF1ABCE0A   ; /** Relative address of global PATM iret function. */
 
 
Index: /trunk/src/VBox/VMM/PATM/PATMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/PATM/PATMInternal.h	(revision 301)
+++ /trunk/src/VBox/VMM/PATM/PATMInternal.h	(revision 302)
@@ -37,5 +37,5 @@
 
 
-#define PATM_SSM_VERSION                    49
+#define PATM_SSM_VERSION                    50
 
 /* Enable for call patching. */
@@ -402,4 +402,6 @@
     /** Global PATM jump function (used by indirect jmp patches). */
     RTGCPTR                 pfnHelperJumpGC;
+    /** Global PATM return function (used by iret patches). */
+    RTGCPTR                 pfnHelperIretGC;
 
     /** Fake patch record for global functions. */
Index: /trunk/src/VBox/VMM/PATM/PATMPatch.cpp
===================================================================
--- /trunk/src/VBox/VMM/PATM/PATMPatch.cpp	(revision 301)
+++ /trunk/src/VBox/VMM/PATM/PATMPatch.cpp	(revision 302)
@@ -124,5 +124,5 @@
 
 #define PATCHGEN_EPILOG(pPatch, size) \
-    Assert(size <= 400);              \
+    Assert(size <= 512);              \
     pPatch->uCurPatchOffset += size;
 
@@ -309,4 +309,15 @@
                     /* Relative value is target minus address of instruction after the actual call instruction. */
                     dest = pVM->patm.s.pfnHelperRetGC - pInstrAfterCall;
+                    break;
+                }
+
+                case PATM_IRET_FUNCTION:
+                {
+                    RTGCPTR pInstrAfterCall = pVM->patm.s.pPatchMemGC + (RTGCUINTPTR)(&pPB[j] + sizeof(RTGCPTR) - pVM->patm.s.pPatchMemHC);
+                    Assert(pVM->patm.s.pfnHelperIretGC);
+                    Assert(sizeof(uint32_t) == sizeof(RTGCPTR));
+
+                    /* Relative value is target minus address of instruction after the actual call instruction. */
+                    dest = pVM->patm.s.pfnHelperIretGC - pInstrAfterCall;
                     break;
                 }
@@ -895,7 +906,16 @@
     PATCHGEN_EPILOG(pPatch, size);
 
+    /* Round to next 8 byte boundary. */
+    pPatch->uCurPatchOffset = RT_ALIGN_32(pPatch->uCurPatchOffset, 8);
+
+    pVM->patm.s.pfnHelperIretGC = PATCHCODE_PTR_GC(pPatch) + pPatch->uCurPatchOffset;
+    PATCHGEN_PROLOG_NODEF(pVM, pPatch);
+    size = patmPatchGenCode(pVM, pPatch, pPB, &PATMIretFunctionRecord, 0, false);
+    PATCHGEN_EPILOG(pPatch, size);
+
     Log(("pfnHelperCallGC %VGv\n", pVM->patm.s.pfnHelperCallGC));
     Log(("pfnHelperRetGC  %VGv\n", pVM->patm.s.pfnHelperRetGC));
     Log(("pfnHelperJumpGC %VGv\n", pVM->patm.s.pfnHelperJumpGC));
+    Log(("pfnHelperIretGC  %VGv\n", pVM->patm.s.pfnHelperIretGC));
 
     return VINF_SUCCESS;
Index: /trunk/src/VBox/VMM/PATM/PATMSSM.cpp
===================================================================
--- /trunk/src/VBox/VMM/PATM/PATMSSM.cpp	(revision 301)
+++ /trunk/src/VBox/VMM/PATM/PATMSSM.cpp	(revision 302)
@@ -302,4 +302,14 @@
     }
 
+    /* Relative calls are made to the helper functions. Therefor their location must not change! */
+    if (    pVM->patm.s.pfnHelperCallGC != patmInfo.pfnHelperCallGC
+        ||  pVM->patm.s.pfnHelperRetGC  != patmInfo.pfnHelperRetGC
+        ||  pVM->patm.s.pfnHelperJumpGC != patmInfo.pfnHelperJumpGC
+        ||  pVM->patm.s.pfnHelperIretGC != patmInfo.pfnHelperIretGC)
+    {
+        AssertMsgFailed(("Helper function ptrs don't match!!!\n"));
+        return VERR_SSM_INVALID_STATE;
+    }
+
     if (    pVM->patm.s.pPatchMemGC != patmInfo.pPatchMemGC
         ||  pVM->patm.s.cbPatchMem != patmInfo.cbPatchMem)
