Index: /trunk/include/VBox/err.h
===================================================================
--- /trunk/include/VBox/err.h	(revision 57988)
+++ /trunk/include/VBox/err.h	(revision 57989)
@@ -2671,4 +2671,14 @@
 /** Hypercall cannot be enabled/performed due to access/permissions/CPL. */
 #define VERR_GIM_HYPERCALL_ACCESS_DENIED            (-6311)
+/** Failed to read to a memory region while performing a hypercall. */
+#define VERR_GIM_HYPERCALL_MEMORY_READ_FAILED       (-6312)
+/** Failed to write to a memory region while performing a hypercall. */
+#define VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED      (-6313)
+/** Generic hypercall operation failure. */
+#define VERR_GIM_HYPERCALL_FAILED                   (-6314)
+/** No debug connection configured. */
+#define VERR_GIM_NO_DEBUG_CONNECTION                (-6315)
+/** Return to ring-3 to perform the hypercall there. */
+#define VINF_GIM_R3_HYPERCALL                       6316
 /** @} */
 
Index: /trunk/include/VBox/log.h
===================================================================
--- /trunk/include/VBox/log.h	(revision 57988)
+++ /trunk/include/VBox/log.h	(revision 57989)
@@ -228,4 +228,6 @@
     /** TUN network transport driver group */
     LOG_GROUP_DRV_TUN,
+    /** UDP socket stream driver group. */
+    LOG_GROUP_DRV_UDP,
     /** UDP tunnet network transport driver group. */
     LOG_GROUP_DRV_UDPTUNNEL,
@@ -885,4 +887,5 @@
     "DRV_TRANSPORT_ASYNC", \
     "DRV_TUN",      \
+    "DRV_UDP", \
     "DRV_UDPTUNNEL", \
     "DRV_USBPROXY", \
Index: /trunk/include/VBox/vmm/gim.h
===================================================================
--- /trunk/include/VBox/vmm/gim.h	(revision 57988)
+++ /trunk/include/VBox/vmm/gim.h	(revision 57989)
@@ -32,4 +32,5 @@
 
 #include <VBox/vmm/cpum.h>
+#include <VBox/vmm/pdmifs.h>
 
 /** The value used to specify that VirtualBox must use the newest
@@ -164,5 +165,5 @@
 VMMR3_INT_DECL(int)         GIMR3Term(PVM pVM);
 VMMR3_INT_DECL(void)        GIMR3Reset(PVM pVM);
-VMMR3DECL(void)             GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns);
+VMMR3DECL(void)             GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PPDMISTREAM pDebugStreamR3);
 VMMR3DECL(PGIMMMIO2REGION)  GIMR3GetMmio2Regions(PVM pVM, uint32_t *pcRegions);
 /** @} */
Index: /trunk/include/VBox/vmm/vm.h
===================================================================
--- /trunk/include/VBox/vmm/vm.h	(revision 57988)
+++ /trunk/include/VBox/vmm/vm.h	(revision 57989)
@@ -225,5 +225,5 @@
         struct GIMCPU s;
 #endif
-        uint8_t             padding[64];      /* multiple of 64 */
+        uint8_t             padding[64];        /* multiple of 64 */
     } gim;
 
@@ -1119,5 +1119,5 @@
         struct SSM  s;
 #endif
-        uint8_t     padding[128];        /* multiple of 64 */
+        uint8_t     padding[128];       /* multiple of 64 */
     } ssm;
 
@@ -1128,5 +1128,5 @@
         struct FTM  s;
 #endif
-        uint8_t     padding[512];        /* multiple of 64 */
+        uint8_t     padding[512];       /* multiple of 64 */
     } ftm;
 
@@ -1145,5 +1145,5 @@
         struct GIM s;
 #endif
-        uint8_t     padding[320];        /* multiple of 64 */
+        uint8_t     padding[320+64];    /* multiple of 64 */
     } gim;
 
@@ -1170,5 +1170,5 @@
 
     /** Padding for aligning the cpu array on a page boundary. */
-    uint8_t         abAlignment2[30];
+    uint8_t         abAlignment2[4062];
 
     /* ---- end small stuff ---- */
Index: /trunk/src/VBox/Devices/GIMDev/DrvUDP.cpp
===================================================================
--- /trunk/src/VBox/Devices/GIMDev/DrvUDP.cpp	(revision 57989)
+++ /trunk/src/VBox/Devices/GIMDev/DrvUDP.cpp	(revision 57989)
@@ -0,0 +1,261 @@
+/* $Id$ */
+/** @file
+ * UDP socket stream driver.
+ */
+
+/*
+ * Copyright (C) 2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DRV_UDP
+#include <VBox/log.h>
+#include <VBox/vmm/pdmdrv.h>
+
+#include "VBoxDD.h"
+
+#include <iprt/socket.h>
+#include <iprt/udp.h>
+#include <iprt/uuid.h>
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+/** Converts a pointer to DRVUDP::IStream to a PDRVUDP. */
+#define PDMISTREAM_2_DRVUDP(pInterface) ( (PDRVUDP)((uintptr_t)pInterface - RT_OFFSETOF(DRVUDP, IStream)) )
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+/**
+ * UDP driver instance data.
+ *
+ * @implements PDMISTREAM
+ */
+typedef struct DRVUDP
+{
+    /** The stream interface. */
+    PDMISTREAM          IStream;
+    /** Pointer to the driver instance. */
+    PPDMDRVINS          pDrvIns;
+    /** The server port. */
+    uint16_t            uServerPort;
+    /** The server address. */
+    char               *pszServerAddress;
+    /** The resolved server address struct. */
+    RTNETADDR           ServerAddr;
+    /** The UDP socket. */
+    RTSOCKET            hSocket;
+} DRVUDP, *PDRVUDP;
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+
+
+/** @copydoc PDMISTREAM::pfnRead */
+static DECLCALLBACK(int) drvUDPRead(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)
+{
+    int rc = VINF_SUCCESS;
+    PDRVUDP pThis = PDMISTREAM_2_DRVUDP(pInterface);
+    LogFlowFunc(("pvBuf=%p *pcbRead=%#x (%s:%u)\n", pvBuf, *pcbRead, pThis->pszServerAddress, pThis->uServerPort));
+
+    Assert(pvBuf);
+    Assert(pcbRead);
+    if (pThis->hSocket != NIL_RTSOCKET)
+    {
+        size_t cbReallyRead = 0;
+        rc = RTSocketReadNB(pThis->hSocket, pvBuf, *pcbRead, &cbReallyRead);
+        if (RT_SUCCESS(rc))
+            *pcbRead = cbReallyRead;
+    }
+    else
+        rc = VERR_NET_NOT_SOCKET;
+
+    LogFlowFunc(("*pcbRead=%zu returns %Rrc\n", *pcbRead, rc));
+    return rc;
+}
+
+
+/** @copydoc PDMISTREAM::pfnWrite */
+static DECLCALLBACK(int) drvUDPWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)
+{
+    int rc = VINF_SUCCESS;
+    PDRVUDP pThis = PDMISTREAM_2_DRVUDP(pInterface);
+    LogFlowFunc(("pvBuf=%p *pcbWrite=%#x (%s:%u)\n", pvBuf, *pcbWrite, pThis->pszServerAddress, pThis->uServerPort));
+
+    Assert(pvBuf);
+    Assert(pcbWrite);
+    if (pThis->hSocket != NIL_RTSOCKET)
+    {
+        size_t cbReallyWritten = 0;
+        rc = RTSocketWriteNB(pThis->hSocket, pvBuf, *pcbWrite, &cbReallyWritten);
+        if (RT_SUCCESS(rc))
+            *pcbWrite = cbReallyWritten;
+    }
+    else
+        rc = VERR_NET_NOT_SOCKET;
+
+    LogFlowFunc(("*pcbWrite=%zu returns %Rrc\n", *pcbWrite, rc));
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvUDPQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVUDP    pThis   = PDMINS_2_DATA(pDrvIns, PDRVUDP);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE,   &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMISTREAM, &pThis->IStream);
+    return NULL;
+}
+
+
+/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
+
+/**
+ * Destruct a UDP socket stream driver instance.
+ *
+ * Most VM resources are freed by the VM. This callback is provided so that
+ * any non-VM resources can be freed correctly.
+ *
+ * @param   pDrvIns     The driver instance data.
+ */
+static DECLCALLBACK(void) drvUDPDestruct(PPDMDRVINS pDrvIns)
+{
+    PDRVUDP pThis = PDMINS_2_DATA(pDrvIns, PDRVUDP);
+    LogFlowFunc(("\n"));
+    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+
+    if (pThis->hSocket != NIL_RTSOCKET)
+    {
+        RTSocketClose(pThis->hSocket);
+        pThis->hSocket = NIL_RTSOCKET;
+        LogRel(("DrvUDP#%u: Closed socket to %s:%u\n", pThis->pDrvIns->iInstance, pThis->pszServerAddress, pThis->uServerPort));
+    }
+
+    MMR3HeapFree(pThis->pszServerAddress);
+    pThis->pszServerAddress = NULL;
+}
+
+
+/**
+ * Construct a UDP socket stream driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvUDPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+    PDRVUDP pThis = PDMINS_2_DATA(pDrvIns, PDRVUDP);
+    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+
+    /*
+     * Init the static parts.
+     */
+    pThis->pDrvIns                      = pDrvIns;
+    /* IBase */
+    pDrvIns->IBase.pfnQueryInterface    = drvUDPQueryInterface;
+    /* IStream */
+    pThis->IStream.pfnRead              = drvUDPRead;
+    pThis->IStream.pfnWrite             = drvUDPWrite;
+
+    /*
+     * Validate and read the configuration.
+     */
+    PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "ServerAddress|ServerPort", "");
+
+    int rc = CFGMR3QueryStringAlloc(pCfg, "ServerAddress", &pThis->pszServerAddress);
+    if (RT_FAILURE(rc))
+        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
+                                   N_("Configuration error: querying \"ServerAddress\" resulted in %Rrc"), rc);
+    rc = CFGMR3QueryU16(pCfg, "ServerPort", &pThis->uServerPort);
+    if (RT_FAILURE(rc))
+        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
+                                   N_("Configuration error: querying \"ServerPort\" resulted in %Rrc"), rc);
+
+    /*
+     * Create the socket and connect.
+     */
+    rc = RTUdpCreateClientSocket(pThis->pszServerAddress, pThis->uServerPort, NULL, &pThis->hSocket);
+    if (RT_SUCCESS(rc))
+    {
+        LogRel(("DrvUDP#%u: Connected socket to %s:%u\n", pThis->pDrvIns->iInstance, pThis->pszServerAddress,
+                pThis->uServerPort));
+    }
+    else
+    {
+        LogRel(("DrvUDP#%u: Failed to create/connect socket to %s:%u rc=%Rrc\n", pThis->pDrvIns->iInstance,
+                pThis->pszServerAddress, pThis->uServerPort, rc));
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * UDP socket driver registration record.
+ */
+const PDMDRVREG g_DrvUDP =
+{
+    /* u32Version */
+    PDM_DRVREG_VERSION,
+    /* szName */
+    "UDP",
+    /* szRCMod */
+    "",
+    /* szR0Mod */
+    "",
+    /* pszDescription */
+    "UDP socket stream driver.",
+    /* fFlags */
+    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+    /* fClass. */
+    PDM_DRVREG_CLASS_STREAM,
+    /* cMaxInstances */
+    ~0U,
+    /* cbInstance */
+    sizeof(DRVUDP),
+    /* pfnConstruct */
+    drvUDPConstruct,
+    /* pfnDestruct */
+    drvUDPDestruct,
+    /* pfnRelocate */
+    NULL,
+    /* pfnIOCtl */
+    NULL,
+    /* pfnPowerOn */
+    NULL,
+    /* pfnReset */
+    NULL,
+    /* pfnSuspend */
+    NULL,
+    /* pfnResume */
+    NULL,
+    /* pfnAttach */
+    NULL,
+    /* pfnDetach */
+    NULL,
+    /* pfnPowerOff */
+    NULL,
+    /* pfnSoftReset */
+    NULL,
+    /* u32EndVersion */
+    PDM_DRVREG_VERSION
+};
+
Index: /trunk/src/VBox/Devices/GIMDev/GIMDev.cpp
===================================================================
--- /trunk/src/VBox/Devices/GIMDev/GIMDev.cpp	(revision 57988)
+++ /trunk/src/VBox/Devices/GIMDev/GIMDev.cpp	(revision 57989)
@@ -26,4 +26,7 @@
 
 #include "VBoxDD.h"
+#include <iprt/uuid.h>
+
+#define GIMDEV_DEBUG_LUN                998
 
 /**
@@ -40,12 +43,37 @@
     /** Alignment. */
     RTRCPTR                         Alignment0;
+
+    /** LUN\#998: The debug interface. */
+    PDMIBASE                        IDbgBase;
+    /** LUN\#998: The stream port interface. */
+    PDMISTREAM                      IDbgStreamPort;
+    /** Pointer to the attached base debug driver. */
+    R3PTRTYPE(PPDMIBASE)            pDbgDrvBase;
+    /** Pointer to the attached debug stream driver. */
+    R3PTRTYPE(PPDMISTREAM)          pDbgDrvStream;
 } GIMDEV;
 /** Pointer to the GIM device state. */
 typedef GIMDEV *PGIMDEV;
-
+AssertCompileMemberAlignment(GIMDEV, IDbgBase, 8);
 
 #ifndef VBOX_DEVICE_STRUCT_TESTCASE
 
 #ifdef IN_RING3
+
+
+/* -=-=-=-=-=-=-=-=- PDMIBASE on LUN#GIMDEV_DEBUG_LUN -=-=-=-=-=-=-=-=- */
+
+/**
+ * @interface_method_impl{PDMIBASE, pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) gimdevR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PGIMDEV pThis = RT_FROM_MEMBER(pInterface, GIMDEV, IDbgBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IDbgBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMISTREAM, &pThis->IDbgStreamPort);
+    return NULL;
+}
+
+
 /**
  * @interface_method_impl{PDMDEVREG,pfnConstruct}
@@ -65,8 +93,34 @@
 
     /*
+     * Attach the stream driver for the debug connection.
+     */
+    pThis->IDbgBase.pfnQueryInterface = gimdevR3QueryInterface;
+    int rc = PDMDevHlpDriverAttach(pDevIns, GIMDEV_DEBUG_LUN, &pThis->IDbgBase, &pThis->pDbgDrvBase, "GIM Debug Port");
+    if (RT_SUCCESS(rc))
+    {
+        pThis->pDbgDrvStream = PDMIBASE_QUERY_INTERFACE(pThis->pDbgDrvBase, PDMISTREAM);
+        if (pThis->pDbgDrvStream)
+            LogRel(("GIMDev: LUN#%u: Debug port configured\n", GIMDEV_DEBUG_LUN));
+        else
+            LogRel(("GIMDev: LUN#%u: No unit\n", GIMDEV_DEBUG_LUN));
+    }
+    else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
+    {
+        pThis->pDbgDrvBase   = NULL;
+        pThis->pDbgDrvStream = NULL;
+        LogRel(("GIMDev: LUN#%u: No debug port configured\n", GIMDEV_DEBUG_LUN));
+    }
+    else
+    {
+        AssertLogRelMsgFailed(("GIMDev: LUN#%u: Failed to attach to driver on debug port. rc=%Rrc\n", GIMDEV_DEBUG_LUN, rc));
+        /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
+        return rc;
+    }
+
+    /*
      * Register ourselves with the GIM VMM component.
      */
     PVM pVM = PDMDevHlpGetVM(pDevIns);
-    GIMR3GimDeviceRegister(pVM, pDevIns);
+    GIMR3GimDeviceRegister(pVM, pDevIns, pThis->pDbgDrvStream);
 
     /*
@@ -85,5 +139,5 @@
         {
             Assert(!pCur->fRegistered);
-            int rc = PDMDevHlpMMIO2Register(pDevIns, pCur->iRegion, pCur->cbRegion, 0 /* fFlags */, &pCur->pvPageR3,
+            rc = PDMDevHlpMMIO2Register(pDevIns, pCur->iRegion, pCur->cbRegion, 0 /* fFlags */, &pCur->pvPageR3,
                                             pCur->szDescription);
             if (RT_FAILURE(rc))
@@ -126,4 +180,5 @@
     return VINF_SUCCESS;
 }
+
 
 /**
Index: /trunk/src/VBox/Devices/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Devices/Makefile.kmk	(revision 57988)
+++ /trunk/src/VBox/Devices/Makefile.kmk	(revision 57989)
@@ -153,4 +153,5 @@
  	PC/DevPcArch.cpp \
 	GIMDev/GIMDev.cpp \
+	GIMDev/DrvUDP.cpp \
  	VMMDev/VMMDev.cpp \
  	$(if $(VBOX_WITH_HGCM),VMMDev/VMMDevHGCM.cpp,) \
Index: /trunk/src/VBox/Devices/build/VBoxDD.cpp
===================================================================
--- /trunk/src/VBox/Devices/build/VBoxDD.cpp	(revision 57988)
+++ /trunk/src/VBox/Devices/build/VBoxDD.cpp	(revision 57989)
@@ -339,4 +339,7 @@
     if (RT_FAILURE(rc))
         return rc;
+    rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvUDP);
+    if (RT_FAILURE(rc))
+        return rc;
     rc = pCallbacks->pfnRegister(pCallbacks, &g_DrvRawFile);
     if (RT_FAILURE(rc))
Index: /trunk/src/VBox/Devices/build/VBoxDD.h
===================================================================
--- /trunk/src/VBox/Devices/build/VBoxDD.h	(revision 57988)
+++ /trunk/src/VBox/Devices/build/VBoxDD.h	(revision 57989)
@@ -146,4 +146,5 @@
 extern const PDMDRVREG g_DrvNamedPipe;
 extern const PDMDRVREG g_DrvTCP;
+extern const PDMDRVREG g_DrvUDP;
 extern const PDMDRVREG g_DrvRawFile;
 extern const PDMDRVREG g_DrvHostParallel;
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 57988)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp	(revision 57989)
@@ -1410,4 +1410,10 @@
             InsertConfigInteger(pInst, "Trusted",              1); /* boolean */
             //InsertConfigNode(pInst,    "Config", &pCfg);
+
+            InsertConfigNode(pInst,     "LUN#998", &pLunL0);
+            InsertConfigString(pLunL0,  "Driver", "UDP");
+            InsertConfigNode(pLunL0,    "Config", &pLunL1);
+            InsertConfigString(pLunL1,  "ServerAddress", "127.0.0.1");
+            InsertConfigInteger(pLunL1, "ServerPort", 51000);
         }
 
Index: /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAll.cpp	(revision 57989)
@@ -88,4 +88,6 @@
  * @param   pVCpu       Pointer to the VMCPU.
  * @param   pCtx        Pointer to the guest-CPU context.
+ *
+ * @remarks Guest RIP may or may not have been incremented at this point.
  */
 VMM_INT_DECL(int) GIMHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
@@ -162,4 +164,7 @@
             return gimKvmShouldTrapXcptUD(pVCpu);
 
+        case GIMPROVIDERID_HYPERV:
+            return gimHvShouldTrapXcptUD(pVCpu);
+
         default:
             return false;
@@ -185,4 +190,7 @@
         case GIMPROVIDERID_KVM:
             return gimKvmXcptUD(pVCpu, pCtx, pDis);
+
+        case GIMPROVIDERID_HYPERV:
+            return gimHvXcptUD(pVCpu, pCtx, pDis);
 
         default:
Index: /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp	(revision 57989)
@@ -24,5 +24,11 @@
 #include "GIMInternal.h"
 
+#include <iprt/asm-amd64-x86.h>
+#ifdef IN_RING3
+# include <iprt/mem.h>
+#endif
+
 #include <VBox/err.h>
+#include <VBox/vmm/em.h>
 #include <VBox/vmm/hm.h>
 #include <VBox/vmm/tm.h>
@@ -32,23 +38,229 @@
 #include <VBox/vmm/pdmapi.h>
 
-#include <iprt/asm-amd64-x86.h>
-
-
-/**
- * Handles the Hyper-V hypercall.
+
+#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.
+ *
+ * @returns VBox status code.
+ * @param   pVM               Pointer to the VM.
+ * @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   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)
+{
+    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);
+            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;
+            }
+        }
+        else
+            *prcHv = GIM_HV_STATUS_INVALID_PARAMETER;
+    }
+    else
+        *prcHv = GIM_HV_STATUS_INVALID_ALIGNMENT;
+    return rc;
+}
+#endif
+
+
+/**
+ * Handles all Hyper-V hypercalls.
  *
  * @returns VBox status code.
  * @param   pVCpu           Pointer to the VMCPU.
  * @param   pCtx            Pointer to the guest-CPU context.
+ *
+ * @thread  EMT.
+ * @remarks Guest RIP may or may not have been incremented at this point.
  */
 VMM_INT_DECL(int) gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
 {
-    NOREF(pCtx);
+#ifndef IN_RING3
+    return VINF_GIM_R3_HYPERCALL;
+#else
     PVM pVM = pVCpu->CTX_SUFF(pVM);
+
+    /*
+     * Verify that hypercalls are enabled.
+     */
     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;
+    /*
+     * Verify guest is in ring-0 protected mode.
+     */
+    uint32_t uCpl = CPUMGetGuestCPL(pVCpu);
+    if (   uCpl
+        || CPUMIsGuestInRealModeEx(pCtx))
+    {
+        return VERR_GIM_HYPERCALL_ACCESS_DENIED;
+    }
+
+    /*
+     * Get the hypercall operation code and modes.
+     */
+    const bool       fIs64BitMode     = CPUMIsGuestIn64BitCodeEx(pCtx);
+    const uint64_t   uHyperIn         = fIs64BitMode ? pCtx->rcx : (pCtx->rdx << 32) | pCtx->eax;
+    const uint16_t   uHyperOp         = GIM_HV_HYPERCALL_IN_CALL_CODE(uHyperIn);
+    const bool       fHyperFast       = GIM_HV_HYPERCALL_IN_IS_FAST(uHyperIn);
+    const uint16_t   cHyperReps       = GIM_HV_HYPERCALL_IN_REP_COUNT(uHyperIn);
+    const uint16_t   idxHyperRepStart = GIM_HV_HYPERCALL_IN_REP_START_IDX(uHyperIn);
+    uint64_t         cHyperRepsDone   = 0;
+
+    int rc     = VINF_SUCCESS;
+    int rcHv   = GIM_HV_STATUS_OPERATION_DENIED;
+    PGIMHV pHv = &pVM->gim.s.u.Hv;
+
+    /*
+     * Validate common hypercall input parameters.
+     */
+    if (   !GIM_HV_HYPERCALL_IN_RSVD_1(uHyperIn)
+        && !GIM_HV_HYPERCALL_IN_RSVD_2(uHyperIn)
+        && !GIM_HV_HYPERCALL_IN_RSVD_3(uHyperIn))
+    {
+        /*
+         * Perform the hypercall.
+         */
+        switch (uHyperOp)
+        {
+            case GIM_HV_HYPERCALL_OP_RETREIVE_DEBUG_DATA:   /* Non-rep, memory IO. */
+            {
+                if (pHv->uPartFlags & GIM_HV_PART_FLAGS_DEBUGGING)
+                {
+                    RTGCPHYS GCPhysOut;
+                    rc = gimHvReadSlowHypercallParams(pVM, pCtx, fIs64BitMode, NULL /*pGCPhysIn*/, &GCPhysOut, &rcHv);
+                    if (   RT_SUCCESS(rc)
+                        && rcHv == GIM_HV_STATUS_SUCCESS)
+                    {
+                        rc = gimR3HvHypercallRetrieveDebugData(pVM, GCPhysOut, &rcHv);
+                        if (RT_FAILURE(rc))
+                            LogRelMax(10, ("GIM: HyperV: gimR3HvHypercallRetrieveDebugData failed. rc=%Rrc\n", rc));
+                    }
+                }
+                else
+                    rcHv = GIM_HV_STATUS_ACCESS_DENIED;
+                break;
+            }
+
+            case GIM_HV_HYPERCALL_OP_POST_DEBUG_DATA:   /* Non-rep, memory IO. */
+            {
+                if (pHv->uPartFlags & GIM_HV_PART_FLAGS_DEBUGGING)
+                {
+                    RTGCPHYS GCPhysOut;
+                    rc = gimHvReadSlowHypercallParams(pVM, pCtx, fIs64BitMode, NULL /*pGCPhysIn*/, &GCPhysOut, &rcHv);
+                    if (   RT_SUCCESS(rc)
+                        && rcHv == GIM_HV_STATUS_SUCCESS)
+                    {
+                        rc = gimR3HvHypercallPostDebugData(pVM, GCPhysOut, &rcHv);
+                        if (RT_FAILURE(rc))
+                            LogRelMax(10, ("GIM: HyperV: gimR3HvHypercallPostDebugData failed. rc=%Rrc\n", rc));
+                    }
+                }
+                else
+                    rcHv = GIM_HV_STATUS_ACCESS_DENIED;
+                break;
+            }
+
+            case GIM_HV_HYPERCALL_OP_RESET_DEBUG_SESSION:   /* Non-rep, fast (register IO). */
+            {
+                if (pHv->uPartFlags & GIM_HV_PART_FLAGS_DEBUGGING)
+                {
+                    uint32_t fFlags = 0;
+                    if (!fHyperFast)
+                    {
+                        rc = gimHvReadSlowHypercallParams(pVM, pCtx, fIs64BitMode, NULL /*pGCPhysIn*/, NULL /*pGCPhysOut*/,
+                                                            &rcHv);
+                        if (   RT_SUCCESS(rc)
+                            && rcHv == GIM_HV_STATUS_SUCCESS)
+                        {
+                            PGIMHVDEBUGRESETIN pIn = (PGIMHVDEBUGRESETIN)pHv->pbHypercallIn;
+                            fFlags = pIn->fFlags;
+                        }
+                    }
+                    else
+                    {
+                        rcHv = GIM_HV_STATUS_SUCCESS;
+                        fFlags = fIs64BitMode ? pCtx->rdx : pCtx->ebx;
+                    }
+
+                    /*
+                     * Since we don't really maintain our own buffers for the debug
+                     * communication channel, we don't have anything to flush.
+                     */
+                    if (rcHv == GIM_HV_STATUS_SUCCESS)
+                    {
+                        if (!fFlags)
+                            rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
+                    }
+                }
+                else
+                    rcHv = GIM_HV_STATUS_ACCESS_DENIED;
+                break;
+            }
+
+            default:
+                rcHv = GIM_HV_STATUS_INVALID_HYPERCALL_CODE;
+                break;
+        }
+    }
+    else
+        rcHv = GIM_HV_STATUS_INVALID_HYPERCALL_INPUT;
+
+    /*
+     * Update the guest with results of the hypercall.
+     */
+    if (RT_SUCCESS(rc))
+    {
+        if (fIs64BitMode)
+            pCtx->rax = (cHyperRepsDone << 32) | rcHv;
+        else
+        {
+            pCtx->edx = cHyperRepsDone;
+            pCtx->eax = rcHv;
+        }
+    }
+
+    return rc;
+#endif
 }
 
@@ -122,4 +334,6 @@
  * @param   pRange      The range this MSR belongs to.
  * @param   puValue     Where to store the MSR value read.
+ *
+ * @thread  EMT.
  */
 VMM_INT_DECL(VBOXSTRICTRC) gimHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue)
@@ -195,4 +409,14 @@
         case MSR_GIM_HV_CRASH_P4: *puValue = pHv->uCrashP4;   return VINF_SUCCESS;
 
+        case MSR_GIM_HV_DEBUG_OPTIONS_MSR:
+        {
+            if (pHv->fIsVendorMsHv)
+            {
+                *puValue = GIM_HV_DEBUG_OPTIONS_MSR_ENABLE;
+                return VINF_SUCCESS;
+            }
+            return VERR_CPUM_RAISE_GP_0;
+        }
+
         default:
         {
@@ -201,4 +425,6 @@
             if (s_cTimes++ < 20)
                 LogRel(("GIM: HyperV: Unknown/invalid RdMsr (%#x) -> #GP(0)\n", idMsr));
+#else
+            return VINF_CPUM_R3_MSR_READ;
 #endif
             LogFunc(("Unknown/invalid RdMsr (%#RX32) -> #GP(0)\n", idMsr));
@@ -222,4 +448,6 @@
  * @param   pRange      The range this MSR belongs to.
  * @param   uRawValue   The raw value with the ignored bits not masked.
+ *
+ * @thread  EMT.
  */
 VMM_INT_DECL(VBOXSTRICTRC) gimHvWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue)
@@ -253,4 +481,5 @@
                 gimR3HvDisableHypercallPage(pVM);
                 pHv->u64HypercallMsr &= ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT;
+                LogRel(("GIM: HyperV: Hypercalls disabled via Guest OS ID Msr\n"));
             }
             else
@@ -286,4 +515,5 @@
             return VINF_CPUM_R3_MSR_WRITE;
 #else  /* IN_RING3 */
+# if 0
             /*
              * For now ignore writes to the hypercall MSR (i.e. keeps it disabled).
@@ -292,5 +522,5 @@
              */
             return VINF_SUCCESS;
-# if 0
+# else
             /* First, update all but the hypercall enable bit. */
             pHv->u64HypercallMsr = (uRawValue & ~MSR_GIM_HV_HYPERCALL_ENABLE_BIT);
@@ -399,4 +629,11 @@
             return VERR_CPUM_RAISE_GP_0;
 
+        case MSR_GIM_HV_DEBUG_OPTIONS_MSR:
+        {
+            if (pHv->fIsVendorMsHv)
+                return VINF_SUCCESS;
+            return VERR_CPUM_RAISE_GP_0;
+        }
+
         default:
         {
@@ -406,4 +643,6 @@
                 LogRel(("GIM: HyperV: Unknown/invalid WrMsr (%#x,%#x`%08x) -> #GP(0)\n", idMsr,
                         uRawValue & UINT64_C(0xffffffff00000000), uRawValue & UINT64_C(0xffffffff)));
+#else
+            return VINF_CPUM_R3_MSR_WRITE;
 #endif
             LogFunc(("Unknown/invalid WrMsr (%#RX32,%#RX64) -> #GP(0)\n", idMsr, uRawValue));
@@ -415,2 +654,80 @@
 }
 
+
+/**
+ * Whether we need to trap #UD exceptions in the guest.
+ *
+ * We only need to trap #UD exceptions for raw-mode guests when hypercalls are
+ * enabled. For HM VMs, the hypercall would be handled via the
+ * VMCALL/VMMCALL VM-exit.
+ *
+ * @param   pVCpu       Pointer to the VMCPU.
+ */
+VMM_INT_DECL(bool) gimHvShouldTrapXcptUD(PVMCPU pVCpu)
+{
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    if (   !HMIsEnabled(pVM)
+        && gimHvAreHypercallsEnabled(pVCpu))
+        return true;
+    return false;
+}
+
+
+/**
+ * Exception handler for #UD.
+ *
+ * @param   pVCpu       Pointer to the VMCPU.
+ * @param   pCtx        Pointer to the guest-CPU context.
+ * @param   pDis        Pointer to the disassembled instruction state at RIP.
+ *                      Optional, can be NULL.
+ *
+ * @thread  EMT.
+ */
+VMM_INT_DECL(int) gimHvXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
+{
+    /*
+     * If we didn't ask for #UD to be trapped, bail.
+     */
+    PVM pVM = pVCpu->CTX_SUFF(pVM);
+    if (!gimHvShouldTrapXcptUD(pVCpu))
+        return VERR_GIM_OPERATION_FAILED;
+
+    int rc = VINF_SUCCESS;
+    if (!pDis)
+    {
+        /*
+         * Disassemble the instruction at RIP to figure out if it's the Intel VMCALL instruction
+         * or the AMD VMMCALL instruction and if so, handle it as a hypercall.
+         */
+        DISCPUSTATE Dis;
+        rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, NULL /* pcbInstr */);
+        pDis = &Dis;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        CPUMCPUVENDOR enmGuestCpuVendor = CPUMGetGuestCpuVendor(pVM);
+        if (   (   pDis->pCurInstr->uOpcode == OP_VMCALL
+                && (   enmGuestCpuVendor == CPUMCPUVENDOR_INTEL
+                    || enmGuestCpuVendor == CPUMCPUVENDOR_VIA))
+            || (   pDis->pCurInstr->uOpcode == OP_VMMCALL
+                && enmGuestCpuVendor == CPUMCPUVENDOR_AMD))
+        {
+            /*
+             * Make sure guest ring-0 is the one making the hypercall.
+             */
+            if (CPUMGetGuestCPL(pVCpu))
+                return VERR_GIM_HYPERCALL_ACCESS_DENIED;
+
+            /*
+             * Perform the hypercall and update RIP.
+             */
+            rc = gimHvHypercall(pVCpu, pCtx);
+            pCtx->rip += pDis->cbInstr;
+            return rc;
+        }
+        return VERR_GIM_OPERATION_FAILED;
+    }
+    return VERR_GIM_OPERATION_FAILED;
+}
+
Index: /trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMAll/GIMAllKvm.cpp	(revision 57989)
@@ -45,4 +45,6 @@
  * @param   pVCpu           Pointer to the VMCPU.
  * @param   pCtx            Pointer to the guest-CPU context.
+ *
+ * @remarks Guest RIP may or may not have been incremented at this point.
  */
 VMM_INT_DECL(int) gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
@@ -353,4 +355,6 @@
  * @param   pDis        Pointer to the disassembled instruction state at RIP.
  *                      Optional, can be NULL.
+ *
+ * @thread  EMT.
  */
 VMM_INT_DECL(int) gimKvmXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis)
@@ -364,10 +368,4 @@
         return VERR_GIM_OPERATION_FAILED;
 
-    /*
-     * 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)
@@ -391,4 +389,10 @@
             || pDis->pCurInstr->uOpcode == OP_VMMCALL)
         {
+            /*
+             * Make sure guest ring-0 is the one making the hypercall.
+             */
+            if (CPUMGetGuestCPL(pVCpu))
+                return VERR_GIM_HYPERCALL_ACCESS_DENIED;
+
             if (   pDis->pCurInstr->uOpcode != pKvm->uOpCodeNative
                 && HMIsEnabled(pVM))
Index: /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp	(revision 57989)
@@ -5156,10 +5156,11 @@
         {
             rc = GIMHypercall(pVCpu, pCtx);
-            if (RT_SUCCESS(rc))
+            if (   rc == VINF_SUCCESS
+                || rc == VINF_GIM_R3_HYPERCALL)
             {
                 /* 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;
+                return rc;
             }
         }
Index: /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp	(revision 57989)
@@ -10153,10 +10153,11 @@
 
         rc = GIMHypercall(pVCpu, pMixedCtx);
-        if (RT_SUCCESS(rc))
+        if (   rc == VINF_SUCCESS
+            || rc == VINF_GIM_R3_HYPERCALL)
         {
             /* 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;
+            return rc;
         }
     }
Index: /trunk/src/VBox/VMM/VMMR3/EMHM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/EMHM.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMR3/EMHM.cpp	(revision 57989)
@@ -42,4 +42,5 @@
 #include "EMInternal.h"
 #include <VBox/vmm/vm.h>
+#include <VBox/vmm/gim.h>
 #include <VBox/vmm/cpumdis.h>
 #include <VBox/dis.h>
Index: /trunk/src/VBox/VMM/VMMR3/EMRaw.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/EMRaw.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMR3/EMRaw.cpp	(revision 57989)
@@ -43,4 +43,5 @@
 #include "EMInternal.h"
 #include <VBox/vmm/vm.h>
+#include <VBox/vmm/gim.h>
 #include <VBox/vmm/cpumdis.h>
 #include <VBox/dis.h>
Index: /trunk/src/VBox/VMM/VMMR3/GIM.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/GIM.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMR3/GIM.cpp	(revision 57989)
@@ -72,5 +72,5 @@
 static DECLCALLBACK(int) gimR3Save(PVM pVM, PSSMHANDLE pSSM);
 static DECLCALLBACK(int) gimR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion, uint32_t uPass);
-static FNPGMPHYSHANDLER gimR3Mmio2WriteHandler;
+static FNPGMPHYSHANDLER  gimR3Mmio2WriteHandler;
 
 
@@ -410,10 +410,53 @@
  * Registers the GIM device with VMM.
  *
- * @param   pVM         Pointer to the VM.
- * @param   pDevIns     Pointer to the GIM device instance.
- */
-VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns)
-{
-    pVM->gim.s.pDevInsR3 = pDevIns;
+ * @param   pVM             Pointer to the VM.
+ * @param   pDevInsR3       Pointer to the GIM device instance.
+ * @param   pDebugStream    Pointer to the GIM device debug connection, can be
+ *                          NULL.
+ */
+VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PPDMISTREAM pDebugStreamR3)
+{
+    pVM->gim.s.pDevInsR3 = pDevInsR3;
+    pVM->gim.s.pDebugStreamR3 = pDebugStreamR3;
+}
+
+
+/**
+ * Read data from a host debug session.
+ *
+ * @returns VBox status code.
+ *
+ * @param   pVM         Pointer to the VM.
+ * @param   pvRead      The read buffer.
+ * @param   pcbRead     The size of the read buffer as well as where to store
+ *                      the number of bytes read.
+ * @thread  EMT.
+ */
+VMMR3_INT_DECL(int) GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead)
+{
+    PPDMISTREAM pDebugStream = pVM->gim.s.pDebugStreamR3;
+    if (pDebugStream)
+        return pDebugStream->pfnRead(pDebugStream, pvRead, pcbRead);
+    return VERR_GIM_NO_DEBUG_CONNECTION;
+}
+
+
+/**
+ * Write data to a host debug session.
+ *
+ * @returns VBox status code.
+ *
+ * @param   pVM         Pointer to the VM.
+ * @param   pvWrite     The write buffer.
+ * @param   pcbWrite    The size of the write buffer as well as where to store
+ *                      the number of bytes written.
+ * @thread  EMT.
+ */
+VMMR3_INT_DECL(int) GIMR3DebugWrite(PVM pVM, void *pvWrite, size_t *pcbWrite)
+{
+    PPDMISTREAM pDebugStream = pVM->gim.s.pDebugStreamR3;
+    if (pDebugStream)
+        return pDebugStream->pfnWrite(pDebugStream, pvWrite, pcbWrite);
+    return VERR_GIM_NO_DEBUG_CONNECTION;
 }
 
Index: /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 57988)
+++ /trunk/src/VBox/VMM/VMMR3/GIMHv.cpp	(revision 57989)
@@ -27,7 +27,9 @@
 #include <iprt/string.h>
 #include <iprt/mem.h>
+#include <iprt/semaphore.h>
 #include <iprt/spinlock.h>
 
 #include <VBox/vmm/cpum.h>
+#include <VBox/vmm/mm.h>
 #include <VBox/vmm/ssm.h>
 #include <VBox/vmm/vm.h>
@@ -40,6 +42,4 @@
 *   Defined Constants And Macros                                                                                                 *
 *********************************************************************************************************************************/
-//#define GIMHV_HYPERCALL                 "GIMHvHypercall"
-
 /**
  * GIM Hyper-V saved-state version.
@@ -47,8 +47,4 @@
 #define GIM_HV_SAVED_STATE_VERSION          UINT32_C(1)
 
-
-/*********************************************************************************************************************************
-*   Global Variables                                                                                                             *
-*********************************************************************************************************************************/
 #ifdef VBOX_WITH_STATISTICS
 # define GIMHV_MSRRANGE(a_uFirst, a_uLast, a_szName) \
@@ -59,4 +55,8 @@
 #endif
 
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
 /**
  * Array of MSR ranges supported by Hyper-V.
@@ -75,7 +75,15 @@
     GIMHV_MSRRANGE(MSR_GIM_HV_RANGE9_START,  MSR_GIM_HV_RANGE9_END,  "Hyper-V range 9"),
     GIMHV_MSRRANGE(MSR_GIM_HV_RANGE10_START, MSR_GIM_HV_RANGE10_END, "Hyper-V range 10"),
-    GIMHV_MSRRANGE(MSR_GIM_HV_RANGE11_START, MSR_GIM_HV_RANGE11_END, "Hyper-V range 11")
+    GIMHV_MSRRANGE(MSR_GIM_HV_RANGE11_START, MSR_GIM_HV_RANGE11_END, "Hyper-V range 11"),
+    GIMHV_MSRRANGE(MSR_GIM_HV_RANGE12_START, MSR_GIM_HV_RANGE12_END, "Hyper-V range 12")
 };
 #undef GIMHV_MSRRANGE
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+static int    gimR3HvInitDebugSupport(PVM pVM);
+static void   gimR3HvTermDebugSupport(PVM pVM);
 
 
@@ -105,4 +113,7 @@
     rc = CFGMR3QueryStringDef(pCfgNode, "VendorID", szVendor, sizeof(szVendor), "VBoxVBoxVBox");
     AssertLogRelRCReturn(rc, rc);
+
+    if (!RTStrNCmp(szVendor, GIM_HV_VENDOR_MICROSOFT, sizeof(GIM_HV_VENDOR_MICROSOFT) - 1))
+        pHv->fIsVendorMsHv = true;
 
     /*
@@ -129,10 +140,24 @@
 
         /* Miscellaneous features. */
-        pHv->uMiscFeat = GIM_HV_MISC_FEAT_TIMER_FREQ
-                       | GIM_HV_MISC_FEAT_GUEST_CRASH_MSRS;
+        pHv->uMiscFeat = 0
+                       //| GIM_HV_MISC_FEAT_GUEST_DEBUGGING
+                       //| GIM_HV_MISC_FEAT_XMM_HYPERCALL_INPUT
+                       | GIM_HV_MISC_FEAT_TIMER_FREQ
+                       | GIM_HV_MISC_FEAT_GUEST_CRASH_MSRS
+                       //| GIM_HV_MISC_FEAT_DEBUG_MSRS
+                       ;
 
         /* Hypervisor recommendations to the guest. */
         pHv->uHyperHints = GIM_HV_HINT_MSR_FOR_SYS_RESET
                          | GIM_HV_HINT_RELAX_TIME_CHECKS;
+
+        /* Expose more if we're posing as Microsoft. */
+        if (pHv->fIsVendorMsHv)
+        {
+            pHv->uMiscFeat  |= GIM_HV_MISC_FEAT_GUEST_DEBUGGING
+                             | GIM_HV_MISC_FEAT_DEBUG_MSRS;
+
+            pHv->uPartFlags |= GIM_HV_PART_FLAGS_DEBUGGING;
+        }
     }
 
@@ -190,5 +215,8 @@
     HyperLeaf.uLeaf        = UINT32_C(0x40000000);
     HyperLeaf.uEax         = UINT32_C(0x40000006); /* Minimum value for Hyper-V is 0x40000005. */
-    /* Don't report vendor as 'Microsoft Hv' by default, see @bugref{7270#c152}. */
+    /*
+     * Don't report vendor as 'Microsoft Hv'[1] by default, see @bugref{7270#c152}.
+     * [1]: ebx=0x7263694d ('rciM') ecx=0x666f736f ('foso') edx=0x76482074 ('vH t')
+     */
     {
         uint32_t uVendorEbx;
@@ -258,4 +286,24 @@
         pHv->uCrashCtl = MSR_GIM_HV_CRASH_CTL_NOTIFY_BIT;
 
+    /*
+     * Setup guest-host debugging connection.
+     */
+    if (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_DEBUGGING)
+    {
+        rc = gimR3HvInitDebugSupport(pVM);
+        AssertLogRelRCReturn(rc, rc);
+
+        /*
+         * Pretend that hypercalls are enabled unconditionally when posing as Microsoft,
+         * as Windows guests invoke debug hypercalls before enabling them via the hypercall MSR.
+         */
+        if (pHv->fIsVendorMsHv)
+        {
+            pHv->u64HypercallMsr |= MSR_GIM_HV_HYPERCALL_ENABLE_BIT;
+            for (VMCPUID i = 0; i < pVM->cCpus; i++)
+                VMMHypercallsEnable(&pVM->aCpus[i]);
+        }
+    }
+
     return VINF_SUCCESS;
 }
@@ -323,4 +371,8 @@
 {
     gimR3HvReset(pVM);
+
+    PGIMHV pHv = &pVM->gim.s.u.Hv;
+    if (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_DEBUGGING)
+        gimR3HvTermDebugSupport(pVM);
     return VINF_SUCCESS;
 }
@@ -352,5 +404,6 @@
  *
  * @param   pVM     Pointer to the VM.
- * @thread EMT(0).
+ *
+ * @thread  EMT(0).
  */
 VMMR3_INT_DECL(void) gimR3HvReset(PVM pVM)
@@ -375,5 +428,5 @@
 
     /*
-     * Reset MSRs.
+     * Reset MSRs (Careful! Don't reset non-zero MSRs).
      */
     pHv->u64GuestOsIdMsr = 0;
@@ -385,4 +438,13 @@
     pHv->uCrashP3        = 0;
     pHv->uCrashP4        = 0;
+
+    /* Extra faking required while posing as Microsoft, see gimR3HvInit(). */
+    if (   (pHv->uMiscFeat & GIM_HV_MISC_FEAT_GUEST_DEBUGGING)
+        && pHv->fIsVendorMsHv)
+    {
+        pHv->u64HypercallMsr |= MSR_GIM_HV_HYPERCALL_ENABLE_BIT;
+        for (VMCPUID i = 0; i < pVM->cCpus; i++)
+            VMMHypercallsEnable(&pVM->aCpus[i]);
+    }
 }
 
@@ -870,2 +932,336 @@
 }
 
+
+/**
+ * Initializes Hyper-V guest debugging support.
+ *
+ * @returns VBox status code.
+ * @param   pVM     Pointer to the VM.
+ */
+static int gimR3HvInitDebugSupport(PVM pVM)
+{
+    int rc = VINF_SUCCESS;
+    PGIMHV pHv = &pVM->gim.s.u.Hv;
+    pHv->pbHypercallIn = (uint8_t *)RTMemAllocZ(GIM_HV_PAGE_SIZE);
+    if (RT_LIKELY(pHv->pbHypercallIn))
+    {
+        pHv->pbHypercallOut = (uint8_t *)RTMemAllocZ(GIM_HV_PAGE_SIZE);
+        if (RT_LIKELY(pHv->pbHypercallOut))
+            return VINF_SUCCESS;
+        RTMemFree(pHv->pbHypercallIn);
+    }
+    return VERR_NO_MEMORY;
+}
+
+
+/**
+ * Terminates Hyper-V guest debugging support.
+ *
+ * @param   pVM     Pointer to the VM.
+ */
+static void gimR3HvTermDebugSupport(PVM pVM)
+{
+    PGIMHV pHv = &pVM->gim.s.u.Hv;
+    RTMemFree(pHv->pbHypercallIn);
+    pHv->pbHypercallIn = NULL;
+
+    RTMemFree(pHv->pbHypercallOut);
+    pHv->pbHypercallOut = NULL;
+}
+
+
+/**
+ * Reads data from a debugger connection, asynchronous.
+ *
+ * @returns VBox status code.
+ * @param   pVM         Pointer to the VM.
+ * @param   pvBuf       Where to read the data.
+ * @param   cbBuf       Size of the read buffer @a pvBuf.
+ * @param   pcbRead     Where to store how many bytes were really read.
+ * @param   cMsTimeout  Timeout of the read operation in milliseconds.
+ *
+ * @thread  EMT.
+ */
+static int gimR3HvDebugRead(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead, uint32_t cMsTimeout)
+{
+    NOREF(cMsTimeout);      /** @todo implement */
+    PGIMHV pHv = &pVM->gim.s.u.Hv;
+    AssertCompile(sizeof(size_t) >= sizeof(uint32_t));
+    size_t cbRead = cbBuf;
+    int rc = GIMR3DebugRead(pVM, pvBuf, &cbRead);
+    *pcbRead = (uint32_t)cbRead;
+    return rc;
+}
+
+
+/**
+ * Writes data to the debugger connection, asynchronous.
+ *
+ * @returns VBox status code.
+ * @param   pVM         Pointer to the VM.
+ * @param   pvBuf       Pointer to the data to be written.
+ * @param   cbBuf       Size of the write buffer @a pvBuf.
+ * @param   pcbWritten  Where to store how many bytes were really written.
+ *
+ * @thread  EMT.
+ */
+static int gimR3HvDebugWrite(PVM pVM, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+{
+    PGIMHV pHv = &pVM->gim.s.u.Hv;
+    AssertCompile(sizeof(size_t) >= sizeof(uint32_t));
+    size_t cbWrite = cbBuf;
+    int rc = GIMR3DebugWrite(pVM, pvBuf, &cbWrite);
+    *pcbWritten = (uint32_t)cbWrite;
+    return rc;
+}
+
+
+/**
+ * Performs the HvPostDebugData hypercall.
+ *
+ * @returns VBox status code.
+ * @param   pVM         Pointer to the VM.
+ * @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)
+{
+    AssertPtr(pVM);
+    AssertPtr(prcHv);
+    PGIMHV pHv = &pVM->gim.s.u.Hv;
+    int    rcHv = GIM_HV_STATUS_OPERATION_DENIED;
+
+    /*
+     * Grab the parameters.
+     */
+    PGIMHVDEBUGPOSTIN pIn = (PGIMHVDEBUGPOSTIN)pHv->pbHypercallIn;
+    AssertPtrReturn(pIn, VERR_GIM_IPE_1);
+    uint32_t   cbWrite = pIn->cbWrite;
+    uint32_t   fFlags = pIn->fFlags;
+    uint8_t   *pbData = ((uint8_t *)pIn) + sizeof(PGIMHVDEBUGPOSTIN);
+
+    PGIMHVDEBUGPOSTOUT pOut = (PGIMHVDEBUGPOSTOUT)pHv->pbHypercallOut;
+    AssertPtrReturn(pOut, VERR_GIM_IPE_2);
+    uint32_t *pcbPendingWrite = &pOut->cbPending;
+
+    /*
+     * Perform the hypercall.
+     */
+#if 0
+    /* Currently disabled as Windows 10 guest passes us undocumented flags. */
+    if (fFlags & ~GIM_HV_DEBUG_POST_OPTIONS_MASK))
+        rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
+#endif
+    if (cbWrite > GIM_HV_DEBUG_MAX_DATA_SIZE)
+        rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
+    else if (!cbWrite)
+        rcHv = GIM_HV_STATUS_SUCCESS;
+    else if (cbWrite > 0)
+    {
+        bool fIgnorePacket = false;
+        if (pHv->fIsVendorMsHv)
+        {
+            /*
+             * Windows guests sends us ethernet frames over the Hyper-V debug connection.
+             * It sends DHCP/ARP queries with zero'd out MAC addresses and requires fudging up the
+             * packets somewhere.
+             *
+             * The Microsoft WinDbg debugger talks UDP and thus only expects the actual debug
+             * protocol payload.
+             *
+             * At present, we only handle guests configured with the "nodhcp" option. This makes
+             * the guest send ARP queries with a self-chosen IP and after a couple of attempts of
+             * receiving no replies, the guest picks its own IP address. After this, the guest
+             * starts sending the UDP packets we require. We thus ignore the initial ARP packets
+             * (and to be safe all non-UDP packets) until the guest eventually starts talking
+             * UDP. Then we can finally feed the UDP payload over the debug connection.
+             */
+            if (cbWrite > sizeof(RTNETETHERHDR))
+            {
+                PRTNETETHERHDR pEtherHdr = (PRTNETETHERHDR)pbData;
+                if (pEtherHdr->EtherType != RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4))
+                    fIgnorePacket = true;       /* Supress passing ARP and other non IPv4 frames to debugger. */
+                else if (cbWrite > sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN)
+                {
+                    /* Extract UDP payload, recording the guest IP address to pass to the debugger. */
+                    PRTNETIPV4 pIp4Hdr = (PRTNETIPV4)(pbData + sizeof(RTNETETHERHDR));
+                    if (   pIp4Hdr->ip_v == 4
+                        && pIp4Hdr->ip_p == RTNETIPV4_PROT_UDP)
+                    {
+                        pHv->DbgGuestAddr = pIp4Hdr->ip_src;
+                        pbData += sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN;
+                        cbWrite -= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN;
+                    }
+                    else
+                        fIgnorePacket = true;   /* Supress passing non-UDP packets to the debugger. */
+                }
+            }
+        }
+
+        if (!fIgnorePacket)
+        {
+            uint32_t cbReallyWritten = 0;
+            int rc2 = gimR3HvDebugWrite(pVM, pbData, cbWrite, &cbReallyWritten);
+            if (   RT_SUCCESS(rc2)
+                && cbReallyWritten == cbWrite)
+            {
+                *pcbPendingWrite = 0;
+                rcHv = GIM_HV_STATUS_SUCCESS;
+            }
+            else
+            {
+                /*
+                 * No need to update "*pcbPendingWrite" here as the guest isn't supposed to/doesn't
+                 * look at any of the output parameters when we fail the hypercall operation.
+                 */
+                rcHv = GIM_HV_STATUS_INSUFFICIENT_BUFFERS;
+            }
+        }
+        else
+        {
+            /* Pretend success. */
+            *pcbPendingWrite = 0;
+            rcHv = GIM_HV_STATUS_SUCCESS;
+        }
+    }
+
+    /*
+     * Update the guest memory with result.
+     */
+    int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysOut, pHv->pbHypercallOut, sizeof(GIMHVDEBUGPOSTOUT));
+    if (RT_FAILURE(rc))
+    {
+        LogRelMax(10, ("GIM: HyperV: HvPostDebugData failed to update guest memory. rc=%Rrc\n", rc));
+        rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
+    }
+
+    *prcHv = rcHv;
+    return rc;
+}
+
+
+/**
+ * Performs the HvRetrieveDebugData hypercall.
+ *
+ * @returns VBox status code.
+ * @param   pVM         Pointer to the VM.
+ * @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)
+{
+    AssertPtr(pVM);
+    AssertPtr(prcHv);
+    PGIMHV pHv = &pVM->gim.s.u.Hv;
+    int    rcHv = GIM_HV_STATUS_OPERATION_DENIED;
+
+    /*
+     * Grab the parameters.
+     */
+    PGIMHVDEBUGRETRIEVEIN pIn = (PGIMHVDEBUGRETRIEVEIN)pHv->pbHypercallIn;
+    AssertPtrReturn(pIn, VERR_GIM_IPE_1);
+    uint32_t   cbRead = pIn->cbRead;
+    uint32_t   fFlags = pIn->fFlags;
+    uint64_t   uTimeout = pIn->u64Timeout;
+    uint32_t   cMsTimeout = (fFlags & GIM_HV_DEBUG_RETREIVE_LOOP) ? (uTimeout * 100) / RT_NS_1MS_64 : 0;
+
+    PGIMHVDEBUGRETRIEVEOUT pOut = (PGIMHVDEBUGRETRIEVEOUT)pHv->pbHypercallOut;
+    AssertPtrReturn(pOut, VERR_GIM_IPE_2);
+    uint32_t   *pcbReallyRead = &pOut->cbRead;
+    uint32_t   *pcbRemainingRead = &pOut->cbRemaining;
+    void       *pvData = ((uint8_t *)pOut) + sizeof(GIMHVDEBUGRETRIEVEOUT);
+
+    /*
+     * Perform the hypercall.
+     */
+    *pcbReallyRead    = 0;
+    *pcbRemainingRead = cbRead;
+#if 0
+    /* Currently disabled as Windows 10 guest passes us undocumented flags. */
+    if (fFlags & ~GIM_HV_DEBUG_RETREIVE_OPTIONS_MASK)
+        rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
+#endif
+    if (cbRead > GIM_HV_DEBUG_MAX_DATA_SIZE)
+        rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
+    else if (fFlags & GIM_HV_DEBUG_RETREIVE_TEST_ACTIVITY)
+        rcHv = GIM_HV_STATUS_SUCCESS; /** @todo implement this. */
+    else if (!cbRead)
+        rcHv = GIM_HV_STATUS_SUCCESS;
+    else if (cbRead > 0)
+    {
+        int rc2 = gimR3HvDebugRead(pVM, pvData, cbRead, pcbReallyRead, cMsTimeout);
+        Assert(*pcbReallyRead <= cbRead);
+        if (   RT_SUCCESS(rc2)
+            && *pcbReallyRead > 0)
+        {
+            uint8_t abFrame[sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + sizeof(RTNETUDP)];
+            if (   pHv->fIsVendorMsHv
+                && *pcbReallyRead + sizeof(abFrame) <= GIM_HV_PAGE_SIZE)
+            {
+                /*
+                 * Windows guests pumps ethernet frames over the Hyper-V debug connection as
+                 * explained in gimR3HvHypercallPostDebugData(). Here, we reconstruct the packet
+                 * with the guest's self-chosen IP ARP address we saved in pHv->DbgGuestAddr.
+                 *
+                 * Note! We really need to pass the minimum IPv4 header length. The Windows 10 guest
+                 * is -not- happy if we include the IPv4 options field, i.e. using sizeof(RTNETIPV4)
+                 * instead of RTNETIPV4_MIN_LEN.
+                 */
+                RT_ZERO(abFrame);
+                PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)&abFrame[0];
+                PRTNETIPV4     pIpHdr  = (PRTNETIPV4)    (pEthHdr + 1);
+                PRTNETUDP      pUdpHdr = (PRTNETUDP)     ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
+
+                /* Ethernet */
+                pEthHdr->EtherType = RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4);
+                /* IPv4 */
+                pIpHdr->ip_v       = 4;
+                pIpHdr->ip_hl      = RTNETIPV4_MIN_LEN / sizeof(uint32_t);
+                pIpHdr->ip_tos     = 0;
+                pIpHdr->ip_len     = RT_H2N_U16((uint16_t)*pcbReallyRead + sizeof(RTNETUDP) + RTNETIPV4_MIN_LEN);
+                pIpHdr->ip_id      = 0;
+                pIpHdr->ip_off     = 0;
+                pIpHdr->ip_ttl     = 255;
+                pIpHdr->ip_p       = RTNETIPV4_PROT_UDP;
+                pIpHdr->ip_sum     = 0;
+                pIpHdr->ip_src.u   = 0;
+                pIpHdr->ip_dst.u   = pHv->DbgGuestAddr.u;
+                pIpHdr->ip_sum     = RTNetIPv4HdrChecksum(pIpHdr);
+                /* UDP */
+                pUdpHdr->uh_ulen   = RT_H2N_U16_C((uint16_t)*pcbReallyRead + sizeof(*pUdpHdr));
+
+                /* Make room by moving the payload and prepending the headers. */
+                uint8_t *pbData = (uint8_t *)pvData;
+                memmove(pbData + sizeof(abFrame), pbData, *pcbReallyRead);
+                memcpy(pbData, &abFrame[0], sizeof(abFrame));
+
+                /* Update the adjusted sizes. */
+                *pcbReallyRead += sizeof(abFrame);
+                *pcbRemainingRead = cbRead - *pcbReallyRead;
+            }
+            rcHv = GIM_HV_STATUS_SUCCESS;
+        }
+        else
+            rcHv = GIM_HV_STATUS_NO_DATA;
+    }
+
+    /*
+     * Update the guest memory with result.
+     */
+    int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysOut, pHv->pbHypercallOut, sizeof(GIMHVDEBUGRETRIEVEOUT) + *pcbReallyRead);
+    if (RT_FAILURE(rc))
+    {
+        LogRelMax(10, ("GIM: HyperV: HvRetrieveDebugData failed to update guest memory. rc=%Rrc\n", rc));
+        rc = VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED;
+    }
+
+    *prcHv = rcHv;
+    return rc;
+}
+
Index: /trunk/src/VBox/VMM/include/EMHandleRCTmpl.h
===================================================================
--- /trunk/src/VBox/VMM/include/EMHandleRCTmpl.h	(revision 57988)
+++ /trunk/src/VBox/VMM/include/EMHandleRCTmpl.h	(revision 57989)
@@ -232,4 +232,11 @@
             break;
 
+        /*
+         * GIM hypercall.
+         */
+        case VINF_GIM_R3_HYPERCALL:
+            rc = GIMHypercall(pVCpu, pCtx);
+            break;
+
 #ifdef EMHANDLERC_WITH_HM
         /*
Index: /trunk/src/VBox/VMM/include/GIMHvInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/GIMHvInternal.h	(revision 57988)
+++ /trunk/src/VBox/VMM/include/GIMHvInternal.h	(revision 57989)
@@ -22,4 +22,5 @@
 #include <VBox/vmm/cpum.h>
 
+#include <iprt/net.h>
 
 /** @name Hyper-V base feature identification.
@@ -32,7 +33,7 @@
 #define GIM_HV_BASE_FEAT_PART_TIME_REF_COUNT_MSR  RT_BIT(1)
 /** Basic Synthetic Interrupt Controller MSRs available. */
-#define GIM_HV_BASE_FEAT_BASIC_SYNTH_IC           RT_BIT(2)
+#define GIM_HV_BASE_FEAT_BASIC_SYNIC_MSRS         RT_BIT(2)
 /** Synthetic Timer MSRs available. */
-#define GIM_HV_BASE_FEAT_SYNTH_TIMER_MSRS         RT_BIT(3)
+#define GIM_HV_BASE_FEAT_STIMER_MSRS              RT_BIT(3)
 /** APIC access MSRs (EOI, ICR, TPR) available. */
 #define GIM_HV_BASE_FEAT_APIC_ACCESS_MSRS         RT_BIT(4)
@@ -125,5 +126,5 @@
 #define GIM_HV_MISC_FEAT_TIMER_FREQ               RT_BIT(8)
 /** Support for injecting synthetic machine checks. */
-#define GIM_HV_MISC_FEAT_INJECT_SYNTH_MC_XCPT     RT_BIT(9)
+#define GIM_HV_MISC_FEAT_INJECT_SYNMC_XCPT        RT_BIT(9)
 /** Support for guest crash MSRs. */
 #define GIM_HV_MISC_FEAT_GUEST_CRASH_MSRS         RT_BIT(10)
@@ -360,5 +361,12 @@
 
 /** Start of range 11. */
-#define MSR_GIM_HV_RANGE11_START                  UINT32_C(0x40000100)
+#define MSR_GIM_HV_RANGE11_START                  UINT32_C(0x400000FF)
+/** Undocumented debug options MSR. */
+#define MSR_GIM_HV_DEBUG_OPTIONS_MSR              UINT32_C(0x400000FF)
+/** End of range 11. */
+#define MSR_GIM_HV_RANGE11_END                    MSR_GIM_HV_DEBUG_OPTIONS_MSR
+
+/** Start of range 12. */
+#define MSR_GIM_HV_RANGE12_START                  UINT32_C(0x40000100)
 /** Guest crash MSR 0. */
 #define MSR_GIM_HV_CRASH_P0                       UINT32_C(0x40000100)
@@ -373,6 +381,6 @@
 /** Guest crash control. */
 #define MSR_GIM_HV_CRASH_CTL                      UINT32_C(0x40000105)
-/** End of range 11. */
-#define MSR_GIM_HV_RANGE11_END                    MSR_GIM_HV_CRASH_CTL
+/** End of range 12. */
+#define MSR_GIM_HV_RANGE12_END                    MSR_GIM_HV_CRASH_CTL
 /** @} */
 
@@ -447,6 +455,289 @@
 /** @} */
 
+/** @name Hyper-V hypercall op codes.
+ * @{
+ */
+/** Post debug data to hypervisor. */
+#define GIM_HV_HYPERCALL_OP_POST_DEBUG_DATA       0x69
+/** Retreive debug data from hypervisor. */
+#define GIM_HV_HYPERCALL_OP_RETREIVE_DEBUG_DATA   0x6A
+/** Reset debug session. */
+#define GIM_HV_HYPERCALL_OP_RESET_DEBUG_SESSION   0x6B
+/** @} */
+
+/** @name Hyper-V hypercall inputs.
+ * @{
+ */
+/** The hypercall call operation code. */
+#define GIM_HV_HYPERCALL_IN_CALL_CODE(a)         ((a) & UINT64_C(0xffff))
+/** Whether it's a fast (register based) hypercall or not (memory-based). */
+#define GIM_HV_HYPERCALL_IN_IS_FAST(a)           RT_BOOL((a) & RT_BIT_64(16))
+/** Total number of reps for a rep hypercall. */
+#define GIM_HV_HYPERCALL_IN_REP_COUNT(a)         (((a) << 32) & UINT64_C(0xfff))
+/** Rep start index for a rep hypercall. */
+#define GIM_HV_HYPERCALL_IN_REP_START_IDX(a)     (((a) << 48) & UINT64_C(0xfff))
+/** Reserved bits range 1. */
+#define GIM_HV_HYPERCALL_IN_RSVD_1(a)            (((a) << 17) & UINT64_C(0x7fff))
+/** Reserved bits range 2. */
+#define GIM_HV_HYPERCALL_IN_RSVD_2(a)            (((a) << 44) & UINT64_C(0xf))
+/** Reserved bits range 3. */
+#define GIM_HV_HYPERCALL_IN_RSVD_3(a)            (((a) << 60) & UINT64_C(0x7))
+/** @} */
+
+
+/** @name Hyper-V hypercall status codes.
+ * @{
+ */
+/** Success. */
+#define GIM_HV_STATUS_SUCCESS                                        0x00
+/** Unrecognized hypercall. */
+#define GIM_HV_STATUS_INVALID_HYPERCALL_CODE                         0x02
+/** Invalid hypercall input (rep count, rsvd bits). */
+#define GIM_HV_STATUS_INVALID_HYPERCALL_INPUT                        0x03
+/** Hypercall guest-physical address not 8-byte aligned or crosses page boundary. */
+#define GIM_HV_STATUS_INVALID_ALIGNMENT                              0x04
+/** Invalid hypercall parameters. */
+#define GIM_HV_STATUS_INVALID_PARAMETER                              0x05
+/** Access denied. */
+#define GIM_HV_STATUS_ACCESS_DENIED                                  0x06
+/** The partition state not valid for specified op. */
+#define GIM_HV_STATUS_INVALID_PARTITION_STATE                        0x07
+/** The hypercall operation could not be performed. */
+#define GIM_HV_STATUS_OPERATION_DENIED                               0x08
+/** Specified partition property ID not recognized. */
+#define GIM_HV_STATUS_UNKNOWN_PROPERTY                               0x09
+/** Specified partition property value not within range. */
+#define GIM_HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE                    0x0a
+/** Insufficient memory for performing the hypercall. */
+#define GIM_HV_STATUS_INSUFFICIENT_MEMORY                            0x0b
+/** Maximum partition depth has been exceeded for the partition hierarchy. */
+#define GIM_HV_STATUS_PARTITION_TOO_DEEP                             0x0c
+/** The specified partition ID is not valid. */
+#define GIM_HV_STATUS_INVALID_PARTITION_ID                           0x0d
+/** The specified virtual processor index in invalid. */
+#define GIM_HV_STATUS_INVALID_VP_INDEX                               0x0e
+/** The specified port ID is not unique or doesn't exist. */
+#define GIM_HV_STATUS_INVALID_PORT_ID                                0x11
+/** The specified connection ID is not unique or doesn't exist. */
+#define GIM_HV_STATUS_INVALID_CONNECTION_ID                          0x12
+/** The target port doesn't have sufficient buffers for the caller to post a message. */
+#define GIM_HV_STATUS_INSUFFICIENT_BUFFERS                           0x13
+/** External interrupt not acknowledged.*/
+#define GIM_HV_STATUS_NOT_ACKNOWLEDGED                               0x14
+/** External interrupt acknowledged. */
+#define GIM_HV_STATUS_ACKNOWLEDGED                                   0x16
+/** Invalid state due to misordering Hv[Save|Restore]PartitionState. */
+#define GIM_HV_STATUS_INVALID_SAVE_RESTORE_STATE                     0x17
+/** Operation not perform due to a required feature of SynIc was disabled. */
+#define GIM_HV_STATUS_INVALID_SYNIC_STATE                            0x18
+/** Object or value already in use. */
+#define GIM_HV_STATUS_OBJECT_IN_USE                                  0x19
+/** Invalid proximity domain information. */
+#define GIM_HV_STATUS_INVALID_PROXIMITY_DOMAIN_INFO                  0x1A
+/** Attempt to retrieve data failed. */
+#define GIM_HV_STATUS_NO_DATA                                        0x1B
+/** Debug connection has not recieved any new data since the last time. */
+#define GIM_HV_STATUS_INACTIVE                                       0x1C
+/** A resource is unavailable for allocation. */
+#define GIM_HV_STATUS_NO_RESOURCES                                   0x1D
+/** A hypervisor feature is not available to the caller. */
+#define GIM_HV_STATUS_FEATURE_UNAVAILABLE                            0x1E
+/** The debug packet returned is partial due to an I/O error. */
+#define GIM_HV_STATUS_PARTIAL_PACKET                                 0x1F
+/** Processor feature SSE3 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_SSE3_NOT_SUPPORTED                   0x20
+/** Processor feature LAHSAHF unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_LAHSAHF_NOT_SUPPORTED                0x21
+/** Processor feature SSSE3 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_SSSE3_NOT_SUPPORTED                  0x22
+/** Processor feature SSE4.1 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_SSE4_1_NOT_SUPPORTED                 0x23
+/** Processor feature SSE4.2 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_SSE4_2_NOT_SUPPORTED                 0x24
+/** Processor feature SSE4A unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_SSE4A_NOT_SUPPORTED                  0x25
+/** Processor feature XOP unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_XOP_NOT_SUPPORTED                    0x26
+/** Processor feature POPCNT unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_POPCNT_NOT_SUPPORTED                 0x27
+/** Processor feature CMPXCHG16B unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_CMPXCHG16B_NOT_SUPPORTED             0x28
+/** Processor feature ALTMOVCR8 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_ALTMOVCR8_NOT_SUPPORTED              0x29
+/** Processor feature LZCNT unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_LZCNT_NOT_SUPPORTED                  0x2A
+/** Processor feature misaligned SSE unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_MISALIGNED_SSE_NOT_SUPPORTED         0x2B
+/** Processor feature MMX extensions unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_MMX_EXT_NOT_SUPPORTED                0x2C
+/** Processor feature 3DNow! unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_3DNOW_NOT_SUPPORTED                  0x2D
+/** Processor feature Extended 3DNow! unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_EXTENDED_3DNOW_NOT_SUPPORTED         0x2E
+/** Processor feature 1GB large page unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_PAGE_1GB_NOT_SUPPORTED               0x2F
+/** Processor cache line flush size incompatible. */
+#define GIM_HV_STATUS_PROC_CACHE_LINE_FLUSH_SIZE_INCOMPATIBLE        0x30
+/** Processor feature XSAVE unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_XSAVE_NOT_SUPPORTED                  0x31
+/** Processor feature XSAVEOPT unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_XSAVEOPT_NOT_SUPPORTED               0x32
+/** The specified buffer was too small for all requested data. */
+#define GIM_HV_STATUS_INSUFFICIENT_BUFFER                            0x33
+/** Processor feature XSAVEOPT unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_XSAVE_AVX_NOT_SUPPORTED              0x34
+/** Processor feature XSAVEOPT unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_XSAVE_FEAT_NOT_SUPPORTED             0x35   /** Huh, isn't this same as 0x31? */
+/** Processor feature XSAVEOPT unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_PAGE_XSAVE_SAVE_AREA_INCOMPATIBLE    0x36
+/** Processor architecture unsupoorted. */
+#define GIM_HV_STATUS_INCOMPATIBLE_PROCESSOR                         0x37
+/** Max. domains for platform I/O remapping reached. */
+#define GIM_HV_STATUS_INSUFFICIENT_DEVICE_DOMAINS                    0x38
+/** Processor feature AES unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_AES_NOT_SUPPORTED                    0x39
+/** Processor feature PCMULQDQ unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_PCMULQDQ_NOT_SUPPORTED               0x3A
+/** Processor feature XSAVE features unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_XSAVE_FEATURES_INCOMPATIBLE          0x3B
+/** Generic CPUID validation error. */
+#define GIM_HV_STATUS_CPUID_FEAT_VALIDATION_ERROR                    0x3C
+/** XSAVE CPUID validation error. */
+#define GIM_HV_STATUS_CPUID_XSAVE_FEAT_VALIDATION_ERROR              0x3D
+/** Processor startup timed out. */
+#define GIM_HV_STATUS_PROCESSOR_STARTUP_TIMEOUT                      0x3E
+/** SMX enabled by the BIOS. */
+#define GIM_HV_STATUS_SMX_ENABLED                                    0x3F
+/** Processor feature PCID unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_PCID_NOT_SUPPORTED                   0x40
+/** Invalid LP index. */
+#define GIM_HV_STATUS_INVALID_LP_INDEX                               0x41
+/** Processor feature PCID unsupported. */
+#define GIM_HV_STATUS_FEAT_FMA4_NOT_SUPPORTED                        0x42
+/** Processor feature PCID unsupported. */
+#define GIM_HV_STATUS_FEAT_F16C_NOT_SUPPORTED                        0x43
+/** Processor feature PCID unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_RDRAND_NOT_SUPPORTED                 0x44
+/** Processor feature RDWRFSGS unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_RDWRFSGS_NOT_SUPPORTED               0x45
+/** Processor feature SMEP unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_SMEP_NOT_SUPPORTED                   0x46
+/** Processor feature enhanced fast string unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_ENHANCED_FAST_STRING_NOT_SUPPORTED   0x47
+/** Processor feature MOVBE unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_MOVBE_NOT_SUPPORTED                  0x48
+/** Processor feature BMI1 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_BMI1_NOT_SUPPORTED                   0x49
+/** Processor feature BMI2 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_BMI2_NOT_SUPPORTED                   0x4A
+/** Processor feature HLE unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_HLE_NOT_SUPPORTED                    0x4B
+/** Processor feature RTM unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_RTM_NOT_SUPPORTED                    0x4C
+/** Processor feature XSAVE FMA unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_XSAVE_FMA_NOT_SUPPORTED              0x4D
+/** Processor feature XSAVE AVX2 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_XSAVE_AVX2_NOT_SUPPORTED             0x4E
+/** Processor feature NPIEP1 unsupported. */
+#define GIM_HV_STATUS_PROC_FEAT_NPIEP1_NOT_SUPPORTED                 0x4F
+/** @} */
+
+
+/** @name Hyper-V debug support.
+ * Options and constants for Hyper-V debug hypercalls.
+ * @{
+ */
+/** Maximum debug data payload size in bytes. */
+#define GIM_HV_DEBUG_MAX_DATA_SIZE                4088
+
+/** The undocumented bit for MSR_GIM_HV_DEBUG_OPTIONS_MSR that makes it all
+ *  work. */
+#define GIM_HV_DEBUG_OPTIONS_MSR_ENABLE           RT_BIT(2)
+
+/** Guest will perform the HvPostDebugData hypercall until completion. */
+#define GIM_HV_DEBUG_POST_LOOP                    RT_BIT_32(0)
+/** Mask of valid HvPostDebugData options. */
+#define GIM_HV_DEBUG_POST_OPTIONS_MASK            RT_BIT_32(0)
+
+/** Guest will perform the HvRetrieveDebugData hypercall until completion. */
+#define GIM_HV_DEBUG_RETREIVE_LOOP                RT_BIT_32(0)
+/** Guest checks if any global debug session is active. */
+#define GIM_HV_DEBUG_RETREIVE_TEST_ACTIVITY       RT_BIT_32(1)
+/** Mask of valid HvRetrieveDebugData options. */
+#define GIM_HV_DEBUG_RETREIVE_OPTIONS_MASK        RT_BIT_32(0) | RT_BIT_32(1)
+
+/** Guest requests purging of incoming debug data. */
+#define GIM_HV_DEBUG_PURGE_INCOMING_DATA          RT_BIT_32(0)
+/** Guest requests purging of outgoing debug data. */
+#define GIM_HV_DEBUG_PURGE_OUTGOING_DATA          RT_BIT_32(1)
+
+/**
+ * HvResetDebugData hypercall input.
+ */
+typedef struct GIMHVDEBUGRESETIN
+{
+    uint32_t fFlags;
+    uint32_t uPadding;
+} GIMHVDEBUGRESETIN;
+/** Pointer to a HvResetDebugData input struct. */
+typedef GIMHVDEBUGRESETIN *PGIMHVDEBUGRESETIN;
+AssertCompileSize(GIMHVDEBUGRESETIN, 8);
+
+/**
+ * HvPostDebugData hypercall input.
+ */
+typedef struct GIMHVDEBUGPOSTIN
+{
+    uint32_t cbWrite;
+    uint32_t fFlags;
+} GIMHVDEBUGPOSTIN;
+/** Pointer to a HvPostDebugData input struct. */
+typedef GIMHVDEBUGPOSTIN *PGIMHVDEBUGPOSTIN;
+AssertCompileSize(GIMHVDEBUGPOSTIN, 8);
+
+/**
+ * HvPostDebugData hypercall output.
+ */
+typedef struct GIMHVDEBUGPOSTOUT
+{
+    uint32_t cbPending;
+    uint32_t uPadding;
+} GIMHVDEBUGPOSTOUT;
+/** Pointer to a HvPostDebugData output struct. */
+typedef GIMHVDEBUGPOSTOUT *PGIMHVDEBUGPOSTOUT;
+AssertCompileSize(GIMHVDEBUGPOSTOUT, 8);
+
+/**
+ * HvRetrieveDebugData hypercall input.
+ */
+typedef struct GIMHVDEBUGRETRIEVEIN
+{
+    uint32_t cbRead;
+    uint32_t fFlags;
+    uint64_t u64Timeout;
+} GIMHVDEBUGRETRIEVEIN;
+/** Pointer to a HvRetrieveDebugData input struct. */
+typedef GIMHVDEBUGRETRIEVEIN *PGIMHVDEBUGRETRIEVEIN;
+AssertCompileSize(GIMHVDEBUGRETRIEVEIN, 16);
+
+/**
+ * HvRetriveDebugData hypercall output.
+ */
+typedef struct GIMHVDEBUGRETRIEVEOUT
+{
+    uint32_t cbRead;
+    uint32_t cbRemaining;
+} GIMHVDEBUGRETRIEVEOUT;
+/** Pointer to a HvRetrieveDebugData output struct. */
+typedef GIMHVDEBUGRETRIEVEOUT *PGIMHVDEBUGRETRIEVEOUT;
+AssertCompileSize(GIMHVDEBUGRETRIEVEOUT, 8);
+/** @} */
+
+
 /** Hyper-V page size.  */
-#define GIM_HV_PAGE_SIZE                          0x1000
+#define GIM_HV_PAGE_SIZE                          4096
+
+/** Microsoft Hyper-V vendor signature. */
+#define GIM_HV_VENDOR_MICROSOFT                   "Microsoft Hv"
 
 /**
@@ -476,5 +767,4 @@
 typedef GIMHVREFTSC const *PCGIMHVREFTSC;
 
-
 /**
  * GIM Hyper-V VM instance data.
@@ -483,6 +773,6 @@
 typedef struct GIMHV
 {
-    /** @name MSRs.
-     *  { */
+    /** @name Primary MSRs.
+     * @{ */
     /** Guest OS identity MSR. */
     uint64_t                    u64GuestOsIdMsr;
@@ -494,5 +784,5 @@
 
     /** @name CPUID features.
-     *  { */
+     * @{ */
     /** Basic features. */
     uint32_t                    uBaseFeat;
@@ -510,5 +800,5 @@
 
     /** @name Guest Crash MSRs.
-     *  @{
+     * @{
      */
     /** Guest crash control MSR. */
@@ -526,4 +816,6 @@
     /** @} */
 
+    /** @name Time management.
+     * @{ */
     /** Per-VM R0 Spinlock for protecting EMT writes to the TSC page. */
     RTSPINLOCK                  hSpinlockR0;
@@ -533,4 +825,23 @@
     /** The TSC frequency (in HZ) reported to the guest. */
     uint64_t                    cTscTicksPerSecond;
+    /** @} */
+
+    /** @name Hypercalls. */
+    /* @{ */
+    /** Pointer to the hypercall input parameter page - R3. */
+    R3PTRTYPE(uint8_t *)        pbHypercallIn;
+    /** Pointer to the hypercall output parameter page - R3. */
+    R3PTRTYPE(uint8_t *)        pbHypercallOut;
+    /** @} */
+
+    /** @name Guest debugging.
+     * @{ */
+    /** Whether we're posing as the official Microsoft vendor. */
+    bool                        fIsVendorMsHv;
+    bool                        afAlignment0[7];
+    /** The auto IP address last chosen by the guest after failed ARP queries. */
+    RTNETADDRIPV4               DbgGuestAddr;
+    uint32_t                    uAlignment1;
+    /** @} */
 
     /** Array of MMIO2 regions. */
@@ -566,8 +877,13 @@
 VMMR3_INT_DECL(int)             gimR3HvDisableHypercallPage(PVM pVM);
 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);
 #endif /* IN_RING3 */
 
 VMM_INT_DECL(bool)              gimHvIsParavirtTscEnabled(PVM pVM);
 VMM_INT_DECL(bool)              gimHvAreHypercallsEnabled(PVMCPU pVCpu);
+VMM_INT_DECL(bool)              gimHvShouldTrapXcptUD(PVMCPU pVCpu);
+VMM_INT_DECL(int)               gimHvXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis);
 VMM_INT_DECL(int)               gimHvHypercall(PVMCPU pVCpu, PCPUMCTX pCtx);
 VMM_INT_DECL(VBOXSTRICTRC)      gimHvReadMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
Index: /trunk/src/VBox/VMM/include/GIMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/GIMInternal.h	(revision 57988)
+++ /trunk/src/VBox/VMM/include/GIMInternal.h	(revision 57989)
@@ -52,6 +52,8 @@
     uint32_t                        u32Padding;
 
-    /** Pointer to the GIM device - ring-3 context. */
+    /** Pointer to the GIM device - R3 ptr. */
     R3PTRTYPE(PPDMDEVINS)            pDevInsR3;
+    /** Pointer to the GIM device debug stream - R3 ptr. */
+    R3PTRTYPE(PPDMISTREAM)           pDebugStreamR3;
 #if 0
     /** Pointer to the provider's ring-3 hypercall handler. */
@@ -105,4 +107,7 @@
 VMMR3_INT_DECL(int)           GIMR3Mmio2HandlerPhysicalRegister(PVM pVM, PGIMMMIO2REGION pRegion);
 VMMR3_INT_DECL(int)           GIMR3Mmio2HandlerPhysicalDeregister(PVM pVM, PGIMMMIO2REGION pRegion);
+
+VMMR3_INT_DECL(int)           GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead);
+VMMR3_INT_DECL(int)           GIMR3DebugWrite(PVM pVM, void *pvWrite, size_t *pcbWrite);
 #endif /* IN_RING3 */
 
