Index: /trunk/include/VBox/vmm/vm.h
===================================================================
--- /trunk/include/VBox/vmm/vm.h	(revision 58282)
+++ /trunk/include/VBox/vmm/vm.h	(revision 58283)
@@ -1146,5 +1146,5 @@
         struct GIM s;
 #endif
-        uint8_t     padding[320+64];    /* multiple of 64 */
+        uint8_t     padding[448];       /* multiple of 64 */
     } gim;
 
@@ -1171,5 +1171,5 @@
 
     /** Padding for aligning the cpu array on a page boundary. */
-    uint8_t         abAlignment2[4062];
+    uint8_t         abAlignment2[3998];
 
     /* ---- end small stuff ---- */
Index: /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 58282)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 58283)
@@ -41,9 +41,5 @@
 #ifdef IN_RING3
 /**
- * Helper for reading and validating slow hypercall input/output parameters.
- *
- * A 'slow' hypercall is one that passes parameters pointers through guest
- * memory as opposed to a 'fast' hypercall which passes parameters through guest
- * general-purpose registers.
+ * Read and validate slow hypercall parameters.
  *
  * @returns VBox status code.
@@ -51,52 +47,75 @@
  * @param   pCtx              Pointer to the guest-CPU context.
  * @param   fIs64BitMode      Whether the guest is currently in 64-bit mode or not.
- * @param   pGCPhysIn         Where to store the guest-physical address of the
- *                            hypercall input page. Optional, can be NULL.
- * @param   pGCPhysOut        Where to store the guest-physical address of the
- *                            hypercall output page. Optional, can be NULL.
+ * @param   enmParam          The hypercall parameter type.
  * @param   prcHv             Where to store the Hyper-V status code. Only valid
  *                            to the caller when this function returns
  *                            VINF_SUCCESS.
  */
-static int gimHvReadSlowHypercallParams(PVM pVM, PCPUMCTX pCtx, bool fIs64BitMode, PRTGCPHYS pGCPhysIn, PRTGCPHYS pGCPhysOut,
-                                        int *prcHv)
+static int gimHvReadSlowHypercallParam(PVM pVM, PCPUMCTX pCtx, bool fIs64BitMode, GIMHVHYPERCALLPARAM enmParam, int *prcHv)
 {
-    int rc = VINF_SUCCESS;
-    RTGCPHYS GCPhysIn  = fIs64BitMode ? pCtx->rdx : (pCtx->rbx << 32) | pCtx->ecx;
-    RTGCPHYS GCPhysOut = fIs64BitMode ? pCtx->r8  : (pCtx->rdi << 32) | pCtx->esi;
-    if (pGCPhysIn)
-        *pGCPhysIn = GCPhysIn;
-    if (pGCPhysOut)
-        *pGCPhysOut = GCPhysOut;
-    if (   RT_ALIGN_64(GCPhysIn,  8) == GCPhysIn
-        && RT_ALIGN_64(GCPhysOut, 8) == GCPhysOut)
-    {
-        if (   PGMPhysIsGCPhysNormal(pVM, GCPhysIn)
-            && PGMPhysIsGCPhysNormal(pVM, GCPhysOut))
-        {
-            PGIMHV pHv = &pVM->gim.s.u.Hv;
-            rc = PGMPhysSimpleReadGCPhys(pVM, pHv->pbHypercallIn, GCPhysIn, GIM_HV_PAGE_SIZE);
+    int       rc = VINF_SUCCESS;
+    PGIMHV    pHv = &pVM->gim.s.u.Hv;
+    RTGCPHYS  GCPhysParam;
+    void     *pvDst;
+    if (enmParam == GIMHVHYPERCALLPARAM_IN)
+    {
+        GCPhysParam = fIs64BitMode ? pCtx->rdx : (pCtx->rbx << 32) | pCtx->ecx;
+        pvDst = pHv->pbHypercallIn;
+        pHv->GCPhysHypercallIn = GCPhysParam;
+    }
+    else
+    {
+        GCPhysParam = fIs64BitMode ? pCtx->r8 : (pCtx->rdi << 32) | pCtx->esi;
+        pvDst = pHv->pbHypercallOut;
+        pHv->GCPhysHypercallOut = GCPhysParam;
+        Assert(enmParam == GIMHVHYPERCALLPARAM_OUT);
+    }
+
+    const char *pcszParam = enmParam == GIMHVHYPERCALLPARAM_IN ? "input" : "output";  NOREF(pcszParam);
+    if (RT_ALIGN_64(GCPhysParam, 8) == GCPhysParam)
+    {
+        if (PGMPhysIsGCPhysNormal(pVM, GCPhysParam))
+        {
+            rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysParam, GIM_HV_PAGE_SIZE);
             if (RT_SUCCESS(rc))
             {
-                rc = PGMPhysSimpleReadGCPhys(pVM, pHv->pbHypercallOut, GCPhysOut, GIM_HV_PAGE_SIZE);
-                if (RT_SUCCESS(rc))
-                {
-                    *prcHv = GIM_HV_STATUS_SUCCESS;
-                    return VINF_SUCCESS;
-                }
-                Log(("GIM: HyperV: gimHvReadSlowHypercallParams reading GCPhysOut=%#RGp failed. rc=%Rrc\n", GCPhysOut, rc));
-                rc = VERR_GIM_HYPERCALL_MEMORY_READ_FAILED;
-            }
-            else
-            {
-                Log(("GIM: HyperV: gimHvReadSlowHypercallParams reading GCPhysIn=%#RGp failed. rc=%Rrc\n", GCPhysIn,rc));
-                rc = VERR_GIM_HYPERCALL_MEMORY_READ_FAILED;
-            }
+                *prcHv = GIM_HV_STATUS_SUCCESS;
+                return VINF_SUCCESS;
+            }
+            LogRel(("GIM: HyperV: Failed reading %s param at %#RGp. rc=%Rrc\n", pcszParam, GCPhysParam, rc));
+            rc = VERR_GIM_HYPERCALL_MEMORY_READ_FAILED;
         }
         else
+        {
+            Log(("GIM: HyperV: Invalid %s param address %#RGp\n", pcszParam, GCPhysParam));
             *prcHv = GIM_HV_STATUS_INVALID_PARAMETER;
+        }
     }
     else
+    {
+        Log(("GIM: HyperV: Misaligned %s param address %#RGp\n", pcszParam, GCPhysParam));
         *prcHv = GIM_HV_STATUS_INVALID_ALIGNMENT;
+    }
+    return rc;
+}
+
+
+/**
+ * Helper for reading and validating slow hypercall input and output parameters.
+ *
+ * @returns VBox status code.
+ * @param   pVM               The cross context VM structure.
+ * @param   pCtx              Pointer to the guest-CPU context.
+ * @param   fIs64BitMode      Whether the guest is currently in 64-bit mode or not.
+ * @param   prcHv             Where to store the Hyper-V status code. Only valid
+ *                            to the caller when this function returns
+ *                            VINF_SUCCESS.
+ */
+static int gimHvReadSlowHypercallParamsInOut(PVM pVM, PCPUMCTX pCtx, bool fIs64BitMode, int *prcHv)
+{
+    int rc = gimHvReadSlowHypercallParam(pVM, pCtx, fIs64BitMode, GIMHVHYPERCALLPARAM_IN, prcHv);
+    if (   RT_SUCCESS(rc)
+        && *prcHv == GIM_HV_STATUS_SUCCESS)
+        rc = gimHvReadSlowHypercallParam(pVM, pCtx, fIs64BitMode, GIMHVHYPERCALLPARAM_OUT, prcHv);
     return rc;
 }
@@ -168,10 +187,10 @@
                 {
                     RTGCPHYS GCPhysOut;
-                    rc = gimHvReadSlowHypercallParams(pVM, pCtx, fIs64BitMode, NULL /*pGCPhysIn*/, &GCPhysOut, &rcHv);
+                    rc  = gimHvReadSlowHypercallParamsInOut(pVM, pCtx, fIs64BitMode, &rcHv);
                     if (   RT_SUCCESS(rc)
                         && rcHv == GIM_HV_STATUS_SUCCESS)
                     {
-                        LogRelMax(1, ("GIM: HyperV: Guest initiated debug data reception via hypercall\n"));
-                        rc = gimR3HvHypercallRetrieveDebugData(pVM, GCPhysOut, &rcHv);
+                        LogRelMax(1, ("GIM: HyperV: Initiated debug data reception via hypercall\n"));
+                        rc = gimR3HvHypercallRetrieveDebugData(pVM, &rcHv);
                         if (RT_FAILURE(rc))
                             LogRelMax(10, ("GIM: HyperV: gimR3HvHypercallRetrieveDebugData failed. rc=%Rrc\n", rc));
@@ -187,11 +206,10 @@
                 if (pHv->uPartFlags & GIM_HV_PART_FLAGS_DEBUGGING)
                 {
-                    RTGCPHYS GCPhysOut;
-                    rc = gimHvReadSlowHypercallParams(pVM, pCtx, fIs64BitMode, NULL /*pGCPhysIn*/, &GCPhysOut, &rcHv);
+                    rc = gimHvReadSlowHypercallParamsInOut(pVM, pCtx, fIs64BitMode, &rcHv);
                     if (   RT_SUCCESS(rc)
                         && rcHv == GIM_HV_STATUS_SUCCESS)
                     {
-                        LogRelMax(1, ("GIM: HyperV: Guest initiated debug data transmission via hypercall\n"));
-                        rc = gimR3HvHypercallPostDebugData(pVM, GCPhysOut, &rcHv);
+                        LogRelMax(1, ("GIM: HyperV: Initiated debug data transmission via hypercall\n"));
+                        rc = gimR3HvHypercallPostDebugData(pVM, &rcHv);
                         if (RT_FAILURE(rc))
                             LogRelMax(10, ("GIM: HyperV: gimR3HvHypercallPostDebugData failed. rc=%Rrc\n", rc));
@@ -210,6 +228,5 @@
                     if (!fHyperFast)
                     {
-                        rc = gimHvReadSlowHypercallParams(pVM, pCtx, fIs64BitMode, NULL /*pGCPhysIn*/, NULL /*pGCPhysOut*/,
-                                                            &rcHv);
+                        rc = gimHvReadSlowHypercallParam(pVM, pCtx, fIs64BitMode, GIMHVHYPERCALLPARAM_IN, &rcHv);
                         if (   RT_SUCCESS(rc)
                             && rcHv == GIM_HV_STATUS_SUCCESS)
@@ -234,6 +251,61 @@
                             rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
                         else
-                            LogRelMax(1, ("GIM: HyperV: Guest resetting debug session via hypercall\n"));
+                            LogRelMax(1, ("GIM: HyperV: Resetting debug session via hypercall\n"));
                     }
+                }
+                else
+                    rcHv = GIM_HV_STATUS_ACCESS_DENIED;
+                break;
+            }
+
+            case GIM_HV_HYPERCALL_OP_POST_MESSAGE:      /* Non-rep, memory IO. */
+            {
+                if (pHv->fIsInterfaceVs)
+                {
+                    rc = gimHvReadSlowHypercallParam(pVM, pCtx, fIs64BitMode, GIMHVHYPERCALLPARAM_IN, &rcHv);
+                    if (   RT_SUCCESS(rc)
+                        && rcHv == GIM_HV_STATUS_SUCCESS)
+                    {
+                        PGIMHVPOSTMESSAGEIN pMsgIn = (PGIMHVPOSTMESSAGEIN)pHv->pbHypercallIn;
+                        PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
+                        if (    pMsgIn->uConnectionId  == GIM_HV_VMBUS_MSG_CONNECTION_ID
+                            &&  pMsgIn->enmMessageType == GIMHVMSGTYPE_VMBUS
+                            && !MSR_GIM_HV_SINT_IS_MASKED(pHvCpu->uSint2Msr)
+                            &&  MSR_GIM_HV_SIMP_IS_ENABLED(pHvCpu->uSimpMsr))
+                        {
+                            RTGCPHYS GCPhysSimp = MSR_GIM_HV_SIMP_GPA(pHvCpu->uSimpMsr);
+                            if (PGMPhysIsGCPhysNormal(pVM, GCPhysSimp))
+                            {
+                                /*
+                                 * The VMBus client (guest) expects to see 0xf at offsets 4 and 16 and 1 at offset 0.
+                                 */
+                                GIMHVMSG HvMsg;
+                                RT_ZERO(HvMsg);
+                                HvMsg.MsgHdr.enmMessageType = GIMHVMSGTYPE_VMBUS;
+                                HvMsg.MsgHdr.cbPayload = 0xf;
+                                HvMsg.aPayload[0]      = 0xf;
+                                uint16_t const offMsg = GIM_HV_VMBUS_MSG_SINT * sizeof(GIMHVMSG);
+                                int rc2 = PGMPhysSimpleWriteGCPhys(pVM, GCPhysSimp + offMsg, &HvMsg, sizeof(HvMsg));
+                                if (RT_SUCCESS(rc2))
+                                    LogRel(("GIM: HyperV: SIMP hypercall faking message at %#RGp:%u\n", GCPhysSimp, offMsg));
+                                else
+                                {
+                                    LogRel(("GIM: HyperV: Failed to write SIMP message at %#RGp:%u, rc=%Rrc\n", GCPhysSimp,
+                                            offMsg, rc));
+                                }
+                            }
+                        }
+
+                        /*
+                         * Make the call fail after updating the SIMP, so the guest can go back to using
+                         * the Hyper-V debug MSR interface. Any error code below GIM_HV_STATUS_NOT_ACKNOWLEDGED
+                         * and the guest tries to proceed with initializing VMBus which is totally unnecessary
+                         * for what we're trying to accomplish, i.e. convince guest to use Hyper-V debugging. Also,
+                         * we don't implement other VMBus/SynIC functionality so the guest would #GP and die.
+                         */
+                        rcHv = GIM_HV_STATUS_NOT_ACKNOWLEDGED;
+                    }
+                    else
+                        rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
                 }
                 else
@@ -404,22 +476,14 @@
         case MSR_GIM_HV_SINT2:
         {
-#ifndef IN_RING3
-            return VINF_CPUM_R3_MSR_READ;
-#else
-            LogRelMax(10, ("GIM: HyperV: reading MSR_GIM_HV_SINT2 CS:RIP=%04x:%RX64\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu)));
-            *puValue = RT_BIT_64(16);
-            return VERR_CPUM_RAISE_GP_0;
-#endif
+            PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
+            *puValue = pHvCpu->uSint2Msr;
+            return VINF_SUCCESS;
         }
 
         case MSR_GIM_HV_SIMP:
         {
-#ifndef IN_RING3
-            return VINF_CPUM_R3_MSR_READ;
-#else
-            LogRelMax(10, ("GIM: HyperV: reading MSR_GIM_HV_SIMP CS:RIP=%04x:%RX64\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu)));
-            *puValue = 0;
-            return VINF_SUCCESS;
-#endif
+            PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
+            *puValue = pHvCpu->uSimpMsr;
+            return VINF_SUCCESS;
         }
 
@@ -445,5 +509,5 @@
                 return VINF_CPUM_R3_MSR_READ;
 #else
-                LogRelMax(1, ("GIM: HyperV: Guest querying debug options MSR, returning %#x\n", GIM_HV_DEBUG_OPTIONS_MSR_ENABLE));
+                LogRelMax(1, ("GIM: HyperV: Guest queried debug options MSR\n"));
                 *puValue = GIM_HV_DEBUG_OPTIONS_MSR_ENABLE;
                 return VINF_SUCCESS;
@@ -564,13 +628,7 @@
 #ifndef IN_RING3
             return VINF_CPUM_R3_MSR_WRITE;
-#else  /* IN_RING3 */
-# if 0
-            /*
-             * For now ignore writes to the hypercall MSR (i.e. keeps it disabled).
-             * This is required to boot FreeBSD 10.1 (with Hyper-V enabled ofc),
-             * see @bugref{7270#c116}.
-             */
-            return VINF_SUCCESS;
-# else
+#else
+            /** @todo There is/was a problem with hypercalls for FreeBSD 10.1 guests,
+             *  see @bugref{7270#c116}. */
             /* First, update all but the hypercall page enable bit. */
             pHv->u64HypercallMsr = (uRawValue & ~MSR_GIM_HV_HYPERCALL_PAGE_ENABLE_BIT);
@@ -602,6 +660,5 @@
 
             return VERR_CPUM_RAISE_GP_0;
-# endif
-#endif /* IN_RING3 */
+#endif
         }
 
@@ -674,7 +731,7 @@
             pHv->uDebugSendBufferMsr = GCPhysBuffer;
             if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer))
-                LogRel(("GIM: HyperV: Guest set up debug send buffer at %#RGp\n", GCPhysBuffer));
+                LogRel(("GIM: HyperV: Set up debug send buffer at %#RGp\n", GCPhysBuffer));
             else
-                LogRel(("GIM: HyperV: Guest destroyed debug send buffer\n"));
+                LogRel(("GIM: HyperV: Destroyed debug send buffer\n"));
             pHv->uDebugSendBufferMsr = uRawValue;
             return VINF_SUCCESS;
@@ -690,7 +747,7 @@
             pHv->uDebugRecvBufferMsr = GCPhysBuffer;
             if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer))
-                LogRel(("GIM: HyperV: Guest set up debug receive buffer at %#RGp\n", GCPhysBuffer));
+                LogRel(("GIM: HyperV: Set up debug receive buffer at %#RGp\n", GCPhysBuffer));
             else
-                LogRel(("GIM: HyperV: Guest destroyed debug receive buffer\n"));
+                LogRel(("GIM: HyperV: Destroyed debug receive buffer\n"));
             return VINF_SUCCESS;
 #endif
@@ -706,7 +763,10 @@
             if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer))
             {
-                LogRel(("GIM: HyperV: Guest set up debug pending buffer at %#RGp\n", uRawValue));
+                LogRel(("GIM: HyperV: Set up debug pending buffer at %#RGp\n", uRawValue));
 
                 /* Indicate that there is always debug data to be read (guest will poll). */
+                /** @todo Later implement this by doing the transport read in a separate
+                 *        thread and updating this page, saves lots of VM-exits as the guest
+                 *        won't poll and fail all the time. */
                 uint8_t uPendingData = 1;
                 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysBuffer, (void *)&uPendingData, sizeof(uPendingData));
@@ -715,5 +775,5 @@
             }
             else
-                LogRel(("GIM: HyperV: Guest destroyed debug pending buffer\n"));
+                LogRel(("GIM: HyperV: Destroyed debug pending buffer\n"));
             return VINF_SUCCESS;
 #endif
@@ -727,5 +787,5 @@
             if (MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_WRITE(uRawValue))
             {
-                LogRelMax(1, ("GIM: HyperV: Guest initiated debug data transmission via MSR\n",
+                LogRelMax(1, ("GIM: HyperV: Initiated debug data transmission via MSR\n",
                               MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue)));
                 uint32_t cbWrite = MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue);
@@ -769,5 +829,5 @@
             else if (MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_READ(uRawValue))
             {
-                LogRelMax(1, ("GIM: HyperV: Guest initiated debug data reception via MSR\n"));
+                LogRelMax(1, ("GIM: HyperV: Initiated debug data reception via MSR\n"));
                 if (PGMPhysIsGCPhysNormal(pVM, (RTGCPHYS)pHv->uDebugRecvBufferMsr))
                 {
@@ -810,11 +870,58 @@
 
         case MSR_GIM_HV_SINT2:
-#ifndef IN_RING3
-            return VINF_CPUM_R3_MSR_WRITE;
-#else
-            LogRelMax(5, ("GIM: HyperV: Guest writing MSR_GIM_HV_SINT2 with %#RX64, ignoring CS:RIP=%04x:%RX64\n", uRawValue,
-                           CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu)));
-            return VERR_CPUM_RAISE_GP_0;
-#endif
+        {
+#ifndef IN_RING3
+            return VINF_CPUM_R3_MSR_WRITE;
+#else
+            PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
+            uint8_t uVector = MSR_GIM_HV_SINT_VECTOR(uRawValue);
+            if (  !MSR_GIM_HV_SINT_IS_MASKED(uRawValue)
+                && uVector < 16)
+            {
+                LogRel(("GIM: HyperV: Programmed an invalid vector in SINT2, uVector=%u -> #GP(0)\n", uVector));
+                return VERR_CPUM_RAISE_GP_0;
+            }
+
+            pHvCpu->uSint2Msr = uRawValue;
+            if (MSR_GIM_HV_SINT_IS_MASKED(uRawValue))
+                LogRel(("GIM: HyperV: Masked SINT2\n"));
+            else
+                LogRel(("GIM: HyperV: Unmasked SINT2, uVector=%u\n", uVector));
+            return VINF_SUCCESS;
+#endif
+        }
+
+        case MSR_GIM_HV_SIMP:
+        {
+#ifndef IN_RING3
+            return VINF_CPUM_R3_MSR_WRITE;
+#else
+            PGIMHVCPU pHvCpu = &pVCpu->gim.s.u.HvCpu;
+            pHvCpu->uSimpMsr = uRawValue;
+            if (MSR_GIM_HV_SIMP_IS_ENABLED(uRawValue))
+            {
+                RTGCPHYS GCPhysSimp = MSR_GIM_HV_SIMP_GPA(uRawValue);
+                if (PGMPhysIsGCPhysNormal(pVM, GCPhysSimp))
+                {
+                    uint8_t abSimp[PAGE_SIZE];
+                    RT_ZERO(abSimp);
+                    int rc2 = PGMPhysSimpleWriteGCPhys(pVM, GCPhysSimp, &abSimp[0], sizeof(abSimp));
+                    if (RT_SUCCESS(rc2))
+                        LogRel(("GIM: HyperV: Enabled synthetic interrupt message page at %#RGp\n", GCPhysSimp));
+                    else
+                    {
+                        LogRel(("GIM: HyperV: WrMsr on MSR_GIM_HV_SIMP failed to update SIMP at %#RGp rc=%Rrc -> #GP(0)\n",
+                                GCPhysSimp, rc2));
+                        return VERR_CPUM_RAISE_GP_0;
+                    }
+                }
+                else
+                    LogRel(("GIM: HyperV: Enabled synthetic interrupt message page at invalid address %#RGp\n",GCPhysSimp));
+            }
+            else
+                LogRel(("GIM: HyperV: Disabled synthetic interrupt message page\n"));
+            return VINF_SUCCESS;
+#endif
+        }
 
         case MSR_GIM_HV_CRASH_P0:  pHv->uCrashP0 = uRawValue;  return VINF_SUCCESS;
@@ -838,5 +945,5 @@
                 return VINF_CPUM_R3_MSR_WRITE;
 #else
-                LogRelMax(5, ("GIM: HyperV: Guest setting debug options MSR to %#RX64, ignoring\n", uRawValue));
+                LogRelMax(5, ("GIM: HyperV: Write debug options MSR with %#RX64 ignored\n", uRawValue));
                 return VINF_SUCCESS;
 #endif
Index: /trunk/src/VBox/VMM/VMMR3/GIM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/GIM.cpp	(revision 58282)
+++ /trunk/src/VBox/VMM/VMMR3/GIM.cpp	(revision 58283)
@@ -89,4 +89,6 @@
      */
     AssertCompile(sizeof(pVM->gim.s) <= sizeof(pVM->gim.padding));
+    AssertCompile(sizeof(pVM->aCpus[0].gim.s) <= sizeof(pVM->aCpus[0].gim.padding));
+
 
     /*
Index: /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 58282)
+++ /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 58283)
@@ -113,5 +113,6 @@
          */
         rc = CFGMR3ValidateConfig(pCfgHv, "/HyperV/",
-                                  "VendorID",
+                                  "VendorID"
+                                  "|VSInterface",
                                   "" /* pszValidNodes */, "GIM/HyperV" /* pszWho */, 0 /* uInstance */);
         if (RT_FAILURE(rc))
@@ -132,5 +133,13 @@
     }
 
-    pHv->fIsInterfaceVs = true;
+    if (pHv->fIsVendorMsHv)
+    {
+        /** @cfgm{/GIM/HyperV/VSInterface, bool, true}
+         * The Microsoft virtualization service interface (debugging). */
+        rc = CFGMR3QueryBoolDef(pCfgHv, "VSInterface", &pHv->fIsInterfaceVs, true);
+        AssertLogRelRCReturn(rc, rc);
+    }
+    else
+        Assert(pHv->fIsInterfaceVs == false);
 
     /*
@@ -169,7 +178,7 @@
                          | GIM_HV_HINT_RELAX_TIME_CHECKS;
 
-        /* Expose more if we're posing as Microsoft. */
-        if (   pHv->fIsVendorMsHv
-            /*&& !pHv->fIsInterfaceVs*/)
+        /* Expose more if we're posing as Microsoft. We can, if needed, force MSR-based Hv
+           debugging by not exposing these bits while exposing the VS interface.*/
+        if (pHv->fIsVendorMsHv)
         {
             pHv->uMiscFeat  |= GIM_HV_MISC_FEAT_GUEST_DEBUGGING
@@ -331,13 +340,12 @@
     if (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_CRASH_MSRS)
         pHv->uCrashCtl = MSR_GIM_HV_CRASH_CTL_NOTIFY_BIT;
-
-    /*
-     * Setup guest-host hypercall based debugging support.
-     */
-    if (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_DEBUGGING)
-    {
-        rc = gimR3HvInitHypercallSupport(pVM);
-        AssertLogRelRCReturn(rc, rc);
-    }
+    for (VMCPUID i = 0; i < pVM->cCpus; i++)
+        pVM->aCpus[i].gim.s.u.HvCpu.uSint2Msr = MSR_GIM_HV_SINT_MASKED_BIT;
+
+    /*
+     * Setup hypercall support.
+     */
+    rc = gimR3HvInitHypercallSupport(pVM);
+    AssertLogRelRCReturn(rc, rc);
 
     return VINF_SUCCESS;
@@ -406,8 +414,5 @@
 {
     gimR3HvReset(pVM);
-
-    PGIMHV pHv = &pVM->gim.s.u.Hv;
-    if (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_DEBUGGING)
-        gimR3HvTermHypercallSupport(pVM);
+    gimR3HvTermHypercallSupport(pVM);
     return VINF_SUCCESS;
 }
@@ -463,5 +468,5 @@
 
     /*
-     * Reset MSRs (Careful! Don't reset non-zero MSRs).
+     * Reset MSRs.
      */
     pHv->u64GuestOsIdMsr        = 0;
@@ -477,4 +482,10 @@
     pHv->uDebugSendBufferMsr    = 0;
     pHv->uDebugRecvBufferMsr    = 0;
+    for (VMCPUID i = 0; i < pVM->cCpus; i++)
+    {
+        PVMCPU pVCpu = &pVM->aCpus[i];
+        pVCpu->gim.s.u.HvCpu.uSint2Msr = MSR_GIM_HV_SINT_MASKED_BIT;
+        pVCpu->gim.s.u.HvCpu.uSimpMsr  = 0;
+    }
 }
 
@@ -1209,11 +1220,9 @@
  * @returns VBox status code.
  * @param   pVM         The cross context VM structure.
- * @param   GCPhysOut   Where to write the hypercall output parameters after
- *                      performing the hypercall.
  * @param   prcHv       Where to store the result of the hypercall operation.
  *
  * @thread  EMT.
  */
-VMMR3_INT_DECL(int) gimR3HvHypercallPostDebugData(PVM pVM, RTGCPHYS GCPhysOut, int *prcHv)
+VMMR3_INT_DECL(int) gimR3HvHypercallPostDebugData(PVM pVM, int *prcHv)
 {
     AssertPtr(pVM);
@@ -1265,5 +1274,5 @@
      * Update the guest memory with result.
      */
-    int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysOut, pHv->pbHypercallOut, sizeof(GIMHVDEBUGPOSTOUT));
+    int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut, sizeof(GIMHVDEBUGPOSTOUT));
     if (RT_FAILURE(rc))
     {
@@ -1282,11 +1291,9 @@
  * @returns VBox status code.
  * @param   pVM         The cross context VM structure.
- * @param   GCPhysOut   Where to write the hypercall output parameters after
- *                      performing the hypercall.
  * @param   prcHv       Where to store the result of the hypercall operation.
  *
  * @thread  EMT.
  */
-VMMR3_INT_DECL(int) gimR3HvHypercallRetrieveDebugData(PVM pVM, RTGCPHYS GCPhysOut, int *prcHv)
+VMMR3_INT_DECL(int) gimR3HvHypercallRetrieveDebugData(PVM pVM, int *prcHv)
 {
     AssertPtr(pVM);
@@ -1345,5 +1352,6 @@
      * Update the guest memory with result.
      */
-    int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysOut, pHv->pbHypercallOut, sizeof(GIMHVDEBUGRETRIEVEOUT) + *pcbReallyRead);
+    int rc = PGMPhysSimpleWriteGCPhys(pVM, pHv->GCPhysHypercallOut, pHv->pbHypercallOut,
+                                      sizeof(GIMHVDEBUGRETRIEVEOUT) + *pcbReallyRead);
     if (RT_FAILURE(rc))
     {
Index: /trunk/src/VBox/VMM/include/GIMHvInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/GIMHvInternal.h	(revision 58282)
+++ /trunk/src/VBox/VMM/include/GIMHvInternal.h	(revision 58283)
@@ -455,7 +455,20 @@
 /** @} */
 
+
+/**
+ * Hypercall parameter type.
+ */
+typedef enum GIMHVHYPERCALLPARAM
+{
+    GIMHVHYPERCALLPARAM_IN = 0,
+    GIMHVHYPERCALLPARAM_OUT
+} GIMHVHYPERCALLPARAM;
+
+
 /** @name Hyper-V hypercall op codes.
  * @{
  */
+/** Post message to hypervisor or VMs. */
+#define GIM_HV_HYPERCALL_OP_POST_MESSAGE          0x5C
 /** Post debug data to hypervisor. */
 #define GIM_HV_HYPERCALL_OP_POST_DEBUG_DATA       0x69
@@ -465,4 +478,5 @@
 #define GIM_HV_HYPERCALL_OP_RESET_DEBUG_SESSION   0x6B
 /** @} */
+
 
 /** @name Hyper-V hypercall inputs.
@@ -660,16 +674,38 @@
  */
 /** Debug send buffer operation success. */
-#define MSR_GIM_HV_SYNTH_DEBUG_STATUS_W_SUCCESS_BIT    RT_BIT_32(0)
+#define MSR_GIM_HV_SYNTH_DEBUG_STATUS_W_SUCCESS_BIT    RT_BIT_64(0)
 /** Debug receive buffer operation success. */
-#define MSR_GIM_HV_SYNTH_DEBUG_STATUS_R_SUCCESS_BIT    RT_BIT_32(2)
+#define MSR_GIM_HV_SYNTH_DEBUG_STATUS_R_SUCCESS_BIT    RT_BIT_64(2)
 /** Debug connection was reset. */
-#define MSR_GIM_HV_SYNTH_DEBUG_STATUS_CONN_RESET_BIT   RT_BIT_32(3)
-/** @} */
-
-
-/** @name Hyper-V hypercall debug support.
- * Options and constants for Hyper-V debug hypercalls.
- * @{
- */
+#define MSR_GIM_HV_SYNTH_DEBUG_STATUS_CONN_RESET_BIT   RT_BIT_64(3)
+/** @} */
+
+
+/** @name Hyper-V MSR - synthetic interrupt (MSR_GIM_HV_SINTx).
+ * @{
+ */
+/** The interrupt masked bit. */
+#define MSR_GIM_HV_SINT_MASKED_BIT                     RT_BIT_64(16)
+/** Whether the interrupt source is masked. */
+#define MSR_GIM_HV_SINT_IS_MASKED(a)                   RT_BOOL((a) & MSR_GIM_HV_SINT_MASKED_BIT)
+/** Interrupt vector. */
+#define MSR_GIM_HV_SINT_VECTOR(a)                      ((a) & UINT64_C(0xff))
+/** @} */
+
+
+/** @name Hyper-V MSR - synthetic interrupt message page (MSR_GIM_HV_SIMP).
+ * @{
+ */
+/** The SIMP enabled bit. */
+#define MSR_GIM_HV_SIMP_ENABLED_BIT                    RT_BIT_64(0)
+/** Whether the SIMP is enabled. */
+#define MSR_GIM_HV_SIMP_IS_ENABLED(a)                  RT_BOOL((a) & MSR_GIM_HV_SIMP_ENABLED_BIT)
+/** The SIMP guest-physical address. */
+#define MSR_GIM_HV_SIMP_GPA(a)                         ((a) & UINT64_C(0xfffffffffffff000))
+/** @} */
+
+
+/** @name Hyper-V hypercall debug options.
+ * @{ */
 /** Maximum debug data payload size in bytes. */
 #define GIM_HV_DEBUG_MAX_DATA_SIZE                4088
@@ -695,4 +731,119 @@
 /** Guest requests purging of outgoing debug data. */
 #define GIM_HV_DEBUG_PURGE_OUTGOING_DATA          RT_BIT_32(1)
+/** @}*/
+
+
+/** @name VMBus.
+ *  These are just arbitrary definitions made up by Microsoft without
+ *  any publicly available specification behind it.
+ * @{ */
+/** VMBus connection ID. */
+#define GIM_HV_VMBUS_MSG_CONNECTION_ID            1
+/** VMBus synthetic interrupt source. */
+#define GIM_HV_VMBUS_MSG_SINT                     2
+/** @} */
+
+
+/** @name Hyper-V synthetic interrupt message type.
+ * @{
+ */
+typedef enum GIMHVMSGTYPE
+{
+    GIMHVMSGTYPE_NONE                 = 0,              /* Common messages */
+    GIMHVMSGTYPE_VMBUS                = 1,              /* Guest messages */
+    GIMHVMSGTYPE_UNMAPPEDGPA          = 0x80000000,     /* Hypervisor messages */
+    GIMHVMSGTYPE_GPAINTERCEPT         = 0x80000001,
+    GIMHVMSGTYPE_TIMEREXPIRED         = 0x80000010,
+    GIMHVMSGTYPE_INVALIDVPREGVAL      = 0x80000020,
+    GIMHVMSGTYPE_UNRECOVERABLEXCPT    = 0x80000021,
+    GIMHVMSGTYPE_UNSUPPORTEDFEAT      = 0x80000022,
+    GIMHVMSGTYPE_APICEOI              = 0x80000030,
+    GIMHVMSGTYPE_X64LEGACYFPERROR     = 0x80000031,
+    GIMHVMSGTYPE_EVENTLOGBUFSCOMPLETE = 0x80000040,
+    GIMHVMSGTYPE_X64IOPORTINTERCEPT   = 0x80010000,
+    GIMHVMSGTYPE_X64MSRINTERCEPT      = 0x80010001,
+    GIMHVMSGTYPE_X64CPUIDINTERCEPT    = 0x80010002,
+    GIMHVMSGTYPE_X64XCPTINTERCEPT     = 0x80010003
+} GIMHVMSGTYPE;
+AssertCompileSize(GIMHVMSGTYPE, 4);
+/** @} */
+
+
+/** @name Hyper-V synthetic interrupt message format.
+ * @{ */
+#define GIM_HV_MSG_SIZE                           256
+#define GIM_HV_MSG_MAX_PAYLOAD_SIZE               240
+#define GIM_HV_MSG_MAX_PAYLOAD_UNITS               30
+
+/**
+ * Synthetic interrupt message flags.
+ */
+typedef union GIMHVMSGFLAGS
+{
+    struct
+    {
+        uint8_t  u1Pending  : 1;
+        uint8_t  u7Reserved : 7;
+    } n;
+    uint8_t u;
+} GIMHVMSGFLAGS;
+AssertCompileSize(GIMHVMSGFLAGS, sizeof(uint8_t));
+
+/**
+ * Synthetic interrupt message header.
+ *
+ * @remarks The layout of this structure differs from
+ *          the Hyper-V spec. Aug 8, 2013 v4.0a. Layout
+ *          in accordance w/ VMBus client expectations.
+ */
+typedef struct GIMHVMSGHDR
+{
+    GIMHVMSGTYPE    enmMessageType;
+    uint8_t         cbPayload;
+    GIMHVMSGFLAGS   MessageFlags;
+    uint16_t        uRsvd;
+    union
+    {
+        uint64_t    uOriginatorId;
+        uint64_t    uPartitionId;
+        uint64_t    uPortId;
+    } msgid;
+} GIMHVMSGHDR;
+/** Pointer to a synthetic interrupt message header. */
+typedef GIMHVMSGHDR *PGIMHVMSGHDR;
+AssertCompileMemberOffset(GIMHVMSGHDR, cbPayload,    4);
+AssertCompileMemberOffset(GIMHVMSGHDR, MessageFlags, 5);
+AssertCompileMemberOffset(GIMHVMSGHDR, msgid,        8);
+AssertCompileSize(GIMHVMSGHDR, GIM_HV_MSG_SIZE - GIM_HV_MSG_MAX_PAYLOAD_SIZE);
+
+/**
+ * Synthetic interrupt message.
+ */
+typedef struct GIMHVMSG
+{
+    GIMHVMSGHDR     MsgHdr;
+    uint64_t        aPayload[GIM_HV_MSG_MAX_PAYLOAD_UNITS];
+} GIMHVMSG;
+/** Pointer to a synthetic interrupt message. */
+typedef GIMHVMSG *PGIMHVMSG;
+AssertCompileSize(GIMHVMSG, GIM_HV_MSG_SIZE);
+/** @} */
+
+
+/** @name Hyper-V hypercall parameters.
+ * @{ */
+/**
+ * HvPostMessage hypercall input.
+ */
+typedef struct GIMHVPOSTMESSAGEIN
+{
+    uint32_t      uConnectionId;
+    uint32_t      uPadding;
+    GIMHVMSGTYPE  enmMessageType;
+    uint32_t      cbPayload;
+} GIMHVPOSTMESSAGEIN;
+/** Pointer to a HvPostMessage input struct. */
+typedef GIMHVPOSTMESSAGEIN *PGIMHVPOSTMESSAGEIN;
+AssertCompileSize(GIMHVPOSTMESSAGEIN, 16);
 
 /**
@@ -853,4 +1004,8 @@
     /** @name Hypercalls. */
     /* @{ */
+    /** Guest address of the hypercall input parameter page. */
+    RTGCPHYS                    GCPhysHypercallIn;
+    /** Guest address of the hypercall output parameter page. */
+    RTGCPHYS                    GCPhysHypercallOut;
     /** Pointer to the hypercall input parameter page - R3. */
     R3PTRTYPE(uint8_t *)        pbHypercallIn;
@@ -889,4 +1044,24 @@
 AssertCompileMemberAlignment(GIMHV, hSpinlockR0, sizeof(uintptr_t));
 
+/**
+ * GIM Hyper-V VCPU instance data.
+ * Changes to this must checked against the padding of the gim union in VMCPU!
+ */
+typedef struct GIMHVCPU
+{
+    /** @name Synthetic interrupt MSRs.
+     * @{ */
+    /** Synthetic interrupt message page MSR. */
+    uint64_t                    uSimpMsr;
+    /** Interrupt source 2 MSR. */
+    uint64_t                    uSint2Msr;
+    /** @} */
+} GIMHVCPU;
+/** Pointer to per-VCPU GIM Hyper-V instance data. */
+typedef GIMHVCPU *PGIMHVCPU;
+/** Pointer to const per-VCPU GIM Hyper-V instance data. */
+typedef GIMHVCPU const *PCGIMHVCPU;
+
+
 RT_C_DECLS_BEGIN
 
@@ -912,6 +1087,6 @@
 VMMR3_INT_DECL(int)             gimR3HvEnableHypercallPage(PVM pVM, RTGCPHYS GCPhysHypercallPage);
 
-VMMR3_INT_DECL(int)             gimR3HvHypercallPostDebugData(PVM pVM, RTGCPHYS GCPhysOut, int *prcHv);
-VMMR3_INT_DECL(int)             gimR3HvHypercallRetrieveDebugData(PVM pVM, RTGCPHYS GCPhysOut, int *prcHv);
+VMMR3_INT_DECL(int)             gimR3HvHypercallPostDebugData(PVM pVM, int *prcHv);
+VMMR3_INT_DECL(int)             gimR3HvHypercallRetrieveDebugData(PVM pVM, int *prcHv);
 VMMR3_INT_DECL(int)             gimR3HvDebugWrite(PVM pVM, void *pvData, uint32_t cbWrite, uint32_t *pcbWritten, bool fUdpPkt);
 VMMR3_INT_DECL(int)             gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t cbRead, uint32_t *pcbRead,
Index: /trunk/src/VBox/VMM/include/GIMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/GIMInternal.h	(revision 58282)
+++ /trunk/src/VBox/VMM/include/GIMInternal.h	(revision 58283)
@@ -97,4 +97,5 @@
     {
         GIMKVMCPU KvmCpu;
+        GIMHVCPU  HvCpu;
     } u;
 } GIMCPU;
