VirtualBox

Ignore:
Timestamp:
Apr 7, 2025 9:10:44 AM (2 weeks ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
168314
Message:

VMM/GIC: bugref:10877 GIC ITS command-queue, work-in-progress.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/GITSAll.cpp

    r108835 r108864  
    3535#include <VBox/log.h>
    3636#include <VBox/gic.h>
     37#include <VBox/vmm/pdmdev.h>
    3738#include <VBox/vmm/dbgf.h>
    3839#include <iprt/errcore.h>       /* VINF_SUCCESS */
    3940#include <iprt/string.h>        /* RT_ZERO */
     41#include <iprt/mem.h>           /* RTMemAllocZ, RTMemFree */
    4042
    4143
     
    103105        default:
    104106            return "<UNKNOWN>";
     107    }
     108}
     109
     110
     111DECL_FORCE_INLINE(bool) gitsCmdQueueIsEmptyEx(PCGITSDEV pGitsDev, uint32_t *poffRead, uint32_t *poffWrite)
     112{
     113    *poffRead  = pGitsDev->uCmdReadReg  & GITS_BF_CTRL_REG_CREADR_OFFSET_MASK;
     114    *poffWrite = pGitsDev->uCmdWriteReg & GITS_BF_CTRL_REG_CWRITER_OFFSET_MASK;
     115    return *poffRead == *poffWrite;
     116}
     117
     118
     119DECL_HIDDEN_CALLBACK(bool) gitsCmdQueueIsEmpty(PCGITSDEV pGitsDev)
     120{
     121    uint32_t offRead;
     122    uint32_t offWrite;
     123    return gitsCmdQueueIsEmptyEx(pGitsDev, &offRead, &offWrite);
     124}
     125
     126
     127DECL_HIDDEN_CALLBACK(bool) gitsCmdQueueCanProcessRequests(PCGITSDEV pGitsDev)
     128{
     129    if (     pGitsDev->fEnabled
     130        &&  (pGitsDev->uCmdBaseReg.u & GITS_BF_CTRL_REG_CBASER_VALID_MASK)
     131        && !(pGitsDev->uCmdReadReg   & GITS_BF_CTRL_REG_CREADR_STALLED_MASK))
     132        return true;
     133    return false;
     134}
     135
     136
     137static void gitsCmdQueueThreadWakeUpIfNeeded(PPDMDEVINS pDevIns, PGITSDEV pGitsDev)
     138{
     139    Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo)));
     140    if (    gitsCmdQueueCanProcessRequests(pGitsDev)
     141        && !gitsCmdQueueIsEmpty(pGitsDev))
     142    {
     143        int const rc = PDMDevHlpSUPSemEventSignal(pDevIns, pGitsDev->hEvtCmdQueue);
     144        AssertRC(rc);
    105145    }
    106146}
     
    218258
    219259
    220 DECL_HIDDEN_CALLBACK(void) gitsMmioWriteCtrl(PGITSDEV pGitsDev, uint16_t offReg, uint64_t uValue, unsigned cb)
     260DECL_HIDDEN_CALLBACK(void) gitsMmioWriteCtrl(PPDMDEVINS pDevIns, PGITSDEV pGitsDev, uint16_t offReg, uint64_t uValue, unsigned cb)
    221261{
    222262    Assert(cb == 8 || cb == 4);
     
    250290            Assert(cb == 4);
    251291            pGitsDev->fEnabled = RT_BF_GET(uValue, GITS_BF_CTRL_REG_CTLR_ENABLED);
     292            gitsCmdQueueThreadWakeUpIfNeeded(pDevIns, pGitsDev);
    252293            break;
    253294
     
    258299            else
    259300                pGitsDev->uCmdBaseReg.s.Lo = (uint32_t)uValue;
     301            gitsCmdQueueThreadWakeUpIfNeeded(pDevIns, pGitsDev);
    260302            break;
    261303
     
    263305            Assert(cb == 4);
    264306            pGitsDev->uCmdBaseReg.s.Hi = uValue & RT_HI_U32(GITS_CTRL_REG_CBASER_RW_MASK);
     307            gitsCmdQueueThreadWakeUpIfNeeded(pDevIns, pGitsDev);
    265308            break;
    266309
    267310        case GITS_CTRL_REG_CWRITER_OFF:
    268311            pGitsDev->uCmdWriteReg = uValue & RT_LO_U32(GITS_CTRL_REG_CWRITER_RW_MASK);
     312            gitsCmdQueueThreadWakeUpIfNeeded(pDevIns, pGitsDev);
    269313            break;
    270314
     
    272316            /* Upper 32-bits are all reserved, ignore write. Fedora 40 arm64 guests (and probably others) do this. */
    273317            Assert(uValue == 0);
     318            gitsCmdQueueThreadWakeUpIfNeeded(pDevIns, pGitsDev);
    274319            break;
    275320
     
    371416    }
    372417}
     418
     419
     420DECL_HIDDEN_CALLBACK(int) gitsR3CmdQueueProcess(PPDMDEVINS pDevIns, PGITSDEV pGitsDev, void *pvBuf, uint32_t cbBuf)
     421{
     422    int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VINF_SUCCESS);
     423    PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock);
     424
     425    if (gitsCmdQueueCanProcessRequests(pGitsDev))
     426    {
     427        uint32_t   offRead;
     428        uint32_t   offWrite;
     429        bool const fIsEmpty = gitsCmdQueueIsEmptyEx(pGitsDev, &offRead, &offWrite);
     430        if (!fIsEmpty)
     431        {
     432            uint32_t const cCmdQueuePages = (pGitsDev->uCmdBaseReg.u & GITS_BF_CTRL_REG_CBASER_SIZE_MASK) + 1;
     433            uint32_t const cbCmdQueue     = cCmdQueuePages << GITS_CMD_QUEUE_PAGE_SHIFT;
     434            AssertRelease(cbCmdQueue <= cbBuf); /** @todo Paranoia; make this a debug assert later. */
     435
     436#if 0
     437            /*
     438             * Allocate space for the command-queue if we haven't done so already.
     439             */
     440            if (pGitsDev->pvCmdQueue != NULL)
     441            {
     442                if (pGitsDev->cbCmdQueue <= cbCmdQueue)
     443                {   /* Already allocated sufficient space. */   }
     444                else
     445                {
     446                    /* Free old allocation and allocate a new one. */
     447                    RTMemFree(pGitsDev->pvCmdQueue);
     448                    pGitsDev->cbCmdQueue = cbCmdQueue;
     449                    pGitsDev->pvCmdQueue = RTMemAllocZ(cbCmdQueue);
     450                    if (pGitsDev->pvCmdQueue)
     451                    { /* likely */ }
     452                    else
     453                        return VERR_NO_MEMORY;
     454                }
     455            }
     456            else
     457            {
     458                /* Allocate one. */
     459                pGitsDev->cbCmdQueue = cbCmdQueue;
     460                pGitsDev->pvCmdQueue = RTMemAllocZ(cbCmdQueue);
     461                if (pGitsDev->pvCmdQueue)
     462                { /* likely */ }
     463                else
     464                    return VERR_NO_MEMORY;
     465            }
     466#endif
     467
     468            /*
     469             * Read all the commands into the command queue.
     470             */
     471            RTGCPHYS const GCPhysCmds = pGitsDev->uCmdBaseReg.u & GITS_BF_CTRL_REG_CBASER_PHYS_ADDR_MASK;
     472
     473            /* Leave the critical section before reading (a potentially large amount of) commands. */
     474            PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
     475
     476            int      rc;
     477            uint32_t cbCmds;
     478            if (offWrite > offRead)
     479            {
     480                /* The commands have not wrapped around, read them in one go. */
     481                cbCmds = offWrite - offRead;
     482                Assert(cbCmds <= cbBuf);
     483                rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysCmds, pvBuf, cbCmds);
     484            }
     485            else
     486            {
     487                /* The commands have wrapped around, read forward and wrapped-around. */
     488                uint32_t const cbForward = cbCmdQueue - offRead;
     489                uint32_t const cbWrapped = offWrite;
     490                Assert(cbForward + cbWrapped <= cbBuf);
     491                rc  = PDMDevHlpPhysReadMeta(pDevIns, GCPhysCmds, pvBuf, cbForward);
     492                if (   RT_SUCCESS(rc)
     493                    && cbWrapped > 0)
     494                    rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysCmds + cbForward,
     495                                               (void *)((uintptr_t)pvBuf + cbForward), cbWrapped);
     496                cbCmds = cbForward + cbWrapped;
     497            }
     498
     499            /* Re-acquire the critical section as we now need to modify device state. */
     500            int const rcLock2 = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VINF_SUCCESS);
     501            PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock2);
     502
     503            /*
     504             * Process the commands in the queue.
     505             */
     506            if (RT_SUCCESS(rc))
     507            {
     508
     509                uint32_t const cCmds = cbCmds / GITS_CMD_SIZE;
     510                for (uint32_t idxCmd = 0; idxCmd < cCmds; idxCmd++)
     511                {
     512                    PCGITSCMD pCmd = (PCGITSCMD)((uintptr_t)pvBuf + (idxCmd * sizeof(GITSCMD)));
     513                    AssertReleaseMsgFailed(("Cmd=%#x\n", pCmd->clear.uCmdId));
     514                }
     515
     516                PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
     517                return VINF_SUCCESS;
     518            }
     519
     520            /* Failed to read command queue from the physical address specified by the guest, stall queue and retry later. */
     521
     522
     523            /** @todo Stall the command queue. */
     524            return VINF_TRY_AGAIN;
     525        }
     526    }
     527
     528    PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
     529    return VINF_SUCCESS;
     530}
    373531#endif /* IN_RING3 */
    374532
Note: See TracChangeset for help on using the changeset viewer.

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