VirtualBox

Changeset 84101 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Apr 30, 2020 12:54:05 PM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
137690
Message:

AMD IOMMU: bugref:9654 Bits.

File:
1 edited

Legend:

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

    r84089 r84101  
    569569    /** The 32-bit unsigned integer view. */
    570570    uint32_t        au32[8];
     571    /** The 64-bit unsigned integer view. */
     572    uint64_t        au64[4];
    571573} DEV_TAB_ENTRY_T;
    572574AssertCompileSize(DEV_TAB_ENTRY_T, 32);
     575#define IOMMU_DEV_TAB_ENTRY_QWORD_0_VALID_MASK      UINT64_C(0x7fffffffffffff83)
     576#define IOMMU_DEV_TAB_ENTRY_QWORD_1_VALID_MASK      UINT64_C(0xfffffbffffffffff)
     577#define IOMMU_DEV_TAB_ENTRY_QWORD_2_VALID_MASK      UINT64_C(0xf70fffffffffffff)
     578#define IOMMU_DEV_TAB_ENTRY_QWORD_3_VALID_MASK      UINT64_C(0xffc0000000000000)
     579/** Pointer to a device table entry. */
     580typedef DEV_TAB_ENTRY_T *PDEVTAB_ENTRY_T;
     581/** Pointer to a const device table entry. */
     582typedef DEV_TAB_ENTRY_T const *PCDEV_TAB_ENTRY_T;
    573583
    574584/**
     
    843853
    844854/**
    845  * Event log types.
    846  * In accordance with the AMD spec.
    847  */
    848 typedef enum EVTLOGTYPE
    849 {
    850     EVTLOGTYPE_RSVD = 0,
    851     EVTLOGTYPE_MASTER_ABORT,
    852     EVTLOGTYPE_TARGET_ABORT,
    853     EVTLOGTYPE_DATA_ERROR
    854 } EVTLOGTYPE;
    855 AssertCompileSize(EVTLOGTYPE, 4);
     855 * Hardware event types.
     856 * In accordance with the AMD spec.
     857 */
     858typedef enum HWEVTTYPE
     859{
     860    HWEVTTYPE_RSVD = 0,
     861    HWEVTTYPE_MASTER_ABORT,
     862    HWEVTTYPE_TARGET_ABORT,
     863    HWEVTTYPE_DATA_ERROR
     864} HWEVTTYPE;
     865AssertCompileSize(HWEVTTYPE, 4);
    856866
    857867/**
     
    873883        uint16_t    u1ReadWrite : 1;        /**< Bit  53     - RW: Read/Write. */
    874884        uint16_t    u1Rsvd1 : 1;            /**< Bit  54     - Reserved. */
    875         uint16_t    u1RsvdZero : 1;         /**< Bit  55     - RZ: Reserved bit not Zero or invalid level encoding. */
     885        uint16_t    u1RsvdNotZero : 1;      /**< Bit  55     - RZ: Reserved bit not Zero or invalid level encoding. */
    876886        uint16_t    u1Translation : 1;      /**< Bit  56     - TN: Translation. */
    877887        uint16_t    u3Rsvd0 : 3;            /**< Bits 59:57  - Reserved. */
    878888        uint16_t    u4EvtCode : 4;          /**< Bits 63:60  - Event code. */
    879         uint32_t    u2Rsvd1 : 2;            /**< Bits 65:64  - Reserved. */
    880         uint32_t    u30AddrLo : 2;          /**< Bits 95:66  - Address: Device Virtual Address (Lo). */
    881         uint32_t    u30AddrHi;              /**< Bits 127:96 - Address: Device Virtual Address (Hi). */
     889        uint64_t    u64Addr;                /**< Bits 127:64 - Address: Device Virtual Address. */
    882890    } n;
    883891    /** The 32-bit unsigned integer view.  */
     
    885893} EVT_ILLEGAL_DEV_TAB_ENTRY_T;
    886894AssertCompileSize(EVT_ILLEGAL_DEV_TAB_ENTRY_T, 16);
     895/** Pointer to an illegal device table entry event. */
     896typedef EVT_ILLEGAL_DEV_TAB_ENTRY_T *PEVT_ILLEGAL_DEV_TAB_ENTRY_T;
    887897
    888898/**
     
    904914        uint16_t    u1ReadWrite : 1;        /**< Bit  53     - RW: Read/Write. */
    905915        uint16_t    u1Perm : 1;             /**< Bit  54     - PE: Permission Indicator. */
    906         uint16_t    u1RsvdZero : 1;         /**< Bit  55     - RZ: Reserved bit not Zero or invalid level encoding. */
     916        uint16_t    u1RsvdNotZero : 1;      /**< Bit  55     - RZ: Reserved bit not Zero or invalid level encoding. */
    907917        uint16_t    u1Translation : 1;      /**< Bit  56     - TN: Translation. */
    908918        uint16_t    u3Rsvd0 : 3;            /**< Bit  59:57  - Reserved. */
     
    11251135} IOMMU_BAR_T;
    11261136AssertCompileSize(IOMMU_BAR_T, 8);
    1127 #define IOMMU_BAR_VALID_MASK    UINT64_C(0xffffffffffffc001)
     1137#define IOMMU_BAR_VALID_MASK        UINT64_C(0xffffffffffffc001)
    11281138
    11291139/**
     
    19711981typedef PPR_LOG_OVERFLOW_EARLY_T        PPR_LOG_B_OVERFLOW_EARLY_T;
    19721982
     1983/**
     1984 * IOMMU operation types.
     1985 */
     1986typedef enum IOMMUOP
     1987{
     1988    /** Address translation request. */
     1989    IOMMUOP_TRANSLATE_REQ = 0,
     1990    /** Memory read request. */
     1991    IOMMUOP_MEM_READ,
     1992    /** Memory write request. */
     1993    IOMMUOP_MEM_WRITE,
     1994    /** Interrupt request. */
     1995    IOMMUOP_INTR_REQ,
     1996    /** Command request. */
     1997    IOMMUOP_CMD
     1998} IOMMUOP;
     1999AssertCompileSize(IOMMUOP, 4);
     2000
    19732001
    19742002/**
     
    31643192
    31653193/**
    3166  * Constructs a DEV_TAB_HARDWARE_ERROR event.
    3167  *
    3168  * @param   uDevId          The device ID.
    3169  * @param   GCPhysDevTab    The device table system physical address.
    3170  * @param   fTranslation    Whether this is an translation or transaction request.
    3171  * @param   fInterrupt      Whether the transaction was an interrupt or memory
    3172  *                          request.
    3173  * @param   fReadWrite      Whether the transaction was read-write or read-only.
    3174  *                          Only meaninful when @a fTranslate is @c false and
    3175  *                          @a fInterrupt is false.
    3176  * @param   pEvent          Where to store the constructed event.
    3177  *
    3178  * @thread  Any.
    3179  */
    3180 static void iommuAmdMakeDevTabHwErrorEvent(uint16_t uDevId, RTGCPHYS GCPhysDevTab, bool fTranslation, bool fReadWrite,
    3181                                            bool fInterrupt, PEVT_GENERIC_T pEvent)
    3182 {
    3183     memset(pEvent, 0, sizeof(*pEvent));
    3184     PEVT_DEV_TAB_HW_ERROR_T pDevTabHwErr = (PEVT_DEV_TAB_HW_ERROR_T)pEvent;
    3185     pDevTabHwErr->n.u16DevId      = uDevId;
    3186     pDevTabHwErr->n.u1Intr        = fInterrupt;
    3187     pDevTabHwErr->n.u1ReadWrite   = fReadWrite;
    3188     pDevTabHwErr->n.u1Translation = fTranslation;
    3189     pDevTabHwErr->n.u2Type        = EVTLOGTYPE_TARGET_ABORT;
    3190     pDevTabHwErr->n.u4EvtCode     = IOMMU_EVT_DEV_TAB_HW_ERROR;
    3191     pDevTabHwErr->n.u64Addr       = GCPhysDevTab;
    3192 }
    3193 
    3194 
    3195 /**
    31963194 * Sets an event in the hardware error registers.
    31973195 *
     
    32173215
    32183216/**
     3217 * Constructs a DEV_TAB_HARDWARE_ERROR event.
     3218 *
     3219 * @param   uDevId          The device ID.
     3220 * @param   GCPhysDevTab    The system physical address of the failed device table
     3221 *                          access.
     3222 * @param   fOperation      The operation being performed.
     3223 * @param   pEvent          Where to store the constructed event.
     3224 *
     3225 * @thread  Any.
     3226 */
     3227static void iommuAmdMakeDevTabHwErrorEvent(uint16_t uDevId, RTGCPHYS GCPhysDevTabEntry, IOMMUOP enmOp, PEVT_GENERIC_T pEvent)
     3228{
     3229    memset(pEvent, 0, sizeof(*pEvent));
     3230    AssertCompile(sizeof(EVT_DEV_TAB_HW_ERROR_T) == sizeof(EVT_GENERIC_T));
     3231    PEVT_DEV_TAB_HW_ERROR_T pDevTabHwErr = (PEVT_DEV_TAB_HW_ERROR_T)pEvent;
     3232    pDevTabHwErr->n.u16DevId      = uDevId;
     3233    pDevTabHwErr->n.u1Intr        = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
     3234    pDevTabHwErr->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
     3235    pDevTabHwErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
     3236    pDevTabHwErr->n.u2Type        = enmOp == IOMMUOP_CMD ? HWEVTTYPE_DATA_ERROR : HWEVTTYPE_TARGET_ABORT;
     3237    pDevTabHwErr->n.u4EvtCode     = IOMMU_EVT_DEV_TAB_HW_ERROR;
     3238    pDevTabHwErr->n.u64Addr       = GCPhysDevTabEntry;
     3239}
     3240
     3241
     3242/**
     3243 * Raises a DEV_TAB_HARDWARE_ERROR event.
     3244 *
     3245 * @param   pDevIns             The IOMMU device instance.
     3246 * @param   uDevId              The device ID.
     3247 * @param   GCPhysDevTabEntry   The system physical address of the failed device
     3248 *                              table access.
     3249 * @param   enmOp               The operation being performed by the IOMMU.
     3250 */
     3251static void iommuAmdRaiseDevTabHwErrorEvent(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysDevTabEntry, IOMMUOP enmOp)
     3252{
     3253    EVT_GENERIC_T Event;
     3254    iommuAmdMakeDevTabHwErrorEvent(uDevId, GCPhysDevTabEntry, enmOp, &Event);
     3255    iommuAmdSetHwError(pDevIns, &Event);
     3256    iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3257    if (enmOp != IOMMUOP_CMD)
     3258        iommuAmdSetPciTargetAbort(pDevIns);
     3259}
     3260
     3261
     3262/**
     3263 * Constructs an ILLEGAL_DEV_TAB_ENTRY event.
     3264 *
     3265 * @param   uDevId          The device ID.
     3266 * @param   uDva            The device virtual address.
     3267 * @param   fRsvdNotZero    Whether reserved bits in the device table entry were not
     3268 *                          zero.
     3269 * @param   enmOp           The operation being performed.
     3270 * @param   pEvent          Where to store the constructed event.
     3271 */
     3272static void iommuAmdMakeIllegalDevTabEntryEvent(uint16_t uDevId, uint64_t uDva, bool fRsvdNotZero, IOMMUOP enmOp,
     3273                                                PEVT_GENERIC_T pEvent)
     3274{
     3275    memset(pEvent, 0, sizeof(*pEvent));
     3276    AssertCompile(sizeof(EVT_ILLEGAL_DEV_TAB_ENTRY_T) == sizeof(EVT_GENERIC_T));
     3277    PEVT_ILLEGAL_DEV_TAB_ENTRY_T pIllegalDteErr = (PEVT_ILLEGAL_DEV_TAB_ENTRY_T)pEvent;
     3278    pIllegalDteErr->n.u16DevId      = uDevId;
     3279    pIllegalDteErr->n.u1Interrupt   = RT_BOOL(enmOp == IOMMUOP_INTR_REQ);
     3280    pIllegalDteErr->n.u1ReadWrite   = RT_BOOL(enmOp == IOMMUOP_MEM_WRITE);
     3281    pIllegalDteErr->n.u1RsvdNotZero = fRsvdNotZero;
     3282    pIllegalDteErr->n.u1Translation = RT_BOOL(enmOp == IOMMUOP_TRANSLATE_REQ);
     3283    pIllegalDteErr->n.u4EvtCode     = IOMMU_EVT_ILLEGAL_DEV_TAB_ENTRY;
     3284    pIllegalDteErr->n.u64Addr       = uDva & ~UINT64_C(0x3);
     3285    /** @todo r=ramshankar: Not sure why the last 2 bits are marked as reserved by the
     3286     *        IOMMU spec here but not for this field for I/O page fault event. */
     3287    Assert(!(uDva & UINT64_C(0x3)));
     3288}
     3289
     3290
     3291/**
     3292 * Raises an ILLEGAL_DEV_TAB_ENTRY event.
     3293 *
     3294 * @param   pDevIns         The IOMMU instance data.
     3295 * @param   uDevId          The device ID.
     3296 * @param   uDva            The device virtual address.
     3297 * @param   fRsvdNotZero    Whether reserved bits in the device table entry were not
     3298 *                          zero.
     3299 * @param   enmOp           The operation being performed.
     3300 */
     3301static void iommuAmdRaiseIllegalDevTabEntryEvent(PPDMDEVINS pDevIns, uint16_t uDevId, uint64_t uDva, bool fRsvdNotZero,
     3302                                                 IOMMUOP enmOp)
     3303{
     3304    EVT_GENERIC_T Event;
     3305    iommuAmdMakeIllegalDevTabEntryEvent(uDevId, uDva, fRsvdNotZero, enmOp, &Event);
     3306    iommuAmdWriteEvtLogEntry(pDevIns, &Event);
     3307    if (enmOp != IOMMUOP_CMD)
     3308        iommuAmdSetPciTargetAbort(pDevIns);
     3309}
     3310
     3311
     3312/**
    32193313 * Reads a device table entry from guest memory given the device ID.
    32203314 *
     
    32223316 * @param   pDevIns         The IOMMU device instance.
    32233317 * @param   uDevId          The device ID.
     3318 * @param   enmOp           The operation being performed by the IOMMU.
    32243319 * @param   pDevTabEntry    Where to store the device table entry.
    32253320 *
    32263321 * @thread  Any.
    32273322 */
    3228 static int iommuAmdReadDevTabEntry(PPDMDEVINS pDevIns, uint16_t uDevId, DEV_TAB_ENTRY_T *pDevTabEntry)
     3323static int iommuAmdReadDevTabEntry(PPDMDEVINS pDevIns, uint16_t uDevId, IOMMUOP enmOp, DEV_TAB_ENTRY_T *pDevTabEntry)
    32293324{
    32303325    PCIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     
    32453340    if (RT_FAILURE(rc))
    32463341    {
    3247         EVT_GENERIC_T Event;
    3248         iommuAmdMakeDevTabHwErrorEvent(uDevId,
    3249                                        GCPhysDevTab,
    3250                                        true  /* fTranslation */,
    3251                                        false /* fReadWrite */,
    3252                                        false /* fInterrupt */,
    3253                                        &Event);
    3254         iommuAmdSetHwError(pDevIns, &Event);
    3255         iommuAmdWriteEvtLogEntry(pDevIns, &Event);
    3256         iommuAmdSetPciTargetAbort(pDevIns);
    3257         Log((IOMMU_LOG_PFX ": Failed to read device table entry at %#RGp. rc=%Rrc -> target abort\n", GCPhysDevTabEntry, rc));
     3342        Log((IOMMU_LOG_PFX ": Failed to read device table entry at %#RGp. rc=%Rrc\n", GCPhysDevTabEntry, rc));
     3343        iommuAmdRaiseDevTabHwErrorEvent(pDevIns, uDevId, GCPhysDevTabEntry, enmOp);
    32583344    }
    32593345
     
    32773363{
    32783364    RT_NOREF(pDevIns, uDevId, uDva, cbRead, pGCPhysOut);
    3279     return VERR_NOT_IMPLEMENTED;
     3365
     3366    Assert(pDevIns);
     3367    Assert(pGCPhysOut);
     3368
     3369    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
     3370    IOMMUOP const enmOp = IOMMUOP_TRANSLATE_REQ;
     3371
     3372    /* Addresses are forwarded without translation when the IOMMU is disabled. */
     3373    IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis);
     3374    if (Ctrl.n.u1IommuEn)
     3375    {
     3376        /** @todo IOTLB cache lookup. */
     3377
     3378        /* Read the device table entry. */
     3379        DEV_TAB_ENTRY_T DevTabEntry;
     3380        int rc = iommuAmdReadDevTabEntry(pDevIns, uDevId, enmOp, &DevTabEntry);
     3381        if (RT_SUCCESS(rc))
     3382        {
     3383            /* Addresses are forwarded without translation when DTE.V is 0. */
     3384            if (DevTabEntry.n.u1Valid)
     3385            {
     3386                /* Validate bits 127:0 of the device table entry when DTE.V is 1. */
     3387                uint64_t const fRsvdQword0 = DevTabEntry.au64[0] & ~IOMMU_DEV_TAB_ENTRY_QWORD_0_VALID_MASK;
     3388                uint64_t const fRsvdQword1 = DevTabEntry.au64[1] & ~IOMMU_DEV_TAB_ENTRY_QWORD_1_VALID_MASK;
     3389                if (   fRsvdQword0
     3390                    || fRsvdQword1)
     3391                {
     3392                    Log((IOMMU_LOG_PFX ":DTE invalid reserved bits ([0]=%#RX64 [1]=%#RX64)\n", fRsvdQword0, fRsvdQword1));
     3393                    iommuAmdRaiseIllegalDevTabEntryEvent(pDevIns, uDevId, uDva, true /* fRsvdNotZero */, enmOp);
     3394                    return VERR_GENERAL_FAILURE; /** @todo IOMMU: Change this. */
     3395                }
     3396
     3397                /** @todo IOMMU: Traverse the I/O page table and translate. */
     3398                return VERR_NOT_IMPLEMENTED;
     3399            }
     3400        }
     3401        else
     3402        {
     3403            Log((IOMMU_LOG_PFX ":Failed to read device table entry. uDevId=%#x rc=%Rrc\n", uDevId, rc));
     3404            return VERR_GENERAL_FAILURE; /** @todo IOMMU: Change this. */
     3405        }
     3406    }
     3407
     3408    *pGCPhysOut = uDva;
     3409    return VINF_SUCCESS;
    32803410}
    32813411
     
    33813511        case IOMMU_PCI_OFF_BASE_ADDR_REG_LO:
    33823512        {
    3383             IOMMU_BAR_T const IommuBar = pThis->IommuBar;
    3384             if (!IommuBar.n.u1Enable)
     3513            if (pThis->IommuBar.n.u1Enable)
    33853514            {
    3386                 pThis->IommuBar.au32[0] = u32Value & IOMMU_BAR_VALID_MASK;
     3515                rcStrict = VINF_SUCCESS;
     3516                Log((IOMMU_LOG_PFX ": Writing Base Address (Lo) when it's already enabled -> Ignored\n"));
     3517                break;
     3518            }
     3519
     3520            pThis->IommuBar.au32[0] = u32Value & IOMMU_BAR_VALID_MASK;
     3521            if (pThis->IommuBar.n.u1Enable)
     3522            {
    33873523                Assert(pThis->hMmio == NIL_IOMMMIOHANDLE);
    3388                 Assert(!pThis->ExtFeat.n.u1PerfCounterSup); /* 16K aligned when performance counters aren't supported. */
    3389                 uint64_t const fAlignMask = UINT64_C(0xffffffffffffc000);
    3390                 RTGCPHYS const GCPhysMmioBase = RT_MAKE_U64(pThis->IommuBar.au32[0] & fAlignMask, pThis->IommuBar.au32[1]);
     3524                Assert(!pThis->ExtFeat.n.u1PerfCounterSup); /* Base is 16K aligned when performance counters aren't supported. */
     3525                RTGCPHYS const GCPhysMmioBase = RT_MAKE_U64(pThis->IommuBar.au32[0] & 0xffffc000, pThis->IommuBar.au32[1]);
    33913526                rcStrict = PDMDevHlpMmioMap(pDevIns, pThis->hMmio, GCPhysMmioBase);
    33923527                if (RT_FAILURE(rcStrict))
    33933528                    Log((IOMMU_LOG_PFX ": Failed to map IOMMU MMIO region at %#RGp. rc=%Rrc\n", GCPhysMmioBase, rcStrict));
    33943529            }
    3395             else
    3396             {
    3397                 rcStrict = VINF_SUCCESS;
    3398                 Log((IOMMU_LOG_PFX ": Writing Base Address (Lo) when it's already enabled -> Ignored\n"));
    3399             }
    34003530            break;
    34013531        }
     
    34033533        case IOMMU_PCI_OFF_BASE_ADDR_REG_HI:
    34043534        {
    3405             IOMMU_BAR_T const IommuBar = pThis->IommuBar;
    3406             if (!IommuBar.n.u1Enable)
     3535            if (!pThis->IommuBar.n.u1Enable)
    34073536                pThis->IommuBar.au32[1] = u32Value;
    34083537            else
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette