VirtualBox

Changeset 84285 in vbox for trunk


Ignore:
Timestamp:
May 13, 2020 12:59:23 PM (5 years ago)
Author:
vboxsync
Message:

AMD IOMMU: bugref:9654 Asynchronous IOMMU command processing.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp

    r84242 r84285  
    486486
    487487/**
    488  * Acquires the IOMMU PDM lock or returns @a a_rcBusy if it's busy.
    489  */
    490 #define IOMMU_LOCK_RET(a_pDevIns, a_pThis, a_rcBusy)  \
     488 * Acquires the IOMMU PDM lock.
     489 * This will make a long jump to ring-3 to acquire the lock if necessary.
     490 */
     491#define IOMMU_LOCK(a_pDevIns, a_pThis)  \
    491492    do { \
    492493        NOREF(pThis); \
    493         int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo), (a_rcBusy)); \
     494        int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo), VINF_SUCCESS); \
    494495        if (RT_LIKELY(rcLock == VINF_SUCCESS)) \
    495496        { /* likely */ } \
     
    512513    do { \
    513514        Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo))); \
     515    }  while (0)
     516
     517/**
     518 * Asserts that the critsect is not owned by this thread.
     519 */
     520#define IOMMU_ASSERT_NOT_LOCKED(a_pDevIns) \
     521    do { \
     522        Assert(!PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo))); \
    514523    }  while (0)
    515524
     
    757766} CMD_GENERIC_T;
    758767AssertCompileSize(CMD_GENERIC_T, 16);
     768/** Pointer to a generic command buffer entry. */
     769typedef CMD_GENERIC_T *PCMD_GENERIC_T;
     770/** Pointer to a const generic command buffer entry. */
     771typedef CMD_GENERIC_T const *PCCMD_GENERIC_T;
     772
    759773/** Number of bits to shift the byte offset of a command in the command buffer to
    760774 *  get its index. */
     
    13721386} IOMMU_CTRL_T;
    13731387AssertCompileSize(IOMMU_CTRL_T, 8);
    1374 #define IOMMU_CTRL_VALID_MASK       UINT64_C(0x004defffffffffff)
     1388#define IOMMU_CTRL_VALID_MASK           UINT64_C(0x004defffffffffff)
     1389#define IOMMU_CTRL_CMD_BUF_EN_MASK      UINT64_C(0x0000000000001001)
    13751390
    13761391/**
     
    22542269    /** Alignment padding. */
    22552270    uint32_t                    uPadding0;
     2271
     2272    /** Whether the command thread is sleeping. */
     2273    bool volatile               fCmdThreadSleeping;
     2274    /** Alignment padding. */
     2275    uint8_t                     afPadding0[3];
     2276    /** Whether the command thread has been signaled for wake up. */
     2277    bool volatile               fCmdThreadSignaled;
     2278    /** Alignment padding. */
     2279    uint8_t                     afPadding1[3];
     2280
    22562281    /** The event semaphore the command thread waits on. */
    22572282    SUPSEMEVENT                 hEvtCmdThread;
     
    23832408/** Pointer to the const IOMMU device state. */
    23842409typedef const struct IOMMU *PCIOMMU;
     2410AssertCompileMemberAlignment(IOMMU, fCmdThreadSleeping, 4);
     2411AssertCompileMemberAlignment(IOMMU, fCmdThreadSignaled, 4);
    23852412AssertCompileMemberAlignment(IOMMU, hEvtCmdThread, 8);
    23862413AssertCompileMemberAlignment(IOMMU, hMmio, 8);
     
    23932420{
    23942421    /** Device instance. */
    2395     PPDMDEVINSR3            pDevInsR3;
     2422    PPDMDEVINSR3                pDevInsR3;
    23962423    /** The IOMMU helpers. */
    2397     PCPDMIOMMUHLPR3         pIommuHlpR3;
     2424    PCPDMIOMMUHLPR3             pIommuHlpR3;
    23982425    /** The command thread handle. */
    2399     R3PTRTYPE(PPDMTHREAD)   pCmdThread;
     2426    R3PTRTYPE(PPDMTHREAD)       pCmdThread;
    24002427} IOMMUR3;
    24012428/** Pointer to the ring-3 IOMMU device state. */
     
    24082435{
    24092436    /** Device instance. */
    2410     PPDMDEVINSR0            pDevInsR0;
     2437    PPDMDEVINSR0                pDevInsR0;
    24112438    /** The IOMMU helpers. */
    2412     PCPDMIOMMUHLPR0         pIommuHlpR0;
     2439    PCPDMIOMMUHLPR0             pIommuHlpR0;
    24132440} IOMMUR0;
    24142441/** Pointer to the ring-0 IOMMU device state. */
     
    24212448{
    24222449    /** Device instance. */
    2423     PPDMDEVINSR0            pDevInsRC;
     2450    PPDMDEVINSR0                pDevInsRC;
    24242451    /** The IOMMU helpers. */
    2425     PCPDMIOMMUHLPRC         pIommuHlpRC;
     2452    PCPDMIOMMUHLPRC             pIommuHlpRC;
    24262453} IOMMURC;
    24272454/** Pointer to the raw-mode IOMMU device state. */
     
    25242551        return idxTail - idxHead;
    25252552
    2526     uint32_t const cMaxEvts = iommuAmdGetBufMaxEntries(pThis->CmdBufBaseAddr.n.u4Len);
    2527     return cMaxEvts - idxHead + idxTail;
     2553    uint32_t const cMaxCmds = iommuAmdGetBufMaxEntries(pThis->CmdBufBaseAddr.n.u4Len);
     2554    return cMaxCmds - idxHead + idxTail;
    25282555}
    25292556
     
    25752602
    25762603/**
    2577  * The IOMMU command thread.
     2604 * Wakes up the command thread if there are commands to be processed or if
     2605 * processing is requested to be stopped by software.
    25782606 *
    2579  * @returns VBox status code.
    25802607 * @param   pDevIns     The IOMMU device instance.
    2581  * @param   pThread     The command thread.
    2582  */
    2583 static DECLCALLBACK(int) iommuAmdR3CmdThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
    2584 {
    2585     RT_NOREF(pDevIns, pThread);
    2586 }
    2587 
    2588 
    2589 /**
    2590  * Unblocks the command thread so it can respond to a state change.
    2591  *
    2592  * @returns VBox status code.
    2593  * @param   pDevIns     The IOMMU device instance.
    2594  * @param   pThread     The command thread.
    2595  */
    2596 static DECLCALLBACK(int) iommuAmdR3CmdThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
    2597 {
    2598     RT_NOREF(pThread);
     2608 */
     2609static void iommuAmdCmdThreadWakeUpIfNeeded(PPDMDEVINS pDevIns)
     2610{
     2611    IOMMU_ASSERT_LOCKED(pDevIns);
     2612
    25992613    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
    2600     return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread);
     2614    if (   !ASMAtomicXchgBool(&pThis->fCmdThreadSignaled, true)
     2615        &&  ASMAtomicReadBool(&pThis->fCmdThreadSleeping))
     2616        PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread);
    26012617}
    26022618
     
    27302746    NewCtrl.u64 = u64Value;
    27312747
     2748    /* Update the register. */
     2749    ASMAtomicWriteU64(&pThis->Ctrl.u64, NewCtrl.u64);
     2750
    27322751    /* Enable or disable event logging when the bit transitions. */
    2733     if (OldCtrl.n.u1EvtLogEn != NewCtrl.n.u1EvtLogEn)
    2734     {
    2735         if (NewCtrl.n.u1EvtLogEn)
     2752    bool const fNewIommuEn  = NewCtrl.n.u1IommuEn;
     2753    bool const fOldEvtLogEn = OldCtrl.n.u1EvtLogEn;
     2754    bool const fNewEvtLogEn = NewCtrl.n.u1EvtLogEn;
     2755    if (fOldEvtLogEn != fNewEvtLogEn)
     2756    {
     2757        if (   fNewIommuEn
     2758            && fNewEvtLogEn)
    27362759        {
    27372760            ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_EVT_LOG_OVERFLOW);
     
    27422765    }
    27432766
    2744     /* Update the register. */
    2745     ASMAtomicWriteU64(&pThis->Ctrl.u64, NewCtrl.u64);
    2746 
    27472767    /* Enable or disable command buffer processing when the bit transitions. */
    2748     if (OldCtrl.n.u1CmdBufEn != NewCtrl.n.u1CmdBufEn)
    2749     {
    2750         if (NewCtrl.n.u1CmdBufEn)
    2751         {
     2768    bool const fOldCmdBufEn = OldCtrl.n.u1CmdBufEn;
     2769    bool const fNewCmdBufEn = NewCtrl.n.u1CmdBufEn;
     2770    if (fOldCmdBufEn != fNewCmdBufEn)
     2771    {
     2772        if (   fNewIommuEn
     2773            && fNewCmdBufEn)
    27522774            ASMAtomicOrU64(&pThis->Status.u64, IOMMU_STATUS_CMD_BUF_RUNNING);
    2753 
    2754             /* If the command buffer isn't empty, kick the command thread to start processing commands. */
    2755             if (pThis->CmdBufTailPtr.n.off != pThis->CmdBufHeadPtr.n.off)
    2756                 PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread);
    2757         }
    27582775        else
    2759         {
    27602776            ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_CMD_BUF_RUNNING);
    2761             /* Kick the command thread to stop processing commands. */
    2762             PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread);
    2763         }
     2777
     2778        /* Wake up the command thread to start or stop processing commands. */
     2779        iommuAmdCmdThreadWakeUpIfNeeded(pDevIns);
    27642780    }
    27652781}
     
    29702986    pThis->CmdBufHeadPtr.au32[0] = offBuf;
    29712987
     2988    iommuAmdCmdThreadWakeUpIfNeeded(pDevIns);
     2989
    29722990    LogFlow((IOMMU_LOG_PFX ": Set CmdBufHeadPtr to %#RX32\n", offBuf));
    29732991    return VINF_SUCCESS;
     
    30093027     */
    30103028    pThis->CmdBufTailPtr.au32[0] = offBuf;
     3029
     3030    iommuAmdCmdThreadWakeUpIfNeeded(pDevIns);
    30113031
    30123032    LogFlow((IOMMU_LOG_PFX ": Set CmdBufTailPtr to %#RX32\n", offBuf));
     
    34823502{
    34833503    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     3504
     3505    IOMMU_LOCK(pDevIns, pThis);
     3506
     3507    /* Check if event logging is active and the log has not overflowed. */
    34843508    IOMMU_STATUS_T const Status = iommuAmdGetStatus(pThis);
    3485 
    3486     /** @todo IOMMU: Consider locking here.  */
    3487 
    3488     /* Check if event logging is active and the log has not overflowed. */
    34893509    if (   Status.n.u1EvtLogRunning
    34903510        && !Status.n.u1EvtOverflow)
     
    35313551        }
    35323552    }
     3553
     3554    IOMMU_UNLOCK(pDevIns, pThis);
    35333555}
    35343556
     
    44444466
    44454467# ifdef IN_RING3
     4468
     4469/**
     4470 * Processes an IOMMU command.
     4471 *
     4472 * @returns VBox status code.
     4473 * @param   pDevIns     The IOMMU device instance.
     4474 * @param   pCmd        The command to process.
     4475 */
     4476static int iommuAmdR3ProcessCmd(PPDMDEVINS pDevIns, PCCMD_GENERIC_T pCmd)
     4477{
     4478    IOMMU_ASSERT_NOT_LOCKED(pDevIns);
     4479
     4480    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     4481    uint8_t const bCmd = pCmd->n.u4Opcode;
     4482    switch (bCmd)
     4483    {
     4484        case IOMMU_CMD_COMPLETION_WAIT:
     4485        case IOMMU_CMD_INV_DEV_TAB_ENTRY:
     4486        case IOMMU_CMD_INV_IOMMU_PAGES:
     4487        case IOMMU_CMD_INV_IOTLB_PAGES:
     4488        case IOMMU_CMD_INV_INTR_TABLE:
     4489        case IOMMU_CMD_PREFETCH_IOMMU_PAGES:
     4490        case IOMMU_CMD_COMPLETE_PPR_REQ:
     4491        case IOMMU_CMD_INV_IOMMU_ALL:
     4492        {
     4493            NOREF(pThis);
     4494            return VERR_NOT_IMPLEMENTED;
     4495        }
     4496
     4497        default:
     4498            break;
     4499    }
     4500
     4501    Log((IOMMU_LOG_PFX ": Invalid/Unrecognized command opcode %u (%#x)\n", bCmd, bCmd));
     4502    return VERR_INVALID_FUNCTION;
     4503}
     4504
     4505
     4506/**
     4507 * The IOMMU command thread.
     4508 *
     4509 * @returns VBox status code.
     4510 * @param   pDevIns     The IOMMU device instance.
     4511 * @param   pThread     The command thread.
     4512 */
     4513static DECLCALLBACK(int) iommuAmdR3CmdThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
     4514{
     4515    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     4516
     4517    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
     4518        return VINF_SUCCESS;
     4519
     4520    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     4521    {
     4522        /*
     4523         * Sleep perpetually until we are woken up to process commands.
     4524         */
     4525        {
     4526            ASMAtomicWriteBool(&pThis->fCmdThreadSleeping, true);
     4527            bool fSignaled = ASMAtomicXchgBool(&pThis->fCmdThreadSignaled, false);
     4528            if (!fSignaled)
     4529            {
     4530                Assert(ASMAtomicReadBool(&pThis->fCmdThreadSleeping));
     4531                int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtCmdThread, RT_INDEFINITE_WAIT);
     4532                AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
     4533                if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
     4534                    break;
     4535                LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
     4536                ASMAtomicWriteBool(&pThis->fCmdThreadSignaled, false);
     4537            }
     4538            ASMAtomicWriteBool(&pThis->fCmdThreadSleeping, false);
     4539        }
     4540
     4541        /*
     4542         * Fetch and process IOMMU commands.
     4543         */
     4544        /** @todo r=ramshankar: This employs a simplistic method of fetching commands (one
     4545         *        at a time) and is expensive due to calls to PGM for fetching guest memory.
     4546         *        We could optimize by fetching a bunch of commands at a time reducing
     4547         *        number of calls to PGM. In the longer run we could lock the memory and
     4548         *        mappings and accessing them directly. */
     4549        IOMMU_STATUS_T Status = iommuAmdGetStatus(pThis);
     4550        if (Status.n.u1CmdBufRunning)
     4551        {
     4552            IOMMU_LOCK(pDevIns, pThis);
     4553
     4554            uint32_t const cbCmdBuf = iommuAmdGetBufLength(pThis->CmdBufBaseAddr.n.u4Len);
     4555            uint32_t offHead = pThis->CmdBufHeadPtr.n.off;
     4556            Assert(!(offHead & ~IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK));
     4557            while (offHead != pThis->CmdBufTailPtr.n.off)
     4558            {
     4559                /* Fetch the command from guest memory. */
     4560                CMD_GENERIC_T Cmd;
     4561                RTGCPHYS const GCPhysCmd = (pThis->CmdBufBaseAddr.n.u40Base << X86_PAGE_4K_SHIFT) + offHead;
     4562                int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhysCmd, &Cmd, sizeof(Cmd));
     4563                if (RT_SUCCESS(rc))
     4564                {
     4565                    /* Increment the command buffer head pointer. */
     4566                    offHead = (offHead + sizeof(CMD_GENERIC_T)) % cbCmdBuf;
     4567                    pThis->CmdBufHeadPtr.n.off = offHead;
     4568
     4569                    /* Process the fetched command. */
     4570                    IOMMU_UNLOCK(pDevIns, pThis);
     4571                    rc = iommuAmdR3ProcessCmd(pDevIns, &Cmd);
     4572                    IOMMU_LOCK(pDevIns, pThis);
     4573                    if (RT_SUCCESS(rc))
     4574                    { /* likely */ }
     4575                    else
     4576                    {
     4577                        /** @todo IOMMU: Raise illegal command error. */
     4578                        /* Stop command processing. */
     4579                        ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_CMD_BUF_RUNNING);
     4580                        break;
     4581                    }
     4582                }
     4583                else
     4584                {
     4585                    /** @todo IOMMU: Raise command hardware error. */
     4586                    /* Stop command processing. */
     4587                    ASMAtomicAndU64(&pThis->Status.u64, ~IOMMU_STATUS_CMD_BUF_RUNNING);
     4588                    break;
     4589                }
     4590            }
     4591
     4592            IOMMU_UNLOCK(pDevIns, pThis);
     4593        }
     4594    }
     4595}
     4596
     4597
     4598/**
     4599 * Wakes up the command thread so it can respond to a state change.
     4600 *
     4601 * @returns VBox status code.
     4602 * @param   pDevIns     The IOMMU device instance.
     4603 * @param   pThread     The command thread.
     4604 */
     4605static DECLCALLBACK(int) iommuAmdR3CmdThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
     4606{
     4607    RT_NOREF(pThread);
     4608
     4609    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     4610    return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtCmdThread);
     4611}
     4612
     4613
    44464614/**
    44474615 * @callback_method_impl{FNPCICONFIGREAD}
     
    44834651    }
    44844652
    4485     IOMMU_LOCK_RET(pDevIns, pThis, VERR_IGNORED);
     4653    IOMMU_LOCK(pDevIns, pThis);
    44864654
    44874655    VBOXSTRICTRC rcStrict;
     
    45274695            RT_FALL_THRU();
    45284696        }
    4529 
    45304697        default:
    45314698        {
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