Index: /trunk/include/VBox/vmm/gim.h
===================================================================
--- /trunk/include/VBox/vmm/gim.h	(revision 52005)
+++ /trunk/include/VBox/vmm/gim.h	(revision 52006)
@@ -200,5 +200,6 @@
 VMMDECL(bool)               GIMIsEnabled(PVM pVM);
 VMMDECL(GIMPROVIDERID)      GIMGetProvider(PVM pVM);
-VMMDECL(bool)               GIMIsParavirtTscEnabled(PVM pVM);
+VMM_INT_DECL(bool)          GIMIsParavirtTscEnabled(PVM pVM);
+VMM_INT_DECL(bool)          GIMAreHypercallsEnabled(PVMCPU pVCpu);
 VMM_INT_DECL(int)           GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
 VMM_INT_DECL(int)           GIMReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
Index: /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp	(revision 52005)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp	(revision 52006)
@@ -57,4 +57,27 @@
 
 /**
+ * Returns whether the guest has configured and enabled calls to the hypervisor.
+ *
+ * @returns true if hypercalls are enabled and usable, false otherwise.
+ * @param   pVCpu           Pointer to the VMCPU.
+ */
+VMM_INT_DECL(bool) GIMAreHypercallsEnabled(PVMCPU pVCpu)
+{
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    if (!GIMIsEnabled(pVM))
+        return false;
+
+    switch (pVM->gim.s.enmProviderId)
+    {
+        case GIMPROVIDERID_HYPERV:
+            return GIMHvAreHypercallsEnabled(pVCpu);
+
+        default:
+            return false;
+    }
+}
+
+
+/**
  * Implements a GIM hypercall with the provider configured for the VM.
  *
@@ -66,6 +89,8 @@
 {
     PVM pVM = pVCpu->CTX_SUFF(pVM);
-    Assert(GIMIsEnabled(pVM));
     VMCPU_ASSERT_EMT(pVCpu);
+
+    if (RT_UNLIKELY(!GIMIsEnabled(pVM)))
+        return VERR_GIM_NOT_ENABLED;
 
     switch (pVM->gim.s.enmProviderId)
@@ -80,5 +105,14 @@
 }
 
-VMMDECL(bool) GIMIsParavirtTscEnabled(PVM pVM)
+
+/**
+ * Returns whether the guest has configured and setup the use of paravirtualized
+ * TSC. Paravirtualized TSCs are per-VM and the rest of the execution engine
+ * logic relies on that.
+ *
+ * @returns true if enabled and usable, false otherwise.
+ * @param   pVM         Pointer to the VM.
+ */
+VMM_INT_DECL(bool) GIMIsParavirtTscEnabled(PVM pVM)
 {
     if (!pVM->gim.s.fEnabled)
Index: /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 52005)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 52006)
@@ -44,5 +44,23 @@
 VMM_INT_DECL(int) GIMHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
 {
-    return VINF_SUCCESS;
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    if (!MSR_GIM_HV_HYPERCALL_IS_ENABLED(pVM->gim.s.u.Hv.u64HypercallMsr))
+        return VERR_GIM_HYPERCALLS_NOT_ENABLED;
+
+    /** @todo Handle hypercalls. Fail for now */
+    return VERR_GIM_IPE_3;
+}
+
+
+/**
+ * Returns whether the guest has configured and enabled the use of Hyper-V's
+ * hypercall interface.
+ *
+ * @returns true if hypercalls are enabled, false otherwise.
+ * @param   pVCpu       Pointer to the VMCPU.
+ */
+VMM_INT_DECL(bool) GIMHvAreHypercallsEnabled(PVMCPU pVCpu)
+{
+    return MSR_GIM_HV_HYPERCALL_IS_ENABLED(pVCpu->CTX_SUFF(pVM)->gim.s.u.Hv.u64HypercallMsr);
 }
 
Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 52005)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 52006)
@@ -3831,4 +3831,8 @@
  *
  * @returns VBox status code.
+ * @retval VINF_SUCCESS if the access was handled successfully.
+ * @retval VERR_NOT_FOUND if no patch record for this eip could be found.
+ * @retval VERR_SVM_UNEXPECTED_PATCH_TYPE if the found patch type is invalid.
+ *
  * @param   pVM         Pointer to the VM.
  * @param   pVCpu       Pointer to the VMCPU.
@@ -3838,4 +3842,5 @@
 {
     Log4(("Emulated VMMCall TPR access replacement at RIP=%RGv\n", pCtx->rip));
+    bool fPatchFound = false;
     for (;;)
     {
@@ -3847,4 +3852,5 @@
             break;
 
+        fPatchFound = true;
         switch (pPatch->enmType)
         {
@@ -3888,5 +3894,7 @@
     }
 
-    return VINF_SUCCESS;
+    if (fPatchFound)
+        return VINF_SUCCESS;
+    return VERR_NOT_FOUND;
 }
 
@@ -4896,8 +4904,17 @@
     HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
 
+    /* First check if this is a patched VMMCALL for mov TPR */
     int rc = hmR0SvmEmulateMovTpr(pVCpu->CTX_SUFF(pVM), pVCpu, pCtx);
-    if (RT_LIKELY(rc == VINF_SUCCESS))
+    if (rc == VINF_SUCCESS)
         HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
-    else
+    else if (rc == VERR_NOT_FOUND)
+    {
+        /* Handle GIM provider hypercalls. */
+        rc = VERR_NOT_SUPPORTED;
+        if (GIMAreHypercallsEnabled(pVCpu))
+            rc = GIMHypercall(pVCpu, pCtx);
+    }
+
+    if (rc != VINF_SUCCESS)
         hmR0SvmSetPendingXcptUD(pVCpu);
     return VINF_SUCCESS;
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 52005)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 52006)
@@ -371,4 +371,5 @@
 static FNVMXEXITHANDLER hmR0VmxExitInvlpg;
 static FNVMXEXITHANDLER hmR0VmxExitRdpmc;
+static FNVMXEXITHANDLER hmR0VmxExitVmcall;
 static FNVMXEXITHANDLER hmR0VmxExitRdtsc;
 static FNVMXEXITHANDLER hmR0VmxExitRsm;
@@ -440,5 +441,5 @@
  /* 16  VMX_EXIT_RDTSC                   */  hmR0VmxExitRdtsc,
  /* 17  VMX_EXIT_RSM                     */  hmR0VmxExitRsm,
- /* 18  VMX_EXIT_VMCALL                  */  hmR0VmxExitSetPendingXcptUD,
+ /* 18  VMX_EXIT_VMCALL                  */  hmR0VmxExitVmcall,
  /* 19  VMX_EXIT_VMCLEAR                 */  hmR0VmxExitSetPendingXcptUD,
  /* 20  VMX_EXIT_VMLAUNCH                */  hmR0VmxExitSetPendingXcptUD,
@@ -8924,4 +8925,5 @@
         case VMX_EXIT_GETSEC:                  /* SVVMCS(); */ rc = hmR0VmxExitGetsec(pVCpu, pMixedCtx, pVmxTransient);            /* LDVMCS(); */ break;
         case VMX_EXIT_RDPMC:                   /* SVVMCS(); */ rc = hmR0VmxExitRdpmc(pVCpu, pMixedCtx, pVmxTransient);             /* LDVMCS(); */ break;
+        case VMX_EXIT_VMCALL:                  /* SVVMCS(); */ rc = hmR0VmxExitVmcall(pVCpu, pMixedCtx, pVmxTransient);            /* LDVMCS(); */ break;
 
         case VMX_EXIT_TRIPLE_FAULT:            rc = hmR0VmxExitTripleFault(pVCpu, pMixedCtx, pVmxTransient); break;
@@ -8935,5 +8937,4 @@
         case VMX_EXIT_ERR_MACHINE_CHECK:       rc = hmR0VmxExitErrMachineCheck(pVCpu, pMixedCtx, pVmxTransient); break;
 
-        case VMX_EXIT_VMCALL:
         case VMX_EXIT_VMCLEAR:
         case VMX_EXIT_VMLAUNCH:
@@ -9977,4 +9978,30 @@
 
 /**
+ * VM-exit handler for VMCALL (VMX_EXIT_VMCALL). Unconditional VM-exit.
+ */
+HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient)
+{
+    HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
+
+    int rc = VERR_NOT_SUPPORTED;
+    if (GIMAreHypercallsEnabled(pVCpu))
+    {
+        rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
+        AssertRCReturn(rc, rc);
+
+        rc = GIMHypercall(pVCpu, pMixedCtx);
+    }
+    if (rc != VINF_SUCCESS)
+    {
+        hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
+        rc = VINF_SUCCESS;
+    }
+
+    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
+    return rc;
+}
+
+
+/**
  * VM-exit handler for INVLPG (VMX_EXIT_INVLPG). Conditional VM-exit.
  */
Index: /trunk/src/VBox/VMM/include/GIMHvInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/GIMHvInternal.h	(revision 52005)
+++ /trunk/src/VBox/VMM/include/GIMHvInternal.h	(revision 52006)
@@ -516,4 +516,5 @@
 
 VMM_INT_DECL(bool)              GIMHvIsParavirtTscEnabled(PVM pVM);
+VMM_INT_DECL(bool)              GIMHvAreHypercallsEnabled(PVMCPU pVCpu);
 VMM_INT_DECL(int)               GIMHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
 VMM_INT_DECL(int)               GIMHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
Index: /trunk/src/VBox/VMM/include/HMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/HMInternal.h	(revision 52005)
+++ /trunk/src/VBox/VMM/include/HMInternal.h	(revision 52006)
@@ -857,4 +857,5 @@
     STAMCOUNTER             StatExitRdtscp;
     STAMCOUNTER             StatExitRdpmc;
+    STAMCOUNTER             StatExitVmcall;
     STAMCOUNTER             StatExitRdrand;
     STAMCOUNTER             StatExitCli;
