Index: /trunk/include/VBox/sup.h
===================================================================
--- /trunk/include/VBox/sup.h	(revision 67954)
+++ /trunk/include/VBox/sup.h	(revision 67955)
@@ -1888,4 +1888,8 @@
 SUPR0DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName);
 
+SUPR0DECL(PVM) SUPR0GetSessionVM(PSUPDRVSESSION pSession);
+SUPR0DECL(PGVM) SUPR0GetSessionGVM(PSUPDRVSESSION pSession);
+SUPR0DECL(int) SUPR0SetSessionVM(PSUPDRVSESSION pSession, PGVM pGVM, PVM pVM);
+
 SUPR0DECL(int) SUPR0LockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages);
 SUPR0DECL(int) SUPR0UnlockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3);
Index: /trunk/include/VBox/vmm/gvm.h
===================================================================
--- /trunk/include/VBox/vmm/gvm.h	(revision 67954)
+++ /trunk/include/VBox/vmm/gvm.h	(revision 67955)
@@ -82,4 +82,6 @@
     /** The ring-0 mapping of the VM structure. */
     PVM             pVM;
+    /** The support driver session the VM is associated with. */
+    PSUPDRVSESSION  pSession;
     /** Number of Virtual CPUs, i.e. how many entries there are in aCpus.
      * Same same as VM::cCpus. */
Index: /trunk/include/VBox/vmm/gvmm.h
===================================================================
--- /trunk/include/VBox/vmm/gvmm.h	(revision 67954)
+++ /trunk/include/VBox/vmm/gvmm.h	(revision 67955)
@@ -163,6 +163,6 @@
 GVMMR0DECL(void)    GVMMR0DoneInitVM(PVM pVM);
 GVMMR0DECL(bool)    GVMMR0DoingTermVM(PVM pVM, PGVM pGVM);
-GVMMR0DECL(int)     GVMMR0DestroyVM(PVM pVM);
-GVMMR0DECL(int)     GVMMR0RegisterVCpu(PVM pVM, VMCPUID idCpu);
+GVMMR0DECL(int)     GVMMR0DestroyVM(PGVM pGVM, PVM pVM);
+GVMMR0DECL(int)     GVMMR0RegisterVCpu(PGVM pGVM, PVM pVM, VMCPUID idCpu);
 GVMMR0DECL(PGVM)    GVMMR0ByHandle(uint32_t hGVM);
 GVMMR0DECL(int)     GVMMR0ByVM(PVM pVM, PGVM *ppGVM);
@@ -201,5 +201,5 @@
 typedef GVMMCREATEVMREQ *PGVMMCREATEVMREQ;
 
-GVMMR0DECL(int)     GVMMR0CreateVMReq(PGVMMCREATEVMREQ pReq);
+GVMMR0DECL(int)     GVMMR0CreateVMReq(PGVMMCREATEVMREQ pReq, PSUPDRVSESSION pSession);
 
 
@@ -239,5 +239,5 @@
 typedef GVMMQUERYSTATISTICSSREQ *PGVMMQUERYSTATISTICSSREQ;
 
-GVMMR0DECL(int)     GVMMR0QueryStatisticsReq(PVM pVM, PGVMMQUERYSTATISTICSSREQ pReq);
+GVMMR0DECL(int)     GVMMR0QueryStatisticsReq(PVM pVM, PGVMMQUERYSTATISTICSSREQ pReq, PSUPDRVSESSION pSession);
 
 
@@ -259,5 +259,5 @@
 typedef GVMMRESETSTATISTICSSREQ *PGVMMRESETSTATISTICSSREQ;
 
-GVMMR0DECL(int)     GVMMR0ResetStatisticsReq(PVM pVM, PGVMMRESETSTATISTICSSREQ pReq);
+GVMMR0DECL(int)     GVMMR0ResetStatisticsReq(PVM pVM, PGVMMRESETSTATISTICSSREQ pReq, PSUPDRVSESSION pSession);
 
 
Index: /trunk/include/VBox/vmm/vmm.h
===================================================================
--- /trunk/include/VBox/vmm/vmm.h	(revision 67954)
+++ /trunk/include/VBox/vmm/vmm.h	(revision 67955)
@@ -516,7 +516,7 @@
 
 #if defined(IN_RING0) || defined(DOXYGEN_RUNNING)
-VMMR0DECL(int)       VMMR0EntryInt(PVM pVM, VMMR0OPERATION enmOperation, void *pvArg);
-VMMR0DECL(void)      VMMR0EntryFast(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation);
-VMMR0DECL(int)       VMMR0EntryEx(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION);
+VMMR0DECL(void)      VMMR0EntryFast(PGVM pGVM, PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation);
+VMMR0DECL(int)       VMMR0EntryEx(PGVM pGVM, PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation,
+                                  PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION);
 VMMR0_INT_DECL(int)  VMMR0TermVM(PVM pVM, PGVM pGVM);
 VMMR0_INT_DECL(bool) VMMR0IsLongJumpArmed(PVMCPU pVCpu);
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp	(revision 67954)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp	(revision 67955)
@@ -218,4 +218,7 @@
     { "SUPR0PageFree",                          (void *)(uintptr_t)SUPR0PageFree },
     { "SUPR0Printf",                            (void *)(uintptr_t)SUPR0Printf },
+    { "SUPR0GetSessionGVM",                     (void *)(uintptr_t)SUPR0GetSessionGVM },
+    { "SUPR0GetSessionVM",                      (void *)(uintptr_t)SUPR0GetSessionVM },
+    { "SUPR0SetSessionVM",                      (void *)(uintptr_t)SUPR0SetSessionVM },
     { "SUPR0TscDeltaMeasureBySetIndex",         (void *)(uintptr_t)SUPR0TscDeltaMeasureBySetIndex },
     { "SUPR0TracerDeregisterDrv",               (void *)(uintptr_t)SUPR0TracerDeregisterDrv },
@@ -924,4 +927,16 @@
 
     /*
+     * Make sure the associated VM pointers are NULL.
+     */
+    if (pSession->pSessionGVM || pSession->pSessionVM || pSession->pFastIoCtrlVM)
+    {
+        SUPR0Printf("supdrvCleanupSession: VM not disassociated! pSessionGVM=%p pSessionVM=%p pFastIoCtrlVM=%p\n",
+                    pSession->pSessionGVM, pSession->pSessionVM, pSession->pFastIoCtrlVM);
+        pSession->pSessionGVM   = NULL;
+        pSession->pSessionVM    = NULL;
+        pSession->pFastIoCtrlVM = NULL;
+    }
+
+    /*
      * Do tracer cleanups related to this session.
      */
@@ -1424,26 +1439,44 @@
 {
     /*
-     * We check the two prereqs after doing this only to allow the compiler to optimize things better.
-     */
-    if (RT_LIKELY(   RT_VALID_PTR(pSession)
-                  && pSession->pVM
-                  && pDevExt->pfnVMMR0EntryFast))
-    {
-        switch (uIOCtl)
-        {
-            case SUP_IOCTL_FAST_DO_RAW_RUN:
-                pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_RAW_RUN);
-                break;
-            case SUP_IOCTL_FAST_DO_HM_RUN:
-                pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_HM_RUN);
-                break;
-            case SUP_IOCTL_FAST_DO_NOP:
-                pDevExt->pfnVMMR0EntryFast(pSession->pVM, idCpu, SUP_VMMR0_DO_NOP);
-                break;
-            default:
-                return VERR_INTERNAL_ERROR;
-        }
-        return VINF_SUCCESS;
-    }
+     * Validate input and check that the VM has a session.
+     */
+    if (RT_LIKELY(RT_VALID_PTR(pSession)))
+    {
+        PVM  pVM  = pSession->pSessionVM;
+        PGVM pGVM = pSession->pSessionGVM;
+        if (RT_LIKELY(   pGVM != NULL
+                      && pVM  != NULL
+                      && pVM  == pSession->pFastIoCtrlVM))
+        {
+            if (RT_LIKELY(pDevExt->pfnVMMR0EntryFast))
+            {
+                /*
+                 * Do the call.
+                 */
+                switch (uIOCtl)
+                {
+                    case SUP_IOCTL_FAST_DO_RAW_RUN:
+                        pDevExt->pfnVMMR0EntryFast(pGVM, pVM, idCpu, SUP_VMMR0_DO_RAW_RUN);
+                        break;
+                    case SUP_IOCTL_FAST_DO_HM_RUN:
+                        pDevExt->pfnVMMR0EntryFast(pGVM, pVM, idCpu, SUP_VMMR0_DO_HM_RUN);
+                        break;
+                    case SUP_IOCTL_FAST_DO_NOP:
+                        pDevExt->pfnVMMR0EntryFast(pGVM, pVM, idCpu, SUP_VMMR0_DO_NOP);
+                        break;
+                    default:
+                        return VERR_INTERNAL_ERROR;
+                }
+                return VINF_SUCCESS;
+            }
+
+            SUPR0Printf("supdrvIOCtlFast: pfnVMMR0EntryFast is NULL\n");
+        }
+        else
+            SUPR0Printf("supdrvIOCtlFast: Misconfig session: pGVM=%p pVM=%p pFastIoCtrlVM=%p\n",
+                        pGVM, pVM, pSession->pFastIoCtrlVM);
+    }
+    else
+        SUPR0Printf("supdrvIOCtlFast: Bad session pointer %p\n", pSession);
     return VERR_INTERNAL_ERROR;
 }
@@ -1781,5 +1814,14 @@
                 /* execute */
                 if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
-                    pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.idCpu, pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg, pSession);
+                {
+                    if (pReq->u.In.pVMR0 == NULL)
+                        pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(NULL, NULL, pReq->u.In.idCpu,
+                                                                pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg, pSession);
+                    else if (pReq->u.In.pVMR0 == pSession->pSessionVM)
+                        pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pSession->pSessionGVM, pSession->pSessionVM, pReq->u.In.idCpu,
+                                                                pReq->u.In.uOperation, NULL, pReq->u.In.u64Arg, pSession);
+                    else
+                        pReq->Hdr.rc = VERR_INVALID_VM_HANDLE;
+                }
                 else
                     pReq->Hdr.rc = VERR_WRONG_ORDER;
@@ -1795,5 +1837,14 @@
                 /* execute */
                 if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
-                    pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.idCpu, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
+                {
+                    if (pReq->u.In.pVMR0 == NULL)
+                        pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(NULL, NULL, pReq->u.In.idCpu,
+                                                                pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
+                    else if (pReq->u.In.pVMR0 == pSession->pSessionVM)
+                        pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pSession->pSessionGVM, pSession->pSessionVM, pReq->u.In.idCpu,
+                                                                pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
+                    else
+                        pReq->Hdr.rc = VERR_INVALID_VM_HANDLE;
+                }
                 else
                     pReq->Hdr.rc = VERR_WRONG_ORDER;
@@ -1827,5 +1878,13 @@
             /* execute */
             if (RT_LIKELY(pDevExt->pfnVMMR0EntryEx))
-                pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pReq->u.In.pVMR0, pReq->u.In.idCpu, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
+            {
+                if (pReq->u.In.pVMR0 == NULL)
+                    pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(NULL, NULL, pReq->u.In.idCpu, pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
+                else if (pReq->u.In.pVMR0 == pSession->pSessionVM)
+                    pReq->Hdr.rc = pDevExt->pfnVMMR0EntryEx(pSession->pSessionGVM, pSession->pSessionVM, pReq->u.In.idCpu,
+                                                            pReq->u.In.uOperation, pVMMReq, pReq->u.In.u64Arg, pSession);
+                else
+                    pReq->Hdr.rc = VERR_INVALID_VM_HANDLE;
+            }
             else
                 pReq->Hdr.rc = VERR_WRONG_ORDER;
@@ -1912,7 +1971,30 @@
                                      && !((uintptr_t)pReq->u.In.pVMR0 & (PAGE_SIZE - 1))),
                                ("SUP_IOCTL_SET_VM_FOR_FAST: pVMR0=%p!\n", pReq->u.In.pVMR0));
+
             /* execute */
-            pSession->pVM = pReq->u.In.pVMR0;
-            pReq->Hdr.rc = VINF_SUCCESS;
+            RTSpinlockAcquire(pDevExt->Spinlock);
+            if (pSession->pSessionVM == pReq->u.In.pVMR0)
+            {
+                if (pSession->pFastIoCtrlVM == NULL)
+                {
+                    pSession->pFastIoCtrlVM = pSession->pSessionVM;
+                    RTSpinlockRelease(pDevExt->Spinlock);
+                    pReq->Hdr.rc = VINF_SUCCESS;
+                }
+                else
+                {
+                    RTSpinlockRelease(pDevExt->Spinlock);
+                    OSDBGPRINT(("SUP_IOCTL_SET_VM_FOR_FAST: pSession->pFastIoCtrlVM=%p! (pVMR0=%p)\n",
+                                pSession->pFastIoCtrlVM, pReq->u.In.pVMR0));
+                    pReq->Hdr.rc = VERR_ALREADY_EXISTS;
+                }
+            }
+            else
+            {
+                RTSpinlockRelease(pDevExt->Spinlock);
+                OSDBGPRINT(("SUP_IOCTL_SET_VM_FOR_FAST: pSession->pSessionVM=%p vs pVMR0=%p)\n",
+                            pSession->pSessionVM, pReq->u.In.pVMR0));
+                pReq->Hdr.rc = pSession->pSessionVM ? VERR_ACCESS_DENIED : VERR_WRONG_ORDER;
+            }
             return 0;
         }
@@ -3013,4 +3095,81 @@
 
 /**
+ * API for the VMMR0 module to get the SUPDRVSESSION::pSessionVM member.
+ *
+ * @returns The associated VM pointer.
+ * @param   pSession    The session of the current thread.
+ */
+SUPR0DECL(PVM) SUPR0GetSessionVM(PSUPDRVSESSION pSession)
+{
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), NULL);
+    return pSession->pSessionVM;
+}
+
+
+/**
+ * API for the VMMR0 module to get the SUPDRVSESSION::pSessionGVM member.
+ *
+ * @returns The associated GVM pointer.
+ * @param   pSession    The session of the current thread.
+ */
+SUPR0DECL(PGVM) SUPR0GetSessionGVM(PSUPDRVSESSION pSession)
+{
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), NULL);
+    return pSession->pSessionGVM;
+}
+
+
+/**
+ * API for the VMMR0 module to work the SUPDRVSESSION::pSessionVM member.
+ *
+ * This will fail if there is already a VM associated with the session and pVM
+ * isn't NULL.
+ *
+ * @retval  VINF_SUCCESS
+ * @retval  VERR_ALREADY_EXISTS if there already is a VM associated with the
+ *          session.
+ * @retval  VERR_INVALID_PARAMETER if only one of the parameters are NULL or if
+ *          the session is invalid.
+ *
+ * @param   pSession    The session of the current thread.
+ * @param   pGVM        The GVM to associate with the session.  Pass NULL to
+ *                      dissassociate.
+ * @param   pVM         The VM to associate with the session.  Pass NULL to
+ *                      dissassociate.
+ */
+SUPR0DECL(int) SUPR0SetSessionVM(PSUPDRVSESSION pSession, PGVM pGVM, PVM pVM)
+{
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    AssertReturn((pGVM != NULL) == (pVM != NULL), VERR_INVALID_PARAMETER);
+
+    RTSpinlockAcquire(pSession->pDevExt->Spinlock);
+    if (pGVM)
+    {
+        if (!pSession->pSessionGVM)
+        {
+            pSession->pSessionGVM   = pGVM;
+            pSession->pSessionVM    = pVM;
+            pSession->pFastIoCtrlVM = NULL;
+        }
+        else
+        {
+            RTSpinlockRelease(pSession->pDevExt->Spinlock);
+            SUPR0Printf("SUPR0SetSessionVM: Unable to associated GVM/VM %p/%p with session %p as it has %p/%p already!\n",
+                        pGVM, pVM, pSession, pSession->pSessionGVM, pSession->pSessionVM);
+            return VERR_ALREADY_EXISTS;
+        }
+    }
+    else
+    {
+        pSession->pSessionGVM   = NULL;
+        pSession->pSessionVM    = NULL;
+        pSession->pFastIoCtrlVM = NULL;
+    }
+    RTSpinlockRelease(pSession->pDevExt->Spinlock);
+    return VINF_SUCCESS;
+}
+
+
+/**
  * Lock pages.
  *
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h	(revision 67954)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h	(revision 67955)
@@ -215,5 +215,5 @@
  *          - nothing.
  */
-#define SUPDRV_IOC_VERSION                              0x00280002
+#define SUPDRV_IOC_VERSION                              0x00290000
 
 /** SUP_IOCTL_COOKIE. */
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 67954)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 67955)
@@ -488,6 +488,12 @@
     RTR0PROCESS                     R0Process;
 
-    /** The VM associated with the session. */
-    PVM                             pVM;
+    /** The GVM associated with the session.
+     * This is set by VMMR0.  */
+    PGVM                            pSessionGVM;
+    /** The VM associated with the session.
+     * This is set by VMMR0.  */
+    PVM                             pSessionVM;
+    /** Set to pSessionVM if fast I/O controlls are enabled. */
+    PVM                             pFastIoCtrlVM;
     /** Handle table for IPRT semaphore wrapper APIs.
      * This takes care of its own locking in an IRQ safe manner. */
@@ -588,7 +594,8 @@
     void * volatile                 pvVMMR0;
     /** VMMR0EntryFast() pointer. */
-    DECLR0CALLBACKMEMBER(void,      pfnVMMR0EntryFast, (PVM pVM, VMCPUID idCpu, unsigned uOperation));
+    DECLR0CALLBACKMEMBER(void,      pfnVMMR0EntryFast, (PGVM pGVM, PVM pVM, VMCPUID idCpu, uint32_t uOperation));
     /** VMMR0EntryEx() pointer. */
-    DECLR0CALLBACKMEMBER(int,       pfnVMMR0EntryEx, (PVM pVM, VMCPUID idCpu, unsigned uOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession));
+    DECLR0CALLBACKMEMBER(int,       pfnVMMR0EntryEx, (PGVM pGVM, PVM pVM, VMCPUID idCpu, uint32_t uOperation,
+                                                      PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession));
 
     /** Linked list of loaded code. */
Index: /trunk/src/VBox/HostDrivers/Support/testcase/tstInt.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/testcase/tstInt.cpp	(revision 67954)
+++ /trunk/src/VBox/HostDrivers/Support/testcase/tstInt.cpp	(revision 67955)
@@ -32,4 +32,5 @@
 #include <VBox/vmm/vm.h>
 #include <VBox/vmm/vmm.h>
+#include <VBox/vmm/gvmm.h>
 #include <VBox/err.h>
 #include <VBox/param.h>
@@ -80,27 +81,28 @@
         {
             /*
-             * Create a fake 'VM'.
+             * Create a tiny dummy VM so we can do NOP calls into it using the fast I/O control path.
              */
-            PVMR0 pVMR0 = NIL_RTR0PTR;
-            PVM pVM = NULL;
-            const unsigned cPages = RT_ALIGN_Z(sizeof(*pVM), PAGE_SIZE) >> PAGE_SHIFT;
-            PSUPPAGE paPages = (PSUPPAGE)RTMemAllocZ(cPages * sizeof(SUPPAGE));
-            if (paPages)
-                rc = SUPR3LowAlloc(cPages, (void **)&pVM, &pVMR0, &paPages[0]);
-            else
-                rc = VERR_NO_MEMORY;
+            GVMMCREATEVMREQ CreateVMReq;
+            CreateVMReq.Hdr.u32Magic    = SUPVMMR0REQHDR_MAGIC;
+            CreateVMReq.Hdr.cbReq       = sizeof(CreateVMReq);
+            CreateVMReq.pSession        = pSession;
+            CreateVMReq.pVMR0           = NIL_RTR0PTR;
+            CreateVMReq.pVMR3           = NULL;
+            CreateVMReq.cCpus           = 1;
+            rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_GVMM_CREATE_VM, 0, &CreateVMReq.Hdr);
             if (RT_SUCCESS(rc))
             {
-                pVM->pVMRC = 0;
-                pVM->pVMR3 = pVM;
-                pVM->pVMR0 = pVMR0;
-                pVM->paVMPagesR3 = paPages;
-                pVM->pSession = pSession;
+                PVM pVM = CreateVMReq.pVMR3;
+                AssertRelease(VALID_PTR(pVM));
+                AssertRelease(pVM->pVMR0 == CreateVMReq.pVMR0);
+                AssertRelease(pVM->pSession == pSession);
+                AssertRelease(pVM->cCpus == 1);
+                AssertRelease(pVM->offVMCPU == RT_UOFFSETOF(VM, aCpus));
                 pVM->enmVMState = VMSTATE_CREATED;
-
-                rc = SUPR3SetVMForFastIOCtl(pVMR0);
+                PVMR0 const pVMR0 = pVM->pVMR0;
+
+                rc = SUPR3SetVMForFastIOCtl(pVM->pVMR0);
                 if (!rc)
                 {
-
                     /*
                      * Call VMM code with invalid function.
@@ -182,8 +184,15 @@
                     rcRet++;
                 }
+
+                rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /*idCpu*/, VMMR0_DO_GVMM_DESTROY_VM, 0, NULL);
+                if (RT_FAILURE(rc))
+                {
+                    RTPrintf("tstInt: VMMR0_DO_GVMM_DESTROY_VM failed: %Rrc\n", rc);
+                    rcRet++;
+                }
             }
             else
             {
-                RTPrintf("tstInt: SUPR3ContAlloc(%#zx,,) failed\n", sizeof(*pVM));
+                RTPrintf("tstInt: VMMR0_DO_GVMM_CREATE_VM failed\n");
                 rcRet++;
             }
Index: /trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp	(revision 67954)
+++ /trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp	(revision 67955)
@@ -361,4 +361,6 @@
 static int gvmmR0ByVM(PVM pVM, PGVM *ppGVM, PGVMM *ppGVMM, bool fTakeUsedLock);
 static int gvmmR0ByVMAndEMT(PVM pVM, VMCPUID idCpu, PGVM *ppGVM, PGVMM *ppGVMM);
+static int gvmmR0ByGVMandVM(PGVM pGVM, PVM pVM, PGVMM *ppGVMM, bool fTakeUsedLock);
+
 #ifdef GVMM_SCHED_WITH_PPT
 static DECLCALLBACK(void) gvmmR0SchedPeriodicPreemptionTimerCallback(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
@@ -769,6 +771,7 @@
  * @returns VBox status code.
  * @param   pReq        The request buffer.
- */
-GVMMR0DECL(int) GVMMR0CreateVMReq(PGVMMCREATEVMREQ pReq)
+ * @param   pSession    The session handle. The VM will be associated with this.
+ */
+GVMMR0DECL(int) GVMMR0CreateVMReq(PGVMMCREATEVMREQ pReq, PSUPDRVSESSION pSession)
 {
     /*
@@ -779,5 +782,5 @@
     if (pReq->Hdr.cbReq != sizeof(*pReq))
         return VERR_INVALID_PARAMETER;
-    if (!VALID_PTR(pReq->pSession))
+    if (pReq->pSession != pSession)
         return VERR_INVALID_POINTER;
 
@@ -788,5 +791,5 @@
     pReq->pVMR0 = NULL;
     pReq->pVMR3 = NIL_RTR3PTR;
-    int rc = GVMMR0CreateVM(pReq->pSession, pReq->cCpus, &pVM);
+    int rc = GVMMR0CreateVM(pSession, pReq->cCpus, &pVM);
     if (RT_SUCCESS(rc))
     {
@@ -833,4 +836,14 @@
     int rc = gvmmR0CreateDestroyLock(pGVMM);
     AssertRCReturn(rc, rc);
+
+    /*
+     * Only one VM per session.
+     */
+    if (SUPR0GetSessionVM(pSession) != NULL)
+    {
+        gvmmR0CreateDestroyUnlock(pGVMM);
+        SUPR0Printf("GVMMR0CreateVM: The session %p already got a VM: %p\n", pSession, SUPR0GetSessionVM(pSession));
+        return VERR_ALREADY_EXISTS;
+    }
 
     /*
@@ -883,4 +896,5 @@
                         pGVM->pVM       = NULL;
                         pGVM->cCpus     = cCpus;
+                        pGVM->pSession  = pSession;
 
                         gvmmR0InitPerVMData(pGVM);
@@ -960,19 +974,28 @@
                                         pGVMM->cEMTs += cCpus;
 
-                                        rc = VMMR0ThreadCtxHookCreateForEmt(&pVM->aCpus[0]);
+                                        /* Associate it with the session and create the context hook for EMT0. */
+                                        rc = SUPR0SetSessionVM(pSession, pGVM, pVM);
                                         if (RT_SUCCESS(rc))
                                         {
-                                            VBOXVMM_R0_GVMM_VM_CREATED(pGVM, pVM, ProcId, (void *)hEMT0, cCpus);
-
-                                            GVMMR0_USED_EXCLUSIVE_UNLOCK(pGVMM);
-                                            gvmmR0CreateDestroyUnlock(pGVMM);
-
-                                            CPUMR0RegisterVCpuThread(&pVM->aCpus[0]);
-
-                                            *ppVM = pVM;
-                                            Log(("GVMMR0CreateVM: pVM=%p pVMR3=%p pGVM=%p hGVM=%d\n", pVM, pVM->pVMR3, pGVM, iHandle));
-                                            return VINF_SUCCESS;
+                                            rc = VMMR0ThreadCtxHookCreateForEmt(&pVM->aCpus[0]);
+                                            if (RT_SUCCESS(rc))
+                                            {
+                                                /*
+                                                 * Done!
+                                                 */
+                                                VBOXVMM_R0_GVMM_VM_CREATED(pGVM, pVM, ProcId, (void *)hEMT0, cCpus);
+
+                                                GVMMR0_USED_EXCLUSIVE_UNLOCK(pGVMM);
+                                                gvmmR0CreateDestroyUnlock(pGVMM);
+
+                                                CPUMR0RegisterVCpuThread(&pVM->aCpus[0]);
+
+                                                *ppVM = pVM;
+                                                Log(("GVMMR0CreateVM: pVM=%p pVMR3=%p pGVM=%p hGVM=%d\n", pVM, pVM->pVMR3, pGVM, iHandle));
+                                                return VINF_SUCCESS;
+                                            }
+
+                                            SUPR0SetSessionVM(pSession, NULL, NULL);
                                         }
-
                                         GVMMR0_USED_EXCLUSIVE_UNLOCK(pGVMM);
                                     }
@@ -1139,11 +1162,12 @@
  *
  * @returns VBox status code.
+ * @param   pGVM        The global (ring-0) VM structure.
  * @param   pVM         The cross context VM structure.
  *
  * @thread  EMT(0) if it's associated with the VM, otherwise any thread.
  */
-GVMMR0DECL(int) GVMMR0DestroyVM(PVM pVM)
-{
-    LogFlow(("GVMMR0DestroyVM: pVM=%p\n", pVM));
+GVMMR0DECL(int) GVMMR0DestroyVM(PGVM pGVM, PVM pVM)
+{
+    LogFlow(("GVMMR0DestroyVM: pGVM=%p pVM=%p\n", pGVM, pVM));
     PGVMM pGVMM;
     GVMM_GET_VALID_INSTANCE(pGVMM, VERR_GVMM_INSTANCE);
@@ -1152,10 +1176,12 @@
      * Validate the VM structure, state and caller.
      */
+    AssertPtrReturn(pGVM, VERR_INVALID_POINTER);
     AssertPtrReturn(pVM, VERR_INVALID_POINTER);
     AssertReturn(!((uintptr_t)pVM & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
+    AssertReturn(pGVM->pVM == pVM, VERR_INVALID_POINTER);
     AssertMsgReturn(pVM->enmVMState >= VMSTATE_CREATING && pVM->enmVMState <= VMSTATE_TERMINATED, ("%d\n", pVM->enmVMState),
                     VERR_WRONG_ORDER);
 
-    uint32_t hGVM = pVM->hSelf;
+    uint32_t hGVM = pGVM->hSelf;
     AssertReturn(hGVM != NIL_GVM_HANDLE, VERR_INVALID_HANDLE);
     AssertReturn(hGVM < RT_ELEMENTS(pGVMM->aHandles), VERR_INVALID_HANDLE);
@@ -1330,4 +1356,8 @@
     {
         pGVMM->cEMTs -= pGVM->cCpus;
+
+        if (pGVM->pSession)
+            SUPR0SetSessionVM(pGVM->pSession, NULL, NULL);
+
         GVMMR0_USED_EXCLUSIVE_UNLOCK(pGVMM);
 
@@ -1405,8 +1435,9 @@
  *
  * @returns VBox status code
- * @param   pVM             The cross context VM structure.
- * @param   idCpu           VCPU id.
- */
-GVMMR0DECL(int) GVMMR0RegisterVCpu(PVM pVM, VMCPUID idCpu)
+ * @param   pGVM        The global (ring-0) VM structure.
+ * @param   pVM         The cross context VM structure.
+ * @param   idCpu       VCPU id to register the current thread as.
+ */
+GVMMR0DECL(int) GVMMR0RegisterVCpu(PGVM pGVM, PVM pVM, VMCPUID idCpu)
 {
     AssertReturn(idCpu != 0, VERR_NOT_OWNER);
@@ -1415,20 +1446,39 @@
      * Validate the VM structure, state and handle.
      */
-    PGVM pGVM;
     PGVMM pGVMM;
-    int rc = gvmmR0ByVM(pVM, &pGVM, &pGVMM, false /* fTakeUsedLock */); /** @todo take lock here. */
-    if (RT_FAILURE(rc))
-        return rc;
-
-    AssertReturn(idCpu < pGVM->cCpus, VERR_INVALID_CPU_ID);
-    AssertReturn(pGVM->aCpus[idCpu].hEMT == NIL_RTNATIVETHREAD, VERR_ACCESS_DENIED);
-    Assert(pGVM->cCpus == pVM->cCpus);
-    Assert(pVM->aCpus[idCpu].hNativeThreadR0 == NIL_RTNATIVETHREAD);
-
-    pVM->aCpus[idCpu].hNativeThreadR0 = pGVM->aCpus[idCpu].hEMT = RTThreadNativeSelf();
-
-    rc = VMMR0ThreadCtxHookCreateForEmt(&pVM->aCpus[idCpu]);
+    int rc = gvmmR0ByGVMandVM(pGVM, pVM, &pGVMM, false /* fTakeUsedLock */); /** @todo take lock here. */
     if (RT_SUCCESS(rc))
-        CPUMR0RegisterVCpuThread(&pVM->aCpus[idCpu]);
+    {
+        if (idCpu < pGVM->cCpus)
+        {
+            /* Check that the EMT isn't already assigned to a thread. */
+            if (pGVM->aCpus[idCpu].hEMT == NIL_RTNATIVETHREAD)
+            {
+                Assert(pVM->aCpus[idCpu].hNativeThreadR0 == NIL_RTNATIVETHREAD);
+
+                /* A thread may only be one EMT. */
+                RTNATIVETHREAD const hNativeSelf = RTThreadNativeSelf();
+                for (VMCPUID iCpu = 0; iCpu < pGVM->cCpus; iCpu++)
+                    AssertBreakStmt(pGVM->aCpus[iCpu].hEMT != hNativeSelf, rc = VERR_INVALID_PARAMETER);
+                if (RT_SUCCESS(rc))
+                {
+                    /*
+                     * Do the assignment, then try setup the hook. Undo if that fails.
+                     */
+                    pVM->aCpus[idCpu].hNativeThreadR0 = pGVM->aCpus[idCpu].hEMT = RTThreadNativeSelf();
+
+                    rc = VMMR0ThreadCtxHookCreateForEmt(&pVM->aCpus[idCpu]);
+                    if (RT_SUCCESS(rc))
+                        CPUMR0RegisterVCpuThread(&pVM->aCpus[idCpu]);
+                    else
+                        pVM->aCpus[idCpu].hNativeThreadR0 = pGVM->aCpus[idCpu].hEMT = NIL_RTNATIVETHREAD;
+                }
+            }
+            else
+                rc = VERR_ACCESS_DENIED;
+        }
+        else
+            rc = VERR_INVALID_CPU_ID;
+    }
     return rc;
 }
@@ -1545,4 +1595,87 @@
     *ppGVMM = pGVMM;
     return VINF_SUCCESS;
+}
+
+
+/**
+ * Check that the given GVM and VM structures match up.
+ *
+ * The calling thread must be in the same process as the VM. All current lookups
+ * are by threads inside the same process, so this will not be an issue.
+ *
+ * @returns VBox status code.
+ * @param   pGVM            The global (ring-0) VM structure.
+ * @param   pVM             The cross context VM structure.
+ * @param   ppGVMM          Where to store the pointer to the GVMM instance data.
+ * @param   fTakeUsedLock   Whether to take the used lock or not.  We take it in
+ *                          shared mode when requested.
+ *
+ *                          Be very careful if not taking the lock as it's
+ *                          possible that the VM will disappear then!
+ *
+ * @remark  This will not assert on an invalid pVM but try return silently.
+ */
+static int gvmmR0ByGVMandVM(PGVM pGVM, PVM pVM, PGVMM *ppGVMM, bool fTakeUsedLock)
+{
+    /*
+     * Check the pointers.
+     */
+    int rc;
+    if (RT_LIKELY(RT_VALID_PTR(pGVM)))
+    {
+        if (RT_LIKELY(   RT_VALID_PTR(pVM)
+                      && ((uintptr_t)pVM & PAGE_OFFSET_MASK) == 0))
+        {
+            if (RT_LIKELY(pGVM->pVM == pVM))
+            {
+                /*
+                 * Get the pGVMM instance and check the VM handle.
+                 */
+                PGVMM pGVMM;
+                GVMM_GET_VALID_INSTANCE(pGVMM, VERR_GVMM_INSTANCE);
+
+                uint16_t hGVM = pGVM->hSelf;
+                if (RT_LIKELY(   hGVM != NIL_GVM_HANDLE
+                              && hGVM < RT_ELEMENTS(pGVMM->aHandles)))
+                {
+                    RTPROCESS const pidSelf = RTProcSelf();
+                    PGVMHANDLE      pHandle = &pGVMM->aHandles[hGVM];
+                    if (fTakeUsedLock)
+                    {
+                        rc = GVMMR0_USED_SHARED_LOCK(pGVMM);
+                        AssertRCReturn(rc, rc);
+                    }
+
+                    if (RT_LIKELY(   pHandle->pGVM   == pGVM
+                                  && pHandle->pVM    == pVM
+                                  && pHandle->ProcId == pidSelf
+                                  && RT_VALID_PTR(pHandle->pvObj)))
+                    {
+                        /*
+                         * Some more VM data consistency checks.
+                         */
+                        if (RT_LIKELY(   pVM->cCpus == pGVM->cCpus
+                                      && pVM->hSelf == hGVM
+                                      && pVM->enmVMState >= VMSTATE_CREATING
+                                      && pVM->enmVMState <= VMSTATE_TERMINATED
+                                      && pVM->pVMR0 == pVM))
+                        {
+                            *ppGVMM = pGVMM;
+                            return VINF_SUCCESS;
+                        }
+                    }
+
+                    if (fTakeUsedLock)
+                        GVMMR0_USED_SHARED_UNLOCK(pGVMM);
+                }
+            }
+            rc = VERR_INVALID_HANDLE;
+        }
+        else
+            rc = VERR_INVALID_POINTER;
+    }
+    else
+        rc = VERR_INVALID_POINTER;
+    return rc;
 }
 
@@ -2590,6 +2723,7 @@
  * @param   pVM             The cross context VM structure. Optional.
  * @param   pReq            Pointer to the request packet.
- */
-GVMMR0DECL(int) GVMMR0QueryStatisticsReq(PVM pVM, PGVMMQUERYSTATISTICSSREQ pReq)
+ * @param   pSession        The current session.
+ */
+GVMMR0DECL(int) GVMMR0QueryStatisticsReq(PVM pVM, PGVMMQUERYSTATISTICSSREQ pReq, PSUPDRVSESSION pSession)
 {
     /*
@@ -2598,6 +2732,7 @@
     AssertPtrReturn(pReq, VERR_INVALID_POINTER);
     AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
-
-    return GVMMR0QueryStatistics(&pReq->Stats, pReq->pSession, pVM);
+    AssertReturn(pReq->pSession == pSession, VERR_INVALID_PARAMETER);
+
+    return GVMMR0QueryStatistics(&pReq->Stats, pSession, pVM);
 }
 
@@ -2705,6 +2840,7 @@
  * @param   pVM             The cross context VM structure. Optional.
  * @param   pReq            Pointer to the request packet.
- */
-GVMMR0DECL(int) GVMMR0ResetStatisticsReq(PVM pVM, PGVMMRESETSTATISTICSSREQ pReq)
+ * @param   pSession        The current session.
+ */
+GVMMR0DECL(int) GVMMR0ResetStatisticsReq(PVM pVM, PGVMMRESETSTATISTICSSREQ pReq, PSUPDRVSESSION pSession)
 {
     /*
@@ -2713,6 +2849,7 @@
     AssertPtrReturn(pReq, VERR_INVALID_POINTER);
     AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
-
-    return GVMMR0ResetStatistics(&pReq->Stats, pReq->pSession, pVM);
-}
-
+    AssertReturn(pReq->pSession == pSession, VERR_INVALID_PARAMETER);
+
+    return GVMMR0ResetStatistics(&pReq->Stats, pSession, pVM);
+}
+
Index: /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 67954)
+++ /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 67955)
@@ -31,4 +31,5 @@
 #include "VMMInternal.h"
 #include <VBox/vmm/vm.h>
+#include <VBox/vmm/gvm.h>
 #ifdef VBOX_WITH_PCI_PASSTHROUGH
 # include <VBox/vmm/pdmpci.h>
@@ -930,4 +931,5 @@
  * The Ring 0 entry point, called by the fast-ioctl path.
  *
+ * @param   pGVM            The global (ring-0) VM structure.
  * @param   pVM             The cross context VM structure.
  *                          The return code is stored in pVM->vmm.s.iLastGZRc.
@@ -936,14 +938,34 @@
  * @remarks Assume called with interrupts _enabled_.
  */
-VMMR0DECL(void) VMMR0EntryFast(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation)
+VMMR0DECL(void) VMMR0EntryFast(PGVM pGVM, PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation)
 {
     /*
      * Validation.
      */
-    if (RT_UNLIKELY(idCpu >= pVM->cCpus))
+    if (   idCpu < pGVM->cCpus
+        && pGVM->cCpus == pVM->cCpus)
+    { /*likely*/ }
+    else
+    {
+        SUPR0Printf("VMMR0EntryFast: Bad idCpu=%#x cCpus=%#x/%#x\n", idCpu, pGVM->cCpus, pVM->cCpus);
         return;
-    PVMCPU pVCpu = &pVM->aCpus[idCpu];
-    if (RT_UNLIKELY(pVCpu->hNativeThreadR0 != RTThreadNativeSelf()))
+    }
+
+    PGVMCPU pGVCpu = &pGVM->aCpus[idCpu];
+    PVMCPU  pVCpu  = &pVM->aCpus[idCpu];
+    RTNATIVETHREAD const hNativeThread = RTThreadNativeSelf();
+    if (RT_LIKELY(   pGVCpu->hEMT           == hNativeThread
+                  && pVCpu->hNativeThreadR0 == hNativeThread))
+    { /* likely */ }
+    else
+    {
+        SUPR0Printf("VMMR0EntryFast: Bad thread idCpu=%#x hNativeSelf=%p pGVCpu->hEmt=%p pVCpu->hNativeThreadR0=%p\n",
+                    idCpu, hNativeThread, pGVCpu->hEMT, pVCpu->hNativeThreadR0);
         return;
+    }
+
+    /*
+     * SMAP fun.
+     */
     VMM_CHECK_SMAP_SETUP();
     VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
@@ -1314,4 +1336,5 @@
  *
  * @returns VBox status code.
+ * @param   pGVM            The global (ring-0) VM structure.
  * @param   pVM             The cross context VM structure.
  * @param   idCpu           Virtual CPU ID argument. Must be NIL_VMCPUID if pVM
@@ -1322,43 +1345,73 @@
  * @param   u64Arg          Some simple constant argument.
  * @param   pSession        The session of the caller.
+ *
  * @remarks Assume called with interrupts _enabled_.
  */
-static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReqHdr, uint64_t u64Arg, PSUPDRVSESSION pSession)
-{
-    /*
-     * Common VM pointer validation.
-     */
-    if (pVM)
+static int vmmR0EntryExWorker(PGVM pGVM, PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation,
+                              PSUPVMMR0REQHDR pReqHdr, uint64_t u64Arg, PSUPDRVSESSION pSession)
+{
+    /*
+     * Validate pGVM, pVM and idCpu for consistency and validity.
+     */
+    if (   pGVM != NULL
+        || pVM  != NULL)
     {
-        if (RT_UNLIKELY(    !VALID_PTR(pVM)
-                        ||  ((uintptr_t)pVM & PAGE_OFFSET_MASK)))
+        if (RT_LIKELY(   RT_VALID_PTR(pGVM)
+                      && RT_VALID_PTR(pVM)
+                      && ((uintptr_t)pVM & PAGE_OFFSET_MASK) == 0))
+        { /* likely */ }
+        else
         {
-            SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p! (op=%d)\n", pVM, enmOperation);
+            SUPR0Printf("vmmR0EntryExWorker: Invalid pGVM=%p and/or pVM=%p! (op=%d)\n", pGVM, pVM, enmOperation);
             return VERR_INVALID_POINTER;
         }
-        if (RT_UNLIKELY(    pVM->enmVMState < VMSTATE_CREATING
-                        ||  pVM->enmVMState > VMSTATE_TERMINATED
-                        ||  pVM->pVMR0 != pVM))
+
+        if (RT_LIKELY(pGVM->pVM == pVM))
+        { /* likely */ }
+        else
         {
-            SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p:{enmVMState=%d, .pVMR0=%p}! (op=%d)\n",
-                        pVM, pVM->enmVMState, pVM->pVMR0, enmOperation);
+            SUPR0Printf("vmmR0EntryExWorker: pVM mismatch: got %p, pGVM->pVM=%p\n", pVM, pGVM->pVM);
+            return VERR_INVALID_PARAMETER;
+        }
+
+        if (RT_LIKELY(idCpu == NIL_VMCPUID || idCpu < pGVM->cCpus))
+        { /* likely */ }
+        else
+        {
+            SUPR0Printf("vmmR0EntryExWorker: Invalid idCpu %#x (cCpus=%#x)\n", idCpu, pGVM->cCpus);
+            return VERR_INVALID_PARAMETER;
+        }
+
+        if (RT_LIKELY(   pVM->enmVMState >= VMSTATE_CREATING
+                      && pVM->enmVMState <= VMSTATE_TERMINATED
+                      && pVM->cCpus      == pGVM->cCpus
+                      && pVM->pSession   == pSession
+                      && pVM->pVMR0      == pVM))
+        { /* likely */ }
+        else
+        {
+            SUPR0Printf("vmmR0EntryExWorker: Invalid pVM=%p:{.enmVMState=%d, .cCpus=%#x(==%#x), .pSession=%p(==%p), .pVMR0=%p(==%p)}! (op=%d)\n",
+                        pVM, pVM->enmVMState, pVM->cCpus, pGVM->cCpus, pVM->pSession, pSession, pVM->pVMR0, pVM, enmOperation);
             return VERR_INVALID_POINTER;
         }
-
-        if (RT_UNLIKELY(idCpu >= pVM->cCpus && idCpu != NIL_VMCPUID))
-        {
-            SUPR0Printf("vmmR0EntryExWorker: Invalid idCpu (%u vs cCpus=%u)\n", idCpu, pVM->cCpus);
-            return VERR_INVALID_PARAMETER;
-        }
     }
-    else if (RT_UNLIKELY(idCpu != NIL_VMCPUID))
+    else if (RT_LIKELY(idCpu == NIL_VMCPUID))
+    { /* likely */ }
+    else
     {
         SUPR0Printf("vmmR0EntryExWorker: Invalid idCpu=%u\n", idCpu);
         return VERR_INVALID_PARAMETER;
     }
+
+    /*
+     * SMAP fun.
+     */
     VMM_CHECK_SMAP_SETUP();
     VMM_CHECK_SMAP_CHECK(RT_NOTHING);
+
+    /*
+     * Process the request.
+     */
     int rc;
-
     switch (enmOperation)
     {
@@ -1367,25 +1420,26 @@
          */
         case VMMR0_DO_GVMM_CREATE_VM:
-            if (pVM || u64Arg || idCpu != NIL_VMCPUID)
-                return VERR_INVALID_PARAMETER;
-            rc = GVMMR0CreateVMReq((PGVMMCREATEVMREQ)pReqHdr);
+            if (pGVM == NULL && pVM == NULL && u64Arg == 0 && idCpu == NIL_VMCPUID)
+                rc = GVMMR0CreateVMReq((PGVMMCREATEVMREQ)pReqHdr, pSession);
+            else
+                rc = VERR_INVALID_PARAMETER;
             VMM_CHECK_SMAP_CHECK(RT_NOTHING);
             break;
 
         case VMMR0_DO_GVMM_DESTROY_VM:
-            if (pReqHdr || u64Arg)
-                return VERR_INVALID_PARAMETER;
-            rc = GVMMR0DestroyVM(pVM);
+            if (pReqHdr == NULL && u64Arg == 0)
+                rc = GVMMR0DestroyVM(pGVM, pVM);
+            else
+                rc = VERR_INVALID_PARAMETER;
             VMM_CHECK_SMAP_CHECK(RT_NOTHING);
             break;
 
         case VMMR0_DO_GVMM_REGISTER_VMCPU:
-        {
-            if (!pVM)
-                return VERR_INVALID_PARAMETER;
-            rc = GVMMR0RegisterVCpu(pVM, idCpu);
-            VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
-            break;
-        }
+            if (pGVM != NULL && pVM != NULL )
+                rc = GVMMR0RegisterVCpu(pGVM, pVM, idCpu);
+            else
+                rc = VERR_INVALID_PARAMETER;
+            VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+            break;
 
         case VMMR0_DO_GVMM_SCHED_HALT:
@@ -1429,5 +1483,5 @@
             if (u64Arg)
                 return VERR_INVALID_PARAMETER;
-            rc = GVMMR0QueryStatisticsReq(pVM, (PGVMMQUERYSTATISTICSSREQ)pReqHdr);
+            rc = GVMMR0QueryStatisticsReq(pVM, (PGVMMQUERYSTATISTICSSREQ)pReqHdr, pSession);
             VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
             break;
@@ -1436,5 +1490,5 @@
             if (u64Arg)
                 return VERR_INVALID_PARAMETER;
-            rc = GVMMR0ResetStatisticsReq(pVM, (PGVMMRESETSTATISTICSSREQ)pReqHdr);
+            rc = GVMMR0ResetStatisticsReq(pVM, (PGVMMRESETSTATISTICSSREQ)pReqHdr, pSession);
             VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
             break;
@@ -1923,4 +1977,5 @@
 typedef struct VMMR0ENTRYEXARGS
 {
+    PGVM                pGVM;
     PVM                 pVM;
     VMCPUID             idCpu;
@@ -1941,5 +1996,6 @@
 static DECLCALLBACK(int) vmmR0EntryExWrapper(void *pvArgs)
 {
-    return vmmR0EntryExWorker(((PVMMR0ENTRYEXARGS)pvArgs)->pVM,
+    return vmmR0EntryExWorker(((PVMMR0ENTRYEXARGS)pvArgs)->pGVM,
+                              ((PVMMR0ENTRYEXARGS)pvArgs)->pVM,
                               ((PVMMR0ENTRYEXARGS)pvArgs)->idCpu,
                               ((PVMMR0ENTRYEXARGS)pvArgs)->enmOperation,
@@ -1963,5 +2019,6 @@
  * @remarks Assume called with interrupts _enabled_.
  */
-VMMR0DECL(int) VMMR0EntryEx(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession)
+VMMR0DECL(int) VMMR0EntryEx(PGVM pGVM, PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation,
+                            PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession)
 {
     /*
@@ -1969,7 +2026,8 @@
      * wrapped in a setjmp so we can assert without causing trouble.
      */
-    if (    VALID_PTR(pVM)
-        &&  pVM->pVMR0
-        &&  idCpu < pVM->cCpus)
+    if (   pVM  != NULL
+        && pGVM != NULL
+        && idCpu < pGVM->cCpus
+        && pVM->pVMR0 != NULL)
     {
         switch (enmOperation)
@@ -1985,18 +2043,25 @@
             case VMMR0_DO_VMMR0_TERM:
             {
-                PVMCPU pVCpu = &pVM->aCpus[idCpu];
-
-                if (!pVCpu->vmm.s.CallRing3JmpBufR0.pvSavedStack)
-                    break;
-
-                /** @todo validate this EMT claim... GVM knows. */
-                VMMR0ENTRYEXARGS Args;
-                Args.pVM = pVM;
-                Args.idCpu = idCpu;
-                Args.enmOperation = enmOperation;
-                Args.pReq = pReq;
-                Args.u64Arg = u64Arg;
-                Args.pSession = pSession;
-                return vmmR0CallRing3SetJmpEx(&pVCpu->vmm.s.CallRing3JmpBufR0, vmmR0EntryExWrapper, &Args);
+                PGVMCPU pGVCpu = &pGVM->aCpus[idCpu];
+                PVMCPU  pVCpu  = &pVM->aCpus[idCpu];
+                RTNATIVETHREAD hNativeThread = RTThreadNativeSelf();
+                if (RT_LIKELY(   pGVCpu->hEMT           == hNativeThread
+                              && pVCpu->hNativeThreadR0 == hNativeThread))
+                {
+                    if (!pVCpu->vmm.s.CallRing3JmpBufR0.pvSavedStack)
+                        break;
+
+                    /** @todo validate this EMT claim... GVM knows. */
+                    VMMR0ENTRYEXARGS Args;
+                    Args.pGVM = pGVM;
+                    Args.pVM = pVM;
+                    Args.idCpu = idCpu;
+                    Args.enmOperation = enmOperation;
+                    Args.pReq = pReq;
+                    Args.u64Arg = u64Arg;
+                    Args.pSession = pSession;
+                    return vmmR0CallRing3SetJmpEx(&pVCpu->vmm.s.CallRing3JmpBufR0, vmmR0EntryExWrapper, &Args);
+                }
+                return VERR_VM_THREAD_NOT_EMT;
             }
 
@@ -2005,5 +2070,5 @@
         }
     }
-    return vmmR0EntryExWorker(pVM, idCpu, enmOperation, pReq, u64Arg, pSession);
+    return vmmR0EntryExWorker(pGVM, pVM, idCpu, enmOperation, pReq, u64Arg, pSession);
 }
 
