Changeset 86699 in vbox
- Timestamp:
- Oct 25, 2020 10:44:39 AM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 141083
- Location:
- trunk
- Files:
-
- 1 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/err.h
r86666 r86699 331 331 /** The breakpoint owner handle is still used by one or more breakpoints. */ 332 332 #define VERR_DBGF_OWNER_BUSY (-1225) 333 /** Internal processing error \#1 in the DBGF breakpoint manager code. */ 334 #define VERR_DBGF_BP_IPE_1 (-1226) 335 /** Internal processing error \#2 in the DBGF breakpoint manager code. */ 336 #define VERR_DBGF_BP_IPE_2 (-1227) 337 /** Internal processing error \#3 in the DBGF breakpoint manager code. */ 338 #define VERR_DBGF_BP_IPE_3 (-1228) 339 /** Internal processing error \#4 in the DBGF breakpoint manager code. */ 340 #define VERR_DBGF_BP_IPE_4 (-1229) 341 /** Internal processing error \#5 in the DBGF breakpoint manager code. */ 342 #define VERR_DBGF_BP_IPE_5 (-1230) 333 343 /** @} */ 334 344 -
trunk/include/VBox/vmm/dbgf.h
r86683 r86699 86 86 87 87 VMMR0_INT_DECL(int) DBGFR0TracerCreateReqHandler(PGVM pGVM, PDBGFTRACERCREATEREQ pReq); 88 89 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 90 /** 91 * Request buffer for DBGFR0BpInitReqHandler / VMMR0_DO_DBGF_BP_INIT. 92 * @see DBGFR0BpInitReqHandler. 93 */ 94 typedef struct DBGFBPINITREQ 95 { 96 /** The header. */ 97 SUPVMMR0REQHDR Hdr; 98 /** Out: Ring-3 pointer of the L1 lookup table on success. */ 99 R3PTRTYPE(volatile uint32_t *) paBpLocL1R3; 100 } DBGFBPINITREQ; 101 /** Pointer to a DBGFR0BpInitReqHandler / VMMR0_DO_DBGF_BP_INIT request buffer. */ 102 typedef DBGFBPINITREQ *PDBGFBPINITREQ; 103 104 VMMR0_INT_DECL(int) DBGFR0BpInitReqHandler(PGVM pGVM, PDBGFBPINITREQ pReq); 105 106 /** 107 * Request buffer for DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_CHUNK_ALLOC. 108 * @see DBGFR0BpChunkAllocReqHandler. 109 */ 110 typedef struct DBGFBPCHUNKALLOCREQ 111 { 112 /** The header. */ 113 SUPVMMR0REQHDR Hdr; 114 /** Out: Ring-3 pointer of the chunk base on success. */ 115 R3PTRTYPE(void *) pChunkBaseR3; 116 117 /** The chunk ID to allocate. */ 118 uint32_t idChunk; 119 } DBGFBPCHUNKALLOCREQ; 120 /** Pointer to a DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_CHUNK_ALLOC request buffer. */ 121 typedef DBGFBPCHUNKALLOCREQ *PDBGFBPCHUNKALLOCREQ; 122 123 VMMR0_INT_DECL(int) DBGFR0BpChunkAllocReqHandler(PGVM pGVM, PDBGFBPCHUNKALLOCREQ pReq); 124 #endif 88 125 /** @} */ 89 126 … … 829 866 * debugger). */ 830 867 DBGFBPOWNER hOwner; 831 /** The breakpoint type. */ 832 DBGFBPTYPE enmType; 833 /** The breakpoint handle this state belongs to. */ 834 DBGFBP hBp; 835 /** Breakpoint flags, see DBGF_BP_F_XXX. */ 836 uint32_t fFlags; 868 /** Breakpoint type and flags, see DBGFBPTYPE for type and DBGF_BP_F_XXX for flags. 869 * Needs to be smashed together to be able to stay in the size limits. */ 870 uint32_t fFlagsAndType; 837 871 838 872 /** Union of type specific data. */ … … 889 923 890 924 /** Padding to the anticipated size. */ 891 uint64_t u64Padding[ 3];925 uint64_t u64Padding[2]; 892 926 } u; 893 927 } DBGFBPPUB; 894 AssertCompileSize(DBGFBPPUB, 64 );928 AssertCompileSize(DBGFBPPUB, 64 - 8); 895 929 AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Reg.GCPtr); 896 930 AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Int3.GCPtr); … … 901 935 typedef const DBGFBPPUB *PCDBGFBPPUB; 902 936 903 /** @name Possible DBGFBPPUB::fFlags flags. 937 /** Sets the DBGFPUB::fFlagsAndType member. */ 938 #define DBGF_BP_PUB_SET_FLAGS_AND_TYPE(a_enmType, a_fFlags) ((uint32_t)(a_enmType) | (a_fFlags)) 939 /** Returns the type of the DBGFPUB::fFlagsAndType member. */ 940 #define DBGF_BP_PUB_GET_TYPE(a_fFlagsAndType) ((DBGFBPTYPE)((a_fFlagsAndType) & (UINT32_C(0x7fffffff)))) 941 /** Returns the enabled status of DBGFPUB::fFlagsAndType member. */ 942 #define DBGF_BP_PUB_IS_ENABLED(a_fFlagsAndType) RT_BOOL((DBGFBPTYPE)((a_fFlagsAndType) & DBGF_BP_F_ENABLED)) 943 944 /** @name Possible DBGFBPPUB::fFlagsAndType flags. 904 945 * @{ */ 946 /** Default flags. */ 947 #define DBGF_BP_F_DEFAULT 0 905 948 /** Flag whether the breakpoint is enabled currently. */ 906 #define DBGF_BP_F_ENABLED RT_BIT_32( 0)949 #define DBGF_BP_F_ENABLED RT_BIT_32(31) 907 950 /** @} */ 951 908 952 909 953 /** … … 916 960 * @param pVM The cross-context VM structure pointer. 917 961 * @param idCpu ID of the vCPU triggering the breakpoint. 918 * @param pvUser User argument of the set breakpoint. 962 * @param pvUserBp User argument of the set breakpoint. 963 * @param hBp The breakpoint handle. 919 964 * @param pBpPub Pointer to the readonly public state of the breakpoint. 920 965 * … … 923 968 * guru meditation. 924 969 */ 925 typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, PCDBGFBPPUB pBpPub));970 typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub)); 926 971 /** Pointer to a FNDBGFBPHIT(). */ 927 972 typedef FNDBGFBPHIT *PFNDBGFBPHIT; … … 967 1012 * @param pUVM The user mode VM handle. 968 1013 * @param pvUser The user argument. 969 * @param pBp Pointer to the breakpoint information. (readonly) 970 */ 971 typedef DECLCALLBACKTYPE(int, FNDBGFBPENUM,(PUVM pUVM, PCDBGFBPPUB pBpPub)); 1014 * @param hBp The breakpoint handle. 1015 * @param pBp Pointer to the public breakpoint information. (readonly) 1016 */ 1017 typedef DECLCALLBACKTYPE(int, FNDBGFBPENUM,(PUVM pUVM, void *pvUser, DBGFBP hBp, PCDBGFBPPUB pBpPub)); 972 1018 /** Pointer to a breakpoint enumeration callback function. */ 973 1019 typedef FNDBGFBPENUM *PFNDBGFBPENUM; -
trunk/include/VBox/vmm/gvm.h
r84458 r86699 234 234 struct DBGFR0PERVM s; 235 235 #endif 236 uint8_t padding[ 64];236 uint8_t padding[1024]; 237 237 } dbgfr0; 238 238 239 239 /** Padding so aCpus starts on a page boundrary. */ 240 240 #ifdef VBOX_WITH_NEM_R0 241 uint8_t abPadding2[4096*2 - 64 - 256 - 1024 - 256 - 64 - 2176 - 640 - 512 - 64 - 64 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT];242 #else 243 uint8_t abPadding2[4096*2 - 64 - 256 - 1024 - 64 - 2176 - 640 - 512 - 64 - 64 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT];241 uint8_t abPadding2[4096*2 - 64 - 256 - 1024 - 256 - 64 - 2176 - 640 - 512 - 64 - 1024 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT]; 242 #else 243 uint8_t abPadding2[4096*2 - 64 - 256 - 1024 - 64 - 2176 - 640 - 512 - 64 - 1024 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT]; 244 244 #endif 245 245 -
trunk/include/VBox/vmm/uvm.h
r82968 r86699 148 148 struct DBGFUSERPERVM s; 149 149 #endif 150 uint8_t padding[ 384];150 uint8_t padding[1024]; 151 151 } dbgf; 152 152 -
trunk/include/VBox/vmm/vmm.h
r86452 r86699 431 431 /** Call DBGFR0TraceCallReqHandler. */ 432 432 VMMR0_DO_DBGF_TRACER_CALL_REQ_HANDLER, 433 /** Call DBGFR0BpInitReqHandler(). */ 434 VMMR0_DO_DBGF_BP_INIT, 435 /** Call DBGFR0BpChunkAllocReqHandler(). */ 436 VMMR0_DO_DBGF_BP_CHUNK_ALLOC, 433 437 434 438 /** The usual 32-bit type blow up. */ -
trunk/src/VBox/VMM/Makefile.kmk
r86683 r86699 457 457 VMMR0_DEFS += VBOX_WITH_DBGF_TRACING 458 458 endif 459 ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 460 VMMR0_DEFS += VBOX_WITH_LOTS_OF_DBGF_BPS 461 endif 459 462 ifdef VBOX_WITH_VMM_R0_SWITCH_STACK 460 463 VMMR0_DEFS += VMM_R0_SWITCH_STACK … … 479 482 VMMR0/CPUMR0A.asm \ 480 483 VMMR0/DBGFR0.cpp \ 484 $(if-expr defined(VBOX_WITH_LOTS_OF_DBGF_BPS), VMMR0/DBGFR0Bp.cpp,) \ 481 485 $(if-expr defined(VBOX_WITH_DBGF_TRACING), VMMR0/DBGFR0Tracer.cpp,) \ 482 486 VMMR0/GIMR0.cpp \ -
trunk/src/VBox/VMM/VMMR0/DBGFR0.cpp
r86683 r86699 55 55 { 56 56 pGVM->dbgfr0.s.pTracerR0 = NULL; 57 58 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 59 dbgfR0BpInit(pGVM); 60 #endif 57 61 } 58 62 … … 68 72 pGVM->dbgfr0.s.pTracerR0 = NULL; 69 73 #endif 74 75 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 76 dbgfR0BpDestroy(pGVM); 77 #endif 70 78 } 71 79 -
trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
r86452 r86699 2242 2242 } 2243 2243 2244 /* 2245 * DBGF requests. 2246 */ 2244 2247 #ifdef VBOX_WITH_DBGF_TRACING 2245 2248 case VMMR0_DO_DBGF_TRACER_CREATE: … … 2261 2264 rc = VERR_NOT_IMPLEMENTED; 2262 2265 #endif 2266 VMM_CHECK_SMAP_CHECK2(pGVM, RT_NOTHING); 2267 break; 2268 } 2269 #endif 2270 2271 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 2272 case VMMR0_DO_DBGF_BP_INIT: 2273 { 2274 if (!pReqHdr || u64Arg || idCpu != 0) 2275 return VERR_INVALID_PARAMETER; 2276 rc = DBGFR0BpInitReqHandler(pGVM, (PDBGFBPINITREQ)pReqHdr); 2277 VMM_CHECK_SMAP_CHECK2(pGVM, RT_NOTHING); 2278 break; 2279 } 2280 2281 case VMMR0_DO_DBGF_BP_CHUNK_ALLOC: 2282 { 2283 if (!pReqHdr || u64Arg || idCpu != 0) 2284 return VERR_INVALID_PARAMETER; 2285 rc = DBGFR0BpChunkAllocReqHandler(pGVM, (PDBGFBPCHUNKALLOCREQ)pReqHdr); 2263 2286 VMM_CHECK_SMAP_CHECK2(pGVM, RT_NOTHING); 2264 2287 break; … … 2368 2391 case VMMR0_DO_IOM_GROW_IO_PORTS: 2369 2392 case VMMR0_DO_IOM_GROW_IO_PORT_STATS: 2393 2394 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 2395 case VMMR0_DO_DBGF_BP_INIT: 2396 case VMMR0_DO_DBGF_BP_CHUNK_ALLOC: 2397 #endif 2370 2398 { 2371 2399 PGVMCPU pGVCpu = &pGVM->aCpus[idCpu]; -
trunk/src/VBox/VMM/VMMR3/DBGF.cpp
r86666 r86699 149 149 if (RT_SUCCESS(rc)) 150 150 { 151 #ifndef VBOX_WITH_LOTS_OF_DBGF_BPS 151 152 rc = dbgfR3BpInit(pVM); 153 #else 154 rc = dbgfR3BpInit(pUVM); 155 #endif 152 156 if (RT_SUCCESS(rc)) 153 157 { … … 175 179 } 176 180 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 177 dbgfR3BpTerm(p VM);181 dbgfR3BpTerm(pUVM); 178 182 #endif 179 183 } … … 207 211 dbgfR3OSTermPart2(pUVM); 208 212 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 209 dbgfR3BpTerm(p VM);213 dbgfR3BpTerm(pUVM); 210 214 #endif 211 215 dbgfR3AsTerm(pUVM); -
trunk/src/VBox/VMM/VMMR3/DBGFR3Bp.cpp
r86666 r86699 110 110 * from the L1 table. The key for the table are the upper 6 bytes of the breakpoint address 111 111 * used for searching. This tree is traversed until either a matching address is found and 112 * the breakpoint is being processed or again forwarded to the guest if it isn't successful.112 * the breakpoint is being processed or again forwarded to the guest if it isn't successful. 113 113 * Each entry in the L2 table is 16 bytes big and densly packed to avoid excessive memory usage. 114 114 * … … 155 155 #include <VBox/log.h> 156 156 #include <iprt/assert.h> 157 #include <iprt/ string.h>157 #include <iprt/mem.h> 158 158 159 159 … … 170 170 171 171 172 173 172 /** 174 173 * Initialize the breakpoint mangement. 175 174 * 176 175 * @returns VBox status code. 177 * @param pVM The cross context VM structure. 178 */ 179 DECLHIDDEN(int) dbgfR3BpInit(PVM pVM) 180 { 181 RT_NOREF(pVM); 176 * @param pUVM The user mode VM handle. 177 */ 178 DECLHIDDEN(int) dbgfR3BpInit(PUVM pUVM) 179 { 180 PVM pVM = pUVM->pVM; 181 182 /* Init hardware breakpoint states. */ 183 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++) 184 { 185 PDBGFBPHW pHwBp = &pVM->dbgf.s.aHwBreakpoints[i]; 186 187 AssertCompileSize(DBGFBP, sizeof(uint32_t)); 188 pHwBp->hBp = NIL_DBGFBP; 189 //pHwBp->fEnabled = false; 190 } 191 192 /* Now the global breakpoint table chunks. */ 193 for (uint32_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.aBpChunks); i++) 194 { 195 PDBGFBPCHUNKR3 pBpChunk = &pUVM->dbgf.s.aBpChunks[i]; 196 197 //pBpChunk->pBpBaseR3 = NULL; 198 //pBpChunk->pbmAlloc = NULL; 199 //pBpChunk->cBpsFree = 0; 200 pBpChunk->idChunk = DBGF_BP_CHUNK_ID_INVALID; /* Not allocated. */ 201 } 202 203 //pUVM->dbgf.s.paBpLocL1R3 = NULL; 182 204 return VINF_SUCCESS; 183 205 } … … 188 210 * 189 211 * @returns VBox status code. 190 * @param pVM The cross context VM structure. 191 */ 192 DECLHIDDEN(int) dbgfR3BpTerm(PVM pVM) 193 { 194 RT_NOREF(pVM); 212 * @param pUVM The user mode VM handle. 213 */ 214 DECLHIDDEN(int) dbgfR3BpTerm(PUVM pUVM) 215 { 216 /* Free all allocated chunk bitmaps (the chunks itself are destroyed during ring-0 VM destruction). */ 217 for (uint32_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.aBpChunks); i++) 218 { 219 PDBGFBPCHUNKR3 pBpChunk = &pUVM->dbgf.s.aBpChunks[i]; 220 221 if (pBpChunk->idChunk != DBGF_BP_CHUNK_ID_INVALID) 222 { 223 AssertPtr(pBpChunk->pbmAlloc); 224 RTMemFree((void *)pBpChunk->pbmAlloc); 225 pBpChunk->pbmAlloc = NULL; 226 pBpChunk->idChunk = DBGF_BP_CHUNK_ID_INVALID; 227 } 228 } 229 195 230 return VINF_SUCCESS; 231 } 232 233 234 /** 235 * @callback_method_impl{FNVMMEMTRENDEZVOUS} 236 */ 237 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpInitEmtWorker(PVM pVM, PVMCPU pVCpu, void *pvUser) 238 { 239 RT_NOREF(pvUser); 240 241 VMCPU_ASSERT_EMT(pVCpu); 242 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 243 244 /* 245 * The initialization will be done on EMT(0). It is possible that multiple 246 * initialization attempts are done because dbgfR3BpEnsureInit() can be called 247 * from racing non EMT threads when trying to set a breakpoint for the first time. 248 * Just fake success if the L1 is already present which means that a previous rendezvous 249 * successfully initialized the breakpoint manager. 250 */ 251 PUVM pUVM = pVM->pUVM; 252 if ( pVCpu->idCpu == 0 253 && !pUVM->dbgf.s.paBpLocL1R3) 254 { 255 DBGFBPINITREQ Req; 256 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; 257 Req.Hdr.cbReq = sizeof(Req); 258 Req.paBpLocL1R3 = NULL; 259 int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_DBGF_BP_INIT, 0 /*u64Arg*/, &Req.Hdr); 260 AssertLogRelMsgRCReturn(rc, ("VMMR0_DO_DBGF_BP_INIT failed: %Rrc\n", rc), rc); 261 pUVM->dbgf.s.paBpLocL1R3 = Req.paBpLocL1R3; 262 } 263 264 return VINF_SUCCESS; 265 } 266 267 268 /** 269 * Ensures that the breakpoint manager is fully initialized. 270 * 271 * @returns VBox status code. 272 * @param pUVM The user mode VM handle. 273 * 274 * @thread Any thread. 275 */ 276 static int dbgfR3BpEnsureInit(PUVM pUVM) 277 { 278 /* If the L1 lookup table is allocated initialization succeeded before. */ 279 if (RT_LIKELY(pUVM->dbgf.s.paBpLocL1R3)) 280 return VINF_SUCCESS; 281 282 /* Gather all EMTs and call into ring-0 to initialize the breakpoint manager. */ 283 return VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpInitEmtWorker, NULL /*pvUser*/); 284 } 285 286 287 /** 288 * Returns the internal breakpoint state for the given handle. 289 * 290 * @returns Pointer to the internal breakpoint state or NULL if the handle is invalid. 291 * @param pUVM The user mode VM handle. 292 * @param hBp The breakpoint handle to resolve. 293 */ 294 DECLINLINE(PDBGFBPINT) dbgfR3BpGetByHnd(PUVM pUVM, DBGFBP hBp) 295 { 296 uint32_t idChunk = DBGF_BP_HND_GET_CHUNK_ID(hBp); 297 uint32_t idxEntry = DBGF_BP_HND_GET_ENTRY(hBp); 298 299 AssertReturn(idChunk < DBGF_BP_CHUNK_COUNT, NULL); 300 AssertReturn(idxEntry < DBGF_BP_COUNT_PER_CHUNK, NULL); 301 302 PDBGFBPCHUNKR3 pBpChunk = &pUVM->dbgf.s.aBpChunks[idChunk]; 303 AssertReturn(pBpChunk->idChunk == idChunk, NULL); 304 AssertPtrReturn(pBpChunk->pbmAlloc, NULL); 305 AssertReturn(ASMBitTest(pBpChunk->pbmAlloc, idxEntry), NULL); 306 307 return &pBpChunk->pBpBaseR3[idxEntry]; 308 } 309 310 311 /** 312 * Get a breakpoint give by address. 313 * 314 * @returns The breakpoint handle on success or NIL_DBGF if not found. 315 * @param pUVM The user mode VM handle. 316 * @param enmType The breakpoint type. 317 * @param GCPtr The breakpoint address. 318 * @param ppBp Where to store the pointer to the internal breakpoint state on success, optional. 319 */ 320 static DBGFBP dbgfR3BpGetByAddr(PUVM pUVM, DBGFBPTYPE enmType, RTGCUINTPTR GCPtr, PDBGFBPINT *ppBp) 321 { 322 DBGFBP hBp = NIL_DBGFBP; 323 324 switch (enmType) 325 { 326 case DBGFBPTYPE_REG: 327 { 328 PVM pVM = pUVM->pVM; 329 VM_ASSERT_VALID_EXT_RETURN(pVM, NIL_DBGFBP); 330 331 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++) 332 { 333 PDBGFBPHW pHwBp = &pVM->dbgf.s.aHwBreakpoints[i]; 334 335 AssertCompileSize(DBGFBP, sizeof(uint32_t)); 336 DBGFBP hBpTmp = ASMAtomicReadU32(&pHwBp->hBp); 337 if ( pHwBp->GCPtr == GCPtr 338 && hBpTmp != NIL_DBGFBP) 339 { 340 hBp = hBpTmp; 341 break; 342 } 343 } 344 345 break; 346 } 347 348 case DBGFBPTYPE_INT3: 349 break; 350 351 default: 352 AssertMsgFailed(("enmType=%d\n", enmType)); 353 break; 354 } 355 356 if ( hBp != NIL_DBGFBP 357 && ppBp) 358 *ppBp = dbgfR3BpGetByHnd(pUVM, hBp); 359 return hBp; 360 } 361 362 363 /** 364 * @callback_method_impl{FNVMMEMTRENDEZVOUS} 365 */ 366 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpChunkAllocEmtWorker(PVM pVM, PVMCPU pVCpu, void *pvUser) 367 { 368 uint32_t idChunk = (uint32_t)(uintptr_t)pvUser; 369 370 VMCPU_ASSERT_EMT(pVCpu); 371 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 372 373 AssertReturn(idChunk < DBGF_BP_CHUNK_COUNT, VERR_DBGF_BP_IPE_1); 374 375 PUVM pUVM = pVM->pUVM; 376 PDBGFBPCHUNKR3 pBpChunk = &pUVM->dbgf.s.aBpChunks[idChunk]; 377 378 AssertReturn( pBpChunk->idChunk == DBGF_BP_CHUNK_ID_INVALID 379 || pBpChunk->idChunk == idChunk, 380 VERR_DBGF_BP_IPE_2); 381 382 /* 383 * The initialization will be done on EMT(0). It is possible that multiple 384 * allocation attempts are done when multiple racing non EMT threads try to 385 * allocate a breakpoint and a new chunk needs to be allocated. 386 * Ignore the request and succeed if the chunk is allocated meaning that a 387 * previous rendezvous successfully allocated the chunk. 388 */ 389 int rc = VINF_SUCCESS; 390 if ( pVCpu->idCpu == 0 391 && pBpChunk->idChunk == DBGF_BP_CHUNK_ID_INVALID) 392 { 393 /* Allocate the bitmap first so we can skip calling into VMMR0 if it fails. */ 394 AssertCompile(!(DBGF_BP_COUNT_PER_CHUNK % 8)); 395 volatile void *pbmAlloc = RTMemAllocZ(DBGF_BP_COUNT_PER_CHUNK / 8); 396 if (RT_LIKELY(pbmAlloc)) 397 { 398 DBGFBPCHUNKALLOCREQ Req; 399 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; 400 Req.Hdr.cbReq = sizeof(Req); 401 Req.idChunk = idChunk; 402 Req.pChunkBaseR3 = NULL; 403 rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_DBGF_BP_CHUNK_ALLOC, 0 /*u64Arg*/, &Req.Hdr); 404 AssertLogRelMsgRC(rc, ("VMMR0_DO_DBGF_BP_CHUNK_ALLOC failed: %Rrc\n", rc)); 405 if (RT_SUCCESS(rc)) 406 { 407 pBpChunk->pBpBaseR3 = (PDBGFBPINT)Req.pChunkBaseR3; 408 pBpChunk->pbmAlloc = pbmAlloc; 409 pBpChunk->cBpsFree = DBGF_BP_COUNT_PER_CHUNK; 410 pBpChunk->idChunk = idChunk; 411 return VINF_SUCCESS; 412 } 413 414 RTMemFree((void *)pbmAlloc); 415 } 416 else 417 rc = VERR_NO_MEMORY; 418 } 419 420 return rc; 421 } 422 423 424 /** 425 * Tries to allocate the given chunk which requires an EMT rendezvous. 426 * 427 * @returns VBox status code. 428 * @param pUVM The user mode VM handle. 429 * @param idChunk The chunk to allocate. 430 * 431 * @thread Any thread. 432 */ 433 DECLINLINE(int) dbgfR3BpChunkAlloc(PUVM pUVM, uint32_t idChunk) 434 { 435 return VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpChunkAllocEmtWorker, (void *)(uintptr_t)idChunk); 436 } 437 438 439 /** 440 * Tries to allocate a new breakpoint of the given type. 441 * 442 * @returns VBox status code. 443 * @param pUVM The user mode VM handle. 444 * @param hOwner The owner handle, NIL_DBGFBPOWNER if none assigned. 445 * @param pvUser Opaque user data passed in the owner callback. 446 * @param enmType Breakpoint type to allocate. 447 * @param iHitTrigger The hit count at which the breakpoint start triggering. 448 * Use 0 (or 1) if it's gonna trigger at once. 449 * @param iHitDisable The hit count which disables the breakpoint. 450 * Use ~(uint64_t) if it's never gonna be disabled. 451 * @param phBp Where to return the opaque breakpoint handle on success. 452 * @param ppBp Where to return the pointer to the internal breakpoint state on success. 453 * 454 * @thread Any thread. 455 */ 456 static int dbgfR3BpAlloc(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, DBGFBPTYPE enmType, 457 uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp, 458 PDBGFBPINT *ppBp) 459 { 460 /* 461 * Search for a chunk having a free entry, allocating new chunks 462 * if the encountered ones are full. 463 * 464 * This can be called from multiple threads at the same time so special care 465 * has to be taken to not require any locking here. 466 */ 467 for (uint32_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.aBpChunks); i++) 468 { 469 PDBGFBPCHUNKR3 pBpChunk = &pUVM->dbgf.s.aBpChunks[i]; 470 471 uint32_t idChunk = ASMAtomicReadU32(&pBpChunk->idChunk); 472 if (idChunk == DBGF_BP_CHUNK_ID_INVALID) 473 { 474 int rc = dbgfR3BpChunkAlloc(pUVM, i); 475 if (RT_FAILURE(rc)) 476 { 477 LogRel(("DBGF/Bp: Allocating new breakpoint table chunk failed with %Rrc\n", rc)); 478 break; 479 } 480 481 idChunk = ASMAtomicReadU32(&pBpChunk->idChunk); 482 Assert(idChunk == i); 483 } 484 485 /** @todo Optimize with some hinting if this turns out to be too slow. */ 486 for (;;) 487 { 488 uint32_t cBpsFree = ASMAtomicReadU32(&pBpChunk->cBpsFree); 489 if (cBpsFree) 490 { 491 /* 492 * Scan the associated bitmap for a free entry, if none can be found another thread 493 * raced us and we go to the next chunk. 494 */ 495 int32_t iClr = ASMBitFirstClear(pBpChunk->pbmAlloc, DBGF_BP_COUNT_PER_CHUNK); 496 if (iClr != -1) 497 { 498 /* 499 * Try to allocate, we could get raced here as well. In that case 500 * we try again. 501 */ 502 if (!ASMAtomicBitTestAndSet(pBpChunk->pbmAlloc, iClr)) 503 { 504 /* Success, immediately mark as allocated, initialize the breakpoint state and return. */ 505 ASMAtomicDecU32(&pBpChunk->cBpsFree); 506 507 PDBGFBPINT pBp = &pBpChunk->pBpBaseR3[iClr]; 508 pBp->Pub.cHits = 0; 509 pBp->Pub.iHitTrigger = iHitTrigger; 510 pBp->Pub.iHitDisable = iHitDisable; 511 pBp->Pub.hOwner = hOwner; 512 pBp->Pub.fFlagsAndType = DBGF_BP_PUB_SET_FLAGS_AND_TYPE(enmType, DBGF_BP_F_DEFAULT); 513 pBp->pvUserR3 = pvUser; 514 515 /** @todo Owner handling (reference and call ring-0 if it has an ring-0 callback). */ 516 517 *phBp = DBGF_BP_HND_CREATE(idChunk, iClr); 518 *ppBp = pBp; 519 return VINF_SUCCESS; 520 } 521 /* else Retry with another spot. */ 522 } 523 else /* no free entry in bitmap, go to the next chunk */ 524 break; 525 } 526 else /* !cBpsFree, go to the next chunk */ 527 break; 528 } 529 } 530 531 return VERR_DBGF_NO_MORE_BP_SLOTS; 532 } 533 534 535 /** 536 * Frees the given breakpoint handle. 537 * 538 * @returns nothing. 539 * @param pUVM The user mode VM handle. 540 * @param hBp The breakpoint handle to free. 541 * @param pBp The internal breakpoint state pointer. 542 */ 543 static void dbgfR3BpFree(PUVM pUVM, DBGFBP hBp, PDBGFBPINT pBp) 544 { 545 uint32_t idChunk = DBGF_BP_HND_GET_CHUNK_ID(hBp); 546 uint32_t idxEntry = DBGF_BP_HND_GET_ENTRY(hBp); 547 548 AssertReturnVoid(idChunk < DBGF_BP_CHUNK_COUNT); 549 AssertReturnVoid(idxEntry < DBGF_BP_COUNT_PER_CHUNK); 550 551 PDBGFBPCHUNKR3 pBpChunk = &pUVM->dbgf.s.aBpChunks[idChunk]; 552 AssertPtrReturnVoid(pBpChunk->pbmAlloc); 553 AssertReturnVoid(ASMBitTest(pBpChunk->pbmAlloc, idxEntry)); 554 555 /** @todo Need a trip to Ring-0 if an owner is assigned with a Ring-0 part to clear the breakpoint. */ 556 /** @todo Release owner. */ 557 memset(pBp, 0, sizeof(*pBp)); 558 559 ASMAtomicBitClear(pBpChunk->pbmAlloc, idxEntry); 560 ASMAtomicIncU32(&pBpChunk->cBpsFree); 561 } 562 563 564 /** 565 * Sets the enabled flag of the given breakpoint to the given value. 566 * 567 * @returns nothing. 568 * @param pBp The breakpoint to set the state. 569 * @param fEnabled Enabled status. 570 */ 571 DECLINLINE(void) dbgfR3BpSetEnabled(PDBGFBPINT pBp, bool fEnabled) 572 { 573 DBGFBPTYPE enmType = DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType); 574 if (fEnabled) 575 pBp->Pub.fFlagsAndType = DBGF_BP_PUB_SET_FLAGS_AND_TYPE(enmType, DBGF_BP_F_ENABLED); 576 else 577 pBp->Pub.fFlagsAndType = DBGF_BP_PUB_SET_FLAGS_AND_TYPE(enmType, 0 /*fFlags*/); 578 } 579 580 581 /** 582 * Assigns a hardware breakpoint state to the given register breakpoint. 583 * 584 * @returns VBox status code. 585 * @param pVM The cross-context VM structure pointer. 586 * @param hBp The breakpoint handle to assign. 587 * @param pBp The internal breakpoint state. 588 * 589 * @thread Any thread. 590 */ 591 static int dbgfR3BpRegAssign(PVM pVM, DBGFBP hBp, PDBGFBPINT pBp) 592 { 593 AssertReturn(pBp->Pub.u.Reg.iReg == UINT8_MAX, VERR_DBGF_BP_IPE_3); 594 595 for (uint8_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++) 596 { 597 PDBGFBPHW pHwBp = &pVM->dbgf.s.aHwBreakpoints[i]; 598 599 AssertCompileSize(DBGFBP, sizeof(uint32_t)); 600 if (ASMAtomicCmpXchgU32(&pHwBp->hBp, hBp, NIL_DBGFBP)) 601 { 602 pHwBp->GCPtr = pBp->Pub.u.Reg.GCPtr; 603 pHwBp->fType = pBp->Pub.u.Reg.fType; 604 pHwBp->cb = pBp->Pub.u.Reg.cb; 605 pHwBp->fEnabled = DBGF_BP_PUB_IS_ENABLED(pBp->Pub.fFlagsAndType); 606 607 pBp->Pub.u.Reg.iReg = i; 608 return VINF_SUCCESS; 609 } 610 } 611 612 return VERR_DBGF_NO_MORE_BP_SLOTS; 613 } 614 615 616 /** 617 * Removes the assigned hardware breakpoint state from the given register breakpoint. 618 * 619 * @returns VBox status code. 620 * @param pVM The cross-context VM structure pointer. 621 * @param hBp The breakpoint handle to remove. 622 * @param pBp The internal breakpoint state. 623 * 624 * @thread Any thread. 625 */ 626 static int dbgfR3BpRegRemove(PVM pVM, DBGFBP hBp, PDBGFBPINT pBp) 627 { 628 AssertReturn(pBp->Pub.u.Reg.iReg < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints), VERR_DBGF_BP_IPE_3); 629 630 PDBGFBPHW pHwBp = &pVM->dbgf.s.aHwBreakpoints[pBp->Pub.u.Reg.iReg]; 631 AssertReturn(pHwBp->hBp == hBp, VERR_DBGF_BP_IPE_4); 632 AssertReturn(!pHwBp->fEnabled, VERR_DBGF_BP_IPE_5); 633 634 pHwBp->GCPtr = 0; 635 pHwBp->fType = 0; 636 pHwBp->cb = 0; 637 ASMCompilerBarrier(); 638 639 ASMAtomicWriteU32(&pHwBp->hBp, NIL_DBGFBP); 640 return VINF_SUCCESS; 641 } 642 643 644 /** 645 * @callback_method_impl{FNVMMEMTRENDEZVOUS} 646 */ 647 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpRegRecalcOnCpu(PVM pVM, PVMCPU pVCpu, void *pvUser) 648 { 649 RT_NOREF(pvUser); 650 651 /* 652 * CPU 0 updates the enabled hardware breakpoint counts. 653 */ 654 if (pVCpu->idCpu == 0) 655 { 656 pVM->dbgf.s.cEnabledHwBreakpoints = 0; 657 pVM->dbgf.s.cEnabledHwIoBreakpoints = 0; 658 659 for (uint32_t iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++) 660 { 661 if (pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled) 662 { 663 pVM->dbgf.s.cEnabledHwBreakpoints += 1; 664 pVM->dbgf.s.cEnabledHwIoBreakpoints += pVM->dbgf.s.aHwBreakpoints[iBp].fType == X86_DR7_RW_IO; 665 } 666 } 667 } 668 669 return CPUMRecalcHyperDRx(pVCpu, UINT8_MAX, false); 670 } 671 672 673 /** 674 * Arms the given breakpoint. 675 * 676 * @returns VBox status code. 677 * @param pUVM The user mode VM handle. 678 * @param hBp The breakpoint handle to arm. 679 * @param pBp The internal breakpoint state pointer for the handle. 680 */ 681 static int dbgfR3BpArm(PUVM pUVM, DBGFBP hBp, PDBGFBPINT pBp) 682 { 683 int rc = VINF_SUCCESS; 684 PVM pVM = pUVM->pVM; 685 686 Assert(!DBGF_BP_PUB_IS_ENABLED(pBp->Pub.fFlagsAndType)); 687 switch (DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType)) 688 { 689 case DBGFBPTYPE_REG: 690 { 691 Assert(pBp->Pub.u.Reg.iReg < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints)); 692 PDBGFBPHW pBpHw = &pVM->dbgf.s.aHwBreakpoints[pBp->Pub.u.Reg.iReg]; 693 Assert(pBpHw->hBp == hBp); RT_NOREF(hBp); 694 695 dbgfR3BpSetEnabled(pBp, true /*fEnabled*/); 696 ASMAtomicWriteBool(&pBpHw->fEnabled, true); 697 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL); 698 if (RT_FAILURE(rc)) 699 { 700 ASMAtomicWriteBool(&pBpHw->fEnabled, false); 701 dbgfR3BpSetEnabled(pBp, false /*fEnabled*/); 702 } 703 break; 704 } 705 case DBGFBPTYPE_INT3: 706 case DBGFBPTYPE_PORT_IO: 707 case DBGFBPTYPE_MMIO: 708 rc = VERR_NOT_IMPLEMENTED; 709 break; 710 default: 711 AssertMsgFailedReturn(("Invalid breakpoint type %d\n", DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType)), 712 VERR_IPE_NOT_REACHED_DEFAULT_CASE); 713 } 714 715 return rc; 716 } 717 718 719 /** 720 * Disarms the given breakpoint. 721 * 722 * @returns VBox status code. 723 * @param pUVM The user mode VM handle. 724 * @param hBp The breakpoint handle to disarm. 725 * @param pBp The internal breakpoint state pointer for the handle. 726 */ 727 static int dbgfR3BpDisarm(PUVM pUVM, DBGFBP hBp, PDBGFBPINT pBp) 728 { 729 int rc = VINF_SUCCESS; 730 PVM pVM = pUVM->pVM; 731 732 Assert(DBGF_BP_PUB_IS_ENABLED(pBp->Pub.fFlagsAndType)); 733 switch (DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType)) 734 { 735 case DBGFBPTYPE_REG: 736 { 737 Assert(pBp->Pub.u.Reg.iReg < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints)); 738 PDBGFBPHW pBpHw = &pVM->dbgf.s.aHwBreakpoints[pBp->Pub.u.Reg.iReg]; 739 Assert(pBpHw->hBp == hBp); RT_NOREF(hBp); 740 741 dbgfR3BpSetEnabled(pBp, false /*fEnabled*/); 742 ASMAtomicWriteBool(&pBpHw->fEnabled, false); 743 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpRegRecalcOnCpu, NULL); 744 if (RT_FAILURE(rc)) 745 { 746 ASMAtomicWriteBool(&pBpHw->fEnabled, true); 747 dbgfR3BpSetEnabled(pBp, true /*fEnabled*/); 748 } 749 break; 750 } 751 case DBGFBPTYPE_INT3: 752 case DBGFBPTYPE_PORT_IO: 753 case DBGFBPTYPE_MMIO: 754 rc = VERR_NOT_IMPLEMENTED; 755 break; 756 default: 757 AssertMsgFailedReturn(("Invalid breakpoint type %d\n", DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType)), 758 VERR_IPE_NOT_REACHED_DEFAULT_CASE); 759 } 760 761 return rc; 196 762 } 197 763 … … 285 851 { 286 852 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 287 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER);853 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser == NULL, VERR_INVALID_PARAMETER); 288 854 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); 289 855 AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER); 290 856 AssertPtrReturn(phBp, VERR_INVALID_POINTER); 291 857 292 RT_NOREF(idSrcCpu); 293 294 return VERR_NOT_IMPLEMENTED; 858 int rc = dbgfR3BpEnsureInit(pUVM); 859 AssertRCReturn(rc, rc); 860 861 DBGFBP hBp = NIL_DBGFBP; 862 PDBGFBPINT pBp = NULL; 863 rc = dbgfR3BpAlloc(pUVM, hOwner, pvUser, DBGFBPTYPE_INT3, iHitTrigger, iHitDisable, &hBp, &pBp); 864 if (RT_SUCCESS(rc)) 865 { 866 /* 867 * Translate & save the breakpoint address into a guest-physical address. 868 */ 869 rc = DBGFR3AddrToPhys(pUVM, idSrcCpu, pAddress, &pBp->Pub.u.Int3.PhysAddr); 870 if (RT_SUCCESS(rc)) 871 { 872 /* 873 * The physical address from DBGFR3AddrToPhys() is the start of the page, 874 * we need the exact byte offset into the page while writing to it in dbgfR3BpInt3Arm(). 875 */ 876 pBp->Pub.u.Int3.PhysAddr |= (pAddress->FlatPtr & X86_PAGE_OFFSET_MASK); 877 pBp->Pub.u.Int3.GCPtr = pAddress->FlatPtr; 878 879 /* Enable the breakpoint. */ 880 rc = dbgfR3BpArm(pUVM, hBp, pBp); 881 if (RT_SUCCESS(rc)) 882 { 883 *phBp = hBp; 884 return VINF_SUCCESS; 885 } 886 } 887 888 dbgfR3BpFree(pUVM, hBp, pBp); 889 } 890 891 return rc; 295 892 } 296 893 … … 345 942 { 346 943 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 347 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER);944 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser == NULL, VERR_INVALID_PARAMETER); 348 945 AssertReturn(DBGFR3AddrIsValid(pUVM, pAddress), VERR_INVALID_PARAMETER); 349 946 AssertReturn(iHitTrigger <= iHitDisable, VERR_INVALID_PARAMETER); … … 364 961 } 365 962 366 return VERR_NOT_IMPLEMENTED; 963 int rc = dbgfR3BpEnsureInit(pUVM); 964 AssertRCReturn(rc, rc); 965 966 PDBGFBPINT pBp = NULL; 967 DBGFBP hBp = dbgfR3BpGetByAddr(pUVM, DBGFBPTYPE_REG, pAddress->FlatPtr, &pBp); 968 if ( hBp != NIL_DBGFBP 969 && pBp->Pub.u.Reg.cb == cb 970 && pBp->Pub.u.Reg.fType == fType) 971 { 972 rc = VINF_SUCCESS; 973 if (!DBGF_BP_PUB_IS_ENABLED(pBp->Pub.fFlagsAndType)) 974 rc = dbgfR3BpArm(pUVM, hBp, pBp); 975 if (RT_SUCCESS(rc)) 976 { 977 rc = VINF_DBGF_BP_ALREADY_EXIST; 978 if (phBp) 979 *phBp = hBp; 980 } 981 return rc; 982 } 983 984 /* Allocate new breakpoint. */ 985 rc = dbgfR3BpAlloc(pUVM, hOwner, pvUser, DBGFBPTYPE_REG, iHitTrigger, iHitDisable, &hBp, &pBp); 986 if (RT_SUCCESS(rc)) 987 { 988 pBp->Pub.u.Reg.GCPtr = pAddress->FlatPtr; 989 pBp->Pub.u.Reg.fType = fType; 990 pBp->Pub.u.Reg.cb = cb; 991 pBp->Pub.u.Reg.iReg = UINT8_MAX; 992 ASMCompilerBarrier(); 993 994 /* Assign the proper hardware breakpoint. */ 995 rc = dbgfR3BpRegAssign(pUVM->pVM, hBp, pBp); 996 if (RT_SUCCESS(rc)) 997 { 998 /* Arm the breakpoint. */ 999 rc = dbgfR3BpArm(pUVM, hBp, pBp); 1000 if (RT_SUCCESS(rc)) 1001 { 1002 if (phBp) 1003 *phBp = hBp; 1004 return VINF_SUCCESS; 1005 } 1006 else 1007 { 1008 int rc2 = dbgfR3BpRegRemove(pUVM->pVM, hBp, pBp); 1009 AssertRC(rc2); RT_NOREF(rc2); 1010 } 1011 } 1012 1013 dbgfR3BpFree(pUVM, hBp, pBp); 1014 } 1015 1016 return rc; 367 1017 } 368 1018 … … 430 1080 { 431 1081 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 432 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER);1082 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser == NULL, VERR_INVALID_PARAMETER); 433 1083 AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_PORT_IO), VERR_INVALID_FLAGS); 434 1084 AssertReturn(fAccess, VERR_INVALID_FLAGS); … … 437 1087 AssertReturn(cPorts > 0, VERR_OUT_OF_RANGE); 438 1088 AssertReturn((RTIOPORT)(uPort + cPorts) < uPort, VERR_OUT_OF_RANGE); 1089 1090 int rc = dbgfR3BpEnsureInit(pUVM); 1091 AssertRCReturn(rc, rc); 439 1092 440 1093 return VERR_NOT_IMPLEMENTED; … … 491 1144 { 492 1145 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 493 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser != NULL, VERR_INVALID_PARAMETER);1146 AssertReturn(hOwner != NIL_DBGFBPOWNER || pvUser == NULL, VERR_INVALID_PARAMETER); 494 1147 AssertReturn(!(fAccess & ~DBGFBPIOACCESS_VALID_MASK_MMIO), VERR_INVALID_FLAGS); 495 1148 AssertReturn(fAccess, VERR_INVALID_FLAGS); … … 499 1152 AssertReturn(GCPhys + cb < GCPhys, VERR_OUT_OF_RANGE); 500 1153 1154 int rc = dbgfR3BpEnsureInit(pUVM); 1155 AssertRCReturn(rc, rc); 1156 501 1157 return VERR_NOT_IMPLEMENTED; 502 1158 } … … 517 1173 AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE); 518 1174 519 return VERR_NOT_IMPLEMENTED; 1175 PDBGFBPINT pBp = dbgfR3BpGetByHnd(pUVM, hBp); 1176 AssertPtrReturn(pBp, VERR_DBGF_BP_NOT_FOUND); 1177 1178 /* Disarm the breakpoint when it is enabled. */ 1179 if (DBGF_BP_PUB_IS_ENABLED(pBp->Pub.fFlagsAndType)) 1180 { 1181 int rc = dbgfR3BpDisarm(pUVM, hBp, pBp); 1182 AssertRC(rc); 1183 } 1184 1185 switch (DBGF_BP_PUB_GET_TYPE(pBp->Pub.fFlagsAndType)) 1186 { 1187 case DBGFBPTYPE_REG: 1188 { 1189 int rc = dbgfR3BpRegRemove(pUVM->pVM, hBp, pBp); 1190 AssertRC(rc); 1191 break; 1192 } 1193 default: 1194 break; 1195 } 1196 1197 dbgfR3BpFree(pUVM, hBp, pBp); 1198 return VINF_SUCCESS; 520 1199 } 521 1200 … … 531 1210 */ 532 1211 VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, DBGFBP hBp) 533 {534 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);535 AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE);536 537 return VERR_NOT_IMPLEMENTED;538 }539 540 541 /**542 * Disables a breakpoint.543 *544 * @returns VBox status code.545 * @param pUVM The user mode VM handle.546 * @param hBp The handle of the breakpoint which should be disabled.547 *548 * @thread Any thread.549 */550 VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp)551 1212 { 552 1213 /* … … 556 1217 AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE); 557 1218 558 return VERR_NOT_IMPLEMENTED; 1219 PDBGFBPINT pBp = dbgfR3BpGetByHnd(pUVM, hBp); 1220 AssertPtrReturn(pBp, VERR_DBGF_BP_NOT_FOUND); 1221 1222 int rc = VINF_SUCCESS; 1223 if (!DBGF_BP_PUB_IS_ENABLED(pBp->Pub.fFlagsAndType)) 1224 rc = dbgfR3BpArm(pUVM, hBp, pBp); 1225 else 1226 rc = VINF_DBGF_BP_ALREADY_ENABLED; 1227 1228 return rc; 1229 } 1230 1231 1232 /** 1233 * Disables a breakpoint. 1234 * 1235 * @returns VBox status code. 1236 * @param pUVM The user mode VM handle. 1237 * @param hBp The handle of the breakpoint which should be disabled. 1238 * 1239 * @thread Any thread. 1240 */ 1241 VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp) 1242 { 1243 /* 1244 * Validate the input. 1245 */ 1246 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE); 1247 AssertReturn(hBp != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE); 1248 1249 PDBGFBPINT pBp = dbgfR3BpGetByHnd(pUVM, hBp); 1250 AssertPtrReturn(pBp, VERR_DBGF_BP_NOT_FOUND); 1251 1252 int rc = VINF_SUCCESS; 1253 if (DBGF_BP_PUB_IS_ENABLED(pBp->Pub.fFlagsAndType)) 1254 rc = dbgfR3BpDisarm(pUVM, hBp, pBp); 1255 else 1256 rc = VINF_DBGF_BP_ALREADY_DISABLED; 1257 1258 return rc; 559 1259 } 560 1260 -
trunk/src/VBox/VMM/include/DBGFInternal.h
r86683 r86699 54 54 #define DBGF_TRACER_EVT_SZ (DBGF_TRACER_EVT_HDR_SZ + DBGF_TRACER_EVT_PAYLOAD_SZ) 55 55 56 57 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 58 /** @name Breakpoint handling defines. 59 * @{ */ 60 /** Maximum number of breakpoints supported (power of two). */ 61 #define DBGF_BP_COUNT_MAX _1M 62 /** Size of a single breakpoint structure in bytes. */ 63 #define DBGF_BP_ENTRY_SZ 64 64 /** Number of breakpoints handled in one chunk (power of two). */ 65 #define DBGF_BP_COUNT_PER_CHUNK _64K 66 /** Number of chunks required to support all breakpoints. */ 67 #define DBGF_BP_CHUNK_COUNT (DBGF_BP_COUNT_MAX / DBGF_BP_COUNT_PER_CHUNK) 68 /** @} */ 69 #endif 56 70 57 71 … … 763 777 typedef DBGFBPSEARCHOPT *PDBGFBPSEARCHOPT; 764 778 #else 779 780 /** An invalid breakpoint chunk ID. */ 781 #define DBGF_BP_CHUNK_ID_INVALID UINT32_MAX 782 /** Generates a unique breakpoint handle from the given chunk ID and entry inside the chunk. */ 783 #define DBGF_BP_HND_CREATE(a_idChunk, a_idEntry) RT_MAKE_U32(a_idEntry, a_idChunk); 784 /** Returns the chunk ID from the given breakpoint handle. */ 785 #define DBGF_BP_HND_GET_CHUNK_ID(a_hBp) ((uint32_t)RT_HI_U16(a_hBp)) 786 /** Returns the entry index inside a chunk from the given breakpoint handle. */ 787 #define DBGF_BP_HND_GET_ENTRY(a_hBp) ((uint32_t)RT_LO_U16(a_hBp)) 788 789 790 /** 791 * The internal breakpoint state, shared part. 792 */ 793 typedef struct DBGFBPINT 794 { 795 /** The publicly visible part. */ 796 DBGFBPPUB Pub; 797 /** The opaque user argument for the owner callback, Ring-3 Ptr. */ 798 R3PTRTYPE(void *) pvUserR3; 799 } DBGFBPINT; 800 AssertCompileSize(DBGFBPINT, DBGF_BP_ENTRY_SZ); 801 /** Pointer to an internal breakpoint state. */ 802 typedef DBGFBPINT *PDBGFBPINT; 803 /** Pointer to an const internal breakpoint state. */ 804 typedef const DBGFBPINT *PCDBGFBPINT; 805 806 807 /** 808 * The internal breakpoint state, R0 part. 809 */ 810 typedef struct DBGFBPINTR0 811 { 812 /** The owner handle. */ 813 DBGFBPOWNER hOwner; 814 /** Flag whether the breakpoint is in use. */ 815 bool fInUse; 816 /** Padding to 8 byte alignment. */ 817 bool afPad[3]; 818 /** Opaque user data for the owner callback, Ring-0 Ptr. */ 819 R0PTRTYPE(void *) pvUserR0; 820 } DBGFBPINTR0; 821 AssertCompileMemberAlignment(DBGFBPINTR0, pvUserR0, 8); 822 AssertCompileSize(DBGFBPINTR0, 16); 823 /** Pointer to an internal breakpoint state - Ring-0 Ptr. */ 824 typedef R0PTRTYPE(DBGFBPINTR0 *) PDBGFBPINTR0; 825 826 765 827 /** 766 828 * Hardware breakpoint state. … … 769 831 { 770 832 /** The flat GC address of the breakpoint. */ 771 RTGCUINTPTR GCPtr;772 /** The breakpoint handle if active, NIL_DBGFBP if disabled. */773 DBGFBPhBp;833 RTGCUINTPTR GCPtr; 834 /** The breakpoint handle if active, NIL_DBGFBP if not in use. */ 835 volatile DBGFBP hBp; 774 836 /** The access type (one of the X86_DR7_RW_* value). */ 775 uint8_t fType;837 uint8_t fType; 776 838 /** The access size. */ 777 uint8_t cb;839 uint8_t cb; 778 840 /** Flag whether the breakpoint is currently enabled. */ 779 boolfEnabled;841 volatile bool fEnabled; 780 842 /** Padding. */ 781 uint8_t bPad;843 uint8_t bPad; 782 844 } DBGFBPHW; 783 845 AssertCompileSize(DBGFBPHW, 16); … … 786 848 /** Pointer to a const hardware breakpoint state. */ 787 849 typedef const DBGFBPHW *PCDBGFBPHW; 850 851 852 /** 853 * A breakpoint table chunk, ring-3 state. 854 */ 855 typedef struct DBGFBPCHUNKR3 856 { 857 /** Pointer to the R3 base of the chunk. */ 858 R3PTRTYPE(PDBGFBPINT) pBpBaseR3; 859 /** Bitmap of free/occupied breakpoint entries. */ 860 R3PTRTYPE(volatile void *) pbmAlloc; 861 /** Number of free breakpoints in the chunk. */ 862 volatile uint32_t cBpsFree; 863 /** The chunk index this tracking structure refers to. */ 864 uint32_t idChunk; 865 } DBGFBPCHUNKR3; 866 /** Pointer to a breakpoint table chunk - Ring-3 Ptr. */ 867 typedef DBGFBPCHUNKR3 *PDBGFBPCHUNKR3; 868 /** Pointer to a const breakpoint table chunk - Ring-3 Ptr. */ 869 typedef const DBGFBPCHUNKR3 *PCDBGFBPCHUNKR3; 870 871 872 /** 873 * Breakpoint table chunk, ring-0 state. 874 */ 875 typedef struct DBGFBPCHUNKR0 876 { 877 /** The chunks memory. */ 878 RTR0MEMOBJ hMemObj; 879 /** The ring-3 mapping object. */ 880 RTR0MEMOBJ hMapObj; 881 /** Pointer to the breakpoint entries base. */ 882 R0PTRTYPE(PDBGFBPINT) paBpBaseSharedR0; 883 /** Pointer to the Ring-0 only part of the breakpoints. */ 884 PDBGFBPINTR0 paBpBaseR0Only; 885 } DBGFBPCHUNKR0; 886 /** Pointer to a breakpoint table chunk - Ring-0 Ptr. */ 887 typedef R0PTRTYPE(DBGFBPCHUNKR0 *) PDBGFBPCHUNKR0; 788 888 #endif 789 889 … … 875 975 DBGFBPSEARCHOPT Int3; 876 976 #else 977 /** @name Breakpoint handling related state. 978 * @{ */ 877 979 /** Array of hardware breakpoints (0..3). 878 980 * This is shared among all the CPUs because life is much simpler that way. */ 879 DBGFBPHW aHwBreakpoints[4]; 981 DBGFBPHW aHwBreakpoints[4]; 982 /** @} */ 880 983 #endif 881 984 … … 1017 1120 /** Pointer to the tracer instance if enabled. */ 1018 1121 R0PTRTYPE(struct DBGFTRACERINSR0 *) pTracerR0; 1122 1123 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 1124 /** @name Breakpoint handling related state, Ring-0 only part. 1125 * @{ */ 1126 /** Global breakpoint table chunk array. */ 1127 DBGFBPCHUNKR0 aBpChunks[DBGF_BP_CHUNK_COUNT]; 1128 /** The L1 lookup tables memory object. */ 1129 RTR0MEMOBJ hMemObjBpLocL1; 1130 /** The L1 lookup tables mapping object. */ 1131 RTR0MEMOBJ hMapObjBpLocL1; 1132 /** Base pointer to the L1 locator table. */ 1133 R0PTRTYPE(volatile uint32_t *) paBpLocL1R0; 1134 /** Flag whether the breakpoint manager was initialized (on demand). */ 1135 bool fInit; 1136 /** @} */ 1137 #endif 1019 1138 } DBGFR0PERVM; 1020 1139 … … 1091 1210 /** @} */ 1092 1211 1212 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 1213 /** @name Breakpoint handling related state. 1214 * @{ */ 1215 /** Global breakpoint table chunk array. */ 1216 DBGFBPCHUNKR3 aBpChunks[DBGF_BP_CHUNK_COUNT]; 1217 /** Base pointer to the L1 locator table. */ 1218 R3PTRTYPE(volatile uint32_t *) paBpLocL1R3; 1219 /** @} */ 1220 #endif 1221 1093 1222 /** The type database lock. */ 1094 1223 RTSEMRW hTypeDbLock; … … 1138 1267 void dbgfR3AsRelocate(PUVM pUVM, RTGCUINTPTR offDelta); 1139 1268 #ifdef VBOX_WITH_LOTS_OF_DBGF_BPS 1140 DECLHIDDEN(int) dbgfR3BpInit(P VM pVM);1141 DECLHIDDEN(int) dbgfR3BpTerm(P VM pVM);1269 DECLHIDDEN(int) dbgfR3BpInit(PUVM pUVM); 1270 DECLHIDDEN(int) dbgfR3BpTerm(PUVM pUVM); 1142 1271 #else 1143 1272 int dbgfR3BpInit(PVM pVM); … … 1188 1317 #ifdef IN_RING0 1189 1318 DECLHIDDEN(void) dbgfR0TracerDestroy(PGVM pGVM, PDBGFTRACERINSR0 pTracer); 1319 DECLHIDDEN(void) dbgfR0BpInit(PGVM pGVM); 1320 DECLHIDDEN(void) dbgfR0BpDestroy(PGVM pGVM); 1190 1321 #endif /* !IN_RING0 */ 1191 1322
Note:
See TracChangeset
for help on using the changeset viewer.