VirtualBox

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


Ignore:
Timestamp:
May 12, 2021 8:43:29 AM (4 years ago)
Author:
vboxsync
Message:

Intel IOMMU: bugref:9967 Interrupt remapping, work-in-progress.

File:
1 edited

Legend:

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

    r88894 r89001  
    363363/** Pointer to the const DMAR device state for the current context. */
    364364typedef CTX_SUFF(PDMAR) const PCDMARCC;
     365
     366/**
     367 * Type of DMAR originated events that generate interrupts.
     368 */
     369typedef enum DMAREVENTTYPE
     370{
     371    /** Invalidation completion event. */
     372    DMAREVENTTYPE_INV_COMPLETE = 0,
     373    /** Fault event. */
     374    DMAREVENTTYPE_FAULT
     375} DMAREVENTTYPE;
    365376
    366377
     
    10531064
    10541065/**
     1066 * Raises an event on behalf of the DMAR.
     1067 *
     1068 * These are events that are generated by the DMAR itself (like faults and
     1069 * invalidation completion notifications).
     1070 *
     1071 * @param   pDevIns         The IOMMU device instance.
     1072 * @param   enmEventType    The DMAR event type.
     1073 *
     1074 * @remarks The DMAR lock must be held while calling this function.
     1075 */
     1076static void dmarEventRaiseInterrupt(PPDMDEVINS pDevIns, DMAREVENTTYPE enmEventType)
     1077{
     1078    uint16_t offCtlReg;
     1079    uint32_t fIntrMaskedMask;
     1080    uint32_t fIntrPendingMask;
     1081    uint16_t offMsiAddrLoReg;
     1082    uint16_t offMsiAddrHiReg;
     1083    uint16_t offMsiDataReg;
     1084    switch (enmEventType)
     1085    {
     1086        case DMAREVENTTYPE_INV_COMPLETE:
     1087        {
     1088            offCtlReg        = VTD_MMIO_OFF_IECTL_REG;
     1089            fIntrMaskedMask  = VTD_BF_IECTL_REG_IM_MASK;
     1090            fIntrPendingMask = VTD_BF_IECTL_REG_IP_MASK;
     1091            offMsiAddrLoReg  = VTD_MMIO_OFF_IEADDR_REG;
     1092            offMsiAddrHiReg  = VTD_MMIO_OFF_IEUADDR_REG;
     1093            offMsiDataReg    = VTD_MMIO_OFF_IEDATA_REG;
     1094            break;
     1095        }
     1096
     1097        case DMAREVENTTYPE_FAULT:
     1098        {
     1099            offCtlReg        = VTD_MMIO_OFF_FECTL_REG;
     1100            fIntrMaskedMask  = VTD_BF_FECTL_REG_IM_MASK;
     1101            fIntrPendingMask = VTD_BF_FECTL_REG_IP_MASK;
     1102            offMsiAddrLoReg  = VTD_MMIO_OFF_FEADDR_REG;
     1103            offMsiAddrHiReg  = VTD_MMIO_OFF_FEUADDR_REG;
     1104            offMsiDataReg    = VTD_MMIO_OFF_FEDATA_REG;
     1105            break;
     1106        }
     1107
     1108        default:
     1109        {
     1110            /* Shouldn't ever happen. */
     1111            AssertMsgFailedReturnVoid(("DMAR event type %#x unknown!\n", enmEventType));
     1112        }
     1113    }
     1114
     1115    /* Check if software has masked the interrupt. */
     1116    PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     1117    uint32_t uCtlReg = dmarRegReadRaw32(pThis, offCtlReg);
     1118    if (!(uCtlReg & fIntrMaskedMask))
     1119    {
     1120        /*
     1121         * Interrupt is unmasked, raise it.
     1122         *
     1123         * Interrupts generated by the DMAR have trigger mode and level as 0.
     1124         * See Intel spec. 5.1.6 "Remapping Hardware Event Interrupt Programming".
     1125         */
     1126        MSIMSG Msi;
     1127        Msi.Addr.au32[0]         = dmarRegReadRaw32(pThis, offMsiAddrLoReg);
     1128        Msi.Addr.au32[1]         = (pThis->fExtCapReg & VTD_BF_ECAP_REG_EIM_MASK) ? dmarRegReadRaw32(pThis, offMsiAddrHiReg) : 0;
     1129        Msi.Data.u32             = dmarRegReadRaw32(pThis, offMsiDataReg);
     1130        Msi.Data.n.u1Level       = 0;
     1131        Msi.Data.n.u1TriggerMode = 0;
     1132
     1133        PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
     1134        pThisCC->CTX_SUFF(pIommuHlp)->pfnSendMsi(pDevIns, &Msi, 0 /* uTagSrc */);
     1135
     1136        /* Clear interrupt pending bit. */
     1137        uCtlReg &= ~fIntrPendingMask;
     1138        dmarRegWriteRaw32(pThis, offCtlReg, uCtlReg);
     1139    }
     1140    else
     1141    {
     1142        /* Interrupt is masked, set the interrupt pending bit. */
     1143        uCtlReg |= fIntrPendingMask;
     1144        dmarRegWriteRaw32(pThis, offCtlReg, uCtlReg);
     1145    }
     1146}
     1147
     1148
     1149/**
    10551150 * Raises an interrupt in response to a fault event.
    10561151 *
     
    10641159    PDMAR    pThis   = PDMDEVINS_2_DATA(pDevIns, PDMAR);
    10651160    PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
    1066 
    10671161    DMAR_ASSERT_LOCK_IS_OWNER(pDevIns, pThisCC);
    10681162
     
    10771171    }
    10781172#endif
    1079 
    1080     uint32_t uFectlReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FECTL_REG);
    1081     if (!(uFectlReg & VTD_BF_FECTL_REG_IM_MASK))
    1082     {
    1083         /* Software has unmasked the interrupt, raise it. */
    1084         MSIMSG Msi;
    1085         Msi.Addr.au32[0] = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FEADDR_REG);
    1086         Msi.Addr.au32[1] = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FEUADDR_REG);
    1087         Msi.Data.u32     = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_FEDATA_REG);
    1088 
    1089         /** @todo Assert Msi.Addr is in the MSR_IA32_APICBASE_ADDR range and ensure on
    1090          *        FEADD_REG write it can't be anything else? */
    1091         pThisCC->CTX_SUFF(pIommuHlp)->pfnSendMsi(pDevIns, &Msi, 0 /* uTagSrc */);
    1092 
    1093         /* Clear interrupt pending bit. */
    1094         uFectlReg &= ~VTD_BF_FECTL_REG_IP_MASK;
    1095         dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_FECTL_REG, uFectlReg);
    1096     }
    1097     else
    1098     {
    1099         /* Interrupt is masked, set the interrupt pending bit. */
    1100         uFectlReg |= VTD_BF_FECTL_REG_IP_MASK;
    1101         dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_FECTL_REG, uFectlReg);
    1102     }
     1173    dmarEventRaiseInterrupt(pDevIns, DMAREVENTTYPE_FAULT);
    11031174}
    11041175
     
    11141185    PDMAR    pThis   = PDMDEVINS_2_DATA(pDevIns, PDMAR);
    11151186    PCDMARCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PCDMARCC);
    1116 
    11171187    DMAR_ASSERT_LOCK_IS_OWNER(pDevIns, pThisCC);
    11181188
    11191189    uint32_t const uIcsReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_ICS_REG);
    11201190    if (!(uIcsReg & VTD_BF_ICS_REG_IWC_MASK))
    1121     {
    1122         uint32_t uIectlReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IECTL_REG);
    1123         if (!(uIectlReg & VTD_BF_IECTL_REG_IM_MASK))
    1124         {
    1125             /* Software has unmasked the interrupt, raise it. */
    1126             MSIMSG Msi;
    1127             Msi.Addr.au32[0] = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEADDR_REG);
    1128             Msi.Addr.au32[1] = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEUADDR_REG);
    1129             Msi.Data.u32     = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IEDATA_REG);
    1130 
    1131             pThisCC->CTX_SUFF(pIommuHlp)->pfnSendMsi(pDevIns, &Msi, 0 /* uTagSrc */);
    1132 
    1133             /* Clear interrupt pending bit. */
    1134             uIectlReg &= ~VTD_BF_IECTL_REG_IP_MASK;
    1135             dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_IECTL_REG, uIectlReg);
    1136         }
    1137         else
    1138         {
    1139             /* Interrupt is masked, set the interrupt pending bit. */
    1140             uIectlReg |= VTD_BF_IECTL_REG_IP_MASK;
    1141             dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_IECTL_REG, uIectlReg);
    1142         }
    1143     }
     1191        dmarEventRaiseInterrupt(pDevIns, DMAREVENTTYPE_INV_COMPLETE);
    11441192}
    11451193#endif /* IN_RING3 */
     
    15111559                                             uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)
    15121560{
    1513     RT_NOREF7(pDevIns, idDevice, uIova, cbIova, fFlags, pGCPhysSpa, pcbContiguous);
     1561    RT_NOREF6(idDevice, uIova, cbIova, fFlags, pGCPhysSpa, pcbContiguous);
     1562
     1563    PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     1564    if (fFlags & PDMIOMMU_MEM_F_READ)
     1565        STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMemRead));
     1566    else
     1567        STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMemWrite));
     1568
    15141569    return VERR_NOT_IMPLEMENTED;
    15151570}
     
    15911646static int dmarIrRemapIntr(PPDMDEVINS pDevIns, uint64_t uIrtaReg, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)
    15921647{
    1593     Assert(VTD_MSI_ADDR_GET_INTR_FORMAT(pMsiIn->Addr.u64) == VTD_INTR_FORMAT_REMAPPABLE);
     1648    Assert(pMsiIn->Addr.dmar_remap.fIntrFormat == VTD_INTR_FORMAT_REMAPPABLE);
    15941649
    15951650    /* Validate reserved bits in the interrupt request. */
     
    17351790    {
    17361791        /* Handle compatibility format interrupts. */
    1737         bool const fIsRemapFormat = RT_BF_GET(pMsiIn->Addr.au32[0], VTD_BF_REMAPPABLE_MSI_ADDR_INTR_FMT);
    1738         if (!fIsRemapFormat)
     1792        bool const fIsRemappable = RT_BF_GET(pMsiIn->Addr.au32[0], VTD_BF_REMAPPABLE_MSI_ADDR_INTR_FMT);
     1793        if (!fIsRemappable)
    17391794        {
    17401795            STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatMsiRemapCfi));
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