VirtualBox

Ignore:
Timestamp:
May 8, 2020 8:23:30 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

    r84183 r84199  
    606606
    607607/** Mask of valid  bits for EPHSUP (Enhanced Peripheral Page Request Handling
    608  *  Support) features (bits 52:53). */
     608 *  Support) feature (bits 52:53). */
    609609#define IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK      UINT64_C(0x0030000000000000)
    610610
    611 /** Mask of valid bits for GTSup (Guest Translation Support) features (bits
    612  *  55:60, bits 80:95). */
     611/** Mask of valid bits for GTSup (Guest Translation Support) feature (bits 55:60,
     612 *  bits 80:95). */
    613613#define IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK       UINT64_C(0x1f80000000000000)
    614614#define IOMMU_DTE_QWORD_1_FEAT_GTSUP_MASK       UINT64_C(0x00000000ffff0000)
    615615
    616 /* Mask of valid bits for GIoSup (Guest I/O Protection Support) features (bit 54). */
     616/* Mask of valid bits for GIoSup (Guest I/O Protection Support) feature (bit 54). */
    617617#define IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK      UINT64_C(0x0040000000000000)
    618618
    619 /* Mask of all valid DTE feature bits. */
     619/* Mask of valid DTE feature bits. */
    620620#define IOMMU_DTE_QWORD_0_FEAT_MASK             (  IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK \
    621621                                                 | IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK  \
     
    623623#define IOMMU_DTE_QWORD_1_FEAT_MASK             (IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK)
    624624
    625 /* Mask of all valid DTE bits. */
     625/* Mask of all valid DTE bits (including all feature bits). */
    626626#define IOMMU_DTE_QWORD_0_VALID_MASK            UINT64_C(0x7fffffffffffff83)
    627627#define IOMMU_DTE_QWORD_1_VALID_MASK            UINT64_C(0xfffffbffffffffff)
     
    630630
    631631/**
    632  * I/O Page Table Entry.
     632 * I/O Page Translation Entry.
    633633 * In accordance with the AMD spec.
    634634 */
     
    652652    } n;
    653653    /** The 64-bit unsigned integer view. */
    654     uint64_t        u;
     654    uint64_t        u64;
    655655} IOPTE_T;
    656656AssertCompileSize(IOPTE_T, 8);
     
    676676    } n;
    677677    /** The 64-bit unsigned integer view. */
    678     uint64_t        u;
     678    uint64_t        u64;
    679679} IOPDE_T;
    680680AssertCompileSize(IOPDE_T, 8);
    681681
    682682/**
    683  * I/O Page Table Generic Entity.
     683 * I/O Page Table Entry/Entity.
    684684 * In accordance with the AMD spec.
    685685 *
    686  * This a common subset of a page table entry.
    687  * Can be either an IOPTE_T or and IOPDE_T.
    688  */
    689 typedef union
    690 {
    691     struct
    692     {
    693         RT_GCC_EXTENSION uint64_t    u1Present : 1;             /**< Bit  0      - PR: Present. */
    694         RT_GCC_EXTENSION uint64_t    u4Ign0 : 4;                /**< Bits 4:1    - Ignored. */
    695         RT_GCC_EXTENSION uint64_t    u1Accessed : 1;            /**< Bit  5      - A: Accessed. */
    696         RT_GCC_EXTENSION uint64_t    u3Ign0 : 3;                /**< Bits 8:6    - Ignored. */
    697         RT_GCC_EXTENSION uint64_t    u3NextLevel : 3;           /**< Bits 11:9   - Next Level: Next page translation level. */
    698         RT_GCC_EXTENSION uint64_t    u40PageAddr : 40;          /**< Bits 51:12  - Page address. */
    699         RT_GCC_EXTENSION uint64_t    u9Rsvd0 : 9;               /**< Bits 60:52  - Reserved. */
    700         RT_GCC_EXTENSION uint64_t    u1IoRead : 1;              /**< Bit 61      - IR: I/O Read permission. */
    701         RT_GCC_EXTENSION uint64_t    u1IoWrite : 1;             /**< Bit 62      - IW: I/O Wead permission. */
    702         RT_GCC_EXTENSION uint64_t    u1Ign0 : 1;                /**< Bit 63      - Ignored. */
    703     } n;
     686 * This a common subset of an DTE.au64[0], PTE and PDE.
     687 * Named as an "entity" to avoid confusing it with PTE.
     688 */
     689typedef union
     690{
     691    struct
     692    {
     693        RT_GCC_EXTENSION uint64_t    u1Present : 1;         /**< Bit  0      - PR: Present. */
     694        RT_GCC_EXTENSION uint64_t    u8Ign0 : 8;            /**< Bits 8:1    - Ignored. */
     695        RT_GCC_EXTENSION uint64_t    u3NextLevel : 3;       /**< Bits 11:9   - Mode / Next Level: Next page translation level. */
     696        RT_GCC_EXTENSION uint64_t    u40Addr : 40;          /**< Bits 51:12  - Page address. */
     697        RT_GCC_EXTENSION uint64_t    u9Ign0 : 9;            /**< Bits 60:52  - Ignored. */
     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    /** The 64-bit unsigned integer view. */
     703    uint64_t        u64;
    704704} IOPTENTITY_T;
    705 AssertCompileSize(IOPDE_T, 8);
     705AssertCompileSize(IOPTENTITY_T, 8);
     706AssertCompile(sizeof(IOPTENTITY_T) == sizeof(IOPTE_T));
     707AssertCompile(sizeof(IOPTENTITY_T) == sizeof(IOPDE_T));
    706708/** Pointer to an IOPT_ENTITY_T struct. */
    707709typedef IOPTENTITY_T *PIOPTENTITY_T;
     
    710712
    711713/**
    712  * Interrupt Remapping Table Entry.
     714 * Interrupt Remapping Table Entry (IRTE).
    713715 * In accordance with the AMD spec.
    714716 */
     
    728730    } n;
    729731    /** The 32-bit unsigned integer view. */
    730     uint32_t        u;
     732    uint32_t        u32;
    731733} IRTE_T;
    732734AssertCompileSize(IRTE_T, 4);
     735/** Pointer to an IRTE_T struct. */
     736typedef IRTE_T *PIRTE_T;
     737/** Pointer to a const IRTE_T struct. */
     738typedef IRTE_T const *PCIRTE_T;
    733739
    734740/**
     
    771777    } n;
    772778    /** The 64-bit unsigned integer view. */
    773     uint32_t    au64[2];
     779    uint64_t    au64[2];
    774780} CMD_COMPLETION_WAIT_T;
    775781AssertCompileSize(CMD_COMPLETION_WAIT_T, 16);
     
    977983/** Pointer to an illegal device table entry event. */
    978984typedef EVT_ILLEGAL_DTE_T *PEVT_ILLEGAL_DTE_T;
     985/** Pointer to a const illegal device table entry event. */
     986typedef EVT_ILLEGAL_DTE_T const *PCEVT_ILLEGAL_DTE_T;
    979987
    980988/**
     
    10081016/** Pointer to an I/O page fault event. */
    10091017typedef EVT_IO_PAGE_FAULT_T *PEVT_IO_PAGE_FAULT_T;
     1018/** Pointer to a const I/O page fault event. */
     1019typedef EVT_IO_PAGE_FAULT_T const *PCEVT_IO_PAGE_FAULT_T;
     1020
    10101021
    10111022/**
     
    10361047/** Pointer to a device table hardware error event. */
    10371048typedef EVT_DEV_TAB_HW_ERROR_T *PEVT_DEV_TAB_HW_ERROR_T;
     1049/** Pointer to a const device table hardware error event. */
     1050typedef EVT_DEV_TAB_HW_ERROR_T const *PCEVT_DEV_TAB_HW_ERROR_T;
    10381051
    10391052/**
     
    22232236    /** The number of offset bits in the system physical address. */
    22242237    uint8_t         cShift;
    2225     /** The translated system physical address of the page. */
     2238    /** The translated system physical address (SPA) of the page. */
    22262239    RTGCPHYS        GCPhysSpa;
    22272240} IOTLBE_T;
     
    23742387AssertCompileMemberAlignment(IOMMU, hMmio, 8);
    23752388AssertCompileMemberAlignment(IOMMU, IommuBar, 8);
    2376 
    23772389
    23782390/**
     
    31293141 * @param   cb          The size of the write access.
    31303142 * @param   uValue      The value being written.
     3143 *
     3144 * @thread  EMT.
    31313145 */
    31323146static VBOXSTRICTRC iommuAmdWriteRegister(PPDMDEVINS pDevIns, uint32_t off, uint8_t cb, uint64_t uValue)
     
    32703284 * @param   off         The MMIO offset of the register in bytes.
    32713285 * @param   puResult    Where to store the value being read.
     3286 *
     3287 * @thread  EMT.
    32723288 */
    32733289static VBOXSTRICTRC iommuAmdReadRegister(PPDMDEVINS pDevIns, uint32_t off, uint64_t *puResult)
     
    34313447 *
    34323448 * @param   pDevIns     The IOMMU device instance.
     3449 *
     3450 * @thread  Any.
    34333451 */
    34343452static void iommuAmdRaiseMsiInterrupt(PPDMDEVINS pDevIns)
     
    34433461 *
    34443462 * @param   pDevIns     The IOMMU device instance.
     3463 *
     3464 * @thread  Any.
    34453465 */
    34463466static void iommuAmdClearMsiInterrupt(PPDMDEVINS pDevIns)
     
    34653485    IOMMU_STATUS_T const Status = iommuAmdGetStatus(pThis);
    34663486
     3487    /** @todo IOMMU: Consider locking here.  */
     3488
    34673489    /* Check if event logging is active and the log has not overflowed. */
    34683490    if (   Status.n.u1EvtLogRunning
     
    35233545static void iommuAmdSetHwError(PPDMDEVINS pDevIns, PCEVT_GENERIC_T pEvent)
    35243546{
     3547    /** @todo IOMMU: We should probably lock the device here */
    35253548    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
    35263549    if (pThis->ExtFeat.n.u1HwErrorSup)
     
    35393562 * Initializes a DEV_TAB_HARDWARE_ERROR event.
    35403563 *
    3541  * @param   uDevId      The device ID.
    3542  * @param   GCPhysDte   The system physical address of the failed device table
    3543  *                      access.
    3544  * @param   enmOp       The IOMMU operation being performed.
    3545  * @param   pEvent      Where to store the initialized event.
     3564 * @param   uDevId              The device ID.
     3565 * @param   GCPhysDte           The system physical address of the failed device table
     3566 *                              access.
     3567 * @param   enmOp               The IOMMU operation being performed.
     3568 * @param   pEvtDevTabHwErr     Where to store the initialized event.
    35463569 *
    35473570 * @thread  Any.
    35483571 */
    3549 static void iommuAmdInitDevTabHwErrorEvent(uint16_t uDevId, RTGCPHYS GCPhysDte, IOMMUOP enmOp, PEVT_GENERIC_T pEvent)
    3550 {
    3551     memset(pEvent, 0, sizeof(*pEvent));
    3552     AssertCompile(sizeof(EVT_DEV_TAB_HW_ERROR_T) == sizeof(EVT_GENERIC_T));
    3553     PEVT_DEV_TAB_HW_ERROR_T pDevTabHwErr = (PEVT_DEV_TAB_HW_ERROR_T)pEvent;
    3554     pDevTabHwErr->n.u16DevId      = uDevId;
    3555     pDevTabHwErr->n.u1Intr        = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
     3572static void iommuAmdInitDevTabHwErrorEvent(uint16_t uDevId, RTGCPHYS GCPhysDte, IOMMUOP enmOp,
     3573                                           PEVT_DEV_TAB_HW_ERROR_T pEvtDevTabHwErr)
     3574{
     3575    memset(pEvtDevTabHwErr, 0, sizeof(*pEvtDevTabHwErr));
     3576    pEvtDevTabHwErr->n.u16DevId      = uDevId;
     3577    pEvtDevTabHwErr->n.u1Intr        = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
    35563578    /** @todo r=ramshankar: Any other transaction type that can set read/write bit? */
    3557     pDevTabHwErr->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
    3558     pDevTabHwErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
    3559     pDevTabHwErr->n.u2Type        = enmOp == IOMMUOP_CMD ? HWEVTTYPE_DATA_ERROR : HWEVTTYPE_TARGET_ABORT;
    3560     pDevTabHwErr->n.u4EvtCode     = IOMMU_EVT_DEV_TAB_HW_ERROR;
    3561     pDevTabHwErr->n.u64Addr       = GCPhysDte;
     3579    pEvtDevTabHwErr->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
     3580    pEvtDevTabHwErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
     3581    pEvtDevTabHwErr->n.u2Type        = enmOp == IOMMUOP_CMD ? HWEVTTYPE_DATA_ERROR : HWEVTTYPE_TARGET_ABORT;
     3582    pEvtDevTabHwErr->n.u4EvtCode     = IOMMU_EVT_DEV_TAB_HW_ERROR;
     3583    pEvtDevTabHwErr->n.u64Addr       = GCPhysDte;
    35623584}
    35633585
     
    35663588 * Raises a DEV_TAB_HARDWARE_ERROR event.
    35673589 *
    3568  * @param   pDevIns     The IOMMU device instance.
    3569  * @param   uDevId      The device ID.
    3570  * @param   GCPhysDte   The system physical address of the failed device table
    3571  *                      access.
    3572  * @param   enmOp       The IOMMU operation being performed.
    3573  * @param   enmEvtType  The device table hardware error event type.
    3574  */
    3575 static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysDte, IOMMUOP enmOp,
     3590 * @param   pDevIns             The IOMMU device instance.
     3591 * @param   uDevId              The device ID.
     3592 * @param   enmOp               The IOMMU operation being performed.
     3593 * @param   pEvtDevTabHwErr     The device table hardware error event.
     3594 * @param   enmEvtType          The device table hardware error event type.
     3595 */
     3596static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, IOMMUOP enmOp, PEVT_DEV_TAB_HW_ERROR_T pEvtDevTabHwErr,
    35763597                                            EVT_DEV_TAB_HW_ERROR_TYPE_T enmEvtType)
    35773598{
    3578     EVT_GENERIC_T Event;
    3579     iommuAmdInitDevTabHwErrorEvent(uDevId, GCPhysDte, enmOp, &Event);
    3580     iommuAmdSetHwError(pDevIns, &Event);
    3581     iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3599    AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_DEV_TAB_HW_ERROR_T));
     3600    PCEVT_GENERIC_T pEvent = (PCEVT_GENERIC_T)pEvtDevTabHwErr;
     3601    iommuAmdSetHwError(pDevIns, (PCEVT_GENERIC_T)pEvent);
     3602    iommuAmdWriteEvtLogEntry(pDevIns, (PCEVT_GENERIC_T)pEvent);
    35823603    if (enmOp != IOMMUOP_CMD)
    35833604        iommuAmdSetPciTargetAbort(pDevIns);
    35843605
    3585     Log((IOMMU_LOG_PFX ": Raised DEV_TAB_HARDWARE_ERROR. uDevId=%#x GCPhysDte=%#RGp enmOp=%u enmType=%u\n", uDevId, GCPhysDte,
    3586          enmOp, enmEvtType));
     3606    Log((IOMMU_LOG_PFX ": Raised DEV_TAB_HARDWARE_ERROR. uDevId=%#x GCPhysDte=%#RGp enmOp=%u enmType=%u\n",
     3607         pEvtDevTabHwErr->n.u16DevId, pEvtDevTabHwErr->n.u64Addr, enmOp, enmEvtType));
    35873608    NOREF(enmEvtType);
    35883609}
     
    35943615 * @param   uDevId          The device ID.
    35953616 * @param   uIova           The I/O virtual address.
     3617 * @param   fRsvdNotZero    Whether reserved bits are not zero. Pass @c false if the
     3618 *                          event was caused by an invalid level encoding in the
     3619 *                          DTE.
    35963620 * @param   enmOp           The IOMMU operation being performed.
    3597  * @param   enmEvtType      The illegal DTE event type.
    3598  * @param   pEvent          Where to store the initialized event.
    3599  */
    3600 static void iommuAmdInitIllegalDteEvent(uint16_t uDevId, uint64_t uIova, IOMMUOP enmOp, EVT_ILLEGAL_DTE_TYPE_T enmEvtType,
    3601                                         PEVT_GENERIC_T pEvent)
    3602 {
    3603     memset(pEvent, 0, sizeof(*pEvent));
    3604     AssertCompile(sizeof(EVT_ILLEGAL_DTE_T) == sizeof(EVT_GENERIC_T));
    3605     PEVT_ILLEGAL_DTE_T pIllegalDteErr = (PEVT_ILLEGAL_DTE_T)pEvent;
    3606     pIllegalDteErr->n.u16DevId      = uDevId;
    3607     pIllegalDteErr->n.u1Interrupt   = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
    3608     pIllegalDteErr->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
    3609     pIllegalDteErr->n.u1RsvdNotZero = RT_BOOL(enmEvtType == kIllegalDteType_RsvdNotZero);
    3610     pIllegalDteErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
    3611     pIllegalDteErr->n.u4EvtCode     = IOMMU_EVT_ILLEGAL_DEV_TAB_ENTRY;
    3612     pIllegalDteErr->n.u64Addr       = uIova & ~UINT64_C(0x3);
     3621 * @param   pEvtIllegalDte  Where to store the initialized event.
     3622 */
     3623static void iommuAmdInitIllegalDteEvent(uint16_t uDevId, uint64_t uIova, bool fRsvdNotZero, IOMMUOP enmOp,
     3624                                        PEVT_ILLEGAL_DTE_T pEvtIllegalDte)
     3625{
     3626    memset(pEvtIllegalDte, 0, sizeof(*pEvtIllegalDte));
     3627    pEvtIllegalDte->n.u16DevId      = uDevId;
     3628    pEvtIllegalDte->n.u1Interrupt   = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
     3629    pEvtIllegalDte->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
     3630    pEvtIllegalDte->n.u1RsvdNotZero = fRsvdNotZero;
     3631    pEvtIllegalDte->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
     3632    pEvtIllegalDte->n.u4EvtCode     = IOMMU_EVT_ILLEGAL_DEV_TAB_ENTRY;
     3633    pEvtIllegalDte->n.u64Addr       = uIova & ~UINT64_C(0x3);
    36133634    /** @todo r=ramshankar: Not sure why the last 2 bits are marked as reserved by the
    36143635     *        IOMMU spec here but not for this field for I/O page fault event. */
     
    36213642 *
    36223643 * @param   pDevIns         The IOMMU instance data.
    3623  * @param   uDevId          The device ID.
    3624  * @param   uIova           The I/O virtual address.
    36253644 * @param   enmOp           The IOMMU operation being performed.
     3645 * @param   pEvtIllegalDte  The illegal device table entry event.
    36263646 * @param   enmEvtType      The illegal DTE event type.
    36273647 */
    3628 static void iommuAmdRaiseIllegalDteEvent(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, IOMMUOP enmOp,
     3648static void iommuAmdRaiseIllegalDteEvent(PPDMDEVINS pDevIns, IOMMUOP enmOp, PCEVT_ILLEGAL_DTE_T pEvtIllegalDte,
    36293649                                         EVT_ILLEGAL_DTE_TYPE_T enmEvtType)
    36303650{
    3631     EVT_GENERIC_T Event;
    3632     iommuAmdInitIllegalDteEvent(uDevId, uIova, enmOp, enmEvtType, &Event);
    3633     iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3651    AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_ILLEGAL_DTE_T));
     3652    PCEVT_GENERIC_T pEvent = (PCEVT_GENERIC_T)pEvtIllegalDte;
     3653    iommuAmdWriteEvtLogEntry(pDevIns, pEvent);
    36343654    if (enmOp != IOMMUOP_CMD)
    36353655        iommuAmdSetPciTargetAbort(pDevIns);
    36363656
    3637     Log((IOMMU_LOG_PFX ": Raised ILLEGAL_DTE_EVENT. uDevId=%#x uIova=%#RX64 enmOp=%u enmType=%u\n", uDevId, uIova, enmOp,
    3638          enmEvtType));
     3657    Log((IOMMU_LOG_PFX ": Raised ILLEGAL_DTE_EVENT. uDevId=%#x uIova=%#RX64 enmOp=%u enmEvtType=%u\n", pEvtIllegalDte->n.u16DevId,
     3658         pEvtIllegalDte->n.u64Addr, enmOp, enmEvtType));
    36393659    NOREF(enmEvtType);
    36403660}
     
    36443664 * Initializes an IO_PAGE_FAULT event.
    36453665 *
    3646  * @param   uDevId          The device ID.
    3647  * @param   uDomainId       The domain ID.
    3648  * @param   uIova           The I/O virtual address being accessed.
    3649  * @param   fPresent        Transaction to a page marked as present (including
    3650  *                          DTE.V=1) or interrupt marked as remapped
    3651  *                          (IRTE.RemapEn=1).
    3652  * @param   enmOp           The IOMMU operation being performed.
    3653  * @param   enmEvtType      The I/O page fault event type.
    3654  * @param   pEvent          Where to store the initialized event.
    3655  */
    3656 static void iommuAmdInitIoPageFaultEvent(uint16_t uDevId, uint16_t uDomainId, uint64_t uIova, bool fPresent,
    3657                                          IOMMUOP enmOp, EVT_IO_PAGE_FAULT_TYPE_T enmEvtType, PEVT_GENERIC_T pEvent)
    3658 {
    3659     memset(pEvent, 0, sizeof(*pEvent));
    3660     AssertCompile(sizeof(EVT_IO_PAGE_FAULT_T) == sizeof(EVT_GENERIC_T));
    3661     PEVT_IO_PAGE_FAULT_T pIoPageFault = (PEVT_IO_PAGE_FAULT_T)pEvent;
    3662     pIoPageFault->n.u16DevId            = uDevId;
    3663     //pIoPageFault->n.u4PasidHi         = 0;
    3664     pIoPageFault->n.u16DomainOrPasidLo  = uDomainId;
    3665     //pIoPageFault->n.u1GuestOrNested   = 0;
    3666     //pIoPageFault->n.u1NoExecute       = 0;
    3667     //pIoPageFault->n.u1User            = 0;
    3668     pIoPageFault->n.u1Interrupt         = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
    3669     pIoPageFault->n.u1Present           = fPresent;
    3670     pIoPageFault->n.u1ReadWrite         = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
    3671     //pIoPageFault->n.u1PermIndicator   = 0;
    3672     pIoPageFault->n.u1RsvdNotZero       = RT_BOOL(   enmEvtType == kIoPageFaultType_PteRsvdNotZero
    3673                                                   || enmEvtType == kIoPageFaultType_IrteRemapEn);
    3674     pIoPageFault->n.u1Translation       = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
    3675     pIoPageFault->n.u4EvtCode           = IOMMU_EVT_IO_PAGE_FAULT;
    3676     pIoPageFault->n.u64Addr             = uIova;
     3666 * @param   uDevId              The device ID.
     3667 * @param   uDomainId           The domain ID.
     3668 * @param   uIova               The I/O virtual address being accessed.
     3669 * @param   fPresent            Transaction to a page marked as present (including
     3670 *                              DTE.V=1) or interrupt marked as remapped
     3671 *                              (IRTE.RemapEn=1).
     3672 * @param   fRsvdNotZero        Whether reserved bits are not zero. Pass @c false if
     3673 *                              the I/O page fault was caused by invalid level
     3674 *                              encoding.
     3675 * @param   enmOp               The IOMMU operation being performed.
     3676 * @param   pEvtIoPageFault     Where to store the initialized event.
     3677 */
     3678static void iommuAmdInitIoPageFaultEvent(uint16_t uDevId, uint16_t uDomainId, uint64_t uIova, bool fPresent, bool fRsvdNotZero,
     3679                                         IOMMUOP enmOp, PEVT_IO_PAGE_FAULT_T pEvtIoPageFault)
     3680{
     3681    memset(pEvtIoPageFault, 0, sizeof(*pEvtIoPageFault));
     3682    pEvtIoPageFault->n.u16DevId            = uDevId;
     3683    //pEvtIoPageFault->n.u4PasidHi         = 0;
     3684    pEvtIoPageFault->n.u16DomainOrPasidLo  = uDomainId;
     3685    //pEvtIoPageFault->n.u1GuestOrNested   = 0;
     3686    //pEvtIoPageFault->n.u1NoExecute       = 0;
     3687    //pEvtIoPageFault->n.u1User            = 0;
     3688    pEvtIoPageFault->n.u1Interrupt         = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
     3689    pEvtIoPageFault->n.u1Present           = fPresent;
     3690    pEvtIoPageFault->n.u1ReadWrite         = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
     3691    //pEvtIoPageFault->n.u1PermIndicator   = 0;
     3692    pEvtIoPageFault->n.u1RsvdNotZero       = fRsvdNotZero;
     3693    pEvtIoPageFault->n.u1Translation       = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
     3694    pEvtIoPageFault->n.u4EvtCode           = IOMMU_EVT_IO_PAGE_FAULT;
     3695    pEvtIoPageFault->n.u64Addr             = uIova;
    36773696}
    36783697
     
    36823701 *
    36833702 * @param   pDevIns             The IOMMU instance data.
    3684  * @param   uDevId              The device ID.
    3685  * @param   uDomainId           The domain ID.
    3686  * @param   uIova               The I/O virtual address being accessed.
    3687  * @param   fPresentOrValid     Transaction to a page marked as present (including
    3688  *                              DTE.V=1) or interrupt marked as remapped
    3689  *                              (IRTE.RemapEn=1).
     3703 * @param   pDte                The device table entry. Optional, can be NULL
     3704 *                              depending on @a enmOp.
     3705 * @param   pIrte               The interrupt remapping table entry. Optional, can
     3706 *                              be NULL depending on @a enmOp.
    36903707 * @param   enmOp               The IOMMU operation being performed.
     3708 * @param   pEvtIoPageFault     The I/O page fault event.
    36913709 * @param   enmEvtType          The I/O page fault event type.
    3692  */
    3693 static void iommuAmdRaiseIoPageFaultEvent(PPDMDEVINS pDevIns, uint16_t uDevId, uint16_t uDomainId, uint64_t uIova,
    3694                                           bool fPresentOrValid, IOMMUOP enmOp, EVT_IO_PAGE_FAULT_TYPE_T enmEvtType)
    3695 {
    3696     EVT_GENERIC_T Event;
    3697     iommuAmdInitIoPageFaultEvent(uDevId, uDomainId, uIova, fPresentOrValid, enmOp, enmEvtType, &Event);
     3710 *
     3711 * @thread  Any.
     3712 */
     3713static void iommuAmdRaiseIoPageFaultEvent(PPDMDEVINS pDevIns, PCDTE_T pDte, PCIRTE_T pIrte, IOMMUOP enmOp,
     3714                                          PCEVT_IO_PAGE_FAULT_T pEvtIoPageFault, EVT_IO_PAGE_FAULT_TYPE_T enmEvtType)
     3715{
     3716    AssertCompile(sizeof(EVT_GENERIC_T) == sizeof(EVT_IO_PAGE_FAULT_T));
     3717    PCEVT_GENERIC_T pEvent = (PCEVT_GENERIC_T)pEvtIoPageFault;
     3718
     3719    bool fSuppressEvtLogging = false;
     3720    if (   enmOp == IOMMUOP_MEM_READ
     3721        || enmOp == IOMMUOP_MEM_WRITE)
     3722    {
     3723        if (   pDte
     3724            && pDte->n.u1Valid)
     3725        {
     3726            fSuppressEvtLogging = pDte->n.u1SuppressAllPfEvents;
     3727            /** @todo IOMMU: Implement DTE.SE bit, i.e. device ID specific I/O page fault
     3728             *        suppression. Perhaps will be possible when we complete IOTLB/cache
     3729             *        handling. */
     3730        }
     3731    }
     3732    else if (enmOp == IOMMUOP_INTR_REQ)
     3733    {
     3734        if (   pDte
     3735            && pDte->n.u1IntrMapValid)
     3736            fSuppressEvtLogging = !pDte->n.u1IgnoreUnmappedIntrs;
     3737
     3738        if (   !fSuppressEvtLogging
     3739            && pIrte)
     3740            fSuppressEvtLogging = pIrte->n.u1SuppressPf;
     3741    }
     3742    /* else: Events are never suppressed for commands. */
    36983743
    36993744    switch (enmEvtType)
     
    37223767            if (enmOp != IOMMUOP_TRANSLATE_REQ)
    37233768            {
    3724                 iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3769                if (!fSuppressEvtLogging)
     3770                    iommuAmdWriteEvtLogEntry(pDevIns, pEvent);
    37253771                if (enmOp != IOMMUOP_CMD)
    37263772                    iommuAmdSetPciTargetAbort(pDevIns);
     
    37323778        {
    37333779            /* Access is blocked and only creates an event log entry. */
    3734             iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3780            if (!fSuppressEvtLogging)
     3781                iommuAmdWriteEvtLogEntry(pDevIns, pEvent);
    37353782            break;
    37363783        }
     
    37453792            /* Only trigerred by interrupt requests. */
    37463793            Assert(enmOp == IOMMUOP_INTR_REQ);
    3747             iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3794            if (!fSuppressEvtLogging)
     3795                iommuAmdWriteEvtLogEntry(pDevIns, pEvent);
    37483796            iommuAmdSetPciTargetAbort(pDevIns);
    37493797            break;
     
    37623810            Assert(enmOp != IOMMUOP_CMD);
    37633811            Assert(enmOp != IOMMUOP_TRANSLATE_REQ); /** @todo IOMMU: We don't support translation requests yet. */
    3764             iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3812            if (!fSuppressEvtLogging)
     3813                iommuAmdWriteEvtLogEntry(pDevIns, pEvent);
    37653814            if (   enmOp == IOMMUOP_MEM_READ
    37663815                || enmOp == IOMMUOP_MEM_WRITE)
     
    37883837    pIotlbe->GCPhysSpa = GCPhysSpa;
    37893838}
     3839
    37903840
    37913841/**
     
    38163866 *
    38173867 * @remarks Ensure the exclusion range is enabled prior to calling this function.
     3868 *
     3869 * @thread  Any.
    38183870 */
    38193871static bool iommuAmdIsDvaInExclRange(PCIOMMU pThis, PCDTE_T pDte, uint64_t uIova)
     
    38673919    {
    38683920        Log((IOMMU_LOG_PFX ": Failed to read device table entry at %#RGp. rc=%Rrc -> DevTabHwError\n", GCPhysDte, rc));
    3869         iommuAmdRaiseDevTabHwErrorEvent(pDevIns, uDevId, GCPhysDte, enmOp, kDevTabHwErrType_TargetAbort);
     3921
     3922        EVT_DEV_TAB_HW_ERROR_T EvtDevTabHwErr;
     3923        iommuAmdInitDevTabHwErrorEvent(uDevId, GCPhysDte, enmOp, &EvtDevTabHwErr);
     3924        iommuAmdRaiseDevTabHwErrorEvent(pDevIns, enmOp, &EvtDevTabHwErr, kDevTabHwErrType_TargetAbort);
    38703925    }
    38713926
     
    38893944 * @param   pIotlbe     The IOTLB entry to update with the results of the
    38903945 *                      translation.
     3946 *
     3947 * @thread  Any.
    38913948 */
    38923949static int iommuAmdWalkIoPageTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess,
    38933950                                    PCDTE_T pDte, IOMMUOP enmOp, PIOTLBE_T pIotlbe)
    38943951{
    3895     NOREF(pDevIns);
     3952    NOREF(cbAccess);
    38963953    Assert(pDte->n.u1Valid);
    3897     Assert(pDte->n.u1TranslationValid);
    3898     Assert(cbAccess > 0);
    3899 
     3954
     3955    /* If the translation is not valid, raise an I/O page fault. */
    39003956    if (pDte->n.u1TranslationValid)
    39013957    { /* likely */ }
    39023958    else
    39033959    {
    3904         iommuAmdRaiseIoPageFaultEvent(pDevIns, uDevId, pDte->n.u16DomainId, uIova, true /* fPresentOrValid */,
    3905                                       enmOp, kIoPageFaultType_DteTranslationDisabled);
     3960        /** @todo r=ramshankar: The AMD IOMMU spec. says page walk is terminated but
     3961         *        doesn't explicitly say whether an I/O page fault is raised. From other
     3962         *        places in the spec. it seems early page walk terminations (starting with
     3963         *        the DTE) return the state computed so far and raises an I/O page fault. So
     3964         *        returning an invalid translation rather than skipping translation. */
     3965        EVT_IO_PAGE_FAULT_T EvtIoPageFault;
     3966        iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, false /* fPresent */, false /* fRsvdNotZero */,
     3967                                     enmOp, &EvtIoPageFault);
     3968        iommuAmdRaiseIoPageFaultEvent(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,
     3969                                      kIoPageFaultType_DteTranslationDisabled);
    39063970        iommuAmdUpdateIotlbe(NIL_RTGCPHYS, 0 /* cShift */,  IOMMU_IO_PERM_NONE, pIotlbe);
    39073971        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    39083972    }
    39093973
    3910     /* If the page table depth is 0, translation is disabled and access is controlled by IR and IW bits. */
    3911     if (pDte->n.u3Mode == 0)
     3974    /* If the page table level (depth) is 0, translation is disabled and access is controlled by the permission bits. */
     3975    uint8_t const uLevel = pDte->n.u3Mode;
     3976    if (uLevel == 0)
    39123977    {
    39133978        uint8_t const fDtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK;
     
    39213986    }
    39223987
    3923     /* If the paging mode exceeds the host-address translation levels, translation fails. */
    3924     if (pDte->n.u3Mode > IOMMU_MAX_HOST_PT_LEVEL)
     3988    /* If the page table level (depth) exceeds the allowed host-address translation levels, page walk terminates. */
     3989    if (uLevel > IOMMU_MAX_HOST_PT_LEVEL)
    39253990    {
    39263991        /** @todo r=ramshankar: I cannot make out from the AMD IOMMU spec. if I should be
    39273992         *        raising an ILLEGAL_DEV_TABLE_ENTRY event or an IO_PAGE_FAULT event here.
    3928          *        I'm just going with this one... */
    3929         /** @todo IOMMU: raise I/O page fault. */
     3993         *        I'm just going with I/O page fault. */
     3994        EVT_IO_PAGE_FAULT_T EvtIoPageFault;
     3995        iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, enmOp,
     3996                                     &EvtIoPageFault);
     3997        iommuAmdRaiseIoPageFaultEvent(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault,kIoPageFaultType_PteInvalidLvlEncoding);
     3998
    39303999        iommuAmdUpdateIotlbe(NIL_RTGCPHYS, 0 /* cShift */,  IOMMU_IO_PERM_NONE, pIotlbe);
    39314000        return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    39324001    }
    39334002
    3934     /** @todo IOMMU: page walk. */
     4003    /* Traverse the I/O page table starting with the validated DTE. */
     4004    PIOPTENTITY_T pPtEntity = (PIOPTENTITY_T)&pDte->au64[0];
     4005    for (;;)
     4006    {
     4007        /* If the page entity isn't present or has insufficient permissions for the access being made, raise an I/O page fault. */
     4008        uint8_t const fPtePerm = (pPtEntity->u64 >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK;
     4009        if (   !pPtEntity->n.u1Present
     4010            || (fAccess & fPtePerm) != fAccess)
     4011        {
     4012            EVT_IO_PAGE_FAULT_TYPE_T const EvtIoPageFaultType = (fAccess & IOMMU_IO_PERM_WRITE) ? kIoPageFaultType_WriteProtect
     4013                                                                                                : kIoPageFaultType_ReadProtect;
     4014            EVT_IO_PAGE_FAULT_T EvtIoPageFault;
     4015            iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */,
     4016                                         enmOp, &EvtIoPageFault);
     4017            iommuAmdRaiseIoPageFaultEvent(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, EvtIoPageFaultType);
     4018            iommuAmdUpdateIotlbe(NIL_RTGCPHYS, 0 /* cShift */,  IOMMU_IO_PERM_NONE, pIotlbe);
     4019            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
     4020        }
     4021
     4022        /** @todo IOMMU: rest of page walk. */
     4023    }
    39354024
    39364025    return VERR_NOT_IMPLEMENTED;
     
    39514040 *          pIotlbe when this function returns VINF_SUCCESS. Caller is expected to
    39524041 *          know and fill in the rest already.
     4042 *
     4043 * @thread  Any.
    39534044 */
    39544045static int iommuAmdLookupDeviceTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, IOMMUOP enmOp,
     
    39634054    if (RT_SUCCESS(rc))
    39644055    {
    3965         /* If the DTE is not valid addresses are forwarded without translation */
     4056        /* If the DTE is not valid, addresses are forwarded without translation */
    39664057        if (Dte.n.u1Valid)
    39674058        { /* likely */ }
     
    39734064
    39744065        /* Validate bits 127:0 of the device table entry when DTE.V is 1. */
    3975         uint64_t const fRsvdQword0 = Dte.au64[0] & ~(IOMMU_DTE_QWORD_0_VALID_MASK & ~IOMMU_DTE_QWORD_0_FEAT_MASK);
    3976         uint64_t const fRsvdQword1 = Dte.au64[1] & ~(IOMMU_DTE_QWORD_1_VALID_MASK & ~IOMMU_DTE_QWORD_1_FEAT_MASK);
    3977         if (RT_LIKELY(   !fRsvdQword0
    3978                       && !fRsvdQword1))
     4066        uint64_t const fRsvd0 = Dte.au64[0] & ~(IOMMU_DTE_QWORD_0_VALID_MASK & ~IOMMU_DTE_QWORD_0_FEAT_MASK);
     4067        uint64_t const fRsvd1 = Dte.au64[1] & ~(IOMMU_DTE_QWORD_1_VALID_MASK & ~IOMMU_DTE_QWORD_1_FEAT_MASK);
     4068        if (RT_LIKELY(   !fRsvd0
     4069                      && !fRsvd1))
    39794070        { /* likely */ }
    39804071        else
    39814072        {
    3982             Log((IOMMU_LOG_PFX ": Invalid reserved bits in DTE (u64[0]=%#RX64 u64[1]=%#RX64) -> Illegal DTE\n", fRsvdQword0,
    3983                  fRsvdQword1));
    3984             iommuAmdRaiseIllegalDteEvent(pDevIns, uDevId, uIova, enmOp, kIllegalDteType_RsvdNotZero);
     4073            Log((IOMMU_LOG_PFX ": Invalid reserved bits in DTE (u64[0]=%#RX64 u64[1]=%#RX64) -> Illegal DTE\n", fRsvd0, fRsvd1));
     4074            EVT_ILLEGAL_DTE_T Event;
     4075            iommuAmdInitIllegalDteEvent(uDevId, uIova, true /* fRsvdNotZero */, enmOp, &Event);
     4076            iommuAmdRaiseIllegalDteEvent(pDevIns, enmOp, &Event, kIllegalDteType_RsvdNotZero);
    39854077            return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
    39864078        }
    39874079
    3988         /* If the IOVA is subject to address exclusion addresses are forwarded without translation. */
     4080        /* If the IOVA is subject to address exclusion, addresses are forwarded without translation. */
    39894081        if (   !pThis->ExclRangeBaseAddr.n.u1ExclEnable
    39904082            || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova))
     
    39964088        }
    39974089
    3998         /* Walk the I/O page tables to translate and get permission bits for the IOVA. */
     4090        /* Walk the I/O page tables to translate and get permission bits for the IOVA access. */
    39994091        rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uIova, cbAccess, IOMMU_IO_PERM_READ, &Dte, enmOp, pIotlbe);
    40004092        if (RT_FAILURE(rc))
     
    40344126    {
    40354127        IOTLBE_T Iotlbe;
    4036         iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /*cShift*/, IOMMU_IO_PERM_NONE, &Iotlbe);
     4128        iommuAmdInitIotlbe(NIL_RTGCPHYS, 0 /* cShift */, IOMMU_IO_PERM_NONE, &Iotlbe);
    40374129
    40384130        /** @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