Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 68405)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 68406)
@@ -912,28 +912,10 @@
     }
 
-#ifdef VBOX_WITH_NESTED_HWVIRT
-    /*
-     * Only if the nested hypervisor says it does not need to flush anything in the TLB,
-     * can we possibly apply it on the host. Otherwise, the nested-guest TLB flush setting
-     * should be used and then the host settings be added on top.
-     */
-    if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
-    {
-        PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
-        if (pVmcbNstGstCache->TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_NOTHING)
-            pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_NOTHING;
-        else
-            pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = pVmcbNstGstCache->TLBCtrl.n.u8TLBFlush;
-    }
-#else
-    RT_NOREF(pCtx);
-    pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_NOTHING;
-#endif
-
+    /*
+     * If the AMD CPU erratum 170, We need to flush the entire TLB for each world switch. Sad.
+     * This Host CPU requirement takes precedence.
+     */
     if (pVM->hm.s.svm.fAlwaysFlushTLB)
     {
-        /*
-         * This is the AMD erratum 170. We need to flush the entire TLB for each world switch. Sad.
-         */
         pCpu->uCurrentAsid               = 1;
         pVCpu->hm.s.uCurrentAsid         = 1;
@@ -948,56 +930,77 @@
             pVCpu->hm.s.idLastCpu = pCpu->idCpu;
     }
-    else if (pVCpu->hm.s.fForceTLBFlush)
-    {
-        /* Clear the VMCB Clean Bit for NP while flushing the TLB. See @bugref{7152}. */
-        pVmcb->ctrl.u64VmcbCleanBits    &= ~HMSVM_VMCB_CLEAN_NP;
-
-        if (fNewAsid)
-        {
-            ++pCpu->uCurrentAsid;
-            bool fHitASIDLimit = false;
-            if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
+    else
+    {
+#ifdef VBOX_WITH_NESTED_HWVIRT
+        /*
+         * Only if the nested hypervisor says it does not need to flush anything in the TLB,
+         * can we possibly apply it on the host. Otherwise, the nested-guest TLB flush setting
+         * should be used and then the host settings be added on top.
+         */
+        if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
+        {
+            PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
+            if (pVmcbNstGstCache->TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_NOTHING)
+                pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_NOTHING;
+            else
+                pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = pVmcbNstGstCache->TLBCtrl.n.u8TLBFlush;
+        }
+#else
+        RT_NOREF(pCtx);
+        pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_NOTHING;
+#endif
+        if (pVCpu->hm.s.fForceTLBFlush)
+        {
+            /* Clear the VMCB Clean Bit for NP while flushing the TLB. See @bugref{7152}. */
+            pVmcb->ctrl.u64VmcbCleanBits    &= ~HMSVM_VMCB_CLEAN_NP;
+
+            if (fNewAsid)
             {
-                pCpu->uCurrentAsid = 1;      /* Wraparound at 1; host uses 0 */
-                pCpu->cTlbFlushes++;         /* All VCPUs that run on this host CPU must use a new ASID. */
-                fHitASIDLimit      = true;
-
-                if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
+                ++pCpu->uCurrentAsid;
+                bool fHitASIDLimit = false;
+                if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
                 {
-                    pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
-                    pCpu->fFlushAsidBeforeUse = true;
+                    pCpu->uCurrentAsid = 1;      /* Wraparound at 1; host uses 0 */
+                    pCpu->cTlbFlushes++;         /* All VCPUs that run on this host CPU must use a new ASID. */
+                    fHitASIDLimit      = true;
+
+                    if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
+                    {
+                        pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
+                        pCpu->fFlushAsidBeforeUse = true;
+                    }
+                    else
+                    {
+                        pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
+                        pCpu->fFlushAsidBeforeUse = false;
+                    }
                 }
-                else
+
+                if (   !fHitASIDLimit
+                    && pCpu->fFlushAsidBeforeUse)
                 {
-                    pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
-                    pCpu->fFlushAsidBeforeUse = false;
+                    if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
+                        pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
+                    else
+                    {
+                        pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
+                        pCpu->fFlushAsidBeforeUse = false;
+                    }
                 }
+
+                pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
+                pVCpu->hm.s.idLastCpu    = pCpu->idCpu;
+                pVCpu->hm.s.cTlbFlushes  = pCpu->cTlbFlushes;
             }
-
-            if (   !fHitASIDLimit
-                && pCpu->fFlushAsidBeforeUse)
+            else
             {
                 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
                     pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
                 else
-                {
                     pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
-                    pCpu->fFlushAsidBeforeUse = false;
-                }
             }
 
-            pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
-            pVCpu->hm.s.idLastCpu    = pCpu->idCpu;
-            pVCpu->hm.s.cTlbFlushes  = pCpu->cTlbFlushes;
-        }
-        else
-        {
-            if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
-                pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
-            else
-                pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
-        }
-
-        pVCpu->hm.s.fForceTLBFlush = false;
+            pVCpu->hm.s.fForceTLBFlush = false;
+        }
     }
 
@@ -1010,5 +1013,5 @@
 
 #ifdef VBOX_WITH_NESTED_HWVIRT
-    Assert(pVmcb->ctrl.TLBCtrl.n.u8TLBFlush != SVM_TLB_FLUSH_NOTHING);
+    Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx) || pVmcb->ctrl.TLBCtrl.n.u8TLBFlush != SVM_TLB_FLUSH_NOTHING);
 #endif
 
@@ -1342,4 +1345,14 @@
 static void hmR0SvmLoadGuestControlRegsNested(PVMCPU pVCpu, PSVMVMCB pVmcbNstGst, PCPUMCTX pCtx)
 {
+    /*
+     * Guest CR0.
+     */
+    if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
+    {
+        pVmcbNstGst->guest.u64CR0 = pCtx->cr0;
+        pVmcbNstGst->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
+        HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR0);
+    }
+
     /*
      * Guest CR2.
@@ -2006,5 +2019,6 @@
                ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
 
-    Log4(("Load: CS:RIP=%04x:%RX64 EFL=%#x SS:RSP=%04x:%RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->eflags.u, pCtx->ss.Sel, pCtx->rsp));
+    Log4(("hmR0SvmLoadGuestState: CS:RIP=%04x:%RX64 EFL=%#x CR0=%#RX32 CR3=%#RX32 CR4=%#RX32\n", pCtx->cs.Sel, pCtx->rip,
+          pCtx->eflags.u, pCtx->cr0, pCtx->cr3, pCtx->cr4));
     STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
     return rc;
@@ -2057,4 +2071,7 @@
         hmR0SvmVmRunCacheVmcb(pVCpu, pCtx);
 
+        PSVMVMCB     pVmcbNstGst     = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
+        PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
+
         /*
          * The IOPM of the nested-guest can be ignored because the the guest always
@@ -2062,7 +2079,5 @@
          * into the nested-guest one and swap it back on the #VMEXIT.
          */
-        PSVMVMCB     pVmcbNstGst     = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
-        PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
-        pVmcbNstGstCtrl->u64IOPMPhysAddr  = g_HCPhysIOBitmap;
+        pVmcbNstGstCtrl->u64IOPMPhysAddr = g_HCPhysIOBitmap;
 
         /*
@@ -2138,5 +2153,6 @@
                ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
 
-    Log4(("Load: CS:RIP=%04x:%RX64 EFL=%#x SS:RSP=%04x:%RX64\n", pCtx->cs.Sel, pCtx->rip, pCtx->eflags.u, pCtx->ss.Sel, pCtx->rsp));
+    Log4(("hmR0SvmLoadGuestStateNested: CS:RIP=%04x:%RX64 EFL=%#x CR0=%#RX32 CR3=%#RX32 CR4=%#RX32\n", pCtx->cs.Sel, pCtx->rip,
+          pCtx->eflags.u, pCtx->cr0, pCtx->cr3, pCtx->cr4));
     STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
     return rc;
@@ -2166,4 +2182,6 @@
         if (!CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
             hmR0SvmLoadSharedCR0(pVCpu, pVmcb, pCtx);
+        else
+            Assert(pVmcb->guest.u64CR0 == pCtx->cr0);
 #else
         hmR0SvmLoadSharedCR0(pVCpu, pVmcb, pCtx);
@@ -2227,7 +2245,7 @@
     if (CPUMIsGuestInNestedHwVirtMode(pMixedCtx))
     {
-        pMixedCtx->cr3        = pVmcb->guest.u64CR3;
-        pMixedCtx->cr4        = pVmcb->guest.u64CR4;
-        pMixedCtx->cr0        = pVmcb->guest.u64CR0;
+        pMixedCtx->cr3    = pVmcb->guest.u64CR3;
+        pMixedCtx->cr4    = pVmcb->guest.u64CR4;
+        pMixedCtx->cr0    = pVmcb->guest.u64CR0;
     }
 #endif
@@ -4027,4 +4045,30 @@
 #ifdef VBOX_WITH_NESTED_HWVIRT
 /**
+ * Wrapper for running the nested-guest code in AMD-V.
+ *
+ * @returns VBox strict status code.
+ * @param   pVM         The cross context VM structure.
+ * @param   pVCpu       The cross context virtual CPU structure.
+ * @param   pCtx        Pointer to the guest-CPU context.
+ *
+ * @remarks No-long-jump zone!!!
+ */
+DECLINLINE(int) hmR0SvmRunGuestNested(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
+{
+    /*
+     * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
+     * using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
+     * Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
+     */
+#ifdef VBOX_WITH_KERNEL_USING_XMM
+    return hmR0SVMRunWrapXMM(pVCpu->hm.s.svm.HCPhysVmcbHost, pCtx->hwvirt.svm.HCPhysVmcb, pCtx, pVM, pVCpu,
+                             pVCpu->hm.s.svm.pfnVMRun);
+#else
+    return pVCpu->hm.s.svm.pfnVMRun(pVCpu->hm.s.svm.HCPhysVmcbHost, pCtx->hwvirt.svm.HCPhysVmcb, pCtx, pVM, pVCpu);
+#endif
+}
+
+
+/**
  * Performs some essential restoration of state after running nested-guest code in
  * AMD-V.
@@ -4393,5 +4437,6 @@
          */
         hmR0SvmPreRunGuestCommittedNested(pVM, pVCpu, pCtx, &SvmTransient);
-        rc = hmR0SvmRunGuest(pVM, pVCpu, pCtx);
+
+        rc = hmR0SvmRunGuestNested(pVM, pVCpu, pCtx);
 
         /* Restore any residual host-state and save any bits shared between host
@@ -4399,4 +4444,6 @@
         hmR0SvmPostRunGuestNested(pVM, pVCpu, pCtx, &SvmTransient, rc);
 
+        /** @todo This needs some work... we probably should cause a \#VMEXIT on
+         *        SVM_EXIT_INVALID and handle rc != VINF_SUCCESS differently. */
         if (RT_UNLIKELY(   rc != VINF_SUCCESS                               /* Check for VMRUN errors. */
                         || SvmTransient.u64ExitCode == SVM_EXIT_INVALID))   /* Check for invalid guest-state errors. */
@@ -4699,6 +4746,5 @@
         case SVM_EXIT_INTR:
         {
-            if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_INTR)
-                return hmR0SvmExecVmexit(pVCpu, pCtx);
+            /* We shouldn't direct physical interrupts to the nested-guest. */
             return hmR0SvmExitIntr(pVCpu, pCtx, pSvmTransient);
         }
@@ -5754,24 +5800,4 @@
 {
     /*
-     * Disable the global interrupt flag to not cause any interrupts or NMIs
-     * in the guest.
-     */
-    pCtx->hwvirt.svm.fGif = 0;
-
-    /*
-     * Restore the guest's "host" state.
-     */
-    CPUMSvmVmExitRestoreHostState(pCtx);
-
-    /*
-     * Restore the guest's force-flags.
-     */
-    if (pCtx->hwvirt.fLocalForcedActions)
-    {
-        VMCPU_FF_SET(pVCpu, pCtx->hwvirt.fLocalForcedActions);
-        pCtx->hwvirt.fLocalForcedActions = 0;
-    }
-
-    /*
      * Restore the modifications we did to the nested-guest VMCB in order
      * to execute the nested-guest in SVM R0.
@@ -5784,5 +5810,5 @@
 
     /*
-     * Write the nested-guest VMCB back to nested-guest memory.
+     * Write the nested-guest VMCB back to guest memory.
      */
     RTGCPHYS const GCPhysVmcb = pCtx->hwvirt.svm.GCPhysVmcb;
@@ -5795,4 +5821,24 @@
     memset(pVmcbNstGstCtrl, 0, sizeof(*pVmcbNstGstCtrl));
     Assert(!CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
+
+    /*
+     * Disable the global interrupt flag to not cause any interrupts or NMIs
+     * in the guest.
+     */
+    pCtx->hwvirt.svm.fGif = 0;
+
+    /*
+     * Restore the guest's "host" state.
+     */
+    CPUMSvmVmExitRestoreHostState(pCtx);
+
+    /*
+     * Restore the guest's force-flags.
+     */
+    if (pCtx->hwvirt.fLocalForcedActions)
+    {
+        VMCPU_FF_SET(pVCpu, pCtx->hwvirt.fLocalForcedActions);
+        pCtx->hwvirt.fLocalForcedActions = 0;
+    }
 
     /*
@@ -5914,9 +5960,10 @@
          * IO permission bitmap (IOPM).
          */
-        RTHCPHYS HCPhysNstGstMsrpm;
-        rc = PGMPhysGCPhys2HCPhys(pVM, pVmcbNstGstCtrl->u64MSRPMPhysAddr, &HCPhysNstGstMsrpm);
+        RTGCPHYS const GCPhysIOBitmap = pVmcbNstGstCtrl->u64MSRPMPhysAddr;
+        rc = PGMPhysSimpleReadGCPhys(pVM, pCtx->hwvirt.svm.CTX_SUFF(pvIoBitmap), GCPhysIOBitmap,
+                                     SVM_IOPM_PAGES * X86_PAGE_4K_SIZE);
         if (RT_FAILURE(rc))
         {
-            Log(("hmR0SvmExecVmrun: Failed reading the MSR permission bitmap at %#RGp. rc=%Rrc\n", GCPhysMsrBitmap, rc));
+            Log(("hmR0SvmExecVmrun: Failed reading the IO permission bitmap at %#RGp. rc=%Rrc\n", GCPhysIOBitmap, rc));
             pVmcbNstGstCtrl->u64ExitCode = SVM_EXIT_INVALID;
             return hmR0SvmExecVmexit(pVCpu, pCtx);
@@ -6034,4 +6081,5 @@
         pCtx->hwvirt.svm.fGif = 1;
 
+        Log4(("hmR0SvmExecVmrun: CR0=%#RX32 CR3=%#RX64 CR4=%#RX32\n", pCtx->cr0, pCtx->cr3, pCtx->cr4));
         return hmR0SvmNstGstWorldSwitch(pVCpu, pCtx);
     }
