VirtualBox

Changeset 89476 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Jun 3, 2021 8:58:51 AM (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

    r89455 r89476  
    5454#define DMAR_IS_MMIO_OFF_VALID(a_off)               (   (a_off) < DMAR_MMIO_GROUP_0_OFF_END \
    5555                                                     || (a_off) - DMAR_MMIO_GROUP_1_OFF_FIRST < DMAR_MMIO_GROUP_1_SIZE)
    56 
    57 /** Gets the page offset mask given the number of bits to shift. */
    58 #define DMAR_GET_PAGE_OFF_MASK(a_cShift)            (~(UINT64_C(0xffffffffffffffff) << (a_cShift)))
    5956
    6057/** Acquires the DMAR lock but returns with the given busy error code on failure. */
     
    476473
    477474/**
    478  * I/O TLB entry.
    479  */
    480 typedef struct DMARIOTLBE
    481 {
    482     /** The system-physical base address of the translation. */
     475 * I/O Page.
     476 */
     477typedef struct DMARIOPAGE
     478{
     479    /** The base DMA address of a page. */
    483480    RTGCPHYS            GCPhysBase;
    484     /** The domain ID of the translated region. */
    485     uint16_t            idDomain;
    486     /** The permissions granted. */
     481    /** The page shift. */
     482    uint8_t             cShift;
     483    /** The permissions of this page (DMAR_PERM_XXX). */
    487484    uint8_t             fPerm;
    488     /** The page shift of the translation. */
    489     uint8_t             cShift;
    490 } DMARIOTLBE;
    491 /** Pointer to an IOTLB entry. */
    492 typedef DMARIOTLBE *PDMARIOTLBE;
    493 /** Pointer to a const IOTLB entry. */
    494 typedef DMARIOTLBE const *PCDMARIOTLBE;
    495 AssertCompileSizeAlignment(DMARIOTLBE, 4);
    496 
    497 /**
    498  * DMA Memory Request.
    499  */
    500 typedef struct DMARMEMREQ
    501 {
    502     /** The address being accessed. */
    503     uint64_t            uDmaAddr;
    504     /** The size of the access (in bytes). */
    505     size_t              cbDma;
    506     /** The requested permissions (DMAR_PERM_XXX). */
    507     uint8_t             fReqPerm;
     485} DMARIOPAGE;
     486/** Pointer to an I/O page. */
     487typedef DMARIOPAGE *PDMARIOPAGE;
     488/** Pointer to a const I/O address range. */
     489typedef DMARIOPAGE const *PCDMARIOPAGE;
     490
     491/**
     492 * I/O Address Range.
     493 */
     494typedef struct DMARIOADDRRANGE
     495{
     496    /** The starting DMA address of this range. */
     497    uint64_t            uAddr;
     498    /** The size of the range (in bytes). */
     499    size_t              cb;
     500    /** The permissions of this range (DMAR_PERM_XXX). */
     501    uint8_t             fPerm;
     502} DMARIOADDRRANGE;
     503/** Pointer to an I/O address range. */
     504typedef DMARIOADDRRANGE *PDMARIOADDRRANGE;
     505/** Pointer to a const I/O address range. */
     506typedef DMARIOADDRRANGE const *PCDMARIOADDRRANGE;
     507
     508/**
     509 * DMA Memory Request (Input).
     510 */
     511typedef struct DMARMEMREQIN
     512{
     513    /** The address range being accessed. */
     514    DMARIOADDRRANGE     AddrRange;
    508515    /** The source device ID (bus, device, function). */
    509516    uint16_t            idDevice;
     
    514521    /** The request type. */
    515522    VTDREQTYPE          enmReqType;
    516 } DMARMEMREQ;
    517 /** Pointer to a DMA memory request. */
    518 typedef DMARMEMREQ *PDMARMEMREQ;
    519 /** Pointer to a const DMA memory request. */
    520 typedef DMARMEMREQ const *PCDMARMEMREQ;
    521 
    522 /**
    523  * DMA Memory Request Remapping Information.
    524  */
    525 typedef struct DMARMEMREQREMAP
    526 {
    527     /* The DMA memory request. */
    528     DMARMEMREQ          Req;
     523} DMARMEMREQIN;
     524/** Pointer to a DMA memory request input. */
     525typedef DMARMEMREQIN *PDMARMEMREQIN;
     526/** Pointer to a const DMA memory input. */
     527typedef DMARMEMREQIN const *PCDMARMEMREQIN;
     528
     529/**
     530 * DMA Memory Request (Output).
     531 */
     532typedef struct DMARMEMREQOUT
     533{
     534    /** The address range of the translated region. */
     535    DMARIOADDRRANGE     AddrRange;
     536    /** The domain ID of the translated region. */
     537    uint16_t            idDomain;
     538} DMARMEMREQOUT;
     539/** Pointer to a DMA memory request output. */
     540typedef DMARMEMREQOUT *PDMARMEMREQOUT;
     541/** Pointer to a const DMA memory request output. */
     542typedef DMARMEMREQOUT const *PCDMARMEMREQOUT;
     543
     544/**
     545 * DMA Memory Request (Auxiliary Info).
     546 * These get updated and used as part of the translation process.
     547 */
     548typedef struct DMARMEMREQAUX
     549{
    529550    /** The table translation mode (VTD_TTM_XXX). */
    530551    uint8_t             fTtm;
    531552    /** The fault processing disabled (FPD) bit. */
    532553    uint8_t             fFpd;
    533 
    534     /** The IOTLBE result for this remapping. */
    535     DMARIOTLBE          Iotlbe;
    536     /** The size of the contiguous translated region (in bytes). */
    537     size_t              cbContiguous;
     554    /** The paging level of the translation. */
     555    uint8_t             cPagingLevel;
     556    uint8_t             afPadding[5];
     557    /** The first-level page-table pointer (base).  */
     558    uint64_t            uFlptPtr;
     559    /** The second-level page-table pointer (base).  */
     560    uint64_t            uSlptPtr;
     561} DMARMEMREQAUX;
     562/** Pointer to a DMA memory request output. */
     563typedef DMARMEMREQAUX *PDMARMEMREQAUX;
     564/** Pointer to a const DMA memory request output. */
     565typedef DMARMEMREQAUX const *PCDMARMEMREQAUX;
     566
     567/**
     568 * DMA Memory Request Remapping Information.
     569 */
     570typedef struct DMARMEMREQREMAP
     571{
     572    /** The DMA memory request input. */
     573    DMARMEMREQIN        In;
     574    /** DMA memory request auxiliary information. */
     575    DMARMEMREQAUX       Aux;
     576    /** The DMA memory request output. */
     577    DMARMEMREQOUT       Out;
    538578} DMARMEMREQREMAP;
    539579/** Pointer to a DMA remap info. */
     
    541581/** Pointer to a const DMA remap info. */
    542582typedef DMARMEMREQREMAP const *PCDMARMEMREQREMAP;
     583
     584typedef DECLCALLBACKTYPE(int, FNDMAADDRTRANSLATE,(PPDMDEVINS pDevIns, PCDMARMEMREQIN pMemReqIn, PCDMARMEMREQAUX pMemReqAux,
     585                                                  PDMARIOPAGE pIoPageOut));
     586typedef FNDMAADDRTRANSLATE *PFNDMAADDRTRANSLATE;
    543587
    544588
     
    15011545
    15021546/**
    1503  * Records an address translation fault.
     1547 * Records an address translation fault (extended version).
    15041548 *
    15051549 * @param   pDevIns         The IOMMU device instance.
    15061550 * @param   enmDiag         The diagnostic reason.
    15071551 * @param   enmAtFault      The address translation fault reason.
    1508  * @param   pMemReqRemap    The DMA memory request remapping info.
    1509  */
    1510 static void dmarAtFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARMEMREQREMAP pMemReqRemap)
     1552 * @param   pMemReqIn       The DMA memory request input.
     1553 * @param   pMemReqAux      The DMA memory request auxiliary info.
     1554 */
     1555static void dmarAtFaultRecordEx(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARMEMREQIN pMemReqIn,
     1556                                PCDMARMEMREQAUX pMemReqAux)
    15111557{
    15121558    /*
     
    15141560     * in the contex entry, scalable-mode context entry etc.
    15151561     */
    1516     if (!pMemReqRemap->fFpd)
    1517     {
    1518         uint16_t const idDevice  = pMemReqRemap->Req.idDevice;
    1519         uint8_t const  fType1    = pMemReqRemap->Req.enmReqType & RT_BIT(1);
    1520         uint8_t const  fType2    = pMemReqRemap->Req.enmReqType & RT_BIT(0);
    1521         uint8_t const  fExec     = pMemReqRemap->Req.fReqPerm & DMAR_PERM_EXE;
    1522         uint8_t const  fPriv     = pMemReqRemap->Req.fReqPerm & DMAR_PERM_PRIV;
    1523         bool const     fHasPasid = PCIPASID_IS_VALID(pMemReqRemap->Req.Pasid);
    1524         uint32_t const uPasid    = PCIPASID_VAL(pMemReqRemap->Req.Pasid);
    1525         PCIADDRTYPE const enmAt  = pMemReqRemap->Req.enmAddrType;
     1562    if (!pMemReqAux->fFpd)
     1563    {
     1564        uint16_t const idDevice  = pMemReqIn->idDevice;
     1565        uint8_t const  fType1    = pMemReqIn->enmReqType & RT_BIT(1);
     1566        uint8_t const  fType2    = pMemReqIn->enmReqType & RT_BIT(0);
     1567        uint8_t const  fExec     = pMemReqIn->AddrRange.fPerm & DMAR_PERM_EXE;
     1568        uint8_t const  fPriv     = pMemReqIn->AddrRange.fPerm & DMAR_PERM_PRIV;
     1569        bool const     fHasPasid = PCIPASID_IS_VALID(pMemReqIn->Pasid);
     1570        uint32_t const uPasid    = PCIPASID_VAL(pMemReqIn->Pasid);
     1571        PCIADDRTYPE const enmAt  = pMemReqIn->enmAddrType;
    15261572
    15271573        uint64_t const uFrcdHi = RT_BF_MAKE(VTD_BF_1_FRCD_REG_SID,  idDevice)
     
    15351581                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_T1,   fType1)
    15361582                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_F,    1);
    1537         uint64_t const uFrcdLo = pMemReqRemap->Req.uDmaAddr & X86_PAGE_BASE_MASK;
     1583        uint64_t const uFrcdLo = pMemReqIn->AddrRange.uAddr & X86_PAGE_BASE_MASK;
    15381584        dmarPrimaryFaultRecord(pDevIns, enmDiag, uFrcdHi, uFrcdLo);
    15391585    }
     1586}
     1587
     1588
     1589/**
     1590 * Records an address translation fault.
     1591 *
     1592 * @param   pDevIns         The IOMMU device instance.
     1593 * @param   enmDiag         The diagnostic reason.
     1594 * @param   enmAtFault      The address translation fault reason.
     1595 * @param   pMemReqRemap    The DMA memory request remapping info.
     1596 */
     1597static void dmarAtFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARMEMREQREMAP pMemReqRemap)
     1598{
     1599    dmarAtFaultRecordEx(pDevIns, enmDiag, enmAtFault, &pMemReqRemap->In, &pMemReqRemap->Aux);
    15401600}
    15411601
     
    19972057
    19982058/**
    1999  * Validates the output address of a translation and updates the IOTLB entry for the
    2000  * given memory request remapping.
     2059 * Validates and updates the output I/O page of a translation.
    20012060 *
    20022061 * @returns VBox status code.
    2003  * @param   pDevIns         The IOMMU device instance.
    2004  * @param   GCPhysBase      The output address of the translation.
    2005  * @param   cShift          The page shift of the translation.
    2006  * @param   fPerm           The permissions granted for the translated.
    2007  * @param   idDomain        The domain ID of the translated region.
    2008  * @param   pMemReqRemap    The DMA memory request remapping info.
    2009  */
    2010 static int dmarDrValidateAndUpdateIotlbe(PPDMDEVINS pDevIns, RTGCPHYS GCPhysBase, uint8_t cShift, uint8_t fPerm,
    2011                                          uint16_t idDomain, PDMARMEMREQREMAP pMemReqRemap)
    2012 {
    2013     Assert(   pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE
    2014            || pMemReqRemap->fTtm == VTD_TTM_SCALABLE_MODE);
     2062 * @param   pDevIns     The IOMMU device instance.
     2063 * @param   GCPhysBase  The output address of the translation.
     2064 * @param   cShift      The page shift of the translated address.
     2065 * @param   fPerm       The permissions granted for the translated region.
     2066 * @param   pMemReqIn   The DMA memory request input.
     2067 * @param   pMemReqAux  The DMA memory request auxiliary info.
     2068 * @param   pIoPageOut  Where to store the output of the translation.
     2069 */
     2070static int dmarDrUpdateIoPageOut(PPDMDEVINS pDevIns, RTGCPHYS GCPhysBase, uint8_t cShift, uint8_t fPerm,
     2071                                 PCDMARMEMREQIN pMemReqIn, PCDMARMEMREQAUX pMemReqAux, PDMARIOPAGE pIoPageOut)
     2072{
    20152073    Assert(!(GCPhysBase & X86_PAGE_4K_OFFSET_MASK));
    20162074
     
    20182076    if (GCPhysBase - VBOX_MSI_ADDR_BASE >= VBOX_MSI_ADDR_SIZE)
    20192077    {
    2020         pMemReqRemap->Iotlbe.GCPhysBase = GCPhysBase;
    2021         pMemReqRemap->Iotlbe.cShift     = cShift;
    2022         pMemReqRemap->Iotlbe.fPerm      = fPerm;
    2023         pMemReqRemap->Iotlbe.idDomain   = idDomain;
     2078        pIoPageOut->GCPhysBase = GCPhysBase;
     2079        pIoPageOut->cShift     = cShift;
     2080        pIoPageOut->fPerm       = fPerm;
    20242081        return VINF_SUCCESS;
    20252082    }
    20262083
    2027     if (pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE)
    2028         dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lgn_4, VTDATFAULT_LGN_4, pMemReqRemap);
     2084    if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE)
     2085        dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lgn_4, VTDATFAULT_LGN_4, pMemReqIn, pMemReqAux);
    20292086    else
    2030         dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Sgn_8, VTDATFAULT_SGN_8, pMemReqRemap);
     2087        dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Sgn_8, VTDATFAULT_SGN_8, pMemReqIn, pMemReqAux);
    20312088    return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    20322089}
     
    20372094 *
    20382095 * @returns VBox status code.
    2039  * @param   pDevIns         The IOMMU device instance.
    2040  * @param   SlpEntry        The second-level paging entry.
    2041  * @param   cPagingLevel    The paging level.
    2042  * @param   idDomain        The domain ID for the translation.
    2043  * @param   pMemReqRemap    The DMA memory request remapping info.
    2044  */
    2045 static int dmarDrSecondLevelTranslate(PPDMDEVINS pDevIns, VTD_SLP_ENTRY_T SlpEntry, uint8_t cPagingLevel, uint16_t idDomain,
    2046                                       PDMARMEMREQREMAP pMemReqRemap)
     2096 * @param   pDevIns     The IOMMU device instance.
     2097 * @param   pMemReqIn   The DMA memory request input.
     2098 * @param   pMemReqAux  The DMA memory request auxiliary info.
     2099 * @param   pIoPageOut  Where to store the output of the translation.
     2100 */
     2101static DECLCALLBACK(int) dmarDrSecondLevelTranslate(PPDMDEVINS pDevIns, PCDMARMEMREQIN pMemReqIn, PCDMARMEMREQAUX pMemReqAux,
     2102                                                    PDMARIOPAGE pIoPageOut)
    20472103{
    20482104    PCDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PCDMAR);
     2105
     2106    /* Sanity. */
     2107    Assert(pIoPageOut);
     2108    Assert(pMemReqIn->AddrRange.fPerm & (DMAR_PERM_READ | DMAR_PERM_WRITE));
     2109    Assert(   pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE
     2110           || pMemReqAux->fTtm == VTD_TTM_SCALABLE_MODE);
    20492111
    20502112    /* Mask of valid paging entry bits. */
     
    20552117                                                 VTD_SL_PML5E_VALID_MASK };
    20562118
    2057     /* Mask of valid large-page (1GB, 2MB) paging entries. */
    2058     static uint64_t const s_auLargePageRsvd[] = { 0,
    2059                                                   VTD_SL_PDE2M_VALID_MASK,
    2060                                                   VTD_SL_PDPE1G_VALID_MASK,
    2061                                                   0,
    2062                                                   0 };
    2063 
    20642119    /* Paranoia. */
    2065     Assert(cPagingLevel >= 3 && cPagingLevel <= 5);
    2066     AssertCompile(RT_ELEMENTS(s_auPtEntityRsvd) == RT_ELEMENTS(s_auLargePageRsvd));
     2120    Assert(pMemReqAux->cPagingLevel >= 3 && pMemReqAux->cPagingLevel <= 5);
    20672121    AssertCompile(RT_ELEMENTS(s_auPtEntityRsvd) == 5);
    20682122
    20692123    /* Second-level translations restricts input address to an implementation-specific MGAW. */
    2070     uint64_t const uDmaAddr = pMemReqRemap->Req.uDmaAddr;
     2124    uint64_t const uDmaAddr = pMemReqIn->AddrRange.uAddr;
    20712125    if (!(uDmaAddr & pThis->fInvMgawMask))
    20722126    { /* likely */ }
    20732127    else
    20742128    {
    2075         if (pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE)
    2076             dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lgn_1_1, VTDATFAULT_LGN_1_1, pMemReqRemap);
     2129        if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE)
     2130            dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lgn_1_1, VTDATFAULT_LGN_1_1, pMemReqIn, pMemReqAux);
    20772131        else
    2078             dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Sgn_5, VTDATFAULT_SGN_5, pMemReqRemap);
     2132            dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Sgn_5, VTDATFAULT_SGN_5, pMemReqIn, pMemReqAux);
    20792133        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    20802134    }
     
    20842138     * Unlike AMD IOMMU paging, here there is no feature for "skipping" levels.
    20852139     */
    2086     uint64_t uPtEntity = SlpEntry;
    2087     for (int8_t iLevel = cPagingLevel - 1; iLevel >= 0; iLevel--)
     2140    uint64_t uPtEntity = pMemReqAux->uSlptPtr;
     2141    for (int8_t iLevel = pMemReqAux->cPagingLevel - 1; iLevel >= 0; iLevel--)
    20882142    {
    20892143        /*
    20902144         * Read the paging entry for the current level.
    20912145         */
    2092         uint8_t const cLevelShift = 12 + ((iLevel - 1) * 9);
     2146        uint8_t const cLevelShift = X86_PAGE_4K_SHIFT + (iLevel * 9);
    20932147        {
    20942148            uint16_t const idxPte         = (uDmaAddr >> cLevelShift) & UINT64_C(0x1ff);
     
    21002154            else
    21012155            {
    2102                 if (pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE)
    2103                     dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lsl_1, VTDATFAULT_LSL_1, pMemReqRemap);
     2156                if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE)
     2157                    dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lsl_1, VTDATFAULT_LSL_1, pMemReqIn, pMemReqAux);
    21042158                else
    2105                     dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Ssl_1, VTDATFAULT_SSL_1, pMemReqRemap);
     2159                    dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Ssl_1, VTDATFAULT_SSL_1, pMemReqIn, pMemReqAux);
    21062160                return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    21072161            }
     
    21142168         * See Intel spec. 7.1.3 "Fault conditions and Remapping hardware behavior for various request".
    21152169         */
    2116         uint8_t const fReqPerm = pMemReqRemap->Req.fReqPerm & pThis->fPermValidMask;
     2170        uint8_t const fReqPerm = pMemReqIn->AddrRange.fPerm & pThis->fPermValidMask;
    21172171        uint8_t const fPtPerm  = uPtEntity & pThis->fPermValidMask;
     2172        Assert(!(fReqPerm & DMAR_PERM_EXE));                        /* No Execute-requests support yet. */
     2173        Assert(pThis->fExtCapReg & VTD_BF_ECAP_REG_SLADS_MASK);     /* No Second-level access/dirty support. */
    21182174        if ((fPtPerm & fReqPerm) == fReqPerm)
    21192175        { /* likely */ }
    21202176        else
    21212177        {
    2122             if (pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE)
    2123                 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lsl_2, VTDATFAULT_LSL_2, pMemReqRemap);
     2178            if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE)
     2179                dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lsl_2, VTDATFAULT_LSL_2, pMemReqIn, pMemReqAux);
    21242180            else
    2125                 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Ssl_2, VTDATFAULT_SSL_2, pMemReqRemap);
     2181                dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Ssl_2, VTDATFAULT_SSL_2, pMemReqIn, pMemReqAux);
    21262182            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    21272183        }
     
    21342190        else
    21352191        {
    2136             if (pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE)
    2137                 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lsl_2, VTDATFAULT_LSL_2, pMemReqRemap);
     2192            if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE)
     2193                dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lsl_2, VTDATFAULT_LSL_2, pMemReqIn, pMemReqAux);
    21382194            else
    2139                 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Ssl_3, VTDATFAULT_SSL_3, pMemReqRemap);
     2195                dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Ssl_3, VTDATFAULT_SSL_3, pMemReqIn, pMemReqAux);
    21402196            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    21412197        }
     
    21522208            if (fSllpsMask & RT_BIT(iLevel - 1))
    21532209            {
    2154                 RTGCPHYS const GCPhysBase = uPtEntity & ~(RT_BIT_64(cLevelShift) - 1);
    2155                 return dmarDrValidateAndUpdateIotlbe(pDevIns, GCPhysBase, cLevelShift, fPtPerm, idDomain, pMemReqRemap);
     2210                /*
     2211                 * We don't support MTS (asserted below), hence IPAT and EMT fields of the paging entity are ignored.
     2212                 * All other reserved bits are identical to the regular page-size paging entity which we've already
     2213                 * checked above.
     2214                 */
     2215                Assert(!(pThis->fExtCapReg & VTD_BF_ECAP_REG_MTS_MASK));
     2216
     2217                RTGCPHYS const GCPhysBase = uPtEntity & X86_GET_PAGE_BASE_MASK(cLevelShift);
     2218                return dmarDrUpdateIoPageOut(pDevIns, GCPhysBase, cLevelShift, fPtPerm, pMemReqIn, pMemReqAux, pIoPageOut);
    21562219            }
    21572220
    2158             if (pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE)
    2159                 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lsl_2_LargePage, VTDATFAULT_LSL_2, pMemReqRemap);
     2221            if (pMemReqAux->fTtm == VTD_TTM_LEGACY_MODE)
     2222                dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Lsl_2_LargePage, VTDATFAULT_LSL_2, pMemReqIn, pMemReqAux);
    21602223            else
    2161                 dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Ssl_3_LargePage, VTDATFAULT_SSL_3, pMemReqRemap);
     2224                dmarAtFaultRecordEx(pDevIns, kDmarDiag_Atf_Ssl_3_LargePage, VTDATFAULT_SSL_3, pMemReqIn, pMemReqAux);
    21622225            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    21632226        }
     
    21682231        if (iLevel == 0)
    21692232        {
    2170             RTGCPHYS const GCPhysBase = uPtEntity & ~(RT_BIT_64(cLevelShift) - 1);
    2171             return dmarDrValidateAndUpdateIotlbe(pDevIns, GCPhysBase, cLevelShift, fPtPerm, idDomain, pMemReqRemap);
     2233            RTGCPHYS const GCPhysBase = uPtEntity & X86_GET_PAGE_BASE_MASK(cLevelShift);
     2234            return dmarDrUpdateIoPageOut(pDevIns, GCPhysBase, cLevelShift, fPtPerm, pMemReqIn, pMemReqAux, pIoPageOut);
    21722235        }
    21732236    }
     
    21792242
    21802243/**
    2181  * Handles remapping of DMA address requests in legacy mode.
     2244 * Checks whether two consecutive I/O page results of a DMA memory request form a
     2245 * physically contiguous region.
     2246 *
     2247 * @returns @c true if the I/O pages are contiguous, @c false otherwise.
     2248 * @param   pIoPagePrev     The previous I/O page.
     2249 * @param   pIoPage         The current I/O page.
     2250 */
     2251static bool dmarIsIoPageAccessContig(PCDMARIOPAGE pIoPagePrev, PCDMARIOPAGE pIoPage)
     2252{
     2253    /* Paranoia: Permissions for pages of a DMA memory request must be identical. */
     2254    Assert(pIoPagePrev->fPerm  == pIoPage->fPerm);
     2255
     2256    size_t const   cbPrev      = RT_BIT_64(pIoPagePrev->cShift);
     2257    RTGCPHYS const GCPhysPrev  = pIoPagePrev->GCPhysBase;
     2258    RTGCPHYS const GCPhys      = pIoPage->GCPhysBase;
     2259    uint64_t const offMaskPrev = X86_GET_PAGE_OFFSET_MASK(pIoPagePrev->cShift);
     2260    uint64_t const offMask     = X86_GET_PAGE_OFFSET_MASK(pIoPage->cShift);
     2261
     2262    /* Paranoia: Ensure offset bits are 0. */
     2263    Assert(!(GCPhysPrev & offMaskPrev));
     2264    Assert(!(GCPhys     & offMask));
     2265
     2266    if ((GCPhysPrev & ~offMaskPrev) + cbPrev == (GCPhys & ~offMask))
     2267        return true;
     2268    return false;
     2269}
     2270
     2271
     2272/**
     2273 * Looks up the range of addresses for a DMA memory request remapping.
     2274 *
     2275 * @returns VBox status code.
     2276 * @param   pDevIns         The IOMMU device instance.
     2277 * @param   pfnTranslate    The DMA address translation function.
     2278 * @param   pMemReqRemap    The DMA memory request remapping info.
     2279 */
     2280static int dmarDrMemRangeLookup(PPDMDEVINS pDevIns, PFNDMAADDRTRANSLATE pfnTranslate, PDMARMEMREQREMAP pMemReqRemap)
     2281{
     2282    RTGCPHYS       GCPhysAddr  = NIL_RTGCPHYS;
     2283    DMARMEMREQIN   MemReqIn    = pMemReqRemap->In;
     2284    uint64_t const uAddrIn     = pMemReqRemap->In.AddrRange.uAddr;
     2285    size_t const   cbAddrIn    = pMemReqRemap->In.AddrRange.cb;
     2286    uint64_t       uAddrInBase = pMemReqRemap->In.AddrRange.uAddr & X86_PAGE_4K_BASE_MASK;
     2287    uint64_t       offAddrIn   = pMemReqRemap->In.AddrRange.uAddr & X86_PAGE_4K_OFFSET_MASK;
     2288    size_t         cbRemaining = cbAddrIn;
     2289
     2290    int rc;
     2291    DMARIOPAGE IoPagePrev;
     2292    RT_ZERO(IoPagePrev);
     2293    for (;;)
     2294    {
     2295        /* Update the input memory request with the next address in our range that needs translation. */
     2296        MemReqIn.AddrRange.uAddr = uAddrInBase;
     2297        MemReqIn.AddrRange.cb    = cbRemaining;  /* Not currently accessed by pfnTranslate, but keep things consistent. */
     2298
     2299        DMARIOPAGE IoPage;
     2300        rc = pfnTranslate(pDevIns, &MemReqIn, &pMemReqRemap->Aux, &IoPage);
     2301        if (RT_SUCCESS(rc))
     2302        {
     2303            Assert(IoPage.cShift >= X86_PAGE_4K_SHIFT);
     2304
     2305            /* Store the translated address before continuing to access more pages. */
     2306            if (cbRemaining == cbAddrIn)
     2307            {
     2308                uint64_t const fIoPageMask = X86_GET_PAGE_OFFSET_MASK(IoPage.cShift);
     2309                uint64_t const offAddrOut  = uAddrIn & fIoPageMask;
     2310                Assert(!(IoPage.GCPhysBase & fIoPageMask));
     2311                GCPhysAddr = IoPage.GCPhysBase | offAddrOut;
     2312            }
     2313            /* Check if addresses translated so far result in a physically contiguous region. */
     2314            else if (!dmarIsIoPageAccessContig(&IoPagePrev, &IoPage))
     2315            {
     2316                rc = VERR_OUT_OF_RANGE;
     2317                break;
     2318            }
     2319
     2320            /* Store the I/O page lookup from the first/previous access. */
     2321            IoPagePrev = IoPage;
     2322
     2323            /* Check if we need to access more pages. */
     2324            size_t const cbPage = RT_BIT_64(IoPage.cShift);
     2325            if (cbRemaining > cbPage - offAddrIn)
     2326            {
     2327                cbRemaining -= (cbPage - offAddrIn); /* Calculate how much more we need to access. */
     2328                uAddrInBase += cbPage;               /* Update address of the next access. */
     2329                offAddrIn    = 0;                    /* After first page, all pages are accessed from offset 0. */
     2330            }
     2331            else
     2332            {
     2333                /* Caller (PDM) doesn't expect more data accessed than what was requested. */
     2334                cbRemaining = 0;
     2335                break;
     2336            }
     2337        }
     2338        else
     2339            break;
     2340    }
     2341
     2342    pMemReqRemap->Out.AddrRange.uAddr = GCPhysAddr;
     2343    pMemReqRemap->Out.AddrRange.cb    = cbAddrIn - cbRemaining;
     2344    pMemReqRemap->Out.AddrRange.fPerm = IoPagePrev.fPerm;
     2345    return rc;
     2346}
     2347
     2348
     2349/**
     2350 * Handles legacy mode DMA address remapping.
    21822351 *
    21832352 * @returns VBox status code.
     
    21882357static int dmarDrLegacyModeRemapAddr(PPDMDEVINS pDevIns, uint64_t uRtaddrReg, PDMARMEMREQREMAP pMemReqRemap)
    21892358{
    2190     Assert(pMemReqRemap->fTtm == VTD_TTM_LEGACY_MODE);    /* Paranoia. */
     2359    Assert(pMemReqRemap->Aux.fTtm == VTD_TTM_LEGACY_MODE);    /* Paranoia. */
    21912360
    21922361    /* Read the root-entry from guest memory. */
    2193     uint8_t const idxRootEntry = RT_HI_U8(pMemReqRemap->Req.idDevice);
     2362    uint8_t const idxRootEntry = RT_HI_U8(pMemReqRemap->In.idDevice);
    21942363    VTD_ROOT_ENTRY_T RootEntry;
    21952364    int rc = dmarDrReadRootEntry(pDevIns, uRtaddrReg, idxRootEntry, &RootEntry);
     
    22082377                /* Read the context-entry from guest memory. */
    22092378                RTGCPHYS const GCPhysCtxTable = RT_BF_GET(uRootEntryQword0, VTD_BF_0_ROOT_ENTRY_CTP);
    2210                 uint8_t const idxCtxEntry = RT_LO_U8(pMemReqRemap->Req.idDevice);
     2379                uint8_t const idxCtxEntry = RT_LO_U8(pMemReqRemap->In.idDevice);
    22112380                VTD_CONTEXT_ENTRY_T CtxEntry;
    22122381                rc = dmarDrReadCtxEntry(pDevIns, GCPhysCtxTable, idxCtxEntry, &CtxEntry);
     
    22172386
    22182387                    /* Note the FPD bit which software can use to supress translation faults from here on in. */
    2219                     pMemReqRemap->fFpd = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_FPD);
     2388                    pMemReqRemap->Aux.fFpd = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_FPD);
    22202389
    22212390                    /* Check if the context-entry is present (must be done before validating reserved bits). */
     
    22282397                        {
    22292398                            /* Get the domain ID for this mapping. */
    2230                             uint16_t const idDomain = RT_BF_GET(uCtxEntryQword1, VTD_BF_1_CONTEXT_ENTRY_DID);
     2399                            pMemReqRemap->Out.idDomain = RT_BF_GET(uCtxEntryQword1, VTD_BF_1_CONTEXT_ENTRY_DID);
    22312400
    22322401                            /* Validate the translation type (TT). */
     
    22412410                                     * through SLPTPTR. Translated requests and Translation Requests are blocked.
    22422411                                     */
    2243                                     if (pMemReqRemap->Req.enmAddrType == PCIADDRTYPE_UNTRANSLATED)
     2412                                    if (pMemReqRemap->In.enmAddrType == PCIADDRTYPE_UNTRANSLATED)
    22442413                                    {
    22452414                                        /* Validate the address width and get the paging level. */
     
    22482417                                        {
    22492418                                            /* Read the SLPTPTR from guest memory. */
     2419                                            VTD_SLP_ENTRY_T SlptPtr;
    22502420                                            RTGCPHYS const GCPhysSlptPtr = uCtxEntryQword0 & VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK;
    2251                                             VTD_SLP_ENTRY_T SlpEntry;
    2252                                             rc = dmarDrReadSlpPtr(pDevIns, GCPhysSlptPtr, &SlpEntry);
     2421                                            rc = dmarDrReadSlpPtr(pDevIns, GCPhysSlptPtr, &SlptPtr);
    22532422                                            if (RT_SUCCESS(rc))
    22542423                                            {
    22552424                                                /* Finally... perform second-level translation. */
    2256                                                 return dmarDrSecondLevelTranslate(pDevIns, SlpEntry, cPagingLevel, idDomain,
    2257                                                                                   pMemReqRemap);
     2425                                                pMemReqRemap->Aux.uSlptPtr     = SlptPtr;
     2426                                                pMemReqRemap->Aux.cPagingLevel = cPagingLevel;
     2427                                                return dmarDrMemRangeLookup(pDevIns, dmarDrSecondLevelTranslate, pMemReqRemap);
    22582428                                            }
    22592429                                            dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_3, VTDATFAULT_LCT_4_3, pMemReqRemap);
     
    22762446                                    if (pThis->fExtCapReg & VTD_BF_ECAP_REG_PT_MASK)
    22772447                                    {
    2278                                         if (pMemReqRemap->Req.enmAddrType == PCIADDRTYPE_UNTRANSLATED)
     2448                                        if (pMemReqRemap->In.enmAddrType == PCIADDRTYPE_UNTRANSLATED)
    22792449                                        {
    22802450                                            if (dmarDrLegacyModeIsAwValid(pThis, &CtxEntry, NULL /* pcPagingLevel */))
    22812451                                            {
    2282                                                 pMemReqRemap->Iotlbe.GCPhysBase = pMemReqRemap->Req.uDmaAddr & X86_PAGE_4K_BASE_MASK;
    2283                                                 pMemReqRemap->Iotlbe.cShift     = X86_PAGE_4K_SHIFT;
    2284                                                 pMemReqRemap->Iotlbe.fPerm      = DMAR_PERM_ALL;
    2285                                                 pMemReqRemap->Iotlbe.idDomain   = idDomain;
    2286                                                 pMemReqRemap->cbContiguous      = pMemReqRemap->Req.cbDma;
     2452                                                PDMARMEMREQOUT pOut = &pMemReqRemap->Out;
     2453                                                PCDMARMEMREQIN pIn  = &pMemReqRemap->In;
     2454                                                pOut->AddrRange.uAddr = pIn->AddrRange.uAddr & X86_PAGE_4K_BASE_MASK;
     2455                                                pOut->AddrRange.cb    = pIn->AddrRange.cb;
     2456                                                pOut->AddrRange.fPerm = DMAR_PERM_ALL;
    22872457                                                return VINF_SUCCESS;
    22882458                                            }
     
    24312601        DMARMEMREQREMAP MemReqRemap;
    24322602        RT_ZERO(MemReqRemap);
    2433         MemReqRemap.Req.uDmaAddr      = uIova;
    2434         MemReqRemap.Req.cbDma         = cbIova;
    2435         MemReqRemap.Req.fReqPerm      = fReqPerm;
    2436         MemReqRemap.Req.idDevice      = idDevice;
    2437         MemReqRemap.Req.Pasid         = NIL_PCIPASID;
    2438         MemReqRemap.Req.enmAddrType   = PCIADDRTYPE_UNTRANSLATED;
    2439         MemReqRemap.Req.enmReqType    = enmReqType;
    2440         MemReqRemap.fTtm              = fTtm;
    2441         MemReqRemap.Iotlbe.GCPhysBase = NIL_RTGCPHYS;
     2603        MemReqRemap.In.AddrRange.uAddr  = uIova;
     2604        MemReqRemap.In.AddrRange.cb     = cbIova;
     2605        MemReqRemap.In.AddrRange.fPerm  = fReqPerm;
     2606        MemReqRemap.In.idDevice         = idDevice;
     2607        MemReqRemap.In.Pasid            = NIL_PCIPASID;
     2608        MemReqRemap.In.enmAddrType      = PCIADDRTYPE_UNTRANSLATED;
     2609        MemReqRemap.In.enmReqType       = enmReqType;
     2610        MemReqRemap.Aux.fTtm            = fTtm;
     2611        MemReqRemap.Out.AddrRange.uAddr = NIL_RTGCPHYS;
    24422612
    24432613        int rc;
     
    24742644        }
    24752645
    2476         *pcbContiguous = MemReqRemap.cbContiguous;
    2477         *pGCPhysSpa    = MemReqRemap.Iotlbe.GCPhysBase
    2478                        | (uIova & DMAR_GET_PAGE_OFF_MASK(MemReqRemap.Iotlbe.cShift));
     2646        *pcbContiguous = MemReqRemap.Out.AddrRange.cb;
     2647        *pGCPhysSpa    = MemReqRemap.Out.AddrRange.uAddr;
    24792648        return rc;
    24802649    }
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