VirtualBox

Changeset 87528 in vbox


Ignore:
Timestamp:
Feb 2, 2021 9:56:46 AM (4 years ago)
Author:
vboxsync
Message:

AMD IOMMU: bugref:9654 IOTLB cache bits.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/iommu-amd.h

    r87343 r87528  
    14251425    struct
    14261426    {
    1427         RT_GCC_EXTENSION uint64_t   u52ExclLimit : 52;  /**< Bits 51:0 - Exclusion Range Limit (last 12 bits are treated as 1s). */
    1428         RT_GCC_EXTENSION uint64_t   u12Rsvd1 : 12;      /**< Bits 63:52 - Reserved. */
     1427        RT_GCC_EXTENSION uint64_t   u12Rsvd0 : 12;           /**< Bits 63:52 - Reserved. */
     1428        RT_GCC_EXTENSION uint64_t   u40ExclRangeLimit : 40;  /**< Bits 51:12 - Exclusion Range Limit Address. */
     1429        RT_GCC_EXTENSION uint64_t   u12Rsvd1 : 12;           /**< Bits 63:52 - Reserved (treated as 1s). */
    14291430    } n;
    14301431    /** The 64-bit unsigned integer view. */
  • trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp

    r87527 r87528  
    5656# define IOMMU_IOTLB_DOMAIN_ID_SHIFT                40
    5757#endif
     58
     59/** @name IOMMU_DEV_LOOKUP_F_XXX: I/O device lookup flags.
     60 *  @{ */
     61/** The device lookup was successful. */
     62#define IOMMU_DEV_LOOKUP_F_VALID                    RT_BIT(0)
     63/** Translation required. */
     64#define IOMMU_DEV_LOOKUP_F_TRANSLATE                RT_BIT(1)
     65/** Only DTE permissions apply. */
     66#define IOMMU_DEV_LOOKUP_F_ONLY_DTE_PERM            RT_BIT(2)
     67/** @} */
    5868
    5969
     
    151161 */
    152162#pragma pack(1)
    153 typedef struct IODOMAIN
    154 {
    155     /** The domain ID assigned by software. */
     163typedef struct IODEVICE
     164{
     165    /** The device lookup flags, see IOMMU_DEV_LOOKUP_F_XXX.   */
     166    uint8_t         fFlags;
     167    /** The DTE permission bits. */
     168    uint8_t         fDtePerm;
     169    /** The domain ID assigned for this device by software. */
    156170    uint16_t        uDomainId;
    157     /** Whether the device ID is valid (if not, lookups must re-read DTE). */
    158     bool            fValid;
    159     bool            afAlignment[1];
    160 } IODOMAIN;
     171} IODEVICE;
    161172#pragma pack()
    162 /** Pointer to an I/O domain struct. */
    163 typedef IODOMAIN *PIODOMAIN;
    164 /** Pointer to a const I/O domain struct. */
    165 typedef IODOMAIN *PCIODOMAIN;
    166 AssertCompileSize(IODOMAIN, 4);
     173/** Pointer to an I/O device struct. */
     174typedef IODEVICE *PIODEVICE;
     175/** Pointer to a const I/O device struct. */
     176typedef IODEVICE *PCIODEVICE;
     177AssertCompileSize(IODEVICE, 4);
    167178
    168179/**
     
    211222#ifdef IOMMU_WITH_IOTLBE_CACHE
    212223    /** L1 Cache - Maps [DeviceId] to [DomainId]. */
    213     PIODOMAIN                   paDomainIds;
     224    PIODEVICE                   paDevices;
    214225    /** Pointer to array of allocated IOTLBEs. */
    215226    PIOTLBE                     paIotlbes;
     
    387398AssertCompileMemberAlignment(IOMMU, hMmio, 8);
    388399#ifdef IOMMU_WITH_IOTLBE_CACHE
    389 AssertCompileMemberAlignment(IOMMU, paDomainIds, 8);
     400AssertCompileMemberAlignment(IOMMU, paDevices, 8);
    390401AssertCompileMemberAlignment(IOMMU, paIotlbes, 8);
    391402AssertCompileMemberAlignment(IOMMU, TreeIotlbe, 8);
     
    771782
    772783
    773 DECL_FORCE_INLINE(IOMMU_STATUS_T) iommuAmdGetStatus(PCIOMMU pThis)
     784DECLINLINE(IOMMU_STATUS_T) iommuAmdGetStatus(PCIOMMU pThis)
    774785{
    775786    IOMMU_STATUS_T Status;
     
    779790
    780791
    781 DECL_FORCE_INLINE(IOMMU_CTRL_T) iommuAmdGetCtrl(PCIOMMU pThis)
     792DECLINLINE(IOMMU_CTRL_T) iommuAmdGetCtrl(PCIOMMU pThis)
    782793{
    783794    IOMMU_CTRL_T Ctrl;
     
    25602571
    25612572/**
    2562  * Returns whether the I/O virtual address is to be excluded from translation and
    2563  * permission checks.
    2564  *
    2565  * @returns @c true if the DVA is excluded, @c false otherwise.
    2566  * @param   pThis   The IOMMU device state.
    2567  * @param   pDte    The device table entry.
    2568  * @param   uIova   The I/O virtual address.
    2569  *
    2570  * @remarks Ensure the exclusion range is enabled prior to calling this function.
    2571  *
    2572  * @thread  Any.
    2573  */
    2574 static bool iommuAmdIsDvaInExclRange(PCIOMMU pThis, PCDTE_T pDte, uint64_t uIova)
    2575 {
    2576     /* Ensure the exclusion range is enabled. */
    2577     Assert(pThis->ExclRangeBaseAddr.n.u1ExclEnable);
    2578 
    2579     /* Check if the IOVA falls within the exclusion range. */
    2580     uint64_t const uIovaExclFirst = pThis->ExclRangeBaseAddr.n.u40ExclRangeBase << X86_PAGE_4K_SHIFT;
    2581     uint64_t const uIovaExclLast  = pThis->ExclRangeLimit.n.u52ExclLimit;
    2582     if (uIovaExclLast - uIova >= uIovaExclFirst)
    2583     {
    2584         /* Check if device access to addresses in the exclusion range can be forwarded untranslated. */
    2585         if (   pThis->ExclRangeBaseAddr.n.u1AllowAll
    2586             || pDte->n.u1AllowExclusion)
    2587             return true;
    2588     }
    2589     return false;
    2590 }
    2591 
    2592 
    2593 /**
    25942573 * Reads a device table entry for the given the device ID.
    25952574 *
     
    29842963
    29852964/**
     2965 * Updates the device lookup flags used for IOTLB caching.
     2966 * This is a NOP when IOTLB caching is disabled.
     2967 *
     2968 * @param   pIommu      The IOMMU device.
     2969 * @param   uDevId      The device ID.
     2970 * @param   pDte        The DTE.
     2971 * @param   fFlags      The device lookup flags, see IOMMU_DEV_LOOKUP_F_XXX.
     2972 */
     2973DECL_FORCE_INLINE(void) iommuAmdDteLookupUpdate(PIOMMU pIommu, uint16_t uDevId, PCDTE_T pDte, uint8_t fFlags)
     2974{
     2975#ifdef IOMMU_WITH_IOTLBE_CACHE
     2976    pIommu->paDevices[uDevId].fFlags    = fFlags;
     2977    pIommu->paDevices[uDevId].uDomainId = pDte->n.u16DomainId;
     2978    pIommu->paDevices[uDevId].fDtePerm  = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK;
     2979#else
     2980    RT_NOREF3(pIommu, uDevId, fFlags);
     2981#endif
     2982}
     2983
     2984
     2985/**
    29862986 * Looks up an I/O virtual address from the device table.
    29872987 *
     
    30223022            if (RT_LIKELY(!fRsvd0 && !fRsvd1))
    30233023            {
    3024                 /* If the IOVA is subject to address exclusion, addresses are forwarded without translation. */
    3025                 if (   !pThis->ExclRangeBaseAddr.n.u1ExclEnable         /** @todo lock or make atomic read! */
    3026                     || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova))
     3024                /* Note: Addresses are not subject to exclusion as we do -not- support remote IOTLBs. */
     3025                IOWALKRESULT WalkResult;
     3026                RT_ZERO(WalkResult);
     3027                rc = iommuAmdPreTranslateChecks(pDevIns, uDevId, uIova, fPerm, &Dte, enmOp, &WalkResult);
     3028                if (rc == VINF_SUCCESS)
    30273029                {
    3028                     IOWALKRESULT WalkResult;
    3029                     RT_ZERO(WalkResult);
    3030                     rc = iommuAmdPreTranslateChecks(pDevIns, uDevId, uIova, fPerm, &Dte, enmOp, &WalkResult);
    3031                     if (rc == VINF_SUCCESS)
     3030                    /* Walk the I/O page tables to translate the IOVA and check permissions for the
     3031                       remaining pages in the access. */
     3032                    size_t   cbRemaining = cbAccess;
     3033                    uint64_t uIovaPage   = uIova & X86_PAGE_4K_BASE_MASK;
     3034                    uint64_t offIova     = uIova & X86_PAGE_4K_OFFSET_MASK;
     3035                    uint64_t cbPages     = 0;
     3036                    IOWALKRESULT WalkResultPrev;
     3037                    RT_ZERO(WalkResultPrev);
     3038                    for (;;)
    30323039                    {
    3033                         /* Walk the I/O page tables to translate the IOVA and check permissions for the
    3034                            remaining pages in the access. */
    3035                         size_t   cbRemaining = cbAccess;
    3036                         uint64_t uIovaPage   = uIova & X86_PAGE_4K_BASE_MASK;
    3037                         uint64_t offIova     = uIova & X86_PAGE_4K_OFFSET_MASK;
    3038                         uint64_t cbPages     = 0;
    3039                         IOWALKRESULT WalkResultPrev;
    3040                         RT_ZERO(WalkResultPrev);
    3041                         for (;;)
     3040                        rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fPerm, &Dte, enmOp, &WalkResult);
     3041                        if (RT_SUCCESS(rc))
    30423042                        {
    3043                             rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fPerm, &Dte, enmOp, &WalkResult);
    3044                             if (RT_SUCCESS(rc))
     3043                            /* Store the translated address before continuing to access more pages. */
     3044                            Assert(WalkResult.cShift >= X86_PAGE_4K_SHIFT);
     3045                            if (cbRemaining == cbAccess)
    30453046                            {
    3046                                 /* Store the translated address before continuing to access more pages. */
    3047                                 Assert(WalkResult.cShift >= X86_PAGE_4K_SHIFT);
    3048                                 if (cbRemaining == cbAccess)
    3049                                 {
    3050                                     uint64_t const offMask = ~(UINT64_C(0xffffffffffffffff) << WalkResult.cShift);
    3051                                     uint64_t const offSpa  = uIova & offMask;
    3052                                     Assert(!(WalkResult.GCPhysSpa & offMask));
    3053                                     GCPhysSpa = WalkResult.GCPhysSpa | offSpa;
    3054 
    3055                                     /* Store the walk result from the first page. */
    3056                                     WalkResultPrev = WalkResult;
    3057                                 }
    3058                                 /* Check if addresses translated so far result in a physically contiguous region. */
    3059                                 else if (iommuAmdDteLookupIsAccessContig(&WalkResultPrev, &WalkResult))
    3060                                     WalkResultPrev = WalkResult;
    3061                                 else
    3062                                 {
    3063                                     STAM_COUNTER_INC(&pThis->StatDteLookupNonContig);
    3064                                     break;
    3065                                 }
    3066 
    3067                                 /* Check if we need to access more pages. */
    3068                                 uint64_t const cbPage = RT_BIT_64(WalkResult.cShift);
    3069                                 if (cbRemaining > cbPage - offIova)
    3070                                 {
    3071                                     cbRemaining -= (cbPage - offIova);  /* Calculate how much more we need to access. */
    3072                                     cbPages     += cbPage;              /* Update size of all pages read thus far. */
    3073                                     uIovaPage   += cbPage;              /* Update address of the next access. */
    3074                                     offIova      = 0;                   /* After first page, all pages are accessed from off 0. */
    3075                                 }
    3076                                 else
    3077                                 {
    3078                                     cbRemaining = 0;
    3079                                     break;
    3080                                 }
     3047                                uint64_t const offMask = ~(UINT64_C(0xffffffffffffffff) << WalkResult.cShift);
     3048                                uint64_t const offSpa  = uIova & offMask;
     3049                                Assert(!(WalkResult.GCPhysSpa & offMask));
     3050                                GCPhysSpa = WalkResult.GCPhysSpa | offSpa;
     3051
     3052                                /* Store the walk result from the first page. */
     3053                                WalkResultPrev = WalkResult;
     3054                            }
     3055                            /* Check if addresses translated so far result in a physically contiguous region. */
     3056                            else if (iommuAmdDteLookupIsAccessContig(&WalkResultPrev, &WalkResult))
     3057                                WalkResultPrev = WalkResult;
     3058                            else
     3059                            {
     3060                                STAM_COUNTER_INC(&pThis->StatDteLookupNonContig);
     3061                                break;
     3062                            }
     3063
     3064                            /* Check if we need to access more pages. */
     3065                            uint64_t const cbPage = RT_BIT_64(WalkResult.cShift);
     3066                            if (cbRemaining > cbPage - offIova)
     3067                            {
     3068                                cbRemaining -= (cbPage - offIova);  /* Calculate how much more we need to access. */
     3069                                cbPages     += cbPage;              /* Update size of all pages read thus far. */
     3070                                uIovaPage   += cbPage;              /* Update address of the next access. */
     3071                                offIova      = 0;                   /* After first page, all pages are accessed from off 0. */
    30813072                            }
    30823073                            else
    30833074                            {
    3084                                 /* Translation failed. */
    3085                                 GCPhysSpa   = NIL_RTGCPHYS;
    3086                                 cbRemaining = cbAccess;
     3075                                cbRemaining = 0;
    30873076                                break;
    30883077                            }
    30893078                        }
    3090 
    3091                         /* Update how much contiguous memory was accessed. */
    3092                         cbContiguous = cbAccess - cbRemaining;
     3079                        else
     3080                        {
     3081                            /* Translation failed. */
     3082                            GCPhysSpa   = NIL_RTGCPHYS;
     3083                            cbRemaining = cbAccess;
     3084                            break;
     3085                        }
    30933086                    }
    3094                     else if (rc == VINF_IOMMU_ADDR_TRANSLATION_DISABLED)
    3095                     {
    3096                         /* Translation is disabled for this device (root paging mode is 0). */
    3097                         GCPhysSpa    =  uIova;
    3098                         cbContiguous = cbAccess;
    3099                         rc = VINF_SUCCESS;
    3100 
    3101                         /* Paranoia. */
    3102                         Assert(WalkResult.cShift    == 0);
    3103                         Assert(WalkResult.GCPhysSpa == uIova);
    3104                         Assert((WalkResult.fPerm & fPerm) == fPerm);
    3105                         /** @todo IOMMU: Add to IOLTB cache. */
    3106                     }
    3107                     else
    3108                     {
    3109                         /* Translation failed or access is denied. */
    3110                         GCPhysSpa    = NIL_RTGCPHYS;
    3111                         cbContiguous = 0;
    3112                         Assert(RT_FAILURE(rc));
    3113                     }
     3087
     3088                    /* Update how much contiguous memory was accessed. */
     3089                    cbContiguous = cbAccess - cbRemaining;
     3090
     3091                    /* Update that addresses requires translation (cumulative permissions of DTE and I/O page tables apply). */
     3092                    iommuAmdDteLookupUpdate(pThis, uDevId, &Dte, IOMMU_DEV_LOOKUP_F_VALID | IOMMU_DEV_LOOKUP_F_TRANSLATE);
     3093                }
     3094                else if (rc == VINF_IOMMU_ADDR_TRANSLATION_DISABLED)
     3095                {
     3096                    /*
     3097                     * Translation is disabled for this device (root paging mode is 0).
     3098                     * GPA=SPA, but the permission bits are important and controls accesses.
     3099                     */
     3100                    /* . */
     3101                    GCPhysSpa    =  uIova;
     3102                    cbContiguous = cbAccess;
     3103                    rc = VINF_SUCCESS;
     3104
     3105                    /* Paranoia. */
     3106                    Assert(WalkResult.cShift    == 0);
     3107                    Assert(WalkResult.GCPhysSpa == uIova);
     3108                    Assert((WalkResult.fPerm & fPerm) == fPerm);
     3109
     3110                    /* Update that addresses don't require translation (only permissions of DTE apply). */
     3111                    iommuAmdDteLookupUpdate(pThis, uDevId, &Dte, IOMMU_DEV_LOOKUP_F_VALID | IOMMU_DEV_LOOKUP_F_ONLY_DTE_PERM);
    31143112                }
    31153113                else
    31163114                {
    3117                     /* The IOVA is subject to address exclusion, forward untranslated. */
    3118                     /** @todo IOMMU: Add to IOLTB cache. */
    3119                     GCPhysSpa    = uIova;
    3120                     cbContiguous = cbAccess;
     3115                    /* Translation failed or access is denied. */
     3116                    GCPhysSpa    = NIL_RTGCPHYS;
     3117                    cbContiguous = 0;
     3118                    Assert(RT_FAILURE(rc));
    31213119                }
    31223120            }
     
    31373135             * See AMD IOMMU spec. "Table 5: Feature Enablement for Address Translation".
    31383136             */
    3139             /** @todo IOMMU: Add to IOLTB cache. */
    31403137            GCPhysSpa    = uIova;
    31413138            cbContiguous = cbAccess;
     3139
     3140            /* Update that addresses don't require translation (nor any permissions). */
     3141            iommuAmdDteLookupUpdate(pThis, uDevId, &Dte, IOMMU_DEV_LOOKUP_F_VALID);
    31423142        }
    31433143    }
     
    33123312    return VINF_SUCCESS;
    33133313}
    3314 
    33153314
    33163315
     
    42484247        pHlp->pfnPrintf(pHlp, "  Exclusion Range Limit                   = %#RX64\n", ExclRangeLimit.u64);
    42494248        if (fVerbose)
    4250             pHlp->pfnPrintf(pHlp, "    Range limit                             = %#RX64\n", ExclRangeLimit.n.u52ExclLimit);
     4249        {
     4250            pHlp->pfnPrintf(pHlp, "    Range limit                             = %#RX64\n",
     4251                            (ExclRangeLimit.n.u40ExclRangeLimit << X86_PAGE_4K_SHIFT) | X86_PAGE_4K_OFFSET_MASK);
     4252        }
    42514253    }
    42524254    /* Extended Feature Register. */
     
    49964998#ifdef IOMMU_WITH_IOTLBE_CACHE
    49974999    /* Destroy level 1 cache. */
    4998     if (pThis->paDomainIds)
    4999     {
    5000         PDMDevHlpMMHeapFree(pDevIns, pThis->paDomainIds);
    5001         pThis->paDomainIds = NULL;
     5000    if (pThis->paDevices)
     5001    {
     5002        PDMDevHlpMMHeapFree(pDevIns, pThis->paDevices);
     5003        pThis->paDevices = NULL;
    50025004    }
    50035005
     
    52475249     * of how code, features and devices around the IOMMU changes.
    52485250     */
    5249     size_t const cbDomains = sizeof(IODOMAIN) * UINT16_MAX;
    5250     pThis->paDomainIds = (PIODOMAIN)PDMDevHlpMMHeapAllocZ(pDevIns, cbDomains);
    5251     if (!pThis->paDomainIds)
     5251    size_t const cbDevices = sizeof(IODEVICE) * UINT16_MAX;
     5252    pThis->paDevices = (PIODEVICE)PDMDevHlpMMHeapAllocZ(pDevIns, cbDevices);
     5253    if (!pThis->paDevices)
    52525254    {
    52535255        return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
    5254                                    N_("Failed to allocate %zu bytes from the hyperheap for the IOMMU level 1 cache."),
    5255                                    cbDomains);
     5256                                   N_("Failed to allocate %zu bytes from the hyperheap for the IOMMU level 1 cache."), cbDevices);
    52565257    }
    52575258
     
    52745275    RTListInit(&pThis->LstLruIotlbe);
    52755276
    5276     LogRel(("%s: Allocated %zu bytes from the hyperheap for the IOTLB cache\n", IOMMU_LOG_PFX, cbDomains + cbIotlbes));
     5277    LogRel(("%s: Allocated %zu bytes from the hyperheap for the IOTLB cache\n", IOMMU_LOG_PFX, cbDevices + cbIotlbes));
    52775278#endif
    52785279
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