Changeset 89365 in vbox for trunk/src/VBox
- Timestamp:
- May 28, 2021 4:00:47 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuIntel.cpp
r89312 r89365 168 168 kDmarDiag_Atf_Lct_4_2, 169 169 kDmarDiag_Atf_Lct_4_3, 170 kDmarDiag_Atf_Lct_5, 170 171 kDmarDiag_Atf_Lrt_1, 171 172 kDmarDiag_Atf_Lrt_2, 172 173 kDmarDiag_Atf_Lrt_3, 174 kDmarDiag_Atf_Lsl_1, 175 kDmarDiag_Atf_Lsl_2, 173 176 kDmarDiag_Atf_Rta_1_1, 174 177 kDmarDiag_Atf_Rta_1_2, … … 233 236 DMARDIAG_DESC(Atf_Lct_4_2 ), 234 237 DMARDIAG_DESC(Atf_Lct_4_3 ), 238 DMARDIAG_DESC(Atf_Lct_5 ), 235 239 DMARDIAG_DESC(Atf_Lrt_1 ), 236 240 DMARDIAG_DESC(Atf_Lrt_2 ), 237 241 DMARDIAG_DESC(Atf_Lrt_3 ), 242 DMARDIAG_DESC(Atf_Lsl_1 ), 243 DMARDIAG_DESC(Atf_Lsl_2 ), 238 244 DMARDIAG_DESC(Atf_Rta_1_1 ), 239 245 DMARDIAG_DESC(Atf_Rta_1_2 ), … … 308 314 /** Host-address width (HAW) valid mask. */ 309 315 uint64_t fHawMask; 310 /** Maximum guest-address width (MGAW) valid mask. */ 316 /** Maximum guest-address width (MGAW) valid mask (remove if it turns out we 317 * don't need this). */ 311 318 uint64_t fMgawMask; 319 /** Maximum supported paging level (3, 4 or 5). */ 320 uint8_t uMaxPagingLevel; 312 321 313 322 /** The event semaphore the invalidation-queue thread waits on. */ … … 440 449 /** The type of the translation request. */ 441 450 VTDREQTYPE enmReqType; 451 /** The table translation mode (VTD_TTM_XXX). */ 452 uint8_t fTtm; 453 uint8_t uPadding[7]; 442 454 /** The DMA address being accessed. */ 443 455 uint64_t uDmaAddr; … … 723 735 { 724 736 /* 725 * It doesn't make sense to me that a CPU (or IOMMU hardware) will support 5-level paging 726 * but not 4 or 3 level paging. So smaller page-table levels are always OR'ed in. 737 * It doesn't make sense to me that a CPU (or IOMMU hardware) will ever support 738 * 5-level paging but not 4 or 3-level paging. So smaller page-table levels 739 * are always OR'ed in below. 727 740 * 728 * The values below (57, 48, 39 bits) represents the levels of page-table walks for 729 * 4KB base page size. 741 * The bit values below (57, 48, 39 bits) represents the levels of page-table walks 742 * for 4KB base page size (5-level, 4-level and 3-level paging respectively). 743 * 730 744 * See Intel VT-d spec. 10.4.2 "Capability Register". 731 745 */ … … 736 750 : 0; 737 751 return fSagaw; 752 } 753 754 755 /** 756 * Returns the maximum supported paging level given the supported adjusted 757 * guest-address width (SAGAW) field. 758 * 759 * @returns The highest paging level supported, 0 if invalid. 760 * @param fSagaw The CAP_REG.SAGAW value. 761 */ 762 static uint8_t vtdCapRegGetMaxPagingLevel(uint8_t fSagaw) 763 { 764 uint8_t const cMaxPagingLevel = fSagaw & RT_BIT(3) ? 5 765 : fSagaw & RT_BIT(2) ? 4 766 : fSagaw & RT_BIT(1) ? 3 767 : 0; 768 return cMaxPagingLevel; 738 769 } 739 770 … … 1808 1839 * 1809 1840 * @returns @c true if it's supported, @c false otherwise. 1810 * @param pThis The shared DMAR device state. 1811 * @param pCtxEntry The context entry. 1812 */ 1813 static bool dmarDrLegacyModeIsAwValid(PCDMAR pThis, PCVTD_CONTEXT_ENTRY_T pCtxEntry) 1814 { 1841 * @param pThis The shared DMAR device state. 1842 * @param pCtxEntry The context entry. 1843 * @param puPagingLevel Where to store the paging level. 1844 */ 1845 static bool dmarDrLegacyModeIsAwValid(PCDMAR pThis, PCVTD_CONTEXT_ENTRY_T pCtxEntry, uint8_t *puPagingLevel) 1846 { 1847 uint8_t const fTt = RT_BF_GET(pCtxEntry->au64[0], VTD_BF_0_CONTEXT_ENTRY_TT); 1815 1848 uint8_t const fAw = RT_BF_GET(pCtxEntry->au64[1], VTD_BF_1_CONTEXT_ENTRY_AW); 1849 uint8_t const fAwMask = RT_BIT(fAw); 1816 1850 uint8_t const fSagaw = RT_BF_GET(pThis->fCapReg, VTD_BF_CAP_REG_SAGAW); 1817 uint8_t const fAwMask = RT_BIT(fAw);1818 1851 Assert(!(fSagaw & ~(RT_BIT(1) | RT_BIT(2) | RT_BIT(3)))); 1819 return fAw < 4 ? RT_BOOL(fSagaw & fAwMask) : false; 1852 1853 *puPagingLevel = fAw + 2; 1854 1855 /* With pass-through, the address width must be the largest AGAW supported by hardware. */ 1856 if (fTt == VTD_TT_UNTRANSLATED_PT) 1857 { 1858 Assert(pThis->uMaxPagingLevel >= 3 && pThis->uMaxPagingLevel <= 5); /* Paranoia. */ 1859 return *puPagingLevel == pThis->uMaxPagingLevel; 1860 } 1861 1862 /* The address width must be any of the ones supported by hardware. */ 1863 if (fAw < 4) 1864 return (fSagaw & fAwMask) != 0; 1865 1866 return false; 1820 1867 } 1821 1868 … … 1875 1922 * 1876 1923 * @returns VBox status code. 1877 * @param pDevIns The IOMMU device instance. 1878 * @param SlpEntry The second-level paging entry. 1924 * @param pDevIns The IOMMU device instance. 1925 * @param SlpEntry The second-level paging entry. 1926 * @param uPagingLevel The paging level. 1879 1927 * @param pAddrRemap The DMA address remap info. 1880 1928 */ 1881 static int dmarDrSecondLevelTranslate(PPDMDEVINS pDevIns, VTD_SLP_ENTRY_T SlpEntry, PDMARADDRMAP pAddrRemap) 1882 { 1883 RT_NOREF3(pDevIns, SlpEntry, pAddrRemap); 1884 /** @todo Implement me */ 1929 static int dmarDrSecondLevelTranslate(PPDMDEVINS pDevIns, VTD_SLP_ENTRY_T SlpEntry, uint8_t uPagingLevel, PDMARADDRMAP pAddrRemap) 1930 { 1931 PCDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PCDMAR); 1932 static uint8_t const s_acLevelShifts[] = { 12, 21, 30, 39, 48 }; 1933 static uint64_t const s_auLevelMasks[] = { UINT64_C(0x00000000001ff000), 1934 UINT64_C(0x000000003fe00000), 1935 UINT64_C(0x0000007fc0000000), 1936 UINT64_C(0x0000ff8000000000), 1937 UINT64_C(0x01ff000000000000) }; 1938 AssertCompile(RT_ELEMENTS(s_acLevelShifts) == RT_ELEMENTS(s_auLevelMasks)); 1939 Assert(uPagingLevel >= 3 && uPagingLevel <= RT_ELEMENTS(s_auLevelMasks)); 1940 1941 /* 1942 * Traverse the I/O page table starting with the SLPTPTR (second-level page table pointer). 1943 * Unlike AMD IOMMU paging, here there is no feature for "skipping" levels. 1944 */ 1945 uint64_t uPtEntity = SlpEntry; 1946 uint64_t const uDmaAddr = pAddrRemap->uDmaAddr; 1947 uint64_t const fHawMask = pThis->fHawMask; 1948 for (int8_t iLevel = uPagingLevel - 1; iLevel >= 0; iLevel--) 1949 { 1950 /* Read the paging entry for the current level. */ 1951 { 1952 uint16_t const idxPte = (uDmaAddr >> s_acLevelShifts[iLevel]) & UINT64_C(0x1ff); 1953 uint64_t const offPte = idxPte << 3; 1954 RTGCPHYS const GCPhysPtEntity = (uPtEntity & fHawMask) | offPte; 1955 int const rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysPtEntity, &uPtEntity, sizeof(uPtEntity)); 1956 if (RT_SUCCESS(rc)) 1957 { /* likely */ } 1958 else 1959 { 1960 /** @todo If this function is going to be used for scalable-mode second-level 1961 * translation, we need to report different error codes. The TTM is 1962 * available in pAddrRemap->fTtm, but how cleanly we can handle this is 1963 * something to be decided later. For now we just use legacy mode error 1964 * codes below. Asserted below. */ 1965 Assert(pAddrRemap->fTtm == VTD_TTM_LEGACY_MODE); 1966 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lsl_1, VTDATFAULT_LSL_1, pAddrRemap); 1967 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 1968 } 1969 } 1970 1971 /** @todo validate page table entity. */ 1972 /** @todo once we reach the level 1, compute final address with page offset. */ 1973 } 1885 1974 return VERR_NOT_IMPLEMENTED; 1886 1975 } … … 1897 1986 static int dmarDrLegacyModeRemapAddr(PPDMDEVINS pDevIns, uint64_t uRtaddrReg, PDMARADDRMAP pAddrRemap) 1898 1987 { 1988 Assert(pAddrRemap->fTtm == VTD_TTM_LEGACY_MODE); /* Paranoia. */ 1989 1899 1990 /* Read the root-entry from guest memory. */ 1900 1991 uint8_t const idxRootEntry = RT_HI_U8(pAddrRemap->idDevice); … … 1939 2030 switch (fTt) 1940 2031 { 1941 case 0:2032 case VTD_TT_UNTRANSLATED_SLP: 1942 2033 { 1943 2034 /* … … 1947 2038 if (pAddrRemap->enmAddrType == PCIADDRTYPE_UNTRANSLATED) 1948 2039 { 1949 /* Validate the address width. */ 1950 if (dmarDrLegacyModeIsAwValid(pThis, &CtxEntry)) 2040 /* Validate the address width and get the paging level. */ 2041 uint8_t uPagingLevel; 2042 if (dmarDrLegacyModeIsAwValid(pThis, &CtxEntry, &uPagingLevel)) 1951 2043 { 1952 2044 /* Read the SLPTPTR from guest memory. */ … … 1960 2052 1961 2053 /* Finally... perform second-level translation. */ 1962 return dmarDrSecondLevelTranslate(pDevIns, SlpEntry, pAddrRemap);2054 return dmarDrSecondLevelTranslate(pDevIns, SlpEntry, uPagingLevel, pAddrRemap); 1963 2055 } 1964 2056 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_3, VTDATFAULT_LCT_4_3, pAddrRemap); … … 1967 2059 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_1, VTDATFAULT_LCT_4_1, pAddrRemap); 1968 2060 } 1969 1970 Log4Func(("Translation type blocks translated and translation requests\n"));1971 return VERR_IOMMU_ADDR_TRANSLATION_FAILED;2061 else 2062 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_5, VTDATFAULT_LCT_5, pAddrRemap); 2063 break; 1972 2064 } 1973 2065 1974 case 2:2066 case VTD_TT_UNTRANSLATED_PT: 1975 2067 { 1976 2068 /* 1977 * Untranslated requests are processed as pass-through (PT) if pass-throughis supported.2069 * Untranslated requests are processed as pass-through (PT) if PT is supported. 1978 2070 * Translated and translation requests are blocked. If PT isn't supported this TT value 1979 2071 * is reserved which I assume raises a fault (hence fallthru below). 1980 2072 */ 1981 if ( (pThis->fExtCapReg & VTD_BF_ECAP_REG_PT_MASK) 1982 && (pAddrRemap->enmAddrType == PCIADDRTYPE_UNTRANSLATED)) 2073 if (pThis->fExtCapReg & VTD_BF_ECAP_REG_PT_MASK) 1983 2074 { 1984 pAddrRemap->GCPhysSpa = pAddrRemap->uDmaAddr; 1985 pAddrRemap->cbContiguous = pAddrRemap->cbDma; 1986 return VINF_SUCCESS; 2075 if (pAddrRemap->enmAddrType == PCIADDRTYPE_UNTRANSLATED) 2076 { 2077 /** @todo Check AW == maximum SAGAW bit? */ 2078 pAddrRemap->GCPhysSpa = pAddrRemap->uDmaAddr; 2079 pAddrRemap->cbContiguous = pAddrRemap->cbDma; 2080 return VINF_SUCCESS; 2081 } 2082 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_5, VTDATFAULT_LCT_5, pAddrRemap); 2083 break; 1987 2084 } 1988 2085 RT_FALL_THRU(); 1989 2086 } 1990 2087 1991 case 1:2088 case VTD_TT_UNTRANSLATED_DEV_TLB: 1992 2089 { 1993 /* We don't support device-TLBs, so this TT value is treated as reserved. */ 2090 /* 2091 * Untranslated, translated and translation requests are supported but requires 2092 * device-TLB support. We don't support device-TLBs, so it's treated as reserved. 2093 */ 1994 2094 Assert(!(pThis->fExtCapReg & VTD_BF_ECAP_REG_DT_MASK)); 1995 2095 RT_FALL_THRU(); … … 2115 2215 } 2116 2216 2217 uint8_t const fTtm = RT_BF_GET(uRtaddrReg, VTD_BF_RTADDR_REG_TTM); 2117 2218 DMARADDRMAP AddrRemap; 2118 2219 AddrRemap.idDevice = idDevice; … … 2120 2221 AddrRemap.enmAddrType = PCIADDRTYPE_UNTRANSLATED; 2121 2222 AddrRemap.enmReqType = enmReqType; 2223 AddrRemap.fTtm = fTtm; 2122 2224 AddrRemap.uDmaAddr = uIova; 2123 2225 AddrRemap.cbDma = cbIova; … … 2126 2228 2127 2229 int rc; 2128 uint8_t const fTtm = RT_BF_GET(uRtaddrReg, VTD_BF_RTADDR_REG_TTM);2129 2230 switch (fTtm) 2130 2231 { … … 3197 3298 uint8_t const fPsi = 1; /* Page selective invalidation. */ 3198 3299 uint8_t const uMgaw = cGstPhysAddrBits - 1; /* Maximum guest address width. */ 3199 uint8_t const uSagaw = vtdCapRegGetSagaw(uMgaw); /* Supported adjust guest address width. */3300 uint8_t const fSagaw = vtdCapRegGetSagaw(uMgaw); /* Supported adjust guest address width. */ 3200 3301 uint16_t const offFro = DMAR_MMIO_OFF_FRCD_LO_REG >> 4; /* MMIO offset of FRCD registers. */ 3201 3302 uint8_t const fEsrtps = 1; /* Enhanced SRTPS (auto invalidate cache on SRTP). */ … … 3209 3310 | RT_BF_MAKE(VTD_BF_CAP_REG_PHMR, 0) /* Protected High-Memory Region not supported. */ 3210 3311 | RT_BF_MAKE(VTD_BF_CAP_REG_CM, 1) /* Software should invalidate on mapping structure changes. */ 3211 | RT_BF_MAKE(VTD_BF_CAP_REG_SAGAW, fSlts & uSagaw)3312 | RT_BF_MAKE(VTD_BF_CAP_REG_SAGAW, fSlts & fSagaw) 3212 3313 | RT_BF_MAKE(VTD_BF_CAP_REG_MGAW, uMgaw) 3213 3314 | RT_BF_MAKE(VTD_BF_CAP_REG_ZLR, 1) /** @todo Figure out if/how to support zero-length reads. */ … … 3226 3327 dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_CAP_REG, pThis->fCapReg); 3227 3328 3228 pThis->fHawMask = ~(UINT64_MAX << cGstPhysAddrBits); 3229 pThis->fMgawMask = pThis->fHawMask; 3329 pThis->fHawMask = ~(UINT64_MAX << cGstPhysAddrBits) & UINT64_C(0xfffffffffffff000); 3330 pThis->fMgawMask = pThis->fHawMask; 3331 pThis->uMaxPagingLevel = vtdCapRegGetMaxPagingLevel(fSagaw); 3230 3332 } 3231 3333
Note:
See TracChangeset
for help on using the changeset viewer.