VirtualBox

Changeset 89365 in vbox for trunk/src/VBox


Ignore:
Timestamp:
May 28, 2021 4:00:47 PM (4 years ago)
Author:
vboxsync
Message:

Intel IOMMU: bugref:9967 Address translation, WIP.

File:
1 edited

Legend:

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

    r89312 r89365  
    168168    kDmarDiag_Atf_Lct_4_2,
    169169    kDmarDiag_Atf_Lct_4_3,
     170    kDmarDiag_Atf_Lct_5,
    170171    kDmarDiag_Atf_Lrt_1,
    171172    kDmarDiag_Atf_Lrt_2,
    172173    kDmarDiag_Atf_Lrt_3,
     174    kDmarDiag_Atf_Lsl_1,
     175    kDmarDiag_Atf_Lsl_2,
    173176    kDmarDiag_Atf_Rta_1_1,
    174177    kDmarDiag_Atf_Rta_1_2,
     
    233236    DMARDIAG_DESC(Atf_Lct_4_2               ),
    234237    DMARDIAG_DESC(Atf_Lct_4_3               ),
     238    DMARDIAG_DESC(Atf_Lct_5                 ),
    235239    DMARDIAG_DESC(Atf_Lrt_1                 ),
    236240    DMARDIAG_DESC(Atf_Lrt_2                 ),
    237241    DMARDIAG_DESC(Atf_Lrt_3                 ),
     242    DMARDIAG_DESC(Atf_Lsl_1                 ),
     243    DMARDIAG_DESC(Atf_Lsl_2                 ),
    238244    DMARDIAG_DESC(Atf_Rta_1_1               ),
    239245    DMARDIAG_DESC(Atf_Rta_1_2               ),
     
    308314    /** Host-address width (HAW) valid mask. */
    309315    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). */
    311318    uint64_t                    fMgawMask;
     319    /** Maximum supported paging level (3, 4 or 5). */
     320    uint8_t                     uMaxPagingLevel;
    312321
    313322    /** The event semaphore the invalidation-queue thread waits on. */
     
    440449    /** The type of the translation request. */
    441450    VTDREQTYPE              enmReqType;
     451    /** The table translation mode (VTD_TTM_XXX). */
     452    uint8_t                 fTtm;
     453    uint8_t                 uPadding[7];
    442454    /** The DMA address being accessed. */
    443455    uint64_t                uDmaAddr;
     
    723735{
    724736    /*
    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.
    727740     *
    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     *
    730744     * See Intel VT-d spec. 10.4.2 "Capability Register".
    731745     */
     
    736750                         : 0;
    737751    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 */
     762static 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;
    738769}
    739770
     
    18081839 *
    18091840 * @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 */
     1845static 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);
    18151848    uint8_t const fAw     = RT_BF_GET(pCtxEntry->au64[1], VTD_BF_1_CONTEXT_ENTRY_AW);
     1849    uint8_t const fAwMask = RT_BIT(fAw);
    18161850    uint8_t const fSagaw  = RT_BF_GET(pThis->fCapReg, VTD_BF_CAP_REG_SAGAW);
    1817     uint8_t const fAwMask = RT_BIT(fAw);
    18181851    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;
    18201867}
    18211868
     
    18751922 *
    18761923 * @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.
    18791927 * @param   pAddrRemap      The DMA address remap info.
    18801928 */
    1881 static int dmarDrSecondLevelTranslate(PPDMDEVINS pDevIns, VTD_SLP_ENTRY_T SlpEntry, PDMARADDRMAP pAddrRemap)
    1882 {
    1883     RT_NOREF3(pDevIns, SlpEntry, pAddrRemap);
    1884     /** @todo Implement me */
     1929static 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    }
    18851974    return VERR_NOT_IMPLEMENTED;
    18861975}
     
    18971986static int dmarDrLegacyModeRemapAddr(PPDMDEVINS pDevIns, uint64_t uRtaddrReg, PDMARADDRMAP pAddrRemap)
    18981987{
     1988    Assert(pAddrRemap->fTtm == VTD_TTM_LEGACY_MODE);    /* Paranoia. */
     1989
    18991990    /* Read the root-entry from guest memory. */
    19001991    uint8_t const idxRootEntry = RT_HI_U8(pAddrRemap->idDevice);
     
    19392030                            switch (fTt)
    19402031                            {
    1941                                 case 0:
     2032                                case VTD_TT_UNTRANSLATED_SLP:
    19422033                                {
    19432034                                    /*
     
    19472038                                    if (pAddrRemap->enmAddrType == PCIADDRTYPE_UNTRANSLATED)
    19482039                                    {
    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))
    19512043                                        {
    19522044                                            /* Read the SLPTPTR from guest memory. */
     
    19602052
    19612053                                                /* Finally... perform second-level translation. */
    1962                                                 return dmarDrSecondLevelTranslate(pDevIns, SlpEntry, pAddrRemap);
     2054                                                return dmarDrSecondLevelTranslate(pDevIns, SlpEntry, uPagingLevel, pAddrRemap);
    19632055                                            }
    19642056                                            dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_3, VTDATFAULT_LCT_4_3, pAddrRemap);
     
    19672059                                            dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_1, VTDATFAULT_LCT_4_1, pAddrRemap);
    19682060                                    }
    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;
    19722064                                }
    19732065
    1974                                 case 2:
     2066                                case VTD_TT_UNTRANSLATED_PT:
    19752067                                {
    19762068                                    /*
    1977                                      * Untranslated requests are processed as pass-through (PT) if pass-through is supported.
     2069                                     * Untranslated requests are processed as pass-through (PT) if PT is supported.
    19782070                                     * Translated and translation requests are blocked. If PT isn't supported this TT value
    19792071                                     * is reserved which I assume raises a fault (hence fallthru below).
    19802072                                     */
    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)
    19832074                                    {
    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;
    19872084                                    }
    19882085                                    RT_FALL_THRU();
    19892086                                }
    19902087
    1991                                 case 1:
     2088                                case VTD_TT_UNTRANSLATED_DEV_TLB:
    19922089                                {
    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                                     */
    19942094                                    Assert(!(pThis->fExtCapReg & VTD_BF_ECAP_REG_DT_MASK));
    19952095                                    RT_FALL_THRU();
     
    21152215        }
    21162216
     2217        uint8_t const fTtm = RT_BF_GET(uRtaddrReg, VTD_BF_RTADDR_REG_TTM);
    21172218        DMARADDRMAP AddrRemap;
    21182219        AddrRemap.idDevice       = idDevice;
     
    21202221        AddrRemap.enmAddrType    = PCIADDRTYPE_UNTRANSLATED;
    21212222        AddrRemap.enmReqType     = enmReqType;
     2223        AddrRemap.fTtm           = fTtm;
    21222224        AddrRemap.uDmaAddr       = uIova;
    21232225        AddrRemap.cbDma          = cbIova;
     
    21262228
    21272229        int rc;
    2128         uint8_t const fTtm = RT_BF_GET(uRtaddrReg, VTD_BF_RTADDR_REG_TTM);
    21292230        switch (fTtm)
    21302231        {
     
    31973298        uint8_t const fPsi     = 1;                                /* Page selective invalidation. */
    31983299        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. */
    32003301        uint16_t const offFro  = DMAR_MMIO_OFF_FRCD_LO_REG >> 4;   /* MMIO offset of FRCD registers. */
    32013302        uint8_t const fEsrtps  = 1;                                /* Enhanced SRTPS (auto invalidate cache on SRTP). */
     
    32093310                       | RT_BF_MAKE(VTD_BF_CAP_REG_PHMR,    0)     /* Protected High-Memory Region not supported. */
    32103311                       | 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)
    32123313                       | RT_BF_MAKE(VTD_BF_CAP_REG_MGAW,    uMgaw)
    32133314                       | RT_BF_MAKE(VTD_BF_CAP_REG_ZLR,     1)     /** @todo Figure out if/how to support zero-length reads. */
     
    32263327        dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_CAP_REG, pThis->fCapReg);
    32273328
    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);
    32303332    }
    32313333
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette