VirtualBox

Changeset 58390 in vbox


Ignore:
Timestamp:
Oct 23, 2015 12:35:35 PM (9 years ago)
Author:
vboxsync
Message:

VMM/GIM: Implement Hyper-V debug receive thread optimization. Added a few statistics to GIM.
Fixed a bug in Windows guests' debug DHCP handling.

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/gim.h

    r58124 r58390  
    100100AssertCompileMemberAlignment(GIMMMIO2REGION, pvPageR0, 8);
    101101
    102 #if 0
    103102/**
    104  * A GIM Hypercall handler.
     103 * Debug data buffer available callback over the GIM debug connection.
    105104 *
    106  * @param   pVCpu   The cross context virtual CPU structure of the calling EMT.
    107  * @param   pCtx    Pointer to the guest-CPU context.
     105 * @param   pVM             The cross context VM structure.
    108106 */
    109 typedef DECLCALLBACK(int) FNGIMHYPERCALL(PVMCPU pVCpu, PCPUMCTX pCtx);
    110 /** Pointer to a GIM hypercall handler. */
    111 typedef FNGIMHYPERCALL *PFNGIMHYPERCALL;
     107typedef DECLCALLBACK(void) FNGIMDEBUGBUFAVAIL(PVM pVM);
     108/** Pointer to GIM debug buffer available callback. */
     109typedef FNGIMDEBUGBUFAVAIL *PFNGIMDEBUGBUFAVAIL;
    112110
    113111/**
    114  * A GIM MSR-read handler.
     112 * GIM debug setup.
    115113 *
    116  * @returns VBox status code.
    117  * @param   pVCpu   The cross context virtual CPU structure of the calling EMT.
    118  * @param   idMsr   The MSR being read.
    119  * @param   pRange  The range that the MSR belongs to.
    120  * @param   puValue Where to store the value of the MSR.
     114 * These are parameters/options filled in by the GIM provider and passed along
     115 * to the GIM device.
    121116 */
    122 typedef DECLCALLBACK(int) FNGIMRDMSR(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue);
    123 /** Pointer to a GIM MSR-read handler. */
    124 typedef FNGIMRDMSR *PFNGIMRDMSR;
     117typedef struct GIMDEBUGSETUP
     118{
     119    /** The callback to invoke when the receive buffer has data. */
     120    PFNGIMDEBUGBUFAVAIL     pfnDbgRecvBufAvail;
     121    /** The size of the receive buffer as specified by the GIM provider. */
     122    uint32_t                cbDbgRecvBuf;
     123} GIMDEBUGSETUP;
     124/** Pointer to a GIM debug setup struct. */
     125typedef struct GIMDEBUGSETUP *PGIMDEBUGSETUP;
     126/** Pointer to a const GIM debug setup struct. */
     127typedef struct GIMDEBUGSETUP const *PCGGIMDEBUGSETUP;
    125128
    126129/**
    127  * A GIM MSR-write handler.
     130 * GIM debug structure (common to the GIM device and GIM).
    128131 *
    129  * @returns VBox status code.
    130  * @param   pVCpu       The cross context virtual CPU structure of the calling EMT.
    131  * @param   idMsr       The MSR being written.
    132  * @param   pRange      The range that the MSR belongs to.
    133  * @param   uValue      The value to set, ignored bits masked.
    134  * @param   uRawValue   The raw value with the ignored bits not masked.
     132 * This is used to exchanging data between the GIM provider and the GIM device.
    135133 */
    136 typedef DECLCALLBACK(int) FNGIMWRMSR(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue);
    137 /** Pointer to a GIM MSR-write handler. */
    138 typedef FNGIMWRMSR *PFNGIMWRMSR;
    139 #endif
     134typedef struct GIMDEBUG
     135{
     136    /** The receive buffer. */
     137    void                   *pvDbgRecvBuf;
     138    /** The debug I/O stream driver. */
     139    PPDMISTREAM             pDbgDrvStream;
     140    /** Number of bytes pending to be read from the receive buffer. */
     141    uint32_t                cbDbgRecvBufRead;
     142    /** The flag synchronizing reads of the receive buffer from EMT. */
     143    volatile bool           fDbgRecvBufRead;
     144    /** The receive thread wakeup semaphore. */
     145    RTSEMEVENTMULTI         hDbgRecvThreadSem;
     146} GIMDEBUG;
     147/** Pointer to a GIM debug struct. */
     148typedef struct GIMDEBUG *PGIMDEBUG;
     149/** Pointer to a const GIM debug struct. */
     150typedef struct GIMDEBUG const *PCGIMDEBUG;
    140151
    141152
     
    166177VMMR3_INT_DECL(int)         GIMR3Term(PVM pVM);
    167178VMMR3_INT_DECL(void)        GIMR3Reset(PVM pVM);
    168 VMMR3DECL(void)             GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PPDMISTREAM pDebugStreamR3);
     179VMMR3DECL(void)             GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PGIMDEBUG pDbg);
     180VMMR3DECL(int)              GIMR3GetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup);
    169181VMMR3DECL(PGIMMMIO2REGION)  GIMR3GetMmio2Regions(PVM pVM, uint32_t *pcRegions);
    170182/** @} */
  • trunk/src/VBox/Devices/GIMDev/DrvUDP.cpp

    r57989 r58390  
    8080    {
    8181        size_t cbReallyRead = 0;
    82         rc = RTSocketReadNB(pThis->hSocket, pvBuf, *pcbRead, &cbReallyRead);
     82        rc = RTSocketRead(pThis->hSocket, pvBuf, *pcbRead, &cbReallyRead);
    8383        if (RT_SUCCESS(rc))
    8484            *pcbRead = cbReallyRead;
     
    103103    if (pThis->hSocket != NIL_RTSOCKET)
    104104    {
    105         size_t cbReallyWritten = 0;
    106         rc = RTSocketWriteNB(pThis->hSocket, pvBuf, *pcbWrite, &cbReallyWritten);
     105        size_t cbBuf = *pcbWrite;
     106        rc = RTSocketWriteToNB(pThis->hSocket, pvBuf, cbBuf, NULL /*pDstAddr*/);
    107107        if (RT_SUCCESS(rc))
    108             *pcbWrite = cbReallyWritten;
     108            *pcbWrite = cbBuf;
    109109    }
    110110    else
     
    147147    if (pThis->hSocket != NIL_RTSOCKET)
    148148    {
     149        RTSocketRetain(pThis->hSocket);
     150        RTSocketShutdown(pThis->hSocket, true, true);
    149151        RTSocketClose(pThis->hSocket);
    150152        pThis->hSocket = NIL_RTSOCKET;
  • trunk/src/VBox/Devices/GIMDev/GIMDev.cpp

    r57989 r58390  
    2626
    2727#include "VBoxDD.h"
     28#include <iprt/alloc.h>
     29#include <iprt/semaphore.h>
    2830#include <iprt/uuid.h>
    2931
     
    5052    /** Pointer to the attached base debug driver. */
    5153    R3PTRTYPE(PPDMIBASE)            pDbgDrvBase;
    52     /** Pointer to the attached debug stream driver. */
    53     R3PTRTYPE(PPDMISTREAM)          pDbgDrvStream;
     54    /** The debug receive thread. */
     55    RTTHREAD                        hDbgRecvThread;
     56    /** Flag to indicate shutdown of the debug receive thread. */
     57    bool volatile                   fDbgRecvThreadShutdown;
     58    /** The debug setup parameters. */
     59    GIMDEBUGSETUP                   DbgSetup;
     60    /** The debug transfer struct. */
     61    GIMDEBUG                        Dbg;
    5462} GIMDEV;
    5563/** Pointer to the GIM device state. */
     
    7684
    7785
     86static DECLCALLBACK(int) gimDevR3DbgRecvThread(RTTHREAD ThreadSelf, void *pvUser)
     87{
     88    /*
     89     * Validate.
     90     */
     91    PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
     92    AssertReturn(pDevIns, VERR_INVALID_PARAMETER);
     93    PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
     94
     95    PGIMDEV pThis = PDMINS_2_DATA(pDevIns, PGIMDEV);
     96    AssertReturn(pThis, VERR_INVALID_POINTER);
     97    AssertReturn(pThis->DbgSetup.cbDbgRecvBuf, VERR_INTERNAL_ERROR);
     98    AssertReturn(pThis->Dbg.hDbgRecvThreadSem != NIL_RTSEMEVENTMULTI, VERR_INTERNAL_ERROR_2);
     99    AssertReturn(pThis->Dbg.pvDbgRecvBuf, VERR_INTERNAL_ERROR_3);
     100
     101    PVM pVM = PDMDevHlpGetVM(pDevIns);
     102    AssertReturn(pVM, VERR_INVALID_POINTER);
     103
     104    PPDMISTREAM pDbgDrvStream = pThis->Dbg.pDbgDrvStream;
     105    AssertReturn(pDbgDrvStream, VERR_INVALID_POINTER);
     106
     107    for (;;)
     108    {
     109        /*
     110         * Read incoming debug data.
     111         */
     112        size_t cbRead = pThis->DbgSetup.cbDbgRecvBuf;
     113        int rc = pDbgDrvStream->pfnRead(pDbgDrvStream, pThis->Dbg.pvDbgRecvBuf, &cbRead);
     114        if (   RT_SUCCESS(rc)
     115            && cbRead > 0)
     116        {
     117            /*
     118             * Notify the consumer thread.
     119             */
     120            if (ASMAtomicReadBool(&pThis->Dbg.fDbgRecvBufRead) == false)
     121            {
     122                if (pThis->DbgSetup.pfnDbgRecvBufAvail)
     123                    pThis->DbgSetup.pfnDbgRecvBufAvail(pVM);
     124                pThis->Dbg.cbDbgRecvBufRead = cbRead;
     125                RTSemEventMultiReset(pThis->Dbg.hDbgRecvThreadSem);
     126                ASMAtomicWriteBool(&pThis->Dbg.fDbgRecvBufRead, true);
     127            }
     128
     129            /*
     130             * Wait until the consumer thread has acknowledged reading of the
     131             * current buffer or we're asked to shut down.
     132             *
     133             * It is important that we do NOT re-invoke 'pfnRead' before the
     134             * current buffer is consumed, otherwise we risk data corruption.
     135             */
     136            while (   ASMAtomicReadBool(&pThis->Dbg.fDbgRecvBufRead) == true
     137                   && !pThis->fDbgRecvThreadShutdown)
     138            {
     139                RTSemEventMultiWait(pThis->Dbg.hDbgRecvThreadSem, RT_INDEFINITE_WAIT);
     140            }
     141        }
     142        else if (   rc != VINF_TRY_AGAIN
     143                 && rc != VERR_TRY_AGAIN)
     144        {
     145            LogRel(("GIMDev: Debug thread terminating with rc=%Rrc\n", rc));
     146            break;
     147        }
     148
     149        if (pThis->fDbgRecvThreadShutdown)
     150        {
     151            LogRel(("GIMDev: Debug thread shutting down\n"));
     152            break;
     153        }
     154    }
     155
     156    return VINF_SUCCESS;
     157}
     158
     159
    78160/**
    79161 * @interface_method_impl{PDMDEVREG,pfnConstruct}
     
    93175
    94176    /*
    95      * Attach the stream driver for the debug connection.
    96      */
    97     pThis->IDbgBase.pfnQueryInterface = gimdevR3QueryInterface;
    98     int rc = PDMDevHlpDriverAttach(pDevIns, GIMDEV_DEBUG_LUN, &pThis->IDbgBase, &pThis->pDbgDrvBase, "GIM Debug Port");
    99     if (RT_SUCCESS(rc))
    100     {
    101         pThis->pDbgDrvStream = PDMIBASE_QUERY_INTERFACE(pThis->pDbgDrvBase, PDMISTREAM);
    102         if (pThis->pDbgDrvStream)
    103             LogRel(("GIMDev: LUN#%u: Debug port configured\n", GIMDEV_DEBUG_LUN));
     177     * Get debug setup requirements from GIM.
     178     */
     179    PVM pVM = PDMDevHlpGetVM(pDevIns);
     180    int rc = GIMR3GetDebugSetup(pVM, &pThis->DbgSetup);
     181    if (   RT_SUCCESS(rc)
     182        && pThis->DbgSetup.cbDbgRecvBuf > 0)
     183    {
     184        /*
     185         * Attach the stream driver for the debug connection.
     186         */
     187        PPDMISTREAM pDbgDrvStream = NULL;
     188        pThis->IDbgBase.pfnQueryInterface = gimdevR3QueryInterface;
     189        rc = PDMDevHlpDriverAttach(pDevIns, GIMDEV_DEBUG_LUN, &pThis->IDbgBase, &pThis->pDbgDrvBase, "GIM Debug Port");
     190        if (RT_SUCCESS(rc))
     191        {
     192            pDbgDrvStream = PDMIBASE_QUERY_INTERFACE(pThis->pDbgDrvBase, PDMISTREAM);
     193            if (pDbgDrvStream)
     194                LogRel(("GIMDev: LUN#%u: Debug port configured\n", GIMDEV_DEBUG_LUN));
     195            else
     196                LogRel(("GIMDev: LUN#%u: No unit\n", GIMDEV_DEBUG_LUN));
     197        }
     198        else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
     199        {
     200            pThis->pDbgDrvBase = NULL;
     201            LogRel(("GIMDev: LUN#%u: No debug port configured\n", GIMDEV_DEBUG_LUN));
     202        }
    104203        else
    105             LogRel(("GIMDev: LUN#%u: No unit\n", GIMDEV_DEBUG_LUN));
    106     }
    107     else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
    108     {
    109         pThis->pDbgDrvBase   = NULL;
    110         pThis->pDbgDrvStream = NULL;
    111         LogRel(("GIMDev: LUN#%u: No debug port configured\n", GIMDEV_DEBUG_LUN));
    112     }
    113     else
    114     {
    115         AssertLogRelMsgFailed(("GIMDev: LUN#%u: Failed to attach to driver on debug port. rc=%Rrc\n", GIMDEV_DEBUG_LUN, rc));
    116         /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
    117         return rc;
    118     }
    119 
    120     /*
    121      * Register ourselves with the GIM VMM component.
    122      */
    123     PVM pVM = PDMDevHlpGetVM(pDevIns);
    124     GIMR3GimDeviceRegister(pVM, pDevIns, pThis->pDbgDrvStream);
     204        {
     205            AssertLogRelMsgFailed(("GIMDev: LUN#%u: Failed to attach to driver on debug port. rc=%Rrc\n", GIMDEV_DEBUG_LUN, rc));
     206            /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
     207            return rc;
     208        }
     209
     210        void *pvDbgRecvBuf = RTMemAllocZ(pThis->DbgSetup.cbDbgRecvBuf);
     211        if (RT_UNLIKELY(!pvDbgRecvBuf))
     212        {
     213            LogRel(("GIMDev: Failed to alloc %u bytes for debug receive buffer\n", pThis->DbgSetup.cbDbgRecvBuf));
     214            return VERR_NO_MEMORY;
     215        }
     216
     217        /*
     218         * Update the shared debug struct.
     219         */
     220        pThis->Dbg.pDbgDrvStream    = pDbgDrvStream;
     221        pThis->Dbg.pvDbgRecvBuf     = pvDbgRecvBuf;
     222        pThis->Dbg.cbDbgRecvBufRead = 0;
     223        pThis->Dbg.fDbgRecvBufRead  = false;
     224
     225        /*
     226         * Create the sempahore and the debug receive thread itself.
     227         */
     228        rc = RTSemEventMultiCreate(&pThis->Dbg.hDbgRecvThreadSem);
     229        if (RT_SUCCESS(rc))
     230        {
     231            rc = RTThreadCreate(&pThis->hDbgRecvThread, gimDevR3DbgRecvThread, pDevIns, 0 /*cbStack*/, RTTHREADTYPE_IO,
     232                                RTTHREADFLAGS_WAITABLE, "GIMDebugRecv");
     233            if (RT_FAILURE(rc))
     234            {
     235                RTSemEventMultiDestroy(pThis->Dbg.hDbgRecvThreadSem);
     236                pThis->Dbg.hDbgRecvThreadSem = NIL_RTSEMEVENTMULTI;
     237
     238                RTMemFree(pThis->Dbg.pvDbgRecvBuf);
     239                pThis->Dbg.pvDbgRecvBuf = NULL;
     240                return rc;
     241            }
     242        }
     243        else
     244            return rc;
     245    }
     246
     247    /*
     248     * Register this device with the GIM component.
     249     */
     250    GIMR3GimDeviceRegister(pVM, pDevIns, pThis->DbgSetup.cbDbgRecvBuf ? &pThis->Dbg : NULL);
    125251
    126252    /*
     
    197323        if (RT_FAILURE(rc))
    198324            return rc;
     325    }
     326
     327    /*
     328     * Signal and wait for the debug thread to terminate.
     329     */
     330    if (pThis->hDbgRecvThread != NIL_RTTHREAD)
     331    {
     332        pThis->fDbgRecvThreadShutdown = true;
     333        if (pThis->Dbg.hDbgRecvThreadSem != NIL_RTSEMEVENT)
     334            RTSemEventMultiSignal(pThis->Dbg.hDbgRecvThreadSem);
     335
     336        int rc = RTThreadWait(pThis->hDbgRecvThread, 20000, NULL /*prc*/);
     337        if (RT_SUCCESS(rc))
     338            pThis->hDbgRecvThread = NIL_RTTHREAD;
     339        else
     340        {
     341            LogRel(("GIMDev: Debug thread did not terminate, rc=%Rrc!\n", rc));
     342            return VERR_RESOURCE_BUSY;
     343        }
     344    }
     345
     346    /*
     347     * Now clean up the semaphore & buffer now that the thread is gone.
     348     */
     349    if (pThis->Dbg.hDbgRecvThreadSem != NIL_RTSEMEVENT)
     350    {
     351        RTSemEventMultiDestroy(pThis->Dbg.hDbgRecvThreadSem);
     352        pThis->Dbg.hDbgRecvThreadSem = NIL_RTSEMEVENTMULTI;
     353    }
     354    if (pThis->Dbg.pvDbgRecvBuf)
     355    {
     356        RTMemFree(pThis->Dbg.pvDbgRecvBuf);
     357        pThis->Dbg.pvDbgRecvBuf = NULL;
    199358    }
    200359
  • trunk/src/VBox/VMM/VMMAll/GIMAll.cpp

    r58126 r58390  
    9999        return VERR_GIM_NOT_ENABLED;
    100100
     101    STAM_COUNTER_INC(&pVM->gim.s.StatHypercalls);
    101102    switch (pVM->gim.s.enmProviderId)
    102103    {
  • trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp

    r58331 r58390  
    242242
    243243                    /*
    244                      * Since we don't really maintain our own buffers for the debug
    245                      * communication channel, we don't have anything to flush.
     244                     * Nothing to flush on the sending side as we don't maintain our own buffers.
    246245                     */
     246                    /** @todo We should probably ask the debug receive thread to flush it's buffer. */
    247247                    if (rcHv == GIM_HV_STATUS_SUCCESS)
    248248                    {
    249249                        if (fFlags)
    250                             LogRelMax(1, ("GIM: HyperV: Resetting debug session via hypercall\n"));
     250                            LogRel(("GIM: HyperV: Resetting debug session via hypercall\n"));
    251251                        else
    252252                            rcHv = GIM_HV_STATUS_INVALID_PARAMETER;
     
    470470
    471471        case MSR_GIM_HV_SYNTH_DEBUG_STATUS:
    472             *puValue = pHv->uDebugStatusMsr;
     472            *puValue = pHv->uDbgStatusMsr;
    473473            return VINF_SUCCESS;
    474474
     
    508508                return VINF_CPUM_R3_MSR_READ;
    509509#else
    510                 LogRelMax(1, ("GIM: HyperV: Guest queried debug options MSR\n"));
    511                 *puValue = GIM_HV_DEBUG_OPTIONS_MSR_ENABLE;
     510                LogRelMax(1, ("GIM: HyperV: Guest querying debug options, suggesting %s interface\n",
     511                              pHv->fDbgHypercallInterface ? "hypercall" : "MSR"));
     512                *puValue = pHv->fDbgHypercallInterface ? GIM_HV_DEBUG_OPTIONS_USE_HYPERCALLS : 0;
    512513                return VINF_SUCCESS;
    513514#endif
     
    724725        case MSR_GIM_HV_SYNTH_DEBUG_SEND_BUFFER:
    725726        {
     727            if (!pHv->fDbgEnabled)
     728                return VERR_CPUM_RAISE_GP_0;
    726729#ifndef IN_RING3
    727730            return VINF_CPUM_R3_MSR_WRITE;
    728731#else
    729732            RTGCPHYS GCPhysBuffer    = (RTGCPHYS)uRawValue;
    730             pHv->uDebugSendBufferMsr = GCPhysBuffer;
     733            pHv->uDbgSendBufferMsr = GCPhysBuffer;
    731734            if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer))
    732735                LogRel(("GIM: HyperV: Set up debug send buffer at %#RGp\n", GCPhysBuffer));
    733736            else
    734737                LogRel(("GIM: HyperV: Destroyed debug send buffer\n"));
    735             pHv->uDebugSendBufferMsr = uRawValue;
     738            pHv->uDbgSendBufferMsr = uRawValue;
    736739            return VINF_SUCCESS;
    737740#endif
     
    740743        case MSR_GIM_HV_SYNTH_DEBUG_RECEIVE_BUFFER:
    741744        {
    742 #ifndef IN_RING3
    743             return VINF_CPUM_R3_MSR_WRITE;
    744 #else
    745             RTGCPHYS GCPhysBuffer    = (RTGCPHYS)uRawValue;
    746             pHv->uDebugRecvBufferMsr = GCPhysBuffer;
     745            if (!pHv->fDbgEnabled)
     746                return VERR_CPUM_RAISE_GP_0;
     747#ifndef IN_RING3
     748            return VINF_CPUM_R3_MSR_WRITE;
     749#else
     750            RTGCPHYS GCPhysBuffer  = (RTGCPHYS)uRawValue;
     751            pHv->uDbgRecvBufferMsr = GCPhysBuffer;
    747752            if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer))
    748753                LogRel(("GIM: HyperV: Set up debug receive buffer at %#RGp\n", GCPhysBuffer));
     
    755760        case MSR_GIM_HV_SYNTH_DEBUG_PENDING_BUFFER:
    756761        {
    757 #ifndef IN_RING3
    758             return VINF_CPUM_R3_MSR_WRITE;
    759 #else
    760             RTGCPHYS GCPhysBuffer        = (RTGCPHYS)uRawValue;
    761             pHv->uDebugPendingBufferMsr  = GCPhysBuffer;
     762            if (!pHv->fDbgEnabled)
     763                return VERR_CPUM_RAISE_GP_0;
     764#ifndef IN_RING3
     765            return VINF_CPUM_R3_MSR_WRITE;
     766#else
     767            RTGCPHYS GCPhysBuffer      = (RTGCPHYS)uRawValue;
     768            pHv->uDbgPendingBufferMsr  = GCPhysBuffer;
    762769            if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer))
    763             {
    764770                LogRel(("GIM: HyperV: Set up debug pending buffer at %#RGp\n", uRawValue));
    765 
    766                 /* Indicate that there is always debug data to be read (guest will poll). */
    767                 /** @todo Later implement this by doing the transport read in a separate
    768                  *        thread and updating this page, saves lots of VM-exits as the guest
    769                  *        won't poll and fail all the time. */
    770                 uint8_t uPendingData = 1;
    771                 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysBuffer, (void *)&uPendingData, sizeof(uPendingData));
    772                 if (RT_FAILURE(rc))
    773                     LogRelMax(5, ("GIM: HyperV: Failed to update pending buffer at %#RGp, rc=%Rrc\n", GCPhysBuffer, rc));
    774             }
    775771            else
    776772                LogRel(("GIM: HyperV: Destroyed debug pending buffer\n"));
     
    781777        case MSR_GIM_HV_SYNTH_DEBUG_CONTROL:
    782778        {
    783 #ifndef IN_RING3
    784             return VINF_CPUM_R3_MSR_WRITE;
    785 #else
     779            if (!pHv->fDbgEnabled)
     780                return VERR_CPUM_RAISE_GP_0;
     781#ifndef IN_RING3
     782            return VINF_CPUM_R3_MSR_WRITE;
     783#else
     784            if (   MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_WRITE(uRawValue)
     785                && MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_READ(uRawValue))
     786            {
     787                LogRel(("GIM: HyperV: Requesting both read and write through debug control MSR -> #GP(0)\n"));
     788                return VERR_CPUM_RAISE_GP_0;
     789            }
     790
    786791            if (MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_WRITE(uRawValue))
    787792            {
    788                 LogRelMax(1, ("GIM: HyperV: Initiated debug data transmission via MSR\n",
    789                               MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue)));
    790793                uint32_t cbWrite = MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue);
    791794                if (   cbWrite > 0
    792795                    && cbWrite < GIM_HV_PAGE_SIZE)
    793796                {
    794                     void *pvBuf = RTMemAlloc(cbWrite);  /** @todo perhaps we can do this alloc once during VM init. */
    795                     if (RT_LIKELY(pvBuf))
     797                    if (PGMPhysIsGCPhysNormal(pVM, (RTGCPHYS)pHv->uDbgSendBufferMsr))
    796798                    {
    797                         if (PGMPhysIsGCPhysNormal(pVM, (RTGCPHYS)pHv->uDebugSendBufferMsr))
     799                        Assert(pHv->pvDbgBuffer);
     800                        int rc = PGMPhysSimpleReadGCPhys(pVM, pHv->pvDbgBuffer, (RTGCPHYS)pHv->uDbgSendBufferMsr, cbWrite);
     801                        if (RT_SUCCESS(rc))
    798802                        {
    799                             int rc = PGMPhysSimpleReadGCPhys(pVM, pvBuf, (RTGCPHYS)pHv->uDebugSendBufferMsr, cbWrite);
    800                             if (RT_SUCCESS(rc))
    801                             {
    802                                 uint32_t cbWritten = 0;
    803                                 rc = gimR3HvDebugWrite(pVM, pvBuf, cbWrite, &cbWritten, false /*fUdpPkt*/);
    804                                 if (   RT_SUCCESS(rc)
    805                                     && cbWrite == cbWritten)
    806                                     pHv->uDebugStatusMsr = MSR_GIM_HV_SYNTH_DEBUG_STATUS_W_SUCCESS_BIT;
    807                                 else
    808                                     pHv->uDebugStatusMsr = 0;
    809                             }
     803                            LogRelMax(1, ("GIM: HyperV: Initiated debug data transmission via MSR\n"));
     804                            uint32_t cbWritten = 0;
     805                            rc = gimR3HvDebugWrite(pVM, pHv->pvDbgBuffer, cbWrite, &cbWritten, false /*fUdpPkt*/);
     806                            if (   RT_SUCCESS(rc)
     807                                && cbWrite == cbWritten)
     808                                pHv->uDbgStatusMsr = MSR_GIM_HV_SYNTH_DEBUG_STATUS_W_SUCCESS_BIT;
    810809                            else
    811                             {
    812                                 LogRelMax(5, ("GIM: HyperV: Failed to read debug send buffer at %#RGp, rc=%Rrc\n",
    813                                               (RTGCPHYS)pHv->uDebugSendBufferMsr, rc));
    814                             }
     810                                pHv->uDbgStatusMsr = 0;
    815811                        }
    816812                        else
    817                             LogRelMax(5, ("GIM: HyperV: Debug send buffer address %#RGp invalid! Ignoring debug write\n",
    818                                           (RTGCPHYS)pHv->uDebugSendBufferMsr));
    819                         RTMemFree(pvBuf);
     813                            LogRelMax(5, ("GIM: HyperV: Failed to read debug send buffer at %#RGp, rc=%Rrc\n",
     814                                          (RTGCPHYS)pHv->uDbgSendBufferMsr, rc));
    820815                    }
    821816                    else
     817                        LogRelMax(5, ("GIM: HyperV: Debug send buffer address %#RGp invalid! Ignoring debug write!\n",
     818                                      (RTGCPHYS)pHv->uDbgSendBufferMsr));
     819                }
     820                else
     821                    LogRelMax(5, ("GIM: HyperV: Invalid write size %u specified in MSR, ignoring debug write!\n",
     822                                  MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue)));
     823            }
     824            else if (MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_READ(uRawValue))
     825            {
     826                if (PGMPhysIsGCPhysNormal(pVM, (RTGCPHYS)pHv->uDbgRecvBufferMsr))
     827                {
     828                    LogRelMax(1, ("GIM: HyperV: Initiated debug data reception via MSR\n"));
     829                    uint32_t cbReallyRead;
     830                    Assert(pHv->pvDbgBuffer);
     831                    int rc = gimR3HvDebugRead(pVM, pHv->pvDbgBuffer, PAGE_SIZE, PAGE_SIZE, &cbReallyRead, 0, false /*fUdpPkt*/);
     832                    if (   RT_SUCCESS(rc)
     833                        && cbReallyRead > 0)
    822834                    {
    823                         LogRel(("GIM: HyperV: Failed to alloc %u bytes for copying debug send buffer\n", cbWrite));
    824                         return VERR_NO_MEMORY;
    825                     }
    826                 }
    827             }
    828             else if (MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_READ(uRawValue))
    829             {
    830                 LogRelMax(1, ("GIM: HyperV: Initiated debug data reception via MSR\n"));
    831                 if (PGMPhysIsGCPhysNormal(pVM, (RTGCPHYS)pHv->uDebugRecvBufferMsr))
    832                 {
    833                     void *pvBuf = RTMemAlloc(PAGE_SIZE);        /** @todo perhaps we can do this alloc once during VM init. */
    834                     if (RT_LIKELY(pvBuf))
    835                     {
    836                         uint32_t cbReallyRead;
    837                         int rc = gimR3HvDebugRead(pVM, pvBuf, PAGE_SIZE, PAGE_SIZE, &cbReallyRead, 0, false /*fUdpPkt*/);
    838                         if (   RT_SUCCESS(rc)
    839                             && cbReallyRead > 0)
     835                        rc = PGMPhysSimpleWriteGCPhys(pVM, (RTGCPHYS)pHv->uDbgRecvBufferMsr, pHv->pvDbgBuffer, cbReallyRead);
     836                        if (RT_SUCCESS(rc))
    840837                        {
    841                             rc = PGMPhysSimpleWriteGCPhys(pVM, (RTGCPHYS)pHv->uDebugRecvBufferMsr, pvBuf, cbReallyRead);
    842                             if (RT_SUCCESS(rc))
    843                             {
    844                                 pHv->uDebugStatusMsr  = ((uint16_t)cbReallyRead) << 16;
    845                                 pHv->uDebugStatusMsr |= MSR_GIM_HV_SYNTH_DEBUG_STATUS_R_SUCCESS_BIT;
    846                             }
    847                             else
    848                             {
    849                                 pHv->uDebugStatusMsr = 0;
    850                                 LogRelMax(5, ("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", rc));
    851                             }
     838                            pHv->uDbgStatusMsr  = ((uint16_t)cbReallyRead) << 16;
     839                            pHv->uDbgStatusMsr |= MSR_GIM_HV_SYNTH_DEBUG_STATUS_R_SUCCESS_BIT;
    852840                        }
    853841                        else
    854                             pHv->uDebugStatusMsr = 0;
    855                         RTMemFree(pvBuf);
     842                        {
     843                            pHv->uDbgStatusMsr = 0;
     844                            LogRelMax(5, ("GIM: HyperV: PGMPhysSimpleWriteGCPhys failed. rc=%Rrc\n", rc));
     845                        }
    856846                    }
    857847                    else
    858                     {
    859                         LogRel(("GIM: HyperV: Failed to alloc %u bytes for copying debug receive buffer\n", PAGE_SIZE));
    860                         return VERR_NO_MEMORY;
    861                     }
     848                        pHv->uDbgStatusMsr = 0;
    862849                }
    863850                else
    864                     LogRelMax(5, ("GIM: HyperV: Debug receive buffer address %#RGp invalid! Ignoring debug data reception\n"));
     851                    LogRelMax(5, ("GIM: HyperV: Debug receive buffer address %#RGp invalid! Ignoring debug read!\n"));
    865852            }
    866853            return VINF_SUCCESS;
     
    870857        case MSR_GIM_HV_SINT2:
    871858        {
     859            if (!pHv->fDbgEnabled)
     860                return VERR_CPUM_RAISE_GP_0;
    872861#ifndef IN_RING3
    873862            return VINF_CPUM_R3_MSR_WRITE;
     
    893882        case MSR_GIM_HV_SIMP:
    894883        {
     884            if (!pHv->fDbgEnabled)
     885                return VERR_CPUM_RAISE_GP_0;
    895886#ifndef IN_RING3
    896887            return VINF_CPUM_R3_MSR_WRITE;
  • trunk/src/VBox/VMM/VMMR3/GIM.cpp

    r58283 r58390  
    5959
    6060#include <iprt/err.h>
     61#include <iprt/semaphore.h>
    6162#include <iprt/string.h>
    6263
     
    167168            rc = VMR3SetError(pVM->pUVM, VERR_GIM_INVALID_PROVIDER, RT_SRC_POS, "Provider '%s' unknown.", szProvider);
    168169    }
     170
     171    /*
     172     * Statistics.
     173     */
     174    STAM_REL_REG_USED(pVM, &pVM->gim.s.StatDbgXmit,      STAMTYPE_COUNTER, "/GIM/Debug/Transmit",      STAMUNIT_OCCURENCES, "Debug packets sent.");
     175    STAM_REL_REG_USED(pVM, &pVM->gim.s.StatDbgXmitBytes, STAMTYPE_COUNTER, "/GIM/Debug/TransmitBytes", STAMUNIT_OCCURENCES, "Debug bytes sent.");
     176    STAM_REL_REG_USED(pVM, &pVM->gim.s.StatDbgRecv,      STAMTYPE_COUNTER, "/GIM/Debug/Receive",       STAMUNIT_OCCURENCES, "Debug packets received.");
     177    STAM_REL_REG_USED(pVM, &pVM->gim.s.StatDbgRecvBytes, STAMTYPE_COUNTER, "/GIM/Debug/ReceiveBytes",  STAMUNIT_OCCURENCES, "Debug bytes received.");
     178
     179    STAM_REL_REG_USED(pVM, &pVM->gim.s.StatHypercalls,   STAMTYPE_COUNTER, "/GIM/Hypercalls",          STAMUNIT_OCCURENCES, "Number of hypercalls performed.");
    169180    return rc;
    170181}
     
    415426 * @param   pVM             The cross context VM structure.
    416427 * @param   pDevIns         Pointer to the GIM device instance.
    417  * @param   pDebugStream    Pointer to the GIM device debug connection, can be
     428 * @param   pDbg            Pointer to the GIM device debug structure, can be
    418429 *                          NULL.
    419430 */
    420 VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns, PPDMISTREAM pDebugStream)
     431VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns, PGIMDEBUG pDbg)
    421432{
    422433    pVM->gim.s.pDevInsR3 = pDevIns;
    423     pVM->gim.s.pDebugStreamR3 = pDebugStream;
     434    pVM->gim.s.pDbgR3    = pDbg;
     435}
     436
     437
     438/**
     439 * Gets debug setup specified by the provider.
     440 *
     441 * @returns VBox status code.
     442 * @param   pVM             The cross context VM structure.
     443 * @param   pDevIns         Where to store the debug setup details.
     444 */
     445VMMR3DECL(int) GIMR3GetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup)
     446{
     447    AssertReturn(pVM, VERR_INVALID_PARAMETER);
     448    AssertReturn(pDbgSetup, VERR_INVALID_PARAMETER);
     449
     450    switch (pVM->gim.s.enmProviderId)
     451    {
     452        case GIMPROVIDERID_HYPERV:
     453            return gimR3HvGetDebugSetup(pVM, pDbgSetup);
     454        default:
     455            break;
     456    }
     457    return VERR_GIM_NO_DEBUG_CONNECTION;
    424458}
    425459
     
    430464 * @returns VBox status code.
    431465 *
    432  * @param   pVM         The cross context VM structure.
    433  * @param   pvRead      The read buffer.
    434  * @param   pcbRead     The size of the read buffer as well as where to store
    435  *                      the number of bytes read.
     466 * @param   pVM                 The cross context VM structure.
     467 * @param   pvRead              The read buffer.
     468 * @param   pcbRead             The size of the read buffer as well as where to store
     469 *                              the number of bytes read.
     470 * @param   pfnReadComplete     Callback when the buffer has been read and
     471 *                              before signaling reading of the next buffer.
     472 *                              Optional, can be NULL.
    436473 * @thread  EMT.
    437474 */
    438 VMMR3_INT_DECL(int) GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead)
    439 {
    440     PPDMISTREAM pDebugStream = pVM->gim.s.pDebugStreamR3;
    441     if (pDebugStream)
    442         return pDebugStream->pfnRead(pDebugStream, pvRead, pcbRead);
     475VMMR3_INT_DECL(int) GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead, PFNGIMDEBUGBUFREADCOMPLETED pfnReadComplete)
     476{
     477    PGIMDEBUG pDbg = pVM->gim.s.pDbgR3;
     478    if (pDbg)
     479    {
     480        if (ASMAtomicReadBool(&pDbg->fDbgRecvBufRead) == true)
     481        {
     482            STAM_COUNTER_INC(&pVM->gim.s.StatDbgRecv);
     483            STAM_COUNTER_ADD(&pVM->gim.s.StatDbgRecvBytes, pDbg->cbDbgRecvBufRead);
     484
     485            memcpy(pvRead, pDbg->pvDbgRecvBuf, pDbg->cbDbgRecvBufRead);
     486            *pcbRead = pDbg->cbDbgRecvBufRead;
     487            if (pfnReadComplete)
     488                pfnReadComplete(pVM);
     489            RTSemEventMultiSignal(pDbg->hDbgRecvThreadSem);
     490            ASMAtomicWriteBool(&pDbg->fDbgRecvBufRead, false);
     491            return VINF_SUCCESS;
     492        }
     493        else
     494            *pcbRead = 0;
     495        return VERR_NO_DATA;
     496    }
    443497    return VERR_GIM_NO_DEBUG_CONNECTION;
    444498}
     
    458512VMMR3_INT_DECL(int) GIMR3DebugWrite(PVM pVM, void *pvWrite, size_t *pcbWrite)
    459513{
    460     PPDMISTREAM pDebugStream = pVM->gim.s.pDebugStreamR3;
    461     if (pDebugStream)
    462         return pDebugStream->pfnWrite(pDebugStream, pvWrite, pcbWrite);
     514    PGIMDEBUG pDbg = pVM->gim.s.pDbgR3;
     515    if (pDbg)
     516    {
     517        PPDMISTREAM pDbgStream = pDbg->pDbgDrvStream;
     518        if (pDbgStream)
     519        {
     520            size_t cbWrite = *pcbWrite;
     521            int rc = pDbgStream->pfnWrite(pDbgStream, pvWrite, pcbWrite);
     522            if (   RT_SUCCESS(rc)
     523                && *pcbWrite == cbWrite)
     524            {
     525                STAM_COUNTER_INC(&pVM->gim.s.StatDbgXmit);
     526                STAM_COUNTER_ADD(&pVM->gim.s.StatDbgXmitBytes, *pcbWrite);
     527            }
     528            return rc;
     529        }
     530    }
    463531    return VERR_GIM_NO_DEBUG_CONNECTION;
    464532}
  • trunk/src/VBox/VMM/VMMR3/GIMHv.cpp

    r58337 r58390  
    3737#include <VBox/vmm/pdmapi.h>
    3838#include <VBox/version.h>
     39#ifdef DEBUG_ramshankar
     40# include <iprt/udp.h>
     41#endif
    3942
    4043
     
    175178static int    gimR3HvInitHypercallSupport(PVM pVM);
    176179static void   gimR3HvTermHypercallSupport(PVM pVM);
     180static int    gimR3HvInitDebugSupport(PVM pVM);
     181static void   gimR3HvTermDebugSupport(PVM pVM);
    177182
    178183
     
    203208        rc = CFGMR3ValidateConfig(pCfgHv, "/HyperV/",
    204209                                  "VendorID"
    205                                   "|VSInterface",
     210                                  "|VSInterface"
     211                                  "|HypercallDebugInterface",
    206212                                  "" /* pszValidNodes */, "GIM/HyperV" /* pszWho */, 0 /* uInstance */);
    207213        if (RT_FAILURE(rc))
     
    218224    if (!RTStrNCmp(szVendor, GIM_HV_VENDOR_MICROSOFT, sizeof(GIM_HV_VENDOR_MICROSOFT) - 1))
    219225    {
    220         LogRel(("GIM: HyperV: Warning! Posing as the Microsoft vendor, guest behavior may be altered!\n"));
     226        LogRel(("GIM: HyperV: Warning! Posing as the Microsoft vendor may alter guest behaviour!\n"));
    221227        pHv->fIsVendorMsHv = true;
    222228    }
     
    227233         * The Microsoft virtualization service interface (debugging). */
    228234        rc = CFGMR3QueryBoolDef(pCfgHv, "VSInterface", &pHv->fIsInterfaceVs, true);
     235        AssertLogRelRCReturn(rc, rc);
     236
     237        /** @cfgm{/GIM/HyperV/HypercallDebugInterface, bool, true}
     238         * Whether we specify the guest to use hypercalls for debugging rather than MSRs. */
     239        rc = CFGMR3QueryBoolDef(pCfgHv, "HypercallDebugInterface", &pHv->fDbgHypercallInterface, true);
    229240        AssertLogRelRCReturn(rc, rc);
    230241    }
     
    438449    AssertLogRelRCReturn(rc, rc);
    439450
     451    /*
     452     * Setup debug support.
     453     */
     454    rc = gimR3HvInitDebugSupport(pVM);
     455    AssertLogRelRCReturn(rc, rc);
     456
    440457    return VINF_SUCCESS;
    441458}
     
    559576     * Reset MSRs.
    560577     */
    561     pHv->u64GuestOsIdMsr        = 0;
    562     pHv->u64HypercallMsr        = 0;
    563     pHv->u64TscPageMsr          = 0;
    564     pHv->uCrashP0Msr            = 0;
    565     pHv->uCrashP1Msr            = 0;
    566     pHv->uCrashP2Msr            = 0;
    567     pHv->uCrashP3Msr            = 0;
    568     pHv->uCrashP4Msr            = 0;
    569     pHv->uDebugStatusMsr        = 0;
    570     pHv->uDebugPendingBufferMsr = 0;
    571     pHv->uDebugSendBufferMsr    = 0;
    572     pHv->uDebugRecvBufferMsr    = 0;
     578    pHv->u64GuestOsIdMsr      = 0;
     579    pHv->u64HypercallMsr      = 0;
     580    pHv->u64TscPageMsr        = 0;
     581    pHv->uCrashP0Msr          = 0;
     582    pHv->uCrashP1Msr          = 0;
     583    pHv->uCrashP2Msr          = 0;
     584    pHv->uCrashP3Msr          = 0;
     585    pHv->uCrashP4Msr          = 0;
     586    pHv->uDbgStatusMsr        = 0;
     587    pHv->uDbgPendingBufferMsr = 0;
     588    pHv->uDbgSendBufferMsr    = 0;
     589    pHv->uDbgRecvBufferMsr    = 0;
    573590    for (VMCPUID i = 0; i < pVM->cCpus; i++)
    574591    {
     
    595612    Assert(*pcRegions <= UINT8_MAX);    /* See PGMR3PhysMMIO2Register(). */
    596613    return pHv->aMmio2Regions;
     614}
     615
     616
     617/**
     618 * Callback for when debug data is available over the debugger connection.
     619 *
     620 * @param pVM       The cross context VM structure.
     621 */
     622static DECLCALLBACK(void) gimR3HvDebugBufAvail(PVM pVM)
     623{
     624    PGIMHV   pHv = &pVM->gim.s.u.Hv;
     625    RTGCPHYS GCPhysPendingBuffer = pHv->uDbgPendingBufferMsr;
     626    if (   GCPhysPendingBuffer
     627        && PGMPhysIsGCPhysNormal(pVM, GCPhysPendingBuffer))
     628    {
     629        uint8_t bPendingData = 1;
     630        int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysPendingBuffer, &bPendingData, sizeof(bPendingData));
     631        if (RT_FAILURE(rc))
     632        {
     633            LogRelMax(5, ("GIM: HyperV: Failed to set pending debug receive buffer at %#RGp, rc=%Rrc\n", GCPhysPendingBuffer,
     634                          rc));
     635        }
     636    }
     637}
     638
     639
     640/**
     641 * Callback for when debug data has been read from the debugger connection.
     642 *
     643 * This will be invoked before signalling read of the next debug buffer.
     644 *
     645 * @param pVM       The cross context VM structure.
     646 */
     647static DECLCALLBACK(void) gimR3HvDebugBufReadCompleted(PVM pVM)
     648{
     649    PGIMHV   pHv = &pVM->gim.s.u.Hv;
     650    RTGCPHYS GCPhysPendingBuffer = pHv->uDbgPendingBufferMsr;
     651    if (   GCPhysPendingBuffer
     652        && PGMPhysIsGCPhysNormal(pVM, GCPhysPendingBuffer))
     653    {
     654        uint8_t bPendingData = 0;
     655        int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysPendingBuffer, &bPendingData, sizeof(bPendingData));
     656        if (RT_FAILURE(rc))
     657        {
     658            LogRelMax(5, ("GIM: HyperV: Failed to clear pending debug receive buffer at %#RGp, rc=%Rrc\n", GCPhysPendingBuffer,
     659                          rc));
     660        }
     661    }
     662}
     663
     664
     665/**
     666 * Get Hyper-V debug setup parameters.
     667 *
     668 * @returns VBox status code.
     669 * @param   pVM         The cross context VM structure.
     670 * @param   pDbgSetup   Where to store the debug setup details.
     671 */
     672VMMR3_INT_DECL(int) gimR3HvGetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup)
     673{
     674    Assert(pDbgSetup);
     675    PGIMHV pHv = &pVM->gim.s.u.Hv;
     676    if (pHv->fDbgEnabled)
     677    {
     678        pDbgSetup->pfnDbgRecvBufAvail = gimR3HvDebugBufAvail;
     679        pDbgSetup->cbDbgRecvBuf       = GIM_HV_PAGE_SIZE;
     680        return VINF_SUCCESS;
     681    }
     682    return VERR_GIM_NO_DEBUG_CONNECTION;
    597683}
    598684
     
    663749     * Save debug support data.
    664750     */
    665     SSMR3PutU64(pSSM, pcHv->uDebugPendingBufferMsr);
    666     SSMR3PutU64(pSSM, pcHv->uDebugSendBufferMsr);
    667     SSMR3PutU64(pSSM, pcHv->uDebugRecvBufferMsr);
    668     SSMR3PutU64(pSSM, pcHv->uDebugStatusMsr);
    669     SSMR3PutU32(pSSM, pcHv->enmDebugReply);
    670     SSMR3PutU32(pSSM, pcHv->uBootpXId);
     751    SSMR3PutU64(pSSM, pcHv->uDbgPendingBufferMsr);
     752    SSMR3PutU64(pSSM, pcHv->uDbgSendBufferMsr);
     753    SSMR3PutU64(pSSM, pcHv->uDbgRecvBufferMsr);
     754    SSMR3PutU64(pSSM, pcHv->uDbgStatusMsr);
     755    SSMR3PutU32(pSSM, pcHv->enmDbgReply);
     756    SSMR3PutU32(pSSM, pcHv->uDbgBootpXId);
    671757    SSMR3PutU32(pSSM, pcHv->DbgGuestIp4Addr.u);
    672758
     
    792878    if (uHvSavedStatVersion > GIM_HV_SAVED_STATE_VERSION_PRE_DEBUG)
    793879    {
    794         SSMR3GetU64(pSSM, &pHv->uDebugPendingBufferMsr);
    795         SSMR3GetU64(pSSM, &pHv->uDebugSendBufferMsr);
    796         SSMR3GetU64(pSSM, &pHv->uDebugRecvBufferMsr);
    797         SSMR3GetU64(pSSM, &pHv->uDebugStatusMsr);
    798         SSMR3GetU32(pSSM, (uint32_t *)&pHv->enmDebugReply);
    799         SSMR3GetU32(pSSM, &pHv->uBootpXId);
     880        SSMR3GetU64(pSSM, &pHv->uDbgPendingBufferMsr);
     881        SSMR3GetU64(pSSM, &pHv->uDbgSendBufferMsr);
     882        SSMR3GetU64(pSSM, &pHv->uDbgRecvBufferMsr);
     883        SSMR3GetU64(pSSM, &pHv->uDbgStatusMsr);
     884        SSMR3GetU32(pSSM, (uint32_t *)&pHv->enmDbgReply);
     885        SSMR3GetU32(pSSM, &pHv->uDbgBootpXId);
    800886        rc = SSMR3GetU32(pSSM, &pHv->DbgGuestIp4Addr.u);
    801887        AssertRCReturn(rc, rc);
     
    11371223
    11381224/**
     1225 * Initializes Hyper-V guest debug support.
     1226 *
     1227 * @returns VBox status code.
     1228 * @param   pVM     The cross context VM structure.
     1229 */
     1230static int gimR3HvInitDebugSupport(PVM pVM)
     1231{
     1232    PGIMHV pHv = &pVM->gim.s.u.Hv;
     1233    if (   (pHv->uPartFlags & GIM_HV_PART_FLAGS_DEBUGGING)
     1234        || pHv->fIsInterfaceVs)
     1235    {
     1236        pHv->fDbgEnabled = true;
     1237        pHv->pvDbgBuffer = RTMemAllocZ(PAGE_SIZE);
     1238        if (!pHv->pvDbgBuffer)
     1239            return VERR_NO_MEMORY;
     1240    }
     1241    return VINF_SUCCESS;
     1242}
     1243
     1244
     1245/**
     1246 * Terminates Hyper-V guest debug support.
     1247 *
     1248 * @param   pVM     The cross context VM structure.
     1249 */
     1250static void gimR3HvTermDebugSupport(PVM pVM)
     1251{
     1252    PGIMHV pHv = &pVM->gim.s.u.Hv;
     1253    if (pHv->pvDbgBuffer)
     1254    {
     1255        RTMemFree(pHv->pvDbgBuffer);
     1256        pHv->pvDbgBuffer = NULL;
     1257    }
     1258}
     1259
     1260
     1261/**
    11391262 * Reads data from a debugger connection, asynchronous.
    11401263 *
     
    11651288         */
    11661289        size_t cbReallyRead = cbRead;
    1167         rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead);
     1290        rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted);
    11681291        *pcbRead = (uint32_t)cbReallyRead;
    11691292    }
     
    11751298        PGIMHV pHv = &pVM->gim.s.u.Hv;
    11761299        rc = VERR_GIM_IPE_1;
    1177         switch (pHv->enmDebugReply)
     1300        switch (pHv->enmDbgReply)
    11781301        {
    11791302            case GIMHVDEBUGREPLY_UDP:
    11801303            {
    11811304                size_t cbReallyRead = cbRead;
    1182                 rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead);
     1305                rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted);
    11831306                if (   RT_SUCCESS(rc)
    11841307                    && cbReallyRead > 0)
     
    12171340                        pIpHdr->ip_sum     = RTNetIPv4HdrChecksum(pIpHdr);
    12181341                        /* UDP */
     1342                        pUdpHdr->uh_dport  = pHv->uUdpGuestSrcPort;
     1343                        pUdpHdr->uh_sport  = pHv->uUdpGuestDstPort;
    12191344                        pUdpHdr->uh_ulen   = RT_H2N_U16_C((uint16_t)cbReallyRead + sizeof(*pUdpHdr));
    12201345
     
    12421367                    rc = VINF_SUCCESS;
    12431368                    *pcbRead = cbArpReplyPkt;
    1244                     pHv->enmDebugReply = GIMHVDEBUGREPLY_ARP_REPLY_SENT;
     1369                    pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY_SENT;
    12451370                }
    12461371                else
     
    12621387                    PRTNETUDP      pUdpHdr   = (PRTNETUDP)     ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
    12631388                    PRTNETBOOTP    pBootpHdr = (PRTNETBOOTP)   (pUdpHdr + 1);
    1264                     pBootpHdr->bp_xid = pHv->uBootpXId;
     1389                    pBootpHdr->bp_xid = pHv->uDbgBootpXId;
    12651390
    12661391                    rc = VINF_SUCCESS;
    12671392                    *pcbRead = cbDhcpOfferPkt;
    1268                     pHv->enmDebugReply = GIMHVDEBUGREPLY_DHCP_OFFER_SENT;
     1393                    pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER_SENT;
    12691394                    LogRel(("GIM: HyperV: Debug DHCP offered IP address %RTnaipv4, transaction Id %#x\n", pBootpHdr->bp_yiaddr,
    1270                             RT_N2H_U32(pHv->uBootpXId)));
     1395                            RT_N2H_U32(pHv->uDbgBootpXId)));
    12711396                }
    12721397                else
     
    12881413                    PRTNETUDP      pUdpHdr   = (PRTNETUDP)     ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN);
    12891414                    PRTNETBOOTP    pBootpHdr = (PRTNETBOOTP)   (pUdpHdr + 1);
    1290                     pBootpHdr->bp_xid = pHv->uBootpXId;
     1415                    pBootpHdr->bp_xid = pHv->uDbgBootpXId;
    12911416
    12921417                    rc = VINF_SUCCESS;
    12931418                    *pcbRead = cbDhcpAckPkt;
    1294                     pHv->enmDebugReply = GIMHVDEBUGREPLY_DHCP_ACK_SENT;
     1419                    pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK_SENT;
    12951420                    LogRel(("GIM: HyperV: Debug DHCP acknowledged IP address %RTnaipv4, transaction Id %#x\n",
    1296                             pBootpHdr->bp_yiaddr, RT_N2H_U32(pHv->uBootpXId)));
     1421                            pBootpHdr->bp_yiaddr, RT_N2H_U32(pHv->uDbgBootpXId)));
    12971422                }
    12981423                else
     
    13151440            default:
    13161441            {
    1317                 AssertMsgFailed(("GIM: HyperV: Invalid/unimplemented debug reply type %u\n", pHv->enmDebugReply));
     1442                AssertMsgFailed(("GIM: HyperV: Invalid/unimplemented debug reply type %u\n", pHv->enmDbgReply));
    13181443                rc = VERR_INTERNAL_ERROR_2;
    13191444            }
    13201445        }
    13211446        Assert(rc != VERR_GIM_IPE_1);
    1322     }
     1447
     1448#ifdef DEBUG_ramshankar
     1449        if (   rc == VINF_SUCCESS
     1450            && *pcbRead > 0)
     1451        {
     1452            RTSOCKET hSocket;
     1453            int rc2 = RTUdpCreateClientSocket("localhost", 52000, NULL, &hSocket);
     1454            if (RT_SUCCESS(rc2))
     1455            {
     1456                size_t cbTmpWrite = *pcbRead;
     1457                RTSocketWriteNB(hSocket, pvBuf, *pcbRead, &cbTmpWrite); NOREF(cbTmpWrite);
     1458                RTSocketClose(hSocket);
     1459            }
     1460        }
     1461#endif
     1462    }
     1463
    13231464    return rc;
    13241465}
     
    13471488    if (fUdpPkt)
    13481489    {
     1490#ifdef DEBUG_ramshankar
     1491        RTSOCKET hSocket;
     1492        int rc2 = RTUdpCreateClientSocket("localhost", 52000, NULL, &hSocket);
     1493        if (RT_SUCCESS(rc2))
     1494        {
     1495            size_t cbTmpWrite = cbWrite;
     1496            RTSocketWriteNB(hSocket, pbData, cbWrite, &cbTmpWrite);  NOREF(cbTmpWrite);
     1497            RTSocketClose(hSocket);
     1498        }
     1499#endif
    13491500        /*
    13501501         * Windows guests sends us ethernet frames over the Hyper-V debug connection.
     
    13881539                             * Check for DHCP.
    13891540                             */
     1541                            bool fBuggyPkt = false;
    13901542                            size_t const cbUdpPkt = cbMaxIpPkt - cbIpHdr;
    13911543                            if (   pUdpHdr->uh_dport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPS)
    1392                                 && pUdpHdr->uh_sport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPC)
    1393                                 && cbMaxIpPkt >= cbIpHdr + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN)
     1544                                && pUdpHdr->uh_sport == RT_N2H_U16_C(RTNETIPV4_PORT_BOOTPC))
    13941545                            {
    13951546                                PCRTNETBOOTP pDhcpPkt = (PCRTNETBOOTP)(pUdpHdr + 1);
    13961547                                uint8_t bMsgType;
    1397                                 if (RTNetIPv4IsDHCPValid(pUdpHdr, pDhcpPkt, cbUdpPkt - sizeof(*pUdpHdr), &bMsgType))
     1548                                if (   cbMaxIpPkt >= cbIpHdr + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
     1549                                    && RTNetIPv4IsDHCPValid(pUdpHdr, pDhcpPkt, cbUdpPkt - sizeof(*pUdpHdr), &bMsgType))
    13981550                                {
    13991551                                    switch (bMsgType)
    14001552                                    {
    14011553                                        case RTNET_DHCP_MT_DISCOVER:
    1402                                             pHv->enmDebugReply = GIMHVDEBUGREPLY_DHCP_OFFER;
    1403                                             pHv->uBootpXId = pDhcpPkt->bp_xid;
     1554                                            pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER;
     1555                                            pHv->uDbgBootpXId = pDhcpPkt->bp_xid;
    14041556                                            break;
    14051557                                        case RTNET_DHCP_MT_REQUEST:
    1406                                             pHv->enmDebugReply = GIMHVDEBUGREPLY_DHCP_ACK;
    1407                                             pHv->uBootpXId = pDhcpPkt->bp_xid;
     1558                                            pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK;
     1559                                            pHv->uDbgBootpXId = pDhcpPkt->bp_xid;
    14081560                                            break;
    14091561                                        default:
     
    14121564                                            break;
    14131565                                    }
     1566                                    fIgnorePkt = true;
    14141567                                }
    1415                                 fIgnorePkt = true;
     1568                                else if (   pIp4Hdr->ip_src.u == GIMHV_DEBUGCLIENT_IPV4
     1569                                         && pIp4Hdr->ip_dst.u == 0)
     1570                                {
     1571                                    /*
     1572                                     * Windows 8.1 seems to be sending malformed BOOTP packets at the final stage of the
     1573                                     * debugger sequence. It appears that a previously sent DHCP request buffer wasn't cleared
     1574                                     * in the guest and they re-use it instead of sending a zero destination+source port packet
     1575                                     * as expected below.
     1576                                     *
     1577                                     * We workaround Microsoft's bug here, or at least, I'm classifying it as a bug to
     1578                                     * preserve my own sanity, see @bugref{8006#c54}.
     1579                                     */
     1580                                    fBuggyPkt = true;
     1581                                }
    14161582                            }
    1417                             else if (   !pUdpHdr->uh_dport
    1418                                      && !pUdpHdr->uh_sport)
     1583
     1584                            if (  (   !pUdpHdr->uh_dport
     1585                                   && !pUdpHdr->uh_sport)
     1586                                || fBuggyPkt)
    14191587                            {
    14201588                                /*
    14211589                                 * Extract the UDP payload and pass it to the debugger and record the guest IP address.
    1422                                  * Hyper-V sends UDP debugger packets with source and destination port as 0. If we don't
    1423                                  * filter out the ports here, we would receive BOOTP, NETBIOS and other UDP sub-protocol
    1424                                  * packets which the debugger yells as "Bad packet received from...".
     1590                                 *
     1591                                 * Hyper-V sends UDP debugger packets with source and destination port as 0 except in the
     1592                                 * aformentioned buggy case. The buggy packet case requires us to remember the ports and
     1593                                 * reply to them, otherwise the guest won't receive the replies we sent with port 0.
    14251594                                 */
    14261595                                uint32_t const cbFrameHdr = sizeof(RTNETETHERHDR) + cbIpHdr + sizeof(RTNETUDP);
    14271596                                pbData  += cbFrameHdr;
    14281597                                cbWrite -= cbFrameHdr;
    1429                                 pHv->DbgGuestIp4Addr = pIp4Hdr->ip_src;
    1430                                 pHv->enmDebugReply   = GIMHVDEBUGREPLY_UDP;
     1598                                pHv->DbgGuestIp4Addr.u = pIp4Hdr->ip_src.u;
     1599                                pHv->uUdpGuestDstPort  = pUdpHdr->uh_dport;
     1600                                pHv->uUdpGuestSrcPort  = pUdpHdr->uh_sport;
     1601                                pHv->enmDbgReply       = GIMHVDEBUGREPLY_UDP;
    14311602                            }
    14321603                            else
    14331604                            {
    1434                                 LogFlow(("GIM: HyperV: Ignoring UDP packet not src and dst port 0\n"));
     1605                                LogFlow(("GIM: HyperV: Ignoring UDP packet SourcePort=%u DstPort=%u\n", pUdpHdr->uh_sport,
     1606                                         pUdpHdr->uh_dport));
    14351607                                fIgnorePkt = true;
    14361608                            }
     
    14761648                            &&  pArpPkt->ar_tpa.u == GIMHV_DEBUGSERVER_IPV4)
    14771649                        {
    1478                             pHv->enmDebugReply = GIMHVDEBUGREPLY_ARP_REPLY;
     1650                            pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY;
    14791651                        }
    14801652                    }
  • trunk/src/VBox/VMM/include/GIMHvInternal.h

    r58335 r58390  
    713713/** The undocumented bit for MSR_GIM_HV_DEBUG_OPTIONS_MSR that makes it all
    714714 *  work. */
    715 #define GIM_HV_DEBUG_OPTIONS_MSR_ENABLE           RT_BIT(2)
     715#define GIM_HV_DEBUG_OPTIONS_USE_HYPERCALLS       RT_BIT(2)
    716716
    717717/** Guest will perform the HvPostDebugData hypercall until completion. */
     
    10471047    /** Whether we're posing as the Microsoft virtualization service. */
    10481048    bool                        fIsInterfaceVs;
    1049     bool                        afAlignment0[6];
    1050     /** The auto IP address last chosen by the guest after failed ARP queries. */
     1049    /** Whether debugging support is enabled. */
     1050    bool                        fDbgEnabled;
     1051    /** Whether we should suggest a hypercall-based debug interface to the guest. */
     1052    bool                        fDbgHypercallInterface;
     1053    bool                        afAlignment0[4];
     1054    /** The action to take while sending replies. */
     1055    GIMHVDEBUGREPLY             enmDbgReply;
     1056    /** The IP address chosen by/assigned to the guest. */
    10511057    RTNETADDRIPV4               DbgGuestIp4Addr;
    1052     /** The action to take while sending replies. */
    1053     GIMHVDEBUGREPLY             enmDebugReply;
    10541058    /** Transaction ID for the BOOTP+DHCP sequence. */
    1055     uint32_t                    uBootpXId;
    1056     /** Padding. */
    1057     uint32_t                    uAlignment0;
     1059    uint32_t                    uDbgBootpXId;
     1060    /** The source UDP port used by the guest while sending debug packets. */
     1061    uint16_t                    uUdpGuestSrcPort;
     1062    /** The destination UDP port used by the guest while sending debug packets. */
     1063    uint16_t                    uUdpGuestDstPort;
    10581064    /** Debug send buffer MSR. */
    1059     uint64_t                    uDebugSendBufferMsr;
     1065    uint64_t                    uDbgSendBufferMsr;
    10601066    /** Debug receive buffer MSR. */
    1061     uint64_t                    uDebugRecvBufferMsr;
     1067    uint64_t                    uDbgRecvBufferMsr;
    10621068    /** Debug pending buffer MSR. */
    1063     uint64_t                    uDebugPendingBufferMsr;
     1069    uint64_t                    uDbgPendingBufferMsr;
    10641070    /** Debug status MSR. */
    1065     uint64_t                    uDebugStatusMsr;
     1071    uint64_t                    uDbgStatusMsr;
     1072    /** Intermediate debug I/O buffer. */
     1073    R3PTRTYPE(void *)           pvDbgBuffer;
    10661074    /** @} */
    10671075
     
    11131121VMMR3_INT_DECL(int)             gimR3HvSave(PVM pVM, PSSMHANDLE pSSM);
    11141122VMMR3_INT_DECL(int)             gimR3HvLoad(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion);
     1123VMMR3_INT_DECL(int)             gimR3HvGetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup);
    11151124
    11161125VMMR3_INT_DECL(int)             gimR3HvDisableTscPage(PVM pVM);
  • trunk/src/VBox/VMM/include/GIMInternal.h

    r58283 r58390  
    5454    /** Pointer to the GIM device - R3 ptr. */
    5555    R3PTRTYPE(PPDMDEVINS)            pDevInsR3;
    56     /** Pointer to the GIM device debug stream - R3 ptr. */
    57     R3PTRTYPE(PPDMISTREAM)           pDebugStreamR3;
    58 #if 0
    59     /** Pointer to the provider's ring-3 hypercall handler. */
    60     R3PTRTYPE(PFNGIMHYPERCALL)       pfnHypercallR3;
    61     /** Pointer to the provider's ring-0 hypercall handler. */
    62     R0PTRTYPE(PFNGIMHYPERCALL)       pfnHypercallR0;
    63     /** Pointer to the provider's raw-mode context hypercall handler. */
    64     RCPTRTYPE(PFNGIMHYPERCALL)       pfnHypercallRC;
     56    /** The debug struct - R3 ptr. */
     57    R3PTRTYPE(PGIMDEBUG)             pDbgR3;
    6558
    66     /** Pointer to the provider's ring-3 MSR-read handler. */
    67     R3PTRTYPE(PFNGIMRDMSR)           pfnReadMsrR3;
    68     /** Pointer to the provider's ring-0 MSR-read handler. */
    69     R0PTRTYPE(PFNGIMRDMSR)           pfnReadMsrR0;
    70     /** Pointer to the provider's raw-mode context MSR-read handler. */
    71     RCPTRTYPE(PFNGIMRDMSR)           pfnReadMsrRC;
    72 
    73     /** Pointer to the provider's ring-3 MSR-read handler. */
    74     R3PTRTYPE(PFNGIMWDMSR)           pfnWriteMsrR3;
    75     /** Pointer to the provider's ring-0 MSR-read handler. */
    76     R0PTRTYPE(PFNGIMWDMSR)           pfnWriteMsrRR0;
    77     /** Pointer to the provider's raw-mode context MSR-read handler. */
    78     RCPTRTYPE(PFNGIMWDMSR)           pfnWriteMsrRRC;
    79 #endif
    80 
     59    /** The provider specific data. */
    8160    union
    8261    {
     
    8463        GIMKVM Kvm;
    8564    } u;
     65
     66    /** Number of hypercalls initiated. */
     67    STAMCOUNTER                      StatHypercalls;
     68    /** Debug packets sent. */
     69    STAMCOUNTER                      StatDbgXmit;
     70    /** Debug bytes sent. */
     71    STAMCOUNTER                      StatDbgXmitBytes;
     72    /** Debug packets received. */
     73    STAMCOUNTER                      StatDbgRecv;
     74    /** Debug bytes received. */
     75    STAMCOUNTER                      StatDbgRecvBytes;
    8676} GIM;
    8777/** Pointer to GIM VM instance data. */
    8878typedef GIM *PGIM;
    89 
    9079
    9180/**
     
    10392typedef GIMCPU *PGIMCPU;
    10493
     94/**
     95 * Callback when a debug buffer read has completed and before signaling
     96 * the next read.
     97 *
     98 * @param   pVM             The cross context VM structure.
     99 */
     100typedef DECLCALLBACK(void) FNGIMDEBUGBUFREADCOMPLETED(PVM pVM);
     101/** Pointer to GIM debug buffer read completion callback. */
     102typedef FNGIMDEBUGBUFREADCOMPLETED *PFNGIMDEBUGBUFREADCOMPLETED;
     103
    105104#ifdef IN_RING3
    106105VMMR3_INT_DECL(int)           GIMR3Mmio2Unmap(PVM pVM, PGIMMMIO2REGION pRegion);
     
    109108VMMR3_INT_DECL(int)           GIMR3Mmio2HandlerPhysicalDeregister(PVM pVM, PGIMMMIO2REGION pRegion);
    110109
    111 VMMR3_INT_DECL(int)           GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead);
     110VMMR3_INT_DECL(int)           GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead, PFNGIMDEBUGBUFREADCOMPLETED pfnReadComplete);
    112111VMMR3_INT_DECL(int)           GIMR3DebugWrite(PVM pVM, void *pvWrite, size_t *pcbWrite);
    113112#endif /* IN_RING3 */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette