Changeset 84199 in vbox for trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
- Timestamp:
- May 8, 2020 8:23:30 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r84183 r84199 606 606 607 607 /** Mask of valid bits for EPHSUP (Enhanced Peripheral Page Request Handling 608 * Support) feature s(bits 52:53). */608 * Support) feature (bits 52:53). */ 609 609 #define IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK UINT64_C(0x0030000000000000) 610 610 611 /** Mask of valid bits for GTSup (Guest Translation Support) feature s (bits612 * 55:60,bits 80:95). */611 /** Mask of valid bits for GTSup (Guest Translation Support) feature (bits 55:60, 612 * bits 80:95). */ 613 613 #define IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK UINT64_C(0x1f80000000000000) 614 614 #define IOMMU_DTE_QWORD_1_FEAT_GTSUP_MASK UINT64_C(0x00000000ffff0000) 615 615 616 /* Mask of valid bits for GIoSup (Guest I/O Protection Support) feature s(bit 54). */616 /* Mask of valid bits for GIoSup (Guest I/O Protection Support) feature (bit 54). */ 617 617 #define IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK UINT64_C(0x0040000000000000) 618 618 619 /* Mask of allvalid DTE feature bits. */619 /* Mask of valid DTE feature bits. */ 620 620 #define IOMMU_DTE_QWORD_0_FEAT_MASK ( IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK \ 621 621 | IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK \ … … 623 623 #define IOMMU_DTE_QWORD_1_FEAT_MASK (IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK) 624 624 625 /* Mask of all valid DTE bits . */625 /* Mask of all valid DTE bits (including all feature bits). */ 626 626 #define IOMMU_DTE_QWORD_0_VALID_MASK UINT64_C(0x7fffffffffffff83) 627 627 #define IOMMU_DTE_QWORD_1_VALID_MASK UINT64_C(0xfffffbffffffffff) … … 630 630 631 631 /** 632 * I/O Page T ableEntry.632 * I/O Page Translation Entry. 633 633 * In accordance with the AMD spec. 634 634 */ … … 652 652 } n; 653 653 /** The 64-bit unsigned integer view. */ 654 uint64_t u ;654 uint64_t u64; 655 655 } IOPTE_T; 656 656 AssertCompileSize(IOPTE_T, 8); … … 676 676 } n; 677 677 /** The 64-bit unsigned integer view. */ 678 uint64_t u ;678 uint64_t u64; 679 679 } IOPDE_T; 680 680 AssertCompileSize(IOPDE_T, 8); 681 681 682 682 /** 683 * I/O Page Table GenericEntity.683 * I/O Page Table Entry/Entity. 684 684 * In accordance with the AMD spec. 685 685 * 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; 694 RT_GCC_EXTENSION uint64_t u 4Ign0 : 4; /**< Bits 4:1 - Ignored. */695 RT_GCC_EXTENSION uint64_t u 1Accessed : 1; /**< Bit 5 - A: Accessed. */696 RT_GCC_EXTENSION uint64_t u 3Ign0 : 3; /**< Bits 8:6 - Ignored. */697 RT_GCC_EXTENSION uint64_t u 3NextLevel : 3; /**< Bits 11:9 - Next Level: Next page translation level. */698 RT_GCC_EXTENSION uint64_t u 40PageAddr : 40; /**< Bits 51:12 - Page address. */699 RT_GCC_EXTENSION uint64_t u 9Rsvd0 : 9; /**< Bits 60:52 - Reserved. */700 RT_GCC_EXTENSION uint64_t u1I oRead : 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 */ 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 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; 704 704 } IOPTENTITY_T; 705 AssertCompileSize(IOPDE_T, 8); 705 AssertCompileSize(IOPTENTITY_T, 8); 706 AssertCompile(sizeof(IOPTENTITY_T) == sizeof(IOPTE_T)); 707 AssertCompile(sizeof(IOPTENTITY_T) == sizeof(IOPDE_T)); 706 708 /** Pointer to an IOPT_ENTITY_T struct. */ 707 709 typedef IOPTENTITY_T *PIOPTENTITY_T; … … 710 712 711 713 /** 712 * Interrupt Remapping Table Entry .714 * Interrupt Remapping Table Entry (IRTE). 713 715 * In accordance with the AMD spec. 714 716 */ … … 728 730 } n; 729 731 /** The 32-bit unsigned integer view. */ 730 uint32_t u ;732 uint32_t u32; 731 733 } IRTE_T; 732 734 AssertCompileSize(IRTE_T, 4); 735 /** Pointer to an IRTE_T struct. */ 736 typedef IRTE_T *PIRTE_T; 737 /** Pointer to a const IRTE_T struct. */ 738 typedef IRTE_T const *PCIRTE_T; 733 739 734 740 /** … … 771 777 } n; 772 778 /** The 64-bit unsigned integer view. */ 773 uint 32_t au64[2];779 uint64_t au64[2]; 774 780 } CMD_COMPLETION_WAIT_T; 775 781 AssertCompileSize(CMD_COMPLETION_WAIT_T, 16); … … 977 983 /** Pointer to an illegal device table entry event. */ 978 984 typedef EVT_ILLEGAL_DTE_T *PEVT_ILLEGAL_DTE_T; 985 /** Pointer to a const illegal device table entry event. */ 986 typedef EVT_ILLEGAL_DTE_T const *PCEVT_ILLEGAL_DTE_T; 979 987 980 988 /** … … 1008 1016 /** Pointer to an I/O page fault event. */ 1009 1017 typedef EVT_IO_PAGE_FAULT_T *PEVT_IO_PAGE_FAULT_T; 1018 /** Pointer to a const I/O page fault event. */ 1019 typedef EVT_IO_PAGE_FAULT_T const *PCEVT_IO_PAGE_FAULT_T; 1020 1010 1021 1011 1022 /** … … 1036 1047 /** Pointer to a device table hardware error event. */ 1037 1048 typedef EVT_DEV_TAB_HW_ERROR_T *PEVT_DEV_TAB_HW_ERROR_T; 1049 /** Pointer to a const device table hardware error event. */ 1050 typedef EVT_DEV_TAB_HW_ERROR_T const *PCEVT_DEV_TAB_HW_ERROR_T; 1038 1051 1039 1052 /** … … 2223 2236 /** The number of offset bits in the system physical address. */ 2224 2237 uint8_t cShift; 2225 /** The translated system physical address of the page. */2238 /** The translated system physical address (SPA) of the page. */ 2226 2239 RTGCPHYS GCPhysSpa; 2227 2240 } IOTLBE_T; … … 2374 2387 AssertCompileMemberAlignment(IOMMU, hMmio, 8); 2375 2388 AssertCompileMemberAlignment(IOMMU, IommuBar, 8); 2376 2377 2389 2378 2390 /** … … 3129 3141 * @param cb The size of the write access. 3130 3142 * @param uValue The value being written. 3143 * 3144 * @thread EMT. 3131 3145 */ 3132 3146 static VBOXSTRICTRC iommuAmdWriteRegister(PPDMDEVINS pDevIns, uint32_t off, uint8_t cb, uint64_t uValue) … … 3270 3284 * @param off The MMIO offset of the register in bytes. 3271 3285 * @param puResult Where to store the value being read. 3286 * 3287 * @thread EMT. 3272 3288 */ 3273 3289 static VBOXSTRICTRC iommuAmdReadRegister(PPDMDEVINS pDevIns, uint32_t off, uint64_t *puResult) … … 3431 3447 * 3432 3448 * @param pDevIns The IOMMU device instance. 3449 * 3450 * @thread Any. 3433 3451 */ 3434 3452 static void iommuAmdRaiseMsiInterrupt(PPDMDEVINS pDevIns) … … 3443 3461 * 3444 3462 * @param pDevIns The IOMMU device instance. 3463 * 3464 * @thread Any. 3445 3465 */ 3446 3466 static void iommuAmdClearMsiInterrupt(PPDMDEVINS pDevIns) … … 3465 3485 IOMMU_STATUS_T const Status = iommuAmdGetStatus(pThis); 3466 3486 3487 /** @todo IOMMU: Consider locking here. */ 3488 3467 3489 /* Check if event logging is active and the log has not overflowed. */ 3468 3490 if ( Status.n.u1EvtLogRunning … … 3523 3545 static void iommuAmdSetHwError(PPDMDEVINS pDevIns, PCEVT_GENERIC_T pEvent) 3524 3546 { 3547 /** @todo IOMMU: We should probably lock the device here */ 3525 3548 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 3526 3549 if (pThis->ExtFeat.n.u1HwErrorSup) … … 3539 3562 * Initializes a DEV_TAB_HARDWARE_ERROR event. 3540 3563 * 3541 * @param uDevId The device ID.3542 * @param GCPhysDte The system physical address of the failed device table3543 * access.3544 * @param enmOp The IOMMU operation being performed.3545 * @param pEv entWhere 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. 3546 3569 * 3547 3570 * @thread Any. 3548 3571 */ 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); 3572 static 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); 3556 3578 /** @todo r=ramshankar: Any other transaction type that can set read/write bit? */ 3557 p DevTabHwErr->n.u1ReadWrite = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);3558 p DevTabHwErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);3559 p DevTabHwErr->n.u2Type = enmOp == IOMMUOP_CMD ? HWEVTTYPE_DATA_ERROR : HWEVTTYPE_TARGET_ABORT;3560 p DevTabHwErr->n.u4EvtCode = IOMMU_EVT_DEV_TAB_HW_ERROR;3561 p DevTabHwErr->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; 3562 3584 } 3563 3585 … … 3566 3588 * Raises a DEV_TAB_HARDWARE_ERROR event. 3567 3589 * 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 */ 3596 static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, IOMMUOP enmOp, PEVT_DEV_TAB_HW_ERROR_T pEvtDevTabHwErr, 3576 3597 EVT_DEV_TAB_HW_ERROR_TYPE_T enmEvtType) 3577 3598 { 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); 3582 3603 if (enmOp != IOMMUOP_CMD) 3583 3604 iommuAmdSetPciTargetAbort(pDevIns); 3584 3605 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)); 3587 3608 NOREF(enmEvtType); 3588 3609 } … … 3594 3615 * @param uDevId The device ID. 3595 3616 * @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. 3596 3620 * @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 */ 3623 static 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); 3613 3634 /** @todo r=ramshankar: Not sure why the last 2 bits are marked as reserved by the 3614 3635 * IOMMU spec here but not for this field for I/O page fault event. */ … … 3621 3642 * 3622 3643 * @param pDevIns The IOMMU instance data. 3623 * @param uDevId The device ID.3624 * @param uIova The I/O virtual address.3625 3644 * @param enmOp The IOMMU operation being performed. 3645 * @param pEvtIllegalDte The illegal device table entry event. 3626 3646 * @param enmEvtType The illegal DTE event type. 3627 3647 */ 3628 static void iommuAmdRaiseIllegalDteEvent(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, IOMMUOP enmOp,3648 static void iommuAmdRaiseIllegalDteEvent(PPDMDEVINS pDevIns, IOMMUOP enmOp, PCEVT_ILLEGAL_DTE_T pEvtIllegalDte, 3629 3649 EVT_ILLEGAL_DTE_TYPE_T enmEvtType) 3630 3650 { 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); 3634 3654 if (enmOp != IOMMUOP_CMD) 3635 3655 iommuAmdSetPciTargetAbort(pDevIns); 3636 3656 3637 Log((IOMMU_LOG_PFX ": Raised ILLEGAL_DTE_EVENT. uDevId=%#x uIova=%#RX64 enmOp=%u enm Type=%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)); 3639 3659 NOREF(enmEvtType); 3640 3660 } … … 3644 3664 * Initializes an IO_PAGE_FAULT event. 3645 3665 * 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 */ 3678 static 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; 3677 3696 } 3678 3697 … … 3682 3701 * 3683 3702 * @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. 3690 3707 * @param enmOp The IOMMU operation being performed. 3708 * @param pEvtIoPageFault The I/O page fault event. 3691 3709 * @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 */ 3713 static 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. */ 3698 3743 3699 3744 switch (enmEvtType) … … 3722 3767 if (enmOp != IOMMUOP_TRANSLATE_REQ) 3723 3768 { 3724 iommuAmdWriteEvtLogEntry(pDevIns, &Event); 3769 if (!fSuppressEvtLogging) 3770 iommuAmdWriteEvtLogEntry(pDevIns, pEvent); 3725 3771 if (enmOp != IOMMUOP_CMD) 3726 3772 iommuAmdSetPciTargetAbort(pDevIns); … … 3732 3778 { 3733 3779 /* Access is blocked and only creates an event log entry. */ 3734 iommuAmdWriteEvtLogEntry(pDevIns, &Event); 3780 if (!fSuppressEvtLogging) 3781 iommuAmdWriteEvtLogEntry(pDevIns, pEvent); 3735 3782 break; 3736 3783 } … … 3745 3792 /* Only trigerred by interrupt requests. */ 3746 3793 Assert(enmOp == IOMMUOP_INTR_REQ); 3747 iommuAmdWriteEvtLogEntry(pDevIns, &Event); 3794 if (!fSuppressEvtLogging) 3795 iommuAmdWriteEvtLogEntry(pDevIns, pEvent); 3748 3796 iommuAmdSetPciTargetAbort(pDevIns); 3749 3797 break; … … 3762 3810 Assert(enmOp != IOMMUOP_CMD); 3763 3811 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); 3765 3814 if ( enmOp == IOMMUOP_MEM_READ 3766 3815 || enmOp == IOMMUOP_MEM_WRITE) … … 3788 3837 pIotlbe->GCPhysSpa = GCPhysSpa; 3789 3838 } 3839 3790 3840 3791 3841 /** … … 3816 3866 * 3817 3867 * @remarks Ensure the exclusion range is enabled prior to calling this function. 3868 * 3869 * @thread Any. 3818 3870 */ 3819 3871 static bool iommuAmdIsDvaInExclRange(PCIOMMU pThis, PCDTE_T pDte, uint64_t uIova) … … 3867 3919 { 3868 3920 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); 3870 3925 } 3871 3926 … … 3889 3944 * @param pIotlbe The IOTLB entry to update with the results of the 3890 3945 * translation. 3946 * 3947 * @thread Any. 3891 3948 */ 3892 3949 static int iommuAmdWalkIoPageTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, uint8_t fAccess, 3893 3950 PCDTE_T pDte, IOMMUOP enmOp, PIOTLBE_T pIotlbe) 3894 3951 { 3895 NOREF( pDevIns);3952 NOREF(cbAccess); 3896 3953 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. */ 3900 3956 if (pDte->n.u1TranslationValid) 3901 3957 { /* likely */ } 3902 3958 else 3903 3959 { 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); 3906 3970 iommuAmdUpdateIotlbe(NIL_RTGCPHYS, 0 /* cShift */, IOMMU_IO_PERM_NONE, pIotlbe); 3907 3971 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3908 3972 } 3909 3973 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) 3912 3977 { 3913 3978 uint8_t const fDtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK; … … 3921 3986 } 3922 3987 3923 /* If the pag ing 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) 3925 3990 { 3926 3991 /** @todo r=ramshankar: I cannot make out from the AMD IOMMU spec. if I should be 3927 3992 * 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 3930 3999 iommuAmdUpdateIotlbe(NIL_RTGCPHYS, 0 /* cShift */, IOMMU_IO_PERM_NONE, pIotlbe); 3931 4000 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3932 4001 } 3933 4002 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 } 3935 4024 3936 4025 return VERR_NOT_IMPLEMENTED; … … 3951 4040 * pIotlbe when this function returns VINF_SUCCESS. Caller is expected to 3952 4041 * know and fill in the rest already. 4042 * 4043 * @thread Any. 3953 4044 */ 3954 4045 static int iommuAmdLookupDeviceTables(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, size_t cbAccess, IOMMUOP enmOp, … … 3963 4054 if (RT_SUCCESS(rc)) 3964 4055 { 3965 /* If the DTE is not valid addresses are forwarded without translation */4056 /* If the DTE is not valid, addresses are forwarded without translation */ 3966 4057 if (Dte.n.u1Valid) 3967 4058 { /* likely */ } … … 3973 4064 3974 4065 /* Validate bits 127:0 of the device table entry when DTE.V is 1. */ 3975 uint64_t const fRsvd Qword0 = Dte.au64[0] & ~(IOMMU_DTE_QWORD_0_VALID_MASK & ~IOMMU_DTE_QWORD_0_FEAT_MASK);3976 uint64_t const fRsvd Qword1 = Dte.au64[1] & ~(IOMMU_DTE_QWORD_1_VALID_MASK & ~IOMMU_DTE_QWORD_1_FEAT_MASK);3977 if (RT_LIKELY( !fRsvd Qword03978 && !fRsvd Qword1))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)) 3979 4070 { /* likely */ } 3980 4071 else 3981 4072 { 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); 3985 4077 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 3986 4078 } 3987 4079 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. */ 3989 4081 if ( !pThis->ExclRangeBaseAddr.n.u1ExclEnable 3990 4082 || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova)) … … 3996 4088 } 3997 4089 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. */ 3999 4091 rc = iommuAmdWalkIoPageTables(pDevIns, uDevId, uIova, cbAccess, IOMMU_IO_PERM_READ, &Dte, enmOp, pIotlbe); 4000 4092 if (RT_FAILURE(rc)) … … 4034 4126 { 4035 4127 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); 4037 4129 4038 4130 /** @todo IOMMU: IOTLB cache lookup. */
Note:
See TracChangeset
for help on using the changeset viewer.