VirtualBox

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


Ignore:
Timestamp:
Apr 26, 2021 3:26:56 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

    r88697 r88704  
    2424#include "DevIommuIntel.h"
    2525
     26#include <iprt/mem.h>
    2627#include <iprt/string.h>
    2728
     
    143144    kDmarDiag_None = 0,
    144145    kDmarDiag_IqtReg_Qt_NotAligned,
     146    kDmarDiag_IqtReg_Qt_Invalid,
    145147    kDmarDiag_IqaReg_Dw_Invalid,
     148    kDmarDiag_IqaReg_Dsc_Fetch_Failed,
    146149    kDmarDiag_CcmdReg_Ttm_Invalid,
    147150    kDmarDiag_CcmdReg_Qi_Enabled,
     
    158161static const char *const g_apszDmarDiagDesc[] =
    159162{
    160     DMARDIAG_DESC(kNone                         ,   "None"                ),
    161     DMARDIAG_DESC(kDmarDiag_IqtReg_Qt_NotAligned,   "IqtReg_Qt_NotAligned"),
    162     DMARDIAG_DESC(kDmarDiag_IqaReg_Dw_Invalid   ,   "IqaReg_Dw_Invalid"   ),
    163     DMARDIAG_DESC(kDmarDiag_CcmdReg_Ttm_Invalid ,   "CcmdReg_Ttm_Invalid" ),
    164     DMARDIAG_DESC(kDmarDiag_CcmdReg_Qi_Enabled  ,   "CcmdReg_Qi_Enabled"  ),
    165     DMARDIAG_DESC(kDmarDiag_CcmdReg_NotSupported,   "CcmdReg_NotSupported")
     163    DMARDIAG_DESC(kNone                            ,    "None"                  ),
     164    DMARDIAG_DESC(kDmarDiag_IqtReg_Qt_NotAligned   ,    "IqtReg_Qt_NotAligned"  ),
     165    DMARDIAG_DESC(kDmarDiag_IqtReg_Qt_Invalid      ,    "IqtReg_Qt_Invalid"     ),
     166    DMARDIAG_DESC(kDmarDiag_IqaReg_Dw_Invalid      ,    "IqaReg_Dw_Invalid"     ),
     167    DMARDIAG_DESC(kDmarDiag_IqaReg_Dsc_Fetch_Failed,    "IqaReg_Dsc_Fetch_Failed"),
     168    DMARDIAG_DESC(kDmarDiag_CcmdReg_Ttm_Invalid    ,    "CcmdReg_Ttm_Invalid"   ),
     169    DMARDIAG_DESC(kDmarDiag_CcmdReg_Qi_Enabled     ,    "CcmdReg_Qi_Enabled"    ),
     170    DMARDIAG_DESC(kDmarDiag_CcmdReg_NotSupported   ,    "CcmdReg_NotSupported"  )
    166171    /* kDmarDiag_End */
    167172};
     
    863868 * Checks if the invalidation-queue is empty.
    864869 *
     870 * Extended version which optionally returns the current queue head and tail
     871 * offsets.
     872 *
    865873 * @returns @c true if empty, @c false otherwise.
    866874 * @param   pThis   The shared DMAR device state.
    867  */
    868 static bool dmarInvQueueIsEmpty(PCDMAR pThis)
    869 {
    870     uint64_t const uIqtReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IQT_REG);
    871     uint64_t const uIqhReg = dmarRegReadRaw64(pThis, VTD_MMIO_OFF_IQH_REG);
    872     /* Don't bother masking out QT, QH out of IQT_REG, IQH_REG since all other bits are RsvdZ. */
     875 * @param   poffQh  Where to store the queue head offset. Optional, can be NULL.
     876 * @param   poffQt  Where to store the queue tail offset. Optional, can be NULL.
     877 */
     878static bool dmarInvQueueIsEmptyEx(PCDMAR pThis, uint32_t *poffQh, uint32_t *poffQt)
     879{
     880    /* Read only the low-32 bits of the queue head and queue tail registers as high bits are all reserved.*/
     881    uint32_t const uIqtReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IQT_REG);
     882    uint32_t const uIqhReg = dmarRegReadRaw32(pThis, VTD_MMIO_OFF_IQH_REG);
     883
     884    /* Don't bother masking QT, QH out of IQT_REG, IQH_REG since all other bits are RsvdZ. */
    873885    Assert(!(uIqtReg & ~VTD_BF_IQT_REG_QT_MASK));
    874886    Assert(!(uIqhReg & ~VTD_BF_IQH_REG_QH_MASK));
     887    if (poffQh)
     888        *poffQh = uIqhReg;
     889    if (poffQt)
     890        *poffQt = uIqtReg;
    875891    return uIqtReg == uIqhReg;
     892}
     893
     894
     895/**
     896 * Checks if the invalidation-queue is empty.
     897 *
     898 * @returns @c true if empty, @c false otherwise.
     899 * @param   pThis   The shared DMAR device state.
     900 */
     901static bool dmarInvQueueIsEmpty(PCDMAR pThis)
     902{
     903    return dmarInvQueueIsEmptyEx(pThis, NULL /* poffQh */,  NULL /* poffQt */);
    876904}
    877905
     
    10161044 * @param   enmDiag     The diagnostic reason.
    10171045 */
    1018 static void dmarIqeFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTD_IQERCD_IQEI_T enmIqei)
     1046static void dmarIqeFaultRecord(PPDMDEVINS pDevIns, DMARDIAG enmDiag, VTD_IQEI_T enmIqei)
    10191047{
    10201048    PDMAR    pThis   = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     
    11491177        /* Hardware treats bit 4 as RsvdZ in this situation, so clear it. */
    11501178        dmarRegChangeRaw32(pThis, offReg, ~RT_BIT(4) /* fAndMask*/ , 0 /* fOrMask */);
    1151         dmarIqeFaultRecord(pDevIns, kDmarDiag_IqtReg_Qt_NotAligned, kQueueTailNotAligned);
     1179        dmarIqeFaultRecord(pDevIns, kDmarDiag_IqtReg_Qt_NotAligned, kIqei_QueueTailNotAligned);
    11521180    }
    11531181    return VINF_SUCCESS;
     
    11801208        { /* likely */ }
    11811209        else
    1182             dmarIqeFaultRecord(pDevIns, kDmarDiag_IqaReg_Dw_Invalid, kInvalidDescriptorWidth);
     1210            dmarIqeFaultRecord(pDevIns, kDmarDiag_IqaReg_Dw_Invalid, kIqei_InvalidDescriptorWidth);
    11831211    }
    11841212    return VINF_SUCCESS;
     
    13611389    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    13621390        return VINF_SUCCESS;
     1391
     1392    uint8_t const  cMaxPages = 1 << VTD_BF_IQA_REG_QS_MASK;
     1393    size_t const   cbMaxQs   = cMaxPages << X86_PAGE_SHIFT;
     1394    void *pvQueue = RTMemAllocZ(cbMaxQs);
     1395    AssertPtrReturn(pvQueue, VERR_NO_MEMORY);
    13631396
    13641397    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     
    13831416        if (dmarInvQueueCanProcessRequests(pThis))
    13841417        {
    1385             /** @todo Read IQH and IQT, descriptors from memory and perform invalidation. */
     1418            uint32_t offQueueHead;
     1419            uint32_t offQueueTail;
     1420            bool const fIsEmpty = dmarInvQueueIsEmptyEx(pThis, &offQueueHead, &offQueueTail);
     1421            if (!fIsEmpty)
     1422            {
     1423                uint64_t const uIqaReg      = dmarRegRead64(pThis, VTD_MMIO_OFF_IQA_REG);
     1424                uint8_t const  cQueuePages  = 1 << (uIqaReg & VTD_BF_IQA_REG_QS_MASK);
     1425                uint32_t const cbQueue      = cQueuePages << X86_PAGE_SHIFT;
     1426                if (offQueueTail <= cbQueue)
     1427                {
     1428                    uint32_t const cbDescriptors = offQueueTail - offQueueHead;
     1429                    RTGCPHYS const GCPhysQueueBase = uIqaReg & VTD_BF_IQA_REG_IQA_MASK;
     1430
     1431                    DMAR_UNLOCK(pDevIns, pThisR3);
     1432                    int rc = PDMDevHlpPhysRead(pDevIns, GCPhysQueueBase, pvQueue, cbDescriptors);
     1433                    DMAR_LOCK(pDevIns, pThisR3);
     1434
     1435                    if (RT_SUCCESS(rc))
     1436                    {
     1437                        /** @todo Handle RTADDR_REG MMIO write first, for handling kIqei_InvalidTtm. I
     1438                         *        don't think it needs to be checked/handled here? */
     1439                        /** @todo Process invalidation descriptors. */
     1440                    }
     1441                    else
     1442                        dmarIqeFaultRecord(pDevIns, kDmarDiag_IqaReg_Dsc_Fetch_Failed, kIqei_FetchDescriptorFailed);
     1443                }
     1444                else
     1445                    dmarIqeFaultRecord(pDevIns, kDmarDiag_IqtReg_Qt_Invalid, kIqei_InvalidTailPointer);
     1446            }
    13861447        }
    13871448        DMAR_UNLOCK(pDevIns, pThisR3);
    13881449    }
     1450
     1451    RTMemFree(pvQueue);
     1452    pvQueue = NULL;
    13891453
    13901454    LogFlowFunc(("Invalidation-queue thread terminating\n"));
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