VirtualBox

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


Ignore:
Timestamp:
Apr 29, 2021 1:27:08 PM (4 years ago)
Author:
vboxsync
Message:

Intel IOMMU: bugref:9967 Queued Invalidation WIP.

File:
1 edited

Legend:

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

    r88765 r88781  
    135135/**
    136136 * DMAR error diagnostics.
     137 * Sorted alphabetically so it's easier to add and locate items, no other reason.
    137138 *
    138139 * @note Members of this enum are used as array indices, so no gaps in enum
     
    143144{
    144145    kDmarDiag_None = 0,
     146    kDmarDiag_CcmdReg_NotSupported,
     147    kDmarDiag_CcmdReg_Qi_Enabled,
     148    kDmarDiag_CcmdReg_Ttm_Invalid,
     149    kDmarDiag_IqaReg_Dsc_Fetch_Error,
     150    kDmarDiag_IqaReg_Dw_Invalid,
     151    kDmarDiag_Iqei_Dsc_Type_Invalid,
     152    kDmarDiag_Iqei_Inv_Wait_Dsc_0_1_Rsvd,
     153    kDmarDiag_Iqei_Inv_Wait_Dsc_2_3_Rsvd,
     154    kDmarDiag_Iqei_Inv_Wait_Dsc_Ttm,
     155    kDmarDiag_IqtReg_Qt_Invalid,
    145156    kDmarDiag_IqtReg_Qt_NotAligned,
    146     kDmarDiag_IqtReg_Qt_Invalid,
    147     kDmarDiag_IqaReg_Dw_Invalid,
    148     kDmarDiag_IqaReg_Dsc_Fetch_Error,
    149     kDmarDiag_Iqei_Dsc_Type_Invalid,
    150     kDmarDiag_CcmdReg_Ttm_Invalid,
    151     kDmarDiag_CcmdReg_Qi_Enabled,
    152     kDmarDiag_CcmdReg_NotSupported,
    153157    /* Member for determining array index limit. */
    154158    kDmarDiag_End,
     
    163167#define DMARDIAG_DESC(a_Name)        RT_CONCAT(kDmarDiag_, a_Name) < kDmarDiag_End ? RT_STR(a_Name) : "Ignored"
    164168
    165 /** DMAR diagnostics description. */
     169/** DMAR diagnostics description for members in DMARDIAG. */
    166170static const char *const g_apszDmarDiagDesc[] =
    167171{
    168     DMARDIAG_DESC(None                  ),
    169     DMARDIAG_DESC(IqtReg_Qt_NotAligned  ),
    170     DMARDIAG_DESC(IqtReg_Qt_Invalid     ),
    171     DMARDIAG_DESC(IqaReg_Dw_Invalid     ),
    172     DMARDIAG_DESC(IqaReg_Dsc_Fetch_Error),
    173     DMARDIAG_DESC(Iqei_Dsc_Type_Invalid ),
    174     DMARDIAG_DESC(CcmdReg_Ttm_Invalid   ),
    175     DMARDIAG_DESC(CcmdReg_Qi_Enabled    ),
    176     DMARDIAG_DESC(CcmdReg_NotSupported  )
     172    DMARDIAG_DESC(None                      ),
     173    DMARDIAG_DESC(CcmdReg_NotSupported      ),
     174    DMARDIAG_DESC(CcmdReg_Qi_Enabled        ),
     175    DMARDIAG_DESC(CcmdReg_Ttm_Invalid       ),
     176    DMARDIAG_DESC(IqaReg_Dsc_Fetch_Error    ),
     177    DMARDIAG_DESC(IqaReg_Dw_Invalid         ),
     178    DMARDIAG_DESC(Iqei_Dsc_Type_Invalid     ),
     179    DMARDIAG_DESC(Iqei_Inv_Wait_Dsc_0_1_Rsvd),
     180    DMARDIAG_DESC(Iqei_Inv_Wait_Dsc_2_3_Rsvd),
     181    DMARDIAG_DESC(Iqei_Inv_Wait_Dsc_Ttm     ),
     182    DMARDIAG_DESC(IqtReg_Qt_Invalid         ),
     183    DMARDIAG_DESC(IqtReg_Qt_NotAligned      )
    177184    /* kDmarDiag_End */
    178185};
     
    991998
    992999/**
    993  * Raises an interrupt in response to an event.
     1000 * Raises an interrupt in response to a fault event.
    9941001 *
    9951002 * @param   pDevIns     The IOMMU device instance.
    9961003 */
    997 static void dmarFaultRaiseInterrupt(PPDMDEVINS pDevIns)
     1004static void dmarFaultEventRaiseInterrupt(PPDMDEVINS pDevIns)
    9981005{
    9991006    PDMAR    pThis   = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     
    10351042    }
    10361043}
     1044
     1045
     1046#ifdef IN_RING3
     1047/**
     1048 * Raises an interrupt in response to an invalidation (complete) event.
     1049 *
     1050 * @param   pDevIns     The IOMMU device instance.
     1051 */
     1052static void dmarR3InvEventRaiseInterrupt(PPDMDEVINS pDevIns)
     1053{
     1054    PDMAR    pThis   = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     1055    PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
     1056
     1057    uint32_t const uIcsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_ICS_REG);
     1058    if (uIcsReg & VTD_BF_ICS_REG_IWC_MASK)
     1059        return;
     1060
     1061    uint32_t uIectlReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IECTL_REG);
     1062    if (!(uIectlReg & VTD_BF_FECTL_REG_IM_MASK))
     1063    {
     1064        /* Software has unmasked the interrupt, raise it. */
     1065        MSIMSG Msi;
     1066        Msi.Addr.u64 = RT_MAKE_U64(dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEADDR_REG),
     1067                                   dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEUADDR_REG));
     1068        Msi.Data.u32 = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEDATA_REG);
     1069
     1070        pThisCC->CTX_SUFF(pIommuHlp)->pfnSendMsi(pDevIns, &Msi, 0 /* uTagSrc */);
     1071
     1072        /* Clear interrupt pending bit. */
     1073        uIectlReg &= ~VTD_BF_IECTL_REG_IP_MASK;
     1074        dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_IECTL_REG, uIectlReg);
     1075    }
     1076    else
     1077    {
     1078        /* Interrupt is masked, set the interrupt pending bit. */
     1079        uIectlReg |= VTD_BF_IECTL_REG_IP_MASK;
     1080        dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_IECTL_REG, uIectlReg);
     1081    }
     1082}
     1083#endif /* IN_RING3 */
    10371084
    10381085
     
    11011148    dmarRegChangeRaw64(pThis, VTD_MMIO_OFF_IQERCD_REG, UINT64_MAX, fIqei);
    11021149
    1103     dmarFaultRaiseInterrupt(pDevIns);
     1150    dmarFaultEventRaiseInterrupt(pDevIns);
    11041151}
    11051152
     
    14401487static void dmarR3InvQueueProcessRequests(PPDMDEVINS pDevIns, void const *pvRequests, uint32_t cbRequests, uint8_t fDw)
    14411488{
     1489    PCDMAR   pThis   = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     1490    PCDMARR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARR3);
     1491    DMAR_ASSERT_LOCK_IS_OWNER(pDevIns, pThisR3);
     1492
    14421493    uint8_t const cbDsc = fDw == VTD_IQA_REG_DW_256_BIT ? 32 : 16;
    14431494    for (uint32_t offDsc = 0; offDsc < cbRequests; offDsc += cbDsc)
    14441495    {
    14451496        uint64_t const *puDscQwords = (uint64_t const *)((uintptr_t)pvRequests + offDsc);
    1446         uint8_t const   fDscType    = VTD_GENERIC_INV_DSC_GET_TYPE(puDscQwords[0]);
     1497        uint64_t const  uQword0     = puDscQwords[0];
     1498        uint64_t const  uQword1     = puDscQwords[1];
     1499        uint8_t const   fDscType    = VTD_GENERIC_INV_DSC_GET_TYPE(uQword0);
     1500        uint8_t const   fTtm        = dmarRtAddrRegGetTtm(pThis);
     1501        Assert(fTtm != VTD_TTM_RSVD);       /* Should be guaranteed when software updates GCMD_REG.SRTP. */
     1502
    14471503        switch (fDscType)
    14481504        {
     
    14511507            case VTD_DEV_TLB_INV_DSC_TYPE:      LogRelMax(32, ("%s: DEV_TLB\n", DMAR_LOG_PFX));         break;
    14521508            case VTD_IEC_INV_DSC_TYPE:          LogRelMax(32, ("%s: IEC_INV\n", DMAR_LOG_PFX));         break;
    1453             case VTD_INV_WAIT_DSC_TYPE:         LogRelMax(32, ("%s: INV_WAIT\n", DMAR_LOG_PFX));        break;
     1509
     1510            case VTD_INV_WAIT_DSC_TYPE:
     1511            {
     1512                /* Validate translation modes valid for this descriptor. */
     1513                if (   fTtm == VTD_TTM_LEGACY_MODE
     1514                    || fDw == VTD_IQA_REG_DW_256_BIT)
     1515                { /* likely */  }
     1516                else
     1517                {
     1518                    dmarIqeFaultRecord(pDevIns, kDmarDiag_Iqei_Inv_Wait_Dsc_Ttm, kIqei_InvalidDescriptorType);
     1519                    return;
     1520                }
     1521
     1522                /* Validate reserved bits. */
     1523                uint64_t const fValidMask0 = !(pThis->fExtCap & VTD_BF_ECAP_REG_PDS_MASK)
     1524                                           ? VTD_INV_WAIT_DSC_0_VALID_MASK & ~VTD_BF_0_INV_WAIT_DSC_PD_MASK
     1525                                           : VTD_INV_WAIT_DSC_0_VALID_MASK;
     1526                if (   !(uQword0 & ~fValidMask0)
     1527                    && !(uQword1 & ~VTD_INV_WAIT_DSC_1_VALID_MASK))
     1528                { /* likely */ }
     1529                else
     1530                {
     1531                    dmarIqeFaultRecord(pDevIns, kDmarDiag_Iqei_Inv_Wait_Dsc_0_1_Rsvd, kIqei_RsvdFieldViolation);
     1532                    return;
     1533                }
     1534                if (fDw == VTD_IQA_REG_DW_256_BIT)
     1535                {
     1536                    uint64_t const uQword2 = puDscQwords[2];
     1537                    uint64_t const uQword3 = puDscQwords[3];
     1538                    if (   !uQword2
     1539                        && !uQword3)
     1540                    { /* likely */ }
     1541                    else
     1542                    {
     1543                        dmarIqeFaultRecord(pDevIns, kDmarDiag_Iqei_Inv_Wait_Dsc_2_3_Rsvd, kIqei_RsvdFieldViolation);
     1544                        return;
     1545                    }
     1546                }
     1547
     1548                /* Perform status write (this must be done prior to generating the completion interrupt). */
     1549                bool const fSw = RT_BF_GET(uQword0, VTD_BF_0_INV_WAIT_DSC_SW);
     1550                if (fSw)
     1551                {
     1552                    uint32_t const uStatus      = RT_BF_GET(uQword0, VTD_BF_0_INV_WAIT_DSC_STDATA);
     1553                    RTGCPHYS const GCPhysStatus = uQword1 & VTD_BF_1_INV_WAIT_DSC_STADDR_MASK;
     1554                    DMAR_UNLOCK(pDevIns, pThisR3);
     1555                    int const rc = PDMDevHlpPhysWrite(pDevIns, GCPhysStatus, (void const*)&uStatus, sizeof(uStatus));
     1556                    DMAR_LOCK(pDevIns, pThisR3);
     1557                    AssertRC(rc);
     1558                }
     1559
     1560                /* Generate invalidation event interrupt. */
     1561                bool const fIf = RT_BF_GET(uQword0, VTD_BF_0_INV_WAIT_DSC_IF);
     1562                if (fIf)
     1563                    dmarR3InvEventRaiseInterrupt(pDevIns);
     1564                break;
     1565            }
     1566
    14541567            case VTD_P_IOTLB_INV_DSC_TYPE:      LogRelMax(32, ("%s: P_IOTLB\n", DMAR_LOG_PFX));         break;
    14551568            case VTD_PC_INV_DSC_TYPE:           LogRelMax(32, ("%s: PC_INV\n", DMAR_LOG_PFX));          break;
     
    14611574            default:
    14621575            {
     1576                /* Stop processing further requests. */
    14631577                LogFunc(("Invalid descriptor type: %#x\n", fDscType));
    14641578                dmarIqeFaultRecord(pDevIns, kDmarDiag_Iqei_Dsc_Type_Invalid, kIqei_InvalidDescriptorType);
     
    15101624        if (!fSignaled)
    15111625        {
    1512             int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtInvQueue, RT_INDEFINITE_WAIT);
     1626            int const rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtInvQueue, RT_INDEFINITE_WAIT);
    15131627            AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
    15141628            if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
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