VirtualBox

Changeset 87666 in vbox for trunk/src/VBox/Devices/Bus


Ignore:
Timestamp:
Feb 9, 2021 5:08:04 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
142708
Message:

AMD IOMMU: bugref:9654 IOTLB cache bits. The IOTLB is currently only enabled in ring-3.

File:
1 edited

Legend:

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

    r87528 r87666  
    2828#include <iprt/x86.h>
    2929#include <iprt/string.h>
     30#include <iprt/avl.h>
    3031#ifdef IN_RING3
    3132# include <iprt/mem.h>
     
    4950
    5051#ifdef IOMMU_WITH_IOTLBE_CACHE
     52/** The maximum number of DTE entries. */
     53# define IOMMU_DTE_CACHE_MAX                        UINT16_MAX
    5154/** The maximum number of IOTLB entries. */
    52 # define IOMMU_IOTLBE_MAX                           512
    53 /** The mask of bits for the domain ID of the IOTLBE key. */
     55# define IOMMU_IOTLBE_MAX                           128
     56/** The mask of bits covering the domain ID in the IOTLBE key. */
    5457# define IOMMU_IOTLB_DOMAIN_ID_MASK                 UINT64_C(0xffffff0000000000)
     58/** The mask of bits covering the IOVA in the IOTLBE key. */
     59# define IOMMU_IOTLB_IOVA_MASK                     (~IOMMU_IOTLB_DOMAIN_ID_MASK)
    5560/** The number of bits to shift for the domain ID of the IOTLBE key. */
    5661# define IOMMU_IOTLB_DOMAIN_ID_SHIFT                40
     62/** The mask of bits for the domain ID of the IOTLBE key. */
     63# define IOMMU_IOTLB_KEY_NIL                        UINT64_C(0)
     64/** Gets the domain ID from an IOTLB entry key. */
     65# define IOMMU_IOTLB_KEY_GET_DOMAIN_ID(a_Key)       ((a_Key) >> IOMMU_IOTLB_DOMAIN_ID_SHIFT)
     66/** Gets the IOVA from the IOTLB entry key. */
     67# define IOMMU_IOTLB_KEY_GET_IOVA(a_Key)            (((a_Key) & IOMMU_IOTLB_IOVA_MASK) << X86_PAGE_4K_SHIFT)
     68/** Makes an IOTLB entry key.
     69 *
     70 * Address bits 63:52 of the IOVA are zero extended, so top 12 bits are free.
     71 * Address bits 11:0 of the IOVA are offset into the minimum page size of 4K,
     72 * so bottom 12 bits are free.
     73 *
     74 * Thus we use the top 24 bits of key to hold bits 15:0 of the domain ID.
     75 * We use the bottom 40 bits of the key to hold bits 51:12 of the IOVA.
     76 */
     77# define IOMMU_IOTLB_KEY_MAKE(a_DomainId, a_uIova)  (  ((uint64_t)(a_DomainId) << IOMMU_IOTLB_DOMAIN_ID_SHIFT) \
     78                                                     | (((a_uIova) >> X86_PAGE_4K_SHIFT) & IOMMU_IOTLB_IOVA_MASK))
    5779#endif
    5880
    59 /** @name IOMMU_DEV_LOOKUP_F_XXX: I/O device lookup flags.
     81/** @name IOMMU_DEV_F_XXX: I/O device flags.
     82 *
     83 *  Some of these flags are "basic" i.e. they correspond directly to their bits in
     84 *  the DTE. The rest of the flags are based on checks or operations on several DTE
     85 *  bits.
     86 *
     87 *  The basic flags are:
     88 *    - VALID                (DTE.V)
     89 *    - IO_PERM_READ         (DTE.IR)
     90 *    - IO_PERM_WRITE        (DTE.IW)
     91 *    - IO_PERM_RSVD         (bit following DTW.IW reserved for future & to keep
     92 *                            masking consistent)
     93 *    - SUPPRESS_ALL_IOPF    (DTE.SA)
     94 *    - SUPPRESS_IOPF        (DTE.SE)
     95 *    - INTR_MAP_VALID       (DTE.IV)
     96 *    - IGNORE_UNMAPPED_INTR (DTE.IG)
     97 *
     98 *  @sa iommuAmdGetBasicDevFlags()
    6099 *  @{ */
    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)
     100/** The DTE is present. */
     101#define IOMMU_DEV_F_PRESENT                         RT_BIT(0)
     102/** The DTE is valid. */
     103#define IOMMU_DEV_F_VALID                           RT_BIT(1)
     104/** DTE permissions apply for address translations. */
     105#define IOMMU_DEV_F_IO_PERM                         RT_BIT(2)
     106/** DTE permission - I/O read allowed. */
     107#define IOMMU_DEV_F_IO_PERM_READ                    RT_BIT(3)
     108/** DTE permission - I/O write allowed. */
     109#define IOMMU_DEV_F_IO_PERM_WRITE                   RT_BIT(4)
     110/** DTE permission - reserved. */
     111#define IOMMU_DEV_F_IO_PERM_RSVD                    RT_BIT(5)
     112/** Address translation required. */
     113#define IOMMU_DEV_F_ADDR_TRANSLATE                  RT_BIT(6)
     114/** Suppress all I/O page faults. */
     115#define IOMMU_DEV_F_SUPPRESS_ALL_IOPF               RT_BIT(7)
     116/** Suppress I/O page faults. */
     117#define IOMMU_DEV_F_SUPPRESS_IOPF                   RT_BIT(8)
     118/** Interrupt map valid. */
     119#define IOMMU_DEV_F_INTR_MAP_VALID                  RT_BIT(9)
     120/** Ignore unmapped interrupts. */
     121#define IOMMU_DEV_F_IGNORE_UNMAPPED_INTR            RT_BIT(10)
     122/** An I/O page fault has been raised for this device. */
     123#define IOMMU_DEV_F_IO_PAGE_FAULT_RAISED            RT_BIT(11)
    67124/** @} */
     125/** The number of bits to shift I/O device flags for DTE permissions. */
     126#define IOMMU_DEV_F_IO_PERM_SHIFT                   3
     127/** The mask of DTE permissions in I/O device flags. */
     128#define IOMMU_DEV_F_IO_PERM_MASK                    0x3
     129
     130/** Gets the page offset mask given the number of bits to shift. */
     131#define IOMMU_GET_PAGE_OFF_MASK(a_cShift)           (~(UINT64_C(0xffffffffffffffff) << (a_cShift)))
    68132
    69133
     
    107171#define IOMMU_ASSERT_LOCKED(a_pDevIns) \
    108172    do { \
    109         Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo))); \
     173        Assert(PDMDevHlpCritSectIsOwner((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo))); \
    110174    }  while (0)
    111175
     
    115179#define IOMMU_ASSERT_NOT_LOCKED(a_pDevIns) \
    116180    do { \
    117         Assert(!PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo))); \
     181        Assert(!PDMDevHlpCritSectIsOwner((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo))); \
    118182    }  while (0)
    119183
     
    134198    IOMMUOP_CMD
    135199} IOMMUOP;
    136 AssertCompileSize(IOMMUOP, 4);
    137200/** Pointer to a IOMMU operation. */
    138201typedef IOMMUOP *PIOMMUOP;
     
    147210    /** The number of offset bits in the system physical address. */
    148211    uint8_t         cShift;
    149     /** The I/O permissions allowed for this translation, see IOMMU_IO_PERM_XXX. */
     212    /** The I/O permissions for this translation, see IOMMU_IO_PERM_XXX. */
    150213    uint8_t         fPerm;
    151     /** Padding. */
    152     uint8_t         abPadding[2];
    153214} IOWALKRESULT;
    154215/** Pointer to an I/O walk result struct. */
    155216typedef IOWALKRESULT *PIOWALKRESULT;
    156217/** Pointer to a const I/O walk result struct. */
    157 typedef IOWALKRESULT *PCIOWALKRESULT;
    158 
    159 /**
    160  * IOMMU I/O Device ID mapping.
    161  */
    162 #pragma pack(1)
     218typedef IOWALKRESULT const *PCIOWALKRESULT;
     219
     220/**
     221 * IOMMU I/O Device.
     222 * Used for caching as well as passing flags to events.
     223 */
    163224typedef struct IODEVICE
    164225{
    165     /** The device lookup flags, see IOMMU_DEV_LOOKUP_F_XXX.   */
    166     uint8_t         fFlags;
    167     /** The DTE permission bits. */
    168     uint8_t         fDtePerm;
     226    /** This device's flags, see IOMMU_DEV_F_XXX. */
     227    uint16_t         fFlags;
    169228    /** The domain ID assigned for this device by software. */
    170229    uint16_t        uDomainId;
    171230} IODEVICE;
    172 #pragma pack()
    173231/** Pointer to an I/O device struct. */
    174232typedef IODEVICE *PIODEVICE;
     
    177235AssertCompileSize(IODEVICE, 4);
    178236
     237#ifdef IOMMU_WITH_IOTLBE_CACHE
    179238/**
    180239 * IOMMU I/O TLB Entry.
     
    183242typedef struct IOTLBE
    184243{
    185     /** The AVL tree core. */
    186     AVLRU64NODECORE     Core;
    187     /** List node for the LRU (Least Recently Used) list used for eviction. */
     244    /** The AVL tree node. */
     245    AVLU64NODECORE      Core;
     246    /** The least recently used (LRU) list node. */
    188247    RTLISTNODE          NdLru;
    189248    /** The I/O walk result of the translation. */
    190249    IOWALKRESULT        WalkResult;
     250    /** Whether the entry needs to be evicted from the cache. */
     251    bool                fEvictPending;
    191252} IOTLBE;
    192 AssertCompileSizeAlignment(IOTLBE, 8);
    193253/** Pointer to an IOMMU I/O TLB entry struct. */
    194254typedef IOTLBE *PIOTLBE;
    195255/** Pointer to a const IOMMU I/O TLB entry struct. */
    196256typedef IOTLBE const *PCIOTLBE;
     257AssertCompileSizeAlignment(IOTLBE, 8);
     258AssertCompileMemberOffset(IOTLBE, Core, 0);
     259#endif  /* IOMMU_WITH_IOTLBE_CACHE */
    197260
    198261/**
     
    223286    /** L1 Cache - Maps [DeviceId] to [DomainId]. */
    224287    PIODEVICE                   paDevices;
    225     /** Pointer to array of allocated IOTLBEs. */
     288    /** Pointer to array of pre-allocated IOTLBEs. */
    226289    PIOTLBE                     paIotlbes;
    227290    /** L2 Cache - Maps [DomainId,Iova] to [IOTLBE]. */
    228     AVLRU64TREE                 TreeIotlbe;
     291    AVLU64TREE                  TreeIotlbe;
    229292    /** LRU list anchor for IOTLB entries. */
    230293    RTLISTANCHOR                LstLruIotlbe;
     
    384447    STAMCOUNTER                 StatCmdInvIommuAll;         /**< Number of Invalidate IOMMU All commands processed. */
    385448
    386     STAMCOUNTER                 StatDteLookupNonContig;     /**< Number of non-contiguous address region translations. */
     449    STAMCOUNTER                 StatIotlbeLookupNonContig;  /**< Number of IOTLB lookups that result in non-contiguous regions. */
     450    STAMCOUNTER                 StatIotlbeCached;           /**< Number of IOTLB entries in the cache. */
     451    STAMCOUNTER                 StatIotlbeCacheHit;         /**< Number of IOTLB cache hits. */
     452    STAMCOUNTER                 StatIotlbeCacheMiss;        /**< Number of IOTLB cache misses. */
     453    STAMCOUNTER                 StatIotlbeLazyEvictReuse;   /**< Number of IOTLB entries re-used after lazy eviction. */
     454
     455    STAMCOUNTER                 StatDteLookupNonContig;     /**< Number of DTE lookups that result in non-contiguous regions. */
    387456    STAMPROFILEADV              StatDteLookup;              /**< Profiling of device table entry lookup (uncached). */
    388457    /** @} */
     
    468537typedef IOMMUREGACC const *PCIOMMUREGACC;
    469538
     539#ifdef IOMMU_WITH_IOTLBE_CACHE
     540/**
     541 * IOTLBE flush argument.
     542 */
     543typedef struct IOTLBEFLUSHARG
     544{
     545    /** The IOMMU device state. */
     546    PIOMMU              pIommu;
     547    /** The domain ID to flush. */
     548    uint16_t            uDomainId;
     549} IOTLBEFLUSHARG;
     550/** Pointer to an IOTLBE flush argument. */
     551typedef IOTLBEFLUSHARG *PIOTLBEFLUSHARG;
     552/** Pointer to a const IOTLBE flush argument. */
     553typedef IOTLBEFLUSHARG const *PCIOTLBEFLUSHARG;
     554
     555/**
     556 * IOTLBE Info. argument.
     557 */
     558typedef struct IOTLBEINFOARG
     559{
     560    /** The IOMMU device state. */
     561    PIOMMU              pIommu;
     562    /** The info helper. */
     563    PCDBGFINFOHLP       pHlp;
     564    /** The domain ID to dump IOTLB entry. */
     565    uint16_t            uDomainId;
     566} IOTLBEINFOARG;
     567/** Pointer to an IOTLBE flush argument. */
     568typedef IOTLBEINFOARG *PIOTLBEINFOARG;
     569/** Pointer to a const IOTLBE flush argument. */
     570typedef IOTLBEINFOARG const *PCIOTLBEINFOARG;
     571#endif
     572
    470573
    471574/*********************************************************************************************************************************
     
    498601 * The IOMMU I/O permission names.
    499602 */
    500 static const char * const g_aszPerm[] = { "none", "read", "write" };
     603static const char * const g_aszPerm[] = { "none", "read", "write", "read+write" };
    501604
    502605
     
    548651
    549652
     653/**
     654 * Gets the descriptive I/O permission name for a memory access.
     655 *
     656 * @returns The I/O permission name.
     657 * @param   fPerm   The I/O permissions for the access, see IOMMU_IO_PERM_XXX.
     658 */
     659static const char *iommuAmdMemAccessGetPermName(uint8_t fPerm)
     660{
     661    /* We shouldn't construct an access with "none" or "read+write" (must be read or write) permissions. */
     662    Assert(fPerm > 0 && fPerm < RT_ELEMENTS(g_aszPerm));
     663    return g_aszPerm[fPerm & IOMMU_IO_PERM_MASK];
     664}
     665
     666
    550667#if 0
    551668/**
     
    568685
    569686
     687/**
     688 * Checks whether two consecutive I/O page walk results translates to a physically
     689 * contiguous region.
     690 *
     691 * @returns @c true if they are contiguous, @c false otherwise.
     692 * @param   pWalkResultPrev     The I/O walk result of the previous page.
     693 * @param   pWalkResult         The I/O walk result of the current page.
     694 */
     695static bool iommuAmdLookupIsAccessContig(PCIOWALKRESULT pWalkResultPrev, PCIOWALKRESULT pWalkResult)
     696{
     697    Assert(pWalkResultPrev->fPerm  == pWalkResult->fPerm);
     698    size_t const   cbPrev      = RT_BIT_64(pWalkResultPrev->cShift);
     699    RTGCPHYS const GCPhysPrev  = pWalkResultPrev->GCPhysSpa;
     700    RTGCPHYS const GCPhys      = pWalkResult->GCPhysSpa;
     701    uint64_t const offMaskPrev = IOMMU_GET_PAGE_OFF_MASK(pWalkResultPrev->cShift);
     702    uint64_t const offMask     = IOMMU_GET_PAGE_OFF_MASK(pWalkResult->cShift);
     703
     704    /* Paranoia: Ensure offset bits are 0. */
     705    Assert(!(GCPhysPrev & offMaskPrev));
     706    Assert(!(GCPhys     & offMask));
     707
     708    if ((GCPhysPrev & ~offMaskPrev) + cbPrev == (GCPhys & ~offMask))
     709        return true;
     710    return false;
     711}
     712
     713
     714/**
     715 * Gets the basic I/O device flags for the given device table entry.
     716 *
     717 * @returns The basic I/O device flags.
     718 * @param   pDte    The device table entry.
     719 */
     720static uint16_t iommuAmdGetBasicDevFlags(PCDTE_T pDte)
     721{
     722    /* Extract basic flags from bits 127:0 of the DTE. */
     723    uint16_t fFlags = 0;
     724    if (pDte->n.u1Valid)
     725    {
     726        fFlags |= IOMMU_DEV_F_VALID;
     727
     728        if (pDte->n.u1SuppressAllPfEvents)
     729            fFlags |= IOMMU_DEV_F_SUPPRESS_ALL_IOPF;
     730        if (pDte->n.u1SuppressPfEvents)
     731            fFlags |= IOMMU_DEV_F_SUPPRESS_IOPF;
     732
     733        uint16_t const fDtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK;
     734        AssertCompile(IOMMU_DEV_F_IO_PERM_MASK == IOMMU_IO_PERM_MASK);
     735        fFlags |= fDtePerm << IOMMU_DEV_F_IO_PERM_SHIFT;
     736    }
     737
     738    /* Extract basic flags from bits 255:128 of the DTE. */
     739    if (pDte->n.u1IntrMapValid)
     740    {
     741        fFlags |= IOMMU_DEV_F_INTR_MAP_VALID;
     742        if (pDte->n.u1IgnoreUnmappedIntrs)
     743            fFlags |= IOMMU_DEV_F_IGNORE_UNMAPPED_INTR;
     744    }
     745    return fFlags;
     746}
     747
     748
    570749#ifdef IOMMU_WITH_IOTLBE_CACHE
    571750/**
    572  * @callback_method_impl{AVLRU64CALLBACK}
    573  */
    574 static DECLCALLBACK(int) iommuAmdDestroyIotlbe(PAVLRU64NODECORE pCore, void *pvUser)
    575 {
    576     RT_NOREF2(pCore, pvUser);
    577     /* Nothing to do here as we will destroy IOTLB entries wholesale later when required. */
     751 * Moves the IOTLB entry to the least recently used slot.
     752 *
     753 * @param   pThis       The IOMMU device state.
     754 * @param   pIotlbe     The IOTLB entry.
     755 */
     756static void iommuAmdIotlbEntryMoveToLru(PIOMMU pThis, PIOTLBE pIotlbe)
     757{
     758    if (!RTListNodeIsFirst(&pThis->LstLruIotlbe, &pIotlbe->NdLru))
     759    {
     760        RTListNodeRemove(&pIotlbe->NdLru);
     761        RTListPrepend(&pThis->LstLruIotlbe, &pIotlbe->NdLru);
     762    }
     763}
     764
     765
     766/**
     767 * Moves the IOTLB entry to the most recently used slot.
     768 *
     769 * @param   pThis       The IOMMU device state.
     770 * @param   pIotlbe     The IOTLB entry.
     771 */
     772static void iommuAmdIotlbEntryMoveToMru(PIOMMU pThis, PIOTLBE pIotlbe)
     773{
     774    if (!RTListNodeIsLast(&pThis->LstLruIotlbe, &pIotlbe->NdLru))
     775    {
     776        RTListNodeRemove(&pIotlbe->NdLru);
     777        RTListAppend(&pThis->LstLruIotlbe, &pIotlbe->NdLru);
     778    }
     779}
     780
     781
     782#ifdef IN_RING3
     783/**
     784 * Dumps the IOTLB entry via the debug info helper.
     785 *
     786 * @returns VINF_SUCCESS.
     787 * @param   pNode       Pointer to an IOTLBE.
     788 * @param   pvUser      Pointer to an IOTLBEINFOARG.
     789 */
     790static DECLCALLBACK(int) iommuAmdR3IotlbEntryInfo(PAVLU64NODECORE pNode, void *pvUser)
     791{
     792    /* Validate. */
     793    PCIOTLBEINFOARG pArgs = (PCIOTLBEINFOARG)pvUser;
     794    AssertPtr(pArgs);
     795    AssertPtr(pArgs->pIommu);
     796    AssertPtr(pArgs->pHlp);
     797    Assert(pArgs->pIommu->u32Magic == IOMMU_MAGIC);
     798
     799    uint16_t const uDomainId = IOMMU_IOTLB_KEY_GET_DOMAIN_ID(pNode->Key);
     800    if (uDomainId == pArgs->uDomainId)
     801    {
     802        PCIOTLBE pIotlbe = (PCIOTLBE)pNode;
     803        AVLU64KEY const  uKey          = pIotlbe->Core.Key;
     804        uint64_t const   uIova         = IOMMU_IOTLB_KEY_GET_IOVA(uKey);
     805        RTGCPHYS const   GCPhysSpa     = pIotlbe->WalkResult.GCPhysSpa;
     806        uint8_t const    cShift        = pIotlbe->WalkResult.cShift;
     807        size_t const     cbPage        = RT_BIT_64(cShift);
     808        uint8_t const    fPerm         = pIotlbe->WalkResult.fPerm;
     809        const char      *pszPerm       = iommuAmdMemAccessGetPermName(fPerm);
     810        bool const       fEvictPending = pIotlbe->fEvictPending;
     811
     812        PCDBGFINFOHLP pHlp = pArgs->pHlp;
     813        pHlp->pfnPrintf(pHlp, " Key           = %#RX64 (%#RX64)\n", uKey, uIova);
     814        pHlp->pfnPrintf(pHlp, " GCPhys        = %#RGp\n",           GCPhysSpa);
     815        pHlp->pfnPrintf(pHlp, " cShift        = %u (%zu bytes)\n",  cShift, cbPage);
     816        pHlp->pfnPrintf(pHlp, " fPerm         = %#x (%s)\n",        fPerm, pszPerm);
     817        pHlp->pfnPrintf(pHlp, " fEvictPending = %RTbool\n",         fEvictPending);
     818    }
     819
    578820    return VINF_SUCCESS;
    579821}
    580 
    581 
    582 /**
    583  * Constructs the key for an IOTLB entry suitable for using as part of the IOTLB
    584  * cache.
    585  *
    586  * @returns The key for an IOTLB entry.
     822#endif /* IN_RING3 */
     823
     824
     825/**
     826 * Removes the IOTLB entry if it's associated with the specified domain ID.
     827 *
     828 * @returns VINF_SUCCESS.
     829 * @param   pNode       Pointer to an IOTLBE.
     830 * @param   pvUser      Pointer to an IOTLBEFLUSHARG containing the domain ID.
     831 */
     832static DECLCALLBACK(int) iommuAmdIotlbEntryRemoveDomainId(PAVLU64NODECORE pNode, void *pvUser)
     833{
     834    /* Validate. */
     835    PCIOTLBEFLUSHARG pArgs = (PCIOTLBEFLUSHARG)pvUser;
     836    AssertPtr(pArgs);
     837    AssertPtr(pArgs->pIommu);
     838    Assert(pArgs->pIommu->u32Magic == IOMMU_MAGIC);
     839
     840    uint16_t const uDomainId = IOMMU_IOTLB_KEY_GET_DOMAIN_ID(pNode->Key);
     841    if (uDomainId == pArgs->uDomainId)
     842    {
     843        /* Mark this entry is as invalidated and needs to be evicted later. */
     844        PIOTLBE pIotlbe = (PIOTLBE)pNode;
     845        pIotlbe->fEvictPending = true;
     846        iommuAmdIotlbEntryMoveToLru(pArgs->pIommu, (PIOTLBE)pNode);
     847    }
     848    return VINF_SUCCESS;
     849}
     850
     851
     852/**
     853 * Inserts an IOTLB entry into the cache.
     854 *
     855 * @param   pThis           The IOMMU device state.
     856 * @param   pIotlbe         The IOTLB entry to initialize and insert.
     857 * @param   uDomainId       The domain ID.
     858 * @param   uIova           The I/O virtual address.
     859 * @param   pWalkResult     The I/O page walk result of the access.
     860 */
     861static void iommuAmdIotlbEntryInsert(PIOMMU pThis, PIOTLBE pIotlbe, uint16_t uDomainId, uint64_t uIova,
     862                                     PCIOWALKRESULT pWalkResult)
     863{
     864    /* Initialize the IOTLB entry with results of the I/O page walk. */
     865    pIotlbe->Core.Key   = IOMMU_IOTLB_KEY_MAKE(uDomainId, uIova);
     866    pIotlbe->WalkResult = *pWalkResult;
     867
     868    /* Validate. */
     869    Assert(pIotlbe->Core.Key != IOMMU_IOTLB_KEY_NIL);
     870    Assert(!pIotlbe->fEvictPending);
     871
     872    /* Check if the entry already exists. */
     873    PIOTLBE pFound = (PIOTLBE)RTAvlU64Get(&pThis->TreeIotlbe, pIotlbe->Core.Key);
     874    if (!pFound)
     875    {
     876        /* Insert the entry into the cache. */
     877        bool const fInserted = RTAvlU64Insert(&pThis->TreeIotlbe, &pIotlbe->Core);
     878        Assert(fInserted); NOREF(fInserted);
     879        Assert(pThis->cCachedIotlbes < IOMMU_IOTLBE_MAX);
     880        ++pThis->cCachedIotlbes;
     881        STAM_COUNTER_INC(&pThis->StatIotlbeCached);
     882    }
     883    else
     884    {
     885        /* Update the existing entry. */
     886        if (pFound->fEvictPending)
     887        {
     888            pFound->fEvictPending = false;
     889            STAM_COUNTER_INC(&pThis->StatIotlbeLazyEvictReuse);
     890        }
     891        Assert(pFound->WalkResult.cShift == pWalkResult->cShift);
     892        pFound->WalkResult.fPerm     = pWalkResult->fPerm;
     893        pFound->WalkResult.GCPhysSpa = pWalkResult->GCPhysSpa;
     894    }
     895}
     896
     897
     898/**
     899 * Removes an IOTLB entry from the cache for the given key.
     900 *
     901 * @returns Pointer to the removed IOTLB entry, NULL if the entry wasn't found in
     902 *          the tree.
     903 * @param   pThis   The IOMMU device state.
     904 * @param   uKey    The key of the IOTLB entry to remove.
     905 */
     906static PIOTLBE iommuAmdIotlbEntryRemove(PIOMMU pThis, AVLU64KEY uKey)
     907{
     908    PIOTLBE pIotlbe = (PIOTLBE)RTAvlU64Remove(&pThis->TreeIotlbe, uKey);
     909    if (pIotlbe)
     910    {
     911        Assert(pThis->cCachedIotlbes > 0);
     912        --pThis->cCachedIotlbes;
     913        STAM_COUNTER_DEC(&pThis->StatIotlbeCached);
     914    }
     915    return pIotlbe;
     916}
     917
     918
     919/**
     920 * Destroys an IOTLB entry.
     921 *
     922 * @param   pIotlbe     The IOTLB entry to destroy.
     923 * @remarks An entry must only be destroyed if it's not in the cache!
     924 */
     925static void iommuAmdIotlbEntryDestroy(PIOTLBE pIotlbe)
     926{
     927    /* We must not erase the LRU node connections here! */
     928    RT_ZERO(pIotlbe->Core);
     929    RT_ZERO(pIotlbe->WalkResult);
     930    pIotlbe->fEvictPending = false;
     931    Assert(pIotlbe->Core.Key == IOMMU_IOTLB_KEY_NIL);
     932}
     933
     934
     935/**
     936 * Looks up an IOTLB from the cache.
     937 *
     938 * @returns Pointer to IOTLB entry if found, NULL otherwise.
     939 * @param   pThis           The IOMMU device state.
     940 * @param   uDomainId       The domain ID.
     941 * @param   uIova           The I/O virtual address.
     942 */
     943static PIOTLBE iommuAmdIotlbLookup(PIOMMU pThis, uint64_t uDomainId, uint64_t uIova)
     944{
     945    uint64_t const uKey = IOMMU_IOTLB_KEY_MAKE(uDomainId, uIova);
     946    PIOTLBE pIotlbe = (PIOTLBE)RTAvlU64Get(&pThis->TreeIotlbe, uKey);
     947    if (   pIotlbe
     948        && pIotlbe->fEvictPending)
     949    {
     950        /*
     951         * Domain Id wildcard invalidations only marks entries for eviction later but doesn't remove
     952         * them from the cache immediately. Here we found one such entry, so remove it and move it to
     953         * the LRU list and return that the lookup failed as it should.
     954         */
     955        iommuAmdIotlbEntryRemove(pThis, pIotlbe->Core.Key);
     956        iommuAmdIotlbEntryDestroy(pIotlbe);
     957        Assert(!pIotlbe->fEvictPending);
     958        STAM_COUNTER_INC(&pThis->StatIotlbeLazyEvictReuse);
     959        iommuAmdIotlbEntryMoveToLru(pThis, pIotlbe);
     960        return NULL;
     961    }
     962    return pIotlbe;
     963}
     964
     965
     966/**
     967 * Adds an IOTLB entry to the cache.
     968 *
     969 * @param   pThis           The IOMMU device state.
     970 * @param   uDomainId       The domain ID.
     971 * @param   uIova           The I/O virtual address.
     972 * @param   pWalkResult     The I/O page walk result of the access.
     973 */
     974static void iommuAmdIotlbAdd(PIOMMU pThis, uint16_t uDomainId, uint64_t uIova, PCIOWALKRESULT pWalkResult)
     975{
     976    Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK));
     977    Assert(pWalkResult);
     978    Assert(pWalkResult->cShift <= 31);
     979    Assert(pWalkResult->fPerm != IOMMU_IO_PERM_NONE);
     980
     981    /*
     982     * If there are no unused IOTLB entries, evict the LRU entry.
     983     * Otherwise, get a new IOTLB entry from the pre-allocated list.
     984     */
     985    if (pThis->idxUnusedIotlbe == IOMMU_IOTLBE_MAX)
     986    {
     987        /* Grab the least recently used entry. */
     988        PIOTLBE pIotlbe = RTListGetFirst(&pThis->LstLruIotlbe, IOTLBE, NdLru);
     989        Assert(pIotlbe);
     990
     991        /* If the entry is in the cache, remove it. */
     992        if (pIotlbe->Core.Key != IOMMU_IOTLB_KEY_NIL)
     993        {
     994            if (pIotlbe->fEvictPending)
     995                STAM_COUNTER_INC(&pThis->StatIotlbeLazyEvictReuse);
     996            iommuAmdIotlbEntryRemove(pThis, pIotlbe->Core.Key);
     997            iommuAmdIotlbEntryDestroy(pIotlbe);
     998        }
     999
     1000        /* Initialize and insert the IOTLB entry into the cache. */
     1001        iommuAmdIotlbEntryInsert(pThis, pIotlbe, uDomainId, uIova, pWalkResult);
     1002
     1003        /* Move the entry to the most recently used slot. */
     1004        iommuAmdIotlbEntryMoveToMru(pThis, pIotlbe);
     1005    }
     1006    else
     1007    {
     1008        /* Grab an unused IOTLB entry from the pre-allocated list. */
     1009        PIOTLBE pIotlbe = &pThis->paIotlbes[pThis->idxUnusedIotlbe];
     1010        ++pThis->idxUnusedIotlbe;
     1011
     1012        /* Initialize and insert the IOTLB entry into the cache. */
     1013        iommuAmdIotlbEntryInsert(pThis, pIotlbe, uDomainId, uIova, pWalkResult);
     1014
     1015        /* Add the entry to the most recently used slot. */
     1016        RTListAppend(&pThis->LstLruIotlbe, &pIotlbe->NdLru);
     1017    }
     1018}
     1019
     1020
     1021/**
     1022 * Removes all IOTLB entries from the cache.
     1023 *
     1024 * @param   pDevIns     The IOMMU instance data.
     1025 */
     1026static void iommuAmdIotlbRemoveAll(PPDMDEVINS pDevIns)
     1027{
     1028    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     1029    IOMMU_ASSERT_LOCKED(pDevIns);
     1030
     1031    if (pThis->cCachedIotlbes > 0)
     1032    {
     1033        pThis->idxUnusedIotlbe = 0;
     1034        size_t const cbIotlbes = sizeof(IOTLBE) * IOMMU_IOTLBE_MAX;
     1035        RT_BZERO(pThis->paIotlbes, cbIotlbes);
     1036        pThis->cCachedIotlbes  = 0;
     1037        STAM_COUNTER_RESET(&pThis->StatIotlbeCached);
     1038        RTListInit(&pThis->LstLruIotlbe);
     1039    }
     1040}
     1041
     1042
     1043/**
     1044 * Removes IOTLB entries for the range of I/O virtual addresses and the specified
     1045 * domain ID from the cache.
     1046 *
     1047 * @param   pThis           The IOMMU device state.
     1048 * @param   uDomainId       The domain ID.
     1049 * @param   uIova           The I/O virtual address to invalidate.
     1050 * @param   cbInvalidate    The size of the invalidation (must be 4K aligned).
     1051 */
     1052static void iommuAmdIotlbRemoveRange(PIOMMU pThis, uint16_t uDomainId, uint64_t uIova, size_t cbInvalidate)
     1053{
     1054    /* Validate. */
     1055    Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK));
     1056    Assert(!(cbInvalidate & X86_PAGE_4K_OFFSET_MASK));
     1057    Assert(cbInvalidate >= X86_PAGE_4K_SIZE);
     1058
     1059    do
     1060    {
     1061        uint64_t const uKey = IOMMU_IOTLB_KEY_MAKE(uDomainId, uIova);
     1062        PIOTLBE pIotlbe = iommuAmdIotlbEntryRemove(pThis, uKey);
     1063        if (pIotlbe)
     1064        {
     1065            iommuAmdIotlbEntryDestroy(pIotlbe);
     1066            iommuAmdIotlbEntryMoveToLru(pThis, pIotlbe);
     1067        }
     1068        uIova        += X86_PAGE_4K_SIZE;
     1069        cbInvalidate -= X86_PAGE_4K_SIZE;
     1070    } while (cbInvalidate > 0);
     1071}
     1072
     1073
     1074/**
     1075 * Removes all IOTLB entries for the specified domain ID.
     1076 *
     1077 * @param   pThis       The IOMMU device state.
     1078 * @param   uDomainId   The domain ID.
     1079 */
     1080static void iommuAmdIotlbRemoveDomainId(PIOMMU pThis, uint16_t uDomainId)
     1081{
     1082    /*
     1083     * We need to iterate the tree and search based on the domain ID.
     1084     * But it seems we cannot remove items while iterating the tree.
     1085     * Thus, we simply mark entries for eviction later but move them to the LRU
     1086     * so they will eventually get evicted and re-cycled as the cache gets re-populated.
     1087     */
     1088    IOTLBEFLUSHARG Args;
     1089    Args.pIommu    = pThis;
     1090    Args.uDomainId = uDomainId;
     1091    RTAvlU64DoWithAll(&pThis->TreeIotlbe, true /* fFromLeft */, iommuAmdIotlbEntryRemoveDomainId, &Args);
     1092}
     1093
     1094
     1095/**
     1096 * Adds or updates an IOTLB entry for the given I/O page walk result.
     1097 *
     1098 * @param   pDevIns     The IOMMU instance data.
    5871099 * @param   uDomainId   The domain ID.
    5881100 * @param   uIova       The I/O virtual address.
    589  */
    590 DECL_FORCE_INLINE(uint64_t) iommuAmdIotlbConstructKey(uint16_t uDomainId, uint64_t uIova)
    591 {
    592     /*
    593      * Address bits 63:52 of the IOVA are zero extended, so top 12 bits are free.
    594      * Address bits 11:0 of the IOVA are offset into the minimum page size of 4K,
    595      * so bottom 12 bits are free.
    596      *
    597      * Thus we use the top 24 bits of key to hold bits 15:0 of the domain ID.
    598      * We use the bottom 40 bits of the key to hold bits 51:12 of the IOVA.
    599      */
    600     uIova &= IOMMU_IOTLB_DOMAIN_ID_MASK;
    601     uIova >>= X86_PAGE_4K_SHIFT;
    602     return ((uint64_t)uDomainId << IOMMU_IOTLB_DOMAIN_ID_SHIFT) | uIova;
    603 }
    604 
    605 
    606 /**
    607  * Deconstructs the key of an IOTLB entry into the domain ID and IOVA.
    608  *
    609  * @param   uKey            The key for the IOTLB entry.
    610  * @param   puDomainId      Where to store the domain ID.
    611  * @param   puIova          Where to store the I/O virtual address.
    612  */
    613 DECL_FORCE_INLINE(void) iommuAmdIotlbDeconstructKey(uint64_t uKey, uint16_t *puDomainId, uint64_t *puIova)
    614 {
    615     *puDomainId = (uKey &  IOMMU_IOTLB_DOMAIN_ID_MASK) >> IOMMU_IOTLB_DOMAIN_ID_SHIFT;
    616     *puIova     = (uKey & ~IOMMU_IOTLB_DOMAIN_ID_MASK) << X86_PAGE_4K_SHIFT;
    617 }
    618 
    619 
    620 /**
    621  * Looks up an IOTLB entry from the IOTLB cache.
    622  *
    623  * @returns Pointer to the I/O walk result or NULL if the entry is not found.
    624  * @param   pThis       The IOMMU device state.
    625  * @param   uDomainId   The domain ID.
    626  * @param   uIova       The I/O virtual address.
    627  */
    628 static PIOWALKRESULT iommuAmdIotlbLookup(PIOMMU pThis, uint64_t uDomainId, uint64_t uIova)
     1101 * @param   cbAcess     The size of the access (must be 4K aligned).
     1102 * @param   GCPhysSpa   The translated system-physical address.
     1103 * @param   fPerm       The I/O permissions for the access, see IOMMU_IO_PERM_XXX.
     1104 */
     1105static void iommuAmdIotlbUpdate(PPDMDEVINS pDevIns, uint16_t uDomainId, uint64_t uIova, size_t cbAccess, RTGCPHYS GCPhysSpa,
     1106                                uint8_t fPerm)
    6291107{
    6301108    Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK));
    631 
    632     uint64_t const uKey = iommuAmdIotlbConstructKey(uDomainId, uIova);
    633     PIOTLBE pIotlbe = (PIOTLBE)RTAvlrU64RangeGet(&pThis->TreeIotlbe, uKey);
    634     if (pIotlbe)
    635     {
    636         /* Mark the entry as the most recently used one. */
    637         RTListNodeRemove(&pIotlbe->NdLru);
    638         RTListAppend(&pThis->LstLruIotlbe, &pIotlbe->NdLru);
    639         return &pIotlbe->WalkResult;
    640     }
    641     return NULL;
    642 }
    643 
    644 
    645 /**
    646  * Adds an IOTLB entry corresponding to the given I/O page walk result.
    647  *
    648  * @param   pThis           The IOMMU device state.
    649  * @param   uDomainId       The domain ID.
    650  * @param   uIova           The I/O virtual address being accessed.
    651  * @param   pWalkResult     The I/O page walk result of the access.
    652  */
    653 static void iommuAmdIotlbAdd(PIOMMU pThis, uint16_t uDomainId, uint64_t uIova, PCIOWALKRESULT pWalkResult)
    654 {
    655     Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK));
    656     Assert(pWalkResult);
    657     Assert(pWalkResult->cShift < 63);
    658     Assert(pWalkResult->fPerm != IOMMU_IO_PERM_NONE);
    659 
    660     /*
    661      * If the cache is full, evict the last recently used entry.
    662      * Otherwise, get a new IOTLB entry from the pre-allocated list.
    663      */
    664     PIOTLBE pIotlbe;
    665     if (pThis->idxUnusedIotlbe == IOMMU_IOTLBE_MAX)
    666     {
    667         pIotlbe = RTListRemoveFirst(&pThis->LstLruIotlbe, IOTLBE, NdLru);
    668         Assert(pIotlbe);
    669         RTAvlrU64Remove(&pThis->TreeIotlbe, pIotlbe->Core.Key);
    670         Assert(pThis->cCachedIotlbes > 0);
    671         --pThis->cCachedIotlbes;
     1109    Assert(!(GCPhysSpa & X86_PAGE_4K_OFFSET_MASK));
     1110    Assert(!(cbAccess & X86_PAGE_4K_OFFSET_MASK));
     1111    Assert(cbAccess >= X86_PAGE_4K_SIZE);
     1112    IOMMU_ASSERT_LOCKED(pDevIns);
     1113
     1114    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     1115
     1116    /* Add IOTLB entries for every page in the access. */
     1117    IOWALKRESULT WalkResult;
     1118    RT_ZERO(WalkResult);
     1119    WalkResult.cShift    = X86_PAGE_4K_SHIFT;
     1120    WalkResult.fPerm     = fPerm;
     1121    WalkResult.GCPhysSpa = GCPhysSpa;
     1122
     1123    size_t cPages = cbAccess / X86_PAGE_4K_SIZE;
     1124    cPages = RT_MIN(cPages, IOMMU_IOTLBE_MAX);
     1125    do
     1126    {
     1127        iommuAmdIotlbAdd(pThis, uDomainId, uIova, &WalkResult);
     1128        uIova                += X86_PAGE_4K_SIZE;
     1129        WalkResult.GCPhysSpa += X86_PAGE_4K_SIZE;
     1130        --cPages;
     1131    } while (cPages > 0);
     1132}
     1133
     1134
     1135/**
     1136 * Updates the I/O device flags for the given device ID.
     1137 *
     1138 * @param   pDevIns     The IOMMU instance data.
     1139 * @param   uDevId      The device ID (bus, device, function).
     1140 * @param   pDte        The device table entry. Can be NULL only when @a fFlags is
     1141 *                      0.
     1142 * @param   fOrMask     The device flags (usually compound flags) to OR in with the
     1143 *                      basic flags, see IOMMU_DEV_F_XXX. Pass 0 to flush the DTE
     1144 *                      from the cache.
     1145 */
     1146static void iommuAmdDteCacheUpdate(PPDMDEVINS pDevIns, uint16_t uDevId, PCDTE_T pDte, uint16_t fOrMask)
     1147{
     1148    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     1149    IOMMU_ASSERT_LOCKED(pDevIns);
     1150
     1151    if (fOrMask & IOMMU_DEV_F_PRESENT)
     1152    {
     1153        Assert(pDte);
     1154        pThis->paDevices[uDevId].fFlags    = iommuAmdGetBasicDevFlags(pDte) | fOrMask;
     1155        pThis->paDevices[uDevId].uDomainId = pDte->n.u16DomainId;
    6721156    }
    6731157    else
    6741158    {
    675         pIotlbe = &pThis->paIotlbes[pThis->idxUnusedIotlbe];
    676         ++pThis->idxUnusedIotlbe;
    677     }
    678 
    679     /* Zero out IOTLB entry before reuse. */
    680     Assert(pIotlbe);
    681     RT_ZERO(*pIotlbe);
    682 
    683     /* Update the entry with the result of the page walk. */
    684     pIotlbe->Core.Key     = iommuAmdIotlbConstructKey(uDomainId, uIova);
    685     pIotlbe->Core.KeyLast = iommuAmdIotlbConstructKey(uDomainId, uIova + RT_BIT_64(pWalkResult->cShift) - 1);
    686     pIotlbe->WalkResult   = *pWalkResult;
    687 
    688     /* Add the entry to the cache. */
    689     RTAvlrU64Insert(&pThis->TreeIotlbe, &pIotlbe->Core);
    690     ++pThis->cCachedIotlbes;
    691 
    692     /* Mark the entry as the most recently used one. */
    693     RTListAppend(&pThis->LstLruIotlbe, &pIotlbe->NdLru);
    694 }
    695 
    696 
    697 /**
    698  * Removes all IOTLB entries from the cache.
    699  *
    700  * @param   pThis   The IOMMU device state.
    701  */
    702 static void iommuAmdIotlbRemoveAll(PIOMMU pThis)
    703 {
    704     RTListInit(&pThis->LstLruIotlbe);
    705     RTAvlrU64Destroy(&pThis->TreeIotlbe, iommuAmdDestroyIotlbe, NULL /* pvParam */);
    706     pThis->cCachedIotlbes  = 0;
    707     pThis->idxUnusedIotlbe = 0;
    708     size_t const cbIotlbes = sizeof(IOTLBE) * IOMMU_IOTLBE_MAX;
    709     RT_BZERO(pThis->paIotlbes, cbIotlbes);
    710 }
    711 
    712 
    713 /**
    714  * Removes a set of IOTLB entries from the cache given the domain ID, I/O virtual
    715  * address and size.
    716  *
    717  * @param   pThis       The IOMMU device state.
    718  * @param   uDomainId   The domain ID.
    719  * @param   uIova       The I/O virtual address.
    720  * @param   cShift      The number of bits to shift to get the size of the range
    721  *                      being removed.
    722  */
    723 static void iommuAmdIotlbRemoveRange(PIOMMU pThis, uint16_t uDomainId, uint64_t uIova, uint8_t cShift)
    724 {
    725     Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK));
    726 
    727     /*
    728      * Validate invalidation size.
    729      * See AMD IOMMU spec. 2.2.3 "I/O Page Tables for Host Translations".
    730      */
    731     if (   cShift == 12 /* 4K  */ || cShift == 13 /* 8K  */
    732         || cShift == 14 /* 16K */ || cShift == 20 /* 1M  */
    733         || cShift == 22 /* 4M  */ || cShift == 32 /* 4G  */)
    734     {
    735         /*
    736          * We remove all ranges (in our tree) containing the range of I/O virtual addresses requesting
    737          * to be invalidated. E.g., if the guest is using 1M pages but requests to invalidate only 8K
    738          * we must invalidate the entire 1M page. On the other hand, we must handle cross-boundary
    739          * requests that spans multiple pages. E.g., if the guest is using 4K pages but requests to
    740          * invalid 8K, we would need to invalid two 4K pages.
    741          */
    742         uint64_t const uIovaLast = uIova + RT_BIT_64(cShift) - 1;
    743         for (;;)
    744         {
    745             uint64_t const uKey = iommuAmdIotlbConstructKey(uDomainId, uIova);
    746             PIOTLBE pIotlbe = (PIOTLBE)RTAvlrU64RangeRemove(&pThis->TreeIotlbe, uKey);
    747             if (pIotlbe)
    748             {
    749                 --pThis->cCachedIotlbes;
    750 
    751                 /* Grab the last valid address in the range. */
    752                 uint64_t uRangeIovaLast;
    753                 uint16_t uRangeDomainId;
    754                 iommuAmdIotlbDeconstructKey(pIotlbe->Core.KeyLast, &uRangeDomainId, &uRangeIovaLast);
    755                 Assert(uRangeDomainId == uDomainId); NOREF(uRangeDomainId);   /* Paranoia. */
    756 
    757                 /* Remove the range. */
    758                 RTListNodeRemove(&pIotlbe->NdLru);
    759                 RTListPrepend(&pThis->LstLruIotlbe, &pIotlbe->NdLru);
    760                 RT_ZERO(*pIotlbe);
    761 
    762                 /* Check if we need to invalidate the next range. */
    763                 if (uIovaLast > uRangeIovaLast)
    764                     uIova = uRangeIovaLast + 1;
    765                 else
    766                     break;
    767             }
    768             else
    769                 break;
    770         }
    771     }
    772     else
    773     {
    774         /*
    775          * The guest provided size is either invalid or exceeds the largest, meaningful page size.
    776          * In such situations, we flush the entire cache.
    777          */
    778         iommuAmdIotlbRemoveAll(pThis);
    779     }
     1159        pThis->paDevices[uDevId].fFlags    = 0;
     1160        pThis->paDevices[uDevId].uDomainId = 0;
     1161    }
     1162}
     1163
     1164
     1165/**
     1166 * Sets one or more I/O device flags if the device is present in the cache.
     1167 *
     1168 * @param   pDevIns         The IOMMU instance data.
     1169 * @param   uDevId          The device ID (bus, device, function).
     1170 * @param   fDevIoFlags     The device flags to set.
     1171 */
     1172static void iommuAmdDteCacheSetFlags(PPDMDEVINS pDevIns, uint16_t uDevId, uint16_t fDevIoFlags)
     1173{
     1174    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     1175    IOMMU_ASSERT_LOCKED(pDevIns);
     1176
     1177    if (fDevIoFlags & IOMMU_DEV_F_PRESENT)
     1178        pThis->paDevices[uDevId].fFlags |= fDevIoFlags;
     1179}
     1180
     1181
     1182/**
     1183 * Removes all entries in the device table entry cache.
     1184 *
     1185 * @param   pDevIns     The IOMMU instance data.
     1186 */
     1187static void iommuAmdDteCacheRemoveAll(PPDMDEVINS pDevIns)
     1188{
     1189    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     1190    IOMMU_ASSERT_LOCKED(pDevIns);
     1191
     1192    size_t const cbDevices = sizeof(IODEVICE) * IOMMU_DTE_CACHE_MAX;
     1193    RT_BZERO(pThis->paDevices, cbDevices);
    7801194}
    7811195#endif  /* IOMMU_WITH_IOTLBE_CACHE */
     
    21602574 * Initializes a PAGE_TAB_HARDWARE_ERROR event.
    21612575 *
    2162  * @param   uDevId              The device ID.
     2576 * @param   uDevId              The device ID (bus, device, function).
    21632577 * @param   uDomainId           The domain ID.
    21642578 * @param   GCPhysPtEntity      The system physical address of the page table
     
    22582672 * Initializes a DEV_TAB_HARDWARE_ERROR event.
    22592673 *
    2260  * @param   uDevId              The device ID.
     2674 * @param   uDevId              The device ID (bus, device, function).
    22612675 * @param   GCPhysDte           The system physical address of the failed device table
    22622676 *                              access.
     
    23512765 * Initializes an ILLEGAL_DEV_TABLE_ENTRY event.
    23522766 *
    2353  * @param   uDevId          The device ID.
     2767 * @param   uDevId          The device ID (bus, device, function).
    23542768 * @param   uIova           The I/O virtual address.
    23552769 * @param   fRsvdNotZero    Whether reserved bits are not zero. Pass @c false if the
     
    24092823 * Initializes an IO_PAGE_FAULT event.
    24102824 *
    2411  * @param   uDevId              The device ID.
     2825 * @param   uDevId              The device ID (bus, device, function).
    24122826 * @param   uDomainId           The domain ID.
    24132827 * @param   uIova               The I/O virtual address being accessed.
     
    24482862 *
    24492863 * @param   pDevIns             The IOMMU instance data.
    2450  * @param   pDte                The device table entry. Optional, can be NULL
    2451  *                              depending on @a enmOp.
    2452  * @param   pIrte               The interrupt remapping table entry. Optional, can
    2453  *                              be NULL depending on @a enmOp.
     2864 * @param   fIoDevFlags         The I/O device flags, see IOMMU_DEV_F_XXX.
     2865 * @param   pIrte               The interrupt remapping table entry, can be NULL.
    24542866 * @param   enmOp               The IOMMU operation being performed.
    24552867 * @param   pEvtIoPageFault     The I/O page fault event.
     
    24582870 * @thread  Any.
    24592871 */
    2460 static void iommuAmdIoPageFaultEventRaise(PPDMDEVINS pDevIns, PCDTE_T pDte, PCIRTE_T pIrte, IOMMUOP enmOp,
     2872static void iommuAmdIoPageFaultEventRaise(PPDMDEVINS pDevIns, uint16_t fIoDevFlags, PCIRTE_T pIrte, IOMMUOP enmOp,
    24612873                                          PCEVT_IO_PAGE_FAULT_T pEvtIoPageFault, EVT_IO_PAGE_FAULT_TYPE_T enmEvtType)
    24622874{
    24632875    AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_IO_PAGE_FAULT_T));
    24642876    PCEVT_GENERIC_T pEvent = (PCEVT_GENERIC_T)pEvtIoPageFault;
     2877
     2878#ifdef IOMMU_WITH_IOTLBE_CACHE
     2879# define IOMMU_DTE_CACHE_SET_PF_RAISED(a_pDevIns, a_DevId)  iommuAmdDteCacheSetFlags((a_pDevIns), (a_DevId), \
     2880                                                                                     IOMMU_DEV_F_IO_PAGE_FAULT_RAISED)
     2881#else
     2882# define IOMMU_DTE_CACHE_SET_PF_RAISED(a_pDevIns, a_DevId)  do { } while (0)
     2883#endif
    24652884
    24662885    IOMMU_LOCK_NORET(pDevIns);
     
    24702889        || enmOp == IOMMUOP_MEM_WRITE)
    24712890    {
    2472         if (   pDte
    2473             && pDte->n.u1Valid)
    2474         {
    2475             fSuppressEvtLogging = pDte->n.u1SuppressAllPfEvents;
    2476             /** @todo IOMMU: Implement DTE.SE bit, i.e. device ID specific I/O page fault
    2477              *        suppression. Perhaps will be possible when we complete IOTLB/cache
    2478              *        handling. */
     2891        uint16_t const fSuppressIopf    = IOMMU_DEV_F_VALID | IOMMU_DEV_F_SUPPRESS_IOPF | IOMMU_DEV_F_IO_PAGE_FAULT_RAISED;
     2892        uint16_t const fSuppressAllIopf = IOMMU_DEV_F_VALID | IOMMU_DEV_F_SUPPRESS_ALL_IOPF;
     2893        if (   (fIoDevFlags & fSuppressAllIopf) == fSuppressAllIopf
     2894            || (fIoDevFlags & fSuppressIopf) == fSuppressIopf)
     2895        {
     2896            fSuppressEvtLogging = true;
    24792897        }
    24802898    }
    24812899    else if (enmOp == IOMMUOP_INTR_REQ)
    24822900    {
    2483         if (   pDte
    2484             && pDte->n.u1IntrMapValid)
    2485             fSuppressEvtLogging = !pDte->n.u1IgnoreUnmappedIntrs;
    2486 
    2487         if (   !fSuppressEvtLogging
    2488             && pIrte)
     2901        uint16_t const fSuppressIopf = IOMMU_DEV_F_VALID | IOMMU_DEV_F_INTR_MAP_VALID | IOMMU_DEV_F_IGNORE_UNMAPPED_INTR;
     2902        if ((fIoDevFlags & fSuppressIopf) == fSuppressIopf)
     2903            fSuppressEvtLogging = true;
     2904        else if (pIrte)
    24892905            fSuppressEvtLogging = pIrte->n.u1SuppressIoPf;
    24902906    }
     
    25152931            {
    25162932                if (!fSuppressEvtLogging)
     2933                {
    25172934                    iommuAmdEvtLogEntryWrite(pDevIns, pEvent);
     2935                    IOMMU_DTE_CACHE_SET_PF_RAISED(pDevIns, pEvtIoPageFault->n.u16DevId);
     2936                }
    25182937                if (enmOp != IOMMUOP_CMD)
    25192938                    iommuAmdSetPciTargetAbort(pDevIns);
     
    25262945            /* Access is blocked and only creates an event log entry. */
    25272946            if (!fSuppressEvtLogging)
     2947            {
    25282948                iommuAmdEvtLogEntryWrite(pDevIns, pEvent);
     2949                IOMMU_DTE_CACHE_SET_PF_RAISED(pDevIns, pEvtIoPageFault->n.u16DevId);
     2950            }
    25292951            break;
    25302952        }
     
    25402962            Assert(enmOp == IOMMUOP_INTR_REQ);
    25412963            if (!fSuppressEvtLogging)
     2964            {
    25422965                iommuAmdEvtLogEntryWrite(pDevIns, pEvent);
     2966                IOMMU_DTE_CACHE_SET_PF_RAISED(pDevIns, pEvtIoPageFault->n.u16DevId);
     2967            }
    25432968            iommuAmdSetPciTargetAbort(pDevIns);
    25442969            break;
     
    25582983            Assert(enmOp != IOMMUOP_TRANSLATE_REQ); /** @todo IOMMU: We don't support translation requests yet. */
    25592984            if (!fSuppressEvtLogging)
     2985            {
    25602986                iommuAmdEvtLogEntryWrite(pDevIns, pEvent);
     2987                IOMMU_DTE_CACHE_SET_PF_RAISED(pDevIns, pEvtIoPageFault->n.u16DevId);
     2988            }
    25612989            if (   enmOp == IOMMUOP_MEM_READ
    25622990                || enmOp == IOMMUOP_MEM_WRITE)
     
    25672995
    25682996    IOMMU_UNLOCK(pDevIns);
     2997
     2998#undef IOMMU_DTE_CACHE_SET_PF_RAISED
     2999}
     3000
     3001
     3002/**
     3003 * Raises an IO_PAGE_FAULT event given the DTE.
     3004 *
     3005 * @param   pDevIns             The IOMMU instance data.
     3006 * @param   pDte                The device table entry.
     3007 * @param   pIrte               The interrupt remapping table entry, can be NULL.
     3008 * @param   enmOp               The IOMMU operation being performed.
     3009 * @param   pEvtIoPageFault     The I/O page fault event.
     3010 * @param   enmEvtType          The I/O page fault event type.
     3011 *
     3012 * @thread  Any.
     3013 */
     3014static void iommuAmdIoPageFaultEventRaiseWithDte(PPDMDEVINS pDevIns, PCDTE_T pDte, PCIRTE_T pIrte, IOMMUOP enmOp,
     3015                                                 PCEVT_IO_PAGE_FAULT_T pEvtIoPageFault, EVT_IO_PAGE_FAULT_TYPE_T enmEvtType)
     3016{
     3017    Assert(pDte);
     3018    uint16_t const fIoDevFlags = iommuAmdGetBasicDevFlags(pDte);
     3019    return iommuAmdIoPageFaultEventRaise(pDevIns, fIoDevFlags, pIrte, enmOp, pEvtIoPageFault, enmEvtType);
    25693020}
    25703021
     
    25753026 * @returns VBox status code.
    25763027 * @param   pDevIns     The IOMMU device instance.
    2577  * @param   uDevId      The device ID.
     3028 * @param   uDevId      The device ID (bus, device, function).
    25783029 * @param   enmOp       The IOMMU operation being performed.
    25793030 * @param   pDte        Where to store the device table entry.
     
    25843035{
    25853036    PCIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     3037
     3038    IOMMU_LOCK(pDevIns);
     3039
     3040    /* Figure out which device table segment is being accessed. */
    25863041    IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis);
    2587 
    2588     /* Figure out which device table segment is being accessed. */
    25893042    uint8_t const idxSegsEn = Ctrl.n.u3DevTabSegEn;
    25903043    Assert(idxSegsEn < RT_ELEMENTS(g_auDevTabSegShifts));
     
    26003053    /* Ensure the DTE falls completely within the device table segment. */
    26013054    uint32_t const cbDevTabSeg  = (pThis->aDevTabBaseAddrs[idxSeg].n.u9Size + 1) << X86_PAGE_4K_SHIFT;
     3055
     3056    IOMMU_UNLOCK(pDevIns);
     3057
    26023058    if (offDte + sizeof(DTE_T) <= cbDevTabSeg)
    26033059    {
     
    26213077    iommuAmdIoPageFaultEventInit(uDevId, 0 /* uDomainId */, 0 /* uIova */, false /* fPresent */, false /* fRsvdNotZero */,
    26223078                                 false /* fPermDenied */, enmOp, &EvtIoPageFault);
    2623     iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, kIoPageFaultType_DevId_Invalid);
     3079    iommuAmdIoPageFaultEventRaise(pDevIns, 0 /* fIoDevFlags */, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3080                                  kIoPageFaultType_DevId_Invalid);
    26243081    return VERR_IOMMU_DTE_BAD_OFFSET;
    26253082}
     
    26303087 *
    26313088 * @returns VBox status code.
     3089 * @retval VINF_SUCCESS if the DTE is valid and supports address translation.
     3090 * @retval VINF_IOMMU_ADDR_TRANSLATION_DISABLED if the DTE is valid but address
     3091 *         translation is disabled.
     3092 * @retval VERR_IOMMU_ADDR_TRANSLATION_FAILED if an error occurred and any
     3093 *         corresponding event was raised.
     3094 * @retval VERR_IOMMU_ADDR_ACCESS_DENIED if the DTE denies the requested
     3095 *         permissions.
     3096 *
    26323097 * @param   pDevIns         The IOMMU device instance.
    26333098 * @param   uIova           The I/O virtual address to translate.
    2634  * @param   uDevId          The device ID.
     3099 * @param   uDevId          The device ID (bus, device, function).
    26353100 * @param   fPerm           The I/O permissions for this access, see
    26363101 *                          IOMMU_IO_PERM_XXX.
    26373102 * @param   pDte            The device table entry.
    26383103 * @param   enmOp           The IOMMU operation being performed.
    2639  * @param   pWalkResult     Where to store the results of the I/O page walk. This is
    2640  *                          only updated when VINF_SUCCESS is returned.
    26413104 *
    26423105 * @thread  Any.
    26433106 */
    26443107static int iommuAmdPreTranslateChecks(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fPerm, PCDTE_T pDte,
    2645                                       IOMMUOP enmOp, PIOWALKRESULT pWalkResult)
     3108                                      IOMMUOP enmOp)
    26463109{
    26473110    /*
     
    26613124        iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, false /* fPresent */, false /* fRsvdNotZero */,
    26623125                                     false /* fPermDenied */, enmOp, &EvtIoPageFault);
    2663         iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
    2664                                       kIoPageFaultType_DteTranslationDisabled);
     3126        iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3127                                             kIoPageFaultType_DteTranslationDisabled);
    26653128        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    26663129    }
     
    26793142        iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */,
    26803143                                     true /* fPermDenied */, enmOp, &EvtIoPageFault);
    2681         iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, kIoPageFaultType_PermDenied);
     3144        iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3145                                             kIoPageFaultType_PermDenied);
    26823146        return VERR_IOMMU_ADDR_ACCESS_DENIED;
    26833147    }
     
    26933157    {
    26943158        Assert((fPerm & fDtePerm) == fPerm);   /* Verify we've checked permissions. */
    2695         pWalkResult->GCPhysSpa = uIova;
    2696         pWalkResult->cShift    = 0;
    2697         pWalkResult->fPerm     = fDtePerm;
    26983159        return VINF_IOMMU_ADDR_TRANSLATION_DISABLED;
    26993160    }
     
    27143175        iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */,
    27153176                                     false /* fPermDenied */, enmOp, &EvtIoPageFault);
    2716         iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
    2717                                       kIoPageFaultType_PteInvalidLvlEncoding);
     3177        iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3178                                             kIoPageFaultType_PteInvalidLvlEncoding);
    27183179        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    27193180    }
     
    27313192 * @param   pDevIns         The IOMMU device instance.
    27323193 * @param   uIova           The I/O virtual address to translate. Must be 4K aligned.
    2733  * @param   uDevId          The device ID.
     3194 * @param   uDevId          The device ID (bus, device, function).
    27343195 * @param   fPerm           The I/O permissions for this access, see
    27353196 *                          IOMMU_IO_PERM_XXX.
     
    27953256            iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, false /* fPresent */, false /* fRsvdNotZero */,
    27963257                                         false /* fPermDenied */, enmOp, &EvtIoPageFault);
    2797             iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, kIoPageFaultType_PermDenied);
     3258            iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3259                                                 kIoPageFaultType_PermDenied);
    27983260            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    27993261        }
     
    28093271            iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */,
    28103272                                         true /* fPermDenied */, enmOp, &EvtIoPageFault);
    2811             iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, kIoPageFaultType_PermDenied);
    2812             return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
     3273            iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3274                                                 kIoPageFaultType_PermDenied);
     3275            return VERR_IOMMU_ADDR_ACCESS_DENIED;
    28133276        }
    28143277
     
    28463309            iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */,
    28473310                                         false /* fPermDenied */, enmOp, &EvtIoPageFault);
    2848             iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
    2849                                           kIoPageFaultType_PteInvalidPageSize);
     3311            iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3312                                                 kIoPageFaultType_PteInvalidPageSize);
    28503313            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    28513314        }
     
    28613324            iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */,
    28623325                                         false /* fPermDenied */, enmOp, &EvtIoPageFault);
    2863             iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
    2864                                           kIoPageFaultType_PteInvalidLvlEncoding);
     3326            iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3327                                                 kIoPageFaultType_PteInvalidLvlEncoding);
    28653328            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    28663329        }
     
    28783341            iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */,
    28793342                                         false /* fPermDenied */, enmOp, &EvtIoPageFault);
    2880             iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
    2881                                           kIoPageFaultType_PteInvalidLvlEncoding);
     3343            iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3344                                                 kIoPageFaultType_PteInvalidLvlEncoding);
    28823345            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    28833346        }
     
    28963359            iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */,
    28973360                                         false /* fPermDenied */, enmOp, &EvtIoPageFault);
    2898             iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
    2899                                           kIoPageFaultType_SkippedLevelIovaNotZero);
     3361            iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3362                                                 kIoPageFaultType_SkippedLevelIovaNotZero);
    29003363            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    29013364        }
     
    29033366        /* Continue with traversing the page directory at this level. */
    29043367    }
    2905 }
    2906 
    2907 
    2908 /**
    2909  * Checks whether two consecutive I/O page walk results translates to a physically
    2910  * contiguous region.
    2911  *
    2912  * @returns @c true if they are physically contiguous, @c false otherwise.
    2913  * @param   pWalkResultPrev     The I/O walk result of the previous page.
    2914  * @param   pWalkResult         The I/O walk result of the current page.
    2915  */
    2916 DECL_FORCE_INLINE(bool) iommuAmdDteLookupIsAddrPhysContig(PCIOWALKRESULT pWalkResultPrev, PCIOWALKRESULT pWalkResult)
    2917 {
    2918     size_t const   cbPrev      = RT_BIT_64(pWalkResultPrev->cShift);
    2919     RTGCPHYS const GCPhysPrev  = pWalkResultPrev->GCPhysSpa;
    2920     RTGCPHYS const GCPhys      = pWalkResult->GCPhysSpa;
    2921     uint64_t const offMaskPrev = ~(UINT64_C(0xffffffffffffffff) << pWalkResultPrev->cShift);
    2922     uint64_t const offMask     = ~(UINT64_C(0xffffffffffffffff) << pWalkResult->cShift);
    2923 
    2924     /* Paranoia: Ensure offset bits are 0. */
    2925     Assert(!(GCPhysPrev & offMaskPrev));
    2926     Assert(!(GCPhys     & offMask));
    2927 
    2928     if ((GCPhysPrev & ~offMaskPrev) + cbPrev == (GCPhys & ~offMask))
    2929         return true;
    2930     return false;
    2931 }
    2932 
    2933 
    2934 /**
    2935  * Checks whether two consecutive I/O page walk results are part of a "contiguous"
    2936  * access.
    2937  *
    2938  * A "contiguous" access is when some range of I/O virtual addresses translate to a
    2939  * physically contiguous region of memory.
    2940  *
    2941  * When IOTLB caching is used, in addition to the translated addresses being
    2942  * physically contiguous, all pages in the access must have identical page sizes and
    2943  * I/O permissions. This is required to simplify IOTLB lookups for large accesses
    2944  * (e.g., ATA device doing 52k transfers on Ubuntu 18.04 guests).
    2945  *
    2946  * @returns @c true if they are contiguous, @c false otherwise.
    2947  * @param   pWalkResultPrev     The I/O walk result of the previous page.
    2948  * @param   pWalkResult         The I/O walk result of the current page.
    2949  */
    2950 DECL_FORCE_INLINE(bool) iommuAmdDteLookupIsAccessContig(PCIOWALKRESULT pWalkResultPrev, PCIOWALKRESULT pWalkResult)
    2951 {
    2952 #ifdef IOMMU_WITH_IOTLBE_CACHE
    2953     if (   pWalkResultPrev->cShift == pWalkResult->cShift
    2954         && pWalkResultPrev->fPerm  == pWalkResult->fPerm
    2955         && iommuAmdDteLookupIsAddrPhysContig(pWalkResultPrev, pWalkResult))
    2956         return true;
    2957     return false;
    2958 #else
    2959     return iommuAmdDteLookupIsAddrPhysContig(pWalkResultPrev, pWalkResult);
    2960 #endif
    2961 }
    2962 
    2963 
    2964 /**
    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  */
    2973 DECL_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
    29823368}
    29833369
     
    29883374 * @returns VBox status code.
    29893375 * @param   pDevIns         The IOMMU instance data.
    2990  * @param   uDevId          The device ID.
     3376 * @param   uDevId          The device ID (bus, device, function).
    29913377 * @param   uIova           The I/O virtual address to lookup.
    29923378 * @param   cbAccess        The size of the access.
     
    30143400    if (RT_SUCCESS(rc))
    30153401    {
    3016         /* If the DTE is not valid, addresses are forwarded without translation */
    30173402        if (Dte.n.u1Valid)
    30183403        {
     
    30233408            {
    30243409                /* 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);
     3410                rc = iommuAmdPreTranslateChecks(pDevIns, uDevId, uIova, fPerm, &Dte, enmOp);
    30283411                if (rc == VINF_SUCCESS)
    30293412                {
     
    30383421                    for (;;)
    30393422                    {
     3423                        /** @todo split this into a separate function and reuse from
     3424                         *        iommuAmdCacheLookup(). */
     3425                        IOWALKRESULT WalkResult;
     3426                        RT_ZERO(WalkResult);
    30403427                        rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fPerm, &Dte, enmOp, &WalkResult);
    30413428                        if (RT_SUCCESS(rc))
     
    30453432                            if (cbRemaining == cbAccess)
    30463433                            {
    3047                                 uint64_t const offMask = ~(UINT64_C(0xffffffffffffffff) << WalkResult.cShift);
     3434                                uint64_t const offMask = IOMMU_GET_PAGE_OFF_MASK(WalkResult.cShift);
    30483435                                uint64_t const offSpa  = uIova & offMask;
    30493436                                Assert(!(WalkResult.GCPhysSpa & offMask));
    30503437                                GCPhysSpa = WalkResult.GCPhysSpa | offSpa;
    3051 
    3052                                 /* Store the walk result from the first page. */
    3053                                 WalkResultPrev = WalkResult;
    30543438                            }
    30553439                            /* Check if addresses translated so far result in a physically contiguous region. */
    3056                             else if (iommuAmdDteLookupIsAccessContig(&WalkResultPrev, &WalkResult))
    3057                                 WalkResultPrev = WalkResult;
    3058                             else
     3440                            else if (!iommuAmdLookupIsAccessContig(&WalkResultPrev, &WalkResult))
    30593441                            {
    30603442                                STAM_COUNTER_INC(&pThis->StatDteLookupNonContig);
     
    30623444                            }
    30633445
     3446                            /* Store the walk result from the first/previous page. */
     3447                            WalkResultPrev = WalkResult;
     3448
     3449                            /* Update size of all pages read thus far. */
     3450                            uint64_t const cbPage = RT_BIT_64(WalkResult.cShift);
     3451                            cbPages += cbPage;
     3452
    30643453                            /* Check if we need to access more pages. */
    3065                             uint64_t const cbPage = RT_BIT_64(WalkResult.cShift);
    30663454                            if (cbRemaining > cbPage - offIova)
    30673455                            {
    30683456                                cbRemaining -= (cbPage - offIova);  /* Calculate how much more we need to access. */
    3069                                 cbPages     += cbPage;              /* Update size of all pages read thus far. */
    30703457                                uIovaPage   += cbPage;              /* Update address of the next access. */
    30713458                                offIova      = 0;                   /* After first page, all pages are accessed from off 0. */
     
    30893476                    cbContiguous = cbAccess - cbRemaining;
    30903477
    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);
     3478#if defined(IN_RING3) && defined(IOMMU_WITH_IOTLBE_CACHE)
     3479                    if (RT_SUCCESS(rc))
     3480                    {
     3481                        /* Update that addresses requires translation (cumulative permissions of DTE and I/O page tables). */
     3482                        IOMMU_LOCK(pDevIns);
     3483                        iommuAmdDteCacheUpdate(pDevIns, uDevId, &Dte, IOMMU_DEV_F_PRESENT | IOMMU_DEV_F_ADDR_TRANSLATE);
     3484
     3485                        /* Update IOTLB for the contiguous range of I/O virtual addresses. */
     3486                        iommuAmdIotlbUpdate(pDevIns, Dte.n.u16DomainId, uIova & X86_PAGE_4K_BASE_MASK, cbPages,
     3487                                            GCPhysSpa & X86_PAGE_4K_BASE_MASK, WalkResultPrev.fPerm);
     3488                        IOMMU_UNLOCK(pDevIns);
     3489                    }
     3490#endif
    30933491                }
    30943492                else if (rc == VINF_IOMMU_ADDR_TRANSLATION_DISABLED)
     
    30983496                     * GPA=SPA, but the permission bits are important and controls accesses.
    30993497                     */
    3100                     /* . */
    31013498                    GCPhysSpa    =  uIova;
    31023499                    cbContiguous = cbAccess;
    31033500                    rc = VINF_SUCCESS;
    31043501
    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);
     3502#if defined(IN_RING3) && defined(IOMMU_WITH_IOTLBE_CACHE)
     3503                    /* Update that addresses permissions of DTE apply (but omit address translation). */
     3504                    IOMMU_LOCK(pDevIns);
     3505                    iommuAmdDteCacheUpdate(pDevIns, uDevId, &Dte, IOMMU_DEV_F_PRESENT | IOMMU_DEV_F_IO_PERM);
     3506                    IOMMU_UNLOCK(pDevIns);
     3507#endif
    31123508                }
    31133509                else
    31143510                {
    3115                     /* Translation failed or access is denied. */
     3511                    /* Address translation failed or access is denied. */
     3512                    Assert(rc == VERR_IOMMU_ADDR_ACCESS_DENIED || rc == VERR_IOMMU_ADDR_TRANSLATION_FAILED);
    31163513                    GCPhysSpa    = NIL_RTGCPHYS;
    31173514                    cbContiguous = 0;
    3118                     Assert(RT_FAILURE(rc));
    31193515                }
    31203516            }
     
    31383534            cbContiguous = cbAccess;
    31393535
    3140             /* Update that addresses don't require translation (nor any permissions). */
    3141             iommuAmdDteLookupUpdate(pThis, uDevId, &Dte, IOMMU_DEV_LOOKUP_F_VALID);
     3536#if defined(IN_RING3) && defined(IOMMU_WITH_IOTLBE_CACHE)
     3537            /* Update that addresses don't require translation (nor permission checks) but a DTE is present. */
     3538            IOMMU_LOCK(pDevIns);
     3539            iommuAmdDteCacheUpdate(pDevIns, uDevId, &Dte, IOMMU_DEV_F_PRESENT);
     3540            IOMMU_UNLOCK(pDevIns);
     3541#endif
    31423542        }
    31433543    }
     
    31553555    return rc;
    31563556}
     3557
     3558
     3559#ifdef IOMMU_WITH_IOTLBE_CACHE
     3560/**
     3561 * Lookups a memory access from the IOMMU cache.
     3562 *
     3563 * @returns VBox status code.
     3564 * @retval  VINF_SUCCESS if the access was cached and permissions are verified.
     3565 * @retval  VERR_OUT_OF_RANGE if the access resulted in a non-contiguous physical
     3566 *          address region.
     3567 * @retval  VERR_NOT_FOUND if the access was not cached.
     3568 * @retval  VERR_IOMMU_ADDR_ACCESS_DENIED if the access was cached but permissions
     3569 *          are insufficient.
     3570 *
     3571 * @param   pDevIns         The IOMMU instance data.
     3572 * @param   uDevId          The device ID (bus, device, function).
     3573 * @param   uIova           The I/O virtual address to lookup.
     3574 * @param   cbAccess        The size of the access.
     3575 * @param   fPerm           The I/O permissions for this access, see
     3576 *                          IOMMU_IO_PERM_XXX.
     3577 * @param   pGCPhysSpa      Where to store the translated system physical address.
     3578 * @param   pcbContiguous   Where to store the number of contiguous bytes translated
     3579 *                          and permission-checked.
     3580 */
     3581static int iommuAmdCacheLookup(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fPerm, IOMMUOP enmOp,
     3582                               PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)
     3583{
     3584    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     3585
     3586    IOMMU_LOCK(pDevIns);
     3587
     3588    /* Lookup the device from the level 1 cache. */
     3589    int rc = VERR_NOT_FOUND;
     3590    PCIODEVICE pDevice = &pThis->paDevices[uDevId];
     3591    if ((pDevice->fFlags & (IOMMU_DEV_F_PRESENT | IOMMU_DEV_F_VALID | IOMMU_DEV_F_ADDR_TRANSLATE))
     3592                        == (IOMMU_DEV_F_PRESENT | IOMMU_DEV_F_VALID | IOMMU_DEV_F_ADDR_TRANSLATE))
     3593    {
     3594        /* Lookup the IOTLB entries from the level 2 cache. */
     3595        RTGCPHYS GCPhysSpa    = NIL_RTGCPHYS;
     3596        size_t   cbContiguous = 0;
     3597        size_t   cbRemaining  = cbAccess;
     3598        uint64_t uIovaPage    = uIova & X86_PAGE_4K_BASE_MASK;
     3599        uint64_t offIova      = uIova & X86_PAGE_4K_OFFSET_MASK;
     3600        IOWALKRESULT WalkResultPrev;
     3601        RT_ZERO(WalkResultPrev);
     3602        for (;;)
     3603        {
     3604            PCIOTLBE pIotlbe = iommuAmdIotlbLookup(pThis, pDevice->uDomainId, uIovaPage);
     3605            if (pIotlbe)
     3606            {
     3607                PCIOWALKRESULT pWalkResult = &pIotlbe->WalkResult;
     3608                if ((pWalkResult->fPerm & fPerm) == fPerm)
     3609                { /* likely */ }
     3610                else
     3611                {
     3612                    EVT_IO_PAGE_FAULT_T EvtIoPageFault;
     3613                    iommuAmdIoPageFaultEventInit(uDevId, pDevice->uDomainId, uIova, true /* fPresent */,
     3614                                                 false /* fRsvdNotZero */, true /* fPermDenied */, enmOp, &EvtIoPageFault);
     3615                    iommuAmdIoPageFaultEventRaise(pDevIns, pDevice->fFlags, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3616                                                  kIoPageFaultType_PermDenied);
     3617                    rc = VERR_IOMMU_ADDR_ACCESS_DENIED;
     3618                    break;
     3619                }
     3620
     3621                /* Store the translated address before continuing to translate more pages. */
     3622                Assert(pWalkResult->cShift >= X86_PAGE_4K_SHIFT);
     3623                if (cbRemaining == cbAccess)
     3624                {
     3625                    uint64_t const offMask = IOMMU_GET_PAGE_OFF_MASK(pWalkResult->cShift);
     3626                    uint64_t const offSpa  = uIova & offMask;
     3627                    Assert(!(pWalkResult->GCPhysSpa & offMask));
     3628                    GCPhysSpa = pWalkResult->GCPhysSpa | offSpa;
     3629                }
     3630                /* Check if addresses translated so far result in a physically contiguous region. */
     3631                else if (!iommuAmdLookupIsAccessContig(&WalkResultPrev, pWalkResult))
     3632                {
     3633                    STAM_COUNTER_INC(&pThis->StatIotlbeLookupNonContig);
     3634                    rc = VERR_OUT_OF_RANGE;
     3635                    break;
     3636                }
     3637
     3638                /* Store the walk result from the first/previous page. */
     3639                WalkResultPrev = *pWalkResult;
     3640
     3641                /* Check if we need to access more pages. */
     3642                uint64_t const cbPage = RT_BIT_64(pWalkResult->cShift);
     3643                if (cbRemaining > cbPage - offIova)
     3644                {
     3645                    cbRemaining -= (cbPage - offIova);  /* Calculate how much more we need to access. */
     3646                    uIovaPage   += cbPage;              /* Update address of the next access. */
     3647                    offIova      = 0;                   /* After first page, all pages are accessed from off 0. */
     3648                }
     3649                else
     3650                {
     3651                    cbRemaining = 0;
     3652                    rc = VINF_SUCCESS;
     3653                    break;
     3654                }
     3655            }
     3656            else
     3657            {
     3658                /*
     3659                 * No IOTLB entry was found for this I/O virtual address.
     3660                 * Fallback to walking the I/O page tables from the beginning of the access.
     3661                 * We currently don't support partial lookups.
     3662                 */
     3663                Assert(rc == VERR_NOT_FOUND);
     3664                break;
     3665            }
     3666        }
     3667
     3668        /* Update how much contiguous memory was accessed. */
     3669        cbContiguous  = cbAccess - cbRemaining;
     3670
     3671        *pGCPhysSpa    = GCPhysSpa;
     3672        *pcbContiguous = cbContiguous;
     3673    }
     3674    else if ((pDevice->fFlags & (IOMMU_DEV_F_PRESENT | IOMMU_DEV_F_VALID | IOMMU_DEV_F_IO_PERM))
     3675                             == (IOMMU_DEV_F_PRESENT | IOMMU_DEV_F_VALID | IOMMU_DEV_F_IO_PERM))
     3676    {
     3677        /* Address translation is disabled, but DTE permissions apply. */
     3678        Assert(!(pDevice->fFlags & IOMMU_DEV_F_ADDR_TRANSLATE));
     3679        uint8_t const fDtePerm = (pDevice->fFlags >> IOMMU_DEV_F_IO_PERM_SHIFT) & IOMMU_DEV_F_IO_PERM_MASK;
     3680        if ((fDtePerm & fPerm) == fPerm)
     3681        {
     3682            *pGCPhysSpa    = uIova;
     3683            *pcbContiguous = cbAccess;
     3684            rc = VINF_SUCCESS;
     3685        }
     3686        else
     3687        {
     3688            *pGCPhysSpa    = NIL_RTGCPHYS;
     3689            *pcbContiguous = 0;
     3690            rc = VERR_IOMMU_ADDR_ACCESS_DENIED;
     3691        }
     3692    }
     3693    else if (pDevice->fFlags & IOMMU_DEV_F_PRESENT)
     3694    {
     3695        /* Forward addresses untranslated, without checking permissions. */
     3696        *pGCPhysSpa    = uIova;
     3697        *pcbContiguous = cbAccess;
     3698        rc = VINF_SUCCESS;
     3699    }
     3700
     3701    IOMMU_UNLOCK(pDevIns);
     3702    return rc;
     3703}
     3704#endif /* IOMMU_WITH_IOTLBE_CACHE */
    31573705
    31583706
     
    31833731    }
    31843732}
    3185 
    3186 
    3187 #ifdef LOG_ENABLED
    3188 /**
    3189  * Gets the descriptive I/O permission name for a memory access.
    3190  *
    3191  * @returns The I/O permission name.
    3192  * @param   fPerm   The I/O permissions for the access, see IOMMU_IO_PERM_XXX.
    3193  */
    3194 DECLINLINE(const char *) iommuAmdMemAccessGetPermName(uint8_t fPerm)
    3195 {
    3196     /* We shouldn't construct an access with "none" or "read+write" (must be read or write) permissions. */
    3197     Assert(fPerm > 0 && fPerm < RT_ELEMENTS(g_aszPerm));
    3198     return g_aszPerm[fPerm];
    3199 }
    3200 #endif  /* LOG_ENABLED */
    32013733
    32023734
     
    32343766        LogFlowFunc(("%s: uDevId=%#x uIova=%#RX64 cb=%zu\n", iommuAmdMemAccessGetPermName(fPerm), uDevId, uIova, cbAccess));
    32353767
    3236         /** @todo IOMMU: IOTLB cache lookup. */
     3768        int rc;
     3769#if defined(IN_RING3) && defined(IOMMU_WITH_IOTLBE_CACHE)
     3770        /* Lookup the IOVA from the cache. */
     3771        rc = iommuAmdCacheLookup(pDevIns, uDevId, uIova, cbAccess, fPerm, enmOp, pGCPhysSpa, pcbContiguous);
     3772        if (rc == VINF_SUCCESS)
     3773        {
     3774            STAM_COUNTER_INC(&pThis->StatIotlbeCacheHit);
     3775            Assert(*pcbContiguous == cbAccess);
     3776            Assert(*pGCPhysSpa != NIL_RTGCPHYS);
     3777            return rc;
     3778        }
     3779        if (rc == VERR_OUT_OF_RANGE)
     3780        {
     3781            Assert(*pcbContiguous > 0 && *pcbContiguous < cbAccess);
     3782            return VINF_SUCCESS;
     3783        }
     3784        if (rc == VERR_IOMMU_ADDR_ACCESS_DENIED)
     3785            return VERR_IOMMU_ADDR_ACCESS_DENIED;
     3786        Assert(rc == VERR_NOT_FOUND);
     3787        STAM_COUNTER_INC(&pThis->StatIotlbeCacheMiss);
     3788        /** @todo r=ramshankar: WARNING! when implementing continuing of lookups because
     3789         *        some entries weren't in the IOTLB, make sure to keep the lock held or to
     3790         *        re-lookup the level 1 cache again because the DTE might be invalidated
     3791         *        in-between! */
     3792#endif
    32373793
    32383794        /* Lookup the IOVA from the device table. */
    3239         int rc = iommuAmdDteLookup(pDevIns, uDevId, uIova, cbAccess, fPerm, enmOp, pGCPhysSpa, pcbContiguous);
     3795        rc = iommuAmdDteLookup(pDevIns, uDevId, uIova, cbAccess, fPerm, enmOp, pGCPhysSpa, pcbContiguous);
    32403796        if (RT_SUCCESS(rc))
    32413797        { /* likely */ }
     
    32433799            LogFunc(("DTE lookup failed! uDevId=%#x uIova=%#RX64 fPerm=%u cbAccess=%zu rc=%#Rrc\n", uDevId, uIova, fPerm,
    32443800                     cbAccess, rc));
     3801
    32453802        return rc;
    32463803    }
     
    33193876 * @returns VBox status code.
    33203877 * @param   pDevIns     The IOMMU device instance.
    3321  * @param   uDevId      The device ID.
     3878 * @param   uDevId      The device ID (bus, device, function).
    33223879 * @param   pDte        The device table entry.
    33233880 * @param   GCPhysIn    The source MSI address (used for reporting errors).
     
    33503907        iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, GCPhysIn, false /* fPresent */, false /* fRsvdNotZero */,
    33513908                                     false /* fPermDenied */, enmOp, &EvtIoPageFault);
    3352         iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteAddrInvalid);
     3909        iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3910                                             kIoPageFaultType_IrteAddrInvalid);
    33533911        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    33543912    }
     
    33743932 * @returns VBox status code.
    33753933 * @param   pDevIns     The IOMMU instance data.
    3376  * @param   uDevId      The device ID.
     3934 * @param   uDevId      The device ID (bus, device, function).
    33773935 * @param   pDte        The device table entry.
    33783936 * @param   enmOp       The IOMMU operation being performed.
     
    34123970                iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable,
    34133971                                             true /* fRsvdNotZero */, false /* fPermDenied */, enmOp, &EvtIoPageFault);
    3414                 iommuAmdIoPageFaultEventRaise(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRsvdIntType);
     3972                iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault,
     3973                                                     kIoPageFaultType_IrteRsvdIntType);
    34153974                return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    34163975            }
     
    34203979            iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable,
    34213980                                         true /* fRsvdNotZero */, false /* fPermDenied */, enmOp, &EvtIoPageFault);
    3422             iommuAmdIoPageFaultEventRaise(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRsvdNotZero);
     3981            iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRsvdNotZero);
    34233982            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    34243983        }
     
    34283987        iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable,
    34293988                                     false /* fRsvdNotZero */, false /* fPermDenied */, enmOp, &EvtIoPageFault);
    3430         iommuAmdIoPageFaultEventRaise(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRemapEn);
     3989        iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRemapEn);
    34313990        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    34323991    }
     
    34414000 * @returns VBox status code.
    34424001 * @param   pDevIns     The IOMMU instance data.
    3443  * @param   uDevId      The device ID.
     4002 * @param   uDevId      The device ID (bus, device, function).
    34444003 * @param   enmOp       The IOMMU operation being performed.
    34454004 * @param   pMsiIn      The source MSI.
     
    37514310        case IOMMU_CMD_INV_DEV_TAB_ENTRY:
    37524311        {
    3753             /** @todo IOMMU: Implement this once we implement IOTLB. Pretend success until
    3754              *        then. */
    37554312            STAM_COUNTER_INC(&pThis->StatCmdInvDte);
     4313#ifdef IOMMU_WITH_IOTLBE_CACHE
     4314            PCCMD_INV_DTE_T pCmdInvDte = (PCCMD_INV_DTE_T)pCmd;
     4315            AssertCompile(sizeof(*pCmdInvDte) == sizeof(*pCmd));
     4316
     4317            /* Validate reserved bits in the command. */
     4318            if (   !(pCmdInvDte->au64[0] & ~IOMMU_CMD_INV_DTE_QWORD_0_VALID_MASK)
     4319                && !(pCmdInvDte->au64[1] & ~IOMMU_CMD_INV_DTE_QWORD_1_VALID_MASK))
     4320            {
     4321                IOMMU_LOCK(pDevIns);
     4322                iommuAmdDteCacheUpdate(pDevIns, pCmdInvDte->n.u16DevId, NULL /* pDte */, 0 /* fFlags */);
     4323                IOMMU_UNLOCK(pDevIns);
     4324                return VINF_SUCCESS;
     4325            }
     4326            iommuAmdIllegalCmdEventInit(GCPhysCmd, (PEVT_ILLEGAL_CMD_ERR_T)pEvtError);
     4327            return VERR_IOMMU_CMD_INVALID_FORMAT;
     4328#else
    37564329            return VINF_SUCCESS;
     4330#endif
    37574331        }
    37584332
     
    37704344                uint64_t const uIova = RT_MAKE_U64(pCmdInvPages->n.u20AddrLo << X86_PAGE_4K_SHIFT, pCmdInvPages->n.u32AddrHi);
    37714345                uint16_t const uDomainId = pCmdInvPages->n.u16DomainId;
     4346                bool const     fFlushPde = pCmdInvPages->n.u1PageDirEntries;
    37724347                uint8_t cShift;
    37734348                if (!pCmdInvPages->n.u1Size)
     
    37784353                    unsigned const uFirstZeroBit = ASMBitLastSetU64(~(uIova >> X86_PAGE_4K_SHIFT));
    37794354                    cShift = X86_PAGE_4K_SHIFT + uFirstZeroBit;
     4355
     4356                    /*
     4357                     * For the address 0x7ffffffffffff000, cShift would be 76 (12+64) and the code below
     4358                     * would do the right thing by clearing the entire cache for the specified domain ID.
     4359                     *
     4360                     * However, for the address 0xfffffffffffff000, cShift would be computed as 12.
     4361                     * IOMMU behavior is undefined in this case, so it's safe to invalidate just one page.
     4362                     * A debug-time assert is in place here to let us know if any software tries this.
     4363                     *
     4364                     * See AMD IOMMU spec. 2.4.3 "INVALIDATE_IOMMU_PAGES".
     4365                     * See AMD IOMMU spec. Table 14: "Example Page Size Encodings".
     4366                     */
     4367                    Assert(uIova != UINT64_C(0xfffffffffffff000));
    37804368                }
    37814369
    37824370                IOMMU_LOCK(pDevIns);
    3783                 iommuAmdIotlbRemoveRange(pThis, uDomainId, uIova, cShift);
     4371
     4372                /*
     4373                 * Validate invalidation size.
     4374                 * See AMD IOMMU spec. 2.2.3 "I/O Page Tables for Host Translations".
     4375                 */
     4376                if (   cShift == 12 /* 4K  */ || cShift == 13 /* 8K  */
     4377                    || cShift == 14 /* 16K */ || cShift == 20 /* 1M  */
     4378                    || cShift == 22 /* 4M  */ || cShift == 32 /* 4G  */)
     4379                {
     4380                    /* Remove the range of I/O virtual addresses requesting to be invalidated. */
     4381                    size_t const cbAccess = RT_BIT_64(cShift);
     4382                    iommuAmdIotlbRemoveRange(pThis, uDomainId, uIova, cbAccess);
     4383                }
     4384                else
     4385                {
     4386                    /*
     4387                     * The guest provided size is invalid or exceeds the largest, meaningful page size.
     4388                     * In such situations we must remove all ranges for the specified domain ID.
     4389                     */
     4390                    iommuAmdIotlbRemoveDomainId(pThis, uDomainId);
     4391                }
     4392
    37844393                IOMMU_UNLOCK(pDevIns);
    37854394                return VINF_SUCCESS;
     
    38394448        {
    38404449            STAM_COUNTER_INC(&pThis->StatCmdInvIommuAll);
    3841 
    38424450            if (pThis->ExtFeat.n.u1InvAllSup)
    38434451            {
    3844                 /** @todo IOMMU: Invalidate all. Pretend success until then. */
     4452#ifdef IOMMU_WITH_IOTLBE_CACHE
     4453                PCCMD_INV_IOMMU_ALL_T pCmdInvAll = (PCCMD_INV_IOMMU_ALL_T)pCmd;
     4454                AssertCompile(sizeof(*pCmdInvAll) == sizeof(*pCmd));
     4455
     4456                /* Validate reserved bits in the command. */
     4457                if (   !(pCmdInvAll->au64[0] & ~IOMMU_CMD_INV_IOMMU_ALL_QWORD_0_VALID_MASK)
     4458                    && !(pCmdInvAll->au64[1] & ~IOMMU_CMD_INV_IOMMU_ALL_QWORD_1_VALID_MASK))
     4459                {
     4460                    IOMMU_LOCK(pDevIns);
     4461                    iommuAmdDteCacheRemoveAll(pDevIns);
     4462                    iommuAmdIotlbRemoveAll(pDevIns);
     4463                    IOMMU_UNLOCK(pDevIns);
     4464                    return VINF_SUCCESS;
     4465                }
     4466                iommuAmdIllegalCmdEventInit(GCPhysCmd, (PEVT_ILLEGAL_CMD_ERR_T)pEvtError);
     4467                return VERR_IOMMU_CMD_NOT_SUPPORTED;
     4468#else
    38454469                return VINF_SUCCESS;
     4470#endif
    38464471            }
    38474472            iommuAmdIllegalCmdEventInit(GCPhysCmd, (PEVT_ILLEGAL_CMD_ERR_T)pEvtError);
     
    47295354    pHlp->pfnPrintf(pHlp, "%sAllow Exclusion            = %RTbool\n", pszPrefix, pDte->n.u1AllowExclusion);
    47305355    pHlp->pfnPrintf(pHlp, "%sSysMgt Message Enable      = %RTbool\n", pszPrefix, pDte->n.u2SysMgt);
    4731     pHlp->pfnPrintf(pHlp, "\n");
    4732 
    47335356    pHlp->pfnPrintf(pHlp, "%sInterrupt Map Valid        = %RTbool\n", pszPrefix, pDte->n.u1IntrMapValid);
    47345357    uint8_t const uIntrTabLen = pDte->n.u4IntrTableLength;
     
    47585381    pHlp->pfnPrintf(pHlp, "%sMode0FC                    = %#x\n",     pszPrefix, pDte->n.u1Mode0FC);
    47595382    pHlp->pfnPrintf(pHlp, "%sSnoop Attribute            = %#x\n",     pszPrefix, pDte->n.u8SnoopAttr);
     5383    pHlp->pfnPrintf(pHlp, "\n");
    47605384}
    47615385
     
    47735397        {
    47745398            DTE_T Dte;
     5399            IOMMU_LOCK_NORET(pDevIns);
    47755400            rc = iommuAmdDteRead(pDevIns, uDevId, IOMMUOP_TRANSLATE_REQ,  &Dte);
     5401            IOMMU_UNLOCK(pDevIns);
    47765402            if (RT_SUCCESS(rc))
    47775403            {
     
    47805406                return;
    47815407            }
    4782 
    47835408            pHlp->pfnPrintf(pHlp, "Failed to read DTE for device ID %u (%#x). rc=%Rrc\n", uDevId, uDevId, rc);
    47845409        }
     
    47915416
    47925417
    4793 #if 0
     5418#if defined(IN_RING3) && defined(IOMMU_WITH_IOTLBE_CACHE)
     5419/**
     5420 * @callback_method_impl{FNDBGFHANDLERDEV}
     5421 */
     5422static DECLCALLBACK(void) iommuAmdR3DbgInfoIotlb(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
     5423{
     5424    if (pszArgs)
     5425    {
     5426        uint16_t uDomainId = 0;
     5427        int rc = RTStrToUInt16Full(pszArgs, 0 /* uBase */, &uDomainId);
     5428        if (RT_SUCCESS(rc))
     5429        {
     5430            pHlp->pfnPrintf(pHlp, "IOTLBEs for domain %u (%#x):\n", uDomainId, uDomainId);
     5431            PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     5432            IOTLBEINFOARG Args;
     5433            Args.pIommu    = pThis;
     5434            Args.pHlp      = pHlp;
     5435            Args.uDomainId = uDomainId;
     5436            IOMMU_LOCK_NORET(pDevIns);
     5437            RTAvlU64DoWithAll(&pThis->TreeIotlbe, true /* fFromLeft */, iommuAmdR3IotlbEntryInfo, &Args);
     5438            IOMMU_UNLOCK(pDevIns);
     5439        }
     5440        else
     5441            pHlp->pfnPrintf(pHlp, "Failed to parse a valid 16-bit domain ID. rc=%Rrc\n", rc);
     5442    }
     5443    else
     5444        pHlp->pfnPrintf(pHlp, "Missing domain ID.\n");
     5445}
     5446#endif
     5447
     5448
    47945449/**
    47955450 * @callback_method_impl{FNDBGFHANDLERDEV}
     
    48035458    PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
    48045459
    4805     uint8_t cTables = 0;
     5460    uint8_t cSegments = 0;
    48065461    for (uint8_t i = 0; i < RT_ELEMENTS(pThis->aDevTabBaseAddrs); i++)
    48075462    {
    4808         DEV_TAB_BAR_T  DevTabBar    = pThis->aDevTabBaseAddrs[i];
    4809         RTGCPHYS const GCPhysDevTab = DevTabBar.n.u40Base << X86_PAGE_4K_SHIFT;
     5463        DEV_TAB_BAR_T const DevTabBar = pThis->aDevTabBaseAddrs[i];
     5464        RTGCPHYS const GCPhysDevTab   = DevTabBar.n.u40Base << X86_PAGE_4K_SHIFT;
    48105465        if (GCPhysDevTab)
    4811             ++cTables;
    4812     }
    4813 
    4814     pHlp->pfnPrintf(pHlp, "AMD-IOMMU Device Tables:\n");
    4815     pHlp->pfnPrintf(pHlp, " Tables active: %u\n", cTables);
    4816     if (!cTables)
     5466            ++cSegments;
     5467    }
     5468
     5469    pHlp->pfnPrintf(pHlp, "AMD-IOMMU device tables with address translations enabled:\n");
     5470    pHlp->pfnPrintf(pHlp, " DTE Segments=%u\n", cSegments);
     5471    if (!cSegments)
    48175472        return;
    48185473
    48195474    for (uint8_t i = 0; i < RT_ELEMENTS(pThis->aDevTabBaseAddrs); i++)
    48205475    {
    4821         DEV_TAB_BAR_T  DevTabBar    = pThis->aDevTabBaseAddrs[i];
    4822         RTGCPHYS const GCPhysDevTab = DevTabBar.n.u40Base << X86_PAGE_4K_SHIFT;
     5476        DEV_TAB_BAR_T const DevTabBar = pThis->aDevTabBaseAddrs[i];
     5477        RTGCPHYS const GCPhysDevTab   = DevTabBar.n.u40Base << X86_PAGE_4K_SHIFT;
    48235478        if (GCPhysDevTab)
    48245479        {
    48255480            uint32_t const cbDevTab = IOMMU_GET_DEV_TAB_LEN(&DevTabBar);
    48265481            uint32_t const cDtes    = cbDevTab / sizeof(DTE_T);
    4827             pHlp->pfnPrintf(pHlp, " Table %u (base=%#RGp size=%u bytes entries=%u):\n", i, GCPhysDevTab, cbDevTab, cDtes);
    48285482
    48295483            void *pvDevTab = RTMemAllocZ(cbDevTab);
     
    48355489                    for (uint32_t idxDte = 0; idxDte < cDtes; idxDte++)
    48365490                    {
    4837                         PCDTE_T pDte = (PCDTE_T)((char *)pvDevTab + idxDte * sizeof(DTE_T));
     5491                        PCDTE_T pDte = (PCDTE_T)((uintptr_t)pvDevTab + idxDte * sizeof(DTE_T));
    48385492                        if (   pDte->n.u1Valid
    4839                             || pDte->n.u1IntrMapValid)
     5493                            && pDte->n.u1TranslationValid
     5494                            && pDte->n.u3Mode != 0)
    48405495                        {
    4841                             pHlp->pfnPrintf(pHlp, " DTE %u:\n", idxDte);
     5496                            pHlp->pfnPrintf(pHlp, " DTE %u (BDF %02x:%02x.%d)\n", idxDte,
     5497                                            (idxDte >> VBOX_PCI_BUS_SHIFT) & VBOX_PCI_BUS_MASK,
     5498                                            (idxDte >> VBOX_PCI_DEVFN_DEV_SHIFT) & VBOX_PCI_DEVFN_DEV_MASK,
     5499                                            idxDte & VBOX_PCI_DEVFN_FUN_MASK);
    48425500                            iommuAmdR3DbgInfoDteWorker(pHlp, pDte, " ");
     5501                            pHlp->pfnPrintf(pHlp, "\n");
    48435502                        }
    48445503                    }
     
    48475506                else
    48485507                {
    4849                     pHlp->pfnPrintf(pHlp, " Failed to read table at %#RGp of size %u bytes. rc=%Rrc!\n", GCPhysDevTab,
     5508                    pHlp->pfnPrintf(pHlp, " Failed to read table at %#RGp of size %zu bytes. rc=%Rrc!\n", GCPhysDevTab,
    48505509                                    cbDevTab, rc);
    48515510                }
     
    48555514            else
    48565515            {
    4857                 pHlp->pfnPrintf(pHlp, " Allocating %u bytes for reading the device table failed!\n", cbDevTab);
     5516                pHlp->pfnPrintf(pHlp, " Allocating %zu bytes for reading the device table failed!\n", cbDevTab);
    48585517                return;
    48595518            }
     
    48615520    }
    48625521}
    4863 #endif
    48645522
    48655523
     
    49895647    LogFlowFunc(("\n"));
    49905648
     5649    IOMMU_LOCK_NORET(pDevIns);
     5650
    49915651    /* Close the command thread semaphore. */
    49925652    if (pThis->hEvtCmdThread != NIL_SUPSEMEVENT)
     
    50075667    if (pThis->paIotlbes)
    50085668    {
    5009         iommuAmdIotlbRemoveAll(pThis);
     5669        iommuAmdIotlbRemoveAll(pDevIns);
    50105670        PDMDevHlpMMHeapFree(pDevIns, pThis->paIotlbes);
    50115671        pThis->paIotlbes = NULL;
     
    50135673#endif
    50145674
     5675    IOMMU_UNLOCK(pDevIns);
    50155676    return VINF_SUCCESS;
    50165677}
     
    51855846    PDMDevHlpDBGFInfoRegister(pDevIns, "iommu",    "Display IOMMU state.", iommuAmdR3DbgInfo);
    51865847    PDMDevHlpDBGFInfoRegister(pDevIns, "iommudte", "Display the DTE for a device. Arguments: DeviceID.", iommuAmdR3DbgInfoDte);
    5187 #if 0
    5188     PDMDevHlpDBGFInfoRegister(pDevIns, "iommudevtabs", "Display IOMMU device tables.", iommuAmdR3DbgInfoDevTabs);
     5848    PDMDevHlpDBGFInfoRegister(pDevIns, "iommudevtabs", "Display active IOMMU device tables.", iommuAmdR3DbgInfoDevTabs);
     5849#ifdef IOMMU_WITH_IOTLBE_CACHE
     5850    PDMDevHlpDBGFInfoRegister(pDevIns, "iommutlb", "Display IOTLBs for a domain. Arguments: DomainID.", iommuAmdR3DbgInfoIotlb);
    51895851#endif
    51905852
     
    52245886    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatCmdInvIommuAll, STAMTYPE_COUNTER, "R3/Commands/InvIommuAll", STAMUNIT_OCCURENCES, "Number of Invalidate IOMMU All commands processed.");
    52255887
    5226     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatDteLookupNonContig, STAMTYPE_COUNTER, "DteLookupNonContig", STAMUNIT_OCCURENCES, "Number of non-contiguous translated regions.");
    5227 
    5228     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatDteLookup, STAMTYPE_PROFILE, "DteLookup", STAMUNIT_TICKS_PER_CALL, "Profiling device table entry lookup (uncached).");
     5888    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeLookupNonContig, STAMTYPE_COUNTER, "IOTLB/LookupNonContig", STAMUNIT_OCCURENCES, "IOTLB lookups that resulted in non-contiguous translated regions.");
     5889    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeCached, STAMTYPE_COUNTER, "IOTLB/Cached", STAMUNIT_OCCURENCES, "Number of IOTLB entries in the cache.");
     5890    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeCacheHit, STAMTYPE_COUNTER, "IOTLB/CacheHit", STAMUNIT_OCCURENCES, "Number of IOTLB cache hits.");
     5891    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeCacheMiss, STAMTYPE_COUNTER, "IOTLB/CacheMiss", STAMUNIT_OCCURENCES, "Number of IOTLB cache misses.");
     5892    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIotlbeLazyEvictReuse, STAMTYPE_COUNTER, "IOTLB/LazyEvictReuse", STAMUNIT_OCCURENCES, "Number of IOTLB entries reused after lazy eviction.");
     5893
     5894    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatDteLookupNonContig, STAMTYPE_COUNTER, "DTE/LookupNonContig", STAMUNIT_OCCURENCES, "DTE lookups that resulted in non-contiguous translated regions.");
     5895    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatDteLookup, STAMTYPE_PROFILE, "DTE/Lookup", STAMUNIT_TICKS_PER_CALL, "Profiling device table entry lookup (uncached).");
    52295896# endif
    52305897
     
    52495916     * of how code, features and devices around the IOMMU changes.
    52505917     */
    5251     size_t const cbDevices = sizeof(IODEVICE) * UINT16_MAX;
     5918    size_t const cbDevices = sizeof(IODEVICE) * IOMMU_DTE_CACHE_MAX;
     5919    AssertCompile(IOMMU_DTE_CACHE_MAX >= UINT16_MAX);
    52525920    pThis->paDevices = (PIODEVICE)PDMDevHlpMMHeapAllocZ(pDevIns, cbDevices);
    52535921    if (!pThis->paDevices)
     
    53616029    PIOMMU   pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
    53626030    PIOMMUCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC);
    5363 
    53646031    pThisCC->CTX_SUFF(pDevIns) = pDevIns;
    53656032
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