VirtualBox

Changeset 86704 in vbox for trunk/src/VBox/VMM/VMMR3


Ignore:
Timestamp:
Oct 26, 2020 12:04:05 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
141088
Message:

VMM/DBGF: Updates to the new breakpoint manager, L2 table management groundwork, bugref:9837

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/DBGFR3Bp.cpp

    r86701 r86704  
    201201    }
    202202
     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
    203213    //pUVM->dbgf.s.paBpLocL1R3 = NULL;
    204     return VINF_SUCCESS;
     214    pUVM->dbgf.s.hMtxBpL2Wr = NIL_RTSEMFASTMUTEX;
     215    return RTSemFastMutexCreate(&pUVM->dbgf.s.hMtxBpL2Wr);
    205216}
    206217
     
    226237            pBpChunk->idChunk = DBGF_BP_CHUNK_ID_INVALID;
    227238        }
     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;
    228258    }
    229259
     
    563593
    564594/**
     595 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
     596 */
     597static 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 */
     664DECLINLINE(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 */
     680static 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 */
     757static 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/**
    565777 * Sets the enabled flag of the given breakpoint to the given value.
    566778 *
     
    8811093        case DBGFBPTYPE_INT3:
    8821094        {
    883             dbgfR3BpSetEnabled(pBp, false /*fEnabled*/);
    884 
    8851095            /*
    8861096             * Check that the current byte is the int3 instruction, and restore the original one.
     
    8961106                {
    8971107                    ASMAtomicDecU32(&pVM->dbgf.s.cEnabledInt3Breakpoints);
     1108                    dbgfR3BpSetEnabled(pBp, false /*fEnabled*/);
    8981109                    Log(("DBGF: Removed breakpoint at %RGv (Phys %RGp)\n", pBp->Pub.u.Int3.GCPtr, pBp->Pub.u.Int3.PhysAddr));
    8991110                }
    9001111            }
    901 
    902             if (RT_FAILURE(rc))
    903                 dbgfR3BpSetEnabled(pBp, true /*fEnabled*/);
    904 
    9051112            break;
    9061113        }
Note: See TracChangeset for help on using the changeset viewer.

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