VirtualBox

Changeset 89029 in vbox


Ignore:
Timestamp:
May 13, 2021 8:26:23 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144368
Message:

Intel IOMMU: bugref:9967 Handle clearing of FECTL_REG.IP bit.

File:
1 edited

Legend:

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

    r89028 r89029  
    868868 * @param   offReg  The MMIO offset of the register.
    869869 * @param   uReg    The 32-bit value to write.
    870  */
    871 static uint32_t dmarRegWrite32(PDMAR pThis, uint16_t offReg, uint32_t uReg)
     870 * @param   puPrev  Where to store the register value prior to writing.
     871 */
     872static uint32_t dmarRegWrite32(PDMAR pThis, uint16_t offReg, uint32_t uReg, uint32_t *puPrev)
    872873{
    873874    /* Read current value from the 32-bit register. */
     
    876877    uint32_t fRw1cMask;
    877878    dmarRegReadRaw32Ex(pThis, offReg, &uCurReg, &fRwMask, &fRw1cMask);
     879    *puPrev = uCurReg;
    878880
    879881    uint32_t const fRoBits   = uCurReg & ~fRwMask;      /* Preserve current read-only and reserved bits. */
     
    896898 * @param   offReg  The MMIO offset of the register.
    897899 * @param   uReg    The 64-bit value to write.
    898  */
    899 static uint64_t dmarRegWrite64(PDMAR pThis, uint16_t offReg, uint64_t uReg)
     900 * @param   puPrev  Where to store the register value prior to writing.
     901 */
     902static uint64_t dmarRegWrite64(PDMAR pThis, uint16_t offReg, uint64_t uReg, uint64_t *puPrev)
    900903{
    901904    /* Read current value from the 64-bit register. */
     
    904907    uint64_t fRw1cMask;
    905908    dmarRegReadRaw64Ex(pThis, offReg, &uCurReg, &fRwMask, &fRw1cMask);
     909    *puPrev = uCurReg;
    906910
    907911    uint64_t const fRoBits   = uCurReg & ~fRwMask;      /* Preserve current read-only and reserved bits. */
     
    12271231    {
    12281232        uFstsReg |= VTD_BF_FSTS_REG_PFO_MASK;
    1229         dmarRegWrite32(pThis, VTD_MMIO_OFF_FSTS_REG, uFstsReg);
     1233        dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_FSTS_REG, uFstsReg);
    12301234        return false;
    12311235    }
     
    13991403         *        ESRTPS is supported. */
    14001404        pThis->uRtaddrReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_RTADDR_REG);
     1405        dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_GSTS_REG, UINT32_MAX, VTD_BF_GSTS_REG_RTPS_MASK);
    14011406    }
    14021407
     
    14621467
    14631468/**
     1469 * Handles writes to FECTL_REG.
     1470 *
     1471 * @returns Strict VBox status code.
     1472 * @param   pDevIns     The IOMMU device instance.
     1473 * @param   uFectlReg   The value written to FECTL_REG.
     1474 */
     1475static VBOXSTRICTRC dmarFectlRegWrite(PPDMDEVINS pDevIns, uint32_t uFectlReg)
     1476{
     1477    /*
     1478     * If software unmasks the interrupt when the interrupt is pending, we must raise
     1479     * the interrupt now (which will consequently clear the interrupt pending (IP) bit).
     1480     */
     1481    if (    (uFectlReg & VTD_BF_FECTL_REG_IP_MASK)
     1482        && ~(uFectlReg & VTD_BF_FECTL_REG_IM_MASK))
     1483        dmarEventRaiseInterrupt(pDevIns, DMAREVENTTYPE_FAULT);
     1484    return VINF_SUCCESS;
     1485}
     1486
     1487
     1488/**
     1489 * Handles writes to FSTS_REG.
     1490 *
     1491 * @returns Strict VBox status code.
     1492 * @param   pDevIns     The IOMMU device instance.
     1493 * @param   uFstsReg    The value written to FSTS_REG.
     1494 * @param   uPrev       The value in FSTS_REG prior to writing it.
     1495 */
     1496static VBOXSTRICTRC dmarFstsRegWrite(PPDMDEVINS pDevIns, uint32_t uFstsReg, uint32_t uPrev)
     1497{
     1498    /*
     1499     * If software clears other status bits in FSTS_REG (pertaining to primary fault logging),
     1500     * the interrupt pending (IP) bit must be cleared.
     1501     *
     1502     * See Intel VT-d spec. 10.4.10 "Fault Event Control Register".
     1503     */
     1504    uint32_t const fChanged = uPrev ^ uFstsReg;
     1505    if (fChanged & (  VTD_BF_FSTS_REG_ICE_MASK | VTD_BF_FSTS_REG_ITE_MASK
     1506                    | VTD_BF_FSTS_REG_IQE_MASK | VTD_BF_FSTS_REG_PFO_MASK))
     1507    {
     1508        PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     1509        dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_FECTL_REG, ~VTD_BF_FECTL_REG_IP_MASK, 0 /* fOrMask */);
     1510    }
     1511    return VINF_SUCCESS;
     1512}
     1513
     1514
     1515/**
    14641516 * Handles writes to IQT_REG.
    14651517 *
     
    15621614    /*
    15631615     * If software unmasks the interrupt when the interrupt is pending, we must raise
    1564      * the interrupt now (which will consequently clear the interrupt pending bit).
     1616     * the interrupt now (which will consequently clear the interrupt pending (IP) bit).
    15651617     */
    15661618    if (    (uIectlReg & VTD_BF_IECTL_REG_IP_MASK)
    15671619        && ~(uIectlReg & VTD_BF_IECTL_REG_IM_MASK))
    15681620        dmarEventRaiseInterrupt(pDevIns, DMAREVENTTYPE_INV_COMPLETE);
     1621    return VINF_SUCCESS;
     1622}
     1623
     1624
     1625/**
     1626 * Handles writes to FRCD_REG (High 64-bits).
     1627 *
     1628 * @returns Strict VBox status code.
     1629 * @param   pDevIns     The IOMMU device instance.
     1630 * @param   offReg      The MMIO register offset.
     1631 * @param   cbReg       The size of the MMIO access (in bytes).
     1632 * @param   uFrcdHiReg  The value written to FRCD_REG.
     1633 * @param   uPrev       The value in FRCD_REG prior to writing it.
     1634 */
     1635static VBOXSTRICTRC dmarFrcdHiRegWrite(PPDMDEVINS pDevIns, uint16_t offReg, uint8_t cbReg, uint64_t uFrcdHiReg, uint64_t uPrev)
     1636{
     1637    /* We only care about responding to high 32-bits, low 32-bits are read-only. */
     1638    if (offReg + cbReg > DMAR_MMIO_OFF_FRCD_HI_REG + 4)
     1639    {
     1640        /*
     1641         * If software cleared the RW1C F (fault) bit in all FRCD_REGs, hardware clears the
     1642         * Primary Pending Fault (PPF) and the interrupt pending (IP) bits. Our implementation
     1643         * has only 1 FRCD register.
     1644         *
     1645         * See Intel VT-d spec. 10.4.10 "Fault Event Control Register".
     1646         */
     1647        AssertCompile(DMAR_FRCD_REG_COUNT == 1);
     1648        uint64_t const fChanged = uPrev ^ uFrcdHiReg;
     1649        if (fChanged & VTD_BF_1_FRCD_REG_F_MASK)
     1650        {
     1651            Assert(!(uFrcdHiReg & VTD_BF_1_FRCD_REG_F_MASK));  /* Software should only ever be able to clear this bit. */
     1652            PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     1653            dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_FSTS_REG, ~VTD_BF_FSTS_REG_PPF_MASK, 0 /* fOrMask */);
     1654            dmarRegChangeRaw32(pThis, VTD_MMIO_OFF_FECTL_REG, ~VTD_BF_FECTL_REG_IP_MASK, 0 /* fOrMask */);
     1655        }
     1656    }
    15691657    return VINF_SUCCESS;
    15701658}
     
    18881976        DMAR_LOCK_RET(pDevIns, pThisCC, VINF_IOM_R3_MMIO_WRITE);
    18891977
    1890         uint64_t const uRegWritten = cb == 8 ? dmarRegWrite64(pThis, offReg, *(uint64_t *)pv)
    1891                                              : dmarRegWrite32(pThis, offReg, *(uint32_t *)pv);
     1978        uint64_t uPrev = 0;
     1979        uint64_t const uRegWritten = cb == 8 ? dmarRegWrite64(pThis, offReg, *(uint64_t *)pv, &uPrev)
     1980                                             : dmarRegWrite32(pThis, offReg, *(uint32_t *)pv, (uint32_t *)&uPrev);
    18921981        VBOXSTRICTRC rcStrict = VINF_SUCCESS;
    18931982        switch (off)
     
    19061995            }
    19071996
     1997            case VTD_MMIO_OFF_FSTS_REG:         /* 32-bit */
     1998            {
     1999                rcStrict = dmarFstsRegWrite(pDevIns, uRegWritten, uPrev);
     2000                break;
     2001            }
     2002
     2003            case VTD_MMIO_OFF_FECTL_REG:        /* 32-bit */
     2004            {
     2005                rcStrict = dmarFectlRegWrite(pDevIns, uRegWritten);
     2006                break;
     2007            }
     2008
    19082009            case VTD_MMIO_OFF_IQT_REG:          /* 64-bit */
    19092010            /*   VTD_MMIO_OFF_IQT_REG + 4: */   /* High 32-bits reserved. */
     
    19202021            }
    19212022
    1922             case VTD_MMIO_OFF_ICS_REG:        /* 32-bit */
     2023            case VTD_MMIO_OFF_ICS_REG:          /* 32-bit */
    19232024            {
    19242025                rcStrict = dmarIcsRegWrite(pDevIns, uRegWritten);
     
    19292030            {
    19302031                rcStrict = dmarIectlRegWrite(pDevIns, uRegWritten);
     2032                break;
     2033            }
     2034
     2035            case DMAR_MMIO_OFF_FRCD_HI_REG:     /* 64-bit */
     2036            case DMAR_MMIO_OFF_FRCD_HI_REG + 4:
     2037            {
     2038                rcStrict = dmarFrcdHiRegWrite(pDevIns, offReg, cb, uRegWritten, uPrev);
    19312039                break;
    19322040            }
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