Changeset 87482 in vbox
- Timestamp:
- Jan 29, 2021 4:43:09 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 142504
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/err.h
r87477 r87482 3041 3041 /** Address translation failed. */ 3042 3042 #define VERR_IOMMU_ADDR_TRANSLATION_FAILED (-7207) 3043 /** Address translation disabled (but permission bits apply). */ 3044 #define VINF_IOMMU_ADDR_TRANSLATION_DISABLED 7208 3043 3045 /** Access denied for the address. */ 3044 #define VERR_IOMMU_ADDR_ACCESS_DENIED (-720 8)3046 #define VERR_IOMMU_ADDR_ACCESS_DENIED (-7209) 3045 3047 /** Remapping failed for the interrupt. */ 3046 #define VERR_IOMMU_INTR_REMAP_FAILED (-72 09)3048 #define VERR_IOMMU_INTR_REMAP_FAILED (-7210) 3047 3049 /** Remapping denied for the interrupt (might have caused a PCI target abort). */ 3048 #define VERR_IOMMU_INTR_REMAP_DENIED (-721 0)3050 #define VERR_IOMMU_INTR_REMAP_DENIED (-7211) 3049 3051 /** Command not supported. */ 3050 #define VERR_IOMMU_CMD_NOT_SUPPORTED (-721 1)3052 #define VERR_IOMMU_CMD_NOT_SUPPORTED (-7212) 3051 3053 /** Command format (or reserved bits) invalid. */ 3052 #define VERR_IOMMU_CMD_INVALID_FORMAT (-721 2)3054 #define VERR_IOMMU_CMD_INVALID_FORMAT (-7213) 3053 3055 /** Command hardware failure. */ 3054 #define VERR_IOMMU_CMD_HW_ERROR (-721 3)3056 #define VERR_IOMMU_CMD_HW_ERROR (-7214) 3055 3057 /** IOMMU device is not present. */ 3056 #define VERR_IOMMU_NOT_PRESENT (-721 4)3058 #define VERR_IOMMU_NOT_PRESENT (-7215) 3057 3059 /** @} */ 3058 3060 -
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r87470 r87482 2631 2631 2632 2632 /** 2633 * Walks the I/O page table to translate the I/O virtual address to a system 2634 * physical address. 2633 * Performs pre-translation checks for the given device table entry. 2635 2634 * 2636 2635 * @returns VBox status code. 2637 2636 * @param pDevIns The IOMMU device instance. 2638 * @param uIova The I/O virtual address to translate. Must be 4K aligned.2637 * @param uIova The I/O virtual address to translate. 2639 2638 * @param uDevId The device ID. 2640 2639 * @param fAccess The access permissions (IOMMU_IO_PERM_XXX). This is the 2641 2640 * permissions for the access being made. 2642 2641 * @param pDte The device table entry. 2642 * @param fRootPage Whether to check the root of the access (required only 2643 * for the first page of an access). 2643 2644 * @param enmOp The IOMMU operation being performed. 2644 2645 * @param pWalkResult Where to store the results of the I/O page walk. This is … … 2647 2648 * @thread Any. 2648 2649 */ 2649 static int iommuAmdIoPageTableWalk(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fAccess, PCDTE_T pDte, 2650 IOMMUOP enmOp, PIOWALKRESULT pWalkResult) 2651 { 2652 Assert(pDte->n.u1Valid); 2653 Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK)); 2654 2655 /* If the translation is not valid, raise an I/O page fault. */ 2650 static int iommuAmdPreTranslateChecks(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fAccess, PCDTE_T pDte, 2651 IOMMUOP enmOp, PIOWALKRESULT pWalkResult) 2652 { 2653 /* 2654 * Check if the translation is valid, otherwise raise an I/O page fault. 2655 */ 2656 2656 if (pDte->n.u1TranslationValid) 2657 2657 { /* likely */ } … … 2672 2672 } 2673 2673 2674 /* If the root page table level is 0, translation is skipped and access is controlled by the permission bits. */ 2674 /* 2675 * Check permissions bits in the DTE. 2676 * Note: This MUST be checked prior to checking the root page table level below! 2677 */ 2678 uint8_t const fDtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK; 2679 if ((fAccess & fDtePerm) == fAccess) 2680 { /* likely */ } 2681 else 2682 { 2683 LogFunc(("Permission denied by DTE (fAccess=%#x fDtePerm=%#x) -> IOPF\n", fAccess, fDtePerm)); 2684 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 2685 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2686 true /* fPermDenied */, enmOp, &EvtIoPageFault); 2687 iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, kIoPageFaultType_PermDenied); 2688 return VERR_IOMMU_ADDR_ACCESS_DENIED; 2689 } 2690 2691 /* 2692 * If the root page table level is 0, translation is disabled and GPA=SPA and 2693 * the DTE.IR and DTE.IW bits control permissions (verified above). 2694 */ 2675 2695 uint8_t const uMaxLevel = pDte->n.u3Mode; 2676 2696 if (uMaxLevel != 0) … … 2678 2698 else 2679 2699 { 2680 uint8_t const fDtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK; 2681 if ((fAccess & fDtePerm) != fAccess) 2682 { 2683 LogFunc(("Access denied for IOVA %#RX64. uDevId=%#x fAccess=%#x fDtePerm=%#x\n", uIova, uDevId, fAccess, fDtePerm)); 2684 return VERR_IOMMU_ADDR_ACCESS_DENIED; 2685 } 2700 Assert((fAccess & fDtePerm) == fAccess); /* Verify we've checked permissions. */ 2686 2701 pWalkResult->GCPhysSpa = uIova; 2687 2702 pWalkResult->cShift = 0; 2688 2703 pWalkResult->fIoPerm = fDtePerm; 2689 return VINF_SUCCESS; 2690 } 2691 2692 /* If the root page table level exceeds the allowed host-address translation level, page walk is terminated. */ 2704 return VINF_IOMMU_ADDR_TRANSLATION_DISABLED; 2705 } 2706 2707 /* 2708 * If the root page table level exceeds the allowed host-address translation level, 2709 * page walk is terminated and translation fails. 2710 */ 2693 2711 if (uMaxLevel <= IOMMU_MAX_HOST_PT_LEVEL) 2694 2712 { /* likely */ } … … 2707 2725 } 2708 2726 2709 /* Check permissions bits of the root page table. */ 2710 uint8_t const fRootPtePerm = (pDte->au64[0] >> IOMMU_IO_PERM_SHIFT) & IOMMU_IO_PERM_MASK; 2711 if ((fAccess & fRootPtePerm) == fAccess) 2712 { /* likely */ } 2713 else 2714 { 2715 LogFunc(("Permission denied (fAccess=%#x fRootPtePerm=%#x) -> IOPF\n", fAccess, fRootPtePerm)); 2716 EVT_IO_PAGE_FAULT_T EvtIoPageFault; 2717 iommuAmdIoPageFaultEventInit(uDevId, pDte->n.u16DomainId, uIova, true /* fPresent */, false /* fRsvdNotZero */, 2718 true /* fPermDenied */, enmOp, &EvtIoPageFault); 2719 iommuAmdIoPageFaultEventRaise(pDevIns, pDte, NULL /* pIrte */, enmOp, &EvtIoPageFault, kIoPageFaultType_PermDenied); 2720 return VERR_IOMMU_ADDR_TRANSLATION_FAILED; 2721 } 2722 2723 /** @todo r=ramshankar: IOMMU: Consider splitting the rest of this into a separate 2724 * function called iommuAmdWalkIoPageDirectory() and call it for multi-page 2725 * accesses from the 2nd page. We can avoid re-checking the DTE root-page 2726 * table entry every time. Not sure if it's worth optimizing that case now 2727 * or if at all. */ 2727 /* The DTE allows translations for this device. */ 2728 return VINF_SUCCESS; 2729 } 2730 2731 2732 /** 2733 * Walks the I/O page table to translate the I/O virtual address to a system 2734 * physical address. 2735 * 2736 * @returns VBox status code. 2737 * @param pDevIns The IOMMU device instance. 2738 * @param uIova The I/O virtual address to translate. Must be 4K aligned. 2739 * @param uDevId The device ID. 2740 * @param fAccess The access permissions (IOMMU_IO_PERM_XXX). This is the 2741 * permissions for the access being made. 2742 * @param pDte The device table entry. 2743 * @param enmOp The IOMMU operation being performed. 2744 * @param pWalkResult Where to store the results of the I/O page walk. This is 2745 * only updated when VINF_SUCCESS is returned. 2746 * 2747 * @thread Any. 2748 */ 2749 static int iommuAmdIoPageTableWalk(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uIova, uint8_t fAccess, PCDTE_T pDte, 2750 IOMMUOP enmOp, PIOWALKRESULT pWalkResult) 2751 { 2752 Assert(pDte->n.u1Valid); 2753 Assert(!(uIova & X86_PAGE_4K_OFFSET_MASK)); 2728 2754 2729 2755 /* The virtual address bits indexing table. */ … … 2926 2952 { 2927 2953 /* If the IOVA is subject to address exclusion, addresses are forwarded without translation. */ 2928 if ( !pThis->ExclRangeBaseAddr.n.u1ExclEnable /** @todo lock or make atomic read ?*/2954 if ( !pThis->ExclRangeBaseAddr.n.u1ExclEnable /** @todo lock or make atomic read! */ 2929 2955 || !iommuAmdIsDvaInExclRange(pThis, &Dte, uIova)) 2930 2956 { 2931 /* Walk the I/O page tables to translate the IOVA and check permission for each page in the access. */ 2932 size_t cbRemaining = cbAccess; 2933 uint64_t uIovaPage = uIova & X86_PAGE_4K_BASE_MASK; 2934 uint64_t offIova = uIova & X86_PAGE_4K_OFFSET_MASK; 2935 uint64_t cbPages = 0; 2936 for (;;) 2957 IOWALKRESULT WalkResult; 2958 RT_ZERO(WalkResult); 2959 rc = iommuAmdPreTranslateChecks(pDevIns, uDevId, uIova, fAccess, &Dte, enmOp, &WalkResult); 2960 if (rc == VINF_SUCCESS) 2937 2961 { 2938 IOWALKRESULT WalkResult; 2939 RT_ZERO(WalkResult); 2940 rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fAccess, &Dte, enmOp, &WalkResult); 2941 if (RT_SUCCESS(rc)) 2962 /* Walk the I/O page tables to translate the IOVA and check permissions for the 2963 remaining pages in the access. */ 2964 size_t cbRemaining = cbAccess; 2965 uint64_t uIovaPage = uIova & X86_PAGE_4K_BASE_MASK; 2966 uint64_t offIova = uIova & X86_PAGE_4K_OFFSET_MASK; 2967 uint64_t cbPages = 0; 2968 for (;;) 2942 2969 { 2943 /* If translation is disabled for this device (root paging mode is 0), we're done. */2944 if ( WalkResult.cShift == 0)2970 rc = iommuAmdIoPageTableWalk(pDevIns, uDevId, uIovaPage, fAccess, &Dte, enmOp, &WalkResult); 2971 if (RT_SUCCESS(rc)) 2945 2972 { 2946 GCPhysSpa = uIova; 2947 cbRemaining = 0; 2948 break; 2949 } 2950 2951 /* Store the translated address before continuing to access more pages. */ 2952 Assert(WalkResult.cShift >= X86_PAGE_4K_SHIFT); 2953 if (cbRemaining == cbAccess) 2954 { 2955 uint64_t const offMask = ~(UINT64_C(0xffffffffffffffff) << WalkResult.cShift); 2956 uint64_t const offSpa = uIova & offMask; 2957 GCPhysSpa = WalkResult.GCPhysSpa | offSpa; 2958 } 2959 /* Check if addresses translated so far are physically contiguous. */ 2960 else if ((GCPhysSpa & X86_PAGE_4K_BASE_MASK) + cbPages == WalkResult.GCPhysSpa) 2961 { /* likely */ } 2962 else 2963 break; 2964 2965 /* Check if we need to access more pages. */ 2966 uint64_t const cbPage = UINT64_C(1) << WalkResult.cShift; 2967 if (cbRemaining > cbPage - offIova) 2968 { 2969 cbRemaining -= (cbPage - offIova); /* Calculate how much more we need to access. */ 2970 cbPages += cbPage; /* Update size of all pages read thus far. */ 2971 uIovaPage += cbPage; /* Update address of the next access. */ 2972 offIova = 0; /* After the first page, all pages are accessed from off 0. */ 2973 /* Store the translated address before continuing to access more pages. */ 2974 Assert(WalkResult.cShift >= X86_PAGE_4K_SHIFT); 2975 if (cbRemaining == cbAccess) 2976 { 2977 uint64_t const offMask = ~(UINT64_C(0xffffffffffffffff) << WalkResult.cShift); 2978 uint64_t const offSpa = uIova & offMask; 2979 GCPhysSpa = WalkResult.GCPhysSpa | offSpa; 2980 } 2981 /* Check if addresses translated so far result in a physically contiguous region. */ 2982 else if ((GCPhysSpa & X86_PAGE_4K_BASE_MASK) + cbPages == WalkResult.GCPhysSpa) 2983 { /* likely */ } 2984 else 2985 break; 2986 2987 /* Check if we need to access more pages. */ 2988 uint64_t const cbPage = UINT64_C(1) << WalkResult.cShift; 2989 if (cbRemaining > cbPage - offIova) 2990 { 2991 cbRemaining -= (cbPage - offIova); /* Calculate how much more we need to access. */ 2992 cbPages += cbPage; /* Update size of all pages read thus far. */ 2993 uIovaPage += cbPage; /* Update address of the next access. */ 2994 offIova = 0; /* After first page, all pages are accessed from off 0. */ 2995 } 2996 else 2997 { 2998 cbRemaining = 0; 2999 break; 3000 } 2973 3001 } 2974 3002 else 2975 3003 { 2976 cbRemaining = 0; 3004 /* Translation failed. */ 3005 GCPhysSpa = NIL_RTGCPHYS; 3006 cbRemaining = cbAccess; 2977 3007 break; 2978 3008 } 2979 3009 } 2980 else 2981 { 2982 GCPhysSpa = NIL_RTGCPHYS; 2983 cbRemaining = cbAccess; 2984 break; 2985 } 3010 3011 /* Update how much contiguous memory was accessed. */ 3012 cbContiguous = cbAccess - cbRemaining; 2986 3013 } 2987 2988 /* Calculate how much contiguous memory was accessed. */ 2989 cbContiguous = cbAccess - cbRemaining; 3014 else if (rc == VINF_IOMMU_ADDR_TRANSLATION_DISABLED) 3015 { 3016 /* Translation is disabled for this device (root paging mode is 0). */ 3017 GCPhysSpa = uIova; 3018 cbContiguous = cbAccess; 3019 rc = VINF_SUCCESS; 3020 3021 /* Paranoia. */ 3022 Assert(WalkResult.cShift == 0); 3023 Assert(WalkResult.GCPhysSpa == uIova); 3024 Assert((WalkResult.fIoPerm & fAccess) == fAccess); 3025 /** @todo IOMMU: Add to IOLTB cache. */ 3026 } 3027 else 3028 { 3029 /* Translation failed or access is denied. */ 3030 GCPhysSpa = NIL_RTGCPHYS; 3031 cbContiguous = 0; 3032 Assert(RT_FAILURE(rc)); 3033 } 2990 3034 } 2991 3035 else
Note:
See TracChangeset
for help on using the changeset viewer.