Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 79647)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 79648)
@@ -924,94 +924,67 @@
 
 
-#if 0
-/**
- * Checks whether one of the given Processor-based VM-execution controls are set.
- *
- * @returns @c true if set, @c false otherwise.
+/**
+ * Sets the given Processor-based VM-execution controls.
+ *
+ * @param   pVmxTransient   The VMX-transient structure.
+ * @param   uProcCtls       The Processor-based VM-execution controls to set.
+ */
+static void hmR0VmxSetProcCtlsVmcs(PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
+{
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    if ((pVmcsInfo->u32ProcCtls & uProcCtls) != uProcCtls)
+    {
+        pVmcsInfo->u32ProcCtls |= uProcCtls;
+        int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
+        AssertRC(rc);
+    }
+}
+
+
+/**
+ * Removes the given Processor-based VM-execution controls.
+ *
  * @param   pVCpu           The cross context virtual CPU structure.
  * @param   pVmxTransient   The VMX-transient structure.
- * @param   uProcCtls       The Processor-based VM-execution controls to check.
- *
- * @remarks This will not check merged controls when executing a nested-guest
- *          but the original control specified by the guest hypervisor.
- */
-static bool hmR0VmxIsProcCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
-{
-    if (!pVmxTransient->fIsNestedGuest)
-    {
-        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
-        return RT_BOOL(pVmcsInfo->u32ProcCtls & uProcCtls);
-    }
-    return CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls);
-}
-
-
-/**
- * Checks whether one of the given Secondary Processor-based VM-execution controls
- * are set.
- *
- * @returns @c true if set, @c false otherwise.
- * @param   pVCpu           The cross context virtual CPU structure.
- * @param   pVmxTransient   The VMX-transient structure.
- * @param   uProcCtls2      The Secondary Processor-based VM-execution controls to
- *                          check.
- *
- * @remarks This will not check merged controls when executing a nested-guest
- *          but the original control specified by the guest hypervisor.
- */
-static bool hmR0VmxIsProcCtls2Set(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uProcCtls2)
-{
-    if (!pVmxTransient->fIsNestedGuest)
-    {
-        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
-        return RT_BOOL(pVmcsInfo->u32ProcCtls2 & uProcCtls2);
-    }
-    return CPUMIsGuestVmxProcCtls2Set(pVCpu, &pVCpu->cpum.GstCtx, uProcCtls2);
-}
-
-
-/**
- * Checks whether one of the given VM-entry controls are set.
- *
- * @returns @c true if set, @c false otherwise.
- * @param   pVCpu           The cross context virtual CPU structure.
- * @param   pVmxTransient   The VMX-transient structure.
- * @param   uEntryCtls      The VM-entry controls to check.
- *
- * @remarks This will not check merged controls when executing a nested-guest
- *          but the original control specified by the guest hypervisor.
- */
-static bool hmR0VmxIsEntryCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uEntryCtls)
-{
-    if (!pVmxTransient->fIsNestedGuest)
-    {
-        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
-        return RT_BOOL(pVmcsInfo->u32EntryCtls & uEntryCtls);
-    }
-    return CPUMIsGuestVmxEntryCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uEntryCtls);
-}
-
-
-/**
- * Checks whether one of the given VM-exit controls are set.
- *
- * @returns @c true if set, @c false otherwise.
- * @param   pVCpu           The cross context virtual CPU structure.
- * @param   pVmxTransient   The VMX-transient structure.
- * @param   uExitCtls       The VM-exit controls to check.
- *
- * @remarks This will not check merged controls when executing a nested-guest
- *          but the original control specified by the guest hypervisor.
- */
-static bool hmR0VmxIsExitCtlsSet(PVMCPU pVCpu, PCVMXTRANSIENT pVmxTransient, uint32_t uExitCtls)
-{
-    if (!pVmxTransient->fIsNestedGuest)
-    {
-        PCVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
-        return RT_BOOL(pVmcsInfo->u32ExitCtls & uExitCtls);
-    }
-    return CPUMIsGuestVmxExitCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, uExitCtls);
-}
+ * @param   uProcCtls       The Processor-based VM-execution controls to remove.
+ *
+ * @remarks When executing a nested-guest, this will not remove any of the specified
+ *          controls if the guest hypervisor has set any one of them.
+ */
+static void hmR0VmxRemoveProcCtlsVmcs(PVMCPU pVCpu, PVMXTRANSIENT pVmxTransient, uint32_t uProcCtls)
+{
+#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
+    bool const fRemoveCtls = !pVmxTransient->fIsNestedGuest
+                           ? true
+                           : !CPUMIsGuestVmxProcCtlsSet(pVCpu, &pVCpu->cpum.GstCtx, VMX_PROC_CTLS_RDTSC_EXIT);
+#else
+    bool const fRemoveCtls = true;
 #endif
+    PVMXVMCSINFO pVmcsInfo = pVmxTransient->pVmcsInfo;
+    if (   fRemoveCtls
+        && (pVmcsInfo->u32ProcCtls & uProcCtls))
+    {
+        pVmcsInfo->u32ProcCtls &= ~uProcCtls;
+        int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, pVmcsInfo->u32ProcCtls);
+        AssertRC(rc);
+    }
+}
+
+
+/**
+ * Sets the TSC offset for the current VMCS.
+ *
+ * @param   uTscOffset  The TSC offset to set.
+ * @param   pVmcsInfo   The VMCS info. object.
+ */
+static void hmR0VmxSetTscOffsetVmcs(PVMXVMCSINFO pVmcsInfo, uint64_t uTscOffset)
+{
+    if (pVmcsInfo->u64TscOffset != uTscOffset)
+    {
+        int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
+        AssertRC(rc);
+        pVmcsInfo->u64TscOffset = uTscOffset;
+    }
+}
 
 
@@ -7524,5 +7497,4 @@
     }
 
-    uint32_t uProcCtls = pVmcsInfo->u32ProcCtls;
     if (   fOffsettedTsc
         && RT_LIKELY(!pVCpu->hm.s.fDebugWantRdTscExit))
@@ -7530,31 +7502,11 @@
         if (pVmxTransient->fIsNestedGuest)
             uTscOffset = CPUMApplyNestedGuestTscOffset(pVCpu, uTscOffset);
-        if (pVmcsInfo->u64TscOffset != uTscOffset)
-        {
-            int rc = VMXWriteVmcs64(VMX_VMCS64_CTRL_TSC_OFFSET_FULL, uTscOffset);
-            AssertRC(rc);
-            pVmcsInfo->u64TscOffset = uTscOffset;
-        }
-
-        if (uProcCtls & VMX_PROC_CTLS_RDTSC_EXIT)
-        {
-            uProcCtls &= ~VMX_PROC_CTLS_RDTSC_EXIT;
-            int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
-            AssertRC(rc);
-            pVmcsInfo->u32ProcCtls = uProcCtls;
-        }
-        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
+        hmR0VmxSetTscOffsetVmcs(pVmcsInfo, uTscOffset);
+        hmR0VmxRemoveProcCtlsVmcs(pVCpu, pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
     }
     else
     {
         /* We can't use TSC-offsetting (non-fixed TSC, warp drive active etc.), VM-exit on RDTSC(P). */
-        if (!(uProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
-        {
-            uProcCtls |= VMX_PROC_CTLS_RDTSC_EXIT;
-            int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_PROC_EXEC, uProcCtls);
-            AssertRC(rc);
-            pVmcsInfo->u32ProcCtls = uProcCtls;
-        }
-        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
+        hmR0VmxSetProcCtlsVmcs(pVmxTransient, VMX_PROC_CTLS_RDTSC_EXIT);
     }
 }
@@ -9345,5 +9297,5 @@
                 /*
                  * If we eventually support nested-guest execution without unrestricted guest execution,
-                 * we should clear fInterceptEvents here.
+                 * we should set fInterceptEvents here.
                  */
                 Assert(!pVmxTransient->fIsNestedGuest);
@@ -9377,6 +9329,5 @@
      * Update guest CR2 if this is a page-fault.
      */
-    if (   VMX_ENTRY_INT_INFO_TYPE(u32IntInfo) == VMX_EXIT_INT_INFO_TYPE_HW_XCPT
-        && uVector == X86_XCPT_PF)
+    if (VMX_ENTRY_INT_INFO_IS_XCPT_PF(u32IntInfo))
         pCtx->cr2 = GCPtrFault;
 
@@ -10023,8 +9974,7 @@
 {
 #define HMVMX_ERROR_BREAK(err)              { uError = (err); break; }
-#define HMVMX_CHECK_BREAK(expr, err)        if (!(expr)) { \
-                                                uError = (err); \
-                                                break; \
-                                            } else do { } while (0)
+#define HMVMX_CHECK_BREAK(expr, err)        do { \
+                                                if (!(expr)) { uError = (err); break; } \
+                                            } while (0)
 
     int        rc;
@@ -10135,9 +10085,6 @@
         rc = VMXReadVmcs32(VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO, &u32EntryInfo);
         AssertRCBreak(rc);
-        if (   VMX_ENTRY_INT_INFO_IS_VALID(u32EntryInfo)
-            && VMX_ENTRY_INT_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INT_INFO_TYPE_EXT_INT)
-        {
+        if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
             HMVMX_CHECK_BREAK(u32Eflags & X86_EFL_IF, VMX_IGS_RFLAGS_IF_INVALID);
-        }
 
         /*
@@ -10500,19 +10447,16 @@
                           || !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
                           VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID);
-        if (VMX_ENTRY_INT_INFO_IS_VALID(u32EntryInfo))
-        {
-            if (VMX_ENTRY_INT_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INT_INFO_TYPE_EXT_INT)
-            {
-                HMVMX_CHECK_BREAK(   !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
-                                  && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
-                                  VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
-            }
-            else if (VMX_ENTRY_INT_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INT_INFO_TYPE_NMI)
-            {
-                HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
-                                  VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
-                HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
-                                  VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
-            }
+        if (VMX_ENTRY_INT_INFO_IS_EXT_INT(u32EntryInfo))
+        {
+            HMVMX_CHECK_BREAK(   !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI)
+                              && !(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
+                              VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID);
+        }
+        else if (VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
+        {
+            HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS),
+                              VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID);
+            HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_STI),
+                              VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID);
         }
         /** @todo Assumes the processor is not in SMM. */
@@ -10523,6 +10467,5 @@
                              VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID);
         if (   (pVmcsInfo->u32PinCtls & VMX_PIN_CTLS_VIRT_NMI)
-            && VMX_ENTRY_INT_INFO_IS_VALID(u32EntryInfo)
-            && VMX_ENTRY_INT_INFO_TYPE(u32EntryInfo) == VMX_EXIT_INT_INFO_TYPE_NMI)
+            && VMX_ENTRY_INT_INFO_IS_XCPT_NMI(u32EntryInfo))
         {
             HMVMX_CHECK_BREAK(!(u32IntrState & VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI),
@@ -11324,4 +11267,11 @@
     }
 
+    /* Record statistics of how often we use TSC offsetting as opposed to intercepting RDTSC/P. */
+    bool const fIsRdtscIntercepted = RT_BOOL(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT);
+    if (!fIsRdtscIntercepted)
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
+    else
+        STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
+
     ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true);    /* Used for TLB flushing, set this across the world switch. */
     hmR0VmxFlushTaggedTlb(pHostCpu, pVCpu, pVmcsInfo);          /* Invalidate the appropriate guest entries from the TLB. */
@@ -11343,5 +11293,5 @@
      */
     if (    (pVmcsInfo->u32ProcCtls2 & VMX_PROC_CTLS2_RDTSCP)
-        && !(pVmcsInfo->u32ProcCtls & VMX_PROC_CTLS_RDTSC_EXIT))
+        && !fIsRdtscIntercepted)
     {
         hmR0VmxImportGuestState(pVCpu, pVmcsInfo, CPUMCTX_EXTRN_TSC_AUX);
