VirtualBox

Changeset 87714 in vbox


Ignore:
Timestamp:
Feb 11, 2021 7:12:58 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
142758
Message:

AMD IOMMU: bugref:9654 IOTLB cache bits.

File:
1 edited

Legend:

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

    r87713 r87714  
    204204
    205205/**
    206  * I/O page walk result.
    207  */
    208 typedef struct IOWALKRESULT
     206 * I/O page lookup.
     207 */
     208typedef struct IOPAGELOOKUP
    209209{
    210210    /** The translated system physical address. */
     
    214214    /** The I/O permissions for this translation, see IOMMU_IO_PERM_XXX. */
    215215    uint8_t         fPerm;
    216 } IOWALKRESULT;
    217 /** Pointer to an I/O walk result struct. */
    218 typedef IOWALKRESULT *PIOWALKRESULT;
    219 /** Pointer to a const I/O walk result struct. */
    220 typedef IOWALKRESULT const *PCIOWALKRESULT;
     216} IOPAGELOOKUP;
     217/** Pointer to an I/O page lookup. */
     218typedef IOPAGELOOKUP *PIOPAGELOOKUP;
     219/** Pointer to a const I/O page lookup. */
     220typedef IOPAGELOOKUP const *PCIOPAGELOOKUP;
    221221
    222222/**
     
    248248    /** The least recently used (LRU) list node. */
    249249    RTLISTNODE          NdLru;
    250     /** The I/O walk result of the translation. */
    251     IOWALKRESULT        WalkResult;
     250    /** The I/O page lookup of the translation. */
     251    IOPAGELOOKUP        PageLookup;
    252252    /** Whether the entry needs to be evicted from the cache. */
    253253    bool                fEvictPending;
     
    456456    STAMCOUNTER                 StatIotlbeCacheMiss;        /**< Number of IOTLB cache misses. */
    457457    STAMCOUNTER                 StatIotlbeLazyEvictReuse;   /**< Number of IOTLB entries re-used after lazy eviction. */
    458     STAMPROFILEADV              StatIotlbeLookup;           /**< Profiling of IOTLB entry lookup (cached). */
     458    STAMPROFILEADV              StatIotlbeLookup;           /**< Profiling of IOTLB entry lookup (from cache). */
    459459
    460460    STAMCOUNTER                 StatDteLookupNonContig;     /**< Number of DTE lookups that result in non-contiguous regions. */
    461     STAMPROFILEADV              StatIoPageWalkLookup;       /**< Profiling of I/O page walk (uncached). */
     461    STAMPROFILEADV              StatIoPageWalkLookup;       /**< Profiling of I/O page walk (from memory). */
    462462    /** @} */
    463463#endif
     
    691691
    692692/**
    693  * Checks whether two consecutive I/O page walk results translates to a physically
     693 * Checks whether two consecutive I/O page lookup results translates to a physically
    694694 * contiguous region.
    695695 *
    696696 * @returns @c true if they are contiguous, @c false otherwise.
    697  * @param   pWalkResultPrev     The I/O walk result of the previous page.
    698  * @param   pWalkResult         The I/O walk result of the current page.
    699  */
    700 static bool iommuAmdLookupIsAccessContig(PCIOWALKRESULT pWalkResultPrev, PCIOWALKRESULT pWalkResult)
    701 {
    702     Assert(pWalkResultPrev->fPerm  == pWalkResult->fPerm);
    703     size_t const   cbPrev      = RT_BIT_64(pWalkResultPrev->cShift);
    704     RTGCPHYS const GCPhysPrev  = pWalkResultPrev->GCPhysSpa;
    705     RTGCPHYS const GCPhys      = pWalkResult->GCPhysSpa;
    706     uint64_t const offMaskPrev = IOMMU_GET_PAGE_OFF_MASK(pWalkResultPrev->cShift);
    707     uint64_t const offMask     = IOMMU_GET_PAGE_OFF_MASK(pWalkResult->cShift);
     697 * @param   pPageLookupPrev     The I/O page lookup result of the previous page.
     698 * @param   pPageLookup         The I/O page lookup result of the current page.
     699 */
     700static bool iommuAmdLookupIsAccessContig(PCIOPAGELOOKUP pPageLookupPrev, PCIOPAGELOOKUP pPageLookup)
     701{
     702    Assert(pPageLookupPrev->fPerm  == pPageLookup->fPerm);
     703    size_t const   cbPrev      = RT_BIT_64(pPageLookupPrev->cShift);
     704    RTGCPHYS const GCPhysPrev  = pPageLookupPrev->GCPhysSpa;
     705    RTGCPHYS const GCPhys      = pPageLookup->GCPhysSpa;
     706    uint64_t const offMaskPrev = IOMMU_GET_PAGE_OFF_MASK(pPageLookupPrev->cShift);
     707    uint64_t const offMask     = IOMMU_GET_PAGE_OFF_MASK(pPageLookup->cShift);
    708708
    709709    /* Paranoia: Ensure offset bits are 0. */
     
    808808        AVLU64KEY const  uKey          = pIotlbe->Core.Key;
    809809        uint64_t const   uIova         = IOMMU_IOTLB_KEY_GET_IOVA(uKey);
    810         RTGCPHYS const   GCPhysSpa     = pIotlbe->WalkResult.GCPhysSpa;
    811         uint8_t const    cShift        = pIotlbe->WalkResult.cShift;
     810        RTGCPHYS const   GCPhysSpa     = pIotlbe->PageLookup.GCPhysSpa;
     811        uint8_t const    cShift        = pIotlbe->PageLookup.cShift;
    812812        size_t const     cbPage        = RT_BIT_64(cShift);
    813         uint8_t const    fPerm         = pIotlbe->WalkResult.fPerm;
     813        uint8_t const    fPerm         = pIotlbe->PageLookup.fPerm;
    814814        const char      *pszPerm       = iommuAmdMemAccessGetPermName(fPerm);
    815815        bool const       fEvictPending = pIotlbe->fEvictPending;
     
    862862 * @param   uDomainId       The domain ID.
    863863 * @param   uIova           The I/O virtual address.
    864  * @param   pWalkResult     The I/O page walk result of the access.
     864 * @param   pPageLookup     The I/O page lookup result of the access.
    865865 */
    866866static void iommuAmdIotlbEntryInsert(PIOMMU pThis, PIOTLBE pIotlbe, uint16_t uDomainId, uint64_t uIova,
    867                                      PCIOWALKRESULT pWalkResult)
     867                                     PCIOPAGELOOKUP pPageLookup)
    868868{
    869869    /* Initialize the IOTLB entry with results of the I/O page walk. */
    870870    pIotlbe->Core.Key   = IOMMU_IOTLB_KEY_MAKE(uDomainId, uIova);
    871     pIotlbe->WalkResult = *pWalkResult;
     871    pIotlbe->PageLookup = *pPageLookup;
    872872
    873873    /* Validate. */
     
    894894            STAM_COUNTER_INC(&pThis->StatIotlbeLazyEvictReuse);
    895895        }
    896         Assert(pFound->WalkResult.cShift == pWalkResult->cShift);
    897         pFound->WalkResult.fPerm     = pWalkResult->fPerm;
    898         pFound->WalkResult.GCPhysSpa = pWalkResult->GCPhysSpa;
     896        Assert(pFound->PageLookup.cShift == pPageLookup->cShift);
     897        pFound->PageLookup.fPerm     = pPageLookup->fPerm;
     898        pFound->PageLookup.GCPhysSpa = pPageLookup->GCPhysSpa;
    899899    }
    900900}
     
    918918
    919919        RT_ZERO(pIotlbe->Core);
    920         RT_ZERO(pIotlbe->WalkResult);
     920        RT_ZERO(pIotlbe->PageLookup);
    921921        /* We must not erase the LRU node connections here! */
    922922        pIotlbe->fEvictPending = false;
     
    962962 * @param   uDomainId       The domain ID.
    963963 * @param   uIova           The I/O virtual address.
    964  * @param   pWalkResult     The I/O page walk result of the access.
    965  */
    966 static void iommuAmdIotlbAdd(PIOMMU pThis, uint16_t uDomainId, uint64_t uIova, PCIOWALKRESULT pWalkResult)
     964 * @param   pPageLookup     The I/O page lookup result of the access.
     965 */
     966static void iommuAmdIotlbAdd(PIOMMU pThis, uint16_t uDomainId, uint64_t uIova, PCIOPAGELOOKUP pPageLookup)
    967967{
    968968    Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK));
    969     Assert(pWalkResult);
    970     Assert(pWalkResult->cShift <= 31);
    971     Assert(pWalkResult->fPerm != IOMMU_IO_PERM_NONE);
     969    Assert(pPageLookup);
     970    Assert(pPageLookup->cShift <= 31);
     971    Assert(pPageLookup->fPerm != IOMMU_IO_PERM_NONE);
    972972
    973973    /*
     
    986986
    987987        /* Initialize and insert the IOTLB entry into the cache. */
    988         iommuAmdIotlbEntryInsert(pThis, pIotlbe, uDomainId, uIova, pWalkResult);
     988        iommuAmdIotlbEntryInsert(pThis, pIotlbe, uDomainId, uIova, pPageLookup);
    989989
    990990        /* Move the entry to the most recently used slot. */
     
    998998
    999999        /* Initialize and insert the IOTLB entry into the cache. */
    1000         iommuAmdIotlbEntryInsert(pThis, pIotlbe, uDomainId, uIova, pWalkResult);
     1000        iommuAmdIotlbEntryInsert(pThis, pIotlbe, uDomainId, uIova, pPageLookup);
    10011001
    10021002        /* Add the entry to the most recently used slot. */
     
    10901090
    10911091/**
    1092  * Adds or updates an IOTLB entry for the given I/O page walk result.
     1092 * Adds or updates IOTLB entries for the given range of I/O virtual addresses.
    10931093 *
    10941094 * @param   pDevIns     The IOMMU instance data.
     
    10991099 * @param   fPerm       The I/O permissions for the access, see IOMMU_IO_PERM_XXX.
    11001100 */
    1101 static void iommuAmdIotlbUpdate(PPDMDEVINS pDevIns, uint16_t uDomainId, uint64_t uIova, size_t cbAccess, RTGCPHYS GCPhysSpa,
    1102                                 uint8_t fPerm)
     1101static void iommuAmdIotlbAddRange(PPDMDEVINS pDevIns, uint16_t uDomainId, uint64_t uIova, size_t cbAccess, RTGCPHYS GCPhysSpa,
     1102                                  uint8_t fPerm)
    11031103{
    11041104    Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK));
     
    11101110
    11111111    /* Add IOTLB entries for every page in the access. */
    1112     IOWALKRESULT WalkResult;
    1113     RT_ZERO(WalkResult);
    1114     WalkResult.cShift    = X86_PAGE_4K_SHIFT;
    1115     WalkResult.fPerm     = fPerm;
    1116     WalkResult.GCPhysSpa = GCPhysSpa;
     1112    IOPAGELOOKUP PageLookup;
     1113    RT_ZERO(PageLookup);
     1114    PageLookup.cShift    = X86_PAGE_4K_SHIFT;
     1115    PageLookup.fPerm     = fPerm;
     1116    PageLookup.GCPhysSpa = GCPhysSpa;
    11171117
    11181118    size_t cPages = cbAccess / X86_PAGE_4K_SIZE;
     
    11221122    do
    11231123    {
    1124         iommuAmdIotlbAdd(pThis, uDomainId, uIova, &WalkResult);
     1124        iommuAmdIotlbAdd(pThis, uDomainId, uIova, &PageLookup);
    11251125        uIova                += X86_PAGE_4K_SIZE;
    1126         WalkResult.GCPhysSpa += X86_PAGE_4K_SIZE;
     1126        PageLookup.GCPhysSpa += X86_PAGE_4K_SIZE;
    11271127        --cPages;
    11281128    } while (cPages > 0);
     
    31823182 * @param   pDte            The device table entry.
    31833183 * @param   enmOp           The IOMMU operation being performed.
    3184  * @param   pWalkResult     Where to store the results of the I/O page walk. This is
    3185  *                          only updated when VINF_SUCCESS is returned.
     3184 * @param   pPageLookup     Where to store the results of the I/O page lookup. This
     3185 *                          is only updated when VINF_SUCCESS is returned.
    31863186 *
    31873187 * @thread  Any.
    31883188 */
    31893189static int iommuAmdIoPageTableWalk(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fPerm, PCDTE_T pDte,
    3190                                    IOMMUOP enmOp, PIOWALKRESULT pWalkResult)
     3190                                   IOMMUOP enmOp, PIOPAGELOOKUP pPageLookup)
    31913191{
    31923192    Assert(pDte->n.u1Valid);
     
    32663266        {
    32673267            /* The page size of the translation is the default (4K). */
    3268             pWalkResult->GCPhysSpa = PtEntity.u64 & IOMMU_PTENTITY_ADDR_MASK;
    3269             pWalkResult->cShift    = X86_PAGE_4K_SHIFT;
    3270             pWalkResult->fPerm     = fPtePerm;
     3268            pPageLookup->GCPhysSpa = PtEntity.u64 & IOMMU_PTENTITY_ADDR_MASK;
     3269            pPageLookup->cShift    = X86_PAGE_4K_SHIFT;
     3270            pPageLookup->fPerm     = fPtePerm;
    32713271            return VINF_SUCCESS;
    32723272        }
     
    32843284                && cShift < s_acIovaLevelShifts[uLevel + 1])
    32853285            {
    3286                 pWalkResult->GCPhysSpa = GCPhysPte;
    3287                 pWalkResult->cShift    = cShift;
    3288                 pWalkResult->fPerm     = fPtePerm;
     3286                pPageLookup->GCPhysSpa = GCPhysPte;
     3287                pPageLookup->cShift    = cShift;
     3288                pPageLookup->fPerm     = fPtePerm;
    32893289                return VINF_SUCCESS;
    32903290            }
     
    34003400                    uint64_t offIova     = uIova & X86_PAGE_4K_OFFSET_MASK;
    34013401                    uint64_t cbPages     = 0;
    3402                     IOWALKRESULT WalkResultPrev;
    3403                     RT_ZERO(WalkResultPrev);
     3402                    IOPAGELOOKUP PageLookupPrev;
     3403                    RT_ZERO(PageLookupPrev);
    34043404                    for (;;)
    34053405                    {
    34063406                        /** @todo split this into a separate function and reuse from
    34073407                         *        iommuAmdCacheLookup(). */
    3408                         IOWALKRESULT WalkResult;
    3409                         RT_ZERO(WalkResult);
     3408                        IOPAGELOOKUP PageLookup;
     3409                        RT_ZERO(PageLookup);
    34103410                        STAM_PROFILE_ADV_START(&pThis->StatIoPageWalkLookup, a);
    3411                         rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fPerm, &Dte, enmOp, &WalkResult);
     3411                        rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fPerm, &Dte, enmOp, &PageLookup);
    34123412                        STAM_PROFILE_ADV_STOP(&pThis->StatIoPageWalkLookup, a);
    34133413                        if (RT_SUCCESS(rc))
    34143414                        {
    34153415                            /* Store the translated address before continuing to access more pages. */
    3416                             Assert(WalkResult.cShift >= X86_PAGE_4K_SHIFT);
     3416                            Assert(PageLookup.cShift >= X86_PAGE_4K_SHIFT);
    34173417                            if (cbRemaining == cbAccess)
    34183418                            {
    3419                                 uint64_t const offMask = IOMMU_GET_PAGE_OFF_MASK(WalkResult.cShift);
     3419                                uint64_t const offMask = IOMMU_GET_PAGE_OFF_MASK(PageLookup.cShift);
    34203420                                uint64_t const offSpa  = uIova & offMask;
    3421                                 Assert(!(WalkResult.GCPhysSpa & offMask));
    3422                                 GCPhysSpa = WalkResult.GCPhysSpa | offSpa;
     3421                                Assert(!(PageLookup.GCPhysSpa & offMask));
     3422                                GCPhysSpa = PageLookup.GCPhysSpa | offSpa;
    34233423                            }
    34243424                            /* Check if addresses translated so far result in a physically contiguous region. */
    3425                             else if (!iommuAmdLookupIsAccessContig(&WalkResultPrev, &WalkResult))
     3425                            else if (!iommuAmdLookupIsAccessContig(&PageLookupPrev, &PageLookup))
    34263426                            {
    34273427                                STAM_COUNTER_INC(&pThis->StatDteLookupNonContig);
     
    34293429                            }
    34303430
    3431                             /* Store the walk result from the first/previous page. */
    3432                             WalkResultPrev = WalkResult;
     3431                            /* Store the page lookup result from the first/previous page. */
     3432                            PageLookupPrev = PageLookup;
    34333433
    34343434                            /* Update size of all pages read thus far. */
    3435                             uint64_t const cbPage = RT_BIT_64(WalkResult.cShift);
     3435                            uint64_t const cbPage = RT_BIT_64(PageLookup.cShift);
    34363436                            cbPages += cbPage;
    34373437
     
    34683468
    34693469                        /* Update IOTLB for the contiguous range of I/O virtual addresses. */
    3470                         iommuAmdIotlbUpdate(pDevIns, Dte.n.u16DomainId, uIova & X86_PAGE_4K_BASE_MASK, cbPages,
    3471                                             GCPhysSpa & X86_PAGE_4K_BASE_MASK, WalkResultPrev.fPerm);
     3470                        iommuAmdIotlbAddRange(pDevIns, Dte.n.u16DomainId, uIova & X86_PAGE_4K_BASE_MASK, cbPages,
     3471                                              GCPhysSpa & X86_PAGE_4K_BASE_MASK, PageLookupPrev.fPerm);
    34723472                    }
    34733473#endif
     
    35623562{
    35633563    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     3564    int rc = VERR_NOT_FOUND;
     3565
     3566    /*
     3567     * We hold the cache lock across both the device and the IOTLB lookups (if any) because
     3568     * we don't want the device cache to be invalidate while we perform IOTBL lookups.
     3569     */
    35643570    IOMMU_LOCK_CACHE(pDevIns, pThis);
    35653571
    35663572    /* Lookup the device from the level 1 cache. */
    3567     int rc = VERR_NOT_FOUND;
    35683573    PCIODEVICE pDevice = &pThis->paDevices[uDevId];
    35693574    if ((pDevice->fFlags & (IOMMU_DEV_F_PRESENT | IOMMU_DEV_F_VALID | IOMMU_DEV_F_ADDR_TRANSLATE))
     
    35763581        uint64_t uIovaPage    = uIova & X86_PAGE_4K_BASE_MASK;
    35773582        uint64_t offIova      = uIova & X86_PAGE_4K_OFFSET_MASK;
    3578         IOWALKRESULT WalkResultPrev;
    3579         RT_ZERO(WalkResultPrev);
     3583        IOPAGELOOKUP PageLookupPrev;
     3584        RT_ZERO(PageLookupPrev);
    35803585        for (;;)
    35813586        {
     
    35853590            if (pIotlbe)
    35863591            {
    3587                 PCIOWALKRESULT pWalkResult = &pIotlbe->WalkResult;
    3588                 if ((pWalkResult->fPerm & fPerm) == fPerm)
     3592                PCIOPAGELOOKUP pPageLookup = &pIotlbe->PageLookup;
     3593                if ((pPageLookup->fPerm & fPerm) == fPerm)
    35893594                { /* likely */ }
    35903595                else
     
    36003605
    36013606                /* Store the translated address before continuing to translate more pages. */
    3602                 Assert(pWalkResult->cShift >= X86_PAGE_4K_SHIFT);
     3607                Assert(pPageLookup->cShift >= X86_PAGE_4K_SHIFT);
    36033608                if (cbRemaining == cbAccess)
    36043609                {
    3605                     uint64_t const offMask = IOMMU_GET_PAGE_OFF_MASK(pWalkResult->cShift);
     3610                    uint64_t const offMask = IOMMU_GET_PAGE_OFF_MASK(pPageLookup->cShift);
    36063611                    uint64_t const offSpa  = uIova & offMask;
    3607                     Assert(!(pWalkResult->GCPhysSpa & offMask));
    3608                     GCPhysSpa = pWalkResult->GCPhysSpa | offSpa;
     3612                    Assert(!(pPageLookup->GCPhysSpa & offMask));
     3613                    GCPhysSpa = pPageLookup->GCPhysSpa | offSpa;
    36093614                }
    36103615                /* Check if addresses translated so far result in a physically contiguous region. */
    3611                 else if (!iommuAmdLookupIsAccessContig(&WalkResultPrev, pWalkResult))
     3616                else if (!iommuAmdLookupIsAccessContig(&PageLookupPrev, pPageLookup))
    36123617                {
    36133618                    STAM_COUNTER_INC(&pThis->StatIotlbeLookupNonContig);
     
    36163621                }
    36173622
    3618                 /* Store the walk result from the first/previous page. */
    3619                 WalkResultPrev = *pWalkResult;
     3623                /* Store the page lookup result from the first/previous page. */
     3624                PageLookupPrev = *pPageLookup;
    36203625
    36213626                /* Check if we need to access more pages. */
    3622                 uint64_t const cbPage = RT_BIT_64(pWalkResult->cShift);
     3627                uint64_t const cbPage = RT_BIT_64(pPageLookup->cShift);
    36233628                if (cbRemaining > cbPage - offIova)
    36243629                {
     
    58805885    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeCacheMiss, STAMTYPE_COUNTER, "IOTLB/CacheMiss", STAMUNIT_OCCURENCES, "Number of IOTLB cache misses.");
    58815886    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeLazyEvictReuse, STAMTYPE_COUNTER, "IOTLB/LazyEvictReuse", STAMUNIT_OCCURENCES, "Number of IOTLB entries reused after lazy eviction.");
    5882     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeLookup, STAMTYPE_PROFILE, "Profile/IotlbeLookup", STAMUNIT_TICKS_PER_CALL, "Profiling IOTLB entry lookup.");
     5887    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeLookup, STAMTYPE_PROFILE, "Profile/IotlbeLookup", STAMUNIT_TICKS_PER_CALL, "Profiling IOTLB entry lookup (from cache).");
    58835888
    58845889    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatDteLookupNonContig, STAMTYPE_COUNTER, "DTE/LookupNonContig", STAMUNIT_OCCURENCES, "DTE lookups that resulted in non-contiguous translated regions.");
    5885     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIoPageWalkLookup, STAMTYPE_PROFILE, "Profile/IoPageWalk", STAMUNIT_TICKS_PER_CALL, "Profiling I/O page walk lookup.");
     5890    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIoPageWalkLookup, STAMTYPE_PROFILE, "Profile/IoPageWalk", STAMUNIT_TICKS_PER_CALL, "Profiling I/O page walk (from memory).");
    58865891# endif
    58875892
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