VirtualBox

Changeset 87415 in vbox


Ignore:
Timestamp:
Jan 25, 2021 11:33:58 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
142403
Message:

AMD IOMMU: bugref:9654 Optimize command processing by fetching the buffer in one go. Avoids multiple calls to PGM to read small bits of guest memory at the cost of using a bit more host memory.

File:
1 edited

Legend:

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

    r87410 r87415  
    2828#include <iprt/x86.h>
    2929#include <iprt/string.h>
     30#ifdef IN_RING3
     31# include <iprt/mem.h>
     32#endif
    3033
    3134#include "VBoxDD.h"
     
    489492{
    490493    Assert(uEncodedLen > 7);
     494    Assert(uEncodedLen < 16);
    491495    return 2 << (uEncodedLen - 1);
    492496}
     
    502506{
    503507    Assert(uEncodedLen > 7);
     508    Assert(uEncodedLen < 16);
    504509    return (2 << (uEncodedLen - 1)) << 4;
    505510}
     
    37333738        return VINF_SUCCESS;
    37343739
     3740    /*
     3741     * Pre-allocate the maximum command buffer size supported by the IOMMU.
     3742     * This avoid trashing the heap as well as not wasting time allocating
     3743     * and freeing buffers while processing commands.
     3744     */
     3745    size_t cbMaxCmds = sizeof(CMD_GENERIC_T) * iommuAmdGetBufMaxEntries(15);
     3746    void *pvCmds = RTMemAllocZ(cbMaxCmds);
     3747    AssertReturn(pvCmds, VERR_NO_MEMORY);
     3748
    37353749    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    37363750    {
     
    37573771         * Fetch and process IOMMU commands.
    37583772         */
    3759         /** @todo r=ramshankar: This employs a simplistic method of fetching commands (one
    3760          *        at a time) and is expensive due to calls to PGM for fetching guest memory.
    3761          *        We could optimize by fetching a bunch of commands at a time reducing
    3762          *        number of calls to PGM. In the longer run we could lock the memory and
    3763          *        mappings and accessing them directly. */
     3773        /** @todo r=ramshankar: We currently copy all commands from guest memory into a
     3774         *        temporary host buffer before processing them as a batch. If we want to
     3775         *        save on host memory a bit we could, once PGM has the necessary APIs, lock
     3776         *        the page mappings and access them directly. */
    37643777        IOMMU_LOCK(pDevIns);
    37653778
     
    37673780        if (Status.n.u1CmdBufRunning)
    37683781        {
    3769             /* Get the offset we need to read the command from memory (circular buffer offset). */
     3782            /* Get the offsets we need to read commands from memory (circular buffer offset). */
    37703783            uint32_t const cbCmdBuf = iommuAmdGetTotalBufLength(pThis->CmdBufBaseAddr.n.u4Len);
    3771             uint32_t offHead = pThis->CmdBufHeadPtr.n.off;
     3784            uint32_t const offTail  = pThis->CmdBufTailPtr.n.off;
     3785            uint32_t       offHead  = pThis->CmdBufHeadPtr.n.off;
     3786
     3787            /* Validate. */
    37723788            Assert(!(offHead & ~IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK));
    37733789            Assert(offHead < cbCmdBuf);
    3774             while (offHead != pThis->CmdBufTailPtr.n.off)
     3790            Assert(cbCmdBuf <= cbMaxCmds);
     3791
     3792            if (offHead != offTail)
    37753793            {
    3776                 /* Read the command from memory. */
    3777                 CMD_GENERIC_T Cmd;
    3778                 RTGCPHYS const GCPhysCmd = (pThis->CmdBufBaseAddr.n.u40Base << X86_PAGE_4K_SHIFT) + offHead;
    3779                 int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhysCmd, &Cmd, sizeof(Cmd));
     3794                /* Read the entire command buffer from memory (avoids multiple PGM calls). */
     3795                RTGCPHYS const GCPhysCmdBufBase = pThis->CmdBufBaseAddr.n.u40Base << X86_PAGE_4K_SHIFT;
     3796                int rc = PDMDevHlpPhysRead(pDevIns, GCPhysCmdBufBase, pvCmds, cbCmdBuf);
    37803797                if (RT_SUCCESS(rc))
    37813798                {
    3782                     /* Increment the command buffer head pointer. */
    3783                     offHead = (offHead + sizeof(CMD_GENERIC_T)) % cbCmdBuf;
    3784                     pThis->CmdBufHeadPtr.n.off = offHead;
    3785 
    3786                     /* Process the fetched command. */
     3799                    /* Indicate to software we've fetched all commands from the buffer. */
     3800                    pThis->CmdBufHeadPtr.n.off = offTail;
     3801
     3802                    /* Allow IOMMU to do other work while we process commands. */
     3803                    IOMMU_UNLOCK(pDevIns);
     3804
     3805                    /* Process the fetched commands. */
    37873806                    EVT_GENERIC_T EvtError;
    3788                     IOMMU_UNLOCK(pDevIns);
    3789                     rc = iommuAmdR3ProcessCmd(pDevIns, &Cmd, GCPhysCmd, &EvtError);
    3790                     IOMMU_LOCK(pDevIns);
    3791                     if (RT_FAILURE(rc))
     3807                    do
    37923808                    {
    3793                         if (   rc == VERR_IOMMU_CMD_NOT_SUPPORTED
    3794                             || rc == VERR_IOMMU_CMD_INVALID_FORMAT)
     3809                        PCCMD_GENERIC_T pCmd = (PCCMD_GENERIC_T)((uintptr_t)pvCmds + offHead);
     3810                        rc = iommuAmdR3ProcessCmd(pDevIns, pCmd, GCPhysCmdBufBase + offHead, &EvtError);
     3811                        if (RT_FAILURE(rc))
    37953812                        {
    3796                             Assert(EvtError.n.u4EvtCode == IOMMU_EVT_ILLEGAL_CMD_ERROR);
    3797                             iommuAmdRaiseIllegalCmdEvent(pDevIns, (PCEVT_ILLEGAL_CMD_ERR_T)&EvtError);
     3813                            if (   rc == VERR_IOMMU_CMD_NOT_SUPPORTED
     3814                                || rc == VERR_IOMMU_CMD_INVALID_FORMAT)
     3815                            {
     3816                                Assert(EvtError.n.u4EvtCode == IOMMU_EVT_ILLEGAL_CMD_ERROR);
     3817                                iommuAmdRaiseIllegalCmdEvent(pDevIns, (PCEVT_ILLEGAL_CMD_ERR_T)&EvtError);
     3818                            }
     3819                            else if (rc == VERR_IOMMU_CMD_HW_ERROR)
     3820                            {
     3821                                Assert(EvtError.n.u4EvtCode == IOMMU_EVT_COMMAND_HW_ERROR);
     3822                                LogFunc(("Raising command hardware error. Cmd=%#x -> COMMAND_HW_ERROR\n", pCmd->n.u4Opcode));
     3823                                iommuAmdRaiseCmdHwErrorEvent(pDevIns, (PCEVT_CMD_HW_ERR_T)&EvtError);
     3824                            }
     3825                            break;
    37983826                        }
    3799                         else if (rc == VERR_IOMMU_CMD_HW_ERROR)
    3800                         {
    3801                             Assert(EvtError.n.u4EvtCode == IOMMU_EVT_COMMAND_HW_ERROR);
    3802                             LogFunc(("Raising command hardware error. Cmd=%#x -> COMMAND_HW_ERROR\n", Cmd.n.u4Opcode));
    3803                             iommuAmdRaiseCmdHwErrorEvent(pDevIns, (PCEVT_CMD_HW_ERR_T)&EvtError);
    3804                         }
    3805                         break;
    3806                     }
     3827                        offHead = (offHead + sizeof(CMD_GENERIC_T)) % cbCmdBuf;
     3828                    } while (offHead != offTail);
    38073829                }
    38083830                else
    38093831                {
    3810                     LogFunc(("Failed to read command at %#RGp. rc=%Rrc -> COMMAND_HW_ERROR\n", GCPhysCmd, rc));
     3832                    LogFunc(("Failed to read command at %#RGp. rc=%Rrc -> COMMAND_HW_ERROR\n", GCPhysCmdBufBase, rc));
    38113833                    EVT_CMD_HW_ERR_T EvtCmdHwErr;
    3812                     iommuAmdInitCmdHwErrorEvent(GCPhysCmd, &EvtCmdHwErr);
     3834                    iommuAmdInitCmdHwErrorEvent(GCPhysCmdBufBase, &EvtCmdHwErr);
    38133835                    iommuAmdRaiseCmdHwErrorEvent(pDevIns, &EvtCmdHwErr);
    3814                     break;
     3836                    IOMMU_UNLOCK(pDevIns);
    38153837                }
    38163838            }
    3817         }
    3818 
    3819         IOMMU_UNLOCK(pDevIns);
    3820     }
    3821 
     3839            else
     3840                IOMMU_UNLOCK(pDevIns);
     3841        }
     3842        else
     3843            IOMMU_UNLOCK(pDevIns);
     3844    }
     3845
     3846    RTMemFree(pvCmds);
    38223847    LogFlowFunc(("Command thread terminating\n"));
    38233848    return VINF_SUCCESS;
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