VirtualBox

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


Ignore:
Timestamp:
May 27, 2021 10:44:15 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

    r89307 r89312  
    306306    /** @} */
    307307
    308     /** Host-address width (HAW) mask. */
     308    /** Host-address width (HAW) valid mask. */
    309309    uint64_t                    fHawMask;
    310     /** Maximum guest-address width (MGAW) mask. */
     310    /** Maximum guest-address width (MGAW) valid mask. */
    311311    uint64_t                    fMgawMask;
    312312
     
    432432    /** The extended attributes of the request (VTD_REQ_ATTR_XXX). */
    433433    uint8_t                 fReqAttr;
    434     /** Padding. */
    435     uint8_t                 bPadding;
     434    /** The fault processing disabled (FPD) bit. */
     435    uint8_t                 fFpd;
    436436    /** The PASID if present, can be NIL_PCIPASID. */
    437437    PCIPASID                Pasid;
     
    451451    /** The size of the contiguous translated region (in bytes). */
    452452    size_t                  cbContiguous;
     453    /** The domain ID. */
     454    uint16_t                idDomain;
    453455} DMARADDRMAP;
    454456/** Pointer to a DMA address remapping object. */
     
    14061408static void dmarAtFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARADDRMAP pAddrRemap)
    14071409{
    1408     uint8_t const fType1 = pAddrRemap->enmReqType & RT_BIT(1);
    1409     uint8_t const fType2 = pAddrRemap->enmReqType & RT_BIT(0);
    1410     uint8_t const fExec  = pAddrRemap->fReqAttr & VTD_REQ_ATTR_EXE;
    1411     uint8_t const fPriv  = pAddrRemap->fReqAttr & VTD_REQ_ATTR_PRIV;
    1412     uint64_t const uFrcdHi = RT_BF_MAKE(VTD_BF_1_FRCD_REG_SID,  pAddrRemap->idDevice)
    1413                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_T2,   fType2)
    1414                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PP,   PCIPASID_IS_VALID(pAddrRemap->Pasid))
    1415                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_EXE,  fExec)
    1416                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PRIV, fPriv)
    1417                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_FR,   enmAtFault)
    1418                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PV,   PCIPASID_VAL(pAddrRemap->Pasid))
    1419                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_AT,   pAddrRemap->enmAddrType)
    1420                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_T1,   fType1)
    1421                            | RT_BF_MAKE(VTD_BF_1_FRCD_REG_F,    1);
    1422     uint64_t const uFrcdLo = pAddrRemap->uDmaAddr & X86_PAGE_BASE_MASK;
    1423     dmarPrimaryFaultRecord(pDevIns, enmDiag, uFrcdHi, uFrcdLo);
    1424 }
    1425 
    1426 
    1427 /**
    1428  * Records a qualified address translation fault.
    1429  *
    1430  * Qualified faults are those that can be suppressed by software using the FPD bit
    1431  * in the contex entry, scalable-mode context entry etc.
    1432  *
    1433  * This is to be used when Device-TLB, and PASIDs are not supported or for requests
    1434  * where the device-TLB and PASID is not relevant/present.
    1435  *
    1436  * @param   pDevIns             The IOMMU device instance.
    1437  * @param   enmDiag             The diagnostic reason.
    1438  * @param   enmAtFault          The address translation fault reason.
    1439  * @param   pAddrRemap          The DMA address remap info.
    1440  * @param   uPagingEntryQw0     The first qword of the paging entry.
    1441  */
    1442 static void dmarAtFaultQualifiedRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTDATFAULT enmAtFault, PCDMARADDRMAP pAddrRemap,
    1443                                        uint64_t uPagingEntryQw0)
    1444 {
    1445     AssertCompile(    VTD_BF_0_CONTEXT_ENTRY_FPD_MASK       == 0x2
    1446                    && VTD_BF_0_SM_CONTEXT_ENTRY_FPD_MASK    == 0x2
    1447                    && VTD_BF_0_SM_CONTEXT_ENTRY_FPD_MASK    == 0x2
    1448                    && VTD_BF_SM_PASID_DIR_ENTRY_FPD_MASK    == 0x2
    1449                    && VTD_BF_0_SM_PASID_TBL_ENTRY_FPD_MASK  == 0x2);
    1450     if (!(uPagingEntryQw0 & VTD_BF_0_CONTEXT_ENTRY_FPD_MASK))
    1451         dmarAtFaultRecord(pDevIns, enmDiag, enmAtFault, pAddrRemap);
     1410    /*
     1411     * Qualified faults are those that can be suppressed by software using the FPD bit
     1412     * in the contex entry, scalable-mode context entry etc.
     1413     */
     1414    if (!pAddrRemap->fFpd)
     1415    {
     1416        uint8_t const fType1 = pAddrRemap->enmReqType & RT_BIT(1);
     1417        uint8_t const fType2 = pAddrRemap->enmReqType & RT_BIT(0);
     1418        uint8_t const fExec  = pAddrRemap->fReqAttr & VTD_REQ_ATTR_EXE;
     1419        uint8_t const fPriv  = pAddrRemap->fReqAttr & VTD_REQ_ATTR_PRIV;
     1420        uint64_t const uFrcdHi = RT_BF_MAKE(VTD_BF_1_FRCD_REG_SID,  pAddrRemap->idDevice)
     1421                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_T2,   fType2)
     1422                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PP,   PCIPASID_IS_VALID(pAddrRemap->Pasid))
     1423                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_EXE,  fExec)
     1424                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PRIV, fPriv)
     1425                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_FR,   enmAtFault)
     1426                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_PV,   PCIPASID_VAL(pAddrRemap->Pasid))
     1427                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_AT,   pAddrRemap->enmAddrType)
     1428                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_T1,   fType1)
     1429                               | RT_BF_MAKE(VTD_BF_1_FRCD_REG_F,    1);
     1430        uint64_t const uFrcdLo = pAddrRemap->uDmaAddr & X86_PAGE_BASE_MASK;
     1431        dmarPrimaryFaultRecord(pDevIns, enmDiag, uFrcdHi, uFrcdLo);
     1432    }
    14521433}
    14531434
     
    18681849static int dmarDrReadCtxEntry(PPDMDEVINS pDevIns, RTGCPHYS GCPhysCtxTable, uint8_t idxCtxEntry, PVTD_CONTEXT_ENTRY_T pCtxEntry)
    18691850{
     1851    /* We don't verify bits 63:HAW of GCPhysCtxTable is 0 since reading from such an address should fail anyway. */
    18701852    size_t const   cbCtxEntry     = sizeof(*pCtxEntry);
    18711853    RTGCPHYS const GCPhysCtxEntry = GCPhysCtxTable + (idxCtxEntry * cbCtxEntry);
    18721854    return PDMDevHlpPhysReadMeta(pDevIns, GCPhysCtxEntry, pCtxEntry, cbCtxEntry);
     1855}
     1856
     1857
     1858/**
     1859 * Reads a second-level paging entry from guest memory.
     1860 *
     1861 * @returns VBox status code.
     1862 * @param   pDevIns         The IOMMU device instance.
     1863 * @param   GCPhysSlptPtr   The physical address of the SLPTPTR.
     1864 * @param   pSlpEntry       Where to store the read SLPTPTR.
     1865 */
     1866static int dmarDrReadSlpPtr(PPDMDEVINS pDevIns, RTGCPHYS GCPhysSlptPtr, PVTD_SLP_ENTRY_T pSlpEntry)
     1867{
     1868    /* We don't verify bits 63:HAW of GCPhysSlptPtr is 0 since reading from such an address should fail anyway. */
     1869    return PDMDevHlpPhysReadMeta(pDevIns, GCPhysSlptPtr, pSlpEntry, sizeof(*pSlpEntry));
     1870}
     1871
     1872
     1873/**
     1874 * Performs second level translation.
     1875 *
     1876 * @returns VBox status code.
     1877 * @param   pDevIns     The IOMMU device instance.
     1878 * @param   SlpEntry    The second-level paging entry.
     1879 * @param   pAddrRemap      The DMA address remap info.
     1880 */
     1881static int dmarDrSecondLevelTranslate(PPDMDEVINS pDevIns, VTD_SLP_ENTRY_T SlpEntry, PDMARADDRMAP pAddrRemap)
     1882{
     1883    RT_NOREF3(pDevIns, SlpEntry, pAddrRemap);
     1884    /** @todo Implement me */
     1885    return VERR_NOT_IMPLEMENTED;
    18731886}
    18741887
     
    18841897static int dmarDrLegacyModeRemapAddr(PPDMDEVINS pDevIns, uint64_t uRtaddrReg, PDMARADDRMAP pAddrRemap)
    18851898{
     1899    /* Read the root-entry from guest memory. */
    18861900    uint8_t const idxRootEntry = RT_HI_U8(pAddrRemap->idDevice);
    18871901    VTD_ROOT_ENTRY_T RootEntry;
     
    18891903    if (RT_SUCCESS(rc))
    18901904    {
     1905        /* Check if the root entry is present (must be done before validating reserved bits). */
    18911906        uint64_t const uRootEntryQword0 = RootEntry.au64[0];
    18921907        uint64_t const uRootEntryQword1 = RootEntry.au64[1];
     
    18941909        if (fRootEntryPresent)
    18951910        {
     1911            /* Validate reserved bits in the root entry. */
    18961912            if (   !(uRootEntryQword0 & ~VTD_ROOT_ENTRY_0_VALID_MASK)
    18971913                && !(uRootEntryQword1 & ~VTD_ROOT_ENTRY_1_VALID_MASK))
    18981914            {
     1915                /* Read the context-entry from guest memory. */
    18991916                RTGCPHYS const GCPhysCtxTable = RT_BF_GET(uRootEntryQword0, VTD_BF_0_ROOT_ENTRY_CTP);
    19001917                uint8_t const idxCtxEntry = RT_LO_U8(pAddrRemap->idDevice);
    19011918                VTD_CONTEXT_ENTRY_T CtxEntry;
    1902                 /* We don't verify bits 63:HAW of GCPhysCtxTable is 0 since reading from such an address should fail anyway. */
    19031919                rc = dmarDrReadCtxEntry(pDevIns, GCPhysCtxTable, idxCtxEntry, &CtxEntry);
    19041920                if (RT_SUCCESS(rc))
     
    19061922                    uint64_t const uCtxEntryQword0 = CtxEntry.au64[0];
    19071923                    uint64_t const uCtxEntryQword1 = CtxEntry.au64[1];
     1924
     1925                    /* Note the FPD bit which software can use to supress translation faults from here on in. */
     1926                    pAddrRemap->fFpd = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_FPD);
     1927
     1928                    /* Check if the context-entry is present (must be done before validating reserved bits). */
    19081929                    bool const fCtxEntryPresent = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_P);
    19091930                    if (fCtxEntryPresent)
    19101931                    {
     1932                        /* Validate reserved bits in the context-entry. */
    19111933                        if (   !(uCtxEntryQword0 & ~VTD_CONTEXT_ENTRY_0_VALID_MASK)
    19121934                            && !(uCtxEntryQword1 & ~VTD_CONTEXT_ENTRY_1_VALID_MASK))
    19131935                        {
     1936                            /* Validate the translation type (TT). */
    19141937                            PCDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PCDMAR);
    19151938                            uint8_t const fTt = RT_BF_GET(uCtxEntryQword0, VTD_BF_0_CONTEXT_ENTRY_TT);
     
    19181941                                case 0:
    19191942                                {
     1943                                    /*
     1944                                     * Untranslated requests are translated using second-level paging structures referenced
     1945                                     * through SLPTPTR. Translated requests and Translation Requests are blocked.
     1946                                     */
    19201947                                    if (pAddrRemap->enmAddrType == PCIADDRTYPE_UNTRANSLATED)
    19211948                                    {
     1949                                        /* Validate the address width. */
    19221950                                        if (dmarDrLegacyModeIsAwValid(pThis, &CtxEntry))
    19231951                                        {
    1924 
    1925                                             return VERR_NOT_IMPLEMENTED;
     1952                                            /* Read the SLPTPTR from guest memory. */
     1953                                            RTGCPHYS const GCPhysSlptPtr = uCtxEntryQword0 & VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK;
     1954                                            VTD_SLP_ENTRY_T SlpEntry;
     1955                                            rc = dmarDrReadSlpPtr(pDevIns, GCPhysSlptPtr, &SlpEntry);
     1956                                            if (RT_SUCCESS(rc))
     1957                                            {
     1958                                                /* Note the domain ID this context-entry maps to. */
     1959                                                pAddrRemap->idDomain = RT_BF_GET(uCtxEntryQword1, VTD_BF_1_CONTEXT_ENTRY_DID);
     1960
     1961                                                /* Finally... perform second-level translation. */
     1962                                                return dmarDrSecondLevelTranslate(pDevIns, SlpEntry, pAddrRemap);
     1963                                            }
     1964                                            dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_3, VTDATFAULT_LCT_4_3, pAddrRemap);
    19261965                                        }
    19271966                                        else
    1928                                             dmarAtFaultQualifiedRecord(pDevIns, kDmarDiag_Atf_Lct_4_1, VTDATFAULT_LCT_4_1,
    1929                                                                        pAddrRemap, uCtxEntryQword0);
     1967                                            dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_1, VTDATFAULT_LCT_4_1, pAddrRemap);
    19301968                                    }
     1969
    19311970                                    Log4Func(("Translation type blocks translated and translation requests\n"));
    19321971                                    return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
     
    19351974                                case 2:
    19361975                                {
    1937                                     if (pThis->fExtCapReg & VTD_BF_ECAP_REG_PT_MASK)
     1976                                    /*
     1977                                     * Untranslated requests are processed as pass-through (PT) if pass-through is supported.
     1978                                     * Translated and translation requests are blocked. If PT isn't supported this TT value
     1979                                     * is reserved which I assume raises a fault (hence fallthru below).
     1980                                     */
     1981                                    if (   (pThis->fExtCapReg & VTD_BF_ECAP_REG_PT_MASK)
     1982                                        && (pAddrRemap->enmAddrType == PCIADDRTYPE_UNTRANSLATED))
    19381983                                    {
    19391984                                        pAddrRemap->GCPhysSpa    = pAddrRemap->uDmaAddr;
     
    19461991                                case 1:
    19471992                                {
     1993                                    /* We don't support device-TLBs, so this TT value is treated as reserved. */
    19481994                                    Assert(!(pThis->fExtCapReg & VTD_BF_ECAP_REG_DT_MASK));
    19491995                                    RT_FALL_THRU();
     
    19521998                                default:
    19531999                                {
    1954                                     dmarAtFaultQualifiedRecord(pDevIns, kDmarDiag_Atf_Lct_4_2, VTDATFAULT_LCT_4_2, pAddrRemap,
    1955                                                                uCtxEntryQword0);
     2000                                    /* Any other TT value is reserved. */
     2001                                    dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_4_2, VTDATFAULT_LCT_4_2, pAddrRemap);
    19562002                                    break;
    19572003                                }
     
    19592005                        }
    19602006                        else
    1961                             dmarAtFaultQualifiedRecord(pDevIns, kDmarDiag_Atf_Lct_3, VTDATFAULT_LCT_3, pAddrRemap,
    1962                                                        uCtxEntryQword0);
     2007                            dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_3, VTDATFAULT_LCT_3, pAddrRemap);
    19632008                    }
    19642009                    else
    1965                         dmarAtFaultQualifiedRecord(pDevIns, kDmarDiag_Atf_Lct_2, VTDATFAULT_LCT_2, pAddrRemap,
    1966                                                    uCtxEntryQword0);
     2010                        dmarAtFaultRecord(pDevIns, kDmarDiag_Atf_Lct_2, VTDATFAULT_LCT_2, pAddrRemap);
    19672011                }
    19682012                else
     
    31303174    }
    31313175
    3132     uint8_t const fFlts  = 1;                    /* First-Level translation support. */
    3133     uint8_t const fSlts  = 1;                    /* Second-Level translation support. */
     3176    uint8_t const fFlts  = 1;                    /* First-level translation support. */
     3177    uint8_t const fSlts  = 1;                    /* Second-level translation support. */
    31343178    uint8_t const fPt    = 1;                    /* Pass-Through support. */
    31353179    uint8_t const fSmts  = fFlts & fSlts & fPt;  /* Scalable mode translation support.*/
     
    31423186        PDMDevHlpCpuGetGuestAddrWidths(pDevIns, &cGstPhysAddrBits, &cGstLinearAddrBits);
    31433187
    3144         uint8_t const fFl1gp   = 1;                                /* First-Level 1GB pages support. */
     3188        uint8_t const fFl1gp   = 1;                                /* First-level 1GB pages support. */
    31453189        uint8_t const fFl5lp   = 1;                                /* First-level 5-level paging support (PML5E). */
    3146         uint8_t const fSl2mp   = 1;                                /* Second-Level 2MB pages support. */
    3147         uint8_t const fSl2gp   = fSl2mp & 1;                       /* Second-Level 1GB pages support. */
    3148         uint8_t const fSllps   = fSl2mp | (fSl2gp << 1);           /* Second-Level large page Support. */
     3190        uint8_t const fSl2mp   = 1;                                /* Second-level 2MB pages support. */
     3191        uint8_t const fSl2gp   = fSl2mp & 1;                       /* Second-level 1GB pages support. */
     3192        uint8_t const fSllps   = fSl2mp | (fSl2gp << 1);           /* Second-level large page support. */
    31493193        uint8_t const fMamv    = (fSl2gp ? X86_PAGE_1G_SHIFT       /* Maximum address mask value (for 2nd-level invalidations). */
    31503194                                         : X86_PAGE_2M_SHIFT)
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