Index: /trunk/include/VBox/vmm/pgm.h
===================================================================
--- /trunk/include/VBox/vmm/pgm.h	(revision 55888)
+++ /trunk/include/VBox/vmm/pgm.h	(revision 55889)
@@ -159,15 +159,15 @@
  * Virtual access handler type.
  */
-typedef enum PGMVIRTHANDLERTYPE
+typedef enum PGMVIRTHANDLERKIND
 {
     /** Write access handled. */
-    PGMVIRTHANDLERTYPE_WRITE = 1,
+    PGMVIRTHANDLERKIND_WRITE = 1,
     /** All access handled. */
-    PGMVIRTHANDLERTYPE_ALL,
+    PGMVIRTHANDLERKIND_ALL,
     /** Hypervisor write access handled.
      * This is used to catch the guest trying to write to LDT, TSS and any other
      * system structure which the brain dead intel guys let unprivilegde code find. */
-    PGMVIRTHANDLERTYPE_HYPERVISOR
-} PGMVIRTHANDLERTYPE;
+    PGMVIRTHANDLERKIND_HYPERVISOR
+} PGMVIRTHANDLERKIND;
 
 /**
@@ -357,6 +357,6 @@
 /** NIL value for PGM physical access handler type handle. */
 #define NIL_PGMPHYSHANDLERTYPE  UINT32_MAX
-VMMDECL(uint32_t)   PGMHandlerPhysicalTypeRelease(PVM pVM, PGMPHYSHANDLERTYPE hCallbacks);
-VMMDECL(uint32_t)   PGMHandlerPhysicalTypeRetain(PVM pVM, PGMPHYSHANDLERTYPE hCallbacks);
+VMMDECL(uint32_t)   PGMHandlerPhysicalTypeRelease(PVM pVM, PGMPHYSHANDLERTYPE hType);
+VMMDECL(uint32_t)   PGMHandlerPhysicalTypeRetain(PVM pVM, PGMPHYSHANDLERTYPE hType);
 
 VMMDECL(int)        PGMHandlerPhysicalRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, PGMPHYSHANDLERTYPE hType,
@@ -373,5 +373,17 @@
 VMMDECL(int)        PGMHandlerPhysicalReset(PVM pVM, RTGCPHYS GCPhys);
 VMMDECL(bool)       PGMHandlerPhysicalIsRegistered(PVM pVM, RTGCPHYS GCPhys);
-VMMDECL(bool)       PGMHandlerVirtualIsRegistered(PVM pVM, RTGCPTR GCPtr);
+
+/** PGM virtual access handler type registration handle (heap offset, valid
+ * cross contexts without needing fixing up).  Callbacks and handler type is
+ * associated with this and it is shared by all handler registrations. */
+typedef uint32_t PGMVIRTHANDLERTYPE;
+/** Pointer to a PGM virtual handler type registration handle. */
+typedef PGMVIRTHANDLERTYPE *PPGMVIRTHANDLERTYPE;
+/** NIL value for PGM virtual access handler type handle. */
+#define NIL_PGMVIRTHANDLERTYPE  UINT32_MAX
+VMM_INT_DECL(uint32_t) PGMHandlerVirtualTypeRelease(PVM pVM, PGMVIRTHANDLERTYPE hType);
+VMM_INT_DECL(uint32_t) PGMHandlerVirtualTypeRetain(PVM pVM, PGMVIRTHANDLERTYPE hType);
+VMM_INT_DECL(bool)     PGMHandlerVirtualIsRegistered(PVM pVM, RTGCPTR GCPtr);
+
 VMMDECL(bool)       PGMPhysIsA20Enabled(PVMCPU pVCpu);
 VMMDECL(bool)       PGMPhysIsGCPhysValid(PVM pVM, RTGCPHYS GCPhys);
@@ -521,5 +533,5 @@
 VMMR3DECL(int)      PGMR3MapRead(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb);
 
-VMM_INT_DECL(int)   PGMR3HandlerPhysicalTypeRegisterEx(PVM pVM, PGMPHYSHANDLERKIND enmKind,
+VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegisterEx(PVM pVM, PGMPHYSHANDLERKIND enmKind,
                                                        PFNPGMR3PHYSHANDLER pfnHandlerR3,
                                                        R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0,
@@ -531,15 +543,18 @@
                                                      const char *pszModRC, const char *pszHandlerRC, const char *pszDesc,
                                                      PPGMPHYSHANDLERTYPE phType);
-VMMDECL(int)        PGMR3HandlerVirtualRegisterEx(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
-                                                  R3PTRTYPE(PFNPGMR3VIRTINVALIDATE) pfnInvalidateR3,
-                                                  R3PTRTYPE(PFNPGMR3VIRTHANDLER) pfnHandlerR3,
-                                                  RCPTRTYPE(PFNPGMRCVIRTHANDLER) pfnHandlerRC,
-                                                  R3PTRTYPE(const char *) pszDesc);
-VMMR3DECL(int)      PGMR3HandlerVirtualRegister(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
-                                                PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
-                                                PFNPGMR3VIRTHANDLER pfnHandlerR3,
-                                                const char *pszHandlerRC, const char *pszModRC, const char *pszDesc);
-VMMDECL(int)        PGMHandlerVirtualChangeInvalidateCallback(PVM pVM, RTGCPTR GCPtr, R3PTRTYPE(PFNPGMR3VIRTINVALIDATE) pfnInvalidateR3);
-VMMDECL(int)        PGMHandlerVirtualDeregister(PVM pVM, RTGCPTR GCPtr);
+VMMR3_INT_DECL(int) PGMR3HandlerVirtualTypeRegisterEx(PVM pVM, PGMVIRTHANDLERKIND enmKind, bool fRelocUserRC,
+                                                      PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
+                                                      PFNPGMR3VIRTHANDLER pfnHandlerR3,
+                                                      RCPTRTYPE(PFNPGMRCVIRTHANDLER) pfnHandlerRC,
+                                                      const char *pszDesc, PPGMVIRTHANDLERTYPE phType);
+VMMR3_INT_DECL(int) PGMR3HandlerVirtualTypeRegister(PVM pVM, PGMVIRTHANDLERKIND enmKind, bool fRelocUserRC,
+                                                    PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
+                                                    PFNPGMR3VIRTHANDLER pfnHandlerR3,
+                                                    const char *pszHandlerRC, const char *pszModRC, const char *pszDesc,
+                                                    PPGMVIRTHANDLERTYPE phType);
+VMMR3_INT_DECL(int) PGMR3HandlerVirtualRegister(PVM pVM, PVMCPU pVCpu, PGMVIRTHANDLERTYPE hType, RTGCPTR GCPtr,
+                                                RTGCPTR GCPtrLast, void *pvUserR3, RTRCPTR pvUserRC, const char *pszDesc);
+VMMR3_INT_DECL(int) PGMHandlerVirtualChangeType(PVM pVM, RTGCPTR GCPtr, PGMVIRTHANDLERTYPE hNewType);
+VMMDECL(int)        PGMHandlerVirtualDeregister(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, bool fHypervisor);
 VMMR3DECL(int)      PGMR3PoolGrow(PVM pVM);
 
Index: /trunk/src/VBox/VMM/VMMAll/PGMAllBth.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllBth.h	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllBth.h	(revision 55889)
@@ -16,5 +16,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -320,19 +320,20 @@
         if (pCur)
         {
+            PPGMVIRTHANDLERTYPEINT pCurType = PGMVIRTANDLER_GET_TYPE(pVM, pCur);
             AssertMsg(!(pvFault - pCur->Core.Key < pCur->cb)
-                      || (     pCur->enmType != PGMVIRTHANDLERTYPE_WRITE
+                      || (     pCurType->enmKind != PGMVIRTHANDLERKIND_WRITE
                            || !(uErr & X86_TRAP_PF_P)
-                           || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
-                      ("Unexpected trap for virtual handler: %RGv (phys=%RGp) pPage=%R[pgmpage] uErr=%X, enum=%d\n",
-                       pvFault, pGstWalk->Core.GCPhys, pPage, uErr, pCur->enmType));
+                           || (pCurType->enmKind == PGMVIRTHANDLERKIND_WRITE && (uErr & X86_TRAP_PF_RW))),
+                      ("Unexpected trap for virtual handler: %RGv (phys=%RGp) pPage=%R[pgmpage] uErr=%X, enumKind=%d\n",
+                       pvFault, pGstWalk->Core.GCPhys, pPage, uErr, pCurType->enmKind));
 
             if (    pvFault - pCur->Core.Key < pCur->cb
                 &&  (    uErr & X86_TRAP_PF_RW
-                     ||  pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
+                     ||  pCurType->enmKind != PGMVIRTHANDLERKIND_WRITE ) )
             {
 #   ifdef IN_RC
                 STAM_PROFILE_START(&pCur->Stat, h);
                 RTGCPTR                     GCPtrStart = pCur->Core.Key;
-                CTX_MID(PFNPGM,VIRTHANDLER) pfnHandler = pCur->CTX_SUFF(pfnHandler);
+                CTX_MID(PFNPGM,VIRTHANDLER) pfnHandler = pCurType->CTX_SUFF(pfnHandler);
                 pgmUnlock(pVM);
                 *pfLockTaken = false;
@@ -363,35 +364,39 @@
             rc = pgmHandlerVirtualFindByPhysAddr(pVM, pGstWalk->Core.GCPhys, &pCur, &iPage);
             Assert(RT_SUCCESS(rc) || !pCur);
-            if (    pCur
-                &&  (   uErr & X86_TRAP_PF_RW
-                     || pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
+            if (pCur)
             {
-                Assert((pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) == (pGstWalk->Core.GCPhys & X86_PTE_PAE_PG_MASK));
+                PPGMVIRTHANDLERTYPEINT pCurType = PGMVIRTANDLER_GET_TYPE(pVM, pCur);
+                if  (   uErr & X86_TRAP_PF_RW
+                     || pCurType->enmKind != PGMVIRTHANDLERKIND_WRITE )
+                {
+                    Assert(   (pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK)
+                           == (pGstWalk->Core.GCPhys & X86_PTE_PAE_PG_MASK));
 #   ifdef IN_RC
-                STAM_PROFILE_START(&pCur->Stat, h);
-                RTGCPTR                     GCPtrStart = pCur->Core.Key;
-                CTX_MID(PFNPGM,VIRTHANDLER) pfnHandler = pCur->CTX_SUFF(pfnHandler);
-                pgmUnlock(pVM);
-                *pfLockTaken = false;
-
-                RTGCPTR off = (iPage << PAGE_SHIFT)
-                            + (pvFault    & PAGE_OFFSET_MASK)
-                            - (GCPtrStart & PAGE_OFFSET_MASK);
-                Assert(off < pCur->cb);
-                rc = pfnHandler(pVM, uErr, pRegFrame, pvFault, GCPtrStart, off);
+                    STAM_PROFILE_START(&pCur->Stat, h);
+                    RTGCPTR                     GCPtrStart = pCur->Core.Key;
+                    CTX_MID(PFNPGM,VIRTHANDLER) pfnHandler = pCurType->CTX_SUFF(pfnHandler);
+                    pgmUnlock(pVM);
+                    *pfLockTaken = false;
+
+                    RTGCPTR off = (iPage << PAGE_SHIFT)
+                                + (pvFault    & PAGE_OFFSET_MASK)
+                                - (GCPtrStart & PAGE_OFFSET_MASK);
+                    Assert(off < pCur->cb);
+                    rc = pfnHandler(pVM, uErr, pRegFrame, pvFault, GCPtrStart, off);
 
 #    ifdef VBOX_WITH_STATISTICS
-                pgmLock(pVM);
-                pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtrStart);
-                if (pCur)
-                    STAM_PROFILE_STOP(&pCur->Stat, h);
-                pgmUnlock(pVM);
+                    pgmLock(pVM);
+                    pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtrStart);
+                    if (pCur)
+                        STAM_PROFILE_STOP(&pCur->Stat, h);
+                    pgmUnlock(pVM);
 #    endif
 #   else
-                rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
+                    rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
 #   endif
-                STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersVirtualByPhys);
-                STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2HndVirt; });
-                return rc;
+                    STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eHandlersVirtualByPhys);
+                    STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2HndVirt; });
+                    return rc;
+                }
             }
         }
@@ -720,6 +725,7 @@
 #   ifdef IN_RC
                     STAM_PROFILE_START(&pCur->Stat, h);
+                    PPGMVIRTHANDLERTYPEINT pCurType = PGMVIRTANDLER_GET_TYPE(pVM, pCur);
                     pgmUnlock(pVM);
-                    rc = pCur->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
+                    rc = pCurType->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
                     pgmLock(pVM);
                     STAM_PROFILE_STOP(&pCur->Stat, h);
@@ -800,18 +806,20 @@
         if (pCur)
         {
+            PPGMVIRTHANDLERTYPEINT pCurType = PGMVIRTANDLER_GET_TYPE(pVM, pCur);
             AssertMsg(   !(pvFault - pCur->Core.Key < pCur->cb)
-                      || (    pCur->enmType != PGMVIRTHANDLERTYPE_WRITE
+                      || (    pCurType->enmKind != PGMVIRTHANDLERKIND_WRITE
                            || !(uErr & X86_TRAP_PF_P)
-                           || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
-                      ("Unexpected trap for virtual handler: %08X (phys=%08x) %R[pgmpage] uErr=%X, enum=%d\n", pvFault, GCPhys, pPage, uErr, pCur->enmType));
+                           || (pCurType->enmKind == PGMVIRTHANDLERKIND_WRITE && (uErr & X86_TRAP_PF_RW))),
+                      ("Unexpected trap for virtual handler: %08X (phys=%08x) %R[pgmpage] uErr=%X, enumKind=%d\n",
+                       pvFault, GCPhys, pPage, uErr, pCurType->enmKind));
 
             if (    pvFault - pCur->Core.Key < pCur->cb
                 &&  (    uErr & X86_TRAP_PF_RW
-                     ||  pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
+                     ||  pCurType->enmKind != PGMVIRTHANDLERKIND_WRITE ) )
             {
 #   ifdef IN_RC
                 STAM_PROFILE_START(&pCur->Stat, h);
                 pgmUnlock(pVM);
-                rc = pCur->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
+                rc = pCurType->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
                 pgmLock(pVM);
                 STAM_PROFILE_STOP(&pCur->Stat, h);
Index: /trunk/src/VBox/VMM/VMMAll/PGMAllGst.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllGst.h	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllGst.h	(revision 55889)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -462,9 +462,11 @@
 static DECLCALLBACK(int) PGM_GST_NAME(VirtHandlerUpdateOne)(PAVLROGCPTRNODECORE pNode, void *pvUser)
 {
-    PPGMVIRTHANDLER pCur   = (PPGMVIRTHANDLER)pNode;
-    PPGMHVUSTATE    pState = (PPGMHVUSTATE)pvUser;
-    PVM             pVM    = pState->pVM;
-    PVMCPU          pVCpu  = pState->pVCpu;
-    Assert(pCur->enmType != PGMVIRTHANDLERTYPE_HYPERVISOR);
+    PPGMHVUSTATE            pState   = (PPGMHVUSTATE)pvUser;
+    PVM                     pVM      = pState->pVM;
+    PVMCPU                  pVCpu    = pState->pVCpu;
+    PPGMVIRTHANDLER         pCur     = (PPGMVIRTHANDLER)pNode;
+    PPGMVIRTHANDLERTYPEINT  pCurType = PGMVIRTANDLER_GET_TYPE(pVM, pCur);
+
+    Assert(pCurType->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR);
 
 # if PGM_GST_TYPE == PGM_TYPE_32BIT
Index: /trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp	(revision 55889)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -1367,4 +1367,71 @@
 
 /**
+ * Internal worker for releasing a virtual handler type registration reference.
+ *
+ * @returns New reference count. UINT32_MAX if invalid input (asserted).
+ * @param   pVM         Pointer to the cross context VM structure.
+ * @param   pType       Pointer to the type registration.
+ */
+DECLINLINE(uint32_t) pgmHandlerVirtualTypeRelease(PVM pVM, PPGMVIRTHANDLERTYPEINT pType)
+{
+    AssertMsgReturn(pType->u32Magic == PGMVIRTHANDLERTYPEINT_MAGIC, ("%#x\n", pType->u32Magic), UINT32_MAX);
+    uint32_t cRefs = ASMAtomicDecU32(&pType->cRefs);
+    if (cRefs == 0)
+    {
+        pgmLock(pVM);
+        pType->u32Magic = PGMVIRTHANDLERTYPEINT_MAGIC_DEAD;
+        RTListOff32NodeRemove(&pType->ListNode);
+        pgmUnlock(pVM);
+        MMHyperFree(pVM, pType);
+    }
+    return cRefs;
+}
+
+
+/**
+ * Internal worker for retaining a virtual handler type registration reference.
+ *
+ * @returns New reference count. UINT32_MAX if invalid input (asserted).
+ * @param   pVM         Pointer to the cross context VM structure.
+ * @param   pType       Pointer to the type registration.
+ */
+DECLINLINE(uint32_t) pgmHandlerVirtualTypeRetain(PVM pVM, PPGMVIRTHANDLERTYPEINT pType)
+{
+    AssertMsgReturn(pType->u32Magic == PGMVIRTHANDLERTYPEINT_MAGIC, ("%#x\n", pType->u32Magic), UINT32_MAX);
+    uint32_t cRefs = ASMAtomicIncU32(&pType->cRefs);
+    Assert(cRefs < _1M && cRefs > 0);
+    return cRefs;
+}
+
+
+/**
+ * Releases a reference to a virtual handler type registration.
+ *
+ * @returns New reference count. UINT32_MAX if invalid input (asserted).
+ * @param   pVM         Pointer to the cross context VM structure.
+ * @param   hType       The type regiration handle.
+ */
+VMM_INT_DECL(uint32_t) PGMHandlerVirtualTypeRelease(PVM pVM, PGMVIRTHANDLERTYPE hType)
+{
+    if (hType != NIL_PGMVIRTHANDLERTYPE)
+        return pgmHandlerVirtualTypeRelease(pVM, PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hType));
+    return 0;
+}
+
+
+/**
+ * Retains a reference to a virtual handler type registration.
+ *
+ * @returns New reference count. UINT32_MAX if invalid input (asserted).
+ * @param   pVM         Pointer to the cross context VM structure.
+ * @param   hType       The type regiration handle.
+ */
+VMM_INT_DECL(uint32_t) PGMHandlerVirtualTypeRetain(PVM pVM, PGMVIRTHANDLERTYPE hType)
+{
+    return pgmHandlerVirtualTypeRetain(pVM, PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hType));
+}
+
+
+/**
  * Check if particular guest's VA is being monitored.
  *
@@ -1375,5 +1442,5 @@
  * @thread  Any.
  */
-VMMDECL(bool) PGMHandlerVirtualIsRegistered(PVM pVM, RTGCPTR GCPtr)
+VMM_INT_DECL(bool) PGMHandlerVirtualIsRegistered(PVM pVM, RTGCPTR GCPtr)
 {
     pgmLock(pVM);
@@ -1493,5 +1560,5 @@
      * Iterate the pages and apply the new state.
      */
-    unsigned        uState   = pgmHandlerVirtualCalcState(pCur);
+    uint32_t        uState   = PGMVIRTANDLER_GET_TYPE(pVM, pCur)->uState;
     PPGMRAMRANGE    pRamHint = NULL;
     RTGCUINTPTR     offPage  = ((RTGCUINTPTR)pCur->Core.Key & PAGE_OFFSET_MASK);
@@ -1645,22 +1712,23 @@
 static DECLCALLBACK(int) pgmHandlerVirtualVerifyOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
 {
-    PPGMVIRTHANDLER pVirt   = (PPGMVIRTHANDLER)pNode;
-    PPGMAHAFIS      pState  = (PPGMAHAFIS)pvUser;
-    PVM             pVM     = pState->pVM;
+    PPGMAHAFIS              pState  = (PPGMAHAFIS)pvUser;
+    PVM                     pVM     = pState->pVM;
+    PPGMVIRTHANDLER         pVirt   = (PPGMVIRTHANDLER)pNode;
+    PPGMVIRTHANDLERTYPEINT  pType   = PGMVIRTANDLER_GET_TYPE(pVM, pVirt);
 
     /*
      * Validate the type and calc state.
      */
-    switch (pVirt->enmType)
-    {
-        case PGMVIRTHANDLERTYPE_WRITE:
-        case PGMVIRTHANDLERTYPE_ALL:
+    switch (pType->enmKind)
+    {
+        case PGMVIRTHANDLERKIND_WRITE:
+        case PGMVIRTHANDLERKIND_ALL:
             break;
         default:
-            AssertMsgFailed(("unknown/wrong enmType=%d\n", pVirt->enmType));
+            AssertMsgFailed(("unknown/wrong enmKind=%d\n", pType->enmKind));
             pState->cErrors++;
             return 0;
     }
-    const unsigned uState = pgmHandlerVirtualCalcState(pVirt);
+    const uint32_t uState = pType->uState;
 
     /*
@@ -1857,5 +1925,5 @@
                         GCPhysKey = pPhys2Virt->Core.KeyLast;
                         PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)((uintptr_t)pPhys2Virt + pPhys2Virt->offVirtHandler);
-                        unsigned uState = pgmHandlerVirtualCalcState(pCur);
+                        unsigned uState = PGMVIRTANDLER_GET_TYPE(pVM, pCur)->uState;
                         State.uVirtStateFound = RT_MAX(State.uVirtStateFound, uState);
 
@@ -1865,5 +1933,5 @@
                             pPhys2Virt = (PPGMPHYS2VIRTHANDLER)((uintptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
                             pCur = (PPGMVIRTHANDLER)((uintptr_t)pPhys2Virt + pPhys2Virt->offVirtHandler);
-                            uState = pgmHandlerVirtualCalcState(pCur);
+                            uState = PGMVIRTANDLER_GET_TYPE(pVM, pCur)->uState;
                             State.uVirtStateFound = RT_MAX(State.uVirtStateFound, uState);
                         }
Index: /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp	(revision 55889)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -2159,6 +2159,7 @@
         Assert(GCPhys >= pVirt->aPhysToVirt[iPage].Core.Key && GCPhys <= pVirt->aPhysToVirt[iPage].Core.KeyLast);
 
+        PPGMVIRTHANDLERTYPEINT pVirtType = PGMVIRTANDLER_GET_TYPE(pVM, pVirt);
 #ifdef IN_RING3
-        if (pVirt->pfnHandlerR3)
+        if (pVirtType->pfnHandlerR3)
         {
             if (!pPhys)
@@ -2171,5 +2172,6 @@
 
             STAM_PROFILE_START(&pVirt->Stat, h);
-            rc2 = pVirt->CTX_SUFF(pfnHandler)(pVM, GCPtr, (void *)pvSrc, pvBuf, cb, PGMACCESSTYPE_READ, /*pVirt->CTX_SUFF(pvUser)*/ NULL);
+            rc2 = pVirtType->CTX_SUFF(pfnHandler)(pVM, GCPtr, (void *)pvSrc, pvBuf, cb, PGMACCESSTYPE_READ,
+                                                  pVirt->CTX_SUFF(pvUser));
             STAM_PROFILE_STOP(&pVirt->Stat, h);
             if (rc2 == VINF_SUCCESS)
@@ -2430,4 +2432,6 @@
         if (RT_SUCCESS(rc))
         {
+            PPGMVIRTHANDLERTYPEINT pCurType = PGMVIRTANDLER_GET_TYPE(pVM, pCur);
+
             size_t cbRange = (PAGE_OFFSET_MASK & pCur->Core.KeyLast) - (PAGE_OFFSET_MASK & GCPhys) + 1;
             if (cbRange > cbWrite)
@@ -2447,5 +2451,5 @@
             {
                 rc = VINF_PGM_HANDLER_DO_DEFAULT;
-                if (pCur->pfnHandlerR3)
+                if (pCurType->pfnHandlerR3)
                 {
                     RTGCUINTPTR GCPtr = ((RTGCUINTPTR)pCur->Core.Key & PAGE_BASE_GC_MASK)
@@ -2454,5 +2458,6 @@
 
                     STAM_PROFILE_START(&pCur->Stat, h);
-                    rc = pCur->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, /*pCur->CTX_SUFF(pvUser)*/ NULL);
+                    rc = pCurType->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE,
+                                                        pCur->CTX_SUFF(pvUser));
                     STAM_PROFILE_STOP(&pCur->Stat, h);
                 }
@@ -2631,7 +2636,9 @@
             if (cbRange > offPhys)
                 cbRange = offPhys;
+
+            PPGMVIRTHANDLERTYPEINT pVirtType = PGMVIRTANDLER_GET_TYPE(pVM, pVirt);
 #ifdef IN_RING3
             Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cbRange, pPage, R3STRING(pVirt->pszDesc) ));
-            if (pVirt->pfnHandlerR3)
+            if (pVirtType->pfnHandlerR3)
             {
                 RTGCUINTPTR GCPtr = ((RTGCUINTPTR)pVirt->Core.Key & PAGE_BASE_GC_MASK)
@@ -2639,5 +2646,6 @@
                                   + (GCPhys & PAGE_OFFSET_MASK);
                 STAM_PROFILE_START(&pVirt->Stat, h);
-                rc = pVirt->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, /*pCur->CTX_SUFF(pvUser)*/ NULL);
+                rc = pVirtType->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE,
+                                                     pVirt->CTX_SUFF(pvUser));
                 STAM_PROFILE_STOP(&pVirt->Stat, h);
                 AssertLogRelMsg(rc == VINF_SUCCESS || rc == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc, GCPhys, pPage, pVirt->pszDesc));
@@ -2663,6 +2671,7 @@
                 cbRange = offPhysLast + 1;
 
+            PPGMVIRTHANDLERTYPEINT pVirtType = PGMVIRTANDLER_GET_TYPE(pVM, pVirt);
 #ifdef IN_RING3
-            if (pVirt->pfnHandlerR3)
+            if (pVirtType->pfnHandlerR3)
                 Log(("pgmPhysWriteHandler: overlapping phys and virt handlers at %RGp %R[pgmpage]; cbRange=%#x\n", GCPhys, pPage, cbRange));
             Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys/virt %s/%s\n", GCPhys, cbRange, pPage, R3STRING(pPhys->pszDesc), R3STRING(pVirt->pszDesc) ));
@@ -2685,5 +2694,5 @@
 # endif
             AssertLogRelMsg(rc == VINF_SUCCESS || rc == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc, GCPhys, pPage, (pPhys) ? pPhys->pszDesc : ""));
-            if (pVirt->pfnHandlerR3)
+            if (pVirtType->pfnHandlerR3)
             {
 
@@ -2692,5 +2701,6 @@
                                   + (GCPhys & PAGE_OFFSET_MASK);
                 STAM_PROFILE_START(&pVirt->Stat, h2);
-                int rc2 = pVirt->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, /*pCur->CTX_SUFF(pvUser)*/ NULL);
+                int rc2 = pVirtType->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE,
+                                                          pVirt->CTX_SUFF(pvUser));
                 STAM_PROFILE_STOP(&pVirt->Stat, h2);
                 if (rc2 == VINF_SUCCESS && rc == VINF_PGM_HANDLER_DO_DEFAULT)
Index: /trunk/src/VBox/VMM/VMMR3/CSAM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/CSAM.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMR3/CSAM.cpp	(revision 55889)
@@ -251,4 +251,22 @@
 
     /*
+     * Register virtual handler types.
+     */
+    rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_WRITE, false /*fRelocUserRC*/,
+                                         NULL /*pfnInvalidateR3 */,
+                                         CSAMCodePageWriteHandler,
+                                         "CSAMGCCodePageWriteHandler", NULL /*pszModRC*/,
+                                         "CSAM code page write handler",
+                                         &pVM->csam.s.hCodePageWriteType);
+    AssertLogRelRCReturn(rc, rc);
+    rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_WRITE, false /*fRelocUserRC*/,
+                                         CSAMCodePageInvalidate,
+                                         CSAMCodePageWriteHandler,
+                                         "CSAMGCCodePageWriteHandler", NULL /*pszModRC*/,
+                                         "CSAM code page write and invlpg handler",
+                                         &pVM->csam.s.hCodePageWriteAndInvPgType);
+    AssertLogRelRCReturn(rc, rc);
+
+    /*
      * Register save and load state notifiers.
      */
@@ -1855,14 +1873,16 @@
     case CSAM_TAG_PATM:
     case CSAM_TAG_REM:
-#ifdef CSAM_MONITOR_CSAM_CODE_PAGES
+# ifdef CSAM_MONITOR_CSAM_CODE_PAGES
     case CSAM_TAG_CSAM:
-#endif
-    {
-        rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtr, GCPtr + (PAGE_SIZE - 1) /* inclusive! */,
-                                         (fMonitorInvalidation) ? CSAMCodePageInvalidate : 0, CSAMCodePageWriteHandler, "CSAMGCCodePageWriteHandler", 0,
-                                         csamGetMonitorDescription(enmTag));
-        AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT, ("PGMR3HandlerVirtualRegisterEx %RRv failed with %Rrc\n", GCPtr, rc));
+# endif
+    {
+        rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, fMonitorInvalidation
+                                         ? pVM->csam.s.hCodePageWriteAndInvPgType : pVM->csam.s.hCodePageWriteType,
+                                         GCPtr, GCPtr + (PAGE_SIZE - 1) /* inclusive! */,
+                                         pPage, NIL_RTRCPTR, csamGetMonitorDescription(enmTag));
+        AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT,
+                  ("PGMR3HandlerVirtualRegister %RRv failed with %Rrc\n", GCPtr, rc));
         if (RT_FAILURE(rc))
-            Log(("PGMR3HandlerVirtualRegisterEx for %RRv failed with %Rrc\n", GCPtr, rc));
+            Log(("PGMR3HandlerVirtualRegister for %RRv failed with %Rrc\n", GCPtr, rc));
 
         /* Could fail, because it's already monitored. Don't treat that condition as fatal. */
@@ -1885,5 +1905,5 @@
     Log(("csamCreatePageRecord %RRv GCPhys=%RGp\n", GCPtr, pPage->page.GCPhys));
 
-#ifdef VBOX_WITH_STATISTICS
+# ifdef VBOX_WITH_STATISTICS
     switch (enmTag)
     {
@@ -1900,5 +1920,5 @@
         break; /* to shut up GCC */
     }
-#endif
+# endif
 
 #endif
@@ -1921,5 +1941,5 @@
 VMMR3DECL(int) CSAMR3MonitorPage(PVM pVM, RTRCPTR pPageAddrGC, CSAMTAG enmTag)
 {
-    PCSAMPAGEREC pPageRec = NULL;
+    ;
     int          rc;
     bool         fMonitorInvalidation;
@@ -1941,5 +1961,5 @@
     fMonitorInvalidation = (enmTag == CSAM_TAG_PATM);
 
-    pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)pPageAddrGC);
+    PCSAMPAGEREC pPageRec = (PCSAMPAGEREC)RTAvlPVGet(&pVM->csam.s.pPageTree, (AVLPVKEY)(uintptr_t)pPageAddrGC);
     if (pPageRec == NULL)
     {
@@ -1972,10 +1992,12 @@
         Log(("CSAMR3MonitorPage: activate monitoring for %RRv\n", pPageAddrGC));
 
-        rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, pPageAddrGC, pPageAddrGC + (PAGE_SIZE - 1) /* inclusive! */,
-                                         (fMonitorInvalidation) ? CSAMCodePageInvalidate : 0, CSAMCodePageWriteHandler, "CSAMGCCodePageWriteHandler", 0,
-                                         csamGetMonitorDescription(enmTag));
-        AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT, ("PGMR3HandlerVirtualRegisterEx %RRv failed with %Rrc\n", pPageAddrGC, rc));
+        rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, fMonitorInvalidation
+                                         ? pVM->csam.s.hCodePageWriteAndInvPgType : pVM->csam.s.hCodePageWriteType,
+                                         pPageAddrGC, pPageAddrGC + (PAGE_SIZE - 1) /* inclusive! */,
+                                         pPageRec, NIL_RTRCPTR /*pvUserRC*/, csamGetMonitorDescription(enmTag));
+        AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT,
+                  ("PGMR3HandlerVirtualRegister %RRv failed with %Rrc\n", pPageAddrGC, rc));
         if (RT_FAILURE(rc))
-            Log(("PGMR3HandlerVirtualRegisterEx for %RRv failed with %Rrc\n", pPageAddrGC, rc));
+            Log(("PGMR3HandlerVirtualRegister for %RRv failed with %Rrc\n", pPageAddrGC, rc));
 
         /* Could fail, because it's already monitored. Don't treat that condition as fatal. */
@@ -1998,5 +2020,6 @@
     {
         Assert(pPageRec->page.fMonitorActive);
-        PGMHandlerVirtualChangeInvalidateCallback(pVM, pPageRec->page.pPageGC, CSAMCodePageInvalidate);
+        rc = PGMHandlerVirtualChangeType(pVM, pPageRec->page.pPageGC, pVM->csam.s.hCodePageWriteAndInvPgType);
+        AssertRC(rc);
         pPageRec->page.fMonitorInvalidation = true;
         STAM_COUNTER_INC(&pVM->csam.s.StatNrPagesInv);
@@ -2091,5 +2114,5 @@
             Assert(!fInCSAMCodePageInvalidate);
             STAM_COUNTER_DEC(&pVM->csam.s.StatPageMonitor);
-            PGMHandlerVirtualDeregister(pVM, GCPtr);
+            PGMHandlerVirtualDeregister(pVM, pVCpu, GCPtr, false /*fHypervisor*/);
         }
         if (pPageRec->page.enmTag == CSAM_TAG_PATM)
Index: /trunk/src/VBox/VMM/VMMR3/PATM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PATM.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMR3/PATM.cpp	(revision 55889)
@@ -367,5 +367,17 @@
                           ("%RRv-%RRv => %#x\n", pVM->patm.s.pbPatchHelpersRC, RCPtrEnd, pVM->patm.s.cbPatchHelpers),
                           VERR_INTERNAL_ERROR_4);
-    return rc;
+
+
+    /*
+     * Register the virtual page access handler type.
+     */
+    rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_ALL, false /*fRelocUserRC*/,
+                                         NULL /*pfnInvalidateR3*/,
+                                         patmVirtPageHandler,
+                                         "PATMGCMonitorPage", NULL /*pszModRC*/,
+                                         "PATMMonitorPatchJump", &pVM->patm.s.hMonitorPageType);
+    AssertRCReturn(rc, rc);
+
+    return VINF_SUCCESS;
 }
 
@@ -818,5 +830,8 @@
 
                     Log(("PATM: Patch page not present -> check later!\n"));
-                    rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_ALL, pPage, pPage + (PAGE_SIZE - 1) /* inclusive! */, 0, patmVirtPageHandler, "PATMGCMonitorPage", 0, "PATMMonitorPatchJump");
+                    rc = PGMR3HandlerVirtualRegister(pVM, VMMGetCpu(pVM), pVM->patm.s.hMonitorPageType,
+                                                     pPage,
+                                                     pPage + (PAGE_SIZE - 1) /* inclusive! */,
+                                                     (void *)(uintptr_t)pPage, pPage, NULL /*pszDesc*/);
                     Assert(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT);
                 }
@@ -896,6 +911,9 @@
                 {
                     RTRCPTR pPage = pPatch->patch.pPrivInstrGC & PAGE_BASE_GC_MASK;
-
-                    rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_ALL, pPage, pPage + (PAGE_SIZE - 1) /* inclusive! */, 0, patmVirtPageHandler, "PATMGCMonitorPage", 0, "PATMMonitorPatchJump");
+                    Log(("PATM: Patch page not present -> check later!\n"));
+                    rc = PGMR3HandlerVirtualRegister(pVM, VMMGetCpu(pVM), pVM->patm.s.hMonitorPageType,
+                                                     pPage,
+                                                     pPage + (PAGE_SIZE - 1) /* inclusive! */,
+                                                     (void *)(uintptr_t)pPage, pPage, NULL /*pszDesc*/);
                     Assert(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT);
                 }
@@ -6673,9 +6691,10 @@
 {
     AssertReturn(!HMIsEnabled(pVM), VERR_PATM_HM_IPE);
+    PVMCPU pVCpu = VMMGetCpu0(pVM);
 
     RTRCPTR addr = pVM->patm.s.pvFaultMonitor;
     addr &= PAGE_BASE_GC_MASK;
 
-    int rc = PGMHandlerVirtualDeregister(pVM, addr);
+    int rc = PGMHandlerVirtualDeregister(pVM, pVCpu, addr, false /*fHypervisor*/);
     AssertRC(rc); NOREF(rc);
 
Index: /trunk/src/VBox/VMM/VMMR3/PATMSSM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PATMSSM.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMR3/PATMSSM.cpp	(revision 55889)
@@ -1479,6 +1479,8 @@
             {
                 RTRCPTR pPage = pPatch->pPrivInstrGC & PAGE_BASE_GC_MASK;
-
-                rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_ALL, pPage, pPage + (PAGE_SIZE - 1) /* inclusive! */, 0, patmVirtPageHandler, "PATMGCMonitorPage", 0, "PATMMonitorPatchJump");
+                rc = PGMR3HandlerVirtualRegister(pVM, VMMGetCpu(pVM), pVM->patm.s.hMonitorPageType,
+                                                 pPage,
+                                                 pPage + (PAGE_SIZE - 1) /* inclusive! */,
+                                                 (void *)(uintptr_t)pPage, pPage, NULL /*pszDesc*/);
                 Assert(RT_SUCCESS(rc) || rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT);
             }
@@ -1521,5 +1523,5 @@
 
     }
-}
+    }
     return VINF_SUCCESS;
 }
Index: /trunk/src/VBox/VMM/VMMR3/PGM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PGM.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMR3/PGM.cpp	(revision 55889)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2013 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -164,5 +164,5 @@
  *
  * We currently implement three types of virtual access handlers:  ALL, WRITE
- * and HYPERVISOR (WRITE). See PGMVIRTHANDLERTYPE for some more details.
+ * and HYPERVISOR (WRITE). See PGMVIRTHANDLERKIND for some more details.
  *
  * The HYPERVISOR access handlers is kept in a separate tree since it doesn't apply
@@ -646,4 +646,20 @@
 #include <iprt/string.h>
 #include <iprt/thread.h>
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Argument package for pgmR3RElocatePhysHnadler, pgmR3RelocateVirtHandler and
+ * pgmR3RelocateHyperVirtHandler.
+ */
+typedef struct PGMRELOCHANDLERARGS
+{
+    RTGCINTPTR  offDelta;
+    PVM         pVM;
+} PGMRELOCHANDLERARGS;
+/** Pointer to a page access handlere relocation argument package. */
+typedef PGMRELOCHANDLERARGS const *PCPGMRELOCHANDLERARGS;
 
 
@@ -2407,5 +2423,6 @@
      * Physical and virtual handlers.
      */
-    RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesR3->PhysHandlers,     true, pgmR3RelocatePhysHandler,      &offDelta);
+    PGMRELOCHANDLERARGS Args = { offDelta, pVM };
+    RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesR3->PhysHandlers,     true, pgmR3RelocatePhysHandler,      &Args);
     pVM->pgm.s.pLastPhysHandlerRC = NIL_RTRCPTR;
 
@@ -2413,10 +2430,17 @@
     RTListOff32ForEach(&pVM->pgm.s.pTreesR3->HeadPhysHandlerTypes, pCurPhysType, PGMPHYSHANDLERTYPEINT, ListNode)
     {
-        if (pCurPhysType->pfnHandlerRC)
+        if (pCurPhysType->pfnHandlerRC != NIL_RTRCPTR)
             pCurPhysType->pfnHandlerRC += offDelta;
     }
 
-    RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->VirtHandlers,      true, pgmR3RelocateVirtHandler,      &offDelta);
-    RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->HyperVirtHandlers, true, pgmR3RelocateHyperVirtHandler, &offDelta);
+    RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->VirtHandlers,      true, pgmR3RelocateVirtHandler,      &Args);
+    RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->HyperVirtHandlers, true, pgmR3RelocateHyperVirtHandler, &Args);
+
+    PPGMVIRTHANDLERTYPEINT pCurVirtType;
+    RTListOff32ForEach(&pVM->pgm.s.pTreesR3->HeadVirtHandlerTypes, pCurVirtType, PGMVIRTHANDLERTYPEINT, ListNode)
+    {
+        if (pCurVirtType->pfnHandlerRC != NIL_RTRCPTR)
+            pCurVirtType->pfnHandlerRC += offDelta;
+    }
 
     /*
@@ -2441,13 +2465,12 @@
  * @returns 0 (continue enum)
  * @param   pNode       Pointer to a PGMPHYSHANDLER node.
- * @param   pvUser      Pointer to the offDelta. This is a pointer to the delta since we're
- *                      not certain the delta will fit in a void pointer for all possible configs.
+ * @param   pvUser      Pointer to a PGMRELOCHANDLERARGS.
  */
 static DECLCALLBACK(int) pgmR3RelocatePhysHandler(PAVLROGCPHYSNODECORE pNode, void *pvUser)
 {
-    PPGMPHYSHANDLER pHandler = (PPGMPHYSHANDLER)pNode;
-    RTGCINTPTR      offDelta = *(PRTGCINTPTR)pvUser;
+    PPGMPHYSHANDLER         pHandler = (PPGMPHYSHANDLER)pNode;
+    PCPGMRELOCHANDLERARGS   pArgs    = (PCPGMRELOCHANDLERARGS)pvUser;
     if (pHandler->pvUserRC >= 0x10000)
-        pHandler->pvUserRC += offDelta;
+        pHandler->pvUserRC += pArgs->offDelta;
     return 0;
 }
@@ -2459,15 +2482,15 @@
  * @returns 0 (continue enum)
  * @param   pNode       Pointer to a PGMVIRTHANDLER node.
- * @param   pvUser      Pointer to the offDelta. This is a pointer to the delta since we're
- *                      not certain the delta will fit in a void pointer for all possible configs.
+ * @param   pvUser      Pointer to a PGMRELOCHANDLERARGS.
  */
 static DECLCALLBACK(int) pgmR3RelocateVirtHandler(PAVLROGCPTRNODECORE pNode, void *pvUser)
 {
-    PPGMVIRTHANDLER pHandler = (PPGMVIRTHANDLER)pNode;
-    RTGCINTPTR      offDelta = *(PRTGCINTPTR)pvUser;
-    Assert(     pHandler->enmType == PGMVIRTHANDLERTYPE_ALL
-           ||   pHandler->enmType == PGMVIRTHANDLERTYPE_WRITE);
-    Assert(pHandler->pfnHandlerRC);
-    pHandler->pfnHandlerRC += offDelta;
+    PPGMVIRTHANDLER         pHandler = (PPGMVIRTHANDLER)pNode;
+    PCPGMRELOCHANDLERARGS   pArgs    = (PCPGMRELOCHANDLERARGS)pvUser;
+    Assert(PGMVIRTANDLER_GET_TYPE(pArgs->pVM, pHandler)->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR);
+
+    if (   pHandler->pvUserRC != NIL_RTRCPTR
+        && PGMVIRTANDLER_GET_TYPE(pArgs->pVM, pHandler)->fRelocUserRC)
+        pHandler->pvUserRC += pArgs->offDelta;
     return 0;
 }
@@ -2479,14 +2502,15 @@
  * @returns 0 (continue enum)
  * @param   pNode       Pointer to a PGMVIRTHANDLER node.
- * @param   pvUser      Pointer to the offDelta. This is a pointer to the delta since we're
- *                      not certain the delta will fit in a void pointer for all possible configs.
+ * @param   pvUser      Pointer to a PGMRELOCHANDLERARGS.
  */
 static DECLCALLBACK(int) pgmR3RelocateHyperVirtHandler(PAVLROGCPTRNODECORE pNode, void *pvUser)
 {
-    PPGMVIRTHANDLER pHandler = (PPGMVIRTHANDLER)pNode;
-    RTGCINTPTR      offDelta = *(PRTGCINTPTR)pvUser;
-    Assert(pHandler->enmType == PGMVIRTHANDLERTYPE_HYPERVISOR);
-    Assert(pHandler->pfnHandlerRC);
-    pHandler->pfnHandlerRC  += offDelta;
+    PPGMVIRTHANDLER         pHandler = (PPGMVIRTHANDLER)pNode;
+    PCPGMRELOCHANDLERARGS   pArgs    = (PCPGMRELOCHANDLERARGS)pvUser;
+    Assert(PGMVIRTANDLER_GET_TYPE(pArgs->pVM, pHandler)->enmKind == PGMVIRTHANDLERKIND_HYPERVISOR);
+
+    if (   pHandler->pvUserRC != NIL_RTRCPTR
+        && PGMVIRTANDLER_GET_TYPE(pArgs->pVM, pHandler)->fRelocUserRC)
+        pHandler->pvUserRC += pArgs->offDelta;
     return 0;
 }
Index: /trunk/src/VBox/VMM/VMMR3/PGMHandler.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PGMHandler.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMR3/PGMHandler.cpp	(revision 55889)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -79,9 +79,9 @@
  *                          safe).
  */
-VMM_INT_DECL(int) PGMR3HandlerPhysicalTypeRegisterEx(PVM pVM, PGMPHYSHANDLERKIND enmKind,
-                                                     PFNPGMR3PHYSHANDLER pfnHandlerR3,
-                                                     R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0,
-                                                     RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC,
-                                                     const char *pszDesc, PPGMPHYSHANDLERTYPE phType)
+VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegisterEx(PVM pVM, PGMPHYSHANDLERKIND enmKind,
+                                                       PFNPGMR3PHYSHANDLER pfnHandlerR3,
+                                                       R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0,
+                                                       RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC,
+                                                       const char *pszDesc, PPGMPHYSHANDLERTYPE phType)
 {
     AssertPtrReturn(pfnHandlerR3, VERR_INVALID_POINTER);
@@ -273,124 +273,162 @@
 
 /**
+ * Register a virtual page access handler type, extended version.
+ *
+ * @returns VBox status code.
+ * @param   pVM             Pointer to the cross context VM structure.
+ * @param   enmKind         The kind of access handler.
+ * @param   fRelocUserRC    Whether the pvUserRC argument should be
+ *                          automatically relocated or not.
+ * @param   pfnInvalidateR3 Pointer to the ring-3 invalidation handler callback.
+ * @param   pfnHandlerR3    Pointer to the ring-3 handler callback.
+ * @param   pfnHandlerRC    Pointer to the raw-mode context handler callback.
+ * @param   pszDesc         The type description.
+ * @param   phType          Where to return the type handle (cross context
+ *                          safe).
+ * @remarks No virtual handlers when executing using HM (i.e. ring-0).
+ */
+VMMR3_INT_DECL(int) PGMR3HandlerVirtualTypeRegisterEx(PVM pVM, PGMVIRTHANDLERKIND enmKind, bool fRelocUserRC,
+                                                      PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
+                                                      PFNPGMR3VIRTHANDLER pfnHandlerR3,
+                                                      RCPTRTYPE(PFNPGMRCVIRTHANDLER) pfnHandlerRC,
+                                                      const char *pszDesc, PPGMVIRTHANDLERTYPE phType)
+{
+    AssertReturn(!HMIsEnabled(pVM), VERR_NOT_AVAILABLE); /* Not supported/relevant for VT-x and AMD-V. */
+    AssertReturn(RT_VALID_PTR(pfnHandlerR3) || enmKind == PGMVIRTHANDLERKIND_HYPERVISOR, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pfnInvalidateR3, VERR_INVALID_POINTER);
+    AssertReturn(pfnHandlerRC != NIL_RTRCPTR, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
+    AssertReturn(   enmKind == PGMVIRTHANDLERKIND_WRITE
+                 || enmKind == PGMVIRTHANDLERKIND_ALL
+                 || enmKind == PGMVIRTHANDLERKIND_HYPERVISOR,
+                 VERR_INVALID_PARAMETER);
+
+    PPGMVIRTHANDLERTYPEINT pType;
+    int rc = MMHyperAlloc(pVM, sizeof(*pType), 0, MM_TAG_PGM_HANDLER_TYPES, (void **)&pType);
+    if (RT_SUCCESS(rc))
+    {
+        pType->u32Magic         = PGMVIRTHANDLERTYPEINT_MAGIC;
+        pType->cRefs            = 1;
+        pType->enmKind          = enmKind;
+        pType->fRelocUserRC     = fRelocUserRC;
+        pType->uState           = enmKind == PGMVIRTHANDLERKIND_ALL
+                                ? PGM_PAGE_HNDL_VIRT_STATE_ALL : PGM_PAGE_HNDL_VIRT_STATE_WRITE;
+        pType->pfnInvalidateR3  = pfnInvalidateR3;
+        pType->pfnHandlerR3     = pfnHandlerR3;
+        pType->pfnHandlerRC     = pfnHandlerRC;
+        pType->pszDesc          = pszDesc;
+
+        pgmLock(pVM);
+        RTListOff32Append(&pVM->pgm.s.CTX_SUFF(pTrees)->HeadVirtHandlerTypes, &pType->ListNode);
+        pgmUnlock(pVM);
+
+        *phType = MMHyperHeapPtrToOffset(pVM, pType);
+        LogFlow(("PGMR3HandlerVirtualTypeRegisterEx: %p/%#x: enmKind=%d pfnInvalidateR3=%RHv pfnHandlerR3=%RHv pfnHandlerRC=%RRv pszDesc=%s\n",
+                 pType, *phType, enmKind, pfnInvalidateR3, pfnHandlerR3, pfnHandlerRC, pszDesc));
+        return VINF_SUCCESS;
+    }
+    *phType = NIL_PGMVIRTHANDLERTYPE;
+    return rc;
+}
+
+
+/**
+ * Register a physical page access handler type.
+ *
+ * @returns VBox status code.
+ * @param   pVM             Pointer to the cross context VM structure.
+ * @param   enmKind         The kind of access handler.
+ * @param   fRelocUserRC    Whether the pvUserRC argument should be
+ *                          automatically relocated or not.
+ * @param   pfnInvalidateR3 Pointer to the ring-3 invalidateion callback
+ *                          (optional, can be NULL).
+ * @param   pfnHandlerR3    Pointer to the ring-3 handler callback.
+ * @param   pszModRC        The name of the raw-mode context module, NULL is an
+ *                          alias for the main RC module.
+ * @param   pszHandlerRC    The name of the raw-mode context handler, NULL if
+ *                          the ring-3 handler should be called.
+ * @param   pszDesc         The type description.
+ * @param   phType          Where to return the type handle (cross context
+ *                          safe).
+ * @remarks No virtual handlers when executing using HM (i.e. ring-0).
+ */
+VMMR3_INT_DECL(int) PGMR3HandlerVirtualTypeRegister(PVM pVM, PGMVIRTHANDLERKIND enmKind, bool fRelocUserRC,
+                                                    PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
+                                                    PFNPGMR3VIRTHANDLER pfnHandlerR3,
+                                                    const char *pszHandlerRC, const char *pszModRC, const char *pszDesc,
+                                                    PPGMVIRTHANDLERTYPE phType)
+{
+    LogFlow(("PGMR3HandlerVirtualTypeRegister: enmKind=%d pfnInvalidateR3=%RHv pfnHandlerR3=%RHv pszModRC=%s pszHandlerRC=%s pszDesc=%s\n",
+             enmKind, pfnInvalidateR3, pfnHandlerR3, pszHandlerRC, pszModRC, pszDesc));
+
+    /*
+     * Validate input.
+     */
+    if (!pszModRC)
+        pszModRC = VMMGC_MAIN_MODULE_NAME;
+    if (!pszHandlerRC)
+        pszHandlerRC = "pgmVirtHandlerRedirectToHC";
+    AssertPtrReturn(pszHandlerRC, VERR_INVALID_POINTER);
+
+    /*
+     * Resolve the GC handler.
+     */
+    RTRCPTR pfnHandlerRC = NIL_RTRCPTR;
+    int rc = PDMR3LdrGetSymbolRCLazy(pVM, pszModRC, NULL /*pszSearchPath*/, pszHandlerRC, &pfnHandlerRC);
+    if (RT_SUCCESS(rc))
+        return PGMR3HandlerVirtualTypeRegisterEx(pVM, enmKind, fRelocUserRC,
+                                                 pfnInvalidateR3, pfnHandlerR3,
+                                                 pfnHandlerRC,
+                                                 pszDesc, phType);
+
+    AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszModRC, pszHandlerRC, rc));
+    return rc;
+}
+
+
+/**
  * Register a access handler for a virtual range.
  *
  * @returns VBox status code.
  * @param   pVM             Pointer to the VM.
- * @param   enmType         Handler type. Any of the PGMVIRTHANDLERTYPE_* enums.
+ * @param   hType           The handler type.
  * @param   GCPtr           Start address.
  * @param   GCPtrLast       Last address (inclusive).
- * @param   pfnInvalidateR3 The R3 invalidate callback (can be 0)
- * @param   pfnHandlerR3    The R3 handler.
- * @param   pszHandlerRC    The RC handler symbol name.
- * @param   pszModRC        The RC handler module.
+ * @param   pvUserR3        The ring-3 context user argument.
+ * @param   pvUserRC        The raw-mode context user argument.  Whether this is
+ *                          automatically relocated or not depends on the type.
  * @param   pszDesc         Pointer to description string. This must not be freed.
  */
-VMMR3DECL(int) PGMR3HandlerVirtualRegister(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
-                                           PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
-                                           PFNPGMR3VIRTHANDLER pfnHandlerR3,
-                                           const char *pszHandlerRC, const char *pszModRC,
-                                           const char *pszDesc)
-{
-    LogFlow(("PGMR3HandlerVirtualRegisterEx: enmType=%d GCPtr=%RGv GCPtrLast=%RGv pszHandlerRC=%p:{%s} pszModRC=%p:{%s} pszDesc=%s\n",
-             enmType, GCPtr, GCPtrLast, pszHandlerRC, pszHandlerRC, pszModRC, pszModRC, pszDesc));
-
-    /* Not supported/relevant for VT-x and AMD-V. */
-    if (HMIsEnabled(pVM))
-        return VERR_NOT_IMPLEMENTED;
+VMMR3_INT_DECL(int) PGMR3HandlerVirtualRegister(PVM pVM, PVMCPU pVCpu, PGMVIRTHANDLERTYPE hType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
+                                                void *pvUserR3, RTRCPTR pvUserRC, const char *pszDesc)
+{
+    AssertReturn(!HMIsEnabled(pVM), VERR_NOT_AVAILABLE); /* Not supported/relevant for VT-x and AMD-V. */
+    PPGMVIRTHANDLERTYPEINT pType = PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hType);
+    Log(("PGMR3HandlerVirtualRegister: GCPhys=%RGp GCPhysLast=%RGp pvUserR3=%RHv pvUserGC=%RRv hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
+         GCPtr, GCPtrLast, pvUserR3, pvUserRC, hType, pType->enmKind, R3STRING(pType->pszDesc), pszDesc, R3STRING(pszDesc)));
 
     /*
      * Validate input.
      */
-    if (!pszModRC)
-        pszModRC = VMMGC_MAIN_MODULE_NAME;
-    if (!pszModRC || !*pszModRC || !pszHandlerRC || !*pszHandlerRC)
-    {
-        AssertMsgFailed(("pfnHandlerGC or/and pszModRC is missing\n"));
-        return VERR_INVALID_PARAMETER;
-    }
-
-    /*
-     * Resolve the GC handler.
-     */
-    RTRCPTR pfnHandlerRC;
-    int rc = PDMR3LdrGetSymbolRCLazy(pVM, pszModRC, NULL /*pszSearchPath*/, pszHandlerRC, &pfnHandlerRC);
-    if (RT_SUCCESS(rc))
-        return PGMR3HandlerVirtualRegisterEx(pVM, enmType, GCPtr, GCPtrLast, pfnInvalidateR3,
-                                             pfnHandlerR3, pfnHandlerRC, pszDesc);
-
-    AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszModRC, pszHandlerRC, rc));
-    return rc;
-}
-
-
-/**
- * Register an access handler for a virtual range.
- *
- * @returns VBox status code.
- * @param   pVM             Pointer to the VM.
- * @param   enmType         Handler type. Any of the PGMVIRTHANDLERTYPE_* enums.
- * @param   GCPtr           Start address.
- * @param   GCPtrLast       Last address (inclusive).
- * @param   pfnInvalidateR3 The R3 invalidate callback (can be 0)
- * @param   pfnHandlerR3    The R3 handler.
- * @param   pfnHandlerRC    The RC handler.
- * @param   pszDesc         Pointer to description string. This must not be freed.
- * @thread  EMT
- */
-/** @todo create a template for virtual handlers (see async i/o), we're wasting space
- * duplicating the function pointers now. (Or we will once we add the missing callbacks.) */
-VMMDECL(int) PGMR3HandlerVirtualRegisterEx(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
-                                           R3PTRTYPE(PFNPGMR3VIRTINVALIDATE) pfnInvalidateR3,
-                                           R3PTRTYPE(PFNPGMR3VIRTHANDLER) pfnHandlerR3,
-                                           RCPTRTYPE(PFNPGMRCVIRTHANDLER) pfnHandlerRC,
-                                           R3PTRTYPE(const char *) pszDesc)
-{
-    Log(("PGMR3HandlerVirtualRegister: enmType=%d GCPtr=%RGv GCPtrLast=%RGv pfnInvalidateR3=%RHv pfnHandlerR3=%RHv pfnHandlerRC=%RRv pszDesc=%s\n",
-         enmType, GCPtr, GCPtrLast, pfnInvalidateR3, pfnHandlerR3, pfnHandlerRC, pszDesc));
-
-    /* Not supported/relevant for VT-x and AMD-V. */
-    if (HMIsEnabled(pVM))
-        return VERR_NOT_IMPLEMENTED;
-
-    /*
-     * Validate input.
-     */
-    switch (enmType)
-    {
-        case PGMVIRTHANDLERTYPE_ALL:
+    AssertReturn(pType->u32Magic == PGMVIRTHANDLERTYPEINT_MAGIC, VERR_INVALID_HANDLE);
+    AssertMsgReturn(GCPtr < GCPtrLast, ("GCPtr >= GCPtrLast (%RGp >= %RGp)\n", GCPtr, GCPtrLast), VERR_INVALID_PARAMETER);
+    switch (pType->enmKind)
+    {
+        case PGMVIRTHANDLERKIND_ALL:
             AssertReleaseMsgReturn(   (GCPtr     & PAGE_OFFSET_MASK) == 0
                                    && (GCPtrLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK,
-                                   ("PGMVIRTHANDLERTYPE_ALL: GCPtr=%RGv GCPtrLast=%RGv\n", GCPtr, GCPtrLast),
+                                   ("PGMVIRTHANDLERKIND_ALL: GCPtr=%RGv GCPtrLast=%RGv\n", GCPtr, GCPtrLast),
                                    VERR_NOT_IMPLEMENTED);
             break;
-        case PGMVIRTHANDLERTYPE_WRITE:
-            if (!pfnHandlerR3)
-            {
-                AssertMsgFailed(("No HC handler specified!!\n"));
-                return VERR_INVALID_PARAMETER;
-            }
-            break;
-
-        case PGMVIRTHANDLERTYPE_HYPERVISOR:
-            if (pfnHandlerR3)
-            {
-                AssertMsgFailed(("R3 handler specified for hypervisor range!?!\n"));
-                return VERR_INVALID_PARAMETER;
-            }
+        case PGMVIRTHANDLERKIND_WRITE:
+        case PGMVIRTHANDLERKIND_HYPERVISOR:
             break;
         default:
-            AssertMsgFailed(("Invalid enmType! enmType=%d\n", enmType));
-            return VERR_INVALID_PARAMETER;
-    }
-    if (GCPtrLast < GCPtr)
-    {
-        AssertMsgFailed(("GCPtrLast < GCPtr (%#x < %#x)\n", GCPtrLast, GCPtr));
-        return VERR_INVALID_PARAMETER;
-    }
-    if (!pfnHandlerRC)
-    {
-        AssertMsgFailed(("pfnHandlerRC is missing\n"));
-        return VERR_INVALID_PARAMETER;
-    }
+            AssertMsgFailedReturn(("Invalid enmKind=%d!\n", pType->enmKind), VERR_INVALID_PARAMETER);
+    }
+    AssertMsgReturn(   (RTRCUINTPTR)pvUserRC < 0x10000
+                    || MMHyperR3ToRC(pVM, MMHyperRCToR3(pVM, pvUserRC)) == pvUserRC,
+                    ("Not RC pointer! pvUserRC=%RRv\n", pvUserRC),
+                    VERR_INVALID_PARAMETER);
 
     /*
@@ -406,9 +444,8 @@
     pNew->Core.KeyLast  = GCPtrLast;
 
-    pNew->enmType       = enmType;
-    pNew->pfnInvalidateR3 = pfnInvalidateR3;
-    pNew->pfnHandlerRC  = pfnHandlerRC;
-    pNew->pfnHandlerR3  = pfnHandlerR3;
-    pNew->pszDesc       = pszDesc;
+    pNew->hType         = hType;
+    pNew->pvUserRC      = pvUserRC;
+    pNew->pvUserR3      = pvUserR3;
+    pNew->pszDesc       = pszDesc ? pszDesc : pType->pszDesc;
     pNew->cb            = GCPtrLast - GCPtr + 1;
     pNew->cPages        = cPages;
@@ -428,5 +465,5 @@
      * the same range this makes everything much simpler and faster.
      */
-    AVLROGCPTRTREE *pRoot = enmType != PGMVIRTHANDLERTYPE_HYPERVISOR
+    AVLROGCPTRTREE *pRoot = pType->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR
                           ? &pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers
                           : &pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers;
@@ -456,5 +493,5 @@
     if (RTAvlroGCPtrInsert(pRoot, &pNew->Core))
     {
-        if (enmType != PGMVIRTHANDLERTYPE_HYPERVISOR)
+        if (pType->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR)
         {
             PVMCPU pVCpu = VMMGetCpu(pVM);
@@ -463,8 +500,9 @@
             VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
         }
+        PGMHandlerVirtualTypeRetain(pVM, hType);
         pgmUnlock(pVM);
 
 #ifdef VBOX_WITH_STATISTICS
-        rc = STAMR3RegisterF(pVM, &pNew->Stat, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pszDesc,
+        rc = STAMR3RegisterF(pVM, &pNew->Stat, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pNew->pszDesc,
                              "/PGM/VirtHandler/Calls/%RGv-%RGv", pNew->Core.Key, pNew->Core.KeyLast);
         AssertRC(rc);
@@ -477,24 +515,36 @@
     MMHyperFree(pVM, pNew);
     return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
-}
-
-
-/**
- * Modify the page invalidation callback handler for a registered virtual range.
- * (add more when needed)
+
+}
+
+
+/**
+ * Changes the type of a virtual handler.
+ *
+ * The new and old type must have the same access kind.
  *
  * @returns VBox status code.
  * @param   pVM             Pointer to the VM.
- * @param   GCPtr           Start address.
- * @param   pfnInvalidateR3 The R3 invalidate callback (can be 0)
- * @remarks Doesn't work with the hypervisor access handler type.
- */
-VMMDECL(int) PGMHandlerVirtualChangeInvalidateCallback(PVM pVM, RTGCPTR GCPtr, PFNPGMR3VIRTINVALIDATE pfnInvalidateR3)
-{
+ * @param   GCPtr           Start address of the virtual handler.
+ * @param   hNewType        The new handler type.
+ */
+VMMR3_INT_DECL(int) PGMHandlerVirtualChangeType(PVM pVM, RTGCPTR GCPtr, PGMVIRTHANDLERTYPE hNewType)
+{
+    PPGMVIRTHANDLERTYPEINT pNewType = PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hNewType);
+    AssertReturn(pNewType->u32Magic == PGMVIRTHANDLERTYPEINT_MAGIC, VERR_INVALID_HANDLE);
+
     pgmLock(pVM);
     PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGet(&pVM->pgm.s.pTreesR3->VirtHandlers, GCPtr);
     if (pCur)
     {
-        pCur->pfnInvalidateR3 = pfnInvalidateR3;
+        PGMVIRTHANDLERTYPE     hOldType = pCur->hType;
+        PPGMVIRTHANDLERTYPEINT pOldType = PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hOldType);
+        if (pOldType != pNewType)
+        {
+            AssertReturnStmt(pNewType->enmKind == pOldType->enmKind, pgmUnlock(pVM), VERR_ACCESS_DENIED);
+            PGMHandlerVirtualTypeRetain(pVM, hNewType);
+            pCur->hType = hNewType;
+            PGMHandlerVirtualTypeRelease(pVM, hOldType);
+        }
         pgmUnlock(pVM);
         return VINF_SUCCESS;
@@ -505,4 +555,5 @@
 }
 
+
 /**
  * Deregister an access handler for a virtual range.
@@ -510,34 +561,33 @@
  * @returns VBox status code.
  * @param   pVM         Pointer to the VM.
+ * @param   pVCpu       Pointer to the cross context CPU structure for the
+ *                      calling EMT.
  * @param   GCPtr       Start address.
- * @thread  EMT
- */
-VMMDECL(int) PGMHandlerVirtualDeregister(PVM pVM, RTGCPTR GCPtr)
+ * @param   fHypervisor Set if PGMVIRTHANDLERKIND_HYPERVISOR, false if not.
+ * @thread  EMT(pVCpu)
+ */
+VMM_INT_DECL(int) PGMHandlerVirtualDeregister(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, bool fHypervisor)
 {
     pgmLock(pVM);
 
-    /*
-     * Find the handler.
-     * We naturally assume GCPtr is a unique specification.
-     */
-    PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtr);
-    if (RT_LIKELY(pCur))
-    {
-        Log(("PGMHandlerVirtualDeregister: Removing Virtual (%d) Range %RGv-%RGv %s\n", pCur->enmType,
-             pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
-        Assert(pCur->enmType != PGMVIRTHANDLERTYPE_HYPERVISOR);
-
+    PPGMVIRTHANDLER pCur;
+    if (!fHypervisor)
+    {
         /*
-         * Reset the flags and remove phys2virt nodes.
+         * Normal guest handler.
          */
+        pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtr);
+        AssertMsgReturnStmt(pCur, ("GCPtr=%RGv\n", GCPtr), pgmUnlock(pVM), VERR_INVALID_PARAMETER);
+        Assert(PGMVIRTANDLER_GET_TYPE(pVM, pCur)->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR);
+
+        Log(("PGMHandlerVirtualDeregister: Removing Virtual (%d) Range %RGv-%RGv %s\n",
+             PGMVIRTANDLER_GET_TYPE(pVM, pCur)->enmKind, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
+
+        /* Reset the flags and remove phys2virt nodes. */
         for (uint32_t iPage = 0; iPage < pCur->cPages; iPage++)
             if (pCur->aPhysToVirt[iPage].offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE)
                 pgmHandlerVirtualClearPage(pVM, pCur, iPage);
 
-        /*
-         * Schedule CR3 sync.
-         */
-        PVMCPU pVCpu = VMMGetCpu(pVM);
-
+        /* Schedule CR3 sync. */
         pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
         VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
@@ -545,25 +595,24 @@
     else
     {
-        /* must be a hypervisor one then. */
+        /*
+         * Hypervisor one (hypervisor relocation or termination only).
+         */
         pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers, GCPtr);
-        if (RT_UNLIKELY(!pCur))
-        {
-            pgmUnlock(pVM);
-#ifndef DEBUG_sander
-            AssertMsgFailed(("Range %#x not found!\n", GCPtr));
-#endif
-            return VERR_INVALID_PARAMETER;
-        }
-
-        Log(("PGMHandlerVirtualDeregister: Removing Hyper Virtual (%d) Range %RGv-%RGv %s\n", pCur->enmType,
+        AssertMsgReturnStmt(pCur, ("GCPtr=%RGv\n", GCPtr), pgmUnlock(pVM), VERR_INVALID_PARAMETER);
+        Assert(PGMVIRTANDLER_GET_TYPE(pVM, pCur)->enmKind == PGMVIRTHANDLERKIND_HYPERVISOR);
+
+        Log(("PGMHandlerVirtualDeregister: Removing Hyper Virtual Range %RGv-%RGv %s\n",
              pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
-        Assert(pCur->enmType == PGMVIRTHANDLERTYPE_HYPERVISOR);
     }
 
     pgmUnlock(pVM);
 
+    /*
+     * Free it.
+     */
 #ifdef VBOX_WITH_STATISTICS
     STAMR3DeregisterF(pVM->pUVM, "/PGM/VirtHandler/Calls/%RGv-%RGv", pCur->Core.Key, pCur->Core.KeyLast);
 #endif
+    PGMHandlerVirtualTypeRelease(pVM, pCur->hType);
     MMHyperFree(pVM, pCur);
 
@@ -696,17 +745,18 @@
 static DECLCALLBACK(int) pgmR3InfoHandlersVirtualOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
 {
-    PPGMVIRTHANDLER     pCur = (PPGMVIRTHANDLER)pNode;
-    PPGMHANDLERINFOARG  pArgs= (PPGMHANDLERINFOARG)pvUser;
-    PCDBGFINFOHLP       pHlp = pArgs->pHlp;
+    PPGMVIRTHANDLER         pCur     = (PPGMVIRTHANDLER)pNode;
+    PPGMHANDLERINFOARG      pArgs    = (PPGMHANDLERINFOARG)pvUser;
+    PCDBGFINFOHLP           pHlp     = pArgs->pHlp;
+    PPGMVIRTHANDLERTYPEINT  pCurType = PGMVIRTANDLER_GET_TYPE(pArgs->pVM, pCur);
     const char *pszType;
-    switch (pCur->enmType)
-    {
-        case PGMVIRTHANDLERTYPE_WRITE:      pszType = "Write  "; break;
-        case PGMVIRTHANDLERTYPE_ALL:        pszType = "All    "; break;
-        case PGMVIRTHANDLERTYPE_HYPERVISOR: pszType = "WriteHyp "; break;
+    switch (pCurType->enmKind)
+    {
+        case PGMVIRTHANDLERKIND_WRITE:      pszType = "Write  "; break;
+        case PGMVIRTHANDLERKIND_ALL:        pszType = "All    "; break;
+        case PGMVIRTHANDLERKIND_HYPERVISOR: pszType = "WriteHyp "; break;
         default:                            pszType = "????"; break;
     }
     pHlp->pfnPrintf(pHlp, "%RGv - %RGv  %RHv  %RRv  %s  %s\n",
-        pCur->Core.Key, pCur->Core.KeyLast, pCur->pfnHandlerR3, pCur->pfnHandlerRC, pszType, pCur->pszDesc);
+        pCur->Core.Key, pCur->Core.KeyLast, pCurType->pfnHandlerR3, pCurType->pfnHandlerRC, pszType, pCur->pszDesc);
 #ifdef VBOX_WITH_STATISTICS
     if (pArgs->fStats)
Index: /trunk/src/VBox/VMM/VMMR3/SELM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/SELM.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMR3/SELM.cpp	(revision 55889)
@@ -187,4 +187,55 @@
     /* bit set to 1 means no redirection */
     memset(pVM->selm.s.Tss.IntRedirBitmap, 0xff, sizeof(pVM->selm.s.Tss.IntRedirBitmap));
+
+    /*
+     * Register the virtual access handlers.
+     */
+    pVM->selm.s.hShadowGdtWriteHandlerType = NIL_PGMVIRTHANDLERTYPE;
+    pVM->selm.s.hShadowLdtWriteHandlerType = NIL_PGMVIRTHANDLERTYPE;
+    pVM->selm.s.hShadowTssWriteHandlerType = NIL_PGMVIRTHANDLERTYPE;
+    pVM->selm.s.hGuestGdtWriteHandlerType  = NIL_PGMVIRTHANDLERTYPE;
+    pVM->selm.s.hGuestLdtWriteHandlerType  = NIL_PGMVIRTHANDLERTYPE;
+    pVM->selm.s.hGuestTssWriteHandlerType  = NIL_PGMVIRTHANDLERTYPE;
+#ifdef VBOX_WITH_RAW_MODE
+    if (!HMIsEnabled(pVM))
+    {
+# ifdef SELM_TRACK_SHADOW_GDT_CHANGES
+        rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_HYPERVISOR, false /*fRelocUserRC*/,
+                                             NULL /*pfnInvalidateR3*/, NULL /*pfnHandlerR3*/,
+                                             "selmRCShadowGDTWriteHandler", NULL /*pszModRC*/,
+                                             "Shadow GDT write access handler", &pVM->selm.s.hShadowGdtWriteHandlerType);
+        AssertRCReturn(rc, rc);
+# endif
+# ifdef SELM_TRACK_SHADOW_TSS_CHANGES
+        rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_HYPERVISOR, false /*fRelocUserRC*/,
+                                             NULL /*pfnInvalidateR3*/, NULL /*pfnHandlerR3*/,
+                                             "selmRCShadowTSSWriteHandler", NULL /*pszModRC*/,
+                                             "Shadow TSS write access handler", &pVM->selm.s.hShadowTssWriteHandlerType);
+        AssertRCReturn(rc, rc);
+# endif
+# ifdef SELM_TRACK_SHADOW_LDT_CHANGES
+        rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_HYPERVISOR, false /*fRelocUserRC*/,
+                                             NULL /*pfnInvalidateR3*/, NULL /*pfnHandlerR3*/,
+                                             "selmRCShadowLDTWriteHandler", NULL /*pszModRC*/,
+                                             "Shadow LDT write access handler", &pVM->selm.s.hShadowLdtWriteHandlerType);
+        AssertRCReturn(rc, rc);
+# endif
+        rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_WRITE, false /*fRelocUserRC*/,
+                                             NULL /*pfnInvalidateR3*/, selmR3GuestGDTWriteHandler,
+                                             "selmRCGuestGDTWriteHandler", NULL /*pszModRC*/,
+                                             "Guest GDT write access handler", &pVM->selm.s.hGuestGdtWriteHandlerType);
+        AssertRCReturn(rc, rc);
+        rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_WRITE, false /*fRelocUserRC*/,
+                                             NULL /*pfnInvalidateR3*/, selmR3GuestLDTWriteHandler,
+                                             "selmRCGuestLDTWriteHandler", NULL /*pszModRC*/,
+                                             "Guest LDT write access handler", &pVM->selm.s.hGuestLdtWriteHandlerType);
+        AssertRCReturn(rc, rc);
+        rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_WRITE, false /*fRelocUserRC*/,
+                                             NULL /*pfnInvalidateR3*/, selmR3GuestTSSWriteHandler,
+                                             "selmRCGuestTSSWriteHandler", NULL /*pszModRC*/,
+                                             "Guest TSS write access handler", &pVM->selm.s.hGuestTssWriteHandlerType);
+        AssertRCReturn(rc, rc);
+    }
+#endif /* VBOX_WITH_RAW_MODE */
 
     /*
@@ -499,15 +550,17 @@
          * Update shadow GDT/LDT/TSS write access handlers.
          */
+        PVMCPU pVCpu = VMMGetCpu(pVM); NOREF(pVCpu);
         int rc; NOREF(rc);
 #ifdef SELM_TRACK_SHADOW_GDT_CHANGES
         if (pVM->selm.s.paGdtRC != NIL_RTRCPTR)
         {
-            rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.paGdtRC);
+            rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.paGdtRC, true /*fHypervisor*/);
             AssertRC(rc);
         }
         pVM->selm.s.paGdtRC = MMHyperR3ToRC(pVM, paGdt);
-        rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->selm.s.paGdtRC,
+        rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->selm.s.hShadowGdtWriteHandlerType,
+                                         pVM->selm.s.paGdtRC,
                                          pVM->selm.s.paGdtRC + SELM_GDT_ELEMENTS * sizeof(paGdt[0]) - 1,
-                                         0, 0, "selmRCShadowGDTWriteHandler", 0, "Shadow GDT write access handler");
+                                         NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
         AssertRC(rc);
 #endif
@@ -515,11 +568,12 @@
         if (pVM->selm.s.pvMonShwTssRC != RTRCPTR_MAX)
         {
-            rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.pvMonShwTssRC);
+            rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.pvMonShwTssRC, true /*fHypervisor*/);
             AssertRC(rc);
         }
         pVM->selm.s.pvMonShwTssRC = VM_RC_ADDR(pVM, &pVM->selm.s.Tss);
-        rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->selm.s.pvMonShwTssRC,
+        rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->selm.s.hShadowTssWriteHandlerType,
+                                         pVM->selm.s.pvMonShwTssRC,
                                          pVM->selm.s.pvMonShwTssRC + sizeof(pVM->selm.s.Tss) - 1,
-                                         0, 0, "selmRCShadowTSSWriteHandler", 0, "Shadow TSS write access handler");
+                                         NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
         AssertRC(rc);
 #endif
@@ -531,5 +585,5 @@
         if (pVM->selm.s.pvLdtRC != RTRCPTR_MAX)
         {
-            rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.pvLdtRC);
+            rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.pvLdtRC, true /*fHypervisor*/);
             AssertRC(rc);
         }
@@ -537,7 +591,8 @@
         pVM->selm.s.pvLdtRC = MMHyperR3ToRC(pVM, pVM->selm.s.pvLdtR3);
 #ifdef SELM_TRACK_SHADOW_LDT_CHANGES
-        rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->selm.s.pvLdtRC,
+        rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->selm.s.hShadowLdtWriteHandlerType,
+                                         pVM->selm.s.pvLdtRC,
                                          pVM->selm.s.pvLdtRC + _64K + PAGE_SIZE - 1,
-                                         0, 0, "selmRCShadowLDTWriteHandler", 0, "Shadow LDT write access handler");
+                                         NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
         AssertRC(rc);
 #endif
@@ -578,9 +633,10 @@
      * Uninstall guest GDT/LDT/TSS write access handlers.
      */
+    PVMCPU pVCpu = VMMGetCpu(pVM); NOREF(pVCpu);
     int rc = VINF_SUCCESS;
     if (pVM->selm.s.GuestGdtr.pGdt != RTRCPTR_MAX && pVM->selm.s.fGDTRangeRegistered)
     {
 #ifdef SELM_TRACK_GUEST_GDT_CHANGES
-        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GuestGdtr.pGdt);
+        rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.GuestGdtr.pGdt, false /*fHypervisor*/);
         AssertRC(rc);
 #endif
@@ -592,5 +648,5 @@
     {
 #ifdef SELM_TRACK_GUEST_LDT_CHANGES
-        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestLdt);
+        rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.GCPtrGuestLdt, false /*fHypervisor*/);
         AssertRC(rc);
 #endif
@@ -600,5 +656,5 @@
     {
 #ifdef SELM_TRACK_GUEST_TSS_CHANGES
-        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestTss);
+        rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.GCPtrGuestTss, false /*fHypervisor*/);
         AssertRC(rc);
 #endif
@@ -987,4 +1043,5 @@
     {
         Log(("SELMR3UpdateFromCPUM: Guest's GDT is changed to pGdt=%016RX64 cbGdt=%08X\n", GDTR.pGdt, GDTR.cbGdt));
+        PVMCPU pVCpu = VMMGetCpu(pVM);
 
 # ifdef SELM_TRACK_GUEST_GDT_CHANGES
@@ -994,29 +1051,25 @@
         if (pVM->selm.s.GuestGdtr.pGdt != RTRCPTR_MAX && pVM->selm.s.fGDTRangeRegistered)
         {
-            rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GuestGdtr.pGdt);
+            rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.GuestGdtr.pGdt, false /*fHypervisor*/);
             AssertRC(rc);
         }
-
-        rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE,
+        rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->selm.s.hGuestGdtWriteHandlerType,
                                          GDTR.pGdt, GDTR.pGdt + GDTR.cbGdt /* already inclusive */,
-                                         0, selmR3GuestGDTWriteHandler, "selmRCGuestGDTWriteHandler", 0,
-                                         "Guest GDT write access handler");
+                                         NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
 #  ifdef VBOX_WITH_RAW_RING1
         /** @todo !HACK ALERT!
          * Some guest OSes (QNX) share code and the GDT on the same page;
          * PGMR3HandlerVirtualRegister doesn't support more than one handler,
-         * so we kick out the  PATM handler as this one is more important.
-         * Fix this properly in PGMR3HandlerVirtualRegister?
+         * so we kick out the PATM handler as this one is more important. Fix this
+         * properly in PGMR3HandlerVirtualRegister?
          */
         if (rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT)
         {
             LogRel(("selmR3UpdateShadowGdt: Virtual handler conflict %RGv -> kick out PATM handler for the higher priority GDT page monitor\n", GDTR.pGdt));
-            rc = PGMHandlerVirtualDeregister(pVM, GDTR.pGdt & PAGE_BASE_GC_MASK);
+            rc = PGMHandlerVirtualDeregister(pVM, pVCpu, GDTR.pGdt & PAGE_BASE_GC_MASK, false /*fHypervisor*/);
             AssertRC(rc);
-
-            rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE,
+            rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->selm.s.hGuestGdtWriteHandlerType,
                                              GDTR.pGdt, GDTR.pGdt + GDTR.cbGdt /* already inclusive */,
-                                             0, selmR3GuestGDTWriteHandler, "selmRCGuestGDTWriteHandler", 0,
-                                             "Guest GDT write access handler");
+                                             NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
         }
 #  endif
@@ -1073,5 +1126,5 @@
         if (pVM->selm.s.GCPtrGuestLdt != RTRCPTR_MAX)
         {
-            rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestLdt);
+            rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.GCPtrGuestLdt, false /*fHypervisor*/);
             AssertRC(rc);
             pVM->selm.s.GCPtrGuestLdt = RTRCPTR_MAX;
@@ -1106,5 +1159,5 @@
         if (pVM->selm.s.GCPtrGuestLdt != RTRCPTR_MAX)
         {
-            rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestLdt);
+            rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.GCPtrGuestLdt, false /*fHypervisor*/);
             AssertRC(rc);
             pVM->selm.s.GCPtrGuestLdt = RTRCPTR_MAX;
@@ -1142,5 +1195,5 @@
             if (pVM->selm.s.GCPtrGuestLdt != RTRCPTR_MAX)
             {
-                rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestLdt);
+                rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.GCPtrGuestLdt, false /*fHypervisor*/);
                 AssertRC(rc);
             }
@@ -1149,6 +1202,7 @@
                 Log(("LDT selector marked not present!!\n"));
 #  endif
-            rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrLdt, GCPtrLdt + cbLdt /* already inclusive */,
-                                             0, selmR3GuestLDTWriteHandler, "selmRCGuestLDTWriteHandler", 0, "Guest LDT write access handler");
+            rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->selm.s.hGuestLdtWriteHandlerType,
+                                             GCPtrLdt, GCPtrLdt + cbLdt /* already inclusive */,
+                                             NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
             if (rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT)
             {
@@ -1699,9 +1753,10 @@
         Log(("SELMR3SyncTSS: Guest's TSS is changed to pTss=%RGv cbMonitoredTss=%08X cbGuestTss=%#08x\n",
              GCPtrTss, cbMonitoredTss, pVM->selm.s.cbGuestTss));
+        PVMCPU pVCpu = VMMGetCpu(pVM);
 
         /* Release the old range first. */
         if (pVM->selm.s.GCPtrGuestTss != RTRCPTR_MAX)
         {
-            rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestTss);
+            rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->selm.s.GCPtrGuestTss, false /*fHypervisor*/);
             AssertRC(rc);
         }
@@ -1711,7 +1766,7 @@
         {
 # ifdef SELM_TRACK_GUEST_TSS_CHANGES
-            rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrTss, GCPtrTss + cbMonitoredTss - 1,
-                                             0, selmR3GuestTSSWriteHandler,
-                                             "selmRCGuestTSSWriteHandler", 0, "Guest TSS write access handler");
+            rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->selm.s.hGuestTssWriteHandlerType,
+                                             GCPtrTss, GCPtrTss + cbMonitoredTss - 1,
+                                             NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
             if (RT_FAILURE(rc))
             {
@@ -1726,10 +1781,10 @@
                 {
                     LogRel(("SELMR3SyncTSS: Virtual handler conflict %RGv -> kick out PATM handler for the higher priority TSS page monitor\n", GCPtrTss));
-                    rc = PGMHandlerVirtualDeregister(pVM, GCPtrTss & PAGE_BASE_GC_MASK);
+                    rc = PGMHandlerVirtualDeregister(pVM, pVCpu, GCPtrTss & PAGE_BASE_GC_MASK, false /*fHypervisor*/);
                     AssertRC(rc);
 
-                    rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrTss, GCPtrTss + cbMonitoredTss - 1,
-                                                     0, selmR3GuestTSSWriteHandler,
-                                                     "selmRCGuestTSSWriteHandler", 0, "Guest TSS write access handler");
+                    rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->selm.s.hGuestTssWriteHandlerType,
+                                                     GCPtrTss, GCPtrTss + cbMonitoredTss - 1,
+                                                     NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
                     if (RT_FAILURE(rc))
                     {
Index: /trunk/src/VBox/VMM/VMMR3/TRPM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/TRPM.cpp	(revision 55888)
+++ /trunk/src/VBox/VMM/VMMR3/TRPM.cpp	(revision 55889)
@@ -455,4 +455,5 @@
 {
     LogFlow(("TRPMR3Init\n"));
+    int rc;
 
     /*
@@ -490,5 +491,5 @@
     {
         bool f;
-        int rc = CFGMR3QueryBool(pTRPMNode, "SafeToDropGuestIDTMonitoring", &f);
+        rc = CFGMR3QueryBool(pTRPMNode, "SafeToDropGuestIDTMonitoring", &f);
         if (RT_SUCCESS(rc))
             pVM->trpm.s.fSafeToDropGuestIDTMonitoring = f;
@@ -507,10 +508,33 @@
 
     /*
+     * Register virtual access handlers.
+     */
+    pVM->trpm.s.hShadowIdtWriteHandlerType = NIL_PGMVIRTHANDLERTYPE;
+    pVM->trpm.s.hGuestIdtWriteHandlerType  = NIL_PGMVIRTHANDLERTYPE;
+#ifdef VBOX_WITH_RAW_MODE
+    if (!HMIsEnabled(pVM))
+    {
+# ifdef TRPM_TRACK_SHADOW_IDT_CHANGES
+        rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_HYPERVISOR, false /*fRelocUserRC*/,
+                                             NULL /*pfnInvalidateR3*/, NULL /*pfnHandlerR3*/,
+                                             "trpmRCShadowIDTWriteHandler", NULL /*pszModRC*/,
+                                             "Shadow IDT write access handler", &pVM->trpm.s.hShadowIdtWriteHandlerType);
+        AssertRCReturn(rc, rc);
+# endif
+        rc = PGMR3HandlerVirtualTypeRegister(pVM, PGMVIRTHANDLERKIND_WRITE, false /*fRelocUserRC*/,
+                                             NULL /*pfnInvalidateR3*/, trpmR3GuestIDTWriteHandler,
+                                             "trpmRCGuestIDTWriteHandler", NULL /*pszModRC*/,
+                                             "Guest IDT write access handler", &pVM->trpm.s.hGuestIdtWriteHandlerType);
+        AssertRCReturn(rc, rc);
+    }
+#endif /* VBOX_WITH_RAW_MODE */
+
+    /*
      * Register the saved state data unit.
      */
-    int rc = SSMR3RegisterInternal(pVM, "trpm", 1, TRPM_SAVED_STATE_VERSION, sizeof(TRPM),
-                                   NULL, NULL, NULL,
-                                   NULL, trpmR3Save, NULL,
-                                   NULL, trpmR3Load, NULL);
+    rc = SSMR3RegisterInternal(pVM, "trpm", 1, TRPM_SAVED_STATE_VERSION, sizeof(TRPM),
+                               NULL, NULL, NULL,
+                               NULL, trpmR3Save, NULL,
+                               NULL, trpmR3Load, NULL);
     if (RT_FAILURE(rc))
         return rc;
@@ -692,10 +716,11 @@
     if (pVM->trpm.s.pvMonShwIdtRC != RTRCPTR_MAX)
     {
-        rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.pvMonShwIdtRC);
+        rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->trpm.s.pvMonShwIdtRC, true /*fHypervisor*/);
         AssertRC(rc);
     }
     pVM->trpm.s.pvMonShwIdtRC = VM_RC_ADDR(pVM, &pVM->trpm.s.aIdt[0]);
-    rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->trpm.s.pvMonShwIdtRC, pVM->trpm.s.pvMonShwIdtRC + sizeof(pVM->trpm.s.aIdt) - 1,
-                                     0, 0, "trpmRCShadowIDTWriteHandler", 0, "Shadow IDT write access handler");
+    rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->trpm.s.hShadowIdtWriteHandlerType,
+                                     pVM->trpm.s.pvMonShwIdtRC, pVM->trpm.s.pvMonShwIdtRC + sizeof(pVM->trpm.s.aIdt) - 1,
+                                     NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
     AssertRC(rc);
 # endif
@@ -775,5 +800,5 @@
         if (!pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
         {
-            int rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.GuestIdtr.pIdt);
+            int rc = PGMHandlerVirtualDeregister(pVM, VMMGetCpu(pVM), pVM->trpm.s.GuestIdtr.pIdt, false /*fHypervisor*/);
             AssertRC(rc);
         }
@@ -1090,12 +1115,14 @@
              * [Re]Register write virtual handler for guest's IDT.
              */
+            PVMCPU pVCpu = VMMGetCpu(pVM);
             if (pVM->trpm.s.GuestIdtr.pIdt != RTRCPTR_MAX)
             {
-                rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.GuestIdtr.pIdt);
+                rc = PGMHandlerVirtualDeregister(pVM, pVCpu, pVM->trpm.s.GuestIdtr.pIdt, false /*fHypervisor*/);
                 AssertRCReturn(rc, rc);
             }
             /* limit is including */
-            rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, IDTR.pIdt, IDTR.pIdt + IDTR.cbIdt /* already inclusive */,
-                                             0, trpmR3GuestIDTWriteHandler, "trpmRCGuestIDTWriteHandler", 0, "Guest IDT write access handler");
+            rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->trpm.s.hGuestIdtWriteHandlerType,
+                                             IDTR.pIdt, IDTR.pIdt + IDTR.cbIdt /* already inclusive */,
+                                             NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
 
             if (rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT)
@@ -1106,6 +1133,7 @@
                     CSAMR3RemovePage(pVM, IDTR.pIdt + IDTR.cbIdt);
 
-                rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, IDTR.pIdt, IDTR.pIdt + IDTR.cbIdt /* already inclusive */,
-                                                 0, trpmR3GuestIDTWriteHandler, "trpmRCGuestIDTWriteHandler", 0, "Guest IDT write access handler");
+                rc = PGMR3HandlerVirtualRegister(pVM, pVCpu, pVM->trpm.s.hGuestIdtWriteHandlerType,
+                                                 IDTR.pIdt, IDTR.pIdt + IDTR.cbIdt /* already inclusive */,
+                                                 NULL /*pvUserR3*/, NIL_RTR0PTR /*pvUserRC*/, NULL /*pszDesc*/);
             }
 
Index: /trunk/src/VBox/VMM/include/CSAMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/CSAMInternal.h	(revision 55888)
+++ /trunk/src/VBox/VMM/include/CSAMInternal.h	(revision 55889)
@@ -156,6 +156,6 @@
 
     RCPTRTYPE(RTRCPTR *)  pPDBitmapGC;
-    RCPTRTYPE(RTHCPTR *)    pPDHCBitmapGC;
-    R3PTRTYPE(uint8_t **)   pPDBitmapHC;
+    RCPTRTYPE(RTHCPTR *)  pPDHCBitmapGC;
+    R3PTRTYPE(uint8_t **) pPDBitmapHC;
     R3PTRTYPE(RTRCPTR  *) pPDGCBitmapHC;
 
@@ -175,9 +175,14 @@
     /* To keep track of possible code pages */
     uint32_t            cPossibleCodePages;
-    RTRCPTR           pvPossibleCodePage[CSAM_MAX_CODE_PAGES_FLUSH];
+    RTRCPTR             pvPossibleCodePage[CSAM_MAX_CODE_PAGES_FLUSH];
 
     /* call addresses reported by the recompiler */
-    RTRCPTR           pvCallInstruction[16];
-    RTUINT              iCallInstruction;
+    RTRCPTR             pvCallInstruction[16];
+    uint32_t            iCallInstruction;
+
+    /** Code page write access handler type. */
+    PGMVIRTHANDLERTYPE  hCodePageWriteType;
+    /** Code page write & invalidation access handler type. */
+    PGMVIRTHANDLERTYPE  hCodePageWriteAndInvPgType;
 
     /* Set when scanning has started. */
Index: /trunk/src/VBox/VMM/include/PATMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/PATMInternal.h	(revision 55888)
+++ /trunk/src/VBox/VMM/include/PATMInternal.h	(revision 55889)
@@ -528,5 +528,9 @@
     RTDBGMOD                    hDbgModPatchMem;
 
-#if HC_ARCH_BITS == 32
+    /** Virtual page access handler type (patmVirtPageHandler,
+     * PATMGCMonitorPage). */
+    PGMVIRTHANDLERTYPE          hMonitorPageType;
+
+#if HC_ARCH_BITS == 64
     /** Align statistics on a 8 byte boundary. */
     uint32_t                    u32Alignment1;
Index: /trunk/src/VBox/VMM/include/PGMInline.h
===================================================================
--- /trunk/src/VBox/VMM/include/PGMInline.h	(revision 55888)
+++ /trunk/src/VBox/VMM/include/PGMInline.h	(revision 55889)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -1200,25 +1200,4 @@
 
 /**
- * Gets the page state for a virtual handler.
- *
- * @returns The virtual handler page state.
- * @param   pCur    The virtual handler in question.
- * @remarks This should never be used on a hypervisor access handler.
- */
-DECLINLINE(unsigned) pgmHandlerVirtualCalcState(PPGMVIRTHANDLER pCur)
-{
-    switch (pCur->enmType)
-    {
-        case PGMVIRTHANDLERTYPE_WRITE:
-            return PGM_PAGE_HNDL_VIRT_STATE_WRITE;
-        case PGMVIRTHANDLERTYPE_ALL:
-            return PGM_PAGE_HNDL_VIRT_STATE_ALL;
-        default:
-            AssertFatalMsgFailed(("Invalid type %d\n", pCur->enmType));
-    }
-}
-
-
-/**
  * Clears one physical page of a virtual handler.
  *
Index: /trunk/src/VBox/VMM/include/PGMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/PGMInternal.h	(revision 55888)
+++ /trunk/src/VBox/VMM/include/PGMInternal.h	(revision 55889)
@@ -612,5 +612,5 @@
  * @returns PPGMPHYSHANDLERTYPEINT
  * @param   a_pVM           Pointer to the cross context VM structure.
- * @param   a_hType         Physical access handler handle.
+ * @param   a_hType         Physical access handler type handle.
  */
 #define PGMPHYSHANDLERTYPEINT_FROM_HANDLE(a_pVM, a_hType) ((PPGMPHYSHANDLERTYPEINT)MMHyperHeapOffsetToPtr(a_pVM, a_hType))
@@ -693,4 +693,47 @@
 
 /**
+ * Virtual page access handler type registration.
+ */
+typedef struct PGMVIRTANDLERTYPEINT
+{
+    /** Number of references.   */
+    uint32_t volatile                   cRefs;
+    /** Magic number (PGMVIRTHANDLERTYPEINT_MAGIC). */
+    uint32_t                            u32Magic;
+    /** Link of handler types anchored in PGMTREES::HeadVirtHandlerTypes. */
+    RTLISTOFF32NODE                     ListNode;
+    /** The kind of accesses we're handling. */
+    PGMVIRTHANDLERKIND                  enmKind;
+    /** The PGM_PAGE_HNDL_PHYS_STATE_XXX value corresponding to enmKind. */
+    uint32_t                            uState;
+    /** Whether the pvUserRC argument should be automatically relocated or not. */
+    bool                                fRelocUserRC;
+    bool                                afPadding[3];
+    /** Pointer to RC callback function. */
+    RCPTRTYPE(PFNPGMRCVIRTHANDLER)      pfnHandlerRC;
+    /** Pointer to the R3 callback function for invalidation. */
+    R3PTRTYPE(PFNPGMR3VIRTINVALIDATE)   pfnInvalidateR3;
+    /** Pointer to R3 callback function. */
+    R3PTRTYPE(PFNPGMR3VIRTHANDLER)      pfnHandlerR3;
+    /** Description / Name. For easing debugging. */
+    R3PTRTYPE(const char *)             pszDesc;
+} PGMVIRTHANDLERTYPEINT;
+/** Pointer to a virtual access handler type registration. */
+typedef PGMVIRTHANDLERTYPEINT *PPGMVIRTHANDLERTYPEINT;
+/** Magic value for the virtual handler callbacks (Sir Arthur Charles Clarke). */
+#define PGMVIRTHANDLERTYPEINT_MAGIC        UINT32_C(0x19171216)
+/** Magic value for the virtual handler callbacks. */
+#define PGMVIRTHANDLERTYPEINT_MAGIC_DEAD   UINT32_C(0x20080319)
+
+/**
+ * Converts a handle to a pointer.
+ * @returns PPGMVIRTHANDLERTYPEINT
+ * @param   a_pVM           Pointer to the cross context VM structure.
+ * @param   a_hType         Vitual access handler type handle.
+ */
+#define PGMVIRTHANDLERTYPEINT_FROM_HANDLE(a_pVM, a_hType) ((PPGMVIRTHANDLERTYPEINT)MMHyperHeapOffsetToPtr(a_pVM, a_hType))
+
+
+/**
  * Virtual page access handler structure.
  *
@@ -703,18 +746,13 @@
     AVLROGCPTRNODECORE                  Core;
     /** Size of the range (in bytes). */
-    RTGCPTR                             cb;
+    uint32_t                            cb;
     /** Number of cache pages. */
     uint32_t                            cPages;
-    /** Access type. */
-    PGMVIRTHANDLERTYPE                  enmType;
-    /** Pointer to the RC callback function. */
-    RCPTRTYPE(PFNPGMRCVIRTHANDLER)      pfnHandlerRC;
-#if HC_ARCH_BITS == 64
-    RTRCPTR                             padding;
-#endif
-    /** Pointer to the R3 callback function for invalidation. */
-    R3PTRTYPE(PFNPGMR3VIRTINVALIDATE)   pfnInvalidateR3;
-    /** Pointer to the R3 callback function. */
-    R3PTRTYPE(PFNPGMR3VIRTHANDLER)      pfnHandlerR3;
+    /** Registered handler type handle (heap offset). */
+    PGMVIRTHANDLERTYPE                  hType;
+    /** User argument for RC handlers. */
+    RCPTRTYPE(void *)                   pvUserRC;
+    /** User argument for R3 handlers. */
+    R3PTRTYPE(void *)                   pvUserR3;
     /** Description / Name. For easing debugging. */
     R3PTRTYPE(const char *)             pszDesc;
@@ -728,4 +766,13 @@
 /** Pointer to a virtual page access handler structure. */
 typedef PGMVIRTHANDLER *PPGMVIRTHANDLER;
+
+/**
+ * Gets the type record for a virtual handler (no reference added).
+ * @returns PPGMVIRTHANDLERTYPEINT
+ * @param   a_pVM           Pointer to the cross context VM structure.
+ * @param   a_pVirtHandler  Pointer to the virtual handler structure
+ *                          (PGMVIRTHANDLER).
+ */
+#define PGMVIRTANDLER_GET_TYPE(a_pVM, a_pVirtHandler) PGMVIRTHANDLERTYPEINT_FROM_HANDLE(a_pVM, (a_pVirtHandler)->hType)
 
 
@@ -2670,4 +2717,7 @@
      * PGMPHYSHANDLERTYPEINT.  This is needed for relocations. */
     RTLISTOFF32ANCHOR               HeadPhysHandlerTypes;
+    /** List of virtual access handler types (offset pointers) of type
+     * PGMVIRTHANDLERTYPEINT.  This is needed for relocations. */
+    RTLISTOFF32ANCHOR               HeadVirtHandlerTypes;
 } PGMTREES;
 /** Pointer to PGM trees. */
Index: /trunk/src/VBox/VMM/include/SELMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/SELMInternal.h	(revision 55888)
+++ /trunk/src/VBox/VMM/include/SELMInternal.h	(revision 55889)
@@ -23,4 +23,5 @@
 #include <VBox/vmm/stam.h>
 #include <VBox/vmm/cpum.h>
+#include <VBox/vmm/pgm.h>
 #include <VBox/log.h>
 #include <iprt/x86.h>
@@ -103,4 +104,10 @@
     RTSEL                   aHyperSel[SELM_HYPER_SEL_MAX];
 
+    /** @name GDT
+     * @{ */
+    /** Shadow GDT virtual write access handler type. */
+    PGMVIRTHANDLERTYPE      hShadowGdtWriteHandlerType;
+    /** Guest GDT virtual write access handler type. */
+    PGMVIRTHANDLERTYPE      hGuestGdtWriteHandlerType;
     /** Pointer to the GCs - R3 Ptr.
      * This size is governed by SELM_GDT_ELEMENTS. */
@@ -114,8 +121,16 @@
     VBOXGDTR                GuestGdtr;
     /** The current (last) effective Guest GDT size. */
-    RTUINT                  cbEffGuestGdtLimit;
-
-    uint32_t                padding0;
-
+    uint32_t                cbEffGuestGdtLimit;
+    /** Indicates that the Guest GDT access handler have been registered. */
+    bool                    fGDTRangeRegistered;
+    /** @} */
+    bool                    padding0[3];
+
+    /** @name LDT
+     * @{ */
+    /** Shadow LDT virtual write access handler type. */
+    PGMVIRTHANDLERTYPE      hShadowLdtWriteHandlerType;
+    /** Guest LDT virtual write access handler type. */
+    PGMVIRTHANDLERTYPE      hGuestLdtWriteHandlerType;
     /** R3 pointer to the LDT shadow area in HMA. */
     R3PTRTYPE(void *)       pvLdtR3;
@@ -129,17 +144,23 @@
     RTGCPTR                 GCPtrGuestLdt;
     /** Current LDT limit, both Guest and Shadow. */
-    RTUINT                  cbLdtLimit;
+    uint32_t                cbLdtLimit;
     /** Current LDT offset relative to pvLdtR3/pvLdtRC. */
-    RTUINT                  offLdtHyper;
+    uint32_t                offLdtHyper;
 #if HC_ARCH_BITS == 32 && GC_ARCH_BITS == 64
     uint32_t                padding2[2];
 #endif
+    /** @} */
+
+    /** @name TSS
+     * @{ */
     /** TSS. (This is 16 byte aligned!)
       * @todo I/O bitmap & interrupt redirection table? */
     VBOXTSS                 Tss;
-
     /** TSS for trap 08 (\#DF). */
     VBOXTSS                 TssTrap08;
-
+    /** Shadow TSS virtual write access handler type. */
+    PGMVIRTHANDLERTYPE      hShadowTssWriteHandlerType;
+    /** Guerst TSS virtual write access handler type. */
+    PGMVIRTHANDLERTYPE      hGuestTssWriteHandlerType;
     /** Monitored shadow TSS address. */
     RCPTRTYPE(void *)       pvMonShwTssRC;
@@ -151,9 +172,11 @@
     RTGCPTR                 GCPtrGuestTss;
     /** The size of the guest TSS. */
-    RTUINT                  cbGuestTss;
+    uint32_t                cbGuestTss;
     /** Set if it's a 32-bit TSS. */
     bool                    fGuestTss32Bit;
+    /** Indicates whether the TSS stack selector & base address need to be refreshed.  */
+    bool                    fSyncTSSRing0Stack;
     /** The size of the Guest's TSS part we're monitoring. */
-    RTUINT                  cbMonitoredGuestTss;
+    uint32_t                cbMonitoredGuestTss;
     /** The guest TSS selector at last sync (part of monitoring).
      * Contains RTSEL_MAX if not set. */
@@ -162,11 +185,6 @@
      * This is only used if we monitor the bitmap. */
     uint16_t                offGuestIoBitmap;
-
-    /** Indicates that the Guest GDT access handler have been registered. */
-    bool                    fGDTRangeRegistered;
-
-    /** Indicates whether the TSS stack selector & base address need to be refreshed.  */
-    bool                    fSyncTSSRing0Stack;
-    bool                    fPadding2[4];
+    /** @} */
+    uint16_t                padding4;
 
     /** SELMR3UpdateFromCPUM() profiling. */
Index: /trunk/src/VBox/VMM/include/TRPMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/TRPMInternal.h	(revision 55888)
+++ /trunk/src/VBox/VMM/include/TRPMInternal.h	(revision 55889)
@@ -23,4 +23,5 @@
 #include <VBox/vmm/stam.h>
 #include <VBox/vmm/cpum.h>
+#include <VBox/vmm/pgm.h>
 
 
@@ -126,7 +127,10 @@
     /** Current (last) Guest's IDTR. */
     VBOXIDTR                GuestIdtr;
-
     /** padding. */
     uint8_t                 au8Padding[2];
+    /** Shadow IDT virtual write access handler type. */
+    PGMVIRTHANDLERTYPE      hShadowIdtWriteHandlerType;
+    /** Guest IDT virtual write access handler type. */
+    PGMVIRTHANDLERTYPE      hGuestIdtWriteHandlerType;
 
     /** Checked trap & interrupt handler array */
Index: /trunk/src/VBox/VMM/include/TRPMInternal.mac
===================================================================
--- /trunk/src/VBox/VMM/include/TRPMInternal.mac	(revision 55888)
+++ /trunk/src/VBox/VMM/include/TRPMInternal.mac	(revision 55889)
@@ -36,7 +36,9 @@
     .aTmpTrapHandlers   RTRCPTR_RES 256
 
-    .pvMonShwIdtRC            RTRCPTR_RES 1
-    .GuestIdtr          resb 10
-    .au8Padding         resb 2
+    .pvMonShwIdtRC                  RTRCPTR_RES 1
+    .GuestIdtr                      resb 10
+    .au8Padding                     resb 2
+    .hShadowIdtWriteHandlerType     resd 1
+    .hGuestIdtWriteHandlerType      resd 1
 
     .aGuestTrapHandler  RTRCPTR_RES 256
Index: /trunk/src/VBox/VMM/testcase/tstVMStruct.h
===================================================================
--- /trunk/src/VBox/VMM/testcase/tstVMStruct.h	(revision 55888)
+++ /trunk/src/VBox/VMM/testcase/tstVMStruct.h	(revision 55889)
@@ -799,11 +799,20 @@
     GEN_CHECK_SIZE(PGMVIRTHANDLER);
     GEN_CHECK_OFF(PGMVIRTHANDLER, Core);
-    GEN_CHECK_OFF(PGMVIRTHANDLER, enmType);
+    GEN_CHECK_OFF(PGMVIRTHANDLER, hType);
     GEN_CHECK_OFF(PGMVIRTHANDLER, cb);
-    GEN_CHECK_OFF(PGMVIRTHANDLER, pfnHandlerR3);
-    GEN_CHECK_OFF(PGMVIRTHANDLER, pfnHandlerRC);
+    GEN_CHECK_OFF(PGMVIRTHANDLER, cPages);
     GEN_CHECK_OFF(PGMVIRTHANDLER, pszDesc);
-    GEN_CHECK_OFF(PGMVIRTHANDLER, cPages);
     GEN_CHECK_OFF(PGMVIRTHANDLER, aPhysToVirt);
+    GEN_CHECK_SIZE(PGMVIRTHANDLERTYPEINT);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, u32Magic);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, cRefs);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, ListNode);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, enmKind);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, uState);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, fRelocUserRC);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, pfnHandlerRC);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, pfnInvalidateR3);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, pfnHandlerR3);
+    GEN_CHECK_OFF(PGMVIRTHANDLERTYPEINT, pszDesc);
     GEN_CHECK_SIZE(PGMPAGE);
     GEN_CHECK_OFF_DOT(PGMPAGE, s.cReadLocksY);
@@ -990,8 +999,12 @@
     GEN_CHECK_OFF(SELM, aHyperSel[SELM_HYPER_SEL_TSS]);
     GEN_CHECK_OFF(SELM, aHyperSel[SELM_HYPER_SEL_TSS_TRAP08]);
+    GEN_CHECK_OFF(SELM, hShadowGdtWriteHandlerType);
+    GEN_CHECK_OFF(SELM, hGuestGdtWriteHandlerType);
     GEN_CHECK_OFF(SELM, paGdtR3);
     GEN_CHECK_OFF(SELM, paGdtRC);
     GEN_CHECK_OFF(SELM, GuestGdtr);
     GEN_CHECK_OFF(SELM, cbEffGuestGdtLimit);
+    GEN_CHECK_OFF(SELM, hShadowLdtWriteHandlerType);
+    GEN_CHECK_OFF(SELM, hGuestLdtWriteHandlerType);
     GEN_CHECK_OFF(SELM, pvLdtR3);
     GEN_CHECK_OFF(SELM, pvLdtRC);
@@ -1001,4 +1014,6 @@
     GEN_CHECK_OFF(SELM, Tss);
     GEN_CHECK_OFF(SELM, TssTrap08);
+    GEN_CHECK_OFF(SELM, hShadowTssWriteHandlerType);
+    GEN_CHECK_OFF(SELM, hGuestTssWriteHandlerType);
     GEN_CHECK_OFF(SELM, pvMonShwTssRC);
     GEN_CHECK_OFF(SELM, GCPtrGuestTss);
