VirtualBox

Ignore:
Timestamp:
May 11, 2020 9:13:23 AM (5 years ago)
Author:
vboxsync
Message:

AMD IOMMU: bugref:9654 Use a separate IOWALKRESULT struct rather than use IOTLBE as I expect to change IOTLBE soon (e.g., if it's all 4K pages, we might not need to store 'cShift' in it)

File:
1 edited

Legend:

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

    r84237 r84242  
    22032203
    22042204/**
     2205 * I/O page walk result.
     2206 */
     2207typedef struct
     2208{
     2209    /** The translated system physical address. */
     2210    RTGCPHYS        GCPhysSpa;
     2211    /** The number of offset bits in the system physical address. */
     2212    uint8_t         cShift;
     2213    /** The I/O permissions allowed by the translation (IOMMU_IO_PERM_XXX). */
     2214    uint8_t         fIoPerm;
     2215    /** Padding. */
     2216    uint8_t         abPadding[2];
     2217} IOWALKRESULT;
     2218/** Pointer to an I/O walk result struct. */
     2219typedef IOWALKRESULT *PIOWALKRESULT;
     2220/** Pointer to a const I/O walk result struct. */
     2221typedef IOWALKRESULT *PCIOWALKRESULT;
     2222
     2223/**
    22052224 * IOMMU I/O TLB Entry.
    22062225 * @note Update iommuAmdInitIotlbe() when changes are made.
     
    36053624    pEvtDevTabHwErr->n.u16DevId      = uDevId;
    36063625    pEvtDevTabHwErr->n.u1Intr        = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
    3607     /** @todo r=ramshankar: Any other transaction type that can set read/write bit? */
     3626    /** @todo IOMMU: Any other transaction type that can set read/write bit? */
    36083627    pEvtDevTabHwErr->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
    36093628    pEvtDevTabHwErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
     
    39593978
    39603979/**
    3961  * Walks the I/O page table(s) to translate the I/O virtual address to a system
     3980 * Walks the I/O page table to translate the I/O virtual address to a system
    39623981 * physical address.
    39633982 *
    39643983 * @returns VBox status code.
    3965  * @param   pDevIns     The IOMMU device instance.
    3966  * @param   uIova       The I/O virtual address to translate. Must be 4K aligned!
    3967  * @param   uDevId      The device ID.
    3968  * @param   fAccess     The access permissions (IOMMU_IO_PERM_XXX). This is the
    3969  *                      permissions for the access being made.
    3970  * @param   pDte        The device table entry.
    3971  * @param   enmOp       The IOMMU operation being performed.
    3972  * @param   pIotlbe     The IOTLB entry to update with the results of the
    3973  *                      translation.
     3984 * @param   pDevIns         The IOMMU device instance.
     3985 * @param   uIova           The I/O virtual address to translate. Must be 4K aligned.
     3986 * @param   uDevId          The device ID.
     3987 * @param   fAccess         The access permissions (IOMMU_IO_PERM_XXX). This is the
     3988 *                          permissions for the access being made.
     3989 * @param   pDte            The device table entry.
     3990 * @param   enmOp           The IOMMU operation being performed.
     3991 * @param   pWalkResult     Where to store the results of the I/O page walk. This is
     3992 *                          only updated when VINF_SUCCESS is returned.
    39743993 *
    39753994 * @thread  Any.
    39763995 */
    3977 static int iommuAmdWalkIoPageTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fAccess, PCDTE_T pDte,
    3978                                     IOMMUOP enmOp, PIOTLBE_T pIotlbe)
     3996static int iommuAmdWalkIoPageTable(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fAccess, PCDTE_T pDte,
     3997                                   IOMMUOP enmOp, PIOWALKRESULT pWalkResult)
    39793998{
    39803999    Assert(pDte->n.u1Valid);
    3981     /* The input I/O virtual address must be 4K page aligned. */
    39824000    Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK));
    39834001
     
    40024020    /* If the root page table level is 0, translation is skipped and access is controlled by the permission bits. */
    40034021    uint8_t const uMaxLevel = pDte->n.u3Mode;
    4004     if (uMaxLevel == 0)
     4022    if (uMaxLevel != 0)
     4023    { /* likely */ }
     4024    else
    40054025    {
    40064026        uint8_t const fDtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK;
     
    40104030            return VERR_IOMMU_ADDR_ACCESS_DENIED;
    40114031        }
    4012         iommuAmdUpdateIotlbe(uIova, 0 /* cShift */, fDtePerm, pIotlbe);
     4032        pWalkResult->GCPhysSpa = uIova;
     4033        pWalkResult->cShift    = 0;
     4034        pWalkResult->fIoPerm   = fDtePerm;
    40134035        return VINF_SUCCESS;
    40144036    }
    40154037
    40164038    /* If the root page table level exceeds the allowed host-address translation level, page walk is terminated. */
    4017     if (uMaxLevel > IOMMU_MAX_HOST_PT_LEVEL)
     4039    if (uMaxLevel <= IOMMU_MAX_HOST_PT_LEVEL)
     4040    { /* likely */ }
     4041    else
    40184042    {
    40194043        /** @todo r=ramshankar: I cannot make out from the AMD IOMMU spec. if I should be
     
    40304054    /* Check permissions bits of the root page table. */
    40314055    uint8_t const fPtePerm  = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK;
    4032     if ((fAccess & fPtePerm) != fAccess)
     4056    if ((fAccess & fPtePerm) == fAccess)
     4057    { /* likely */ }
     4058    else
    40334059    {
    40344060        EVT_IO_PAGE_FAULT_T EvtIoPageFault;
     
    40394065    }
    40404066
    4041     /** @todo IOMMU: Split the rest of this into a separate function called
    4042      *        iommuAmdWalkIoPageDirectory() and call it for multi-page accesses. We can
    4043      *        avoid re-checking the DTE root-page table entry every time. */
     4067    /** @todo r=ramshankar: IOMMU: Consider splitting the rest of this into a separate
     4068     *        function called iommuAmdWalkIoPageDirectory() and call it for multi-page
     4069     *        accesses from the 2nd page. We can avoid re-checking the DTE root-page
     4070     *        table entry every time. Not sure if it's worth optimizing that case now
     4071     *        or if at all. */
    40444072
    40454073    /* The virtual address bits indexing table. */
     
    41124140        {
    41134141            /* The page size of the translation is the default (4K). */
    4114             pIotlbe->GCPhysSpa = PtEntity.u64 & IOMMU_PTENTITY_ADDR_MASK;
    4115             pIotlbe->cShift    = X86_PAGE_4K_SHIFT;
    4116             pIotlbe->fIoPerm   = fPtePerm;
     4142            pWalkResult->GCPhysSpa = PtEntity.u64 & IOMMU_PTENTITY_ADDR_MASK;
     4143            pWalkResult->cShift    = X86_PAGE_4K_SHIFT;
     4144            pWalkResult->fIoPerm   = fPtePerm;
    41174145            return VINF_SUCCESS;
    41184146        }
     
    41304158                && cShift < s_acIovaLevelShifts[uLevel + 1])
    41314159            {
    4132                 pIotlbe->GCPhysSpa = GCPhysPte;
    4133                 pIotlbe->cShift    = cShift;
    4134                 pIotlbe->fIoPerm   = fPtePerm;
     4160                pWalkResult->GCPhysSpa = GCPhysPte;
     4161                pWalkResult->cShift    = cShift;
     4162                pWalkResult->fIoPerm   = fPtePerm;
    41354163                return VINF_SUCCESS;
    41364164            }
     
    42004228
    42014229/**
    4202  * Looks up an I/O virtual address from the device table(s).
     4230 * Looks up an I/O virtual address from the device table.
    42034231 *
    42044232 * @returns VBox status code.
     
    42164244 * @thread  Any.
    42174245 */
    4218 static int iommuAmdLookupDeviceTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess,
    4219                                       IOMMUOP enmOp, PRTGCPHYS pGCPhysSpa)
     4246static int iommuAmdLookupDeviceTable(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess,
     4247                                     IOMMUOP enmOp, PRTGCPHYS pGCPhysSpa)
    42204248{
    42214249    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     
    42314259        else
    42324260        {
     4261            /** @todo IOMMU: Add to IOLTB cache. */
    42334262            *pGCPhysSpa = uIova;
    42344263            return VINF_SUCCESS;
     
    42564285        else
    42574286        {
     4287            /** @todo IOMMU: Add to IOLTB cache. */
    42584288            *pGCPhysSpa = uIova;
    42594289            return VINF_SUCCESS;
     
    42624292        /** @todo IOMMU: Perhaps do the <= 4K access case first, if the generic loop
    42634293         *        below gets too expensive and when we have iommuAmdWalkIoPageDirectory. */
    4264 
    4265         IOTLBE_T Iotlbe;
    4266         iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /* cShift */, IOMMU_IO_PERM_NONE, &Iotlbe);
    42674294
    42684295        uint64_t uBaseIova   = uIova & X86_PAGE_4K_BASE_MASK;
     
    42724299        {
    42734300            /* Walk the I/O page tables to translate the IOVA and check permission for the access. */
    4274             rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uBaseIova, fAccess, &Dte, enmOp, &Iotlbe);
     4301            IOWALKRESULT WalkResult;
     4302            rc = iommuAmdWalkIoPageTable(pDevIns, uDevId, uBaseIova, fAccess, &Dte, enmOp, &WalkResult);
    42754303            if (RT_SUCCESS(rc))
    42764304            {
     4305                /** @todo IOMMU: Split large pages into 4K IOTLB entries and add to IOTLB cache. */
     4306
    42774307                /* Store the translated base address before continuing to check permissions for any more pages. */
    42784308                if (cbRemaining == cbAccess)
    42794309                {
    4280                     RTGCPHYS const offSpa = ~(UINT64_C(0xffffffffffffffff) << Iotlbe.cShift);
    4281                     *pGCPhysSpa = Iotlbe.GCPhysSpa | offSpa;
     4310                    RTGCPHYS const offSpa = ~(UINT64_C(0xffffffffffffffff) << WalkResult.cShift);
     4311                    *pGCPhysSpa = WalkResult.GCPhysSpa | offSpa;
    42824312                }
    42834313
    4284                 /** @todo IOMMU: Split large pages into 4K IOTLB entries and add to IOTLB cache. */
    4285 
    4286                 uint64_t const cbPhysPage = UINT64_C(1) << Iotlbe.cShift;
     4314                uint64_t const cbPhysPage = UINT64_C(1) << WalkResult.cShift;
    42874315                if (cbRemaining > cbPhysPage - offIova)
    42884316                {
     
    43374365        /** @todo IOMMU: IOTLB cache lookup. */
    43384366
    4339         /* Lookup the IOVA from the device tables. */
    4340         return iommuAmdLookupDeviceTables(pDevIns, uDevId, uIova, cbRead, IOMMU_IO_PERM_READ, IOMMUOP_MEM_READ, pGCPhysSpa);
     4367        /* Lookup the IOVA from the device table. */
     4368        return iommuAmdLookupDeviceTable(pDevIns, uDevId, uIova, cbRead, IOMMU_IO_PERM_READ, IOMMUOP_MEM_READ, pGCPhysSpa);
    43414369    }
    43424370
     
    43604388static int iommuAmdDeviceMemWrite(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbWrite, PRTGCPHYS pGCPhysSpa)
    43614389{
    4362     RT_NOREF(pDevIns, uDevId, uIova, cbWrite, pGCPhysSpa);
    4363     return VERR_NOT_IMPLEMENTED;
     4390    Assert(pDevIns);
     4391    Assert(pGCPhysSpa);
     4392    Assert(cbWrite > 0);
     4393
     4394    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     4395
     4396    /* Addresses are forwarded without translation when the IOMMU is disabled. */
     4397    IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis);
     4398    if (Ctrl.n.u1IommuEn)
     4399    {
     4400        /** @todo IOMMU: IOTLB cache lookup. */
     4401
     4402        /* Lookup the IOVA from the device table. */
     4403        return iommuAmdLookupDeviceTable(pDevIns, uDevId, uIova, cbWrite, IOMMU_IO_PERM_WRITE, IOMMUOP_MEM_WRITE, pGCPhysSpa);
     4404    }
     4405
     4406    *pGCPhysSpa = uIova;
     4407    return VINF_SUCCESS;
    43644408}
    43654409
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