Index: /trunk/include/VBox/err.h
===================================================================
--- /trunk/include/VBox/err.h	(revision 55117)
+++ /trunk/include/VBox/err.h	(revision 55118)
@@ -2622,4 +2622,6 @@
 /** The GIM device is not registered with GIM when it ought to be. */
 #define VERR_GIM_DEVICE_NOT_REGISTERED              (-6310)
+/** Hypercall cannot be enabled/performed due to access/permissions/CPL. */
+#define VERR_GIM_HYPERCALL_ACCESS_DENIED            (-6311)
 /** @} */
 
Index: /trunk/include/VBox/vmm/gim.h
===================================================================
--- /trunk/include/VBox/vmm/gim.h	(revision 55117)
+++ /trunk/include/VBox/vmm/gim.h	(revision 55118)
@@ -174,5 +174,5 @@
 VMM_INT_DECL(bool)          GIMAreHypercallsEnabled(PVMCPU pVCpu);
 VMM_INT_DECL(int)           GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
-VMM_INT_DECL(int)           GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx);
+VMM_INT_DECL(int)           GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
 VMM_INT_DECL(bool)          GIMShouldTrapXcptUD(PVM pVM);
 VMM_INT_DECL(VBOXSTRICTRC)  GIMReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
Index: /trunk/include/VBox/vmm/hm.h
===================================================================
--- /trunk/include/VBox/vmm/hm.h	(revision 55117)
+++ /trunk/include/VBox/vmm/hm.h	(revision 55118)
@@ -144,5 +144,6 @@
 VMM_INT_DECL(int)               HMAmdIsSubjectToErratum170(uint32_t *pu32Family, uint32_t *pu32Model, uint32_t *pu32Stepping);
 VMM_INT_DECL(bool)              HMSetSingleInstruction(PVMCPU pVCpu, bool fEnable);
-VMM_INT_DECL(int)               HMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten);
+VMM_INT_DECL(void)              HMHypercallsEnable(PVM pVM);
+VMM_INT_DECL(void)              HMHypercallsDisable(PVM pVM);
 
 #ifndef IN_RC
Index: /trunk/include/VBox/vmm/vmm.h
===================================================================
--- /trunk/include/VBox/vmm/vmm.h	(revision 55117)
+++ /trunk/include/VBox/vmm/vmm.h	(revision 55118)
@@ -268,4 +268,7 @@
 VMM_INT_DECL(bool)          VMMIsInRing3Call(PVMCPU pVCpu);
 VMM_INT_DECL(void)          VMMTrashVolatileXMMRegs(void);
+VMM_INT_DECL(int)           VMMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten);
+VMM_INT_DECL(void)          VMMHypercallsEnable(PVM pVM);
+VMM_INT_DECL(void)          VMMHypercallsDisable(PVM pVM);
 
 
Index: /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp	(revision 55118)
@@ -129,4 +129,7 @@
             return gimHvIsParavirtTscEnabled(pVM);
 
+        case GIMPROVIDERID_KVM:
+            return gimKvmIsParavirtTscEnabled(pVM);
+
         default:
             break;
@@ -151,5 +154,5 @@
 {
     if (!GIMIsEnabled(pVM))
-        return 0;
+        return false;
 
     switch (pVM->gim.s.enmProviderId)
@@ -159,5 +162,5 @@
 
         default:
-            return 0;
+            return false;
     }
 }
@@ -169,6 +172,8 @@
  * @param   pVCpu       Pointer to the VMCPU.
  * @param   pCtx        Pointer to the guest-CPU context.
- */
-VMM_INT_DECL(int) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx)
+ * @param   pDis        Pointer to the disassembled instruction state at RIP.
+ *                      Optional, can be NULL.
+ */
+VMM_INT_DECL(int) GIMXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
 {
     PVM pVM = pVCpu->CTX_SUFF(pVM);
@@ -178,5 +183,5 @@
     {
         case GIMPROVIDERID_KVM:
-            return gimKvmXcptUD(pVCpu, pCtx);
+            return gimKvmXcptUD(pVCpu, pCtx, pDis);
 
         default:
Index: /trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp	(revision 55118)
@@ -112,8 +112,5 @@
      * Place the result in rax/eax.
      */
-    if (fIs64BitMode)
-        pCtx->rax = uHyperRet;
-    else
-        pCtx->eax = uHyperRet & uAndMask;
+    pCtx->rax = uHyperRet & uAndMask;
     return VINF_SUCCESS;
 }
@@ -144,5 +141,13 @@
 VMM_INT_DECL(bool) gimKvmIsParavirtTscEnabled(PVM pVM)
 {
-    return false;   /** @todo implement this! */
+    uint32_t cCpus = pVM->cCpus;
+    for (uint32_t i = 0; i < cCpus; i++)
+    {
+        PVMCPU     pVCpu      = &pVM->aCpus[i];
+        PGIMKVMCPU pGimKvmCpu = &pVCpu->gim.s.u.KvmCpu;
+        if (MSR_GIM_KVM_SYSTEM_TIME_IS_ENABLED(pGimKvmCpu->u64SystemTimeMsr))
+            return true;
+    }
+    return false;
 }
 
@@ -223,5 +228,5 @@
             if (fEnable)
             {
-                RTCCUINTREG fEFlags = ASMIntDisableFlags();
+                RTCCUINTREG fEFlags  = ASMIntDisableFlags();
                 pKvmCpu->uTsc        = TMCpuTickGetNoCheck(pVCpu);
                 pKvmCpu->uVirtNanoTS = TMVirtualGetNoCheck(pVM);
@@ -317,9 +322,10 @@
  * elegantly by letting the hypervisor supply an opaque hypercall page.
  *
+ * For raw-mode VMs, this function will always return true. See gimR3KvmInit().
+ *
  * @param   pVM         Pointer to the VM.
  */
 VMM_INT_DECL(bool) gimKvmShouldTrapXcptUD(PVM pVM)
 {
-    pVM->gim.s.u.Kvm.fTrapXcptUD = ASMIsAmdCpu();
     return pVM->gim.s.u.Kvm.fTrapXcptUD;
 }
@@ -331,34 +337,73 @@
  * @param   pVCpu       Pointer to the VMCPU.
  * @param   pCtx        Pointer to the guest-CPU context.
- */
-VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx)
+ * @param   pDis        Pointer to the disassembled instruction state at RIP.
+ *                      Optional, can be NULL.
+ */
+VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
 {
     /*
      * If we didn't ask for #UD to be trapped, bail.
      */
-    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    PVM     pVM  = pVCpu->CTX_SUFF(pVM);
+    PGIMKVM pKvm = &pVM->gim.s.u.Kvm;
     if (RT_UNLIKELY(!pVM->gim.s.u.Kvm.fTrapXcptUD))
         return VERR_GIM_OPERATION_FAILED;
 
     /*
-     * Disassemble the instruction at RIP to figure out if it's the Intel
-     * VMCALL instruction and if so, handle it as a hypercall.
-     */
-    DISCPUSTATE Dis;
-    unsigned    cbInstr;
-    int rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, &cbInstr);
+     * Make sure guest ring-0 is the one making the hypercall.
+     */
+    if (CPUMGetGuestCPL(pVCpu))
+        return VERR_GIM_HYPERCALL_ACCESS_DENIED;
+
+    int rc = VINF_SUCCESS;
+    if (!pDis)
+    {
+        /*
+         * Disassemble the instruction at RIP to figure out if it's the Intel
+         * VMCALL instruction and if so, handle it as a hypercall.
+         */
+        DISCPUSTATE Dis;
+        rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, NULL /* pcbInstr */);
+        pDis = &Dis;
+    }
+
     if (RT_SUCCESS(rc))
     {
-        if (Dis.pCurInstr->uOpcode == OP_VMCALL)
-        {
+        /*
+         * Patch the instruction to so we don't have to spend time disassembling it each time.
+         * Makes sense only for HM as with raw-mode we will be getting a #UD regardless.
+         */
+        if (   pDis->pCurInstr->uOpcode == OP_VMCALL
+            || pDis->pCurInstr->uOpcode == OP_VMMCALL)
+        {
+            uint8_t abHypercall[3];
+            if (   pDis->pCurInstr->uOpcode != pKvm->uOpCodeNative
+                && HMIsEnabled(pVM))
+            {
+                size_t  cbWritten = 0;
+                rc = VMMPatchHypercall(pVM, &abHypercall, sizeof(abHypercall), &cbWritten);
+                AssertRC(rc);
+                Assert(sizeof(abHypercall) == pDis->cbInstr);
+                Assert(sizeof(abHypercall) == cbWritten);
+
+                rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, &abHypercall, sizeof(abHypercall));
+            }
+
             /*
-             * Patch the instruction to so we don't have to spend time disassembling it each time.
+             * Perform the hypercall and update RIP.
+             *
+             * For HM, we can simply resume guest execution without perform the hypercall now and
+             * do it on the next VMCALL/VMMCALL exit handler on the patched instruction.
+             *
+             * For raw-mode we need to do this now anyway. So we do it here regardless with an added
+             * advantage is that it saves one world-switch for the HM case.
              */
-            static uint8_t s_abHypercall[3] = { 0x0F, 0x01, 0x00 };
-            Assert(sizeof(s_abHypercall) == cbInstr);
-            if (!s_abHypercall[2])
-                s_abHypercall[2] = ASMIsAmdCpu() ? 0xD9 /* VMMCALL */ : 0xC1 /* VMCALL */;
-            rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, &s_abHypercall, sizeof(s_abHypercall));
-            return VINF_SUCCESS;
+            if (RT_SUCCESS(rc))
+            {
+                int rc2 = gimKvmHypercall(pVCpu, pCtx);
+                AssertRC(rc2);
+                pCtx->rip += pDis->cbInstr;
+            }
+            return rc;
         }
     }
Index: /trunk/src/VBox/VMM/VMMAll/HMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HMAll.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMAll/HMAll.cpp	(revision 55118)
@@ -508,44 +508,22 @@
 
 /**
- * Patches the instructions necessary for making a hypercall to the hypervisor.
- * Used by GIM.
- *
- * @returns VBox status code.
- * @param   pVM         Pointer to the VM.
- * @param   pvBuf       The buffer in the hypercall page(s) to be patched.
- * @param   cbBuf       The size of the buffer.
- * @param   pcbWritten  Where to store the number of bytes patched. This
- *                      is reliably updated only when this function returns
- *                      VINF_SUCCESS.
- */
-VMM_INT_DECL(int) HMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
-{
-    AssertReturn(pvBuf, VERR_INVALID_POINTER);
-    AssertReturn(pcbWritten, VERR_INVALID_POINTER);
-    AssertReturn(HMIsEnabled(pVM), VERR_HM_IPE_5);
-
-    if (pVM->hm.s.vmx.fSupported)
-    {
-        uint8_t abHypercall[] = { 0x0F, 0x01, 0xC1 };   /* VMCALL */
-        if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
-        {
-            memcpy(pvBuf, abHypercall, sizeof(abHypercall));
-            *pcbWritten = sizeof(abHypercall);
-            return VINF_SUCCESS;
-        }
-        return VERR_BUFFER_OVERFLOW;
-    }
-    else
-    {
-        Assert(pVM->hm.s.svm.fSupported);
-        uint8_t abHypercall[] = { 0x0F, 0x01, 0xD9 };   /* VMMCALL */
-        if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
-        {
-            memcpy(pvBuf, abHypercall, sizeof(abHypercall));
-            *pcbWritten = sizeof(abHypercall);
-            return VINF_SUCCESS;
-        }
-        return VERR_BUFFER_OVERFLOW;
-    }
-}
-
+ * Notifies HM that paravirtualized hypercalls are now enabled.
+ *
+ * @param   pVM     Pointer to the VM.
+ */
+VMM_INT_DECL(void) HMHypercallsEnable(PVM pVM)
+{
+    pVM->hm.s.fHypercallsEnabled = true;
+}
+
+
+/**
+ * Notifies HM that paravirtualized hypercalls are now disabled.
+ *
+ * @param   pVM     Pointer to the VM.
+ */
+VMM_INT_DECL(void) HMHypercallsDisable(PVM pVM)
+{
+    pVM->hm.s.fHypercallsEnabled = false;
+}
+
Index: /trunk/src/VBox/VMM/VMMAll/VMMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/VMMAll.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMAll/VMMAll.cpp	(revision 55118)
@@ -24,4 +24,5 @@
 #include "VMMInternal.h"
 #include <VBox/vmm/vm.h>
+#include <VBox/vmm/hm.h>
 #include <VBox/vmm/vmcpuset.h>
 #include <VBox/param.h>
@@ -391,2 +392,75 @@
 }
 
+
+/**
+ * Patches the instructions necessary for making a hypercall to the hypervisor.
+ * Used by GIM.
+ *
+ * @returns VBox status code.
+ * @param   pVM         Pointer to the VM.
+ * @param   pvBuf       The buffer in the hypercall page(s) to be patched.
+ * @param   cbBuf       The size of the buffer.
+ * @param   pcbWritten  Where to store the number of bytes patched. This
+ *                      is reliably updated only when this function returns
+ *                      VINF_SUCCESS.
+ */
+VMM_INT_DECL(int) VMMPatchHypercall(PVM pVM, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
+{
+    AssertReturn(pvBuf, VERR_INVALID_POINTER);
+    AssertReturn(pcbWritten, VERR_INVALID_POINTER);
+
+    if (ASMIsAmdCpu())
+    {
+        uint8_t abHypercall[] = { 0x0F, 0x01, 0xD9 };   /* VMMCALL */
+        if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
+        {
+            memcpy(pvBuf, abHypercall, sizeof(abHypercall));
+            *pcbWritten = sizeof(abHypercall);
+            return VINF_SUCCESS;
+        }
+        return VERR_BUFFER_OVERFLOW;
+    }
+    else
+    {
+        AssertReturn(ASMIsIntelCpu() || ASMIsViaCentaurCpu(), VERR_UNSUPPORTED_CPU);
+        uint8_t abHypercall[] = { 0x0F, 0x01, 0xC1 };   /* VMCALL */
+        if (RT_LIKELY(cbBuf >= sizeof(abHypercall)))
+        {
+            memcpy(pvBuf, abHypercall, sizeof(abHypercall));
+            *pcbWritten = sizeof(abHypercall);
+            return VINF_SUCCESS;
+        }
+        return VERR_BUFFER_OVERFLOW;
+    }
+}
+
+
+/**
+ * Notifies VMM that paravirtualized hypercalls are now enabled.
+ *
+ * @param   pVM     Pointer to the VM.
+ */
+VMM_INT_DECL(void) VMMHypercallsEnable(PVM pVM)
+{
+    /* If there is anything to do for raw-mode, do it here. */
+#ifndef IN_RC
+    if (HMIsEnabled(pVM))
+        HMHypercallsEnable(pVM);
+#endif
+}
+
+
+/**
+ * Notifies VMM that paravirtualized hypercalls are now disabled.
+ *
+ * @param   pVM     Pointer to the VM.
+ */
+VMM_INT_DECL(void) VMMHypercallsDisable(PVM pVM)
+{
+    /* If there is anything to do for raw-mode, do it here. */
+#ifndef IN_RC
+    if (HMIsEnabled(pVM))
+        HMHypercallsDisable(pVM);
+#endif
+}
+
Index: /trunk/src/VBox/VMM/VMMR0/HMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMR0/HMR0.cpp	(revision 55118)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2006-2014 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -26,4 +26,5 @@
 #include <VBox/vmm/hm_vmx.h>
 #include <VBox/vmm/hm_svm.h>
+#include <VBox/vmm/gim.h>
 #include <VBox/err.h>
 #include <VBox/log.h>
@@ -1211,7 +1212,7 @@
     pVM->hm.s.cpuid.u32AMDFeatureEDX    = g_HvmR0.cpuid.u32AMDFeatureEDX;
     pVM->hm.s.lLastError                = g_HvmR0.lLastError;
-
     pVM->hm.s.uMaxAsid                  = g_HvmR0.uMaxAsid;
 
+    pVM->hm.s.fGIMTrapXcptUD            = GIMShouldTrapXcptUD(pVM);
 
     if (!pVM->hm.s.cMaxResumeLoops) /* allow ring-3 overrides */
Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 55118)
@@ -670,6 +670,5 @@
     Assert(pVM->hm.s.svm.fSupported);
 
-    pVM->hm.s.fTrapXcptUD             = GIMShouldTrapXcptUD(pVM);
-    uint32_t const fGimXcptIntercepts = pVM->hm.s.fTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
+    uint32_t const fGimXcptIntercepts = pVM->hm.s.fGIMTrapXcptUD ? RT_BIT(X86_XCPT_UD) : 0;
     for (VMCPUID i = 0; i < pVM->cCpus; i++)
     {
@@ -3511,4 +3510,7 @@
             return hmR0SvmExitWriteCRx(pVCpu, pCtx, pSvmTransient);
 
+        case SVM_EXIT_VMMCALL:
+            return hmR0SvmExitVmmCall(pVCpu, pCtx, pSvmTransient);
+
         case SVM_EXIT_VINTR:
             return hmR0SvmExitVIntr(pVCpu, pCtx, pSvmTransient);
@@ -3552,7 +3554,4 @@
                 case SVM_EXIT_TASK_SWITCH:
                     return hmR0SvmExitTaskSwitch(pVCpu, pCtx, pSvmTransient);
-
-                case SVM_EXIT_VMMCALL:
-                    return hmR0SvmExitVmmCall(pVCpu, pCtx, pSvmTransient);
 
                 case SVM_EXIT_IRET:
@@ -3899,5 +3898,5 @@
  * @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_NOT_FOUND if no patch record for this RIP could be found.
  * @retval VERR_SVM_UNEXPECTED_PATCH_TYPE if the found patch type is invalid.
  *
@@ -4998,4 +4997,5 @@
 {
     HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
+    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
 
     /* First check if this is a patched VMMCALL for mov TPR */
@@ -5008,12 +5008,12 @@
     else if (rc == VERR_NOT_FOUND)
     {
-        /* Handle GIM provider hypercalls. */
-        if (GIMAreHypercallsEnabled(pVCpu))
+        PVM pVM = pVCpu->CTX_SUFF(pVM);
+        if (pVM->hm.s.fHypercallsEnabled)
         {
             rc = GIMHypercall(pVCpu, pCtx);
-            /* If the hypercall changes anything other than guest general-purpose registers,
-               we would need to reload the guest changed bits on VM-reentry. */
             if (RT_SUCCESS(rc))
             {
+                /* If the hypercall changes anything other than guest general-purpose registers,
+                   we would need to reload the guest changed bits here before VM-reentry. */
                 hmR0SvmUpdateRip(pVCpu, pCtx, 3);
                 return VINF_SUCCESS;
@@ -5228,7 +5228,6 @@
 
     PVM pVM = pVCpu->CTX_SUFF(pVM);
-    if (   pVM->hm.s.fTrapXcptUD
-        && GIMAreHypercallsEnabled(pVCpu))
-        GIMXcptUD(pVCpu, pCtx);
+    if (pVM->hm.s.fGIMTrapXcptUD)
+        GIMXcptUD(pVCpu, pCtx, NULL /* pDis */);
     else
         hmR0SvmSetPendingXcptUD(pVCpu);
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 55118)
@@ -10241,30 +10241,31 @@
 {
     HMVMX_VALIDATE_EXIT_HANDLER_PARAMS();
-
-    int rc = VERR_NOT_SUPPORTED;
-    if (GIMAreHypercallsEnabled(pVCpu))
-    {
-        rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
+    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
+
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    if (pVM->hm.s.fHypercallsEnabled)
+    {
+#if 0
+        int rc = hmR0VmxSaveGuestState(pVCpu, pMixedCtx);
         AssertRCReturn(rc, rc);
+#else
+        /* Aggressive state sync. for now. */
+        int rc  = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
+        rc     |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx);    /* For long-mode checks in gimKvmHypercall(). */
+#endif
+        AssertRCReturn(rc, rc);
 
         rc = GIMHypercall(pVCpu, pMixedCtx);
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        rc = hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
-        Assert(pVmxTransient->cbInstr == 3);
-
-        /* If the hypercall changes anything other than guest general-purpose registers,
-           we would need to reload the guest changed bits on VM-reentry. */
-    }
-    else
-    {
-        hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
-        rc = VINF_SUCCESS;
-    }
-
-    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
-    return rc;
+        if (RT_SUCCESS(rc))
+        {
+            /* If the hypercall changes anything other than guest general-purpose registers,
+               we would need to reload the guest changed bits here before VM-reentry. */
+            hmR0VmxAdvanceGuestRip(pVCpu, pMixedCtx, pVmxTransient);
+            return VINF_SUCCESS;
+        }
+    }
+
+    hmR0VmxSetPendingXcptUD(pVCpu, pMixedCtx);
+    return VINF_SUCCESS;
 }
 
Index: /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 55118)
@@ -633,4 +633,5 @@
         GIMR3Mmio2Unmap(pVM, pRegion);
         Assert(!pRegion->fMapped);
+        VMMHypercallsDisable(pVM);
         LogRel(("GIM: HyperV: Disabled Hypercall-page\n"));
         return VINF_SUCCESS;
@@ -680,34 +681,31 @@
          * Patch the hypercall-page.
          */
-        if (HMIsEnabled(pVM))
+        size_t cbWritten = 0;
+        rc = VMMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
+        if (   RT_SUCCESS(rc)
+            && cbWritten < PAGE_SIZE)
         {
-            size_t cbWritten = 0;
-            rc = HMPatchHypercall(pVM, pRegion->pvPageR3, PAGE_SIZE, &cbWritten);
-            if (   RT_SUCCESS(rc)
-                && cbWritten < PAGE_SIZE)
-            {
-                uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
-                *pbLast = 0xc3;  /* RET */
-
-                LogRel(("GIM: HyperV: Enabled hypercalls at %#RGp\n", GCPhysHypercallPage));
-                return VINF_SUCCESS;
-            }
-            else
-            {
-                if (rc == VINF_SUCCESS)
-                    rc = VERR_GIM_OPERATION_FAILED;
-                LogRelFunc(("HMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
-            }
+            uint8_t *pbLast = (uint8_t *)pRegion->pvPageR3 + cbWritten;
+            *pbLast = 0xc3;  /* RET */
+
+            /*
+             * Notify VMM that hypercalls are now enabled.
+             */
+            VMMHypercallsEnable(pVM);
+
+            LogRel(("GIM: HyperV: Enabled hypercalls at %#RGp\n", GCPhysHypercallPage));
+            return VINF_SUCCESS;
         }
         else
         {
-            /** @todo Handle raw-mode hypercall page patching. */
-            LogRel(("GIM: HyperV: Raw-mode hypercalls not yet implemented!\n"));
+            if (rc == VINF_SUCCESS)
+                rc = VERR_GIM_OPERATION_FAILED;
+            LogRel(("GIM: HyperV: VMMPatchHypercall failed. rc=%Rrc cbWritten=%u\n", rc, cbWritten));
         }
+
         GIMR3Mmio2Unmap(pVM, pRegion);
     }
-    else
-        LogRelFunc(("GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
-
+
+    LogRel(("GIM: HyperV: GIMR3Mmio2Map failed. rc=%Rrc\n", rc));
     return rc;
 }
Index: /trunk/src/VBox/VMM/VMMR3/GIMKvm.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/GIMKvm.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMR3/GIMKvm.cpp	(revision 55118)
@@ -30,4 +30,5 @@
 
 #include <VBox/vmm/cpum.h>
+#include <VBox/disopcode.h>
 #include <VBox/vmm/ssm.h>
 #include <VBox/vmm/vm.h>
@@ -141,4 +142,23 @@
     }
 
+    /*
+     * Setup #UD and hypercall behaviour.
+     */
+    VMMHypercallsEnable(pVM);
+    if (ASMIsAmdCpu())
+    {
+        pKvm->fTrapXcptUD   = true;
+        pKvm->uOpCodeNative = OP_VMMCALL;
+    }
+    else
+    {
+        Assert(ASMIsIntelCpu() || ASMIsViaCentaurCpu());
+        pKvm->fTrapXcptUD   = false;
+        pKvm->uOpCodeNative = OP_VMCALL;
+    }
+    /* We always need to trap VMCALL/VMMCALL hypercall using #UDs for raw-mode VMs. */
+    if (!HMIsEnabled(pVM))
+        pKvm->fTrapXcptUD = true;
+
     return VINF_SUCCESS;
 }
@@ -368,6 +388,6 @@
      * time = ((tsc * SysTime.u32TscScale) >> 32) + SysTime.u64NanoTS
      */
-    uint64_t u64TscFreq = TMCpuTicksPerSecond(pVM);
-    SystemTime.i8TscShift  = 0;
+    uint64_t u64TscFreq   = TMCpuTicksPerSecond(pVM);
+    SystemTime.i8TscShift = 0;
     while (u64TscFreq > 2 * RT_NS_1SEC_64)
     {
Index: /trunk/src/VBox/VMM/VMMRC/TRPMRCHandlers.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMRC/TRPMRCHandlers.cpp	(revision 55117)
+++ /trunk/src/VBox/VMM/VMMRC/TRPMRCHandlers.cpp	(revision 55118)
@@ -27,4 +27,5 @@
 #include <VBox/vmm/dbgf.h>
 #include <VBox/vmm/em.h>
+#include <VBox/vmm/gim.h>
 #include <VBox/vmm/csam.h>
 #include <VBox/vmm/patm.h>
@@ -595,5 +596,5 @@
 #ifdef DTRACE_EXPERIMENT /** @todo fix/remove/permanent-enable this when DIS/PATM handles invalid lock sequences. */
             Assert(!PATMIsPatchGCAddr(pVM, pRegFrame->eip));
-            rc = TRPMForwardTrap(pVCpu, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, 0x6);
+            rc = TRPMForwardTrap(pVCpu, pRegFrame, X86_XCPT_UD, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, X86_XCPT_UD);
             Assert(rc == VINF_EM_RAW_GUEST_TRAP);
 #else
@@ -609,4 +610,14 @@
             rc = EMInterpretInstructionDisasState(pVCpu, &Cpu, pRegFrame, PC, EMCODETYPE_SUPERVISOR);
         }
+        else if (GIMShouldTrapXcptUD(pVM))
+        {
+            LogFlow(("TRPMGCTrap06Handler: -> GIMXcptUD\n"));
+            rc = GIMXcptUD(pVCpu, CPUMCTX_FROM_CORE(pRegFrame), &Cpu);
+            if (RT_FAILURE(rc))
+            {
+                LogFlow(("TRPMGCTrap06Handler: -> GIMXcptUD -> VINF_EM_RAW_EMULATE_INSTR\n"));
+                rc = VINF_EM_RAW_EMULATE_INSTR;
+            }
+        }
         /* Never generate a raw trap here; it might be an instruction, that requires emulation. */
         else
@@ -619,5 +630,5 @@
     {
         LogFlow(("TRPMGCTrap06Handler: -> TRPMForwardTrap\n"));
-        rc = TRPMForwardTrap(pVCpu, pRegFrame, 0x6, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, 0x6);
+        rc = TRPMForwardTrap(pVCpu, pRegFrame, X86_XCPT_UD, 0, TRPM_TRAP_NO_ERRORCODE, TRPM_TRAP, X86_XCPT_UD);
         Assert(rc == VINF_EM_RAW_GUEST_TRAP);
     }
Index: /trunk/src/VBox/VMM/include/GIMKvmInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/GIMKvmInternal.h	(revision 55117)
+++ /trunk/src/VBox/VMM/include/GIMKvmInternal.h	(revision 55118)
@@ -193,16 +193,14 @@
 typedef struct GIMKVM
 {
-    /** @name MSRs. */
     /** Wall-clock MSR. */
     uint64_t                    u64WallClockMsr;
-    /** @} */
-
-    /** @name CPUID features. */
-    /** Basic features. */
+
+    /**  CPUID features: Basic. */
     uint32_t                    uBaseFeat;
-    /** @} */
-
-    /** Whether we need to trap #UD exceptions. */
+
+    /** Whether GIM needs to trap #UD exceptions. */
     bool                        fTrapXcptUD;
+    /** Disassembler opcode of hypercall instruction native for this host CPU. */
+    uint16_t                    uOpCodeNative;
 } GIMKVM;
 /** Pointer to per-VM GIM KVM instance data. */
@@ -264,5 +262,5 @@
 VMM_INT_DECL(VBOXSTRICTRC)      gimKvmWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue);
 VMM_INT_DECL(bool)              gimKvmShouldTrapXcptUD(PVM pVM);
-VMM_INT_DECL(int)               gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx);
+VMM_INT_DECL(int)               gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
 
 
Index: /trunk/src/VBox/VMM/include/HMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/HMInternal.h	(revision 55117)
+++ /trunk/src/VBox/VMM/include/HMInternal.h	(revision 55118)
@@ -344,6 +344,8 @@
     bool                        fTPRPatchingActive;
     /** Whether #UD needs to be intercepted (required by certain GIM providers). */
-    bool                        fTrapXcptUD;
-    bool                        u8Alignment[2];
+    bool                        fGIMTrapXcptUD;
+    /** Whether paravirt. hypercalls are enabled. */
+    bool                        fHypercallsEnabled;
+    bool                        u8Alignment[1];
 
     /** Host kernel flags that HM might need to know (SUPKERNELFEATURES_XXX). */
