Index: /trunk/include/VBox/vmm/hm.h
===================================================================
--- /trunk/include/VBox/vmm/hm.h	(revision 79344)
+++ /trunk/include/VBox/vmm/hm.h	(revision 79345)
@@ -182,6 +182,7 @@
 VMM_INT_DECL(bool)              HMIsNestedPagingActive(PVM pVM);
 VMM_INT_DECL(bool)              HMIsMsrBitmapActive(PVM pVM);
-# ifdef VBOX_WITH_NESTED_HWVIRT_SVM
-VMM_INT_DECL(void)              HMNotifyVmxNstGstVmexit(PVMCPU pVCpu, PCPUMCTX pCtx);
+# ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+VMM_INT_DECL(void)              HMNotifyVmxNstGstVmexit(PVMCPU pVCpu);
+VMM_INT_DECL(void)              HMNotifyVmxNstGstCurrentVmcsChanged(PVMCPU pVCpu);
 # endif
 /** @} */
Index: /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 79344)
+++ /trunk/src/VBox/VMM/VMMAll/HMVMXAll.cpp	(revision 79345)
@@ -1232,12 +1232,9 @@
  *
  * @param   pVCpu   The cross context virtual CPU structure.
- * @param   pCtx    Pointer to the guest-CPU context.
  *
  * @remarks Can be called from ring-0 as well as ring-3.
  */
-VMM_INT_DECL(void) HMNotifyVmxNstGstVmexit(PVMCPU pVCpu, PCPUMCTX pCtx)
-{
-    NOREF(pCtx);
-
+VMM_INT_DECL(void) HMNotifyVmxNstGstVmexit(PVMCPU pVCpu)
+{
     /*
      * Transitions to ring-3 flag a full CPU-state change except if we transition to ring-3
@@ -1249,7 +1246,8 @@
      * for the nested-guest from ring-3.
      *
-     * Flag reloading of just the guest-CPU state is -not- sufficient since HM also needs
-     * to reload related state with VM-entry/VM-exit controls and so on. Flag reloading
-     * the entire state.
+     * Signalling reload of just the guest-CPU state that changed with the VM-exit is -not-
+     * sufficient since HM also needs to reload state related to VM-entry/VM-exit controls
+     * etc. So signal reloading of the entire state. It does not seem worth making this any
+     * more fine grained at the moment.
      */
     CPUM_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_ALL);
@@ -1258,8 +1256,34 @@
     /*
      * Make sure we need to merge the guest VMCS controls with the nested-guest
-     * VMCS controls on the next nested-guest VM entry.
+     * VMCS controls on the next nested-guest VM-entry.
      */
     pVCpu->hm.s.vmx.fMergedNstGstCtls = false;
 }
+
+
+/**
+ * Notification callback for when the guest hypervisor's current VMCS is loaded or
+ * changed outside VMX R0 code (e.g. in IEM).
+ *
+ * This need -not- be called for modifications to the guest hypervisor's current
+ * VMCS when the guest is in VMX non-root mode as VMCS shadowing is not applicable
+ * there.
+ *
+ * @param   pVCpu   The cross context virtual CPU structure.
+ *
+ * @remarks Can be called from ring-0 as well as ring-3.
+ */
+VMM_INT_DECL(void) HMNotifyVmxNstGstCurrentVmcsChanged(PVMCPU pVCpu)
+{
+    CPUM_ASSERT_NOT_EXTRN(pVCpu, CPUMCTX_EXTRN_HWVIRT);
+    ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, CPUMCTX_EXTRN_HWVIRT);
+
+    /*
+     * Make sure we need to copy the guest hypervisor's current VMCS into the shadow VMCS
+     * on the next guest VM-entry.
+     */
+    pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = false;
+}
+
 # endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
 #endif /* IN_RC */
Index: /trunk/src/VBox/VMM/VMMR0/HMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 79344)
+++ /trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 79345)
@@ -1172,5 +1172,5 @@
     if (pVM->hm.s.vmx.fSupported)
     {
-        pVM->hm.s.vmx.fUsePreemptTimer     &= g_HmR0.hwvirt.u.vmx.fUsePreemptTimer; /* Can be overridden by CFGM see HMR3Init(). */
+        pVM->hm.s.vmx.fUsePreemptTimer     &= g_HmR0.hwvirt.u.vmx.fUsePreemptTimer; /* Can be overridden by CFGM in HMR3Init(). */
         pVM->hm.s.vmx.cPreemptTimerShift    = g_HmR0.hwvirt.u.vmx.cPreemptTimerShift;
         pVM->hm.s.vmx.u64HostCr4            = g_HmR0.hwvirt.u.vmx.u64HostCr4;
@@ -1178,4 +1178,37 @@
         pVM->hm.s.vmx.u64HostSmmMonitorCtl  = g_HmR0.hwvirt.u.vmx.u64HostSmmMonitorCtl;
         HMGetVmxMsrsFromHwvirtMsrs(&g_HmR0.hwvirt.Msrs, &pVM->hm.s.vmx.Msrs);
+
+        /* Enable VPID if supported and configured. */
+        if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VPID)
+            pVM->hm.s.vmx.fVpid = pVM->hm.s.vmx.fAllowVpid; /* Can be overridden by CFGM in HMR3Init(). */
+
+        /* Use VMCS shadowing if supported. */
+        Assert(!pVM->hm.s.vmx.fUseVmcsShadowing);
+        if (   pVM->cpum.ro.GuestFeatures.fVmx
+            && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VMCS_SHADOWING))
+            pVM->hm.s.vmx.fUseVmcsShadowing = true;
+
+        /* Use the VMCS controls for swapping the EFER MSR if supported. */
+        Assert(!pVM->hm.s.vmx.fSupportsVmcsEfer);
+#if HC_ARCH_BITS == 64
+        if (   (pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed1 & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
+            && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1  & VMX_EXIT_CTLS_LOAD_EFER_MSR)
+            && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1  & VMX_EXIT_CTLS_SAVE_EFER_MSR))
+            pVM->hm.s.vmx.fSupportsVmcsEfer = true;
+#endif
+
+#if 0
+        /* Enable APIC register virtualization and virtual-interrupt delivery if supported. */
+        if (   (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT)
+            && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY))
+            pVM->hm.s.fVirtApicRegs = true;
+
+        /* Enable posted-interrupt processing if supported. */
+        /** @todo Add and query IPRT API for host OS support for posted-interrupt IPI
+         *        here. */
+        if (   (pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1  & VMX_PIN_CTLS_POSTED_INT)
+            && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT))
+            pVM->hm.s.fPostedIntrs = true;
+#endif
     }
     else if (pVM->hm.s.svm.fSupported)
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 79344)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 79345)
@@ -105,4 +105,5 @@
                                       | CPUMCTX_EXTRN_CR4             \
                                       | CPUMCTX_EXTRN_DR7             \
+                                      | CPUMCTX_EXTRN_HWVIRT          \
                                       | CPUMCTX_EXTRN_HM_VMX_MASK)
 
@@ -355,5 +356,5 @@
 #endif
 
-static int  hmR0VmxImportGuestState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
+static int  hmR0VmxImportGuestState(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat);
 #if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
 static void hmR0VmxInitVmcsReadCache(PVMCPU pVCpu);
@@ -479,8 +480,8 @@
 static VBOXSTRICTRC hmR0VmxExitXcptAC(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient);
 static VBOXSTRICTRC hmR0VmxExitXcptGeneric(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient);
-static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst);
-static VBOXSTRICTRC hmR0VmxExitClts(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t cbInstr);
-static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg);
-static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg);
+static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst);
+static VBOXSTRICTRC hmR0VmxExitClts(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr);
+static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg);
+static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg);
 static VBOXSTRICTRC hmR0VmxExitHostNmi(PVMCPU pVCpu);
 /** @} */
@@ -1217,21 +1218,16 @@
  * @returns VBox status code.
  * @param   pVmcsInfo       The VMCS info. object.
+ *
+ * @remarks Can be called with interrupts disabled.
  */
 static int hmR0VmxLoadVmcs(PVMXVMCSINFO pVmcsInfo)
 {
-    Assert(pVmcsInfo->HCPhysVmcs);
+    Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
 
-    if (pVmcsInfo->fVmcsState & VMX_V_VMCS_LAUNCH_STATE_CLEAR)
-    {
-        int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
-        if (RT_SUCCESS(rc))
-        {
-            pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
-            return VINF_SUCCESS;
-        }
-        return rc;
-    }
-    return VERR_VMX_INVALID_VMCS_LAUNCH_STATE;
+    int rc = VMXLoadVmcs(pVmcsInfo->HCPhysVmcs);
+    if (RT_SUCCESS(rc))
+        pVmcsInfo->fVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
+    return rc;
 }
 
@@ -1242,8 +1238,10 @@
  * @returns VBox status code.
  * @param   pVmcsInfo       The VMCS info. object.
+ *
+ * @remarks Can be called with interrupts disabled.
  */
 static int hmR0VmxClearVmcs(PVMXVMCSINFO pVmcsInfo)
 {
-    Assert(pVmcsInfo->HCPhysVmcs);
+    Assert(pVmcsInfo->HCPhysVmcs != 0 && pVmcsInfo->HCPhysVmcs != NIL_RTHCPHYS);
     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
 
@@ -1256,5 +1254,4 @@
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-#if 0
 /**
  * Loads the shadow VMCS specified by the VMCS info. object.
@@ -1262,23 +1259,17 @@
  * @returns VBox status code.
  * @param   pVmcsInfo       The VMCS info. object.
+ *
+ * @remarks Can be called with interrupts disabled.
  */
 static int hmR0VmxLoadShadowVmcs(PVMXVMCSINFO pVmcsInfo)
 {
-    Assert(pVmcsInfo->HCPhysShadowVmcs);
     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
-
-    if (pVmcsInfo->fShadowVmcsState & VMX_V_VMCS_LAUNCH_STATE_CLEAR)
-    {
-        int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
-        if (RT_SUCCESS(rc))
-        {
-            pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_ACTIVE;
-            return VINF_SUCCESS;
-        }
-        return rc;
-    }
-    return VERR_VMX_INVALID_VMCS_LAUNCH_STATE;
-}
-#endif
+    Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
+
+    int rc = VMXLoadVmcs(pVmcsInfo->HCPhysShadowVmcs);
+    if (RT_SUCCESS(rc))
+        pVmcsInfo->fShadowVmcsState |= VMX_V_VMCS_LAUNCH_STATE_CURRENT;
+    return rc;
+}
 
 
@@ -1288,9 +1279,11 @@
  * @returns VBox status code.
  * @param   pVmcsInfo       The VMCS info. object.
+ *
+ * @remarks Can be called with interrupts disabled.
  */
 static int hmR0VmxClearShadowVmcs(PVMXVMCSINFO pVmcsInfo)
 {
-    Assert(pVmcsInfo->HCPhysShadowVmcs);
     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+    Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
 
     int rc = VMXClearVmcs(pVmcsInfo->HCPhysShadowVmcs);
@@ -1320,5 +1313,13 @@
         int rc = hmR0VmxClearVmcs(pVmcsInfoFrom);
         if (RT_SUCCESS(rc))
-        { /* likely */ }
+        {
+            /*
+             * The shadow VMCS, if any, would not be active at this point since we
+             * would have cleared it while importing the virtual hardware-virtualization
+             * state as part the VMLAUNCH/VMRESUME VM-exit. Hence, there's no need to
+             * clear the shadow VMCS here, just assert for safety.
+             */
+            Assert(!pVmcsInfoFrom->pvShadowVmcs || pVmcsInfoFrom->fShadowVmcsState == VMX_V_VMCS_LAUNCH_STATE_CLEAR);
+        }
         else
             return rc;
@@ -1655,88 +1656,4 @@
     return rc;
 }
-
-
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-/**
- * Initializes the shadow VMCS.
- *
- * This builds an array (for use later while executing a nested-guest) of VMCS
- * fields to copy into the shadow VMCS.
- *
- * @param   pVM     The cross context VM structure.
- */
-static void hmR0VmxInitShadowVmcsFieldsArray(PVM pVM)
-{
-    uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
-    for (uint32_t i = 0; i < cVmcsFields; i++)
-    {
-        /*
-         * If the VMCS field depends on a CPU feature that is not exposed to the guest,
-         * we must not include it in the shadow VMCS fields array. Guests attempting to
-         * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
-         * the required behavior.
-         */
-        uint32_t const uVmcsField      = g_aVmcsFields[i];
-        bool const     fVmcsFieldValid = CPUMIsGuestVmxVmcsFieldValid(pVM, uVmcsField);
-        if (fVmcsFieldValid)
-        {
-            pVM->hm.s.vmx.paShadowVmcsFields[i] = uVmcsField;
-            ++pVM->hm.s.vmx.cShadowVmcsFields;
-        }
-    }
-}
-
-
-/**
- * Initializes the VMREAD/VMWRITE bitmaps.
- *
- * @param   pVM                 The cross context VM structure.
- */
-static void hmR0VmxInitVmreadVmwriteBitmaps(PVM pVM)
-{
-    /*
-     * By default, ensure guest attempts to acceses to any VMCS fields cause VM-exits.
-     */
-    uint32_t const  cbBitmap        = X86_PAGE_4K_SIZE;
-    uint8_t        *pbVmreadBitmap  = (uint8_t *)pVM->hm.s.vmx.pvVmreadBitmap;
-    uint8_t        *pbVmwriteBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmwriteBitmap;
-    ASMMemFill32(pbVmreadBitmap,  cbBitmap, UINT32_C(0xffffffff));
-    ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
-
-    uint32_t const *paShadowVmcsFields = pVM->hm.s.vmx.paShadowVmcsFields;
-    uint32_t const  cShadowVmcsFields  = pVM->hm.s.vmx.cShadowVmcsFields;
-
-    /*
-     * Initialize the VMREAD bitmap.
-     * All valid guest VMCS fields (read-only and read-write) can be accessed
-     * using VMREAD without causing a VM-exit.
-     */
-    for (uint32_t i = 0; i < cShadowVmcsFields; i++)
-    {
-        uint32_t const uVmcsField = paShadowVmcsFields[i];
-        Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
-        uint8_t *pbField = pbVmreadBitmap + (uVmcsField >> 3);
-        ASMBitClear(pbField, uVmcsField & 7);
-    }
-
-    /*
-     * Initialize the VMWRITE bitmap.
-     * Allow the guest to write to read-only guest VMCS fields only if the
-     * host CPU supports it, otherwise it would cause a VMWRITE instruction error.
-     */
-    bool const fHasVmwriteAll = RT_BOOL(pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL);
-    for (uint32_t i = 0; i < cShadowVmcsFields; i++)
-    {
-        uint32_t const uVmcsField = paShadowVmcsFields[i];
-        if (   fHasVmwriteAll
-            || !HMVmxIsVmcsFieldReadOnly(uVmcsField))
-        {
-            Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
-            uint8_t *pbField = pbVmwriteBitmap + (uVmcsField >> 3);
-            ASMBitClear(pbField, uVmcsField & 7);
-        }
-    }
-}
-#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
 
 
@@ -1827,6 +1744,5 @@
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-    if (   pVM->cpum.ro.GuestFeatures.fVmx
-        && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VMCS_SHADOWING))
+    if (pVM->hm.s.vmx.fUseVmcsShadowing)
         hmR0VmxPageFree(&pVmcsInfo->hMemObjShadowVmcs, &pVmcsInfo->pvShadowVmcs, &pVmcsInfo->HCPhysShadowVmcs);
 #endif
@@ -1862,7 +1778,5 @@
         {
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-            /* Allocate the shadow VMCS if supported by the CPU. */
-            if (   pVM->cpum.ro.GuestFeatures.fVmx
-                && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VMCS_SHADOWING))
+            if (pVM->hm.s.vmx.fUseVmcsShadowing)
                 rc = hmR0VmxPageAllocZ(&pVmcsInfo->hMemObjShadowVmcs, &pVmcsInfo->pvShadowVmcs, &pVmcsInfo->HCPhysShadowVmcs);
 #endif
@@ -1959,8 +1873,8 @@
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-    if (   pVM->cpum.ro.GuestFeatures.fVmx
-        && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VMCS_SHADOWING))
+    if (pVM->hm.s.vmx.fUseVmcsShadowing)
     {
         RTMemFree(pVM->hm.s.vmx.paShadowVmcsFields);
+        RTMemFree(pVM->hm.s.vmx.paShadowVmcsRoFields);
         hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjVmreadBitmap,  &pVM->hm.s.vmx.pvVmreadBitmap,  &pVM->hm.s.vmx.HCPhysVmreadBitmap);
         hmR0VmxPageFree(&pVM->hm.s.vmx.hMemObjVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap, &pVM->hm.s.vmx.HCPhysVmwriteBitmap);
@@ -2056,10 +1970,13 @@
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-    /* Allocate the shadow VMCS fields array, VMREAD, VMWRITE bitmaps if VMCS shadowing supported by the CPU. */
-    if (   pVM->cpum.ro.GuestFeatures.fVmx
-        && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VMCS_SHADOWING))
-    {
-        pVM->hm.s.vmx.paShadowVmcsFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
-        if (RT_LIKELY(pVM->hm.s.vmx.paShadowVmcsFields))
+    /* Allocate the shadow VMCS fields array, VMREAD, VMWRITE bitmaps.. */
+    if (pVM->hm.s.vmx.fUseVmcsShadowing)
+    {
+        Assert(!pVM->hm.s.vmx.cShadowVmcsFields);
+        Assert(!pVM->hm.s.vmx.cShadowVmcsRoFields);
+        pVM->hm.s.vmx.paShadowVmcsFields   = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
+        pVM->hm.s.vmx.paShadowVmcsRoFields = (uint32_t *)RTMemAllocZ(sizeof(g_aVmcsFields));
+        if (RT_LIKELY(   pVM->hm.s.vmx.paShadowVmcsFields
+                      && pVM->hm.s.vmx.paShadowVmcsRoFields))
         {
             rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjVmreadBitmap, &pVM->hm.s.vmx.pvVmreadBitmap,
@@ -2069,9 +1986,4 @@
                 rc = hmR0VmxPageAllocZ(&pVM->hm.s.vmx.hMemObjVmwriteBitmap, &pVM->hm.s.vmx.pvVmwriteBitmap,
                                        &pVM->hm.s.vmx.HCPhysVmwriteBitmap);
-                if (RT_SUCCESS(rc))
-                {
-                    hmR0VmxInitShadowVmcsFieldsArray(pVM);
-                    hmR0VmxInitVmreadVmwriteBitmaps(pVM);
-                }
             }
         }
@@ -3376,4 +3288,128 @@
 
 
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+/**
+ * Sets up the shadow VMCS fields arrays.
+ *
+ * This function builds arrays of VMCS fields to sync the shadow VMCS later while
+ * executing the guest.
+ *
+ * @returns VBox status code.
+ * @param   pVM     The cross context VM structure.
+ */
+static int hmR0VmxSetupShadowVmcsFieldsArrays(PVM pVM)
+{
+    /*
+     * Paranoia. Ensure we haven't exposed the VMWRITE-All VMX feature to the guest
+     * when the host does not support it.
+     */
+    bool const fGstVmwriteAll = pVM->cpum.ro.GuestFeatures.fVmxVmwriteAll;
+    if (   !fGstVmwriteAll
+        || (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL))
+    { /* likely. */ }
+    else
+    {
+        LogRelFunc(("VMX VMWRITE-All feature exposed to the guest but host CPU does not support it!\n"));
+        pVM->aCpus[0].hm.s.u32HMError = VMX_UFC_GST_HOST_VMWRITE_ALL;
+        return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
+    }
+
+    uint32_t const cVmcsFields = RT_ELEMENTS(g_aVmcsFields);
+    uint32_t       cRwFields   = 0;
+    uint32_t       cRoFields   = 0;
+    for (uint32_t i = 0; i < cVmcsFields; i++)
+    {
+        VMXVMCSFIELD VmcsField;
+        VmcsField.u = g_aVmcsFields[i];
+
+        /*
+         * We will be writing "FULL" (64-bit) fields while syncing the shadow VMCS.
+         * Therefore, "HIGH" (32-bit portion of 64-bit) fields must not be included
+         * in the shadow VMCS fields array as they would be redundant.
+         *
+         * If the VMCS field depends on a CPU feature that is not exposed to the guest,
+         * we must not include it in the shadow VMCS fields array. Guests attempting to
+         * VMREAD/VMWRITE such VMCS fields would cause a VM-exit and we shall emulate
+         * the required behavior.
+         */
+        if (   VmcsField.n.fAccessType == VMX_VMCSFIELD_ACCESS_FULL
+            && CPUMIsGuestVmxVmcsFieldValid(pVM, VmcsField.u))
+        {
+            /*
+             * Read-only fields are placed in a separate array so that while syncing shadow
+             * VMCS fields later (which is more performance critical) we can avoid branches.
+             *
+             * However, if the guest can write to all fields (including read-only fields),
+             * we treat it a as read/write field. Otherwise, writing to these fields would
+             * cause a VMWRITE instruction error while syncing the shadow VMCS .
+             */
+            if (   fGstVmwriteAll
+                || !HMVmxIsVmcsFieldReadOnly(VmcsField.u))
+                pVM->hm.s.vmx.paShadowVmcsFields[cRwFields++] = VmcsField.u;
+            else
+                pVM->hm.s.vmx.paShadowVmcsRoFields[cRoFields++] = VmcsField.u;
+        }
+    }
+
+    /* Update the counts. */
+    pVM->hm.s.vmx.cShadowVmcsFields   = cRwFields;
+    pVM->hm.s.vmx.cShadowVmcsRoFields = cRoFields;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Sets up the VMREAD and VMWRITE bitmaps.
+ *
+ * @param   pVM     The cross context VM structure.
+ */
+static void hmR0VmxSetupVmreadVmwriteBitmaps(PVM pVM)
+{
+    /*
+     * By default, ensure guest attempts to acceses to any VMCS fields cause VM-exits.
+     */
+    uint32_t const cbBitmap        = X86_PAGE_4K_SIZE;
+    uint8_t       *pbVmreadBitmap  = (uint8_t *)pVM->hm.s.vmx.pvVmreadBitmap;
+    uint8_t       *pbVmwriteBitmap = (uint8_t *)pVM->hm.s.vmx.pvVmwriteBitmap;
+    ASMMemFill32(pbVmreadBitmap,  cbBitmap, UINT32_C(0xffffffff));
+    ASMMemFill32(pbVmwriteBitmap, cbBitmap, UINT32_C(0xffffffff));
+
+    /*
+     * Skip intercepting VMREAD/VMWRITE to guest read/write fields in the
+     * VMREAD and VMWRITE bitmaps.
+     */
+    {
+        uint32_t const *paShadowVmcsFields = pVM->hm.s.vmx.paShadowVmcsFields;
+        uint32_t const  cShadowVmcsFields  = pVM->hm.s.vmx.cShadowVmcsFields;
+        for (uint32_t i = 0; i < cShadowVmcsFields; i++)
+        {
+            uint32_t const uVmcsField = paShadowVmcsFields[i];
+            Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
+            Assert(uVmcsField >> 3 < cbBitmap);
+            ASMBitClear(pbVmreadBitmap  + (uVmcsField >> 3), uVmcsField & 7);
+            ASMBitClear(pbVmwriteBitmap + (uVmcsField >> 3), uVmcsField & 7);
+        }
+    }
+
+    /*
+     * Skip intercepting VMREAD for guest read-only fields in the VMREAD bitmap
+     * if the host supports VMWRITE to all supported VMCS fields.
+     */
+    if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
+    {
+        uint32_t const *paShadowVmcsRoFields = pVM->hm.s.vmx.paShadowVmcsRoFields;
+        uint32_t const  cShadowVmcsRoFields  = pVM->hm.s.vmx.cShadowVmcsRoFields;
+        for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
+        {
+            uint32_t const uVmcsField = paShadowVmcsRoFields[i];
+            Assert(!(uVmcsField & VMX_VMCSFIELD_RSVD_MASK));
+            Assert(uVmcsField >> 3 < cbBitmap);
+            ASMBitClear(pbVmreadBitmap + (uVmcsField >> 3), uVmcsField & 7);
+        }
+    }
+}
+#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
+
+
 /**
  * Sets up the virtual-APIC page address for the VMCS.
@@ -3425,18 +3461,34 @@
 
 
-/**
- * Sets up the VMCS link pointer for the VMCS.
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+/**
+ * Sets up the VMREAD bitmap address for the VMCS.
  *
  * @returns VBox status code.
  * @param   pVCpu       The cross context virtual CPU structure.
- * @param   pVmcsInfo   The VMCS info. object.
- */
-DECLINLINE(int) hmR0VmxSetupVmcsLinkPtr(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
-{
-    NOREF(pVCpu); /* Used implicitly by VMXWriteVmcs64 on 32-bit hosts. */
-    uint64_t const u64VmcsLinkPtr = pVmcsInfo->u64VmcsLinkPtr;
-    Assert(u64VmcsLinkPtr == UINT64_C(0xffffffffffffffff));  /* Bits 63:0 MB1. */
-    return VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, u64VmcsLinkPtr);
-}
+ */
+DECLINLINE(int) hmR0VmxSetupVmcsVmreadBitmapAddr(PVMCPU pVCpu)
+{
+    RTHCPHYS const HCPhysVmreadBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmreadBitmap;
+    Assert(HCPhysVmreadBitmap != NIL_RTHCPHYS);
+    Assert(!(HCPhysVmreadBitmap & 0xfff));                     /* Bits 11:0 MBZ. */
+    return VMXWriteVmcs64(VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL, HCPhysVmreadBitmap);
+}
+
+
+/**
+ * Sets up the VMWRITE bitmap address for the VMCS.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ */
+DECLINLINE(int) hmR0VmxSetupVmcsVmwriteBitmapAddr(PVMCPU pVCpu)
+{
+    RTHCPHYS const HCPhysVmwriteBitmap = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.HCPhysVmwriteBitmap;
+    Assert(HCPhysVmwriteBitmap != NIL_RTHCPHYS);
+    Assert(!(HCPhysVmwriteBitmap & 0xfff));                     /* Bits 11:0 MBZ. */
+    return VMXWriteVmcs64(VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL, HCPhysVmwriteBitmap);
+}
+#endif
 
 
@@ -3624,13 +3676,4 @@
         fVal |= VMX_PROC_CTLS2_UNRESTRICTED_GUEST;
 
-#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-#if 0
-    /* Enable VMCS shadowing if supported by the hardware and VMX is exposed to the guest. */
-    if (   pVM->cpum.ro.GuestFeatures.fVmx
-        && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VMCS_SHADOWING))
-        fVal |= VMX_PROC_CTLS2_VMCS_SHADOWING;
-#endif
-#endif
-
 #if 0
     if (pVM->hm.s.fVirtApicRegs)
@@ -3807,19 +3850,28 @@
  * @param   pVCpu           The cross context virtual CPU structure.
  * @param   pVmcsInfo       The VMCS info. object.
- *
- * @remarks Must be called after secondary processor-based VM-execution controls
- *          have been initialized!
  */
 static int hmR0VmxSetupVmcsMiscCtls(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
 {
-    /* Set the VMCS link pointer in the VMCS. */
-    int rc = hmR0VmxSetupVmcsLinkPtr(pVCpu, pVmcsInfo);
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+    if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
+    {
+        int rc = hmR0VmxSetupVmcsVmreadBitmapAddr(pVCpu);
+        rc    |= hmR0VmxSetupVmcsVmwriteBitmapAddr(pVCpu);
+        if (RT_SUCCESS(rc))
+        { /* likely */ }
+        else
+        {
+            LogRelFunc(("Failed to setup VMREAD/VMWRITE bitmap addresses. rc=%Rrc\n", rc));
+            return rc;
+        }
+    }
+#endif
+
+    int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
     if (RT_SUCCESS(rc))
     {
-        /* Set the auto-load/store MSR area addresses in the VMCS. */
         rc = hmR0VmxSetupVmcsAutoLoadStoreMsrAddrs(pVCpu, pVmcsInfo);
         if (RT_SUCCESS(rc))
         {
-            /* Set the CR0/CR4 guest/host mask. */
             uint64_t const u64Cr0Mask = hmR0VmxGetFixedCr0Mask(pVCpu);
             uint64_t const u64Cr4Mask = hmR0VmxGetFixedCr4Mask(pVCpu);
@@ -3890,5 +3942,5 @@
 {
     PVM pVM = pVCpu->CTX_SUFF(pVM);
-    int rc = hmR0VmxSetupVmcsLinkPtr(pVCpu, pVmcsInfo);
+    int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
     if (RT_SUCCESS(rc))
     {
@@ -3967,8 +4019,11 @@
                             {
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
-                                /* If VMCS shadowing is used, initialize the shadow VMCS. */
-                                if (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
+                                /*
+                                 * If a shadow VMCS is allocated for the VMCS info. object, initialize the
+                                 * VMCS revision ID and shadow VMCS indicator bit. Also, clear the VMCS
+                                 * making it fit for use when VMCS shadowing is later enabled.
+                                 */
+                                if (pVmcsInfo->pvShadowVmcs)
                                 {
-                                    Assert(pVmcsInfo->pvShadowVmcs);
                                     VMXVMCSREVID VmcsRevId;
                                     VmcsRevId.u = RT_BF_GET(pVM->hm.s.vmx.Msrs.u64Basic, VMX_BF_BASIC_VMCS_ID);
@@ -4220,15 +4275,21 @@
     if (RT_FAILURE(rc))
     {
-        LogRelFunc(("hmR0VmxSetupTaggedTlb failed! rc=%Rrc\n", rc));
+        LogRelFunc(("Failed to setup tagged TLB. rc=%Rrc\n", rc));
         return rc;
     }
 
-    /* Check if we can use the VMCS controls for swapping the EFER MSR. */
-    Assert(!pVM->hm.s.vmx.fSupportsVmcsEfer);
-#if HC_ARCH_BITS == 64
-    if (   (pVM->hm.s.vmx.Msrs.EntryCtls.n.allowed1 & VMX_ENTRY_CTLS_LOAD_EFER_MSR)
-        && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1  & VMX_EXIT_CTLS_LOAD_EFER_MSR)
-        && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1  & VMX_EXIT_CTLS_SAVE_EFER_MSR))
-        pVM->hm.s.vmx.fSupportsVmcsEfer = true;
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+    /* Setup the shadow VMCS fields array and VMREAD/VMWRITE bitmaps. */
+    if (pVM->hm.s.vmx.fUseVmcsShadowing)
+    {
+        rc = hmR0VmxSetupShadowVmcsFieldsArrays(pVM);
+        if (RT_SUCCESS(rc))
+            hmR0VmxSetupVmreadVmwriteBitmaps(pVM);
+        else
+        {
+            LogRelFunc(("Failed to setup shadow VMCS fields arrays. rc=%Rrc\n", rc));
+            return rc;
+        }
+    }
 #endif
 
@@ -5345,4 +5406,242 @@
 
 
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+/**
+ * Copies the nested-guest VMCS to the shadow VMCS.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ * @param   pVmcsInfo   The VMCS info. object.
+ *
+ * @remarks No-long-jump zone!!!
+ */
+static int hmR0VmxCopyNstGstToShadowVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
+{
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    PCVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
+
+    /*
+     * Disable interrupts so we don't get preempted while the shadow VMCS is the
+     * current VMCS, as we may try saving guest lazy MSRs.
+     *
+     * Strictly speaking the lazy MSRs are not in the VMCS, but I'd rather not risk
+     * calling the import VMCS code which is currently performing the guest MSR reads
+     * (on 64-bit hosts) and accessing the auto-load/store MSR area on 32-bit hosts
+     * and the rest of the VMX leave session machinery.
+     */
+    RTCCUINTREG const fEFlags = ASMIntDisableFlags();
+
+    int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Copy all guest read/write VMCS fields.
+         *
+         * We don't check for VMWRITE failures here for performance reasons and
+         * because they are not expected to fail, barring irrecoverable conditions
+         * like hardware errors.
+         */
+        uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
+        for (uint32_t i = 0; i < cShadowVmcsFields; i++)
+        {
+            uint64_t       u64Val;
+            uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
+            IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
+            VMXWriteVmcs64(uVmcsField, u64Val);
+        }
+
+        /*
+         * If the host CPU supports writing all VMCS fields, copy the guest read-only
+         * VMCS fields, so the guest can VMREAD them without causing a VM-exit.
+         */
+        if (pVM->hm.s.vmx.Msrs.u64Misc & VMX_MISC_VMWRITE_ALL)
+        {
+            uint32_t const cShadowVmcsRoFields = pVM->hm.s.vmx.cShadowVmcsRoFields;
+            for (uint32_t i = 0; i < cShadowVmcsRoFields; i++)
+            {
+                uint64_t       u64Val;
+                uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsRoFields[i];
+                IEMReadVmxVmcsField(pVmcsNstGst, uVmcsField, &u64Val);
+                VMXWriteVmcs64(uVmcsField, u64Val);
+            }
+        }
+
+        rc  = hmR0VmxClearShadowVmcs(pVmcsInfo);
+        rc |= hmR0VmxLoadVmcs(pVmcsInfo);
+    }
+
+    ASMSetFlags(fEFlags);
+    return rc;
+}
+
+
+/**
+ * Copies the shadow VMCS to the nested-guest VMCS.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ * @param   pVmcsInfo   The VMCS info. object.
+ *
+ * @remarks Called with interrupts disabled.
+ */
+static int hmR0VmxCopyShadowToNstGstVmcs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
+{
+    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    PVMXVVMCS pVmcsNstGst = pVCpu->cpum.GstCtx.hwvirt.vmx.CTX_SUFF(pVmcs);
+
+    int rc = hmR0VmxLoadShadowVmcs(pVmcsInfo);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Copy guest read/write fields from the shadow VMCS.
+         * Guest read-only fields cannot be modified, so no need to copy them.
+         *
+         * We don't check for VMREAD failures here for performance reasons and
+         * because they are not expected to fail, barring irrecoverable conditions
+         * like hardware errors.
+         */
+        uint32_t const cShadowVmcsFields = pVM->hm.s.vmx.cShadowVmcsFields;
+        for (uint32_t i = 0; i < cShadowVmcsFields; i++)
+        {
+            uint64_t       u64Val;
+            uint32_t const uVmcsField = pVM->hm.s.vmx.paShadowVmcsFields[i];
+            VMXReadVmcs64(uVmcsField, &u64Val);
+            IEMWriteVmxVmcsField(pVmcsNstGst, uVmcsField, u64Val);
+        }
+
+        rc  = hmR0VmxClearShadowVmcs(pVmcsInfo);
+        rc |= hmR0VmxLoadVmcs(pVmcsInfo);
+    }
+    return rc;
+}
+
+
+/**
+ * Enables VMCS shadowing for the given VMCS info. object.
+ *
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   pVmcsInfo       The VMCS info. object.
+ *
+ * @remarks No-long-jump zone!!!
+ */
+static void hmR0VmxEnableVmcsShadowing(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
+{
+    NOREF(pVCpu); /* Used implicitly by VMXWriteVmcs64 on 32-bit hosts. */
+
+    uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
+    if (!(uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING))
+    {
+        Assert(pVmcsInfo->HCPhysShadowVmcs != 0 && pVmcsInfo->HCPhysShadowVmcs != NIL_RTHCPHYS);
+        uProcCtls2 |= VMX_PROC_CTLS2_VMCS_SHADOWING;
+        int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2);
+        rc    |= VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, pVmcsInfo->HCPhysShadowVmcs);
+        AssertRC(rc);
+
+        pVmcsInfo->u32ProcCtls2   = uProcCtls2;
+        pVmcsInfo->u64VmcsLinkPtr = pVmcsInfo->HCPhysShadowVmcs;
+        Log4Func(("Enabled\n"));
+    }
+}
+
+
+/**
+ * Disables VMCS shadowing for the given VMCS info. object.
+ *
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   pVmcsInfo       The VMCS info. object.
+ *
+ * @remarks No-long-jump zone!!!
+ */
+static void hmR0VmxDisableVmcsShadowing(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
+{
+    NOREF(pVCpu); /* Used implicitly by VMXWriteVmcs64 on 32-bit hosts. */
+
+    /*
+     * We want all VMREAD and VMWRITE instructions to cause VM-exits, so we clear the
+     * VMCS shadowing control. However, VM-entry requires the shadow VMCS indicator bit
+     * to match the VMCS shadowing control if the VMCS link pointer is not NIL_RTHCPHYS.
+     * Hence, we must also reset the VMCS link pointer to ensure VM-entry does not fail.
+     *
+     * See Intel spec. 26.2.1.1 "VM-Execution Control Fields".
+     * See Intel spec. 26.3.1.5 "Checks on Guest Non-Register State".
+     */
+    uint32_t uProcCtls2 = pVmcsInfo->u32ProcCtls2;
+    if (uProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
+    {
+        uProcCtls2 &= ~VMX_PROC_CTLS2_VMCS_SHADOWING;
+        int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC2, uProcCtls2);
+        rc    |= VMXWriteVmcs64(VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL, NIL_RTHCPHYS);
+        AssertRC(rc);
+
+        pVmcsInfo->u32ProcCtls2   = uProcCtls2;
+        pVmcsInfo->u64VmcsLinkPtr = NIL_RTHCPHYS;
+        Log4Func(("Disabled\n"));
+    }
+}
+#endif
+
+
+/**
+ * Exports the guest hardware-virtualization state.
+ *
+ * @returns VBox status code.
+ * @param   pVCpu           The cross context virtual CPU structure.
+ * @param   pVmxTransient   The VMX-transient structure.
+ *
+ * @remarks No-long-jump zone!!!
+ */
+static int hmR0VmxExportGuestHwvirtState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
+{
+    if (ASMAtomicUoReadU64(&pVCpu->hm.s.fCtxChanged) & HM_CHANGED_GUEST_HWVIRT)
+    {
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+        /*
+         * Check if the VMX feature is exposed to the guest and if the host CPU supports
+         * VMCS shadowing.
+         */
+        if (pVCpu->CTX_SUFF(pVM)->hm.s.vmx.fUseVmcsShadowing)
+        {
+            /*
+             * If the guest hypervisor has loaded a current VMCS and is in VMX root mode,
+             * copy the guest hypervisor's current VMCS into the shadow VMCS and enable
+             * VMCS shadowing to skip intercepting some or all VMREAD/VMWRITE VM-exits.
+             *
+             * We check for VMX root mode here in case the guest executes VMXOFF without
+             * clearing the current VMCS pointer and our VMXOFF instruction emulation does
+             * not clear the current VMCS pointer.
+             */
+            PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+            if (   CPUMIsGuestInVmxRootMode(&pVCpu->cpum.GstCtx)
+                && !CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx)
+                && CPUMIsGuestVmxCurrentVmcsValid(pVCpu, &pVCpu->cpum.GstCtx))
+            {
+                /* Paranoia. */
+                Assert(!pVmxTransient->fIsNestedGuest);
+
+                /*
+                 * For performance reasons, also check if the guest hypervisor's current VMCS
+                 * was newly loaded or modified before copying it to the shadow VMCS.
+                 */
+                if (!pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs)
+                {
+                    int rc = hmR0VmxCopyNstGstToShadowVmcs(pVCpu, pVmcsInfo);
+                    AssertRCReturn(rc, rc);
+                    pVCpu->hm.s.vmx.fCopiedNstGstToShadowVmcs = true;
+                }
+                hmR0VmxEnableVmcsShadowing(pVCpu, pVmcsInfo);
+            }
+            else
+                hmR0VmxDisableVmcsShadowing(pVCpu, pVmcsInfo);
+        }
+#else
+        NOREF(pVmxTransient);
+#endif
+        ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~HM_CHANGED_GUEST_HWVIRT);
+    }
+    return VINF_SUCCESS;
+}
+
+
 /**
  * Exports the guest CR0 control register into the guest-state area in the VMCS.
@@ -5964,5 +6263,5 @@
  *          segments.
  */
-static void hmR0VmxValidateSegmentRegs(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo)
+static void hmR0VmxValidateSegmentRegs(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo)
 {
     /*
@@ -7985,5 +8284,5 @@
  * @param   fWhat       What to import, CPUMCTX_EXTRN_XXX.
  */
-static int hmR0VmxImportGuestState(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
+static int hmR0VmxImportGuestState(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint64_t fWhat)
 {
 #define VMXLOCAL_BREAK_RC(a_rc) \
@@ -8300,6 +8599,17 @@
                     }
                 }
+            }
 
 #ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+            if (fWhat & CPUMCTX_EXTRN_HWVIRT)
+            {
+                if (   (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_VMCS_SHADOWING)
+                    && !CPUMIsGuestInVmxNonRootMode(pCtx))
+                {
+                    Assert(CPUMIsGuestInVmxRootMode(pCtx));
+                    rc = hmR0VmxCopyShadowToNstGstVmcs(pVCpu, pVmcsInfo);
+                    VMXLOCAL_BREAK_RC(rc);
+                }
+
 # if 0
                 /** @todo NSTVMX: We handle most of these fields individually by passing it to IEM
@@ -8312,6 +8622,5 @@
                  * the guest-CPU state when executing a nested-guest.
                  */
-                if (   (fWhat & CPUMCTX_EXTRN_HWVIRT)
-                    && CPUMIsGuestInVmxNonRootMode(pCtx))
+                if (CPUMIsGuestInVmxNonRootMode(pCtx))
                 {
                     PVMXVVMCS pGstVmcs = pCtx->hwvirt.vmx.CTX_SUFF(pVmcs);
@@ -8361,6 +8670,6 @@
                 }
 # endif
+            }
 #endif
-            }
         } while (0);
 
@@ -8434,5 +8743,5 @@
 {
     AssertPtr(pVCpu);
-    PCVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
+    PVMXVMCSINFO pVmcsInfo = hmGetVmxActiveVmcsInfo(pVCpu);
     return hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fWhat);
 }
@@ -8848,4 +9157,21 @@
     int rc = hmR0VmxClearVmcs(pVmcsInfo);
     AssertRCReturn(rc, rc);
+
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+    /*
+     * A valid shadow VMCS is made active as part of VM-entry. It is necessary to
+     * clear a shadow VMCS before allowing that VMCS to become active on another
+     * logical processor. We may or may not be importing guest state which clears
+     * it, so cover for it here.
+     *
+     * See Intel spec. 24.11.1 "Software Use of Virtual-Machine Control Structures".
+     */
+    if (   pVmcsInfo->pvShadowVmcs
+        && pVmcsInfo->fShadowVmcsState != VMX_V_VMCS_LAUNCH_STATE_CLEAR)
+    {
+        rc = hmR0VmxClearShadowVmcs(pVmcsInfo);
+        AssertRCReturn(rc, rc);
+    }
+#endif
 
     Log4Func(("Cleared Vmcs. HostCpuId=%u\n", idCpu));
@@ -9083,5 +9409,6 @@
         VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
 
-        /* Clear the current VMCS data back to memory. */
+        /* Clear the current VMCS data back to memory (shadow VMCS if any would have been
+           cleared as part of importing the guest state above. */
         hmR0VmxClearVmcs(pVmcsInfo);
 
@@ -9233,5 +9560,5 @@
 
             /* We require RIP, RSP, RFLAGS, CS, IDTR, import them. */
-            PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+            PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
             int rc2 = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_SREG_MASK | CPUMCTX_EXTRN_TABLE_MASK
                                                               | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS);
@@ -9876,4 +10203,7 @@
     AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
 
+    rc = hmR0VmxExportGuestHwvirtState(pVCpu, pVmxTransient);
+    AssertLogRelMsgRCReturn(rc, ("rc=%Rrc\n", rc), rc);
+
     /* Clear any bits that may be set but exported unconditionally or unused/reserved bits. */
     ASMAtomicUoAndU64(&pVCpu->hm.s.fCtxChanged, ~(  (HM_CHANGED_GUEST_GPRS_MASK & ~HM_CHANGED_GUEST_RSP)
@@ -9888,5 +10218,4 @@
                                                   |  HM_CHANGED_GUEST_TSC_AUX
                                                   |  HM_CHANGED_GUEST_OTHER_MSRS
-                                                  |  HM_CHANGED_GUEST_HWVIRT         /* More accurate PLE handling someday? */
                                                   | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
 
@@ -11085,4 +11414,6 @@
      * If any new events (interrupts/NMI) are pending currently, we try to set up the
      * guest to cause a VM-exit the next time they are ready to receive the event.
+     *
+     * With nested-guests, evaluating pending events may cause VM-exits.
      */
     if (TRPMHasTrap(pVCpu))
@@ -11111,6 +11442,6 @@
      * also result in triple-faulting the VM.
      *
-     * The above does not apply when executing a nested-guest (since unrestricted guest execution
-     * is a requirement) regardless doing it avoid duplicating code elsewhere.
+     * With nested-guests, the above does not apply since unrestricted guest execution is a
+     * requirement. Regardless, we do this here to avoid duplicating code elsewhere.
      */
     rcStrict = hmR0VmxInjectPendingEvent(pVCpu, pVmxTransient, fIntrState, fStepping);
@@ -11164,5 +11495,5 @@
      *
      * If we are injecting events to a real-on-v86 mode guest, we would have updated RIP and some segment
-     * registers. Hence, loading of the guest state needs to be done -after- injection of events.
+     * registers. Hence, exporting of the guest state needs to be done -after- injection of events.
      */
     rcStrict = hmR0VmxExportGuestStateOptimal(pVCpu, pVmxTransient);
@@ -11657,4 +11988,5 @@
     Assert(pcLoops);
     Assert(*pcLoops <= cMaxResumeLoops);
+    Assert(CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx));
 
     VMXTRANSIENT VmxTransient;
@@ -13145,5 +13477,5 @@
        do { \
             if (a_fSave != 0) \
-                hmR0VmxImportGuestState(pVCpu, HMVMX_CPUMCTX_EXTRN_ALL); \
+                hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL); \
             VBOXSTRICTRC rcStrict = a_CallExpr; \
             if (a_fSave != 0) \
@@ -13697,5 +14029,5 @@
     STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitXcptNmi, y3);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxReadExitIntInfoVmcs(pVmxTransient);
     AssertRCReturn(rc, rc);
@@ -13914,5 +14246,5 @@
      * Get the state we need and update the exit history entry.
      */
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
@@ -13966,5 +14298,5 @@
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4);
     AssertRCReturn(rc, rc);
@@ -13985,5 +14317,5 @@
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
     rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
@@ -14015,5 +14347,5 @@
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_TSC_AUX);
     rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
@@ -14045,5 +14377,5 @@
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_CR4    | CPUMCTX_EXTRN_CR0
                                                      | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS);
@@ -14076,5 +14408,5 @@
     if (EMAreHypercallInstructionsEnabled(pVCpu))
     {
-        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+        PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
         int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CR0
                                                          | CPUMCTX_EXTRN_SS  | CPUMCTX_EXTRN_CS     | CPUMCTX_EXTRN_EFER);
@@ -14118,5 +14450,5 @@
     Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging || pVCpu->hm.s.fUsingDebugLoop);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxReadExitQualVmcs(pVCpu, pVmxTransient);
     rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
@@ -14147,5 +14479,5 @@
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK | CPUMCTX_EXTRN_DS);
     rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
@@ -14172,5 +14504,5 @@
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
     rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
@@ -14259,5 +14591,5 @@
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_CR4);
@@ -14292,5 +14624,5 @@
 HMVMX_EXIT_NSRC_DECL hmR0VmxExitErrInvalidGuestState(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient)
 {
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, HMVMX_CPUMCTX_EXTRN_ALL);
     AssertRCReturn(rc, rc);
@@ -14437,7 +14769,7 @@
      * MSRs required.  That would require changes to IEM and possibly CPUM too.
      * (Should probably do it lazy fashion from CPUMAllMsrs.cpp). */
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
-    uint32_t const idMsr    = pVCpu->cpum.GstCtx.ecx;
-    uint64_t       fImport  = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
+    PVMXVMCSINFO   pVmcsInfo = pVmxTransient->pVmcsInfo;
+    uint32_t const idMsr     = pVCpu->cpum.GstCtx.ecx;
+    uint64_t       fImport   = IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK | CPUMCTX_EXTRN_ALL_MSRS;
     switch (idMsr)
     {
@@ -14517,5 +14849,5 @@
     }
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmcsInfo, fImport);
@@ -14685,5 +15017,5 @@
     STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatExitMovCRx, y2);
 
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxReadExitQualVmcs(pVCpu, pVmxTransient);
     rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
@@ -14838,5 +15170,5 @@
 
     PCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = hmR0VmxReadExitQualVmcs(pVCpu, pVmxTransient);
     rc    |= hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
@@ -15336,5 +15668,5 @@
      */
     RTGCPHYS GCPhys;
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &GCPhys);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
@@ -15415,5 +15747,5 @@
 
     RTGCPHYS GCPhys;
-    PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
     int rc  = VMXReadVmcs64(VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL, &GCPhys);
     rc     |= hmR0VmxReadExitQualVmcs(pVCpu, pVmxTransient);
@@ -15913,6 +16245,5 @@
  * VM-exit helper for LMSW.
  */
-static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw,
-                                    RTGCPTR GCPtrEffDst)
+static VBOXSTRICTRC hmR0VmxExitLmsw(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint16_t uMsw, RTGCPTR GCPtrEffDst)
 {
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
@@ -15939,5 +16270,5 @@
  * VM-exit helper for CLTS.
  */
-static VBOXSTRICTRC hmR0VmxExitClts(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
+static VBOXSTRICTRC hmR0VmxExitClts(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr)
 {
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
@@ -15964,5 +16295,5 @@
  * VM-exit helper for MOV from CRx (CRx read).
  */
-static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
+static VBOXSTRICTRC hmR0VmxExitMovFromCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
 {
     Assert(iCrReg < 16);
@@ -15998,5 +16329,5 @@
  * VM-exit helper for MOV to CRx (CRx write).
  */
-static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPU pVCpu, PCVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
+static VBOXSTRICTRC hmR0VmxExitMovToCrX(PVMCPU pVCpu, PVMXVMCSINFO pVmcsInfo, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg)
 {
     int rc = hmR0VmxImportGuestState(pVCpu, pVmcsInfo, IEM_CPUMCTX_EXTRN_MUST_MASK);
@@ -16094,4 +16425,5 @@
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
+                                                                    | CPUMCTX_EXTRN_HWVIRT
                                                                     | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
     rc    |= hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
@@ -16139,6 +16471,7 @@
     if (RT_LIKELY(rcStrict == VINF_SUCCESS))
     {
-        rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
         ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
+        if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
+            rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
     }
     Assert(rcStrict != VINF_IEM_RAISED_XCPT);
@@ -16156,4 +16489,5 @@
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
+                                                                    | CPUMCTX_EXTRN_HWVIRT
                                                                     | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
     rc    |= hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
@@ -16192,4 +16526,5 @@
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
+                                                                    | CPUMCTX_EXTRN_HWVIRT
                                                                     | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
     rc    |= hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
@@ -16228,4 +16563,5 @@
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
+                                                                    | CPUMCTX_EXTRN_HWVIRT
                                                                     | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
     rc    |= hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
@@ -16274,6 +16610,7 @@
     if (RT_LIKELY(rcStrict == VINF_SUCCESS))
     {
-        rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
         ASMAtomicUoOrU64(&pVCpu->hm.s.fCtxChanged, HM_CHANGED_ALL_GUEST);
+        if (CPUMIsGuestInVmxNonRootMode(&pVCpu->cpum.GstCtx))
+            rcStrict = VINF_VMX_VMLAUNCH_VMRESUME;
     }
     Assert(rcStrict != VINF_IEM_RAISED_XCPT);
@@ -16289,6 +16626,13 @@
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS(pVCpu, pVmxTransient);
 
+    /*
+     * Although we should not get VMWRITE VM-exits for shadow VMCS fields, since
+     * our HM hook that gets invoked when IEM's VMWRITE instruction emulation
+     * modifies the current VMCS signals re-loading the entire shadow VMCS, we
+     * should also save the entire shadow VMCS here.
+     */
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
+                                                                    | CPUMCTX_EXTRN_HWVIRT
                                                                     | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
     rc    |= hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
@@ -16307,4 +16651,7 @@
         HMVMX_DECODE_MEM_OPERAND(pVCpu, ExitInfo.InstrInfo.u, ExitInfo.u64Qual, VMXMEMACCESS_READ, &ExitInfo.GCPtrEffAddr);
 
+    /** @todo NSTVMX: Remove later. */
+    Log4Func(("VMWRITE: %#x\n", pVCpu->cpum.GstCtx.aGRegs[ExitInfo.InstrInfo.VmreadVmwrite.iReg2].u32));
+
     VBOXSTRICTRC rcStrict = IEMExecDecodedVmwrite(pVCpu, &ExitInfo);
     if (RT_LIKELY(rcStrict == VINF_SUCCESS))
@@ -16328,4 +16675,5 @@
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_CR4
+                                                                    | CPUMCTX_EXTRN_HWVIRT
                                                                     | IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
     AssertRCReturn(rc, rc);
@@ -16354,4 +16702,5 @@
     int rc = hmR0VmxReadExitInstrLenVmcs(pVmxTransient);
     rc    |= hmR0VmxImportGuestState(pVCpu, pVmxTransient->pVmcsInfo, CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_SREG_MASK
+                                                                    | CPUMCTX_EXTRN_HWVIRT
                                                                     | IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK);
     rc    |= hmR0VmxReadExitInstrInfoVmcs(pVmxTransient);
Index: /trunk/src/VBox/VMM/VMMR3/HM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 79344)
+++ /trunk/src/VBox/VMM/VMMR3/HM.cpp	(revision 79345)
@@ -1597,28 +1597,4 @@
 
     /*
-     * Enable VPID if configured and supported.
-     */
-    if (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VPID)
-        pVM->hm.s.vmx.fVpid = pVM->hm.s.vmx.fAllowVpid;
-
-#if 0
-    /*
-     * Enable APIC register virtualization and virtual-interrupt delivery if supported.
-     */
-    if (   (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_APIC_REG_VIRT)
-        && (pVM->hm.s.vmx.Msrs.ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_VIRT_INTR_DELIVERY))
-        pVM->hm.s.fVirtApicRegs = true;
-
-    /*
-     * Enable posted-interrupt processing if supported.
-     */
-    /** @todo Add and query IPRT API for host OS support for posted-interrupt IPI
-     *        here. */
-    if (   (pVM->hm.s.vmx.Msrs.PinCtls.n.allowed1  & VMX_PIN_CTLS_POSTED_INT)
-        && (pVM->hm.s.vmx.Msrs.ExitCtls.n.allowed1 & VMX_EXIT_CTLS_ACK_EXT_INT))
-        pVM->hm.s.fPostedIntrs = true;
-#endif
-
-    /*
      * Disallow RDTSCP in the guest if there is no secondary process-based VM execution controls as otherwise
      * RDTSCP would cause a #UD. There might be no CPUs out there where this happens, as RDTSCP was introduced
@@ -1771,10 +1747,4 @@
         Assert(!pVM->hm.s.vmx.fUnrestrictedGuest);
 
-    if (pVM->hm.s.fVirtApicRegs)
-        LogRel(("HM:   Enabled APIC-register virtualization support\n"));
-
-    if (pVM->hm.s.fPostedIntrs)
-        LogRel(("HM:   Enabled posted-interrupt processing support\n"));
-
     if (pVM->hm.s.vmx.fVpid)
     {
@@ -1798,4 +1768,13 @@
     else
         LogRel(("HM: Disabled VMX-preemption timer\n"));
+
+    if (pVM->hm.s.fVirtApicRegs)
+        LogRel(("HM: Enabled APIC-register virtualization support\n"));
+
+    if (pVM->hm.s.fPostedIntrs)
+        LogRel(("HM: Enabled posted-interrupt processing support\n"));
+
+    if (pVM->hm.s.vmx.fUseVmcsShadowing)
+        LogRel(("HM: Enabled VMCS shadowing support\n"));
 
     return VINF_SUCCESS;
Index: /trunk/src/VBox/VMM/include/HMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/HMInternal.h	(revision 79344)
+++ /trunk/src/VBox/VMM/include/HMInternal.h	(revision 79345)
@@ -595,5 +595,7 @@
         /** Whether the CPU supports VMCS fields for swapping EFER. */
         bool                        fSupportsVmcsEfer;
-        uint8_t                     u8Alignment2[7];
+        /** Whether to use VMCS shadowing. */
+        bool                        fUseVmcsShadowing;
+        uint8_t                     u8Alignment2[6];
 
         /** VMX MSR values. */
@@ -603,10 +605,12 @@
         RTHCPHYS                    HCPhysVmxEnableError;
 
-        /** Pointer to the shadow VMCS fields array. */
+        /** Pointer to the shadow VMCS read-only fields array. */
+        R0PTRTYPE(uint32_t *)       paShadowVmcsRoFields;
+        /** Pointer to the shadow VMCS read/write fields array. */
         R0PTRTYPE(uint32_t *)       paShadowVmcsFields;
-        RTR0PTR                     pvR0Alignment1;
-        /** Number of elements in the shadow VMCS fields array. */
+        /** Number of elements in the shadow VMCS read-only fields array. */
+        uint32_t                    cShadowVmcsRoFields;
+        /** Number of elements in the shadow VMCS read-write fields array. */
         uint32_t                    cShadowVmcsFields;
-        uint32_t                    u32Alignemnt0;
     } vmx;
 
@@ -984,6 +988,8 @@
              *  nested-guest VMCS controls. */
             bool                        fMergedNstGstCtls;
+            /** Whether the nested-guest VMCS has been copied to the shadow VMCS. */
+            bool                        fCopiedNstGstToShadowVmcs;
             /** Alignment. */
-            bool                        afAlignment0[6];
+            bool                        afAlignment0[5];
             /** Cached guest APIC-base MSR for identifying when to map the APIC-access page. */
             uint64_t                    u64GstMsrApicBase;
