Changeset 87666 in vbox for trunk/src/VBox/Devices/Bus
- Timestamp:
- Feb 9, 2021 5:08:04 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 142708
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r87528 r87666 28 28 #include <iprt/x86.h> 29 29 #include <iprt/string.h> 30 #include <iprt/avl.h> 30 31 #ifdef IN_RING3 31 32 # include <iprt/mem.h> … … 49 50 50 51 #ifdef IOMMU_WITH_IOTLBE_CACHE 52 /** The maximum number of DTE entries. */ 53 # define IOMMU_DTE_CACHE_MAX UINT16_MAX 51 54 /** The maximum number of IOTLB entries. */ 52 # define IOMMU_IOTLBE_MAX 51253 /** The mask of bits for the domain ID ofthe IOTLBE key. */55 # define IOMMU_IOTLBE_MAX 128 56 /** The mask of bits covering the domain ID in the IOTLBE key. */ 54 57 # 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) 55 60 /** The number of bits to shift for the domain ID of the IOTLBE key. */ 56 61 # 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)) 57 79 #endif 58 80 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() 60 99 * @{ */ 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) 67 124 /** @} */ 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))) 68 132 69 133 … … 107 171 #define IOMMU_ASSERT_LOCKED(a_pDevIns) \ 108 172 do { \ 109 Assert(PDMDevHlpCritSectIsOwner( pDevIns, pDevIns->CTX_SUFF(pCritSectRo))); \173 Assert(PDMDevHlpCritSectIsOwner((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo))); \ 110 174 } while (0) 111 175 … … 115 179 #define IOMMU_ASSERT_NOT_LOCKED(a_pDevIns) \ 116 180 do { \ 117 Assert(!PDMDevHlpCritSectIsOwner( pDevIns, pDevIns->CTX_SUFF(pCritSectRo))); \181 Assert(!PDMDevHlpCritSectIsOwner((a_pDevIns), (a_pDevIns)->CTX_SUFF(pCritSectRo))); \ 118 182 } while (0) 119 183 … … 134 198 IOMMUOP_CMD 135 199 } IOMMUOP; 136 AssertCompileSize(IOMMUOP, 4);137 200 /** Pointer to a IOMMU operation. */ 138 201 typedef IOMMUOP *PIOMMUOP; … … 147 210 /** The number of offset bits in the system physical address. */ 148 211 uint8_t cShift; 149 /** The I/O permissions allowedfor this translation, see IOMMU_IO_PERM_XXX. */212 /** The I/O permissions for this translation, see IOMMU_IO_PERM_XXX. */ 150 213 uint8_t fPerm; 151 /** Padding. */152 uint8_t abPadding[2];153 214 } IOWALKRESULT; 154 215 /** Pointer to an I/O walk result struct. */ 155 216 typedef IOWALKRESULT *PIOWALKRESULT; 156 217 /** 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) 218 typedef IOWALKRESULT const *PCIOWALKRESULT; 219 220 /** 221 * IOMMU I/O Device. 222 * Used for caching as well as passing flags to events. 223 */ 163 224 typedef struct IODEVICE 164 225 { 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; 169 228 /** The domain ID assigned for this device by software. */ 170 229 uint16_t uDomainId; 171 230 } IODEVICE; 172 #pragma pack()173 231 /** Pointer to an I/O device struct. */ 174 232 typedef IODEVICE *PIODEVICE; … … 177 235 AssertCompileSize(IODEVICE, 4); 178 236 237 #ifdef IOMMU_WITH_IOTLBE_CACHE 179 238 /** 180 239 * IOMMU I/O TLB Entry. … … 183 242 typedef struct IOTLBE 184 243 { 185 /** The AVL tree core. */186 AVL RU64NODECORECore;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. */ 188 247 RTLISTNODE NdLru; 189 248 /** The I/O walk result of the translation. */ 190 249 IOWALKRESULT WalkResult; 250 /** Whether the entry needs to be evicted from the cache. */ 251 bool fEvictPending; 191 252 } IOTLBE; 192 AssertCompileSizeAlignment(IOTLBE, 8);193 253 /** Pointer to an IOMMU I/O TLB entry struct. */ 194 254 typedef IOTLBE *PIOTLBE; 195 255 /** Pointer to a const IOMMU I/O TLB entry struct. */ 196 256 typedef IOTLBE const *PCIOTLBE; 257 AssertCompileSizeAlignment(IOTLBE, 8); 258 AssertCompileMemberOffset(IOTLBE, Core, 0); 259 #endif /* IOMMU_WITH_IOTLBE_CACHE */ 197 260 198 261 /** … … 223 286 /** L1 Cache - Maps [DeviceId] to [DomainId]. */ 224 287 PIODEVICE paDevices; 225 /** Pointer to array of allocated IOTLBEs. */288 /** Pointer to array of pre-allocated IOTLBEs. */ 226 289 PIOTLBE paIotlbes; 227 290 /** L2 Cache - Maps [DomainId,Iova] to [IOTLBE]. */ 228 AVL RU64TREETreeIotlbe;291 AVLU64TREE TreeIotlbe; 229 292 /** LRU list anchor for IOTLB entries. */ 230 293 RTLISTANCHOR LstLruIotlbe; … … 384 447 STAMCOUNTER StatCmdInvIommuAll; /**< Number of Invalidate IOMMU All commands processed. */ 385 448 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. */ 387 456 STAMPROFILEADV StatDteLookup; /**< Profiling of device table entry lookup (uncached). */ 388 457 /** @} */ … … 468 537 typedef IOMMUREGACC const *PCIOMMUREGACC; 469 538 539 #ifdef IOMMU_WITH_IOTLBE_CACHE 540 /** 541 * IOTLBE flush argument. 542 */ 543 typedef 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. */ 551 typedef IOTLBEFLUSHARG *PIOTLBEFLUSHARG; 552 /** Pointer to a const IOTLBE flush argument. */ 553 typedef IOTLBEFLUSHARG const *PCIOTLBEFLUSHARG; 554 555 /** 556 * IOTLBE Info. argument. 557 */ 558 typedef 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. */ 568 typedef IOTLBEINFOARG *PIOTLBEINFOARG; 569 /** Pointer to a const IOTLBE flush argument. */ 570 typedef IOTLBEINFOARG const *PCIOTLBEINFOARG; 571 #endif 572 470 573 471 574 /********************************************************************************************************************************* … … 498 601 * The IOMMU I/O permission names. 499 602 */ 500 static const char * const g_aszPerm[] = { "none", "read", "write" };603 static const char * const g_aszPerm[] = { "none", "read", "write", "read+write" }; 501 604 502 605 … … 548 651 549 652 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 */ 659 static 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 550 667 #if 0 551 668 /** … … 568 685 569 686 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 */ 695 static 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 */ 720 static 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 570 749 #ifdef IOMMU_WITH_IOTLBE_CACHE 571 750 /** 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 */ 756 static 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 */ 772 static 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 */ 790 static 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 578 820 return VINF_SUCCESS; 579 821 } 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 */ 832 static 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 */ 861 static 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 */ 906 static 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 */ 925 static 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 */ 943 static 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 */ 974 static 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 */ 1026 static 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 */ 1052 static 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 */ 1080 static 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. 587 1099 * @param uDomainId The domain ID. 588 1100 * @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 */ 1105 static void iommuAmdIotlbUpdate(PPDMDEVINS pDevIns, uint16_t uDomainId, uint64_t uIova, size_t cbAccess, RTGCPHYS GCPhysSpa, 1106 uint8_t fPerm) 629 1107 { 630 1108 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 */ 1146 static 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; 672 1156 } 673 1157 else 674 1158 { 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 */ 1172 static 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 */ 1187 static 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); 780 1194 } 781 1195 #endif /* IOMMU_WITH_IOTLBE_CACHE */ … … 2160 2574 * Initializes a PAGE_TAB_HARDWARE_ERROR event. 2161 2575 * 2162 * @param uDevId The device ID .2576 * @param uDevId The device ID (bus, device, function). 2163 2577 * @param uDomainId The domain ID. 2164 2578 * @param GCPhysPtEntity The system physical address of the page table … … 2258 2672 * Initializes a DEV_TAB_HARDWARE_ERROR event. 2259 2673 * 2260 * @param uDevId The device ID .2674 * @param uDevId The device ID (bus, device, function). 2261 2675 * @param GCPhysDte The system physical address of the failed device table 2262 2676 * access. … … 2351 2765 * Initializes an ILLEGAL_DEV_TABLE_ENTRY event. 2352 2766 * 2353 * @param uDevId The device ID .2767 * @param uDevId The device ID (bus, device, function). 2354 2768 * @param uIova The I/O virtual address. 2355 2769 * @param fRsvdNotZero Whether reserved bits are not zero. Pass @c false if the … … 2409 2823 * Initializes an IO_PAGE_FAULT event. 2410 2824 * 2411 * @param uDevId The device ID .2825 * @param uDevId The device ID (bus, device, function). 2412 2826 * @param uDomainId The domain ID. 2413 2827 * @param uIova The I/O virtual address being accessed. … … 2448 2862 * 2449 2863 * @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. 2454 2866 * @param enmOp The IOMMU operation being performed. 2455 2867 * @param pEvtIoPageFault The I/O page fault event. … … 2458 2870 * @thread Any. 2459 2871 */ 2460 static void iommuAmdIoPageFaultEventRaise(PPDMDEVINS pDevIns, PCDTE_T pDte, PCIRTE_T pIrte, IOMMUOP enmOp,2872 static void iommuAmdIoPageFaultEventRaise(PPDMDEVINS pDevIns, uint16_t fIoDevFlags, PCIRTE_T pIrte, IOMMUOP enmOp, 2461 2873 PCEVT_IO_PAGE_FAULT_T pEvtIoPageFault, EVT_IO_PAGE_FAULT_TYPE_T enmEvtType) 2462 2874 { 2463 2875 AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_IO_PAGE_FAULT_T)); 2464 2876 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 2465 2884 2466 2885 IOMMU_LOCK_NORET(pDevIns); … … 2470 2889 || enmOp == IOMMUOP_MEM_WRITE) 2471 2890 { 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; 2479 2897 } 2480 2898 } 2481 2899 else if (enmOp == IOMMUOP_INTR_REQ) 2482 2900 { 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) 2489 2905 fSuppressEvtLogging = pIrte->n.u1SuppressIoPf; 2490 2906 } … … 2515 2931 { 2516 2932 if (!fSuppressEvtLogging) 2933 { 2517 2934 iommuAmdEvtLogEntryWrite(pDevIns, pEvent); 2935 IOMMU_DTE_CACHE_SET_PF_RAISED(pDevIns, pEvtIoPageFault->n.u16DevId); 2936 } 2518 2937 if (enmOp != IOMMUOP_CMD) 2519 2938 iommuAmdSetPciTargetAbort(pDevIns); … … 2526 2945 /* Access is blocked and only creates an event log entry. */ 2527 2946 if (!fSuppressEvtLogging) 2947 { 2528 2948 iommuAmdEvtLogEntryWrite(pDevIns, pEvent); 2949 IOMMU_DTE_CACHE_SET_PF_RAISED(pDevIns, pEvtIoPageFault->n.u16DevId); 2950 } 2529 2951 break; 2530 2952 } … … 2540 2962 Assert(enmOp == IOMMUOP_INTR_REQ); 2541 2963 if (!fSuppressEvtLogging) 2964 { 2542 2965 iommuAmdEvtLogEntryWrite(pDevIns, pEvent); 2966 IOMMU_DTE_CACHE_SET_PF_RAISED(pDevIns, pEvtIoPageFault->n.u16DevId); 2967 } 2543 2968 iommuAmdSetPciTargetAbort(pDevIns); 2544 2969 break; … … 2558 2983 Assert(enmOp != IOMMUOP_TRANSLATE_REQ); /** @todo IOMMU: We don't support translation requests yet. */ 2559 2984 if (!fSuppressEvtLogging) 2985 { 2560 2986 iommuAmdEvtLogEntryWrite(pDevIns, pEvent); 2987 IOMMU_DTE_CACHE_SET_PF_RAISED(pDevIns, pEvtIoPageFault->n.u16DevId); 2988 } 2561 2989 if ( enmOp == IOMMUOP_MEM_READ 2562 2990 || enmOp == IOMMUOP_MEM_WRITE) … … 2567 2995 2568 2996 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 */ 3014 static 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); 2569 3020 } 2570 3021 … … 2575 3026 * @returns VBox status code. 2576 3027 * @param pDevIns The IOMMU device instance. 2577 * @param uDevId The device ID .3028 * @param uDevId The device ID (bus, device, function). 2578 3029 * @param enmOp The IOMMU operation being performed. 2579 3030 * @param pDte Where to store the device table entry. … … 2584 3035 { 2585 3036 PCIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 3037 3038 IOMMU_LOCK(pDevIns); 3039 3040 /* Figure out which device table segment is being accessed. */ 2586 3041 IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis); 2587 2588 /* Figure out which device table segment is being accessed. */2589 3042 uint8_t const idxSegsEn = Ctrl.n.u3DevTabSegEn; 2590 3043 Assert(idxSegsEn < RT_ELEMENTS(g_auDevTabSegShifts)); … … 2600 3053 /* Ensure the DTE falls completely within the device table segment. */ 2601 3054 uint32_t const cbDevTabSeg = (pThis->aDevTabBaseAddrs[idxSeg].n.u9Size + 1) << X86_PAGE_4K_SHIFT; 3055 3056 IOMMU_UNLOCK(pDevIns); 3057 2602 3058 if (offDte + sizeof(DTE_T) <= cbDevTabSeg) 2603 3059 { … … 2621 3077 iommuAmdIoPageFaultEventInit(uDevId, 0 /* uDomainId */, 0 /* uIova */, false /* fPresent */, false /* fRsvdNotZero */, 2622 3078 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); 2624 3081 return VERR_IOMMU_DTE_BAD_OFFSET; 2625 3082 } … … 2630 3087 * 2631 3088 * @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 * 2632 3097 * @param pDevIns The IOMMU device instance. 2633 3098 * @param uIova The I/O virtual address to translate. 2634 * @param uDevId The device ID .3099 * @param uDevId The device ID (bus, device, function). 2635 3100 * @param fPerm The I/O permissions for this access, see 2636 3101 * IOMMU_IO_PERM_XXX. 2637 3102 * @param pDte The device table entry. 2638 3103 * @param enmOp The IOMMU operation being performed. 2639 * @param pWalkResult Where to store the results of the I/O page walk. This is2640 * only updated when VINF_SUCCESS is returned.2641 3104 * 2642 3105 * @thread Any. 2643 3106 */ 2644 3107 static int iommuAmdPreTranslateChecks(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fPerm, PCDTE_T pDte, 2645 IOMMUOP enmOp , PIOWALKRESULT pWalkResult)3108 IOMMUOP enmOp) 2646 3109 { 2647 3110 /* … … 2661 3124 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, false /* fPresent */, false /* fRsvdNotZero */, 2662 3125 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); 2665 3128 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2666 3129 } … … 2679 3142 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2680 3143 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); 2682 3146 return VERR_IOMMU_ADDR_ACCESS_DENIED; 2683 3147 } … … 2693 3157 { 2694 3158 Assert((fPerm & fDtePerm) == fPerm); /* Verify we've checked permissions. */ 2695 pWalkResult->GCPhysSpa = uIova;2696 pWalkResult->cShift = 0;2697 pWalkResult->fPerm = fDtePerm;2698 3159 return VINF_IOMMU_ADDR_TRANSLATION_DISABLED; 2699 3160 } … … 2714 3175 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2715 3176 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); 2718 3179 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2719 3180 } … … 2731 3192 * @param pDevIns The IOMMU device instance. 2732 3193 * @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). 2734 3195 * @param fPerm The I/O permissions for this access, see 2735 3196 * IOMMU_IO_PERM_XXX. … … 2795 3256 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, false /* fPresent */, false /* fRsvdNotZero */, 2796 3257 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); 2798 3260 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2799 3261 } … … 2809 3271 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2810 3272 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; 2813 3276 } 2814 3277 … … 2846 3309 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2847 3310 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); 2850 3313 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2851 3314 } … … 2861 3324 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2862 3325 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); 2865 3328 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2866 3329 } … … 2878 3341 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2879 3342 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); 2882 3345 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2883 3346 } … … 2896 3359 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2897 3360 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); 2900 3363 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2901 3364 } … … 2903 3366 /* Continue with traversing the page directory at this level. */ 2904 3367 } 2905 }2906 2907 2908 /**2909 * Checks whether two consecutive I/O page walk results translates to a physically2910 * 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 a2939 * physically contiguous region of memory.2940 *2941 * When IOTLB caching is used, in addition to the translated addresses being2942 * physically contiguous, all pages in the access must have identical page sizes and2943 * I/O permissions. This is required to simplify IOTLB lookups for large accesses2944 * (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_CACHE2953 if ( pWalkResultPrev->cShift == pWalkResult->cShift2954 && pWalkResultPrev->fPerm == pWalkResult->fPerm2955 && iommuAmdDteLookupIsAddrPhysContig(pWalkResultPrev, pWalkResult))2956 return true;2957 return false;2958 #else2959 return iommuAmdDteLookupIsAddrPhysContig(pWalkResultPrev, pWalkResult);2960 #endif2961 }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_CACHE2976 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 #else2980 RT_NOREF3(pIommu, uDevId, fFlags);2981 #endif2982 3368 } 2983 3369 … … 2988 3374 * @returns VBox status code. 2989 3375 * @param pDevIns The IOMMU instance data. 2990 * @param uDevId The device ID .3376 * @param uDevId The device ID (bus, device, function). 2991 3377 * @param uIova The I/O virtual address to lookup. 2992 3378 * @param cbAccess The size of the access. … … 3014 3400 if (RT_SUCCESS(rc)) 3015 3401 { 3016 /* If the DTE is not valid, addresses are forwarded without translation */3017 3402 if (Dte.n.u1Valid) 3018 3403 { … … 3023 3408 { 3024 3409 /* 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); 3028 3411 if (rc == VINF_SUCCESS) 3029 3412 { … … 3038 3421 for (;;) 3039 3422 { 3423 /** @todo split this into a separate function and reuse from 3424 * iommuAmdCacheLookup(). */ 3425 IOWALKRESULT WalkResult; 3426 RT_ZERO(WalkResult); 3040 3427 rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fPerm, &Dte, enmOp, &WalkResult); 3041 3428 if (RT_SUCCESS(rc)) … … 3045 3432 if (cbRemaining == cbAccess) 3046 3433 { 3047 uint64_t const offMask = ~(UINT64_C(0xffffffffffffffff) <<WalkResult.cShift);3434 uint64_t const offMask = IOMMU_GET_PAGE_OFF_MASK(WalkResult.cShift); 3048 3435 uint64_t const offSpa = uIova & offMask; 3049 3436 Assert(!(WalkResult.GCPhysSpa & offMask)); 3050 3437 GCPhysSpa = WalkResult.GCPhysSpa | offSpa; 3051 3052 /* Store the walk result from the first page. */3053 WalkResultPrev = WalkResult;3054 3438 } 3055 3439 /* 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)) 3059 3441 { 3060 3442 STAM_COUNTER_INC(&pThis->StatDteLookupNonContig); … … 3062 3444 } 3063 3445 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 3064 3453 /* Check if we need to access more pages. */ 3065 uint64_t const cbPage = RT_BIT_64(WalkResult.cShift);3066 3454 if (cbRemaining > cbPage - offIova) 3067 3455 { 3068 3456 cbRemaining -= (cbPage - offIova); /* Calculate how much more we need to access. */ 3069 cbPages += cbPage; /* Update size of all pages read thus far. */3070 3457 uIovaPage += cbPage; /* Update address of the next access. */ 3071 3458 offIova = 0; /* After first page, all pages are accessed from off 0. */ … … 3089 3476 cbContiguous = cbAccess - cbRemaining; 3090 3477 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 3093 3491 } 3094 3492 else if (rc == VINF_IOMMU_ADDR_TRANSLATION_DISABLED) … … 3098 3496 * GPA=SPA, but the permission bits are important and controls accesses. 3099 3497 */ 3100 /* . */3101 3498 GCPhysSpa = uIova; 3102 3499 cbContiguous = cbAccess; 3103 3500 rc = VINF_SUCCESS; 3104 3501 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 3112 3508 } 3113 3509 else 3114 3510 { 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); 3116 3513 GCPhysSpa = NIL_RTGCPHYS; 3117 3514 cbContiguous = 0; 3118 Assert(RT_FAILURE(rc));3119 3515 } 3120 3516 } … … 3138 3534 cbContiguous = cbAccess; 3139 3535 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 3142 3542 } 3143 3543 } … … 3155 3555 return rc; 3156 3556 } 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 */ 3581 static 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 */ 3157 3705 3158 3706 … … 3183 3731 } 3184 3732 } 3185 3186 3187 #ifdef LOG_ENABLED3188 /**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 */3201 3733 3202 3734 … … 3234 3766 LogFlowFunc(("%s: uDevId=%#x uIova=%#RX64 cb=%zu\n", iommuAmdMemAccessGetPermName(fPerm), uDevId, uIova, cbAccess)); 3235 3767 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 3237 3793 3238 3794 /* Lookup the IOVA from the device table. */ 3239 intrc = iommuAmdDteLookup(pDevIns, uDevId, uIova, cbAccess, fPerm, enmOp, pGCPhysSpa, pcbContiguous);3795 rc = iommuAmdDteLookup(pDevIns, uDevId, uIova, cbAccess, fPerm, enmOp, pGCPhysSpa, pcbContiguous); 3240 3796 if (RT_SUCCESS(rc)) 3241 3797 { /* likely */ } … … 3243 3799 LogFunc(("DTE lookup failed! uDevId=%#x uIova=%#RX64 fPerm=%u cbAccess=%zu rc=%#Rrc\n", uDevId, uIova, fPerm, 3244 3800 cbAccess, rc)); 3801 3245 3802 return rc; 3246 3803 } … … 3319 3876 * @returns VBox status code. 3320 3877 * @param pDevIns The IOMMU device instance. 3321 * @param uDevId The device ID .3878 * @param uDevId The device ID (bus, device, function). 3322 3879 * @param pDte The device table entry. 3323 3880 * @param GCPhysIn The source MSI address (used for reporting errors). … … 3350 3907 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, GCPhysIn, false /* fPresent */, false /* fRsvdNotZero */, 3351 3908 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); 3353 3911 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3354 3912 } … … 3374 3932 * @returns VBox status code. 3375 3933 * @param pDevIns The IOMMU instance data. 3376 * @param uDevId The device ID .3934 * @param uDevId The device ID (bus, device, function). 3377 3935 * @param pDte The device table entry. 3378 3936 * @param enmOp The IOMMU operation being performed. … … 3412 3970 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable, 3413 3971 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); 3415 3974 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3416 3975 } … … 3420 3979 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable, 3421 3980 true /* fRsvdNotZero */, false /* fPermDenied */, enmOp, &EvtIoPageFault); 3422 iommuAmdIoPageFaultEventRaise (pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRsvdNotZero);3981 iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRsvdNotZero); 3423 3982 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3424 3983 } … … 3428 3987 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable, 3429 3988 false /* fRsvdNotZero */, false /* fPermDenied */, enmOp, &EvtIoPageFault); 3430 iommuAmdIoPageFaultEventRaise (pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRemapEn);3989 iommuAmdIoPageFaultEventRaiseWithDte(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRemapEn); 3431 3990 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3432 3991 } … … 3441 4000 * @returns VBox status code. 3442 4001 * @param pDevIns The IOMMU instance data. 3443 * @param uDevId The device ID .4002 * @param uDevId The device ID (bus, device, function). 3444 4003 * @param enmOp The IOMMU operation being performed. 3445 4004 * @param pMsiIn The source MSI. … … 3751 4310 case IOMMU_CMD_INV_DEV_TAB_ENTRY: 3752 4311 { 3753 /** @todo IOMMU: Implement this once we implement IOTLB. Pretend success until3754 * then. */3755 4312 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 3756 4329 return VINF_SUCCESS; 4330 #endif 3757 4331 } 3758 4332 … … 3770 4344 uint64_t const uIova = RT_MAKE_U64(pCmdInvPages->n.u20AddrLo << X86_PAGE_4K_SHIFT, pCmdInvPages->n.u32AddrHi); 3771 4345 uint16_t const uDomainId = pCmdInvPages->n.u16DomainId; 4346 bool const fFlushPde = pCmdInvPages->n.u1PageDirEntries; 3772 4347 uint8_t cShift; 3773 4348 if (!pCmdInvPages->n.u1Size) … … 3778 4353 unsigned const uFirstZeroBit = ASMBitLastSetU64(~(uIova >> X86_PAGE_4K_SHIFT)); 3779 4354 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)); 3780 4368 } 3781 4369 3782 4370 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 3784 4393 IOMMU_UNLOCK(pDevIns); 3785 4394 return VINF_SUCCESS; … … 3839 4448 { 3840 4449 STAM_COUNTER_INC(&pThis->StatCmdInvIommuAll); 3841 3842 4450 if (pThis->ExtFeat.n.u1InvAllSup) 3843 4451 { 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 3845 4469 return VINF_SUCCESS; 4470 #endif 3846 4471 } 3847 4472 iommuAmdIllegalCmdEventInit(GCPhysCmd, (PEVT_ILLEGAL_CMD_ERR_T)pEvtError); … … 4729 5354 pHlp->pfnPrintf(pHlp, "%sAllow Exclusion = %RTbool\n", pszPrefix, pDte->n.u1AllowExclusion); 4730 5355 pHlp->pfnPrintf(pHlp, "%sSysMgt Message Enable = %RTbool\n", pszPrefix, pDte->n.u2SysMgt); 4731 pHlp->pfnPrintf(pHlp, "\n");4732 4733 5356 pHlp->pfnPrintf(pHlp, "%sInterrupt Map Valid = %RTbool\n", pszPrefix, pDte->n.u1IntrMapValid); 4734 5357 uint8_t const uIntrTabLen = pDte->n.u4IntrTableLength; … … 4758 5381 pHlp->pfnPrintf(pHlp, "%sMode0FC = %#x\n", pszPrefix, pDte->n.u1Mode0FC); 4759 5382 pHlp->pfnPrintf(pHlp, "%sSnoop Attribute = %#x\n", pszPrefix, pDte->n.u8SnoopAttr); 5383 pHlp->pfnPrintf(pHlp, "\n"); 4760 5384 } 4761 5385 … … 4773 5397 { 4774 5398 DTE_T Dte; 5399 IOMMU_LOCK_NORET(pDevIns); 4775 5400 rc = iommuAmdDteRead(pDevIns, uDevId, IOMMUOP_TRANSLATE_REQ, &Dte); 5401 IOMMU_UNLOCK(pDevIns); 4776 5402 if (RT_SUCCESS(rc)) 4777 5403 { … … 4780 5406 return; 4781 5407 } 4782 4783 5408 pHlp->pfnPrintf(pHlp, "Failed to read DTE for device ID %u (%#x). rc=%Rrc\n", uDevId, uDevId, rc); 4784 5409 } … … 4791 5416 4792 5417 4793 #if 0 5418 #if defined(IN_RING3) && defined(IOMMU_WITH_IOTLBE_CACHE) 5419 /** 5420 * @callback_method_impl{FNDBGFHANDLERDEV} 5421 */ 5422 static 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 4794 5449 /** 4795 5450 * @callback_method_impl{FNDBGFHANDLERDEV} … … 4803 5458 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev); 4804 5459 4805 uint8_t c Tables = 0;5460 uint8_t cSegments = 0; 4806 5461 for (uint8_t i = 0; i < RT_ELEMENTS(pThis->aDevTabBaseAddrs); i++) 4807 5462 { 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; 4810 5465 if (GCPhysDevTab) 4811 ++c Tables;4812 } 4813 4814 pHlp->pfnPrintf(pHlp, "AMD-IOMMU Device Tables:\n");4815 pHlp->pfnPrintf(pHlp, " Tables active: %u\n", cTables);4816 if (!c Tables)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) 4817 5472 return; 4818 5473 4819 5474 for (uint8_t i = 0; i < RT_ELEMENTS(pThis->aDevTabBaseAddrs); i++) 4820 5475 { 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; 4823 5478 if (GCPhysDevTab) 4824 5479 { 4825 5480 uint32_t const cbDevTab = IOMMU_GET_DEV_TAB_LEN(&DevTabBar); 4826 5481 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);4828 5482 4829 5483 void *pvDevTab = RTMemAllocZ(cbDevTab); … … 4835 5489 for (uint32_t idxDte = 0; idxDte < cDtes; idxDte++) 4836 5490 { 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)); 4838 5492 if ( pDte->n.u1Valid 4839 || pDte->n.u1IntrMapValid) 5493 && pDte->n.u1TranslationValid 5494 && pDte->n.u3Mode != 0) 4840 5495 { 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); 4842 5500 iommuAmdR3DbgInfoDteWorker(pHlp, pDte, " "); 5501 pHlp->pfnPrintf(pHlp, "\n"); 4843 5502 } 4844 5503 } … … 4847 5506 else 4848 5507 { 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, 4850 5509 cbDevTab, rc); 4851 5510 } … … 4855 5514 else 4856 5515 { 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); 4858 5517 return; 4859 5518 } … … 4861 5520 } 4862 5521 } 4863 #endif4864 5522 4865 5523 … … 4989 5647 LogFlowFunc(("\n")); 4990 5648 5649 IOMMU_LOCK_NORET(pDevIns); 5650 4991 5651 /* Close the command thread semaphore. */ 4992 5652 if (pThis->hEvtCmdThread != NIL_SUPSEMEVENT) … … 5007 5667 if (pThis->paIotlbes) 5008 5668 { 5009 iommuAmdIotlbRemoveAll(p This);5669 iommuAmdIotlbRemoveAll(pDevIns); 5010 5670 PDMDevHlpMMHeapFree(pDevIns, pThis->paIotlbes); 5011 5671 pThis->paIotlbes = NULL; … … 5013 5673 #endif 5014 5674 5675 IOMMU_UNLOCK(pDevIns); 5015 5676 return VINF_SUCCESS; 5016 5677 } … … 5185 5846 PDMDevHlpDBGFInfoRegister(pDevIns, "iommu", "Display IOMMU state.", iommuAmdR3DbgInfo); 5186 5847 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); 5189 5851 #endif 5190 5852 … … 5224 5886 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatCmdInvIommuAll, STAMTYPE_COUNTER, "R3/Commands/InvIommuAll", STAMUNIT_OCCURENCES, "Number of Invalidate IOMMU All commands processed."); 5225 5887 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)."); 5229 5896 # endif 5230 5897 … … 5249 5916 * of how code, features and devices around the IOMMU changes. 5250 5917 */ 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); 5252 5920 pThis->paDevices = (PIODEVICE)PDMDevHlpMMHeapAllocZ(pDevIns, cbDevices); 5253 5921 if (!pThis->paDevices) … … 5361 6029 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 5362 6030 PIOMMUCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC); 5363 5364 6031 pThisCC->CTX_SUFF(pDevIns) = pDevIns; 5365 6032
Note:
See TracChangeset
for help on using the changeset viewer.