VirtualBox

Changeset 89552 in vbox


Ignore:
Timestamp:
Jun 8, 2021 5:35:06 AM (3 years ago)
Author:
vboxsync
Message:

Intel IOMMU: bugref:9967 Address translation fixes.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/iommu-intel.h

    r89430 r89552  
    250250/** Pointer to a const context entry. */
    251251typedef VTD_CONTEXT_ENTRY_T const *PCVTD_CONTEXT_ENTRY_T;
     252AssertCompileSize(VTD_CONTEXT_ENTRY_T, 16);
    252253
    253254/** Context Entry: Qword 0 valid mask. */
     
    511512RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FLP_ENTRY_, UINT64_C(0), UINT64_MAX,
    512513                            (P, RW, US, PWT, PCD, A, IGN_6, RSVD_7, IGN_9_8, EA, IGN_11, ADDR, IGN_62_52, XD));
    513 
    514 /** First-Level Paging Entry. */
    515 typedef uint64_t VTD_FLP_ENTRY_T;
    516514/** @} */
    517515
     
    894892                                                                 | VTD_BF_SL_PTE_IGN_10_MASK | VTD_BF_SL_PTE_ADDR_MASK \
    895893                                                                 | VTD_BF_SL_PTE_IGN_61_52_MASK | VTD_BF_SL_PTE_IGN_63_MASK)
    896 /** @} */
    897 
    898 
    899 /** @name Second-Level Generic Paging Entry.
    900  * In accordance with the Intel spec.
    901  * @{ */
    902 /** Second-Level Paging Entry. */
    903 typedef uint64_t VTD_SLP_ENTRY_T;
    904 /** Pointer to a second-level paging entry. */
    905 typedef uint64_t *PVTD_SLP_ENTRY_T;
    906 /** Pointer to a const second-level paging entry. */
    907 typedef uint64_t const *CPVTD_SLP_ENTRY_T;
    908894/** @} */
    909895
  • trunk/src/VBox/Devices/Bus/DevIommuIntel.cpp

    r89548 r89552  
    187187    kDmarDiag_At_Lm_RootEntry_Read_Failed,
    188188    kDmarDiag_At_Lm_RootEntry_Rsvd,
    189     kDmarDiag_At_Lm_Slpptr_Read_Failed,
    190189    kDmarDiag_At_Lm_Tt_Invalid,
    191190    kDmarDiag_At_Lm_Ut_At_Block,
     
    200199    kDmarDiag_At_Xm_Pte_Sllps_Invalid,
    201200    kDmarDiag_At_Xm_Read_Pte_Failed,
     201    kDmarDiag_At_Xm_Slpptr_Read_Failed,
    202202
    203203    /* CCMD_REG faults. */
     
    261261    DMARDIAG_DESC(At_Lm_RootEntry_Read_Failed),
    262262    DMARDIAG_DESC(At_Lm_RootEntry_Rsvd       ),
    263     DMARDIAG_DESC(At_Lm_Slpptr_Read_Failed   ),
    264263    DMARDIAG_DESC(At_Lm_Tt_Invalid           ),
    265264    DMARDIAG_DESC(At_Lm_Ut_At_Block          ),
     
    274273    DMARDIAG_DESC(At_Xm_Pte_Sllps_Invalid    ),
    275274    DMARDIAG_DESC(At_Xm_Read_Pte_Failed      ),
     275    DMARDIAG_DESC(At_Xm_Slpptr_Read_Failed   ),
    276276
    277277    /* CCMD_REG faults. */
     
    555555    uint8_t             cPagingLevel;
    556556    uint8_t             afPadding[5];
    557     /** The first-level page-table pointer.  */
    558     uint64_t            uFlPtPtr;
    559     /** The second-level page-table pointer.  */
    560     uint64_t            uSlPtPtr;
     557    /** The address of the first-level page-table.  */
     558    uint64_t            GCPhysFlPt;
     559    /** The address of second-level page-table.  */
     560    uint64_t            GCPhysSlPt;
    561561} DMARMEMREQAUX;
    562562/** Pointer to a DMA memory request output. */
     
    16171617            case kDmarDiag_At_Lm_RootEntry_Read_Failed:      enmAtFault = VTDATFAULT_LRT_1;    break;
    16181618            case kDmarDiag_At_Lm_RootEntry_Rsvd:             enmAtFault = VTDATFAULT_LRT_3;    break;
    1619             case kDmarDiag_At_Lm_Slpptr_Read_Failed:         enmAtFault = VTDATFAULT_LCT_4_3;  break;
    16201619            case kDmarDiag_At_Lm_Tt_Invalid:                 enmAtFault = VTDATFAULT_LCT_4_2;  break;
    16211620            case kDmarDiag_At_Lm_Ut_At_Block:                enmAtFault = VTDATFAULT_LCT_5;    break;
     
    16341633            case kDmarDiag_At_Xm_Pte_Sllps_Invalid:          enmAtFault = fLm ? VTDATFAULT_LSL_2 : VTDATFAULT_SSL_3;   break;
    16351634            case kDmarDiag_At_Xm_Read_Pte_Failed:            enmAtFault = fLm ? VTDATFAULT_LSL_1 : VTDATFAULT_SSL_1;   break;
     1635            case kDmarDiag_At_Xm_Slpptr_Read_Failed:         enmAtFault = fLm ? VTDATFAULT_LCT_4_3 : VTDATFAULT_SSL_4; break;
    16361636
    16371637            /* Shouldn't ever happen. */
     
    21102110
    21112111/**
    2112  * Reads a second-level page-table pointer from guest memory.
    2113  *
    2114  * @returns VBox status code.
    2115  * @param   pDevIns         The IOMMU device instance.
    2116  * @param   GCPhysSlPtPtr   The physical address of the SLPTPTR.
    2117  * @param   pSlpEntry       Where to store the read SLPTPTR.
    2118  */
    2119 static int dmarDrReadSecondLevelPtPtr(PPDMDEVINS pDevIns, RTGCPHYS GCPhysSlPtPtr, PVTD_SLP_ENTRY_T pSlpEntry)
    2120 {
    2121     /* We don't verify bits 63:HAW of GCPhysSlPtPtr is 0 since reading from such an address should fail anyway. */
    2122     return PDMDevHlpPhysReadMeta(pDevIns, GCPhysSlPtPtr, pSlpEntry, sizeof(*pSlpEntry));
    2123 }
    2124 
    2125 
    2126 /**
    21272112 * Validates and updates the output I/O page of a translation.
    21282113 *
     
    21562141
    21572142/**
    2158  * Performs second level translation.
    2159  *
    2160  * This is a DMA address lookup callback function which performs the translation
     2143 * Performs second level translation by walking the I/O page tables.
     2144 *
     2145 * This is a DMA address-lookup callback function which performs the translation
    21612146 * (and access control) as part of the lookup.
    21622147 *
     
    22032188     * Unlike AMD IOMMU paging, here there is no feature for "skipping" levels.
    22042189     */
    2205     uint64_t uPtEntity   = pMemReqAux->uSlPtPtr;
    2206     int8_t   iLevel      = pMemReqAux->cPagingLevel - 1;
    2207     uint8_t  cLevelShift = X86_PAGE_4K_SHIFT + (iLevel * 9);
    2208     Assert(iLevel >= 2);
    2209     for (;;)
    2210     {
     2190    uint64_t uPtEntity   = pMemReqAux->GCPhysSlPt;
     2191    for (int8_t idxLevel = pMemReqAux->cPagingLevel - 1; idxLevel >= 0; idxLevel--)
     2192    {
     2193        /*
     2194         * Read the paging entry for the current level.
     2195         */
     2196        uint8_t const cLevelShift = X86_PAGE_4K_SHIFT + (idxLevel * 9);
     2197        {
     2198            uint64_t const idxPte         = (uAddrIn >> cLevelShift) & UINT64_C(0x1ff);
     2199            uint64_t const offPte         = idxPte << 3;
     2200            RTGCPHYS const GCPhysPtEntity = (uPtEntity & X86_PAGE_BASE_MASK) | offPte;
     2201            int const rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysPtEntity, &uPtEntity, sizeof(uPtEntity));
     2202            if (RT_SUCCESS(rc))
     2203            { /* likely */ }
     2204            else
     2205            {
     2206                if ((GCPhysPtEntity & X86_PAGE_BASE_MASK) == pMemReqAux->GCPhysSlPt)
     2207                    dmarAtFaultRecord(pDevIns, kDmarDiag_At_Xm_Slpptr_Read_Failed, pMemReqIn, pMemReqAux);
     2208                else
     2209                    dmarAtFaultRecord(pDevIns, kDmarDiag_At_Xm_Read_Pte_Failed, pMemReqIn, pMemReqAux);
     2210                break;
     2211            }
     2212        }
     2213
    22112214        /*
    22122215         * Check I/O permissions.
    22132216         * This must be done prior to check reserved bits for properly reporting errors SSL.2 and SSL.3.
    2214          *
    22152217         * See Intel spec. 7.1.3 "Fault conditions and Remapping hardware behavior for various request".
    22162218         */
     
    22302232         * Validate reserved bits of the current paging entry.
    22312233         */
    2232         if (!(uPtEntity & ~s_auPtEntityRsvd[iLevel]))
     2234        if (!(uPtEntity & ~s_auPtEntityRsvd[idxLevel]))
    22332235        { /* likely */ }
    22342236        else
     
    22432245        AssertCompile(VTD_BF_SL_PDE_PS_MASK == VTD_BF_SL_PDPE_PS_MASK);
    22442246        uint8_t const fLargePage = RT_BF_GET(uPtEntity, VTD_BF_SL_PDE_PS);
    2245         if (fLargePage && iLevel > 0)
     2247        if (fLargePage && idxLevel > 0)
    22462248        {
    2247             Assert(iLevel == 1 || iLevel == 2);     /* Is guaranteed by the reserved bits check above. */
     2249            Assert(idxLevel == 1 || idxLevel == 2);   /* Is guaranteed by the reserved bits check above. */
    22482250            uint8_t const fSllpsMask = RT_BF_GET(pThis->fCapReg, VTD_BF_CAP_REG_SLLPS);
    2249             if (fSllpsMask & RT_BIT(iLevel - 1))
     2251            if (fSllpsMask & RT_BIT(idxLevel - 1))
    22502252            {
    22512253                /*
     
    22672269         * If this is the final PTE, compute the translation address and we're done.
    22682270         */
    2269         if (iLevel == 0)
     2271        if (idxLevel == 0)
    22702272        {
    22712273            RTGCPHYS const GCPhysBase = uPtEntity & X86_GET_PAGE_BASE_MASK(cLevelShift);
    22722274            return dmarDrUpdateIoPageOut(pDevIns, GCPhysBase, cLevelShift, fPtPerm, pMemReqIn, pMemReqAux, pIoPageOut);
    2273         }
    2274 
    2275         /*
    2276          * Move to the next level.
    2277          */
    2278         --iLevel;
    2279         cLevelShift = X86_PAGE_4K_SHIFT + (iLevel * 9);
    2280 
    2281         /*
    2282          * Read the paging entry for the next level.
    2283          */
    2284         {
    2285             uint16_t const idxPte         = (uAddrIn >> cLevelShift) & UINT64_C(0x1ff);
    2286             uint64_t const offPte         = idxPte << 3;
    2287             RTGCPHYS const GCPhysPtEntity = uPtEntity | offPte;
    2288             int const rc = PDMDevHlpPhysReadMeta(pDevIns, GCPhysPtEntity, &uPtEntity, sizeof(uPtEntity));
    2289             if (RT_SUCCESS(rc))
    2290             { /* likely */ }
    2291             else
    2292             {
    2293                 dmarAtFaultRecord(pDevIns, kDmarDiag_At_Xm_Read_Pte_Failed, pMemReqIn, pMemReqAux);
    2294                 break;
    2295             }
    22962275        }
    22972276    }
     
    23402319static int dmarDrMemRangeLookup(PPDMDEVINS pDevIns, PFNDMADDRLOOKUP pfnLookup, PDMARMEMREQREMAP pMemReqRemap)
    23412320{
     2321    AssertPtr(pfnLookup);
     2322
    23422323    RTGCPHYS       GCPhysAddr  = NIL_RTGCPHYS;
    23432324    DMARMEMREQIN   MemReqIn    = pMemReqRemap->In;
     
    24792460                                        if (dmarDrLegacyModeIsAwValid(pThis, &CtxEntry, &cPagingLevel))
    24802461                                        {
    2481                                             /* Read the SLPTPTR from guest memory. */
    2482                                             VTD_SLP_ENTRY_T SlPtPtr;
    2483                                             RTGCPHYS const GCPhysSlPtPtr = uCtxEntryQword0 & VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK;
    2484                                             rc = dmarDrReadSecondLevelPtPtr(pDevIns, GCPhysSlPtPtr, &SlPtPtr);
    2485                                             if (RT_SUCCESS(rc))
    2486                                             {
    2487                                                 /* Finally... perform second-level translation. */
    2488                                                 pMemReqAux->uSlPtPtr     = SlPtPtr;
    2489                                                 pMemReqAux->cPagingLevel = cPagingLevel;
    2490                                                 return dmarDrMemRangeLookup(pDevIns, dmarDrSecondLevelTranslate, pMemReqRemap);
    2491                                             }
    2492                                             dmarAtFaultRecord(pDevIns, kDmarDiag_At_Lm_Slpptr_Read_Failed, pMemReqIn, pMemReqAux);
     2462                                            /*
     2463                                             * The second-level page table is located at the physical address specified
     2464                                             * in the context entry with which we can finally perform second-level translation.
     2465                                             */
     2466                                            pMemReqAux->cPagingLevel = cPagingLevel;
     2467                                            pMemReqAux->GCPhysSlPt   = uCtxEntryQword0 & VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK;
     2468                                            Assert(!(pMemReqAux->GCPhysSlPt & X86_PAGE_OFFSET_MASK));
     2469                                            return dmarDrMemRangeLookup(pDevIns, dmarDrSecondLevelTranslate, pMemReqRemap);
    24932470                                        }
    24942471                                        else
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