Changeset 58390 in vbox
- Timestamp:
- Oct 23, 2015 12:35:35 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/gim.h
r58124 r58390 100 100 AssertCompileMemberAlignment(GIMMMIO2REGION, pvPageR0, 8); 101 101 102 #if 0103 102 /** 104 * A GIM Hypercall handler.103 * Debug data buffer available callback over the GIM debug connection. 105 104 * 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. 108 106 */ 109 typedef DECLCALLBACK( int) FNGIMHYPERCALL(PVMCPU pVCpu, PCPUMCTX pCtx);110 /** Pointer to a GIM hypercall handler. */111 typedef FNGIM HYPERCALL *PFNGIMHYPERCALL;107 typedef DECLCALLBACK(void) FNGIMDEBUGBUFAVAIL(PVM pVM); 108 /** Pointer to GIM debug buffer available callback. */ 109 typedef FNGIMDEBUGBUFAVAIL *PFNGIMDEBUGBUFAVAIL; 112 110 113 111 /** 114 * A GIM MSR-read handler.112 * GIM debug setup. 115 113 * 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. 121 116 */ 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; 117 typedef 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. */ 125 typedef struct GIMDEBUGSETUP *PGIMDEBUGSETUP; 126 /** Pointer to a const GIM debug setup struct. */ 127 typedef struct GIMDEBUGSETUP const *PCGGIMDEBUGSETUP; 125 128 126 129 /** 127 * A GIM MSR-write handler.130 * GIM debug structure (common to the GIM device and GIM). 128 131 * 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. 135 133 */ 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 134 typedef 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. */ 148 typedef struct GIMDEBUG *PGIMDEBUG; 149 /** Pointer to a const GIM debug struct. */ 150 typedef struct GIMDEBUG const *PCGIMDEBUG; 140 151 141 152 … … 166 177 VMMR3_INT_DECL(int) GIMR3Term(PVM pVM); 167 178 VMMR3_INT_DECL(void) GIMR3Reset(PVM pVM); 168 VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PPDMISTREAM pDebugStreamR3); 179 VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PGIMDEBUG pDbg); 180 VMMR3DECL(int) GIMR3GetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup); 169 181 VMMR3DECL(PGIMMMIO2REGION) GIMR3GetMmio2Regions(PVM pVM, uint32_t *pcRegions); 170 182 /** @} */ -
trunk/src/VBox/Devices/GIMDev/DrvUDP.cpp
r57989 r58390 80 80 { 81 81 size_t cbReallyRead = 0; 82 rc = RTSocketRead NB(pThis->hSocket, pvBuf, *pcbRead, &cbReallyRead);82 rc = RTSocketRead(pThis->hSocket, pvBuf, *pcbRead, &cbReallyRead); 83 83 if (RT_SUCCESS(rc)) 84 84 *pcbRead = cbReallyRead; … … 103 103 if (pThis->hSocket != NIL_RTSOCKET) 104 104 { 105 size_t cb ReallyWritten = 0;106 rc = RTSocketWrite NB(pThis->hSocket, pvBuf, *pcbWrite, &cbReallyWritten);105 size_t cbBuf = *pcbWrite; 106 rc = RTSocketWriteToNB(pThis->hSocket, pvBuf, cbBuf, NULL /*pDstAddr*/); 107 107 if (RT_SUCCESS(rc)) 108 *pcbWrite = cb ReallyWritten;108 *pcbWrite = cbBuf; 109 109 } 110 110 else … … 147 147 if (pThis->hSocket != NIL_RTSOCKET) 148 148 { 149 RTSocketRetain(pThis->hSocket); 150 RTSocketShutdown(pThis->hSocket, true, true); 149 151 RTSocketClose(pThis->hSocket); 150 152 pThis->hSocket = NIL_RTSOCKET; -
trunk/src/VBox/Devices/GIMDev/GIMDev.cpp
r57989 r58390 26 26 27 27 #include "VBoxDD.h" 28 #include <iprt/alloc.h> 29 #include <iprt/semaphore.h> 28 30 #include <iprt/uuid.h> 29 31 … … 50 52 /** Pointer to the attached base debug driver. */ 51 53 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; 54 62 } GIMDEV; 55 63 /** Pointer to the GIM device state. */ … … 76 84 77 85 86 static 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 78 160 /** 79 161 * @interface_method_impl{PDMDEVREG,pfnConstruct} … … 93 175 94 176 /* 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 } 104 203 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); 125 251 126 252 /* … … 197 323 if (RT_FAILURE(rc)) 198 324 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; 199 358 } 200 359 -
trunk/src/VBox/VMM/VMMAll/GIMAll.cpp
r58126 r58390 99 99 return VERR_GIM_NOT_ENABLED; 100 100 101 STAM_COUNTER_INC(&pVM->gim.s.StatHypercalls); 101 102 switch (pVM->gim.s.enmProviderId) 102 103 { -
trunk/src/VBox/VMM/VMMAll/GIMAllHv.cpp
r58331 r58390 242 242 243 243 /* 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. 246 245 */ 246 /** @todo We should probably ask the debug receive thread to flush it's buffer. */ 247 247 if (rcHv == GIM_HV_STATUS_SUCCESS) 248 248 { 249 249 if (fFlags) 250 LogRel Max(1,("GIM: HyperV: Resetting debug session via hypercall\n"));250 LogRel(("GIM: HyperV: Resetting debug session via hypercall\n")); 251 251 else 252 252 rcHv = GIM_HV_STATUS_INVALID_PARAMETER; … … 470 470 471 471 case MSR_GIM_HV_SYNTH_DEBUG_STATUS: 472 *puValue = pHv->uD ebugStatusMsr;472 *puValue = pHv->uDbgStatusMsr; 473 473 return VINF_SUCCESS; 474 474 … … 508 508 return VINF_CPUM_R3_MSR_READ; 509 509 #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; 512 513 return VINF_SUCCESS; 513 514 #endif … … 724 725 case MSR_GIM_HV_SYNTH_DEBUG_SEND_BUFFER: 725 726 { 727 if (!pHv->fDbgEnabled) 728 return VERR_CPUM_RAISE_GP_0; 726 729 #ifndef IN_RING3 727 730 return VINF_CPUM_R3_MSR_WRITE; 728 731 #else 729 732 RTGCPHYS GCPhysBuffer = (RTGCPHYS)uRawValue; 730 pHv->uD ebugSendBufferMsr = GCPhysBuffer;733 pHv->uDbgSendBufferMsr = GCPhysBuffer; 731 734 if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer)) 732 735 LogRel(("GIM: HyperV: Set up debug send buffer at %#RGp\n", GCPhysBuffer)); 733 736 else 734 737 LogRel(("GIM: HyperV: Destroyed debug send buffer\n")); 735 pHv->uD ebugSendBufferMsr = uRawValue;738 pHv->uDbgSendBufferMsr = uRawValue; 736 739 return VINF_SUCCESS; 737 740 #endif … … 740 743 case MSR_GIM_HV_SYNTH_DEBUG_RECEIVE_BUFFER: 741 744 { 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; 747 752 if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer)) 748 753 LogRel(("GIM: HyperV: Set up debug receive buffer at %#RGp\n", GCPhysBuffer)); … … 755 760 case MSR_GIM_HV_SYNTH_DEBUG_PENDING_BUFFER: 756 761 { 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; 762 769 if (PGMPhysIsGCPhysNormal(pVM, GCPhysBuffer)) 763 {764 770 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 separate768 * thread and updating this page, saves lots of VM-exits as the guest769 * 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 }775 771 else 776 772 LogRel(("GIM: HyperV: Destroyed debug pending buffer\n")); … … 781 777 case MSR_GIM_HV_SYNTH_DEBUG_CONTROL: 782 778 { 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 786 791 if (MSR_GIM_HV_SYNTH_DEBUG_CONTROL_IS_WRITE(uRawValue)) 787 792 { 788 LogRelMax(1, ("GIM: HyperV: Initiated debug data transmission via MSR\n",789 MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue)));790 793 uint32_t cbWrite = MSR_GIM_HV_SYNTH_DEBUG_CONTROL_W_LEN(uRawValue); 791 794 if ( cbWrite > 0 792 795 && cbWrite < GIM_HV_PAGE_SIZE) 793 796 { 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)) 796 798 { 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)) 798 802 { 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; 810 809 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; 815 811 } 816 812 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)); 820 815 } 821 816 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) 822 834 { 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)) 840 837 { 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; 852 840 } 853 841 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 } 856 846 } 857 847 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; 862 849 } 863 850 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")); 865 852 } 866 853 return VINF_SUCCESS; … … 870 857 case MSR_GIM_HV_SINT2: 871 858 { 859 if (!pHv->fDbgEnabled) 860 return VERR_CPUM_RAISE_GP_0; 872 861 #ifndef IN_RING3 873 862 return VINF_CPUM_R3_MSR_WRITE; … … 893 882 case MSR_GIM_HV_SIMP: 894 883 { 884 if (!pHv->fDbgEnabled) 885 return VERR_CPUM_RAISE_GP_0; 895 886 #ifndef IN_RING3 896 887 return VINF_CPUM_R3_MSR_WRITE; -
trunk/src/VBox/VMM/VMMR3/GIM.cpp
r58283 r58390 59 59 60 60 #include <iprt/err.h> 61 #include <iprt/semaphore.h> 61 62 #include <iprt/string.h> 62 63 … … 167 168 rc = VMR3SetError(pVM->pUVM, VERR_GIM_INVALID_PROVIDER, RT_SRC_POS, "Provider '%s' unknown.", szProvider); 168 169 } 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."); 169 180 return rc; 170 181 } … … 415 426 * @param pVM The cross context VM structure. 416 427 * @param pDevIns Pointer to the GIM device instance. 417 * @param pD ebugStream Pointer to the GIM device debug connection, can be428 * @param pDbg Pointer to the GIM device debug structure, can be 418 429 * NULL. 419 430 */ 420 VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns, P PDMISTREAM pDebugStream)431 VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevIns, PGIMDEBUG pDbg) 421 432 { 422 433 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 */ 445 VMMR3DECL(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; 424 458 } 425 459 … … 430 464 * @returns VBox status code. 431 465 * 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. 436 473 * @thread EMT. 437 474 */ 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); 475 VMMR3_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 } 443 497 return VERR_GIM_NO_DEBUG_CONNECTION; 444 498 } … … 458 512 VMMR3_INT_DECL(int) GIMR3DebugWrite(PVM pVM, void *pvWrite, size_t *pcbWrite) 459 513 { 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 } 463 531 return VERR_GIM_NO_DEBUG_CONNECTION; 464 532 } -
trunk/src/VBox/VMM/VMMR3/GIMHv.cpp
r58337 r58390 37 37 #include <VBox/vmm/pdmapi.h> 38 38 #include <VBox/version.h> 39 #ifdef DEBUG_ramshankar 40 # include <iprt/udp.h> 41 #endif 39 42 40 43 … … 175 178 static int gimR3HvInitHypercallSupport(PVM pVM); 176 179 static void gimR3HvTermHypercallSupport(PVM pVM); 180 static int gimR3HvInitDebugSupport(PVM pVM); 181 static void gimR3HvTermDebugSupport(PVM pVM); 177 182 178 183 … … 203 208 rc = CFGMR3ValidateConfig(pCfgHv, "/HyperV/", 204 209 "VendorID" 205 "|VSInterface", 210 "|VSInterface" 211 "|HypercallDebugInterface", 206 212 "" /* pszValidNodes */, "GIM/HyperV" /* pszWho */, 0 /* uInstance */); 207 213 if (RT_FAILURE(rc)) … … 218 224 if (!RTStrNCmp(szVendor, GIM_HV_VENDOR_MICROSOFT, sizeof(GIM_HV_VENDOR_MICROSOFT) - 1)) 219 225 { 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")); 221 227 pHv->fIsVendorMsHv = true; 222 228 } … … 227 233 * The Microsoft virtualization service interface (debugging). */ 228 234 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); 229 240 AssertLogRelRCReturn(rc, rc); 230 241 } … … 438 449 AssertLogRelRCReturn(rc, rc); 439 450 451 /* 452 * Setup debug support. 453 */ 454 rc = gimR3HvInitDebugSupport(pVM); 455 AssertLogRelRCReturn(rc, rc); 456 440 457 return VINF_SUCCESS; 441 458 } … … 559 576 * Reset MSRs. 560 577 */ 561 pHv->u64GuestOsIdMsr 562 pHv->u64HypercallMsr 563 pHv->u64TscPageMsr 564 pHv->uCrashP0Msr 565 pHv->uCrashP1Msr 566 pHv->uCrashP2Msr 567 pHv->uCrashP3Msr 568 pHv->uCrashP4Msr 569 pHv->uD ebugStatusMsr = 0;570 pHv->uD ebugPendingBufferMsr = 0;571 pHv->uD ebugSendBufferMsr = 0;572 pHv->uD ebugRecvBufferMsr = 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; 573 590 for (VMCPUID i = 0; i < pVM->cCpus; i++) 574 591 { … … 595 612 Assert(*pcRegions <= UINT8_MAX); /* See PGMR3PhysMMIO2Register(). */ 596 613 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 */ 622 static 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 */ 647 static 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 */ 672 VMMR3_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; 597 683 } 598 684 … … 663 749 * Save debug support data. 664 750 */ 665 SSMR3PutU64(pSSM, pcHv->uD ebugPendingBufferMsr);666 SSMR3PutU64(pSSM, pcHv->uD ebugSendBufferMsr);667 SSMR3PutU64(pSSM, pcHv->uD ebugRecvBufferMsr);668 SSMR3PutU64(pSSM, pcHv->uD ebugStatusMsr);669 SSMR3PutU32(pSSM, pcHv->enmD ebugReply);670 SSMR3PutU32(pSSM, pcHv->u BootpXId);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); 671 757 SSMR3PutU32(pSSM, pcHv->DbgGuestIp4Addr.u); 672 758 … … 792 878 if (uHvSavedStatVersion > GIM_HV_SAVED_STATE_VERSION_PRE_DEBUG) 793 879 { 794 SSMR3GetU64(pSSM, &pHv->uD ebugPendingBufferMsr);795 SSMR3GetU64(pSSM, &pHv->uD ebugSendBufferMsr);796 SSMR3GetU64(pSSM, &pHv->uD ebugRecvBufferMsr);797 SSMR3GetU64(pSSM, &pHv->uD ebugStatusMsr);798 SSMR3GetU32(pSSM, (uint32_t *)&pHv->enmD ebugReply);799 SSMR3GetU32(pSSM, &pHv->u BootpXId);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); 800 886 rc = SSMR3GetU32(pSSM, &pHv->DbgGuestIp4Addr.u); 801 887 AssertRCReturn(rc, rc); … … 1137 1223 1138 1224 /** 1225 * Initializes Hyper-V guest debug support. 1226 * 1227 * @returns VBox status code. 1228 * @param pVM The cross context VM structure. 1229 */ 1230 static 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 */ 1250 static 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 /** 1139 1262 * Reads data from a debugger connection, asynchronous. 1140 1263 * … … 1165 1288 */ 1166 1289 size_t cbReallyRead = cbRead; 1167 rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead );1290 rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted); 1168 1291 *pcbRead = (uint32_t)cbReallyRead; 1169 1292 } … … 1175 1298 PGIMHV pHv = &pVM->gim.s.u.Hv; 1176 1299 rc = VERR_GIM_IPE_1; 1177 switch (pHv->enmD ebugReply)1300 switch (pHv->enmDbgReply) 1178 1301 { 1179 1302 case GIMHVDEBUGREPLY_UDP: 1180 1303 { 1181 1304 size_t cbReallyRead = cbRead; 1182 rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead );1305 rc = GIMR3DebugRead(pVM, pvBuf, &cbReallyRead, gimR3HvDebugBufReadCompleted); 1183 1306 if ( RT_SUCCESS(rc) 1184 1307 && cbReallyRead > 0) … … 1217 1340 pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); 1218 1341 /* UDP */ 1342 pUdpHdr->uh_dport = pHv->uUdpGuestSrcPort; 1343 pUdpHdr->uh_sport = pHv->uUdpGuestDstPort; 1219 1344 pUdpHdr->uh_ulen = RT_H2N_U16_C((uint16_t)cbReallyRead + sizeof(*pUdpHdr)); 1220 1345 … … 1242 1367 rc = VINF_SUCCESS; 1243 1368 *pcbRead = cbArpReplyPkt; 1244 pHv->enmD ebugReply = GIMHVDEBUGREPLY_ARP_REPLY_SENT;1369 pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY_SENT; 1245 1370 } 1246 1371 else … … 1262 1387 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN); 1263 1388 PRTNETBOOTP pBootpHdr = (PRTNETBOOTP) (pUdpHdr + 1); 1264 pBootpHdr->bp_xid = pHv->u BootpXId;1389 pBootpHdr->bp_xid = pHv->uDbgBootpXId; 1265 1390 1266 1391 rc = VINF_SUCCESS; 1267 1392 *pcbRead = cbDhcpOfferPkt; 1268 pHv->enmD ebugReply = GIMHVDEBUGREPLY_DHCP_OFFER_SENT;1393 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER_SENT; 1269 1394 LogRel(("GIM: HyperV: Debug DHCP offered IP address %RTnaipv4, transaction Id %#x\n", pBootpHdr->bp_yiaddr, 1270 RT_N2H_U32(pHv->u BootpXId)));1395 RT_N2H_U32(pHv->uDbgBootpXId))); 1271 1396 } 1272 1397 else … … 1288 1413 PRTNETUDP pUdpHdr = (PRTNETUDP) ((uint8_t *)pIpHdr + RTNETIPV4_MIN_LEN); 1289 1414 PRTNETBOOTP pBootpHdr = (PRTNETBOOTP) (pUdpHdr + 1); 1290 pBootpHdr->bp_xid = pHv->u BootpXId;1415 pBootpHdr->bp_xid = pHv->uDbgBootpXId; 1291 1416 1292 1417 rc = VINF_SUCCESS; 1293 1418 *pcbRead = cbDhcpAckPkt; 1294 pHv->enmD ebugReply = GIMHVDEBUGREPLY_DHCP_ACK_SENT;1419 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK_SENT; 1295 1420 LogRel(("GIM: HyperV: Debug DHCP acknowledged IP address %RTnaipv4, transaction Id %#x\n", 1296 pBootpHdr->bp_yiaddr, RT_N2H_U32(pHv->u BootpXId)));1421 pBootpHdr->bp_yiaddr, RT_N2H_U32(pHv->uDbgBootpXId))); 1297 1422 } 1298 1423 else … … 1315 1440 default: 1316 1441 { 1317 AssertMsgFailed(("GIM: HyperV: Invalid/unimplemented debug reply type %u\n", pHv->enmD ebugReply));1442 AssertMsgFailed(("GIM: HyperV: Invalid/unimplemented debug reply type %u\n", pHv->enmDbgReply)); 1318 1443 rc = VERR_INTERNAL_ERROR_2; 1319 1444 } 1320 1445 } 1321 1446 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 1323 1464 return rc; 1324 1465 } … … 1347 1488 if (fUdpPkt) 1348 1489 { 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 1349 1500 /* 1350 1501 * Windows guests sends us ethernet frames over the Hyper-V debug connection. … … 1388 1539 * Check for DHCP. 1389 1540 */ 1541 bool fBuggyPkt = false; 1390 1542 size_t const cbUdpPkt = cbMaxIpPkt - cbIpHdr; 1391 1543 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)) 1394 1545 { 1395 1546 PCRTNETBOOTP pDhcpPkt = (PCRTNETBOOTP)(pUdpHdr + 1); 1396 1547 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)) 1398 1550 { 1399 1551 switch (bMsgType) 1400 1552 { 1401 1553 case RTNET_DHCP_MT_DISCOVER: 1402 pHv->enmD ebugReply = GIMHVDEBUGREPLY_DHCP_OFFER;1403 pHv->u BootpXId = pDhcpPkt->bp_xid;1554 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_OFFER; 1555 pHv->uDbgBootpXId = pDhcpPkt->bp_xid; 1404 1556 break; 1405 1557 case RTNET_DHCP_MT_REQUEST: 1406 pHv->enmD ebugReply = GIMHVDEBUGREPLY_DHCP_ACK;1407 pHv->u BootpXId = pDhcpPkt->bp_xid;1558 pHv->enmDbgReply = GIMHVDEBUGREPLY_DHCP_ACK; 1559 pHv->uDbgBootpXId = pDhcpPkt->bp_xid; 1408 1560 break; 1409 1561 default: … … 1412 1564 break; 1413 1565 } 1566 fIgnorePkt = true; 1414 1567 } 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 } 1416 1582 } 1417 else if ( !pUdpHdr->uh_dport 1418 && !pUdpHdr->uh_sport) 1583 1584 if ( ( !pUdpHdr->uh_dport 1585 && !pUdpHdr->uh_sport) 1586 || fBuggyPkt) 1419 1587 { 1420 1588 /* 1421 1589 * 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. 1425 1594 */ 1426 1595 uint32_t const cbFrameHdr = sizeof(RTNETETHERHDR) + cbIpHdr + sizeof(RTNETUDP); 1427 1596 pbData += cbFrameHdr; 1428 1597 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; 1431 1602 } 1432 1603 else 1433 1604 { 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)); 1435 1607 fIgnorePkt = true; 1436 1608 } … … 1476 1648 && pArpPkt->ar_tpa.u == GIMHV_DEBUGSERVER_IPV4) 1477 1649 { 1478 pHv->enmD ebugReply = GIMHVDEBUGREPLY_ARP_REPLY;1650 pHv->enmDbgReply = GIMHVDEBUGREPLY_ARP_REPLY; 1479 1651 } 1480 1652 } -
trunk/src/VBox/VMM/include/GIMHvInternal.h
r58335 r58390 713 713 /** The undocumented bit for MSR_GIM_HV_DEBUG_OPTIONS_MSR that makes it all 714 714 * work. */ 715 #define GIM_HV_DEBUG_OPTIONS_ MSR_ENABLERT_BIT(2)715 #define GIM_HV_DEBUG_OPTIONS_USE_HYPERCALLS RT_BIT(2) 716 716 717 717 /** Guest will perform the HvPostDebugData hypercall until completion. */ … … 1047 1047 /** Whether we're posing as the Microsoft virtualization service. */ 1048 1048 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. */ 1051 1057 RTNETADDRIPV4 DbgGuestIp4Addr; 1052 /** The action to take while sending replies. */1053 GIMHVDEBUGREPLY enmDebugReply;1054 1058 /** 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; 1058 1064 /** Debug send buffer MSR. */ 1059 uint64_t uD ebugSendBufferMsr;1065 uint64_t uDbgSendBufferMsr; 1060 1066 /** Debug receive buffer MSR. */ 1061 uint64_t uD ebugRecvBufferMsr;1067 uint64_t uDbgRecvBufferMsr; 1062 1068 /** Debug pending buffer MSR. */ 1063 uint64_t uD ebugPendingBufferMsr;1069 uint64_t uDbgPendingBufferMsr; 1064 1070 /** Debug status MSR. */ 1065 uint64_t uDebugStatusMsr; 1071 uint64_t uDbgStatusMsr; 1072 /** Intermediate debug I/O buffer. */ 1073 R3PTRTYPE(void *) pvDbgBuffer; 1066 1074 /** @} */ 1067 1075 … … 1113 1121 VMMR3_INT_DECL(int) gimR3HvSave(PVM pVM, PSSMHANDLE pSSM); 1114 1122 VMMR3_INT_DECL(int) gimR3HvLoad(PVM pVM, PSSMHANDLE pSSM, uint32_t uSSMVersion); 1123 VMMR3_INT_DECL(int) gimR3HvGetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup); 1115 1124 1116 1125 VMMR3_INT_DECL(int) gimR3HvDisableTscPage(PVM pVM); -
trunk/src/VBox/VMM/include/GIMInternal.h
r58283 r58390 54 54 /** Pointer to the GIM device - R3 ptr. */ 55 55 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; 65 58 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. */ 81 60 union 82 61 { … … 84 63 GIMKVM Kvm; 85 64 } 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; 86 76 } GIM; 87 77 /** Pointer to GIM VM instance data. */ 88 78 typedef GIM *PGIM; 89 90 79 91 80 /** … … 103 92 typedef GIMCPU *PGIMCPU; 104 93 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 */ 100 typedef DECLCALLBACK(void) FNGIMDEBUGBUFREADCOMPLETED(PVM pVM); 101 /** Pointer to GIM debug buffer read completion callback. */ 102 typedef FNGIMDEBUGBUFREADCOMPLETED *PFNGIMDEBUGBUFREADCOMPLETED; 103 105 104 #ifdef IN_RING3 106 105 VMMR3_INT_DECL(int) GIMR3Mmio2Unmap(PVM pVM, PGIMMMIO2REGION pRegion); … … 109 108 VMMR3_INT_DECL(int) GIMR3Mmio2HandlerPhysicalDeregister(PVM pVM, PGIMMMIO2REGION pRegion); 110 109 111 VMMR3_INT_DECL(int) GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead );110 VMMR3_INT_DECL(int) GIMR3DebugRead(PVM pVM, void *pvRead, size_t *pcbRead, PFNGIMDEBUGBUFREADCOMPLETED pfnReadComplete); 112 111 VMMR3_INT_DECL(int) GIMR3DebugWrite(PVM pVM, void *pvWrite, size_t *pcbWrite); 113 112 #endif /* IN_RING3 */
Note:
See TracChangeset
for help on using the changeset viewer.