Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 51221)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 51222)
@@ -45,4 +45,5 @@
 # define HMVMX_ALWAYS_SWAP_FPU_STATE
 # define HMVMX_ALWAYS_FLUSH_TLB
+# define HMVMX_ALWAYS_SWAP_EFER
 #endif
 
@@ -1303,7 +1304,4 @@
  * auto-load/store MSR area in the VMCS.
  *
- * Does not fail if the MSR in @a uMsr is not found in the auto-load/store MSR
- * area.
- *
  * @returns VBox status code.
  * @param   pVCpu       Pointer to the VMCPU.
@@ -1328,5 +1326,5 @@
             /* Remove it by swapping the last MSR in place of it, and reducing the count. */
             PVMXAUTOMSR pLastGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
-            pLastGuestMsr            += cMsrs;
+            pLastGuestMsr            += cMsrs - 1;
             pGuestMsr->u32Msr         = pLastGuestMsr->u32Msr;
             pGuestMsr->u64Value       = pLastGuestMsr->u64Value;
@@ -1334,5 +1332,5 @@
             PVMXAUTOMSR pHostMsr     = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
             PVMXAUTOMSR pLastHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
-            pLastHostMsr            += cMsrs;
+            pLastHostMsr            += cMsrs - 1;
             pHostMsr->u32Msr         = pLastHostMsr->u32Msr;
             pHostMsr->u64Value       = pLastHostMsr->u64Value;
@@ -1352,7 +1350,10 @@
         if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
             hmR0VmxSetMsrPermission(pVCpu, uMsr, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
-    }
-
-    return VINF_SUCCESS;
+
+        Log4(("Removed MSR %#RX32 new cMsrs=%u\n", uMsr, pVCpu->hm.s.vmx.cMsrs));
+        return VINF_SUCCESS;
+    }
+
+    return VERR_NOT_FOUND;
 }
 
@@ -1397,5 +1398,13 @@
     {
         AssertReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr);
-        pHostMsr->u64Value = ASMRdMsr(pHostMsr->u32Msr);
+
+        /*
+         * Performance hack for the host EFER MSR. We use the cached value rather than re-read it.
+         * Strict builds will catch mismatches in hmR0VmxCheckAutoLoadStoreMsrs(). See @bugref{7368}.
+         */
+        if (pHostMsr->u32Msr == MSR_K6_EFER)
+            pHostMsr->u64Value = pVCpu->CTX_SUFF(pVM)->hm.s.vmx.u64HostEfer;
+        else
+            pHostMsr->u64Value = ASMRdMsr(pHostMsr->u32Msr);
     }
 
@@ -1646,10 +1655,10 @@
     {
         /* Verify that the MSRs are paired properly and that the host MSR has the correct value. */
-        AssertMsgReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr, ("HostMsr=%#RX32 GuestMsr=%#RX32\n", pHostMsr->u32Msr,
-                                                                    pGuestMsr->u32Msr));
+        AssertMsgReturnVoid(pHostMsr->u32Msr == pGuestMsr->u32Msr, ("HostMsr=%#RX32 GuestMsr=%#RX32 cMsrs=%u\n", pHostMsr->u32Msr,
+                                                                    pGuestMsr->u32Msr, cMsrs));
 
         uint64_t u64Msr = ASMRdMsr(pHostMsr->u32Msr);
-        AssertMsgReturnVoid(pHostMsr->u64Value == u64Msr, ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64\n", pHostMsr->u32Msr,
-                                                           pHostMsr->u64Value, u64Msr));
+        AssertMsgReturnVoid(pHostMsr->u64Value == u64Msr, ("u32Msr=%#RX32 VMCS Value=%#RX64 ASMRdMsr=%#RX64 cMsrs=%u\n",
+                                                           pHostMsr->u32Msr, pHostMsr->u64Value, u64Msr, cMsrs));
 
         /* Verify that the permissions are as expected in the MSR bitmap. */
@@ -1660,8 +1669,16 @@
             rc = hmR0VmxGetMsrPermission(pVCpu, pGuestMsr->u32Msr, &enmRead, &enmWrite);
             AssertMsgReturnVoid(rc == VINF_SUCCESS, ("hmR0VmxGetMsrPermission! failed. rc=%Rrc\n", rc));
-            AssertMsgReturnVoid(enmRead == VMXMSREXIT_PASSTHRU_READ, ("u32Msr=%#RX32 No passthru read permission!\n",
-                                                                      pGuestMsr->u32Msr));
-            AssertMsgReturnVoid(enmWrite == VMXMSREXIT_PASSTHRU_WRITE, ("u32Msr=%#RX32 No passthru write permission!\n",
-                                                                        pGuestMsr->u32Msr));
+            if (pGuestMsr->u32Msr == MSR_K6_EFER)
+            {
+                AssertMsgReturnVoid(enmRead  == VMXMSREXIT_INTERCEPT_READ,  ("Passthru read for EFER!?\n"));
+                AssertMsgReturnVoid(enmWrite == VMXMSREXIT_INTERCEPT_WRITE, ("Passthru write for EFER!?\n"));
+            }
+            else
+            {
+                AssertMsgReturnVoid(enmRead  == VMXMSREXIT_PASSTHRU_READ,  ("u32Msr=%#RX32 cMsrs=%u No passthru read!\n",
+                                                                            pGuestMsr->u32Msr, cMsrs));
+                AssertMsgReturnVoid(enmWrite == VMXMSREXIT_PASSTHRU_WRITE, ("u32Msr=%#RX32 cMsrs=%u No passthru write!\n",
+                                                                            pGuestMsr->u32Msr, cMsrs));
+            }
         }
     }
@@ -3155,5 +3172,7 @@
 
     /*
+     * Host EFER MSR.
      * If the CPU supports the newer VMCS controls for managing EFER, use it.
+     * Otherwise it's done as part of auto-load/store MSR area in the VMCS, see hmR0VmxLoadGuestMsrs().
      */
 #if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
@@ -3193,4 +3212,7 @@
 static bool hmR0VmxShouldSwapEferMsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
 {
+#ifdef HMVMX_ALWAYS_SWAP_EFER
+    return true;
+#endif
     PVM      pVM          = pVCpu->CTX_SUFF(pVM);
     uint64_t u64HostEfer  = pVM->hm.s.vmx.u64HostEfer;
@@ -3201,5 +3223,5 @@
      * guest's SYSCALL behaviour isn't screwed. See @bugref{7386}.
      */
-    if (   pVM->hm.s.fAllow64BitGuests
+    if (   CPUMIsGuestInLongMode(pVCpu)
         && (u64GuestEfer & MSR_K6_EFER_SCE) != (u64HostEfer & MSR_K6_EFER_SCE))
     {
@@ -4655,4 +4677,5 @@
     if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_VMX_GUEST_AUTO_MSRS))
     {
+        /* For 64-bit hosts, we load/restore them lazily, see hmR0VmxLazyLoadGuestMsrs(). */
 #if HC_ARCH_BITS == 32 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
         if (pVM->hm.s.fAllow64BitGuests)
@@ -4698,11 +4721,34 @@
     {
 #if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
-        if (   HMVMX_IS_64BIT_HOST_MODE()
-            && pVM->hm.s.vmx.fSupportsVmcsEfer
-            && hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))  /* Not really needed here, but avoids a VM-write as a nested guest. */
-        {
-            int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pMixedCtx->msrEFER);
-            AssertRCReturn(rc,rc);
-            Log4(("Load: VMX_VMCS64_GUEST_EFER_FULL=%#RX64\n", pMixedCtx->msrEFER));
+        if (HMVMX_IS_64BIT_HOST_MODE())
+        {
+            /*
+             * If the CPU supports VMCS controls for swapping EFER, use it. Otherwise, we have no option
+             * but to use the auto-load store MSR area in the VMCS for swapping EFER. See @bugref{7368}.
+             */
+            if (pVM->hm.s.vmx.fSupportsVmcsEfer)
+            {
+                /* Not strictly necessary to check hmR0VmxShouldSwapEferMsr() here, but it avoids
+                   one VM-write when we're a nested guest. */
+                if (hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
+                {
+                    int rc = VMXWriteVmcs64(VMX_VMCS64_GUEST_EFER_FULL, pMixedCtx->msrEFER);
+                    AssertRCReturn(rc,rc);
+                    Log4(("Load: VMX_VMCS64_GUEST_EFER_FULL=%#RX64\n", pMixedCtx->msrEFER));
+                }
+            }
+            else
+            {
+                if (hmR0VmxShouldSwapEferMsr(pVCpu, pMixedCtx))
+                {
+                    hmR0VmxAddAutoLoadStoreMsr(pVCpu, MSR_K6_EFER, pMixedCtx->msrEFER, false /* fUpdateHostMsr */);
+                    /* We need to intercept reads too, see @bugref{7386} comment #16. */
+                    hmR0VmxSetMsrPermission(pVCpu, MSR_K6_EFER, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
+                    Log4(("Load: MSR[--]: u32Msr=%#RX32 u64Value=%#RX64 cMsrs=%u\n", MSR_K6_EFER, pMixedCtx->msrEFER,
+                          pVCpu->hm.s.vmx.cMsrs));
+                }
+                else
+                    hmR0VmxRemoveAutoLoadStoreMsr(pVCpu, MSR_K6_EFER);
+            }
         }
 #endif
@@ -6137,7 +6183,14 @@
             case MSR_K8_SF_MASK:        pMixedCtx->msrSFMASK       = pMsr->u64Value;             break;
             case MSR_K8_KERNEL_GS_BASE: pMixedCtx->msrKERNELGSBASE = pMsr->u64Value;             break;
+#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
+            case MSR_K6_EFER:
+            {
+                if (HMVMX_IS_64BIT_HOST_MODE())  /* Nothing to do here since we intercept writes, see hmR0VmxLoadGuestMsrs(). */
+                    break;
+            }
+#endif
             default:
             {
-                AssertFailed();
+                AssertMsgFailed(("Unexpected MSR in auto-load/store area. uMsr=%#RX32 cMsrs=%u\n", pMsr->u32Msr, cMsrs));
                 return VERR_HM_UNEXPECTED_LD_ST_MSR;
             }
@@ -7115,4 +7168,5 @@
         }
 #endif
+        /* Update auto-load/store host MSRs values when we re-enter VT-x (as we could be on a different CPU). */
         pVCpu->hm.s.vmx.fUpdatedHostMsrs = false;
         VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
@@ -10291,5 +10345,6 @@
     if (pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS)
     {
-        if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
+        if (   hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx)
+            && pMixedCtx->ecx != MSR_K6_EFER)
         {
             AssertMsgFailed(("Unexpected RDMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n", pMixedCtx->ecx));
@@ -10382,4 +10437,5 @@
                 case MSR_K8_FS_BASE:        /* no break */
                 case MSR_K8_GS_BASE:        HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS);     break;
+                case MSR_K6_EFER:           HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR);         break;
                 default:
                 {
@@ -10415,4 +10471,12 @@
                     if (hmR0VmxIsAutoLoadStoreGuestMsr(pVCpu, pMixedCtx->ecx))
                     {
+#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
+                        /* EFER writes are always intercepted, see hmR0VmxLoadGuestMsrs(). */
+                        if (   HMVMX_IS_64BIT_HOST_MODE()
+                            && pMixedCtx->ecx == MSR_K6_EFER)
+                        {
+                            break;
+                        }
+#endif
                         AssertMsgFailed(("Unexpected WRMSR for an MSR in the auto-load/store area in the VMCS. ecx=%#RX32\n",
                                          pMixedCtx->ecx));
