Index: /trunk/include/VBox/sup.h
===================================================================
--- /trunk/include/VBox/sup.h	(revision 71135)
+++ /trunk/include/VBox/sup.h	(revision 71136)
@@ -1927,4 +1927,58 @@
 SUPR0DECL(void) SUPR0BadContext(PSUPDRVSESSION pSession, const char *pszFile, uint32_t uLine, const char *pszExpr);
 
+/** Context structure returned by SUPR0IoCtlSetup for use with
+ * SUPR0IoCtlPerform and cleaned up by SUPR0IoCtlCleanup. */
+typedef struct SUPR0IOCTLCTX *PSUPR0IOCTLCTX;
+
+/**
+ * Sets up a I/O control context for the given handle.
+ *
+ * @returns VBox status code.
+ * @param   pSession        The support driver session.
+ * @param   hHandle         The handle.
+ * @param   fFlags          Flag, MBZ.
+ * @param   ppCtx           Where the context is returned.
+ */
+SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx);
+
+/**
+ * Cleans up the I/O control context when done.
+ *
+ * This won't close the handle passed to SUPR0IoCtlSetupForHandle.
+ *
+ * @returns VBox status code.
+ * @param   pCtx            The I/O control context to cleanup.
+ */
+SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx);
+
+/**
+ * Performs an I/O control operation.
+ *
+ * @returns VBox status code.
+ * @param   pCtx            The I/O control context returned by
+ *                          SUPR0IoCtlSetupForHandle.
+ * @param   uFunction       The I/O control function to perform.
+ * @param   pvInput         Pointer to input buffer (ring-0).
+ * @param   pvInputUser     Ring-3 pointer corresponding to @a pvInput.
+ * @param   cbInput         The amount of input.  If zero, both input pointers
+ *                          are expected to be NULL.
+ * @param   pvOutput        Pointer to output buffer (ring-0).
+ * @param   pvOutputUser    Ring-3 pointer corresponding to @a pvInput.
+ * @param   cbOutput        The amount of input.  If zero, both input pointers
+ *                          are expected to be NULL.
+ * @param   piNativeRc      Where to return the native return code.   When
+ *                          specified the VBox status code will typically be
+ *                          VINF_SUCCESS and the caller have to consult this for
+ *                          the actual result of the operation.  (This saves
+ *                          pointless status code conversion.)  Optional.
+ *
+ * @note    On unix systems where there is only one set of buffers possible,
+ *          pass the same pointers as input and output.
+ */
+SUPR0DECL(int)  SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction,
+                                  void *pvInput, RTR3PTR pvInputUser, size_t cbInput,
+                                  void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput,
+                                  int32_t *piNativeRc);
+
 /**
  * Writes to the debugger and/or kernel log.
Index: /trunk/include/VBox/vmm/gvm.h
===================================================================
--- /trunk/include/VBox/vmm/gvm.h	(revision 71135)
+++ /trunk/include/VBox/vmm/gvm.h	(revision 71136)
@@ -125,5 +125,5 @@
         struct NEMR0PERVM   s;
 # endif
-        uint8_t             padding[64];
+        uint8_t             padding[128];
     } nem;
 #endif
Index: /trunk/include/VBox/vmm/nem.h
===================================================================
--- /trunk/include/VBox/vmm/nem.h	(revision 71135)
+++ /trunk/include/VBox/vmm/nem.h	(revision 71136)
@@ -84,4 +84,5 @@
  * @{  */
 VMMR0_INT_DECL(int)  NEMR0InitVM(PGVM pGVM, PVM pVM);
+VMMR0_INT_DECL(int)  NEMR0InitVMPart2(PGVM pGVM, PVM pVM);
 VMMR0_INT_DECL(void) NEMR0CleanupVM(PGVM pGVM);
 VMMR0_INT_DECL(int)  NEMR0MapPages(PGVM pGVM, PVM pVM, VMCPUID idCpu);
Index: /trunk/include/VBox/vmm/vmm.h
===================================================================
--- /trunk/include/VBox/vmm/vmm.h	(revision 71135)
+++ /trunk/include/VBox/vmm/vmm.h	(revision 71136)
@@ -432,4 +432,6 @@
     /** Call NEMR0InitVM() (host specific). */
     VMMR0_DO_NEM_INIT_VM = 576,
+    /** Call NEMR0InitVMPart2() (host specific). */
+    VMMR0_DO_NEM_INIT_VM_PART_2,
     /** Call NEMR0MapPages() (host specific). */
     VMMR0_DO_NEM_MAP_PAGES,
Index: /trunk/include/iprt/nt/vid.h
===================================================================
--- /trunk/include/iprt/nt/vid.h	(revision 71135)
+++ /trunk/include/iprt/nt/vid.h	(revision 71136)
@@ -108,81 +108,4 @@
 typedef VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT const *PCVID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT;
 
-
-RT_C_DECLS_BEGIN
-
-/** Calling convention. */
-#ifndef WINAPI
-# define VIDAPI __stdcall
-#else
-# define VIDAPI WINAPI
-#endif
-
-/** Partition handle. */
-#ifndef WINAPI
-typedef void *VID_PARTITION_HANDLE;
-#else
-typedef HANDLE VID_PARTITION_HANDLE;
-#endif
-
-/**
- * Gets the partition ID.
- *
- * The partition ID is the numeric identifier used when making hypercalls to the
- * hypervisor.
- */
-DECLIMPORT(BOOL) VIDAPI VidGetHvPartitionId(VID_PARTITION_HANDLE hPartition, HV_PARTITION_ID *pidPartition);
-
-/**
- * Starts asynchronous execution of a virtual CPU.
- */
-DECLIMPORT(BOOL) VIDAPI VidStartVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu);
-
-/**
- * Stops the asynchronous execution of a virtual CPU.
- *
- * @retval ERROR_VID_STOP_PENDING if busy with intercept, check messages.
- */
-DECLIMPORT(BOOL) VIDAPI VidStopVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu);
-
-/**
- * WHvCreateVirtualProcessor boils down to a call to VidMessageSlotMap and
- * some internal WinHvPlatform state fiddling.
- *
- * Looks like it maps memory and returns the pointer to it.
- * VidMessageSlotHandleAndGetNext is later used to wait for the next message and
- * put (??) it into that memory mapping.
- *
- * @returns Success indicator (details in LastStatusValue and LastErrorValue).
- *
- * @param   hPartition  The partition handle.
- * @param   pOutput     Where to return the pointer to the message memory
- *                      mapping.  The CPU index is also returned here.
- * @param   iCpu        The CPU to wait-and-get messages for.
- */
-DECLIMPORT(BOOL) VIDAPI VidMessageSlotMap(VID_PARTITION_HANDLE hPartition, PVID_MAPPED_MESSAGE_SLOT pOutput, HV_VP_INDEX iCpu);
-
-/**
- * This is used by WHvRunVirtualProcessor to wait for the next exit msg.
- *
- * The message appears in the memory mapping returned by VidMessageSlotMap.
- *
- * @returns Success indicator (details only in LastErrorValue - LastStatusValue
- *          is not set).
- * @retval  STATUS_TIMEOUT for STATUS_TIMEOUT as well as STATUS_USER_APC and
- *          STATUS_ALERTED.
- *
- * @param   hPartition  The partition handle.
- * @param   iCpu        The CPU to wait-and-get messages for.
- * @param   fFlags      Flags. At least one of the two flags must be set:
- *                          - VID_MSHAGN_F_GET_NEXT_MESSAGE (bit 0)
- *                          - VID_MSHAGN_F_HANDLE_MESSAGE (bit 1)
- * @param   cMillies    The timeout, presumably in milliseconds.
- *
- * @todo    Would be awfully nice if someone at Microsoft could hit at the
- *          flags here.
- * @note
- */
-DECLIMPORT(BOOL) VIDAPI VidMessageSlotHandleAndGetNext(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu,
-                                                       uint32_t fFlags, uint32_t cMillies);
 /** @name VID_MSHAGN_F_GET_XXX - Flags for VidMessageSlotHandleAndGetNext
  * @{ */
@@ -196,4 +119,82 @@
 /** @} */
 
+
+#ifdef IN_RING3
+RT_C_DECLS_BEGIN
+
+/** Calling convention. */
+#ifndef WINAPI
+# define VIDAPI __stdcall
+#else
+# define VIDAPI WINAPI
+#endif
+
+/** Partition handle. */
+#ifndef WINAPI
+typedef void *VID_PARTITION_HANDLE;
+#else
+typedef HANDLE VID_PARTITION_HANDLE;
+#endif
+
+/**
+ * Gets the partition ID.
+ *
+ * The partition ID is the numeric identifier used when making hypercalls to the
+ * hypervisor.
+ */
+DECLIMPORT(BOOL) VIDAPI VidGetHvPartitionId(VID_PARTITION_HANDLE hPartition, HV_PARTITION_ID *pidPartition);
+
+/**
+ * Starts asynchronous execution of a virtual CPU.
+ */
+DECLIMPORT(BOOL) VIDAPI VidStartVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu);
+
+/**
+ * Stops the asynchronous execution of a virtual CPU.
+ *
+ * @retval ERROR_VID_STOP_PENDING if busy with intercept, check messages.
+ */
+DECLIMPORT(BOOL) VIDAPI VidStopVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu);
+
+/**
+ * WHvCreateVirtualProcessor boils down to a call to VidMessageSlotMap and
+ * some internal WinHvPlatform state fiddling.
+ *
+ * Looks like it maps memory and returns the pointer to it.
+ * VidMessageSlotHandleAndGetNext is later used to wait for the next message and
+ * put (??) it into that memory mapping.
+ *
+ * @returns Success indicator (details in LastStatusValue and LastErrorValue).
+ *
+ * @param   hPartition  The partition handle.
+ * @param   pOutput     Where to return the pointer to the message memory
+ *                      mapping.  The CPU index is also returned here.
+ * @param   iCpu        The CPU to wait-and-get messages for.
+ */
+DECLIMPORT(BOOL) VIDAPI VidMessageSlotMap(VID_PARTITION_HANDLE hPartition, PVID_MAPPED_MESSAGE_SLOT pOutput, HV_VP_INDEX iCpu);
+
+/**
+ * This is used by WHvRunVirtualProcessor to wait for the next exit msg.
+ *
+ * The message appears in the memory mapping returned by VidMessageSlotMap.
+ *
+ * @returns Success indicator (details only in LastErrorValue - LastStatusValue
+ *          is not set).
+ * @retval  STATUS_TIMEOUT for STATUS_TIMEOUT as well as STATUS_USER_APC and
+ *          STATUS_ALERTED.
+ *
+ * @param   hPartition  The partition handle.
+ * @param   iCpu        The CPU to wait-and-get messages for.
+ * @param   fFlags      Flags. At least one of the two flags must be set:
+ *                          - VID_MSHAGN_F_GET_NEXT_MESSAGE (bit 0)
+ *                          - VID_MSHAGN_F_HANDLE_MESSAGE (bit 1)
+ * @param   cMillies    The timeout, presumably in milliseconds.
+ *
+ * @todo    Would be awfully nice if someone at Microsoft could hit at the
+ *          flags here.
+ * @note
+ */
+DECLIMPORT(BOOL) VIDAPI VidMessageSlotHandleAndGetNext(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu,
+                                                       uint32_t fFlags, uint32_t cMillies);
 /**
  * Gets the processor running status.
@@ -219,4 +220,5 @@
 
 RT_C_DECLS_END
+#endif /* IN_RING3 */
 
 #endif
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp	(revision 71135)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp	(revision 71136)
@@ -231,4 +231,9 @@
     { "SUPR0TracerUmodProbeFire",               (void *)(uintptr_t)SUPR0TracerUmodProbeFire },
     { "SUPR0UnlockMem",                         (void *)(uintptr_t)SUPR0UnlockMem },
+#ifdef RT_OS_WINDOWS
+    { "SUPR0IoCtlSetupForHandle",               (void *)(uintptr_t)SUPR0IoCtlSetupForHandle },  /* only-windows */
+    { "SUPR0IoCtlPerform",                      (void *)(uintptr_t)SUPR0IoCtlPerform },         /* only-windows */
+    { "SUPR0IoCtlCleanup",                      (void *)(uintptr_t)SUPR0IoCtlCleanup },         /* only-windows */
+#endif
     { "SUPSemEventClose",                       (void *)(uintptr_t)SUPSemEventClose },
     { "SUPSemEventCreate",                      (void *)(uintptr_t)SUPSemEventCreate },
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h	(revision 71135)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h	(revision 71136)
@@ -214,5 +214,5 @@
  * @remarks 0x002a0000 is used by 5.1. The next version number must be 0x002b0000.
  */
-#define SUPDRV_IOC_VERSION                              0x00290002
+#define SUPDRV_IOC_VERSION                              0x00290003
 
 /** SUP_IOCTL_COOKIE. */
Index: /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 71135)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h	(revision 71136)
@@ -455,4 +455,30 @@
     uint32_t volatile               cUsage;
 } SUPDRVUSAGE, *PSUPDRVUSAGE;
+
+
+/**
+ * I/O control context.
+ */
+typedef struct SUPR0IOCTLCTX
+{
+    /** Magic value (SUPR0IOCTLCTX_MAGIC). */
+    uint32_t                u32Magic;
+    /** Reference counter. */
+    uint32_t volatile       cRefs;
+#ifdef RT_OS_WINDOWS
+# ifndef SUPDRV_AGNOSTIC
+    /** The file object, referenced. */
+    PFILE_OBJECT            pFileObject;
+    /** The device object, not referenced. */
+    PDEVICE_OBJECT          pDeviceObject;
+    /** Pointer to fast I/O routine if available. */
+    FAST_IO_DEVICE_CONTROL *pfnFastIoDeviceControl;
+# else
+    void                   *apvPadding[3];
+# endif
+#endif
+} SUPR0IOCTLCTX;
+/** Magic value for SUPR0IOCTLCTX (Ahmad Jamal). */
+#define SUPR0IOCTLCTX_MAGIC     UINT32_C(0x19300702)
 
 
Index: /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp	(revision 71135)
+++ /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp	(revision 71136)
@@ -277,5 +277,5 @@
         CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
         const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00290000
-                                   ? 0x00290002
+                                   ? 0x00290003
                                    : SUPDRV_IOC_VERSION & 0xffff0000;
         CookieReq.u.In.u32MinVersion = uMinVersion;
Index: /trunk/src/VBox/HostDrivers/Support/SUPLibLdr.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPLibLdr.cpp	(revision 71135)
+++ /trunk/src/VBox/HostDrivers/Support/SUPLibLdr.cpp	(revision 71136)
@@ -167,9 +167,16 @@
      * Only SUPR0 and VMMR0.r0
      */
-    if (    pszModule
-        &&  *pszModule
-        &&  strcmp(pszModule, "VBoxDrv.sys")
-        &&  strcmp(pszModule, "VMMR0.r0"))
-    {
+    if (   pszModule
+        && *pszModule
+        && strcmp(pszModule, "VBoxDrv.sys")
+        && strcmp(pszModule, "VMMR0.r0"))
+    {
+#if defined(RT_OS_WINDOWS) && 0 /* Useful for VMMR0 hacking, not for production use.  See also SUPDrv-win.cpp */
+        if (strcmp(pszModule, "ntoskrnl.exe") == 0)
+        {
+            *pValue = 42; /* Non-zero so ring-0 can find the end of the IAT and exclude it when comparing. */
+            return VINF_SUCCESS;
+        }
+#endif
         AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitive)\n", pArgs->pszModule, pszModule));
         return RTErrInfoSetF(pArgs->pErrInfo, VERR_SYMBOL_NOT_FOUND,
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp	(revision 71135)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp	(revision 71136)
@@ -2131,4 +2131,36 @@
 }
 
+/** Image compare exclusion regions. */
+typedef struct SUPDRVNTEXCLREGIONS
+{
+    /** Number of regions.   */
+    uint32_t        cRegions;
+    /** The regions. */
+    struct SUPDRVNTEXCLREGION
+    {
+        uint32_t    uRva;
+        uint32_t    cb;
+    }               aRegions[16];
+} SUPDRVNTEXCLREGIONS;
+
+/**
+ * Adds an exclusion region to the collection.
+ */
+static bool supdrvNtAddExclRegion(SUPDRVNTEXCLREGIONS *pRegions, uint32_t uRvaRegion, uint32_t cbRegion)
+{
+    uint32_t const cRegions = pRegions->cRegions;
+    AssertReturn(cRegions + 1 <= RT_ELEMENTS(pRegions->aRegions), false);
+    uint32_t i = 0;
+    for (; i < cRegions; i++)
+        if (uRvaRegion < pRegions->aRegions[i].uRva)
+            break;
+    if (i != cRegions)
+        memmove(&pRegions->aRegions[i + 1], &pRegions->aRegions[i], (cRegions - i) * sizeof(pRegions->aRegions[0]));
+    pRegions->aRegions[i].uRva = uRvaRegion;
+    pRegions->aRegions[i].cb   = cbRegion;
+    pRegions->cRegions++;
+    return true;
+}
+
 
 int  VBOXCALL   supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
@@ -2184,10 +2216,6 @@
             )
         {
-            struct MyRegion
-            {
-                uint32_t uRva;
-                uint32_t cb;
-            }           aExcludeRgns[16];
-            unsigned    cExcludeRgns = 0;
+            SUPDRVNTEXCLREGIONS ExcludeRegions;
+            ExcludeRegions.cRegions = 0;
 
             /* ImageBase: */
@@ -2195,9 +2223,5 @@
                 && (   pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
                     || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage) )
-            {
-                aExcludeRgns[cExcludeRgns].uRva = offImageBase;
-                aExcludeRgns[cExcludeRgns].cb   = cbImageBase;
-                cExcludeRgns++;
-            }
+                supdrvNtAddExclRegion(&ExcludeRegions, offImageBase, cbImageBase);
 
             /* Imports: */
@@ -2208,10 +2232,10 @@
             IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps);
             while (   cImpsLeft-- > 0
-                   && cExcludeRgns < RT_ELEMENTS(aExcludeRgns))
+                   && ExcludeRegions.cRegions < RT_ELEMENTS(ExcludeRegions.aRegions))
             {
                 uint32_t uRvaThunk = pImp->OriginalFirstThunk;
-                if (    uRvaThunk >  sizeof(IMAGE_NT_HEADERS)
-                    &&  uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
-                    &&  uRvaThunk != pImp->FirstThunk)
+                if (   uRvaThunk >  sizeof(IMAGE_NT_HEADERS)
+                    && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
+                    && uRvaThunk != pImp->FirstThunk)
                 {
                     /* Find the size of the thunk table. */
@@ -2221,16 +2245,28 @@
                     while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
                         cThunks++;
-
-                    /* Ordered table insert. */
-                    unsigned i = 0;
-                    for (; i < cExcludeRgns; i++)
-                        if (uRvaThunk < aExcludeRgns[i].uRva)
-                            break;
-                    if (i != cExcludeRgns)
-                        memmove(&aExcludeRgns[i + 1], &aExcludeRgns[i], (cExcludeRgns - i) * sizeof(aExcludeRgns[0]));
-                    aExcludeRgns[i].uRva = uRvaThunk;
-                    aExcludeRgns[i].cb   = cThunks * sizeof(IMAGE_THUNK_DATA);
-                    cExcludeRgns++;
+                    supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
                 }
+
+#if 0 /* Useful for VMMR0 hacking, not for production use.  See also SUPDrvLdr.cpp. */
+                /* Exclude the other thunk table if ntoskrnl.exe. */
+                uint32_t uRvaName = pImp->Name;
+                if (   uRvaName > sizeof(IMAGE_NT_HEADERS)
+                    && uRvaName < pImage->cbImageBits - sizeof("ntoskrnl.exe")
+                    && memcmp(&pbImageBits[uRvaName], RT_STR_TUPLE("ntoskrnl.exe")) == 0)
+                {
+                    uRvaThunk = pImp->FirstThunk;
+                    if (   uRvaThunk >  sizeof(IMAGE_NT_HEADERS)
+                        && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA))
+                    {
+                        /* Find the size of the thunk table. */
+                        IMAGE_THUNK_DATA const *paThunk    = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
+                        uint32_t                cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
+                        uint32_t                cThunks    = 0;
+                        while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
+                            cThunks++;
+                        supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
+                    }
+                }
+#endif
 
                 /* advance */
@@ -2243,9 +2279,9 @@
             int         iDiff    = 0;
             uint32_t    uRvaNext = 0;
-            for (unsigned i = 0; !iDiff && i < cExcludeRgns; i++)
-            {
-                if (uRvaNext < aExcludeRgns[i].uRva)
-                    iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, aExcludeRgns[i].uRva - uRvaNext, pReq);
-                uRvaNext = aExcludeRgns[i].uRva + aExcludeRgns[i].cb;
+            for (unsigned i = 0; !iDiff && i < ExcludeRegions.cRegions; i++)
+            {
+                if (uRvaNext < ExcludeRegions.aRegions[i].uRva)
+                    iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, ExcludeRegions.aRegions[i].uRva - uRvaNext, pReq);
+                uRvaNext = ExcludeRegions.aRegions[i].uRva + ExcludeRegions.aRegions[i].cb;
             }
             if (!iDiff && uRvaNext < pImage->cbImageBits)
@@ -2558,4 +2594,228 @@
 {
     return 0;
+}
+
+
+SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx)
+{
+    /*
+     * Validate input.
+     */
+    AssertPtrReturn(ppCtx, VERR_INVALID_POINTER);
+    *ppCtx = NULL;
+    AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
+    AssertReturn(!fFlags, VERR_INVALID_FLAGS);
+
+    /*
+     * Turn the partition handle into a file object and related device object
+     * so that we can issue direct I/O control calls to the pair later.
+     */
+    PFILE_OBJECT pFileObject = NULL;
+    OBJECT_HANDLE_INFORMATION HandleInfo = { 0, 0 };
+    NTSTATUS rcNt = ObReferenceObjectByHandle((HANDLE)hHandle, /*FILE_WRITE_DATA*/0, *IoFileObjectType,
+                                              UserMode, (void **)&pFileObject, &HandleInfo);
+    if (!NT_SUCCESS(rcNt))
+        return RTErrConvertFromNtStatus(rcNt);
+    AssertPtrReturn(pFileObject, VERR_INTERNAL_ERROR_3);
+
+    PDEVICE_OBJECT pDevObject = IoGetRelatedDeviceObject(pFileObject);
+    AssertMsgReturnStmt(RT_VALID_PTR(pDevObject), ("pDevObject=%p\n", pDevObject),
+                        ObDereferenceObject(pFileObject), VERR_INTERNAL_ERROR_2);
+
+    /*
+     * Allocate a context structure and fill it in.
+     */
+    PSUPR0IOCTLCTX pCtx = (PSUPR0IOCTLCTX)RTMemAllocZ(sizeof(*pCtx));
+    if (pCtx)
+    {
+        pCtx->u32Magic      = SUPR0IOCTLCTX_MAGIC;
+        pCtx->cRefs         = 1;
+        pCtx->pFileObject   = pFileObject;
+        pCtx->pDeviceObject = pDevObject;
+
+        PDRIVER_OBJECT pDrvObject = pDevObject->DriverObject;
+        if (   RT_VALID_PTR(pDrvObject->FastIoDispatch)
+            && RT_VALID_PTR(pDrvObject->FastIoDispatch->FastIoDeviceControl))
+            pCtx->pfnFastIoDeviceControl = pDrvObject->FastIoDispatch->FastIoDeviceControl;
+        else
+            pCtx->pfnFastIoDeviceControl = NULL;
+        *ppCtx = pCtx;
+        return VINF_SUCCESS;
+    }
+
+    ObDereferenceObject(pFileObject);
+    return VERR_NO_MEMORY;
+}
+
+
+/**
+ * I/O control destructor for NT.
+ *
+ * @param   pCtx    The context to destroy.
+ */
+static void supdrvNtIoCtlContextDestroy(PSUPR0IOCTLCTX pCtx)
+{
+    PFILE_OBJECT pFileObject = pCtx->pFileObject;
+    pCtx->pfnFastIoDeviceControl = NULL;
+    pCtx->pFileObject            = NULL;
+    pCtx->pDeviceObject          = NULL;
+    ASMAtomicWriteU32(&pCtx->u32Magic, ~SUPR0IOCTLCTX_MAGIC);
+
+    if (RT_VALID_PTR(pFileObject))
+        ObDereferenceObject(pFileObject);
+    RTMemFree(pCtx);
+}
+
+
+SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx)
+{
+    if (pCtx != NULL)
+    {
+        AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+        AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
+
+        uint32_t cRefs = ASMAtomicDecU32(&pCtx->cRefs);
+        Assert(cRefs < _4K);
+        if (cRefs == 0)
+            supdrvNtIoCtlContextDestroy(pCtx);
+    }
+    return VINF_SUCCESS;
+}
+
+
+SUPR0DECL(int)  SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction,
+                                  void *pvInput, RTR3PTR pvInputUser, size_t cbInput,
+                                  void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput,
+                                  int32_t *piNativeRc)
+{
+    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+    AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
+
+    /* Reference the context. */
+    uint32_t cRefs = ASMAtomicIncU32(&pCtx->cRefs);
+    Assert(cRefs > 1 && cRefs < _4K);
+
+    /*
+     * Try fast I/O control path first.
+     */
+    IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+    if (pCtx->pfnFastIoDeviceControl)
+    {
+        /* Must pass user addresses here as that's what's being expected. */
+        BOOLEAN fHandled = pCtx->pfnFastIoDeviceControl(pCtx->pFileObject,
+                                                        TRUE /*Wait*/,
+                                                        (void *)pvInputUser,  (ULONG)cbInput,
+                                                        (void *)pvOutputUser, (ULONG)cbOutput,
+                                                        uFunction,
+                                                        &Ios,
+                                                        pCtx->pDeviceObject);
+        if (fHandled)
+        {
+            /* Relase the context. */
+            cRefs = ASMAtomicDecU32(&pCtx->cRefs);
+            Assert(cRefs < _4K);
+            if (cRefs == 0)
+                supdrvNtIoCtlContextDestroy(pCtx);
+
+            /* Set/convert status and return. */
+            if (piNativeRc)
+            {
+                *piNativeRc = Ios.Status;
+                return VINF_SUCCESS;
+            }
+            if (NT_SUCCESS(Ios.Status))
+                return VINF_SUCCESS;
+            return RTErrConvertFromNtStatus(Ios.Status);
+        }
+
+        /*
+         * Fall back on IRP if not handled.
+         *
+         * Note! Perhaps we should rather fail, because VID.SYS will crash getting
+         *       the partition ID with the code below.  It tries to zero the output
+         *       buffer as if it were as system buffer...
+         */
+        RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
+    }
+
+    /*
+     * For directly accessed buffers we must supply user mode addresses or
+     * we'll fail ProbeForWrite validation.
+     */
+    switch (uFunction & 3)
+    {
+        case METHOD_BUFFERED:
+            /* For buffered accesses, we can supply kernel buffers. */
+            break;
+
+        case METHOD_IN_DIRECT:
+            pvInput  = (void *)pvInputUser;
+            break;
+
+        case METHOD_NEITHER:
+            pvInput  = (void *)pvInputUser;
+            RT_FALL_THRU();
+
+        case METHOD_OUT_DIRECT:
+            pvOutput = (void *)pvOutputUser;
+            break;
+    }
+
+    /*
+     * Build the request.
+     */
+    int rc;
+    KEVENT Event;
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    PIRP pIrp = IoBuildDeviceIoControlRequest(uFunction, pCtx->pDeviceObject,
+                                              pvInput, (ULONG)cbInput, pvOutput, (ULONG)cbOutput,
+                                              FALSE /* InternalDeviceControl */, &Event, &Ios);
+    if (pIrp)
+    {
+        IoGetNextIrpStackLocation(pIrp)->FileObject = pCtx->pFileObject;
+
+        /*
+         * Make the call.
+         */
+        NTSTATUS rcNt = IoCallDriver(pCtx->pDeviceObject, pIrp);
+        if (rcNt == STATUS_PENDING)
+        {
+            rcNt = KeWaitForSingleObject(&Event,            /* Object */
+                                         Executive,         /* WaitReason */
+                                         KernelMode,        /* WaitMode */
+                                         FALSE,             /* Alertable */
+                                         NULL);             /* TimeOut */
+            AssertMsg(rcNt == STATUS_SUCCESS, ("rcNt=%#x\n", rcNt));
+            rcNt = Ios.Status;
+        }
+        else if (NT_SUCCESS(rcNt) && Ios.Status != STATUS_SUCCESS)
+            rcNt = Ios.Status;
+
+        /* Set/convert return code. */
+        if (piNativeRc)
+        {
+            *piNativeRc = rcNt;
+            rc = VINF_SUCCESS;
+        }
+        else if (NT_SUCCESS(rcNt))
+            rc = VINF_SUCCESS;
+        else
+            rc = RTErrConvertFromNtStatus(rcNt);
+    }
+    else
+    {
+        if (piNativeRc)
+            *piNativeRc = STATUS_NO_MEMORY;
+        rc = VERR_NO_MEMORY;
+    }
+
+    /* Relase the context. */
+    cRefs = ASMAtomicDecU32(&pCtx->cRefs);
+    Assert(cRefs < _4K);
+    if (cRefs == 0)
+        supdrvNtIoCtlContextDestroy(pCtx);
+
+    return rc;
 }
 
Index: /trunk/src/VBox/VMM/Makefile.kmk
===================================================================
--- /trunk/src/VBox/VMM/Makefile.kmk	(revision 71135)
+++ /trunk/src/VBox/VMM/Makefile.kmk	(revision 71136)
@@ -830,9 +830,4 @@
  	VMMR0/VMMR0JmpA-x86.asm
 
- if1of ($(USERNAME),bird) # experimental.
-  VMMR0_SOURCES.win.amd64 += VMMR0/NEMR0Native-win.cpp
-  VMMR0_DEFS.win.amd64    += VBOX_WITH_NATIVE_NEM VBOX_WITH_NEM_R0
- endif
-
  VMMR0_LIBS = \
  	$(PATH_STAGE_LIB)/ServicesR0$(VBOX_SUFF_LIB) \
@@ -842,4 +837,9 @@
   VMMR0_LIBS += \
   	$(PATH_STAGE_LIB)/SUPR0$(VBOX_SUFF_LIB)
+ endif
+ if1of ($(USERNAME),bird) # experimental.
+  VMMR0_SOURCES.win.amd64 += VMMR0/NEMR0Native-win.cpp
+  VMMR0_DEFS.win.amd64    += VBOX_WITH_NATIVE_NEM VBOX_WITH_NEM_R0
+  VMMR0/NEMR0Native-win.cpp_SDKS.win = ReorderCompilerIncs $(VBOX_WINDDK) $(VBOX_WINPSDK)INCS
  endif
 
Index: /trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp	(revision 71135)
+++ /trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp	(revision 71136)
@@ -21,5 +21,7 @@
 *********************************************************************************************************************************/
 #define LOG_GROUP LOG_GROUP_NEM
+#include <iprt/nt/nt.h>
 #include <iprt/nt/hyperv.h>
+#include <iprt/nt/vid.h>
 
 #include <VBox/vmm/nem.h>
@@ -50,5 +52,5 @@
 *   Global Variables                                                                                                             *
 *********************************************************************************************************************************/
-static uint64_t (* g_pfnHvlInvokeHypercall)(uint64_t uCallInfo, uint64_t HCPhysInput, uint64_t HCPhysOutput);
+static uint64_t (*g_pfnHvlInvokeHypercall)(uint64_t uCallInfo, uint64_t HCPhysInput, uint64_t HCPhysOutput);
 
 
@@ -64,4 +66,7 @@
 VMMR0_INT_DECL(int) NEMR0InitVM(PGVM pGVM, PVM pVM)
 {
+    AssertCompile(sizeof(pGVM->nem.s) <= sizeof(pGVM->nem.padding));
+    AssertCompile(sizeof(pGVM->aCpus[0].nem.s) <= sizeof(pGVM->aCpus[0].nem.padding));
+
     int rc = GVMMR0ValidateGVMandVMandEMT(pGVM, pVM, 0);
     AssertRCReturn(rc, rc);
@@ -112,7 +117,4 @@
              * So far, so good.
              */
-            /** @todo would be good if we could establish the partition ID ourselves. */
-            /** @todo this is too EARLY!   */
-            pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;
             return rc;
         }
@@ -122,4 +124,121 @@
 
     RT_NOREF(pGVM, pVM);
+    return rc;
+}
+
+
+/**
+ * Perform an I/O control operation on the partition handle (VID.SYS).
+ *
+ * @returns NT status code.
+ * @param   pGVM            The ring-0 VM structure.
+ * @param   uFunction       The function to perform.
+ * @param   pvInput         The input buffer.  This must point within the VM
+ *                          structure so we can easily convert to a ring-3
+ *                          pointer if necessary.
+ * @param   cbInput         The size of the input.  @a pvInput must be NULL when
+ *                          zero.
+ * @param   pvOutput        The output buffer.  This must also point within the
+ *                          VM structure for ring-3 pointer magic.
+ * @param   cbOutput        The size of the output.  @a pvOutput must be NULL
+ *                          when zero.
+ */
+DECLINLINE(NTSTATUS) nemR0NtPerformIoControl(PGVM pGVM, uint32_t uFunction, void *pvInput, uint32_t cbInput,
+                                             void *pvOutput, uint32_t cbOutput)
+{
+#ifdef RT_STRICT
+    /*
+     * Input and output parameters are part of the VM CPU structure.
+     */
+    PVM          pVM  = pGVM->pVM;
+    size_t const cbVM = RT_UOFFSETOF(VM, aCpus[pGVM->cCpus]);
+    if (pvInput)
+        AssertReturn(((uintptr_t)pvInput + cbInput) - (uintptr_t)pVM <= cbVM, VERR_INVALID_PARAMETER);
+    if (pvOutput)
+        AssertReturn(((uintptr_t)pvOutput + cbOutput) - (uintptr_t)pVM <= cbVM, VERR_INVALID_PARAMETER);
+#endif
+
+    int32_t rcNt = STATUS_UNSUCCESSFUL;
+    int rc = SUPR0IoCtlPerform(pGVM->nem.s.pIoCtlCtx, uFunction,
+                               pvInput,
+                               pvInput  ? (uintptr_t)pvInput  + pGVM->nem.s.offRing3ConversionDelta : NIL_RTR3PTR,
+                               cbInput,
+                               pvOutput,
+                               pvOutput ? (uintptr_t)pvOutput + pGVM->nem.s.offRing3ConversionDelta : NIL_RTR3PTR,
+                               cbOutput,
+                               &rcNt);
+    if (RT_SUCCESS(rc) || !NT_SUCCESS((NTSTATUS)rcNt))
+        return (NTSTATUS)rcNt;
+    return STATUS_UNSUCCESSFUL;
+}
+
+
+/**
+ * 2nd part of the initialization, after we've got a partition handle.
+ *
+ * @returns VBox status code.
+ * @param   pGVM            The ring-0 VM handle.
+ * @param   pVM             The cross context VM handle.
+ * @thread  EMT(0)
+ */
+VMMR0_INT_DECL(int) NEMR0InitVMPart2(PGVM pGVM, PVM pVM)
+{
+    int rc = GVMMR0ValidateGVMandVMandEMT(pGVM, pVM, 0);
+    AssertRCReturn(rc, rc);
+    SUPR0Printf("NEMR0InitVMPart2\n"); LogRel(("2: NEMR0InitVMPart2\n"));
+
+    /*
+     * Copy and validate the I/O control information from ring-3.
+     */
+    NEMWINIOCTL Copy = pVM->nem.s.IoCtlGetHvPartitionId;
+    AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.cbInput == 0, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.cbOutput == sizeof(HV_PARTITION_ID), VERR_NEM_INIT_FAILED);
+    pGVM->nem.s.IoCtlGetHvPartitionId = Copy;
+
+    Copy = pVM->nem.s.IoCtlStartVirtualProcessor;
+    AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.cbInput == sizeof(HV_VP_INDEX), VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.cbOutput == 0, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlGetHvPartitionId.uFunction, VERR_NEM_INIT_FAILED);
+    pGVM->nem.s.IoCtlStartVirtualProcessor = Copy;
+
+    Copy = pVM->nem.s.IoCtlStopVirtualProcessor;
+    AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.cbInput == sizeof(HV_VP_INDEX), VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.cbOutput == 0, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlGetHvPartitionId.uFunction, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlStartVirtualProcessor.uFunction, VERR_NEM_INIT_FAILED);
+    pGVM->nem.s.IoCtlStopVirtualProcessor = Copy;
+
+    Copy = pVM->nem.s.IoCtlMessageSlotHandleAndGetNext;
+    AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.cbInput == sizeof(VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT), VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.cbOutput == 0, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlGetHvPartitionId.uFunction, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlStartVirtualProcessor.uFunction, VERR_NEM_INIT_FAILED);
+    AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlStopVirtualProcessor.uFunction, VERR_NEM_INIT_FAILED);
+    pGVM->nem.s.IoCtlMessageSlotHandleAndGetNext = Copy;
+
+    /*
+     * Setup of an I/O control context for the partition handle for later use.
+     */
+    rc = SUPR0IoCtlSetupForHandle(pGVM->pSession, pVM->nem.s.hPartitionDevice, 0, &pGVM->nem.s.pIoCtlCtx);
+    AssertLogRelRCReturn(rc, rc);
+    pGVM->nem.s.offRing3ConversionDelta = (uintptr_t)pVM->pVMR3 - (uintptr_t)pGVM->pVM;
+
+    /*
+     * Get the partition ID.
+     */
+    PVMCPU pVCpu = &pGVM->pVM->aCpus[0];
+    NTSTATUS rcNt = nemR0NtPerformIoControl(pGVM, pGVM->nem.s.IoCtlGetHvPartitionId.uFunction, NULL, 0,
+                                            &pVCpu->nem.s.uIoCtlBuf.idPartition, sizeof(pVCpu->nem.s.uIoCtlBuf.idPartition));
+    AssertLogRelMsgReturn(NT_SUCCESS(rcNt), ("IoCtlGetHvPartitionId failed: %#x\n", rcNt), VERR_NEM_INIT_FAILED);
+    pGVM->nem.s.idHvPartition = pVCpu->nem.s.uIoCtlBuf.idPartition;
+    AssertLogRelMsgReturn(pGVM->nem.s.idHvPartition == pVM->nem.s.idHvPartition,
+                          ("idHvPartition mismatch: r0=%#RX64, r3=%#RX64\n", pGVM->nem.s.idHvPartition, pVM->nem.s.idHvPartition),
+                          VERR_NEM_INIT_FAILED);
+
+
     return rc;
 }
@@ -137,4 +256,12 @@
 {
     pGVM->nem.s.idHvPartition = HV_PARTITION_ID_INVALID;
+
+    /* Clean up I/O control context. */
+    if (pGVM->nem.s.pIoCtlCtx)
+    {
+        int rc = SUPR0IoCtlCleanup(pGVM->nem.s.pIoCtlCtx);
+        AssertRC(rc);
+        pGVM->nem.s.pIoCtlCtx = NULL;
+    }
 
     /* Free the hypercall pages. */
@@ -195,8 +322,4 @@
             AssertReturn(GCPhysSrc < _1E, VERR_OUT_OF_RANGE);
         }
-
-        /** @todo fix pGVM->nem.s.idHvPartition init. */
-        if (pGVM->nem.s.idHvPartition == 0)
-            pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;
 
         /*
@@ -291,8 +414,4 @@
         AssertMsgReturn(!(GCPhys & X86_PAGE_OFFSET_MASK), ("%RGp\n", GCPhys), VERR_OUT_OF_RANGE);
         AssertReturn(GCPhys < _1E, VERR_OUT_OF_RANGE);
-
-        /** @todo fix pGVM->nem.s.idHvPartition init. */
-        if (pGVM->nem.s.idHvPartition == 0)
-            pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;
 
         /*
@@ -732,8 +851,4 @@
         AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
 
-        /** @todo fix pGVM->nem.s.idHvPartition init. */
-        if (pGVM->nem.s.idHvPartition == 0)
-            pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;
-
         /*
          * Call worker.
@@ -1146,8 +1261,4 @@
         AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
 
-        /** @todo fix pGVM->nem.s.idHvPartition init. */
-        if (pGVM->nem.s.idHvPartition == 0)
-            pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;
-
         /*
          * Call worker.
Index: /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 71135)
+++ /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 71136)
@@ -1975,4 +1975,11 @@
             break;
 
+        case VMMR0_DO_NEM_INIT_VM_PART_2:
+            if (u64Arg || pReqHdr || idCpu != 0)
+                return VERR_INVALID_PARAMETER;
+            rc = NEMR0InitVMPart2(pGVM, pVM);
+            VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
+            break;
+
         case VMMR0_DO_NEM_MAP_PAGES:
             if (u64Arg || pReqHdr || idCpu == NIL_VMCPUID)
Index: /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 71135)
+++ /trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp	(revision 71136)
@@ -1269,6 +1269,14 @@
     pVM->nem.s.fCreatedEmts = true;
 
-    LogRel(("NEM: Successfully set up partition (device handle %p, partition ID %#llx)\n", hPartitionDevice, idHvPartition));
-    return VINF_SUCCESS;
+    /*
+     * Do some more ring-0 initialization now that we've got the partition handle.
+     */
+    int rc = VMMR3CallR0Emt(pVM, &pVM->aCpus[0], VMMR0_DO_NEM_INIT_VM_PART_2, 0, NULL);
+    if (RT_SUCCESS(rc))
+    {
+        LogRel(("NEM: Successfully set up partition (device handle %p, partition ID %#llx)\n", hPartitionDevice, idHvPartition));
+        return VINF_SUCCESS;
+    }
+    return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Call to NEMR0InitVMPart2 failed: %Rrc", rc);
 }
 
@@ -1342,5 +1350,4 @@
     }
 }
-
 
 #ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
@@ -2295,5 +2302,5 @@
                 /* ACK the stop message. */
                 fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
-                                                                 VID_MSHAGN_F_HANDLE_MESSAGE, 5000);
+                                                            VID_MSHAGN_F_HANDLE_MESSAGE, 5000);
                 AssertLogRelMsg(fWait, ("dwErr=%u (%#x) rcNt=%#x\n", RTNtLastErrorValue(), RTNtLastErrorValue(), RTNtLastStatusValue()));
 
Index: /trunk/src/VBox/VMM/include/NEMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/NEMInternal.h	(revision 71135)
+++ /trunk/src/VBox/VMM/include/NEMInternal.h	(revision 71136)
@@ -173,4 +173,10 @@
         }                       UnmapPages;
     } Hypercall;
+    /** I/O control buffer, we always use this for I/O controls. */
+    union
+    {
+        uint8_t                 ab[64];
+        HV_PARTITION_ID         idPartition;
+    } uIoCtlBuf;
 #endif
 } NEMCPU;
@@ -232,4 +238,17 @@
     /** The partition ID. */
     uint64_t                    idHvPartition;
+    /** I/O control context. */
+    PSUPR0IOCTLCTX              pIoCtlCtx;
+    /** Delta to add to convert a ring-0 pointer to a ring-3 one.   */
+    uintptr_t                   offRing3ConversionDelta;
+    /** Info about the VidGetHvPartitionId I/O control interface. */
+    NEMWINIOCTL                 IoCtlGetHvPartitionId;
+    /** Info about the VidStartVirtualProcessor I/O control interface. */
+    NEMWINIOCTL                 IoCtlStartVirtualProcessor;
+    /** Info about the VidStopVirtualProcessor I/O control interface. */
+    NEMWINIOCTL                 IoCtlStopVirtualProcessor;
+    /** Info about the VidStopVirtualProcessor I/O control interface. */
+    NEMWINIOCTL                 IoCtlMessageSlotHandleAndGetNext;
+
 # else
     uint32_t                    uDummy;
