VirtualBox

Ignore:
Timestamp:
May 7, 2020 7:11:49 AM (5 years ago)
Author:
vboxsync
Message:

AMD IOMMU: bugref:9654 Bits.

File:
1 edited

Legend:

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

    r84171 r84181  
    22132213typedef struct
    22142214{
    2215     /** The device ID. */
    2216     uint16_t        uDevId;
    2217     /** The domain ID. */
    2218     uint16_t        uDomainId;
    2219     /** @todo Shouldn't we also store how many bits are the offset into the page for
    2220      *        pages > 4K? */
    2221     /** The I/O virtual address. */
    2222     uint64_t        uIova;
    2223     /** The translated system physical address. */
    2224     RTGCPHYS        GCPhysSpa;
    22252215    /** The I/O access permissions (IOMMU_IO_PERM_XXX). */
    22262216    uint8_t         fIoPerm;
     2217    /** The number of offset bits in the system physical address. */
     2218    uint8_t         cShift;
     2219    /** Reserved for future (eviction hints?). */
     2220    uint16_t        uRsvd0;
    22272221    /** Alignment padding. */
    2228     uint8_t         fRsvd0;
    2229     /** Reserved for future (eviction hints?). */
    2230     uint32_t        uPadding0;
     2222    uint32_t        uRsvd1;
     2223    /** The translated system physical address of the page. */
     2224    RTGCPHYS        GCPhysSpa;
    22312225} IOTLBE_T;
    22322226AssertCompileSizeAlignment(IOTLBE_T, 8);
     2227AssertCompileMemberAlignment(IOTLBE_T, GCPhysSpa, 8);
    22332228/** Pointer to an IOMMU I/O TLB entry struct. */
    22342229typedef IOTLBE_T *PIOTLBE_T;
     
    37783773 * Initializes an IOTLB entry.
    37793774 *
    3780  * @param   uDevId      The device ID.
    3781  * @param   uDomainId   The domain ID.
     3775 * @param   GCPhysSpa   The translated system physical address.
     3776 * @param   cShift      The number of offset bits in the system physical address.
    37823777 * @param   fIoPerm     The I/O access permissions (IOMMU_IO_PERM_XXX).
    3783  * @param   uIova       The I/O virtual address.
    3784  * @param   GCPhysSpa   The translated system physical address.
    37853778 * @param   pIotlbe     Where to store the initialized IOTLB entry.
    37863779 */
    3787 static void iommuAmdInitIotlbe(uint16_t uDevId, uint16_t uDomainId, uint8_t fIoPerm, uint64_t uIova, RTGCPHYS GCPhysSpa,
    3788                                PIOTLBE_T pIotlbe)
    3789 {
    3790     pIotlbe->uDevId    = uDevId;
    3791     pIotlbe->uDomainId = uDomainId;
     3780static void iommuAmdInitIotlbe(RTGCPHYS GCPhysSpa, uint8_t cShift, uint8_t fIoPerm, PIOTLBE_T pIotlbe)
     3781{
    37923782    pIotlbe->fIoPerm   = fIoPerm;
    3793     pIotlbe->fRsvd0    = 0;
    3794     pIotlbe->uPadding0 = 0;
    3795     pIotlbe->uIova     = uIova;
     3783    pIotlbe->uRsvd0    = 0;
     3784    pIotlbe->uRsvd1    = 0;
     3785    pIotlbe->cShift    = cShift;
    37963786    pIotlbe->GCPhysSpa = GCPhysSpa;
    37973787}
     
    38793869 * @param   pDte        The device table entry.
    38803870 * @param   enmOp       The IOMMU operation being performed.
    3881  * @param   pGCPhysSpa  Where to store the system physical address.
    3882  * @param   pfIoPerm    Where to store the I/O access permissions. This is the
    3883  *                      permission of what access is allowed.
     3871 * @param   pIotlbe     The IOTLB entry to update with the results of the
     3872 *                      translation.
    38843873 */
    38853874static int iommuAmdWalkIoPageTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess,
    3886                                     PCDTE_T pDte, IOMMUOP enmOp, PRTGCPHYS pGCPhysSpa, uint8_t *pfIoPerm)
     3875                                    PCDTE_T pDte, IOMMUOP enmOp, PIOTLBE_T pIotlbe)
    38873876{
    38883877    NOREF(pDevIns);
     
    38973886        iommuAmdRaiseIoPageFaultEvent(pDevIns, uDevId, pDte->n.u16DomainId, uIova, true /* fPresentOrValid */,
    38983887                                      enmOp, kIoPageFaultType_DteTranslationDisabled);
    3899         *pGCPhysSpa = 0;
    3900         *pfIoPerm   = 0;
     3888        iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /* cShift */,  IOMMU_IO_PERM_NONE, pIotlbe);
    39013889        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    39023890    }
     
    39113899            return VERR_IOMMU_ADDR_ACCESS_DENIED;
    39123900        }
    3913         *pGCPhysSpa = uIova;
    3914         *pfIoPerm   = fDtePerm;
     3901        iommuAmdInitIotlbe(uIova, 0 /* cShift */, fDtePerm, pIotlbe);
    39153902        return VINF_SUCCESS;
    39163903    }
     
    39223909         *        raising an ILLEGAL_DEV_TABLE_ENTRY event or an IO_PAGE_FAULT event here.
    39233910         *        I'm just going with this one... */
    3924         *pGCPhysSpa = 0;
    3925         *pfIoPerm   = IOMMU_IO_PERM_NONE;
     3911        /** @todo IOMMU: raise I/O page fault. */
     3912        iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /* cShift */,  IOMMU_IO_PERM_NONE, pIotlbe);
    39263913        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    39273914    }
     
    39523939    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
    39533940
    3954     /* Read the device table entry. */
     3941    /* Read the device table entry from memory. */
    39553942    DTE_T Dte;
    39563943    int rc = iommuAmdReadDte(pDevIns, uDevId, enmOp, &Dte);
    39573944    if (RT_SUCCESS(rc))
    39583945    {
    3959         RTGCPHYS GCPhysSpa = 0;
    3960         uint8_t  fIoPerm   = IOMMU_IO_PERM_NONE;
    3961 
     3946        /* If the DTE is not valid addresses are forwarded without translation */
    39623947        if (Dte.n.u1Valid)
    3963         {
    3964             /* Validate bits 127:0 of the device table entry when DTE.V is 1. */
    3965             uint64_t const fRsvdQword0 = Dte.au64[0] & ~(IOMMU_DTE_QWORD_0_VALID_MASK & ~IOMMU_DTE_QWORD_0_FEAT_MASK);
    3966             uint64_t const fRsvdQword1 = Dte.au64[1] & ~(IOMMU_DTE_QWORD_1_VALID_MASK & ~IOMMU_DTE_QWORD_1_FEAT_MASK);
    3967             if (   fRsvdQword0
    3968                 || fRsvdQword1)
    3969             {
    3970                 Log((IOMMU_LOG_PFX ": Invalid reserved bits in DTE (u64[0]=%#RX64 u64[1]=%#RX64) -> Illegal DTE\n", fRsvdQword0,
    3971                      fRsvdQword1));
    3972                 iommuAmdRaiseIllegalDteEvent(pDevIns, uDevId, uIova, enmOp, kIllegalDteType_RsvdNotZero);
    3973                 return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    3974             }
    3975 
    3976             /* Ensure the IOVA is not in the exclusion range. */
    3977             if (   !pThis->ExclRangeBaseAddr.n.u1ExclEnable
    3978                 || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova))
    3979             {
    3980                 rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uIova, cbAccess, IOMMU_IO_PERM_READ, &Dte, enmOp, &GCPhysSpa,
    3981                                               &fIoPerm);
    3982                 if (RT_FAILURE(rc))
    3983                     Log((IOMMU_LOG_PFX ": I/O page table walk failed. rc=%Rrc\n"));
    3984             }
    3985             else
    3986             {
    3987                 /* If the IOVA is subject to address exclusion, addresses are forwarded without translation. */
    3988                 GCPhysSpa = uIova;
    3989                 fIoPerm   = IOMMU_IO_PERM_READ_WRITE;
    3990             }
    3991         }
     3948        { /* likely */ }
    39923949        else
    39933950        {
    3994             /* Addresses are forwarded without translation when DTE.V is 0. */
    3995             GCPhysSpa = uIova;
    3996             fIoPerm   = IOMMU_IO_PERM_READ_WRITE;
    3997         }
    3998 
    3999         pIotlbe->GCPhysSpa = GCPhysSpa;
    4000         pIotlbe->fIoPerm   = fIoPerm;
    4001     }
    4002     else
    4003     {
    4004         Log((IOMMU_LOG_PFX ": Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc));
    4005         return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    4006     }
    4007 
    4008     return rc;
     3951            iommuAmdInitIotlbe(uIova, 0 /* cShift */, IOMMU_IO_PERM_READ_WRITE, pIotlbe);
     3952            return VINF_SUCCESS;
     3953        }
     3954
     3955        /* Validate bits 127:0 of the device table entry when DTE.V is 1. */
     3956        uint64_t const fRsvdQword0 = Dte.au64[0] & ~(IOMMU_DTE_QWORD_0_VALID_MASK & ~IOMMU_DTE_QWORD_0_FEAT_MASK);
     3957        uint64_t const fRsvdQword1 = Dte.au64[1] & ~(IOMMU_DTE_QWORD_1_VALID_MASK & ~IOMMU_DTE_QWORD_1_FEAT_MASK);
     3958        if (RT_LIKELY(   !fRsvdQword0
     3959                      && !fRsvdQword1))
     3960        { /* likely */ }
     3961        else
     3962        {
     3963            Log((IOMMU_LOG_PFX ": Invalid reserved bits in DTE (u64[0]=%#RX64 u64[1]=%#RX64) -> Illegal DTE\n", fRsvdQword0,
     3964                 fRsvdQword1));
     3965            iommuAmdRaiseIllegalDteEvent(pDevIns, uDevId, uIova, enmOp, kIllegalDteType_RsvdNotZero);
     3966            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
     3967        }
     3968
     3969        /* If the IOVA is subject to address exclusion addresses are forwarded without translation. */
     3970        if (   !pThis->ExclRangeBaseAddr.n.u1ExclEnable
     3971            || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova))
     3972        { /* likely */ }
     3973        else
     3974        {
     3975            iommuAmdInitIotlbe(uIova, 0 /* cShift */, IOMMU_IO_PERM_READ_WRITE, pIotlbe);
     3976            return VINF_SUCCESS;
     3977        }
     3978
     3979        /* Walk the I/O page tables to translate and get permission bits for the IOVA. */
     3980        rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uIova, cbAccess, IOMMU_IO_PERM_READ, &Dte, enmOp, pIotlbe);
     3981        if (RT_FAILURE(rc))
     3982            Log((IOMMU_LOG_PFX ": I/O page table walk failed. rc=%Rrc\n"));
     3983
     3984        return rc;
     3985    }
     3986
     3987    Log((IOMMU_LOG_PFX ": Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc));
     3988    return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    40093989}
    40103990
     
    40354015    {
    40364016        IOTLBE_T Iotlbe;
    4037         iommuAmdInitIotlbe(uDevId, 0 /* uDomainId */, IOMMU_IO_PERM_NONE, uIova, 0 /* GCPhySpa */, &Iotlbe);
     4017        iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /*cShift*/, IOMMU_IO_PERM_NONE, &Iotlbe);
    40384018
    40394019        /** @todo IOMMU: IOTLB cache lookup. */
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