Changeset 86704 in vbox for trunk/src/VBox/VMM/VMMR3
- Timestamp:
- Oct 26, 2020 12:04:05 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 141088
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/DBGFR3Bp.cpp
r86701 r86704 201 201 } 202 202 203 for (uint32_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.aBpL2TblChunks); i++) 204 { 205 PDBGFBPL2TBLCHUNKR3 pL2Chunk = &pUVM->dbgf.s.aBpL2TblChunks[i]; 206 207 //pL2Chunk->pL2BaseR3 = NULL; 208 //pL2Chunk->pbmAlloc = NULL; 209 //pL2Chunk->cFree = 0; 210 pL2Chunk->idChunk = DBGF_BP_CHUNK_ID_INVALID; /* Not allocated. */ 211 } 212 203 213 //pUVM->dbgf.s.paBpLocL1R3 = NULL; 204 return VINF_SUCCESS; 214 pUVM->dbgf.s.hMtxBpL2Wr = NIL_RTSEMFASTMUTEX; 215 return RTSemFastMutexCreate(&pUVM->dbgf.s.hMtxBpL2Wr); 205 216 } 206 217 … … 226 237 pBpChunk->idChunk = DBGF_BP_CHUNK_ID_INVALID; 227 238 } 239 } 240 241 for (uint32_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.aBpL2TblChunks); i++) 242 { 243 PDBGFBPL2TBLCHUNKR3 pL2Chunk = &pUVM->dbgf.s.aBpL2TblChunks[i]; 244 245 if (pL2Chunk->idChunk != DBGF_BP_CHUNK_ID_INVALID) 246 { 247 AssertPtr(pL2Chunk->pbmAlloc); 248 RTMemFree((void *)pL2Chunk->pbmAlloc); 249 pL2Chunk->pbmAlloc = NULL; 250 pL2Chunk->idChunk = DBGF_BP_CHUNK_ID_INVALID; 251 } 252 } 253 254 if (pUVM->dbgf.s.hMtxBpL2Wr != NIL_RTSEMFASTMUTEX) 255 { 256 RTSemFastMutexDestroy(pUVM->dbgf.s.hMtxBpL2Wr); 257 pUVM->dbgf.s.hMtxBpL2Wr = NIL_RTSEMFASTMUTEX; 228 258 } 229 259 … … 563 593 564 594 /** 595 * @callback_method_impl{FNVMMEMTRENDEZVOUS} 596 */ 597 static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpL2TblChunkAllocEmtWorker(PVM pVM, PVMCPU pVCpu, void *pvUser) 598 { 599 uint32_t idChunk = (uint32_t)(uintptr_t)pvUser; 600 601 VMCPU_ASSERT_EMT(pVCpu); 602 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); 603 604 AssertReturn(idChunk < DBGF_BP_L2_TBL_CHUNK_COUNT, VERR_DBGF_BP_IPE_1); 605 606 PUVM pUVM = pVM->pUVM; 607 PDBGFBPL2TBLCHUNKR3 pL2Chunk = &pUVM->dbgf.s.aBpL2TblChunks[idChunk]; 608 609 AssertReturn( pL2Chunk->idChunk == DBGF_BP_L2_IDX_CHUNK_ID_INVALID 610 || pL2Chunk->idChunk == idChunk, 611 VERR_DBGF_BP_IPE_2); 612 613 /* 614 * The initialization will be done on EMT(0). It is possible that multiple 615 * allocation attempts are done when multiple racing non EMT threads try to 616 * allocate a breakpoint and a new chunk needs to be allocated. 617 * Ignore the request and succeed if the chunk is allocated meaning that a 618 * previous rendezvous successfully allocated the chunk. 619 */ 620 int rc = VINF_SUCCESS; 621 if ( pVCpu->idCpu == 0 622 && pL2Chunk->idChunk == DBGF_BP_L2_IDX_CHUNK_ID_INVALID) 623 { 624 /* Allocate the bitmap first so we can skip calling into VMMR0 if it fails. */ 625 AssertCompile(!(DBGF_BP_L2_TBL_ENTRIES_PER_CHUNK % 8)); 626 volatile void *pbmAlloc = RTMemAllocZ(DBGF_BP_L2_TBL_ENTRIES_PER_CHUNK / 8); 627 if (RT_LIKELY(pbmAlloc)) 628 { 629 DBGFBPL2TBLCHUNKALLOCREQ Req; 630 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; 631 Req.Hdr.cbReq = sizeof(Req); 632 Req.idChunk = idChunk; 633 Req.pChunkBaseR3 = NULL; 634 rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_DBGF_BP_L2_TBL_CHUNK_ALLOC, 0 /*u64Arg*/, &Req.Hdr); 635 AssertLogRelMsgRC(rc, ("VMMR0_DO_DBGF_BP_L2_TBL_CHUNK_ALLOC failed: %Rrc\n", rc)); 636 if (RT_SUCCESS(rc)) 637 { 638 pL2Chunk->pL2BaseR3 = (PDBGFBPL2ENTRY)Req.pChunkBaseR3; 639 pL2Chunk->pbmAlloc = pbmAlloc; 640 pL2Chunk->cFree = DBGF_BP_L2_TBL_ENTRIES_PER_CHUNK; 641 pL2Chunk->idChunk = idChunk; 642 return VINF_SUCCESS; 643 } 644 645 RTMemFree((void *)pbmAlloc); 646 } 647 else 648 rc = VERR_NO_MEMORY; 649 } 650 651 return rc; 652 } 653 654 655 /** 656 * Tries to allocate the given L2 table chunk which requires an EMT rendezvous. 657 * 658 * @returns VBox status code. 659 * @param pUVM The user mode VM handle. 660 * @param idChunk The chunk to allocate. 661 * 662 * @thread Any thread. 663 */ 664 DECLINLINE(int) dbgfR3BpL2TblChunkAlloc(PUVM pUVM, uint32_t idChunk) 665 { 666 return VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpL2TblChunkAllocEmtWorker, (void *)(uintptr_t)idChunk); 667 } 668 669 670 /** 671 * Tries to allocate a new breakpoint of the given type. 672 * 673 * @returns VBox status code. 674 * @param pUVM The user mode VM handle. 675 * @param pidxL2Tbl Where to return the L2 table entry index on success. 676 * @param ppL2TblEntry Where to return the pointer to the L2 table entry on success. 677 * 678 * @thread Any thread. 679 */ 680 static int dbgfR3BpL2TblEntryAlloc(PUVM pUVM, uint32_t *pidxL2Tbl, PDBGFBPL2ENTRY *ppL2TblEntry) 681 { 682 /* 683 * Search for a chunk having a free entry, allocating new chunks 684 * if the encountered ones are full. 685 * 686 * This can be called from multiple threads at the same time so special care 687 * has to be taken to not require any locking here. 688 */ 689 for (uint32_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.aBpL2TblChunks); i++) 690 { 691 PDBGFBPL2TBLCHUNKR3 pL2Chunk = &pUVM->dbgf.s.aBpL2TblChunks[i]; 692 693 uint32_t idChunk = ASMAtomicReadU32(&pL2Chunk->idChunk); 694 if (idChunk == DBGF_BP_L2_IDX_CHUNK_ID_INVALID) 695 { 696 int rc = dbgfR3BpL2TblChunkAlloc(pUVM, i); 697 if (RT_FAILURE(rc)) 698 { 699 LogRel(("DBGF/Bp: Allocating new breakpoint L2 lookup table chunk failed with %Rrc\n", rc)); 700 break; 701 } 702 703 idChunk = ASMAtomicReadU32(&pL2Chunk->idChunk); 704 Assert(idChunk == i); 705 } 706 707 /** @todo Optimize with some hinting if this turns out to be too slow. */ 708 for (;;) 709 { 710 uint32_t cFree = ASMAtomicReadU32(&pL2Chunk->cFree); 711 if (cFree) 712 { 713 /* 714 * Scan the associated bitmap for a free entry, if none can be found another thread 715 * raced us and we go to the next chunk. 716 */ 717 int32_t iClr = ASMBitFirstClear(pL2Chunk->pbmAlloc, DBGF_BP_L2_TBL_ENTRIES_PER_CHUNK); 718 if (iClr != -1) 719 { 720 /* 721 * Try to allocate, we could get raced here as well. In that case 722 * we try again. 723 */ 724 if (!ASMAtomicBitTestAndSet(pL2Chunk->pbmAlloc, iClr)) 725 { 726 /* Success, immediately mark as allocated, initialize the breakpoint state and return. */ 727 ASMAtomicDecU32(&pL2Chunk->cFree); 728 729 PDBGFBPL2ENTRY pL2Entry = &pL2Chunk->pL2BaseR3[iClr]; 730 731 *pidxL2Tbl = DBGF_BP_L2_IDX_CREATE(idChunk, iClr); 732 *ppL2TblEntry = pL2Entry; 733 return VINF_SUCCESS; 734 } 735 /* else Retry with another spot. */ 736 } 737 else /* no free entry in bitmap, go to the next chunk */ 738 break; 739 } 740 else /* !cFree, go to the next chunk */ 741 break; 742 } 743 } 744 745 return VERR_DBGF_NO_MORE_BP_SLOTS; 746 } 747 748 749 /** 750 * Frees the given breakpoint handle. 751 * 752 * @returns nothing. 753 * @param pUVM The user mode VM handle. 754 * @param idxL2Tbl The L2 table index to free. 755 * @param pL2TblEntry The L2 table entry pointer to free. 756 */ 757 static void dbgfR3BpL2TblEntryFree(PUVM pUVM, uint32_t idxL2Tbl, PDBGFBPL2ENTRY pL2TblEntry) 758 { 759 uint32_t idChunk = DBGF_BP_L2_IDX_GET_CHUNK_ID(idxL2Tbl); 760 uint32_t idxEntry = DBGF_BP_L2_IDX_GET_ENTRY(idxL2Tbl); 761 762 AssertReturnVoid(idChunk < DBGF_BP_L2_TBL_CHUNK_COUNT); 763 AssertReturnVoid(idxEntry < DBGF_BP_L2_TBL_ENTRIES_PER_CHUNK); 764 765 PDBGFBPL2TBLCHUNKR3 pL2Chunk = &pUVM->dbgf.s.aBpL2TblChunks[idChunk]; 766 AssertPtrReturnVoid(pL2Chunk->pbmAlloc); 767 AssertReturnVoid(ASMBitTest(pL2Chunk->pbmAlloc, idxEntry)); 768 769 memset(pL2TblEntry, 0, sizeof(*pL2TblEntry)); 770 771 ASMAtomicBitClear(pL2Chunk->pbmAlloc, idxEntry); 772 ASMAtomicIncU32(&pL2Chunk->cFree); 773 } 774 775 776 /** 565 777 * Sets the enabled flag of the given breakpoint to the given value. 566 778 * … … 881 1093 case DBGFBPTYPE_INT3: 882 1094 { 883 dbgfR3BpSetEnabled(pBp, false /*fEnabled*/);884 885 1095 /* 886 1096 * Check that the current byte is the int3 instruction, and restore the original one. … … 896 1106 { 897 1107 ASMAtomicDecU32(&pVM->dbgf.s.cEnabledInt3Breakpoints); 1108 dbgfR3BpSetEnabled(pBp, false /*fEnabled*/); 898 1109 Log(("DBGF: Removed breakpoint at %RGv (Phys %RGp)\n", pBp->Pub.u.Int3.GCPtr, pBp->Pub.u.Int3.PhysAddr)); 899 1110 } 900 1111 } 901 902 if (RT_FAILURE(rc))903 dbgfR3BpSetEnabled(pBp, true /*fEnabled*/);904 905 1112 break; 906 1113 }
Note:
See TracChangeset
for help on using the changeset viewer.