VirtualBox

Changeset 84170 in vbox


Ignore:
Timestamp:
May 6, 2020 4:50:36 PM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
137775
Message:

AMD IOMMU: bugref:9654 Bits.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/err.h

    r83474 r84170  
    29672967#define VERR_SHCLPB_MAX_EVENTS_REACHED              (-7106)
    29682968/** @} */
     2969
     2970/** @name Virtual IOMMU Status Codes
     2971 * @{
     2972 */
     2973/** Internal processing error \#1 in the IOMMU device code. */
     2974#define VERR_IOMMU_IPE_1                            (-7201)
     2975/** Internal processing error \#2 in the IOMMU device code. */
     2976#define VERR_IOMMU_IPE_2                            (-7202)
     2977/** Address translation failed. */
     2978#define VERR_IOMMU_ADDR_TRANSLATION_FAILED          (-7203)
     2979/** Access denied for the address. */
     2980#define VERR_IOMMU_ADDR_ACCESS_DENIED               (-7204)
     2981/** @} */
     2982
    29692983/* SED-END */
    29702984
  • trunk/include/VBox/vmm/pdmdev.h

    r83987 r84170  
    12611261     * @param   pDevIns     The IOMMU device instance.
    12621262     * @param   uDevId      The device identifier (bus, device, function).
    1263      * @param   uDva        The device virtual address being read.
     1263     * @param   uIova       The I/O virtual address being read.
    12641264     * @param   cbRead      The number of bytes being read.
    1265      * @param   pGCPhysOut  Where to store the translated physical address.
     1265     * @param   pGCPhysSpa  Where to store the translated system physical address.
    12661266     *
    12671267     * @thread  Any.
    12681268     */
    1269     DECLR0CALLBACKMEMBER(int, pfnMemRead,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbRead,
    1270                                           PRTGCPHYS pGCPhysOut));
     1269    DECLR0CALLBACKMEMBER(int, pfnMemRead,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbRead,
     1270                                          PRTGCPHYS pGCPhysSpa));
    12711271
    12721272    /**
     
    12761276     * @param   pDevIns     The IOMMU device instance.
    12771277     * @param   uDevId      The device identifier (bus, device, function).
    1278      * @param   uDva        The device virtual address being written.
     1278     * @param   uIova       The I/O virtual address being written.
    12791279     * @param   cbRead      The number of bytes being written.
    1280      * @param   pGCPhysOut  Where to store the translated physical address.
     1280     * @param   pGCPhysSpa  Where to store the translated system physical address.
    12811281     *
    12821282     * @thread  Any.
    12831283     */
    1284     DECLR0CALLBACKMEMBER(int, pfnMemWrite,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbWrite,
    1285                                            PRTGCPHYS pGCPhysOut));
     1284    DECLR0CALLBACKMEMBER(int, pfnMemWrite,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbWrite,
     1285                                           PRTGCPHYS pGCPhysSpa));
    12861286
    12871287    /** Just a safety precaution. */
     
    13121312     * @param   pDevIns     The IOMMU device instance.
    13131313     * @param   uDevId      The device identifier (bus, device, function).
    1314      * @param   uDva        The device virtual address.
     1314     * @param   uIova       The I/O virtual address being read.
    13151315     * @param   cbRead      The number of bytes being read.
    1316      * @param   pGCPhysOut  Where to store the translated physical address.
     1316     * @param   pGCPhysSpa  Where to store the translated system physical address.
    13171317     *
    13181318     * @thread  Any.
    13191319     */
    1320     DECLRCCALLBACKMEMBER(int, pfnMemRead,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbRead,
    1321                                           PRTGCPHYS pGCPhysOut));
     1320    DECLRCCALLBACKMEMBER(int, pfnMemRead,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbRead,
     1321                                          PRTGCPHYS pGCPhysSpa));
    13221322
    13231323    /**
     
    13271327     * @param   pDevIns     The IOMMU device instance.
    13281328     * @param   uDevId      The device identifier (bus, device, function).
    1329      * @param   uDva        The device virtual address being written.
     1329     * @param   uIova       The I/O virtual address being written.
    13301330     * @param   cbRead      The number of bytes being written.
    1331      * @param   pGCPhysOut  Where to store the translated physical address.
     1331     * @param   pGCPhysSpa  Where to store the translated system physical address.
    13321332     *
    13331333     * @thread  Any.
    13341334     */
    1335     DECLRCCALLBACKMEMBER(int, pfnMemWrite,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbWrite,
    1336                                            PRTGCPHYS pGCPhysOut));
     1335    DECLRCCALLBACKMEMBER(int, pfnMemWrite,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbWrite,
     1336                                           PRTGCPHYS pGCPhysSpa));
    13371337
    13381338    /** Just a safety precaution. */
     
    13631363     * @param   pDevIns     The IOMMU device instance.
    13641364     * @param   uDevId      The device identifier (bus, device, function).
    1365      * @param   uDva        The device virtual address being read.
     1365     * @param   uIova       The I/O virtual address being read.
    13661366     * @param   cbRead      The number of bytes being read.
    1367      * @param   pGCPhysOut  Where to store the translated physical address.
     1367     * @param   pGCPhysSpa  Where to store the translated system physical address.
    13681368     *
    13691369     * @thread  Any.
    13701370     */
    1371     DECLR3CALLBACKMEMBER(int, pfnMemRead,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbRead,
    1372                                           PRTGCPHYS pGCPhysOut));
     1371    DECLR3CALLBACKMEMBER(int, pfnMemRead,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbRead,
     1372                                          PRTGCPHYS pGCPhysSpa));
    13731373
    13741374    /**
     
    13781378     * @param   pDevIns     The IOMMU device instance.
    13791379     * @param   uDevId      The device identifier (bus, device, function).
    1380      * @param   uDva        The device virtual address being written.
     1380     * @param   uIova       The I/O virtual address being written.
    13811381     * @param   cbWrite     The number of bytes being written.
    1382      * @param   pGCPhysOut  Where to store the translated physical address.
     1382     * @param   pGCPhysSpa  Where to store the translated system physical address.
    13831383     *
    13841384     * @thread  Any.
    13851385     */
    1386     DECLR3CALLBACKMEMBER(int, pfnMemWrite,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbWrite,
    1387                                            PRTGCPHYS pGCPhysOut));
     1386    DECLR3CALLBACKMEMBER(int, pfnMemWrite,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbWrite,
     1387                                           PRTGCPHYS pGCPhysSpa));
    13881388
    13891389    /** Just a safety precaution. */
  • trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp

    r84134 r84170  
    419419/** @} */
    420420
    421 /** @name IOMMU_PERM_XXX: IOMMU I/O access permissions bits.
     421/** @name IOMMU_IO_PERM_XXX: IOMMU I/O access permissions bits.
    422422 * In accordance with the AMD spec.
    423423 *
     
    426426 *
    427427 * @{ */
    428 #define IOMMU_IO_PERM_READ                             RT_BIT_64(0)
    429 #define IOMMU_IO_PERM_WRITE                            RT_BIT_64(1)
    430 #define IOMMU_IO_PERM_SHIFT                            61
    431 #define IOMMU_IO_PERM_MASK                             0x3
     428#define IOMMU_IO_PERM_NONE                          (0)
     429#define IOMMU_IO_PERM_READ                          RT_BIT_64(0)
     430#define IOMMU_IO_PERM_WRITE                         RT_BIT_64(1)
     431#define IOMMU_IO_PERM_READ_WRITE                    (IOMMU_IO_PERM_READ | IOMMU_IO_PERM_WRITE)
     432#define IOMMU_IO_PERM_SHIFT                         61
     433#define IOMMU_IO_PERM_MASK                          0x3
     434/** @} */
     435
     436/** @name SYSMGT_TYPE_XXX: System Management Message Enable Types.
     437 * In accordance with the AMD spec.
     438 * @{ */
     439#define SYSMGTTYPE_DMA_DENY                         (0)
     440#define SYSMGTTYPE_MSG_ALL_ALLOW                    (1)
     441#define SYSMGTTYPE_MSG_INT_ALLOW                    (2)
     442#define SYSMGTTYPE_DMA_ALLOW                        (3)
    432443/** @} */
    433444
     
    545556        RT_GCC_EXTENSION uint64_t  u1GstIoValid : 1;              /**< Bit  54      - GIoV: Guest I/O Protection Valid. */
    546557        RT_GCC_EXTENSION uint64_t  u1GstTranslateValid : 1;       /**< Bit  55      - GV: Guest translation Valid. */
    547         RT_GCC_EXTENSION uint64_t  u2GstCr3RootTblTranslated : 2; /**< Bits 57:56   - GLX: Guest Levels Translated. */
     558        RT_GCC_EXTENSION uint64_t  u2GstMode : 2;                 /**< Bits 57:56   - GLX: Guest Paging mode levels. */
    548559        RT_GCC_EXTENSION uint64_t  u3GstCr3TableRootPtrLo : 2;    /**< Bits 60:58   - GCR3 TRP: Guest CR3 Table Root Ptr (Lo). */
    549560        RT_GCC_EXTENSION uint64_t  u1IoRead : 1;                  /**< Bit  61      - IR: I/O Read permission. */
     
    587598} DTE_T;
    588599AssertCompileSize(DTE_T, 32);
    589 #define IOMMU_DTE_QWORD_0_VALID_MASK      UINT64_C(0x7fffffffffffff83)
    590 #define IOMMU_DTE_QWORD_1_VALID_MASK      UINT64_C(0xfffffbffffffffff)
    591 #define IOMMU_DTE_QWORD_2_VALID_MASK      UINT64_C(0xf70fffffffffffff)
    592 #define IOMMU_DTE_QWORD_3_VALID_MASK      UINT64_C(0xffc0000000000000)
    593600/** Pointer to a device table entry. */
    594601typedef DTE_T *PDTE_T;
    595602/** Pointer to a const device table entry. */
    596603typedef DTE_T const *PCDTE_T;
     604
     605/** Mask of valid  bits for EPHSUP (Enhanced Peripheral Page Request Handling
     606 *  Support) features (bits 52:53). */
     607#define IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK      UINT64_C(0x0030000000000000)
     608
     609/** Mask of valid bits for GTSup (Guest Translation Support) features (bits
     610 *  55:60, bits 80:95). */
     611#define IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK       UINT64_C(0x1f80000000000000)
     612#define IOMMU_DTE_QWORD_1_FEAT_GTSUP_MASK       UINT64_C(0x00000000ffff0000)
     613
     614/* Mask of valid bits for GIoSup (Guest I/O Protection Support) features (bit 54). */
     615#define IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK      UINT64_C(0x0040000000000000)
     616
     617/* Mask of all valid DTE feature bits. */
     618#define IOMMU_DTE_QWORD_0_FEAT_MASK             (  IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK \
     619                                                 | IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK  \
     620                                                 | IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK)
     621#define IOMMU_DTE_QWORD_1_FEAT_MASK             (IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK)
     622
     623/* Mask of all valid DTE bits. */
     624#define IOMMU_DTE_QWORD_0_VALID_MASK            UINT64_C(0x7fffffffffffff83)
     625#define IOMMU_DTE_QWORD_1_VALID_MASK            UINT64_C(0xfffffbffffffffff)
     626#define IOMMU_DTE_QWORD_2_VALID_MASK            UINT64_C(0xf70fffffffffffff)
     627#define IOMMU_DTE_QWORD_3_VALID_MASK            UINT64_C(0xffc0000000000000)
    597628
    598629/**
     
    646677} IOPDE_T;
    647678AssertCompileSize(IOPDE_T, 8);
     679
     680/**
     681 * I/O Page Table Generic Entity.
     682 * In accordance with the AMD spec.
     683 *
     684 * This a common subset of a page table entry.
     685 * Can be either an IOPTE_T or and IOPDE_T.
     686 */
     687typedef union
     688{
     689    struct
     690    {
     691        RT_GCC_EXTENSION uint64_t    u1Present : 1;             /**< Bit  0      - PR: Present. */
     692        RT_GCC_EXTENSION uint64_t    u4Ign0 : 4;                /**< Bits 4:1    - Ignored. */
     693        RT_GCC_EXTENSION uint64_t    u1Accessed : 1;            /**< Bit  5      - A: Accessed. */
     694        RT_GCC_EXTENSION uint64_t    u3Ign0 : 3;                /**< Bits 8:6    - Ignored. */
     695        RT_GCC_EXTENSION uint64_t    u3NextLevel : 3;           /**< Bits 11:9   - Next Level: Next page translation level. */
     696        RT_GCC_EXTENSION uint64_t    u40PageAddr : 40;          /**< Bits 51:12  - Page address. */
     697        RT_GCC_EXTENSION uint64_t    u9Rsvd0 : 9;               /**< Bits 60:52  - Reserved. */
     698        RT_GCC_EXTENSION uint64_t    u1IoRead : 1;              /**< Bit 61      - IR: I/O Read permission. */
     699        RT_GCC_EXTENSION uint64_t    u1IoWrite : 1;             /**< Bit 62      - IW: I/O Wead permission. */
     700        RT_GCC_EXTENSION uint64_t    u1Ign0 : 1;                /**< Bit 63      - Ignored. */
     701    } n;
     702} IOPTENTITY_T;
     703AssertCompileSize(IOPDE_T, 8);
     704/** Pointer to an IOPT_ENTITY_T struct. */
     705typedef IOPTENTITY_T *PIOPTENTITY_T;
     706/** Pointer to a const IOPT_ENTITY_T struct. */
     707typedef IOPTENTITY_T const *PCIOPTENTITY_T;
    648708
    649709/**
     
    903963        uint16_t    u1ReadWrite : 1;        /**< Bit  53     - RW: Read/Write. */
    904964        uint16_t    u1Rsvd1 : 1;            /**< Bit  54     - Reserved. */
    905         uint16_t    u1RsvdNotZero : 1;      /**< Bit  55     - RZ: Reserved bit not Zero or invalid level encoding. */
     965        uint16_t    u1RsvdNotZero : 1;      /**< Bit  55     - RZ: Reserved bit not Zero (0=invalid level encoding). */
    906966        uint16_t    u1Translation : 1;      /**< Bit  56     - TN: Translation. */
    907967        uint16_t    u3Rsvd0 : 3;            /**< Bits 59:57  - Reserved. */
    908968        uint16_t    u4EvtCode : 4;          /**< Bits 63:60  - Event code. */
    909         uint64_t    u64Addr;                /**< Bits 127:64 - Address: Device Virtual Address. */
     969        uint64_t    u64Addr;                /**< Bits 127:64 - Address: I/O Virtual Address (IOVA). */
    910970    } n;
    911971    /** The 32-bit unsigned integer view.  */
     
    934994        uint16_t    u1ReadWrite : 1;        /**< Bit  53     - RW: Read/Write. */
    935995        uint16_t    u1Perm : 1;             /**< Bit  54     - PE: Permission Indicator. */
    936         uint16_t    u1RsvdNotZero : 1;      /**< Bit  55     - RZ: Reserved bit not Zero or invalid level encoding. */
     996        uint16_t    u1RsvdNotZero : 1;      /**< Bit  55     - RZ: Reserved bit not Zero (0=invalid level encoding). */
    937997        uint16_t    u1Translation : 1;      /**< Bit  56     - TN: Translation. */
    938998        uint16_t    u3Rsvd0 : 3;            /**< Bit  59:57  - Reserved. */
    939999        uint16_t    u4EvtCode : 4;          /**< Bits 63:60  - Event code. */
    940         uint64_t    u64Addr;                /**< Bits 127:64 - Address: Device Virtual Address. */
     1000        uint64_t    u64Addr;                /**< Bits 127:64 - Address: I/O Virtual Address (IOVA). */
    9411001    } n;
    9421002    /** The 32-bit unsigned integer view.  */
     
    9441004} EVT_IO_PAGE_FAULT_T;
    9451005AssertCompileSize(EVT_IO_PAGE_FAULT_T, 16);
     1006/** Pointer to an I/O page fault event. */
     1007typedef EVT_IO_PAGE_FAULT_T *PEVT_IO_PAGE_FAULT_T;
    9461008
    9471009/**
     
    13431405        uint32_t    u1X2ApicSup : 1;              /**< Bit  2     - XTSup: x2Apic Support. */
    13441406        uint32_t    u1NoExecuteSup : 1;           /**< Bit  3     - NXSup: No-Execute and Privilege Level Support. */
    1345         uint32_t    u1GstTranslateSup : 1;        /**< Bit  4     - GTSup: Guest Translations Support. */
     1407        uint32_t    u1GstTranslateSup : 1;        /**< Bit  4     - GTSup: Guest Translations (for GVAs) Support. */
    13461408        uint32_t    u1Rsvd0 : 1;                  /**< Bit  5     - Reserved. */
    13471409        uint32_t    u1InvAllSup : 1;              /**< Bit  6     - IASup: Invalidate-All Support. */
     
    20022064
    20032065/**
    2004  * IOMMU operation types.
     2066 * ILLEGAL_DEV_TABLE_ENTRY Event Types.
     2067 * In accordance with the AMD spec.
     2068 */
     2069typedef enum EVT_ILLEGAL_DTE_TYPE_T
     2070{
     2071    kIllegalDteType_RsvdNotZero = 0,
     2072    kIllegalDteType_RsvdIntTab,
     2073    kIllegalDteType_RsvdIoCtl,
     2074    kIllegalDteType_RsvdIntCtl
     2075} EVT_ILLEGAL_DTE_TYPE_T;
     2076
     2077/**
     2078 * ILLEGAL_DEV_TABLE_ENTRY Event Types.
     2079 * In accordance with the AMD spec.
     2080 */
     2081typedef enum EVT_IO_PAGE_FAULT_TYPE_T
     2082{
     2083    /* Memory transaction. */
     2084    kIoPageFaultType_DteRsvdPagingMode = 0,
     2085    kIoPageFaultType_PteInvalidPageSize,
     2086    kIoPageFaultType_PteInvalidLvlEncoding,
     2087    kIoPageFaultType_InvalidSkippedPageLvl,
     2088    kIoPageFaultType_PteRsvdNotZero,
     2089    kIoPageFaultType_PteValidNotSet,
     2090    kIoPageFaultType_DteTranslationDisabled,
     2091    kIoPageFaultType_PasidInvalidRange,
     2092    kIoPageFaultType_ReadProtect,
     2093    kIoPageFaultType_WriteProtect,
     2094    kIoPageFaultType_ExecuteProtect,
     2095    kIoPageFaultType_UserSupervisor,
     2096    /* Interrupt remapping */
     2097    kIoPageFaultType_IrteAddrInvalid,
     2098    kIoPageFaultType_IrteRsvdNotZero,
     2099    kIoPageFaultType_IrteRemapEn,
     2100    kIoPageFaultType_IrteRsvdIntType,
     2101    kIoPageFaultType_IntrReqAborted,
     2102    kIoPageFaultType_IntrWithPasid,
     2103    kIoPageFaultType_SmiFilterMismatch,
     2104    /* Memory transaction or interrupt remapping. */
     2105    kIoPageFaultType_DevId_Invalid
     2106} EVT_IO_PAGE_FAULT_TYPE_T;
     2107
     2108/**
     2109 * DEV_TAB_HARDWARE_ERROR Event Types.
     2110 * In accordance with the AMD spec.
     2111 */
     2112typedef enum EVT_DEV_TAB_HW_ERROR_TYPE_T
     2113{
     2114    kDevTabHwErrType_MasterAbort = 0,
     2115    kDevTabHwErrType_TargetAbort,
     2116    kDevTabHwErrType_PoisonedData
     2117} EVT_DEV_TAB_HW_ERROR_TYPE_T;
     2118
     2119/**
     2120 * PAGE_TAB_HARDWARE_ERROR Even Types.
     2121 * In accordance with the AMD spec.
     2122 */
     2123typedef enum EVT_PAGE_TAB_HW_ERR_TYPE_T
     2124{
     2125    kPageTabHwErrType_MasterAbort = 0,
     2126    kPageTabHwErrType_TargetAbort,
     2127    kPageTabHwErrType_PoisonedData,
     2128} EVT_PAGE_TAB_HW_ERR_TYPE_T;
     2129
     2130/**
     2131 * COMMAND_HARDWARE_ERROR Event Types.
     2132 * In accordance with the AMD spec.
     2133 */
     2134typedef enum EVT_CMD_HW_ERROR_TYPE_T
     2135{
     2136    kCmdHwErrType_MasterAbort = 0,
     2137    kCmdHwErrType_TargetAbort,
     2138    kCmdHwErrType_PoisonedData
     2139} EVT_CMD_HW_ERROR_TYPE_T;
     2140
     2141/**
     2142 * ILLEGAL_COMMAND_ERROR Event Types.
     2143 * In accordance with the AMD spec.
     2144 */
     2145typedef enum EVT_ILLEGAL_CMD_ERR_TYPE_T
     2146{
     2147    kIllegalCmdErrType_RsvdNotZero = 0,
     2148    kIllegalCmdErrType_CmdNotSupported,
     2149    kIllegalCmdErrType_IotlbNotSupported
     2150} EVT_ILLEGAL_CMD_ERR_TYPE_T;
     2151
     2152/**
     2153 * IOTLB_INV_TIMEOUT Event Types.
     2154 * In accordance with the AMD spec.
     2155 */
     2156typedef enum EVT_IOTLB_INV_TIMEOUT_TYPE_T
     2157{
     2158    InvTimeoutType_NoResponse = 0
     2159} EVT_IOTLB_INV_TIMEOUT_TYPE_T;
     2160
     2161/**
     2162 * INVALID_DEVICE_REQUEST Event Types.
     2163 * In accordance with the AMD spec.
     2164 */
     2165typedef enum EVT_INVALID_DEV_REQ_TYPE_T
     2166{
     2167    /* Access. */
     2168    kInvalidDevReqType_ReadOrNonPostedWrite = 0,
     2169    kInvalidDevReqType_PretranslatedTransaction,
     2170    kInvalidDevReqType_PortIo,
     2171    kInvalidDevReqType_SysMgt,
     2172    kInvalidDevReqType_IntrRange,
     2173    kInvalidDevReqType_RsvdIntrRange,
     2174    kInvalidDevReqType_SysMgtAddr,
     2175    /* Translation Request. */
     2176    kInvalidDevReqType_TrAccessInvalid,
     2177    kInvalidDevReqType_TrDisabled,
     2178    kInvalidDevReqType_DevIdInvalid,
     2179} EVT_INVALID_DEV_REQ_TYPE_T;
     2180
     2181/**
     2182 * INVALID_PPR_REQUEST Event Types.
     2183 * In accordance with the AMD spec.
     2184 */
     2185typedef enum EVT_INVALID_PPR_REQ_TYPE_T
     2186{
     2187    kInvalidPprReqType_PriNotSupported,
     2188    kInvalidPprReqType_GstTranslateDisabled
     2189} EVT_INVALID_PPR_REQ_TYPE_T;
     2190
     2191/**
     2192 * IOMMU operations (transaction) types.
    20052193 */
    20062194typedef enum IOMMUOP
     
    20142202    /** Interrupt request. */
    20152203    IOMMUOP_INTR_REQ,
    2016     /** Command request. */
     2204    /** Command. */
    20172205    IOMMUOP_CMD
    20182206} IOMMUOP;
    20192207AssertCompileSize(IOMMUOP, 4);
     2208
     2209/**
     2210 * IOMMU I/O TLB Entry.
     2211 * @note Update iommuAmdInitIotlbe() when changes are made.
     2212 */
     2213typedef struct
     2214{
     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;
     2225    /** The I/O access permissions (IOMMU_IO_PERM_XXX). */
     2226    uint8_t         fIoPerm;
     2227    /** Alignment padding. */
     2228    uint8_t         fRsvd0;
     2229    /** Reserved for future (eviction hints?). */
     2230    uint32_t        uPadding0;
     2231} IOTLBE_T;
     2232AssertCompileSizeAlignment(IOTLBE_T, 8);
     2233/** Pointer to an IOMMU I/O TLB entry struct. */
     2234typedef IOTLBE_T *PIOTLBE_T;
     2235/** Pointer to a const IOMMU I/O TLB entry struct. */
     2236typedef IOTLBE_T const *PCIOTLBE_T;
    20202237
    20212238/**
     
    33233540
    33243541/**
    3325  * Constructs a DEV_TAB_HARDWARE_ERROR event.
     3542 * Initializes a DEV_TAB_HARDWARE_ERROR event.
    33263543 *
    33273544 * @param   uDevId      The device ID.
    33283545 * @param   GCPhysDte   The system physical address of the failed device table
    33293546 *                      access.
    3330  * @param   enmOp       The operation being performed.
    3331  * @param   pEvent      Where to store the constructed event.
     3547 * @param   enmOp       The IOMMU operation being performed.
     3548 * @param   pEvent      Where to store the initialized event.
    33323549 *
    33333550 * @thread  Any.
    33343551 */
    3335 static void iommuAmdMakeDevTabHwErrorEvent(uint16_t uDevId, RTGCPHYS GCPhysDte, IOMMUOP enmOp, PEVT_GENERIC_T pEvent)
     3552static void iommuAmdInitDevTabHwErrorEvent(uint16_t uDevId, RTGCPHYS GCPhysDte, IOMMUOP enmOp, PEVT_GENERIC_T pEvent)
    33363553{
    33373554    memset(pEvent, 0, sizeof(*pEvent));
     
    33403557    pDevTabHwErr->n.u16DevId      = uDevId;
    33413558    pDevTabHwErr->n.u1Intr        = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
     3559    /** @todo r=ramshankar: Any other transaction type that can set read/write bit? */
    33423560    pDevTabHwErr->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
    33433561    pDevTabHwErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
     
    33553573 * @param   GCPhysDte   The system physical address of the failed device table
    33563574 *                      access.
    3357  * @param   enmOp       The operation being performed by the IOMMU.
    3358  */
    3359 static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysDte, IOMMUOP enmOp)
     3575 * @param   enmOp       The IOMMU operation being performed.
     3576 * @param   enmEvtType  The device table hardware error event type.
     3577 */
     3578static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysDte, IOMMUOP enmOp,
     3579                                            EVT_DEV_TAB_HW_ERROR_TYPE_T enmEvtType)
    33603580{
    33613581    EVT_GENERIC_T Event;
    3362     iommuAmdMakeDevTabHwErrorEvent(uDevId, GCPhysDte, enmOp, &Event);
     3582    iommuAmdInitDevTabHwErrorEvent(uDevId, GCPhysDte, enmOp, &Event);
    33633583    iommuAmdSetHwError(pDevIns, &Event);
    33643584    iommuAmdWriteEvtLogEntry(pDevIns, &Event);
    33653585    if (enmOp != IOMMUOP_CMD)
    33663586        iommuAmdSetPciTargetAbort(pDevIns);
    3367 }
    3368 
    3369 
    3370 /**
    3371  * Constructs an ILLEGAL_DEV_TAB_ENTRY event.
     3587
     3588    Log((IOMMU_LOG_PFX ": Raised DEV_TAB_HARDWARE_ERROR. uDevId=%#x GCPhysDte=%#RGp enmOp=%u enmType=%u\n", uDevId, GCPhysDte,
     3589         enmOp, enmEvtType));
     3590    NOREF(enmEvtType);
     3591}
     3592
     3593
     3594/**
     3595 * Initializes an ILLEGAL_DEV_TABLE_ENTRY event.
    33723596 *
    33733597 * @param   uDevId          The device ID.
    3374  * @param   uDva            The device virtual address.
    3375  * @param   fRsvdNotZero    Whether reserved bits in the device table entry were not
    3376  *                          zero.
    3377  * @param   enmOp           The operation being performed.
    3378  * @param   pEvent          Where to store the constructed event.
    3379  */
    3380 static void iommuAmdMakeIllegalDteEvent(uint16_t uDevId, uint64_t uDva, bool fRsvdNotZero, IOMMUOP enmOp, PEVT_GENERIC_T pEvent)
     3598 * @param   uIova           The I/O virtual address.
     3599 * @param   enmOp           The IOMMU operation being performed.
     3600 * @param   enmEvtType      The illegal DTE event type.
     3601 * @param   pEvent          Where to store the initialized event.
     3602 */
     3603static void iommuAmdInitIllegalDteEvent(uint16_t uDevId, uint64_t uIova, IOMMUOP enmOp, EVT_ILLEGAL_DTE_TYPE_T enmEvtType,
     3604                                        PEVT_GENERIC_T pEvent)
    33813605{
    33823606    memset(pEvent, 0, sizeof(*pEvent));
     
    33863610    pIllegalDteErr->n.u1Interrupt   = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
    33873611    pIllegalDteErr->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
    3388     pIllegalDteErr->n.u1RsvdNotZero = fRsvdNotZero;
     3612    pIllegalDteErr->n.u1RsvdNotZero = RT_BOOL(enmEvtType == kIllegalDteType_RsvdNotZero);
    33893613    pIllegalDteErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
    33903614    pIllegalDteErr->n.u4EvtCode     = IOMMU_EVT_ILLEGAL_DEV_TAB_ENTRY;
    3391     pIllegalDteErr->n.u64Addr       = uDva & ~UINT64_C(0x3);
     3615    pIllegalDteErr->n.u64Addr       = uIova & ~UINT64_C(0x3);
    33923616    /** @todo r=ramshankar: Not sure why the last 2 bits are marked as reserved by the
    33933617     *        IOMMU spec here but not for this field for I/O page fault event. */
    3394     Assert(!(uDva & UINT64_C(0x3)));
    3395 }
    3396 
    3397 
    3398 /**
    3399  * Raises an ILLEGAL_DEV_TAB_ENTRY event.
     3618    Assert(!(uIova & UINT64_C(0x3)));
     3619}
     3620
     3621
     3622/**
     3623 * Raises an ILLEGAL_DEV_TABLE_ENTRY event.
    34003624 *
    34013625 * @param   pDevIns         The IOMMU instance data.
    34023626 * @param   uDevId          The device ID.
    3403  * @param   uDva            The device virtual address.
    3404  * @param   fRsvdNotZero    Whether reserved bits in the device table entry were not
    3405  *                          zero.
    3406  * @param   enmOp           The operation being performed.
    3407  */
    3408 static void iommuAmdRaiseIllegalDteEvent(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, bool fRsvdNotZero, IOMMUOP enmOp)
     3627 * @param   uIova           The I/O virtual address.
     3628 * @param   enmOp           The IOMMU operation being performed.
     3629 * @param   enmEvtType      The illegal DTE event type.
     3630 */
     3631static void iommuAmdRaiseIllegalDteEvent(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, IOMMUOP enmOp,
     3632                                         EVT_ILLEGAL_DTE_TYPE_T enmEvtType)
    34093633{
    34103634    EVT_GENERIC_T Event;
    3411     iommuAmdMakeIllegalDteEvent(uDevId, uDva, fRsvdNotZero, enmOp, &Event);
     3635    iommuAmdInitIllegalDteEvent(uDevId, uIova, enmOp, enmEvtType, &Event);
    34123636    iommuAmdWriteEvtLogEntry(pDevIns, &Event);
    34133637    if (enmOp != IOMMUOP_CMD)
    34143638        iommuAmdSetPciTargetAbort(pDevIns);
    3415 }
    3416 
    3417 
    3418 /**
    3419  * Returns whether the device virtual address is allowed to be excluded from
    3420  * translation and permission checks.
     3639
     3640    Log((IOMMU_LOG_PFX ": Raised ILLEGAL_DTE_EVENT. uDevId=%#x uIova=%#RX64 enmOp=%u enmType=%u\n", uDevId, uIova, enmOp,
     3641         enmEvtType));
     3642    NOREF(enmEvtType);
     3643}
     3644
     3645
     3646/**
     3647 * Initializes an IO_PAGE_FAULT event.
     3648 *
     3649 * @param   uDevId          The device ID.
     3650 * @param   uDomainId       The domain ID.
     3651 * @param   uIova           The I/O virtual address being accessed.
     3652 * @param   fPresent        Transaction to a page marked as present (including
     3653 *                          DTE.V=1) or interrupt marked as remapped
     3654 *                          (IRTE.RemapEn=1).
     3655 * @param   enmOp           The IOMMU operation being performed.
     3656 * @param   enmEvtType      The I/O page fault event type.
     3657 * @param   pEvent          Where to store the initialized event.
     3658 */
     3659static void iommuAmdInitIoPageFaultEvent(uint16_t uDevId, uint16_t uDomainId, uint64_t uIova, bool fPresent,
     3660                                         IOMMUOP enmOp, EVT_IO_PAGE_FAULT_TYPE_T enmEvtType, PEVT_GENERIC_T pEvent)
     3661{
     3662    memset(pEvent, 0, sizeof(*pEvent));
     3663    AssertCompile(sizeof(EVT_IO_PAGE_FAULT_T) == sizeof(EVT_GENERIC_T));
     3664    PEVT_IO_PAGE_FAULT_T pIoPageFault = (PEVT_IO_PAGE_FAULT_T)pEvent;
     3665    pIoPageFault->n.u16DevId            = uDevId;
     3666    //pIoPageFault->n.u4PasidHi         = 0;
     3667    pIoPageFault->n.u16DomainOrPasidLo  = uDomainId;
     3668    //pIoPageFault->n.u1GuestOrNested   = 0;
     3669    //pIoPageFault->n.u1NoExecute       = 0;
     3670    //pIoPageFault->n.u1User            = 0;
     3671    pIoPageFault->n.u1Interrupt         = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
     3672    pIoPageFault->n.u1Present           = fPresent;
     3673    pIoPageFault->n.u1ReadWrite         = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
     3674    //pIoPageFault->n.u1PermIndicator   = 0;
     3675    pIoPageFault->n.u1RsvdNotZero       = RT_BOOL(   enmEvtType == kIoPageFaultType_PteRsvdNotZero
     3676                                                  || enmEvtType == kIoPageFaultType_IrteRemapEn);
     3677    pIoPageFault->n.u1Translation       = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
     3678    pIoPageFault->n.u4EvtCode           = IOMMU_EVT_IO_PAGE_FAULT;
     3679    pIoPageFault->n.u64Addr             = uIova;
     3680}
     3681
     3682
     3683/**
     3684 * Raises an IO_PAGE_FAULT event.
     3685 *
     3686 * @param   pDevIns             The IOMMU instance data.
     3687 * @param   uDevId              The device ID.
     3688 * @param   uDomainId           The domain ID.
     3689 * @param   uIova               The I/O virtual address being accessed.
     3690 * @param   fPresentOrValid     Transaction to a page marked as present (including
     3691 *                              DTE.V=1) or interrupt marked as remapped
     3692 *                              (IRTE.RemapEn=1).
     3693 * @param   enmOp               The IOMMU operation being performed.
     3694 * @param   enmEvtType          The I/O page fault event type.
     3695 */
     3696static void iommuAmdRaiseIoPageFaultEvent(PPDMDEVINS pDevIns, uint16_t uDevId, uint16_t uDomainId, uint64_t uIova,
     3697                                          bool fPresentOrValid, IOMMUOP enmOp, EVT_IO_PAGE_FAULT_TYPE_T enmEvtType)
     3698{
     3699    EVT_GENERIC_T Event;
     3700    iommuAmdInitIoPageFaultEvent(uDevId, uDomainId, uIova, fPresentOrValid, enmOp, enmEvtType, &Event);
     3701
     3702    switch (enmEvtType)
     3703    {
     3704        case kIoPageFaultType_ReadProtect:
     3705        case kIoPageFaultType_WriteProtect:
     3706        case kIoPageFaultType_ExecuteProtect:
     3707        {
     3708            /* Cannot be triggered by a command. */
     3709            Assert(enmOp != IOMMUOP_CMD);
     3710            RT_FALL_THRU();
     3711        }
     3712        case kIoPageFaultType_DteRsvdPagingMode:
     3713        case kIoPageFaultType_PteInvalidPageSize:
     3714        case kIoPageFaultType_PteInvalidLvlEncoding:
     3715        case kIoPageFaultType_InvalidSkippedPageLvl:
     3716        case kIoPageFaultType_PteRsvdNotZero:
     3717        case kIoPageFaultType_PteValidNotSet:
     3718        case kIoPageFaultType_DteTranslationDisabled:
     3719        case kIoPageFaultType_PasidInvalidRange:
     3720        {
     3721            /*
     3722             * For a translation request, the IOMMU doesn't signal an I/O page fault nor does it
     3723             * create an event log entry. See AMD spec. 2.1.3.2 "I/O Page Faults".
     3724             */
     3725            if (enmOp != IOMMUOP_TRANSLATE_REQ)
     3726            {
     3727                iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3728                if (enmOp != IOMMUOP_CMD)
     3729                    iommuAmdSetPciTargetAbort(pDevIns);
     3730            }
     3731            break;
     3732        }
     3733
     3734        case kIoPageFaultType_UserSupervisor:
     3735        {
     3736            /* Access is blocked and only creates an event log entry. */
     3737            iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3738            break;
     3739        }
     3740
     3741        case kIoPageFaultType_IrteAddrInvalid:
     3742        case kIoPageFaultType_IrteRsvdNotZero:
     3743        case kIoPageFaultType_IrteRemapEn:
     3744        case kIoPageFaultType_IrteRsvdIntType:
     3745        case kIoPageFaultType_IntrReqAborted:
     3746        case kIoPageFaultType_IntrWithPasid:
     3747        {
     3748            /* Only trigerred by interrupt requests. */
     3749            Assert(enmOp == IOMMUOP_INTR_REQ);
     3750            iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3751            iommuAmdSetPciTargetAbort(pDevIns);
     3752            break;
     3753        }
     3754
     3755        case kIoPageFaultType_SmiFilterMismatch:
     3756        {
     3757            /* Not supported and probably will never be, assert. */
     3758            AssertMsgFailed(("kIoPageFaultType_SmiFilterMismatch - Upstream SMI requests not supported/implemented."));
     3759            break;
     3760        }
     3761
     3762        case kIoPageFaultType_DevId_Invalid:
     3763        {
     3764            /* Cannot be triggered by a command. */
     3765            Assert(enmOp != IOMMUOP_CMD);
     3766            Assert(enmOp != IOMMUOP_TRANSLATE_REQ); /** @todo IOMMU: We don't support translation requests yet. */
     3767            iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3768            if (   enmOp == IOMMUOP_MEM_READ
     3769                || enmOp == IOMMUOP_MEM_WRITE)
     3770                iommuAmdSetPciTargetAbort(pDevIns);
     3771            break;
     3772        }
     3773    }
     3774
     3775
     3776}
     3777
     3778
     3779/**
     3780 * Initializes an IOTLB entry.
     3781 *
     3782 * @param   uDevId      The device ID.
     3783 * @param   uDomainId   The domain ID.
     3784 * @param   fIoPerm     The I/O access permissions (IOMMU_IO_PERM_XXX).
     3785 * @param   uIova       The I/O virtual address.
     3786 * @param   GCPhysSpa   The translated system physical address.
     3787 * @param   pIotlbe     Where to store the initialized IOTLB entry.
     3788 */
     3789static void iommuAmdInitIotlbe(uint16_t uDevId, uint16_t uDomainId, uint8_t fIoPerm, uint64_t uIova, RTGCPHYS GCPhysSpa,
     3790                               PIOTLBE_T pIotlbe)
     3791{
     3792    pIotlbe->uDevId    = uDevId;
     3793    pIotlbe->uDomainId = uDomainId;
     3794    pIotlbe->fIoPerm   = fIoPerm;
     3795    pIotlbe->fRsvd0    = 0;
     3796    pIotlbe->uPadding0 = 0;
     3797    pIotlbe->uIova     = uIova;
     3798    pIotlbe->GCPhysSpa = GCPhysSpa;
     3799}
     3800
     3801
     3802/**
     3803 * Returns whether the I/O virtual address is to be excluded from translation and
     3804 * permission checks.
    34213805 *
    34223806 * @returns @c true if the DVA is excluded, @c false otherwise.
    34233807 * @param   pThis   The IOMMU device state.
    34243808 * @param   pDte    The device table entry.
    3425  * @param   uDva    The device virtual address.
    3426  */
    3427 static bool iommuAmdIsDvaSubjectToExclRange(PCIOMMU pThis, PCDTE_T pDte, uint64_t uDva)
    3428 {
    3429     /* Check if the exclusion range is enabled. */
    3430     if (pThis->ExclRangeBaseAddr.n.u1ExclEnable)
    3431     {
    3432         /* Check if the device virtual address falls within the exclusion range. */
    3433         uint64_t const uDvaExclFirst = pThis->ExclRangeBaseAddr.n.u40ExclRangeBase << X86_PAGE_4K_SHIFT;
    3434         uint64_t const uDvaExclLast  = pThis->ExclRangeLimit.n.u52ExclLimit;
    3435         if (uDvaExclLast - uDva >= uDvaExclFirst)
    3436         {
    3437             /* Check if device access to addresses in the exclusion range can be forwarded untranslated. */
    3438             if (    pThis->ExclRangeBaseAddr.n.u1AllowAll
    3439                 ||  pDte->n.u1AllowExclusion)
    3440                 return true;
    3441         }
     3809 * @param   uIova   The I/O virtual address.
     3810 *
     3811 * @remarks Ensure the exclusion range is enabled prior to calling this function.
     3812 */
     3813static bool iommuAmdIsDvaInExclRange(PCIOMMU pThis, PCDTE_T pDte, uint64_t uIova)
     3814{
     3815    /* Ensure the exclusion range is enabled. */
     3816    Assert(pThis->ExclRangeBaseAddr.n.u1ExclEnable);
     3817
     3818    /* Check if the IOVA falls within the exclusion range. */
     3819    uint64_t const uIovaExclFirst = pThis->ExclRangeBaseAddr.n.u40ExclRangeBase << X86_PAGE_4K_SHIFT;
     3820    uint64_t const uIovaExclLast  = pThis->ExclRangeLimit.n.u52ExclLimit;
     3821    if (uIovaExclLast - uIova >= uIovaExclFirst)
     3822    {
     3823        /* Check if device access to addresses in the exclusion range can be forwarded untranslated. */
     3824        if (    pThis->ExclRangeBaseAddr.n.u1AllowAll
     3825            ||  pDte->n.u1AllowExclusion)
     3826            return true;
    34423827    }
    34433828    return false;
     
    34513836 * @param   pDevIns     The IOMMU device instance.
    34523837 * @param   uDevId      The device ID.
    3453  * @param   enmOp       The operation being performed by the IOMMU.
     3838 * @param   enmOp       The IOMMU operation being performed.
    34543839 * @param   pDte        Where to store the device table entry.
    34553840 *
     
    34753860    if (RT_FAILURE(rc))
    34763861    {
    3477         Log((IOMMU_LOG_PFX ": Failed to read device table entry at %#RGp. rc=%Rrc\n", GCPhysDte, rc));
    3478         iommuAmdRaiseDevTabHwErrorEvent(pDevIns, uDevId, GCPhysDte, enmOp);
     3862        Log((IOMMU_LOG_PFX ": Failed to read device table entry at %#RGp. rc=%Rrc -> DevTabHwError\n", GCPhysDte, rc));
     3863        iommuAmdRaiseDevTabHwErrorEvent(pDevIns, uDevId, GCPhysDte, enmOp, kDevTabHwErrType_TargetAbort);
    34793864    }
    34803865
     
    34833868
    34843869
    3485 #if 0
    3486 /**
    3487  * Walks the I/O page tables to translate the given device virtual address and
    3488  * associated data.
     3870/**
     3871 * Walks the I/O page table(s) to translate the I/O virtual address to a system
     3872 * physical address.
    34893873 *
    34903874 * @returns VBox status code.
    34913875 * @param   pDevIns     The IOMMU device instance.
    3492  * @param   uDva        The device virtual address.
    3493  * @param   cbRead      The size of the access.
    3494  * @param   fPerms      The access permissions (IOMMU_PERM_XXX).
    3495  * @param   pGCPhys     Where to store the translated address.
    3496  */
    3497 static int iommuAmdWalkIoPageTable(PPDMDEVINS pDevIns, uint64_t uDva, size_t cbRead, uint32_t fAccess, PRTGCPHYS pGCPhys)
    3498 {
    3499 
    3500 }
    3501 #endif
    3502 
    3503 
    3504 /**
    3505  * Memory read translation request from a device.
     3876 * @param   uIova       The I/O virtual address to translate.
     3877 * @param   uDevId      The device ID.
     3878 * @param   cbAccess    The size of the access.
     3879 * @param   fAccess     The access permissions (IOMMU_IO_PERM_XXX). This is the
     3880 *                      permissions for the access being made.
     3881 * @param   enmOp       The IOMMU operation being performed.
     3882 * @param   pGCPhysSpa  Where to store the system physical address.
     3883 * @param   pfIoPerm    Where to store the I/O access permissions. This is the
     3884 *                      permission of what access is allowed.
     3885 */
     3886static int iommuAmdWalkIoPageTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess,
     3887                                    PCDTE_T pDte, IOMMUOP enmOp, PRTGCPHYS pGCPhysSpa, uint8_t *pfIoPerm)
     3888{
     3889    NOREF(pDevIns);
     3890    Assert(pDte->n.u1Valid);
     3891    Assert(pDte->n.u1TranslationValid);
     3892    Assert(cbAccess > 0);
     3893
     3894    if (pDte->n.u1TranslationValid)
     3895    { /* likely */ }
     3896    else
     3897    {
     3898        iommuAmdRaiseIoPageFaultEvent(pDevIns, uDevId, pDte->n.u16DomainId, uIova, true /* fPresentOrValid */,
     3899                                      enmOp, kIoPageFaultType_DteTranslationDisabled);
     3900        *pGCPhysSpa = 0;
     3901        *pfIoPerm   = 0;
     3902        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
     3903    }
     3904
     3905    /* If the page table depth is 0, translation is disabled and access is controlled by IR and IW bits. */
     3906    if (pDte->n.u3Mode == 0)
     3907    {
     3908        uint8_t const fDtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK;
     3909        if ((fAccess & fDtePerm) != fAccess)
     3910        {
     3911            Log((IOMMU_LOG_PFX ": Access denied for IOVA (%#RX64). fAccess=%#x fDtePerm=%#x\n", uIova, fAccess, fDtePerm));
     3912            return VERR_IOMMU_ADDR_ACCESS_DENIED;
     3913        }
     3914        *pGCPhysSpa = uIova;
     3915        *pfIoPerm   = fDtePerm;
     3916        return VINF_SUCCESS;
     3917    }
     3918
     3919    /* If the paging mode exceeds the host-address translation levels, translation fails. */
     3920    if (pDte->n.u3Mode > IOMMU_MAX_HOST_PT_LEVEL)
     3921    {
     3922        /** @todo r=ramshankar: I cannot make out from the AMD IOMMU spec. if I should be
     3923         *        raising an ILLEGAL_DEV_TABLE_ENTRY event or an IO_PAGE_FAULT event here.
     3924         *        I'm just going with this one... */
     3925        *pGCPhysSpa = 0;
     3926        *pfIoPerm   = IOMMU_IO_PERM_NONE;
     3927        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
     3928    }
     3929
     3930    /** @todo IOMMU: page walk. */
     3931
     3932    return VERR_NOT_IMPLEMENTED;
     3933}
     3934
     3935/**
     3936 * Looks up an I/O virtual address from the device table(s).
     3937 *
     3938 * @returns VBox status code.
     3939 * @param   pDevIns     The IOMMU instance data.
     3940 * @param   uDevId      The device ID.
     3941 * @param   uIova       The I/O virtual address to lookup.
     3942 * @param   cbAccess    The size of the access.
     3943 * @param   enmOp       The IOMMU operation being performed.
     3944 * @param   pIotlbe     The IOTLBE to update.
     3945 *
     3946 * @remarks Only the translated address and permission bits are updated in @a
     3947 *          pIotlbe when this function returns VINF_SUCCESS. Caller is expected to
     3948 *          know and fill in the rest already.
     3949 */
     3950static int iommuAmdLookupDeviceTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, IOMMUOP enmOp,
     3951                                      PIOTLBE_T pIotlbe)
     3952{
     3953    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     3954
     3955    /* Read the device table entry. */
     3956    DTE_T Dte;
     3957    int rc = iommuAmdReadDte(pDevIns, uDevId, enmOp, &Dte);
     3958    if (RT_SUCCESS(rc))
     3959    {
     3960        RTGCPHYS GCPhysSpa = 0;
     3961        uint8_t  fIoPerm   = IOMMU_IO_PERM_NONE;
     3962
     3963        if (Dte.n.u1Valid)
     3964        {
     3965            /* Validate bits 127:0 of the device table entry when DTE.V is 1. */
     3966            uint64_t const fRsvdQword0 = Dte.au64[0] & ~(IOMMU_DTE_QWORD_0_VALID_MASK & ~IOMMU_DTE_QWORD_0_FEAT_MASK);
     3967            uint64_t const fRsvdQword1 = Dte.au64[1] & ~(IOMMU_DTE_QWORD_1_VALID_MASK & ~IOMMU_DTE_QWORD_1_FEAT_MASK);
     3968            if (   fRsvdQword0
     3969                || fRsvdQword1)
     3970            {
     3971                Log((IOMMU_LOG_PFX ": Invalid reserved bits in DTE (u64[0]=%#RX64 u64[1]=%#RX64) -> Illegal DTE\n", fRsvdQword0,
     3972                     fRsvdQword1));
     3973                iommuAmdRaiseIllegalDteEvent(pDevIns, uDevId, uIova, enmOp, kIllegalDteType_RsvdNotZero);
     3974                return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
     3975            }
     3976
     3977            /* Ensure the IOVA is not in the exclusion range. */
     3978            if (   !pThis->ExclRangeBaseAddr.n.u1ExclEnable
     3979                || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova))
     3980            {
     3981                rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uIova, cbAccess, IOMMU_IO_PERM_READ, &Dte, enmOp, &GCPhysSpa,
     3982                                              &fIoPerm);
     3983                if (RT_FAILURE(rc))
     3984                    Log((IOMMU_LOG_PFX ": I/O page table walk failed. rc=%Rrc\n"));
     3985            }
     3986            else
     3987            {
     3988                /* If the IOVA is subject to address exclusion, addresses are forwarded without translation. */
     3989                GCPhysSpa = uIova;
     3990                fIoPerm   = IOMMU_IO_PERM_READ_WRITE;
     3991            }
     3992        }
     3993        else
     3994        {
     3995            /* Addresses are forwarded without translation when DTE.V is 0. */
     3996            GCPhysSpa = uIova;
     3997            fIoPerm   = IOMMU_IO_PERM_READ_WRITE;
     3998        }
     3999
     4000        pIotlbe->GCPhysSpa = GCPhysSpa;
     4001        pIotlbe->fIoPerm   = fIoPerm;
     4002    }
     4003    else
     4004    {
     4005        Log((IOMMU_LOG_PFX ": Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc));
     4006        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
     4007    }
     4008
     4009    return rc;
     4010}
     4011
     4012
     4013/**
     4014 * Memory read request from a device.
    35064015 *
    35074016 * @returns VBox status code.
    35084017 * @param   pDevIns     The IOMMU device instance.
    35094018 * @param   uDevId      The device ID (bus, device, function).
    3510  * @param   uDva        The device virtual address being read.
     4019 * @param   uIova       The I/O virtual address being read.
    35114020 * @param   cbRead      The number of bytes being read.
    3512  * @param   pGCPhysOut  Where to store the translated physical address.
     4021 * @param   pGCPhysSpa  Where to store the translated system physical address.
    35134022 *
    35144023 * @thread  Any.
    35154024 */
    3516 static int iommuAmdDeviceMemRead(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbRead, PRTGCPHYS pGCPhysOut)
    3517 {
    3518     RT_NOREF(pDevIns, uDevId, uDva, cbRead, pGCPhysOut);
    3519 
     4025static int iommuAmdDeviceMemRead(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbRead, PRTGCPHYS pGCPhysSpa)
     4026{
    35204027    Assert(pDevIns);
    3521     Assert(pGCPhysOut);
     4028    Assert(pGCPhysSpa);
     4029    Assert(cbRead > 0);
    35224030
    35234031    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
    3524     IOMMUOP const enmOp = IOMMUOP_TRANSLATE_REQ;
    35254032
    35264033    /* Addresses are forwarded without translation when the IOMMU is disabled. */
     
    35284035    if (Ctrl.n.u1IommuEn)
    35294036    {
    3530         /** @todo IOTLB cache lookup. */
    3531 
    3532         /* Read the device table entry. */
    3533         DTE_T Dte;
    3534         int rc = iommuAmdReadDte(pDevIns, uDevId, enmOp, &Dte);
    3535         if (RT_SUCCESS(rc))
    3536         {
    3537             /* Addresses are forwarded without translation when DTE.V is 0. */
    3538             if (Dte.n.u1Valid)
    3539             {
    3540                 /* Validate bits 127:0 of the device table entry when DTE.V is 1. */
    3541                 uint64_t const fRsvdQword0 = Dte.au64[0] & ~IOMMU_DTE_QWORD_0_VALID_MASK;
    3542                 uint64_t const fRsvdQword1 = Dte.au64[1] & ~IOMMU_DTE_QWORD_1_VALID_MASK;
    3543                 if (   fRsvdQword0
    3544                     || fRsvdQword1)
    3545                 {
    3546                     Log((IOMMU_LOG_PFX ":DTE invalid reserved bits ([0]=%#RX64 [1]=%#RX64)\n", fRsvdQword0, fRsvdQword1));
    3547                     iommuAmdRaiseIllegalDteEvent(pDevIns, uDevId, uDva, true /* fRsvdNotZero */, enmOp);
    3548                     return VERR_GENERAL_FAILURE; /** @todo IOMMU: Change this. */
    3549                 }
    3550 
    3551                 /* Check if the device virtual address is subject to address exclusion. */
    3552                 if (!iommuAmdIsDvaSubjectToExclRange(pThis, &Dte, uDva))
    3553                 {
    3554                     /** @todo IOMMU: Traverse the I/O page table and translate. */
    3555 
    3556                     return VERR_NOT_IMPLEMENTED;
    3557                 }
    3558             }
    3559         }
    3560         else
    3561         {
    3562             Log((IOMMU_LOG_PFX ":Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc));
    3563             return VERR_GENERAL_FAILURE; /** @todo IOMMU: Change this. */
    3564         }
    3565     }
    3566 
    3567     *pGCPhysOut = uDva;
     4037        IOTLBE_T Iotlbe;
     4038        iommuAmdInitIotlbe(uDevId, 0 /* uDomainId */, IOMMU_IO_PERM_NONE, uIova, 0 /* GCPhySpa */, &Iotlbe);
     4039
     4040        /** @todo IOMMU: IOTLB cache lookup. */
     4041
     4042        /* Lookup the IOVA from the device tables. */
     4043        int rc = iommuAmdLookupDeviceTables(pDevIns, uDevId, uIova, cbRead, IOMMUOP_MEM_READ, &Iotlbe);
     4044
     4045        /** @todo IOMMU: Cache translation. */
     4046
     4047        *pGCPhysSpa = Iotlbe.GCPhysSpa;
     4048        return rc;
     4049    }
     4050
     4051    *pGCPhysSpa = uIova;
    35684052    return VINF_SUCCESS;
    35694053}
     
    35714055
    35724056/**
    3573  * Memory write translation request from a device.
     4057 * Memory write request from a device.
    35744058 *
    35754059 * @returns VBox status code.
    35764060 * @param   pDevIns     The IOMMU device instance.
    35774061 * @param   uDevId      The device ID (bus, device, function).
    3578  * @param   uDva        The device virtual address being written.
     4062 * @param   uIova       The I/O virtual address being written.
    35794063 * @param   cbWrite     The number of bytes being written.
    3580  * @param   pGCPhysOut  Where to store the translated physical address.
     4064 * @param   pGCPhysSpa  Where to store the translated physical address.
    35814065 *
    35824066 * @thread  Any.
    35834067 */
    3584 static int iommuAmdDeviceMemWrite(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbWrite, PRTGCPHYS pGCPhysOut)
    3585 {
    3586     RT_NOREF(pDevIns, uDevId, uDva, cbWrite, pGCPhysOut);
     4068static int iommuAmdDeviceMemWrite(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbWrite, PRTGCPHYS pGCPhysSpa)
     4069{
     4070    RT_NOREF(pDevIns, uDevId, uIova, cbWrite, pGCPhysSpa);
    35874071    return VERR_NOT_IMPLEMENTED;
    35884072}
     
    37314215    PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
    37324216
    3733     LogFlow((IOMMU_LOG_PFX ": %s: pThis=%p pszArgs=%s\n", __PRETTY_FUNCTION__, pThis, pszArgs));
     4217    LogFlow((IOMMU_LOG_PFX ": iommuAmdR3DbgInfo: pThis=%p pszArgs=%s\n", pThis, pszArgs));
    37344218    bool const fVerbose = !strncmp(pszArgs, RT_STR_TUPLE("verbose")) ? true : false;
    37354219
  • trunk/src/VBox/VMM/include/PDMInternal.h

    r83987 r84170  
    631631    /** @copydoc PDMIOMMUREGR3::pfnMemRead */
    632632    DECLR3CALLBACKMEMBER(int,   pfnMemRead,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbRead,
    633                                             PRTGCPHYS pGCPhysOut));
     633                                            PRTGCPHYS pGCPhysSpa));
    634634    /** @copydoc PDMIOMMUREGR3::pfnMemWrite */
    635635    DECLR3CALLBACKMEMBER(int,   pfnMemWrite,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbWrite,
    636                                              PRTGCPHYS pGCPhysOut));
     636                                             PRTGCPHYS pGCPhysSpa));
    637637} PDMIOMMU;
    638638
     
    651651    /** @copydoc PDMIOMMUREGR0::pfnMemRead */
    652652    DECLR0CALLBACKMEMBER(int,   pfnMemRead,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbRead,
    653                                             PRTGCPHYS pGCPhysOut));
     653                                            PRTGCPHYS pGCPhysSpa));
    654654    /** @copydoc PDMIOMMUREGR3::pfnMemWrite */
    655655    DECLR0CALLBACKMEMBER(int,   pfnMemWrite,(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, size_t cbWrite,
    656                                              PRTGCPHYS pGCPhysOut));
     656                                             PRTGCPHYS pGCPhysSpa));
    657657} PDMIOMMUR0;
    658658/** Pointer to a ring-0 IOMMU data. */
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