VirtualBox

Changeset 88574 in vbox for trunk/src/VBox/Devices/Bus


Ignore:
Timestamp:
Apr 19, 2021 11:27:23 AM (4 years ago)
Author:
vboxsync
Message:

Intel IOMMU: bugref:9967 WIP.

File:
1 edited

Legend:

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

    r88558 r88574  
    5454                                                     || (a_off) - DMAR_MMIO_GROUP_1_OFF_FIRST < DMAR_MMIO_GROUP_1_SIZE)
    5555
    56 /** @name DMAR implementation specifics.
    57  * @{ */
     56/** Acquires the DMAR lock but returns with the given error code on failure. */
     57#define DMAR_LOCK_RET(a_pDevIns, a_pThisCC, a_rcBusy) \
     58    do { \
     59        if ((a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnLock((a_pDevIns), (a_rcBusy)) == VINF_SUCCESS) \
     60        { /* likely */ } \
     61        else \
     62            return (a_rcBusy); \
     63    } while (0)
     64
     65/** Release the DMAR lock. */
     66#define DMAR_UNLOCK(a_pDevIns, a_pThisCC)           (a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnUnlock(a_pDevIns)
     67
     68/** Checks whether the calling thread is the owner of the DMAR lock. */
     69#define DMAR_LOCK_IS_OWNER(a_pDevIns, a_pThisCC)    (a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnLockIsOwner(a_pDevIns)
     70
     71/** Asserts that the calling thread owns the DMAR lock. */
     72#define DMAR_ASSERT_LOCK_IS_OWNER(a_pDevIns, a_pThisCC) \
     73    do { \
     74        Assert((a_pThisCC)->CTX_SUFF(pIommuHlp)->pfnLockIsOwner(a_pDevIns)); \
     75        RT_NOREF1(a_pThisCC); \
     76    } while (0)
     77
    5878/** The number of fault recording registers our implementation supports.
    5979 *  Normal guest operation shouldn't trigger faults anyway, so we only support the
     
    98118/** DMAR implementation's minor version number (exposed to software). */
    99119#define DMAR_VER_MINOR                              0
    100 /** @} */
    101120
    102121/** Release log prefix string. */
     
    243262/** Pointer to the DMAR device state for the current context. */
    244263typedef CTX_SUFF(PDMAR) PDMARCC;
     264/** Pointer to the const DMAR device state for the current context. */
     265typedef const CTX_SUFF(PDMAR) PCDMARCC;
    245266
    246267
     
    606627
    607628/**
     629 * Modifies a 32-bit register.
     630 *
     631 * @param   pThis       The shared DMAR device state.
     632 * @param   offReg      The MMIO offset of the register.
     633 * @param   fAndMask    The AND mask (applied first).
     634 * @param   fOrMask     The OR mask.
     635 */
     636static void dmarRegChange32(PDMAR pThis, uint16_t offReg, uint32_t fAndMask, uint32_t fOrMask)
     637{
     638    uint8_t idxGroup;
     639    uint8_t *pabRegs = dmarRegGetGroup(pThis, offReg, sizeof(uint32_t), &idxGroup);
     640    NOREF(idxGroup);
     641    uint32_t uReg = *(uint32_t *)(pabRegs + offReg);
     642    uReg = (uReg & fAndMask) | fOrMask;
     643    *(uint32_t *)(pabRegs + offReg) = uReg;
     644}
     645
     646
     647/**
     648 * Modifies a 64-bit register.
     649 *
     650 * @param   pThis       The shared DMAR device state.
     651 * @param   offReg      The MMIO offset of the register.
     652 * @param   fAndMask    The AND mask (applied first).
     653 * @param   fOrMask     The OR mask.
     654 */
     655static void dmarRegChange64(PDMAR pThis, uint16_t offReg, uint64_t fAndMask, uint64_t fOrMask)
     656{
     657    uint8_t idxGroup;
     658    uint8_t *pabRegs = dmarRegGetGroup(pThis, offReg, sizeof(uint64_t), &idxGroup);
     659    NOREF(idxGroup);
     660    uint64_t uReg = *(uint64_t *)(pabRegs + offReg);
     661    uReg = (uReg & fAndMask) | fOrMask;
     662    *(uint64_t *)(pabRegs + offReg) = uReg;
     663}
     664
     665
     666/**
    608667 * Reads a 64-bit register with exactly the value it contains.
    609668 *
     
    751810    uint64_t const uRtAddrReg = dmarRegRead64(pThis, VTD_MMIO_OFF_RTADDR_REG);
    752811    return RT_BF_GET(uRtAddrReg, VTD_BF_RTADDR_REG_TTM);
     812}
     813
     814
     815/**
     816 * Raises an IQE (invalidation queue error) fault.
     817 *
     818 * @param   pDevIns     The IOMMU device instance.
     819 * @param   pThis       The shared DMAR device state.
     820 * @param   enmIqei     The IQE information.
     821 * @param   enmDiag     The diagnostic reason.
     822 */
     823static void dmarFaultRaiseIqe(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTD_IQERCD_IQEI_T enmIqei)
     824{
     825    PDMAR    pThis   = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     826    PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
     827    DMAR_ASSERT_LOCK_IS_OWNER(pDevIns, pThisCC);
     828
     829    /* Set the error bit. */
     830    uint32_t const fIqe = RT_BF_MAKE(VTD_BF_FSTS_REG_IQE, 1);
     831    dmarRegChange32(pThis, VTD_MMIO_OFF_FSTS_REG, UINT32_MAX, fIqe);
     832
     833    /* Set the error information. */
     834    uint64_t const fIqei = RT_BF_MAKE(VTD_BF_IQERCD_REG_IQEI, enmIqei);
     835    dmarRegChange64(pThis, VTD_MMIO_OFF_IQERCD_REG, UINT64_MAX, fIqei);
     836
     837    /* Update diagnostic reason. */
     838    pThis->enmDiag = enmDiag;
     839
     840    /** @todo Raise interrupt based on FECTL_REG. */
    753841}
    754842
     
    820908        }
    821909        else
    822         {
    823             /* Raise invalidation queue error as queue tail not aligned to 256-bits. */
    824             /** @todo Raise error. */
    825         }
     910            dmarFaultRaiseIqe(pDevIns, kDmarDiag_IqtReg_Qt_NotAligned, kQueueTailNotAligned);
    826911    }
    827912    return VINF_SUCCESS;
     
    9691054
    9701055#ifdef IN_RING3
     1056/**
     1057 * @callback_method_impl{FNDBGFHANDLERDEV}
     1058 */
     1059static DECLCALLBACK(void) dmarR3DbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
     1060{
     1061    PCDMAR      pThis   = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     1062    PCPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
     1063    PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
     1064
     1065    bool const fVerbose = RTStrCmp(pszArgs, "verbose") == 0;
     1066
     1067    DMARDIAG const enmDiag = pThis->enmDiag;
     1068    const char *pszDiag    = enmDiag < RT_ELEMENTS(g_apszDmarDiagDesc) ? g_apszDmarDiagDesc[enmDiag] : "(Unknown)";
     1069
     1070    pHlp->pfnPrintf(pHlp, "Intel-IOMMU:\n");
     1071    pHlp->pfnPrintf(pHlp, " Diag = %u (%s)\n", enmDiag, pszDiag);
     1072    pHlp->pfnPrintf(pHlp, "\n");
     1073}
     1074
     1075
    9711076/**
    9721077 * Initializes all registers in the DMAR unit.
     
    12141319    AssertRCReturn(rc, rc);
    12151320
     1321    /*
     1322     * Register debugger info items.
     1323     */
     1324    PDMDevHlpDBGFInfoRegister(pDevIns, "iommu", "Display IOMMU state.", dmarR3DbgInfo);
     1325
    12161326#ifdef VBOX_WITH_STATISTICS
    12171327    /*
     
    12941404    AssertReturn(pThisCC->CTX_SUFF(pIommuHlp)->u32Version == CTX_SUFF(PDM_IOMMUHLP)_VERSION, VERR_VERSION_MISMATCH);
    12951405    AssertReturn(pThisCC->CTX_SUFF(pIommuHlp)->u32TheEnd  == CTX_SUFF(PDM_IOMMUHLP)_VERSION, VERR_VERSION_MISMATCH);
    1296     AssertPtrReturn(pThisCC->CTX_SUFF(pIommuHlp)->pfnLock,   VERR_INVALID_POINTER);
    1297     AssertPtrReturn(pThisCC->CTX_SUFF(pIommuHlp)->pfnUnlock, VERR_INVALID_POINTER);
     1406    AssertPtrReturn(pThisCC->CTX_SUFF(pIommuHlp)->pfnLock,        VERR_INVALID_POINTER);
     1407    AssertPtrReturn(pThisCC->CTX_SUFF(pIommuHlp)->pfnUnlock,      VERR_INVALID_POINTER);
     1408    AssertPtrReturn(pThisCC->CTX_SUFF(pIommuHlp)->pfnLockIsOwner, VERR_INVALID_POINTER);
    12981409
    12991410    return VINF_SUCCESS;
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