Changeset 84181 in vbox for trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
- Timestamp:
- May 7, 2020 7:11:49 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r84171 r84181 2213 2213 typedef struct 2214 2214 { 2215 /** The device ID. */2216 uint16_t uDevId;2217 /** The domain ID. */2218 uint16_t uDomainId;2219 /** @todo Shouldn't we also store how many bits are the offset into the page for2220 * pages > 4K? */2221 /** The I/O virtual address. */2222 uint64_t uIova;2223 /** The translated system physical address. */2224 RTGCPHYS GCPhysSpa;2225 2215 /** The I/O access permissions (IOMMU_IO_PERM_XXX). */ 2226 2216 uint8_t fIoPerm; 2217 /** The number of offset bits in the system physical address. */ 2218 uint8_t cShift; 2219 /** Reserved for future (eviction hints?). */ 2220 uint16_t uRsvd0; 2227 2221 /** Alignment padding. */ 2228 uint 8_t fRsvd0;2229 /** Reserved for future (eviction hints?). */2230 uint32_t uPadding0;2222 uint32_t uRsvd1; 2223 /** The translated system physical address of the page. */ 2224 RTGCPHYS GCPhysSpa; 2231 2225 } IOTLBE_T; 2232 2226 AssertCompileSizeAlignment(IOTLBE_T, 8); 2227 AssertCompileMemberAlignment(IOTLBE_T, GCPhysSpa, 8); 2233 2228 /** Pointer to an IOMMU I/O TLB entry struct. */ 2234 2229 typedef IOTLBE_T *PIOTLBE_T; … … 3778 3773 * Initializes an IOTLB entry. 3779 3774 * 3780 * @param uDevId The device ID.3781 * @param uDomainId The domain ID.3775 * @param GCPhysSpa The translated system physical address. 3776 * @param cShift The number of offset bits in the system physical address. 3782 3777 * @param fIoPerm The I/O access permissions (IOMMU_IO_PERM_XXX). 3783 * @param uIova The I/O virtual address.3784 * @param GCPhysSpa The translated system physical address.3785 3778 * @param pIotlbe Where to store the initialized IOTLB entry. 3786 3779 */ 3787 static void iommuAmdInitIotlbe(uint16_t uDevId, uint16_t uDomainId, uint8_t fIoPerm, uint64_t uIova, RTGCPHYS GCPhysSpa, 3788 PIOTLBE_T pIotlbe) 3789 { 3790 pIotlbe->uDevId = uDevId; 3791 pIotlbe->uDomainId = uDomainId; 3780 static void iommuAmdInitIotlbe(RTGCPHYS GCPhysSpa, uint8_t cShift, uint8_t fIoPerm, PIOTLBE_T pIotlbe) 3781 { 3792 3782 pIotlbe->fIoPerm = fIoPerm; 3793 pIotlbe-> fRsvd0 = 0;3794 pIotlbe->u Padding0= 0;3795 pIotlbe-> uIova = uIova;3783 pIotlbe->uRsvd0 = 0; 3784 pIotlbe->uRsvd1 = 0; 3785 pIotlbe->cShift = cShift; 3796 3786 pIotlbe->GCPhysSpa = GCPhysSpa; 3797 3787 } … … 3879 3869 * @param pDte The device table entry. 3880 3870 * @param enmOp The IOMMU operation being performed. 3881 * @param pGCPhysSpa Where to store the system physical address. 3882 * @param pfIoPerm Where to store the I/O access permissions. This is the 3883 * permission of what access is allowed. 3871 * @param pIotlbe The IOTLB entry to update with the results of the 3872 * translation. 3884 3873 */ 3885 3874 static int iommuAmdWalkIoPageTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess, 3886 PCDTE_T pDte, IOMMUOP enmOp, P RTGCPHYS pGCPhysSpa, uint8_t *pfIoPerm)3875 PCDTE_T pDte, IOMMUOP enmOp, PIOTLBE_T pIotlbe) 3887 3876 { 3888 3877 NOREF(pDevIns); … … 3897 3886 iommuAmdRaiseIoPageFaultEvent(pDevIns, uDevId, pDte->n.u16DomainId, uIova, true /* fPresentOrValid */, 3898 3887 enmOp, kIoPageFaultType_DteTranslationDisabled); 3899 *pGCPhysSpa = 0; 3900 *pfIoPerm = 0; 3888 iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /* cShift */, IOMMU_IO_PERM_NONE, pIotlbe); 3901 3889 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3902 3890 } … … 3911 3899 return VERR_IOMMU_ADDR_ACCESS_DENIED; 3912 3900 } 3913 *pGCPhysSpa = uIova; 3914 *pfIoPerm = fDtePerm; 3901 iommuAmdInitIotlbe(uIova, 0 /* cShift */, fDtePerm, pIotlbe); 3915 3902 return VINF_SUCCESS; 3916 3903 } … … 3922 3909 * raising an ILLEGAL_DEV_TABLE_ENTRY event or an IO_PAGE_FAULT event here. 3923 3910 * I'm just going with this one... */ 3924 *pGCPhysSpa = 0;3925 *pfIoPerm = IOMMU_IO_PERM_NONE;3911 /** @todo IOMMU: raise I/O page fault. */ 3912 iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /* cShift */, IOMMU_IO_PERM_NONE, pIotlbe); 3926 3913 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3927 3914 } … … 3952 3939 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 3953 3940 3954 /* Read the device table entry . */3941 /* Read the device table entry from memory. */ 3955 3942 DTE_T Dte; 3956 3943 int rc = iommuAmdReadDte(pDevIns, uDevId, enmOp, &Dte); 3957 3944 if (RT_SUCCESS(rc)) 3958 3945 { 3959 RTGCPHYS GCPhysSpa = 0; 3960 uint8_t fIoPerm = IOMMU_IO_PERM_NONE; 3961 3946 /* If the DTE is not valid addresses are forwarded without translation */ 3962 3947 if (Dte.n.u1Valid) 3963 { 3964 /* Validate bits 127:0 of the device table entry when DTE.V is 1. */ 3965 uint64_t const fRsvdQword0 = Dte.au64[0] & ~(IOMMU_DTE_QWORD_0_VALID_MASK & ~IOMMU_DTE_QWORD_0_FEAT_MASK); 3966 uint64_t const fRsvdQword1 = Dte.au64[1] & ~(IOMMU_DTE_QWORD_1_VALID_MASK & ~IOMMU_DTE_QWORD_1_FEAT_MASK); 3967 if ( fRsvdQword0 3968 || fRsvdQword1) 3969 { 3970 Log((IOMMU_LOG_PFX ": Invalid reserved bits in DTE (u64[0]=%#RX64 u64[1]=%#RX64) -> Illegal DTE\n", fRsvdQword0, 3971 fRsvdQword1)); 3972 iommuAmdRaiseIllegalDteEvent(pDevIns, uDevId, uIova, enmOp, kIllegalDteType_RsvdNotZero); 3973 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3974 } 3975 3976 /* Ensure the IOVA is not in the exclusion range. */ 3977 if ( !pThis->ExclRangeBaseAddr.n.u1ExclEnable 3978 || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova)) 3979 { 3980 rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uIova, cbAccess, IOMMU_IO_PERM_READ, &Dte, enmOp, &GCPhysSpa, 3981 &fIoPerm); 3982 if (RT_FAILURE(rc)) 3983 Log((IOMMU_LOG_PFX ": I/O page table walk failed. rc=%Rrc\n")); 3984 } 3985 else 3986 { 3987 /* If the IOVA is subject to address exclusion, addresses are forwarded without translation. */ 3988 GCPhysSpa = uIova; 3989 fIoPerm = IOMMU_IO_PERM_READ_WRITE; 3990 } 3991 } 3948 { /* likely */ } 3992 3949 else 3993 3950 { 3994 /* Addresses are forwarded without translation when DTE.V is 0. */ 3995 GCPhysSpa = uIova; 3996 fIoPerm = IOMMU_IO_PERM_READ_WRITE; 3997 } 3998 3999 pIotlbe->GCPhysSpa = GCPhysSpa; 4000 pIotlbe->fIoPerm = fIoPerm; 4001 } 4002 else 4003 { 4004 Log((IOMMU_LOG_PFX ": Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc)); 4005 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 4006 } 4007 4008 return rc; 3951 iommuAmdInitIotlbe(uIova, 0 /* cShift */, IOMMU_IO_PERM_READ_WRITE, pIotlbe); 3952 return VINF_SUCCESS; 3953 } 3954 3955 /* Validate bits 127:0 of the device table entry when DTE.V is 1. */ 3956 uint64_t const fRsvdQword0 = Dte.au64[0] & ~(IOMMU_DTE_QWORD_0_VALID_MASK & ~IOMMU_DTE_QWORD_0_FEAT_MASK); 3957 uint64_t const fRsvdQword1 = Dte.au64[1] & ~(IOMMU_DTE_QWORD_1_VALID_MASK & ~IOMMU_DTE_QWORD_1_FEAT_MASK); 3958 if (RT_LIKELY( !fRsvdQword0 3959 && !fRsvdQword1)) 3960 { /* likely */ } 3961 else 3962 { 3963 Log((IOMMU_LOG_PFX ": Invalid reserved bits in DTE (u64[0]=%#RX64 u64[1]=%#RX64) -> Illegal DTE\n", fRsvdQword0, 3964 fRsvdQword1)); 3965 iommuAmdRaiseIllegalDteEvent(pDevIns, uDevId, uIova, enmOp, kIllegalDteType_RsvdNotZero); 3966 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3967 } 3968 3969 /* If the IOVA is subject to address exclusion addresses are forwarded without translation. */ 3970 if ( !pThis->ExclRangeBaseAddr.n.u1ExclEnable 3971 || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova)) 3972 { /* likely */ } 3973 else 3974 { 3975 iommuAmdInitIotlbe(uIova, 0 /* cShift */, IOMMU_IO_PERM_READ_WRITE, pIotlbe); 3976 return VINF_SUCCESS; 3977 } 3978 3979 /* Walk the I/O page tables to translate and get permission bits for the IOVA. */ 3980 rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uIova, cbAccess, IOMMU_IO_PERM_READ, &Dte, enmOp, pIotlbe); 3981 if (RT_FAILURE(rc)) 3982 Log((IOMMU_LOG_PFX ": I/O page table walk failed. rc=%Rrc\n")); 3983 3984 return rc; 3985 } 3986 3987 Log((IOMMU_LOG_PFX ": Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc)); 3988 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 4009 3989 } 4010 3990 … … 4035 4015 { 4036 4016 IOTLBE_T Iotlbe; 4037 iommuAmdInitIotlbe( uDevId, 0 /* uDomainId */, IOMMU_IO_PERM_NONE, uIova, 0 /* GCPhySpa */, &Iotlbe);4017 iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /*cShift*/, IOMMU_IO_PERM_NONE, &Iotlbe); 4038 4018 4039 4019 /** @todo IOMMU: IOTLB cache lookup. */
Note:
See TracChangeset
for help on using the changeset viewer.