VirtualBox

Changeset 87107 in vbox for trunk/src


Ignore:
Timestamp:
Dec 19, 2020 3:10:18 PM (4 years ago)
Author:
vboxsync
Message:

VMM/DBGF: Started implementing the breakpoint owner management, bugref:9837

Location:
trunk/src/VBox/VMM
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/DBGFR0Bp.cpp

    r86704 r87107  
    5252DECLHIDDEN(void) dbgfR0BpInit(PGVM pGVM)
    5353{
     54    pGVM->dbgfr0.s.hMemObjBpOwners = NIL_RTR0MEMOBJ;
     55    pGVM->dbgfr0.s.hMapObjBpOwners = NIL_RTR0MEMOBJ;
     56    //pGVM->dbgfr0.s.paBpOwnersR0    = NULL;
     57
    5458    for (uint32_t i = 0; i < RT_ELEMENTS(pGVM->dbgfr0.s.aBpChunks); i++)
    5559    {
     
    8791DECLHIDDEN(void) dbgfR0BpDestroy(PGVM pGVM)
    8892{
     93    if (pGVM->dbgfr0.s.hMemObjBpOwners != NIL_RTR0MEMOBJ)
     94    {
     95        Assert(pGVM->dbgfr0.s.hMapObjBpOwners != NIL_RTR0MEMOBJ);
     96        AssertPtr(pGVM->dbgfr0.s.paBpOwnersR0);
     97
     98        RTR0MEMOBJ hMemObj = pGVM->dbgfr0.s.hMapObjBpOwners;
     99        pGVM->dbgfr0.s.hMapObjBpOwners = NIL_RTR0MEMOBJ;
     100        RTR0MemObjFree(hMemObj, true);
     101
     102        hMemObj = pGVM->dbgfr0.s.hMemObjBpOwners;
     103        pGVM->dbgfr0.s.hMemObjBpOwners = NIL_RTR0MEMOBJ;
     104        RTR0MemObjFree(hMemObj, true);
     105    }
     106
    89107    if (pGVM->dbgfr0.s.fInit)
    90108    {
     
    208226        *ppaBpLocL1R3 = RTR0MemObjAddressR3(hMapObj);
    209227        pGVM->dbgfr0.s.fInit = true;
     228        return rc;
     229    }
     230
     231    RTR0MemObjFree(hMemObj, true);
     232    return rc;
     233}
     234
     235
     236/**
     237 * Worker for DBGFR0BpOwnerInitReqHandler() that does the actual initialization.
     238 *
     239 * @returns VBox status code.
     240 * @param   pGVM            The global (ring-0) VM structure.
     241 * @param   ppaBpOwnerR3    Where to return the ring-3 breakpoint owner table base address on success.
     242 * @thread  EMT(0)
     243 */
     244static int dbgfR0BpOwnerInitWorker(PGVM pGVM, R3PTRTYPE(void *) *ppaBpOwnerR3)
     245{
     246    /*
     247     * Figure out how much memory we need for the L1 lookup table and allocate it.
     248     */
     249    uint32_t const cbBpOwnerR0 = RT_ALIGN_32(DBGF_BP_OWNER_COUNT_MAX * sizeof(DBGFBPOWNERINTR0), PAGE_SIZE);
     250    uint32_t const cbBpOwnerR3 = RT_ALIGN_32(DBGF_BP_OWNER_COUNT_MAX * sizeof(DBGFBPOWNERINT), PAGE_SIZE);
     251    uint32_t const cbTotal     = RT_ALIGN_32(cbBpOwnerR0 + cbBpOwnerR3, PAGE_SIZE);
     252
     253    RTR0MEMOBJ hMemObj;
     254    int rc = RTR0MemObjAllocPage(&hMemObj, cbTotal, false /*fExecutable*/);
     255    if (RT_FAILURE(rc))
     256        return rc;
     257    RT_BZERO(RTR0MemObjAddress(hMemObj), cbTotal);
     258
     259    /* Map it. */
     260    RTR0MEMOBJ hMapObj;
     261    rc = RTR0MemObjMapUserEx(&hMapObj, hMemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, RTR0ProcHandleSelf(),
     262                             cbBpOwnerR0 /*offSub*/, cbBpOwnerR3);
     263    if (RT_SUCCESS(rc))
     264    {
     265        pGVM->dbgfr0.s.hMemObjBpOwners = hMemObj;
     266        pGVM->dbgfr0.s.hMapObjBpOwners = hMapObj;
     267        pGVM->dbgfr0.s.paBpOwnersR0    = (PDBGFBPOWNERINTR0)RTR0MemObjAddress(hMemObj);
     268
     269        /*
     270         * We're done.
     271         */
     272        *ppaBpOwnerR3 = RTR0MemObjAddressR3(hMapObj);
    210273        return rc;
    211274    }
     
    349412
    350413/**
    351  * Used by ring-3 DBGF to allocate a given chunk in the global breakpoint table.
     414 * Used by ring-3 DBGF to initialize the breakpoint owner table for operation.
    352415 *
    353416 * @returns VBox status code.
     
    356419 * @thread  EMT(0)
    357420 */
     421VMMR0_INT_DECL(int) DBGFR0BpOwnerInitReqHandler(PGVM pGVM, PDBGFBPOWNERINITREQ pReq)
     422{
     423    LogFlow(("DBGFR0BpOwnerInitReqHandler:\n"));
     424
     425    /*
     426     * Validate the request.
     427     */
     428    AssertReturn(pReq->Hdr.cbReq == sizeof(*pReq), VERR_INVALID_PARAMETER);
     429
     430    int rc = GVMMR0ValidateGVMandEMT(pGVM, 0);
     431    AssertRCReturn(rc, rc);
     432
     433    AssertReturn(!pGVM->dbgfr0.s.paBpOwnersR0, VERR_WRONG_ORDER);
     434
     435    return dbgfR0BpOwnerInitWorker(pGVM, &pReq->paBpOwnerR3);
     436}
     437
     438
     439/**
     440 * Used by ring-3 DBGF to allocate a given chunk in the global breakpoint table.
     441 *
     442 * @returns VBox status code.
     443 * @param   pGVM    The global (ring-0) VM structure.
     444 * @param   pReq    Pointer to the request buffer.
     445 * @thread  EMT(0)
     446 */
    358447VMMR0_INT_DECL(int) DBGFR0BpChunkAllocReqHandler(PGVM pGVM, PDBGFBPCHUNKALLOCREQ pReq)
    359448{
  • trunk/src/VBox/VMM/VMMR0/VMMR0.cpp

    r86704 r87107  
    22962296            break;
    22972297        }
     2298
     2299        case VMMR0_DO_DBGF_BP_OWNER_INIT:
     2300        {
     2301            if (!pReqHdr || u64Arg || idCpu != 0)
     2302                return VERR_INVALID_PARAMETER;
     2303            rc = DBGFR0BpOwnerInitReqHandler(pGVM, (PDBGFBPOWNERINITREQ)pReqHdr);
     2304            VMM_CHECK_SMAP_CHECK2(pGVM, RT_NOTHING);
     2305            break;
     2306        }
    22982307#endif
    22992308
  • trunk/src/VBox/VMM/VMMR3/DBGFR3Bp.cpp

    r86754 r87107  
    182182    PVM pVM = pUVM->pVM;
    183183
     184    //pUVM->dbgf.s.paBpOwnersR3       = NULL;
     185    //pUVM->dbgf.s.pbmBpOwnersAllocR3 = NULL;
     186
    184187    /* Init hardware breakpoint states. */
    185188    for (uint32_t i = 0; i < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); i++)
     
    227230DECLHIDDEN(int) dbgfR3BpTerm(PUVM pUVM)
    228231{
     232    if (pUVM->dbgf.s.pbmBpOwnersAllocR3)
     233    {
     234        RTMemFree((void *)pUVM->dbgf.s.pbmBpOwnersAllocR3);
     235        pUVM->dbgf.s.pbmBpOwnersAllocR3 = NULL;
     236    }
     237
    229238    /* Free all allocated chunk bitmaps (the chunks itself are destroyed during ring-0 VM destruction). */
    230239    for (uint32_t i = 0; i < RT_ELEMENTS(pUVM->dbgf.s.aBpChunks); i++)
     
    314323    /* Gather all EMTs and call into ring-0 to initialize the breakpoint manager. */
    315324    return VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpInitEmtWorker, NULL /*pvUser*/);
     325}
     326
     327
     328/**
     329 * @callback_method_impl{FNVMMEMTRENDEZVOUS}
     330 */
     331static DECLCALLBACK(VBOXSTRICTRC) dbgfR3BpOwnerInitEmtWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
     332{
     333    RT_NOREF(pvUser);
     334
     335    VMCPU_ASSERT_EMT(pVCpu);
     336    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
     337
     338    /*
     339     * The initialization will be done on EMT(0). It is possible that multiple
     340     * initialization attempts are done because dbgfR3BpOwnerEnsureInit() can be called
     341     * from racing non EMT threads when trying to create a breakpoint owner for the first time.
     342     * Just fake success if the pointers are initialized already, meaning that a previous rendezvous
     343     * successfully initialized the breakpoint owner table.
     344     */
     345    int rc = VINF_SUCCESS;
     346    PUVM pUVM = pVM->pUVM;
     347    if (   pVCpu->idCpu == 0
     348        && !pUVM->dbgf.s.pbmBpOwnersAllocR3)
     349    {
     350        pUVM->dbgf.s.pbmBpOwnersAllocR3 = (volatile void *)RTMemAllocZ(DBGF_BP_OWNER_COUNT_MAX / 8);
     351        if (pUVM->dbgf.s.pbmBpOwnersAllocR3)
     352        {
     353            DBGFBPOWNERINITREQ Req;
     354            Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
     355            Req.Hdr.cbReq    = sizeof(Req);
     356            Req.paBpOwnerR3  = NULL;
     357            rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_DBGF_BP_OWNER_INIT, 0 /*u64Arg*/, &Req.Hdr);
     358            AssertLogRelMsgRC(rc, ("VMMR0_DO_DBGF_BP_OWNER_INIT failed: %Rrc\n", rc));
     359            if (RT_SUCCESS(rc))
     360            {
     361                pUVM->dbgf.s.paBpOwnersR3 = (PDBGFBPOWNERINT)Req.paBpOwnerR3;
     362                return VINF_SUCCESS;
     363            }
     364
     365            RTMemFree((void *)pUVM->dbgf.s.pbmBpOwnersAllocR3);
     366            pUVM->dbgf.s.pbmBpOwnersAllocR3 = NULL;
     367        }
     368        else
     369            rc = VERR_NO_MEMORY;
     370    }
     371
     372    return rc;
     373}
     374
     375
     376/**
     377 * Ensures that the breakpoint manager is fully initialized.
     378 *
     379 * @returns VBox status code.
     380 * @param   pUVM                The user mode VM handle.
     381 *
     382 * @thread Any thread.
     383 */
     384static int dbgfR3BpOwnerEnsureInit(PUVM pUVM)
     385{
     386    /* If the allocation bitmap is allocated initialization succeeded before. */
     387    if (RT_LIKELY(pUVM->dbgf.s.pbmBpOwnersAllocR3))
     388        return VINF_SUCCESS;
     389
     390    /* Gather all EMTs and call into ring-0 to initialize the breakpoint manager. */
     391    return VMMR3EmtRendezvous(pUVM->pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3BpOwnerInitEmtWorker, NULL /*pvUser*/);
     392}
     393
     394
     395/**
     396 * Returns the internal breakpoint owner state for the given handle.
     397 *
     398 * @returns Pointer to the internal breakpoint owner state or NULL if the handle is invalid.
     399 * @param   pUVM                The user mode VM handle.
     400 * @param   hBpOwner            The breakpoint owner handle to resolve.
     401 */
     402DECLINLINE(PDBGFBPOWNERINT) dbgfR3BpOwnerGetByHnd(PUVM pUVM, DBGFBPOWNER hBpOwner)
     403{
     404    AssertReturn(hBpOwner < DBGF_BP_OWNER_COUNT_MAX, NULL);
     405    AssertPtrReturn(pUVM->dbgf.s.pbmBpOwnersAllocR3, NULL);
     406
     407    AssertReturn(ASMBitTest(pUVM->dbgf.s.pbmBpOwnersAllocR3, hBpOwner), NULL);
     408    return &pUVM->dbgf.s.paBpOwnersR3[hBpOwner];
     409}
     410
     411
     412/**
     413 * Retains the given breakpoint owner handle for use.
     414 *
     415 * @returns VBox status code.
     416 * @retval VERR_INVALID_HANDLE if the given breakpoint owner handle is invalid.
     417 * @param   pUVM                The user mode VM handle.
     418 * @param   hBpOwner            The breakpoint owner handle to retain, NIL_DBGFOWNER is accepted without doing anything.
     419 */
     420DECLINLINE(int) dbgfR3BpOwnerRetain(PUVM pUVM, DBGFBPOWNER hBpOwner)
     421{
     422    if (hBpOwner == NIL_DBGFBPOWNER)
     423        return VINF_SUCCESS;
     424
     425    PDBGFBPOWNERINT pBpOwner = dbgfR3BpOwnerGetByHnd(pUVM, hBpOwner);
     426    if (pBpOwner)
     427    {
     428        ASMAtomicIncU32(&pBpOwner->cRefs);
     429        return VINF_SUCCESS;
     430    }
     431
     432    return VERR_INVALID_HANDLE;
     433}
     434
     435
     436/**
     437 * Releases the given breakpoint owner handle.
     438 *
     439 * @returns VBox status code.
     440 * @retval VERR_INVALID_HANDLE if the given breakpoint owner handle is invalid.
     441 * @param   pUVM                The user mode VM handle.
     442 * @param   hBpOwner            The breakpoint owner handle to retain, NIL_DBGFOWNER is accepted without doing anything.
     443 */
     444DECLINLINE(int) dbgfR3BpOwnerRelease(PUVM pUVM, DBGFBPOWNER hBpOwner)
     445{
     446    if (hBpOwner == NIL_DBGFBPOWNER)
     447        return VINF_SUCCESS;
     448
     449    PDBGFBPOWNERINT pBpOwner = dbgfR3BpOwnerGetByHnd(pUVM, hBpOwner);
     450    if (pBpOwner)
     451    {
     452        Assert(pBpOwner->cRefs > 1);
     453        ASMAtomicDecU32(&pBpOwner->cRefs);
     454        return VINF_SUCCESS;
     455    }
     456
     457    return VERR_INVALID_HANDLE;
    316458}
    317459
     
    438580                         PDBGFBPINT *ppBp)
    439581{
     582    int rc = dbgfR3BpOwnerRetain(pUVM, hOwner);
     583    if (RT_FAILURE(rc))
     584        return rc;
     585
    440586    /*
    441587     * Search for a chunk having a free entry, allocating new chunks
     
    452598        if (idChunk == DBGF_BP_CHUNK_ID_INVALID)
    453599        {
    454             int rc = dbgfR3BpChunkAlloc(pUVM, i);
     600            rc = dbgfR3BpChunkAlloc(pUVM, i);
    455601            if (RT_FAILURE(rc))
    456602            {
     
    509655    }
    510656
     657    rc = dbgfR3BpOwnerRelease(pUVM, hOwner); AssertRC(rc);
    511658    return VERR_DBGF_NO_MORE_BP_SLOTS;
    512659}
     
    534681
    535682    /** @todo Need a trip to Ring-0 if an owner is assigned with a Ring-0 part to clear the breakpoint. */
    536     /** @todo Release owner. */
     683    int rc = dbgfR3BpOwnerRelease(pUVM, pBp->Pub.hOwner); AssertRC(rc); RT_NOREF(rc);
    537684    memset(pBp, 0, sizeof(*pBp));
    538685
     
    15491696 *
    15501697 * @returns VBox status code.
     1698 * @retval  VERR_DBGF_BP_OWNER_NO_MORE_HANDLES if there are no more free owner handles available.
    15511699 * @param   pUVM                The user mode VM handle.
    15521700 * @param   pfnBpHit            The R3 callback which is called when a breakpoint with the owner handle is hit.
    15531701 * @param   phBpOwner           Where to store the owner handle on success.
     1702 *
     1703 * @thread Any thread but might defer work to EMT on the first call.
    15541704 */
    15551705VMMR3DECL(int) DBGFR3BpOwnerCreate(PUVM pUVM, PFNDBGFBPHIT pfnBpHit, PDBGFBPOWNER phBpOwner)
     
    15621712    AssertPtrReturn(phBpOwner, VERR_INVALID_POINTER);
    15631713
    1564     return VERR_NOT_IMPLEMENTED;
     1714    int rc = dbgfR3BpOwnerEnsureInit(pUVM);
     1715    AssertRCReturn(rc ,rc);
     1716
     1717    /* Try to find a free entry in the owner table. */
     1718    for (;;)
     1719    {
     1720        /* Scan the associated bitmap for a free entry. */
     1721        int32_t iClr = ASMBitFirstClear(pUVM->dbgf.s.pbmBpOwnersAllocR3, DBGF_BP_OWNER_COUNT_MAX);
     1722        if (iClr != -1)
     1723        {
     1724            /*
     1725             * Try to allocate, we could get raced here as well. In that case
     1726             * we try again.
     1727             */
     1728            if (!ASMAtomicBitTestAndSet(pUVM->dbgf.s.pbmBpOwnersAllocR3, iClr))
     1729            {
     1730                PDBGFBPOWNERINT pBpOwner = &pUVM->dbgf.s.paBpOwnersR3[iClr];
     1731                pBpOwner->cRefs      = 1;
     1732                pBpOwner->pfnBpHitR3 = pfnBpHit;
     1733
     1734                *phBpOwner = (DBGFBPOWNER)iClr;
     1735                return VINF_SUCCESS;
     1736            }
     1737            /* else Retry with another spot. */
     1738        }
     1739        else /* no free entry in bitmap, out of entries. */
     1740        {
     1741            rc = VERR_DBGF_BP_OWNER_NO_MORE_HANDLES;
     1742            break;
     1743        }
     1744    }
     1745
     1746    return rc;
    15651747}
    15661748
     
    15701752 *
    15711753 * @returns VBox status code.
     1754 * @retval  VERR_INVALID_HANDLE if the given owner handle is invalid.
    15721755 * @retval  VERR_DBGF_OWNER_BUSY if there are still breakpoints set with the given owner handle.
    15731756 * @param   pUVM                The user mode VM handle.
     
    15821765    AssertReturn(hBpOwner != NIL_DBGFBPOWNER, VERR_INVALID_HANDLE);
    15831766
    1584     return VERR_NOT_IMPLEMENTED;
     1767    int rc = dbgfR3BpOwnerEnsureInit(pUVM);
     1768    AssertRCReturn(rc ,rc);
     1769
     1770    PDBGFBPOWNERINT pBpOwner = dbgfR3BpOwnerGetByHnd(pUVM, hBpOwner);
     1771    if (RT_LIKELY(pBpOwner))
     1772    {
     1773        if (ASMAtomicReadU32(&pBpOwner->cRefs) == 1)
     1774        {
     1775            pBpOwner->pfnBpHitR3 = NULL;
     1776            ASMAtomicDecU32(&pBpOwner->cRefs);
     1777            ASMAtomicBitClear(pUVM->dbgf.s.pbmBpOwnersAllocR3, hBpOwner);
     1778        }
     1779        else
     1780            rc = VERR_DBGF_OWNER_BUSY;
     1781    }
     1782    else
     1783        rc = VERR_INVALID_HANDLE;
     1784
     1785    return rc;
    15851786}
    15861787
  • trunk/src/VBox/VMM/include/DBGFInternal.h

    r86726 r87107  
    5858/** @name Global breakpoint table handling defines.
    5959 * @{ */
     60/** Maximum number of breakpoint owners supported (power of two). */
     61#define DBGF_BP_OWNER_COUNT_MAX             _32K
    6062/** Maximum number of breakpoints supported (power of two). */
    6163#define DBGF_BP_COUNT_MAX                   _1M
     
    829831
    830832/**
     833 * The internal breakpoint owner state, shared part.
     834 */
     835typedef struct DBGFBPOWNERINT
     836{
     837    /** Reference counter indicating how man breakpoints use this owner currently. */
     838    volatile uint32_t           cRefs;
     839    /** Padding. */
     840    uint32_t                    u32Pad0;
     841    /** Callback to call when a breakpoint has hit, Ring-3 Ptr. */
     842    R3PTRTYPE(PFNDBGFBPHIT)     pfnBpHitR3;
     843} DBGFBPOWNERINT;
     844AssertCompileSize(DBGFBPOWNERINT, 16);
     845/** Pointer to an internal breakpoint owner state, shared part. */
     846typedef DBGFBPOWNERINT *PDBGFBPOWNERINT;
     847/** Pointer to a constant internal breakpoint owner state, shared part. */
     848typedef const DBGFBPOWNERINT *PCDBGFBPOWNERINT;
     849
     850
     851/**
     852 * The internal breakpoint owner state, Ring-0 part.
     853 */
     854typedef struct DBGFBPOWNERINTR0
     855{
     856    /** Reference counter indicating how man breakpoints use this owner currently. */
     857    volatile uint32_t           cRefs;
     858    /** Padding. */
     859    uint32_t                    u32Pad0;
     860    /** Callback to call when a breakpoint has hit, Ring-0 Ptr. */
     861    R0PTRTYPE(PFNDBGFBPHIT)     pfnBpHitR0;
     862} DBGFBPOWNERINTR0;
     863AssertCompileSize(DBGFBPOWNERINTR0, 16);
     864/** Pointer to an internal breakpoint owner state, shared part. */
     865typedef DBGFBPOWNERINTR0 *PDBGFBPOWNERINTR0;
     866/** Pointer to a constant internal breakpoint owner state, shared part. */
     867typedef const DBGFBPOWNERINTR0 *PCDBGFBPOWNERINTR0;
     868
     869
     870/**
    831871 * The internal breakpoint state, shared part.
    832872 */
     
    12851325    /** @name Breakpoint handling related state, Ring-0 only part.
    12861326     * @{ */
     1327    /** The breakpoint owner table memory object. */
     1328    RTR0MEMOBJ                          hMemObjBpOwners;
     1329    /** The breakpoint owner table mapping object. */
     1330    RTR0MEMOBJ                          hMapObjBpOwners;
     1331    /** Base pointer to the breakpoint owners table. */
     1332    R0PTRTYPE(PDBGFBPOWNERINTR0)        paBpOwnersR0;
     1333
    12871334    /** Global breakpoint table chunk array. */
    12881335    DBGFBPCHUNKR0                       aBpChunks[DBGF_BP_CHUNK_COUNT];
     
    13761423    /** @name Breakpoint handling related state.
    13771424     * @{ */
     1425    /** Base pointer to the breakpoint owners table. */
     1426    R3PTRTYPE(PDBGFBPOWNERINT)      paBpOwnersR3;
     1427    /** Pointer to the bitmap denoting occupied owner entries. */
     1428    R3PTRTYPE(volatile void *)      pbmBpOwnersAllocR3;
     1429
    13781430    /** Global breakpoint table chunk array. */
    13791431    DBGFBPCHUNKR3                   aBpChunks[DBGF_BP_CHUNK_COUNT];
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