VirtualBox

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


Ignore:
Timestamp:
Apr 9, 2021 10:14:43 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

    r88417 r88427  
    9494/** DMAR implementation's major version number (exposed to software). */
    9595#define DMAR_VER_MAJOR                              1
    96 /** Number of domains supported (0=16, 1=64, 2=256, 3=1024, 4=4K, 5=16K, 6=64K,
    97  *  7=(Reserved). */
    98 #define DMAR_CAP_ND                                 2
    99 /** Large page support level (0=2M, 1=1GB pages). */
    100 #define DMAR_CAP_LARGE_PAGE_LVL                     0
    101 /** Maximum address mask value (9 for 2M, 18 for 1G). */
    102 #define DMAR_CAP_MAMV                               (X86_PAGE_2M_SHIFT - X86_PAGE_4K_SHIFT)
    103 /** Maximum handle mask value (must be 0 to 0xf). */
    104 #define DMAR_ECAP_MHMV                              0xf
    10596/** @} */
    10697
     
    127118    IOMMMIOHANDLE               hMmio;
    128119
    129     /** DMAR registers (group 0). */
     120    /** Registers (group 0). */
    130121    uint8_t                     abRegs0[DMAR_MMIO_GROUP_0_SIZE];
    131     /** DMAR registers (group 1). */
     122    /** Registers (group 1). */
    132123    uint8_t                     abRegs1[DMAR_MMIO_GROUP_1_SIZE];
     124
     125    /** @name Register copies for a tiny bit faster and more convenient access.
     126     *  @{ */
     127    /** Copy of CAP_REG. */
     128    uint64_t                    fCap;
     129    /** Copy of ECAP_REG. */
     130    uint64_t                    fExtCap;
     131    /** @} */
    133132
    134133#ifdef VBOX_WITH_STATISTICS
     
    458457static uint8_t vtdGetSupGstAddrBits(uint8_t uSagaw)
    459458{
    460     if (uSagaw > 0 && uSagaw < 4)
     459    if (RT_LIKELY(uSagaw > 0 && uSagaw < 4))
    461460        return 30 + (uSagaw * 9);
     461    return 0;
     462}
     463
     464
     465/**
     466 * Gets the supported adjusted guest-address width (SAGAW) given the maximum guest
     467 * address width (MGAW).
     468 *
     469 * @returns The CAP.SAGAW value.
     470 * @param   uMgaw  The CAP_REG.MGAW value.
     471 */
     472static uint8_t vtdGetSupGstAddrWidth(uint8_t uMgaw)
     473{
     474    switch (uMgaw + 1)
     475    {
     476        case 39:    return 1;
     477        case 48:    return 2;
     478        case 57:    return 3;
     479    }
    462480    return 0;
    463481}
     
    779797#ifdef IN_RING3
    780798/**
    781  * Initializes registers in the DMAR unit that are constant through the lifetime of
    782  * the VM (immutable by software and not mutated by hardware once initialized).
     799 * Initializes all registers in the DMAR unit.
    783800 *
    784801 * @param   pDevIns     The IOMMU device instance.
    785802 */
    786 static void dmarR3RegsInitImmutable(PPDMDEVINS pDevIns)
     803static void dmarR3RegsInit(PPDMDEVINS pDevIns)
    787804{
    788805    PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
     806    RT_ZERO(pThis->abRegs0);
     807    RT_ZERO(pThis->abRegs1);
     808
     809    /*
     810     * Initialize registers not mutable by software prior to initializing other registers.
     811     */
    789812    /* VER_REG */
    790813    {
     
    793816        dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_VER_REG, uVer);
    794817    }
     818
     819    uint8_t const fFlts  = 1;                    /* First-Level translation support. */
     820    uint8_t const fSlts  = 1;                    /* Second-Level translation support. */
     821    uint8_t const fPt    = 1;                    /* Pass-Through support. */
     822    uint8_t const fNest  = 0;                    /* Nested translation support. */
     823    uint8_t const fSmts  = fFlts & fSlts & fPt;  /* Scalable mode translation support.*/
     824
    795825    /* CAP_REG */
    796826    {
     827        uint8_t const fFl1gp = 1;                               /* First-Level 1GB pages support. */
     828        uint8_t const fFl5lp = 1;                               /* First-level 5-level paging support (PML5E). */
     829        uint8_t const fSl2mp = fSlts & 1;                       /* Second-Level 2MB pages support. */
     830        uint8_t const fSl2gp = fSlts & 1;                       /* Second-Level 1GB pages support. */
     831        uint8_t const fSllps = fSl2mp                           /* Second-Level large page Support. */
     832                             | ((fSl2mp & fFl1gp) & RT_BIT(1));
     833        uint8_t const fMamv  = (fSl2gp ?                        /* Maximum address mask value (for second-level invalidations). */
     834                                X86_PAGE_1G_SHIFT : X86_PAGE_2M_SHIFT) - X86_PAGE_4K_SHIFT;
     835        uint8_t const fNd    = 2;                               /* Number of domains (0=16, 1=64, 2=256, 3=1K, 4=4K, 5=16K, 6=64K,
     836                                                                   7=Reserved). */
     837        uint8_t const fPsi   = 1;                               /* Page selective invalidation. */
    797838        uint8_t cGstPhysAddrBits;
    798839        uint8_t cGstLinearAddrBits;
    799840        PDMDevHlpCpuGetGuestAddrWidths(pDevIns, &cGstPhysAddrBits, &cGstLinearAddrBits);
    800841        NOREF(cGstLinearAddrBits);
    801         uint64_t const uCap = RT_BF_MAKE(VTD_BF_CAP_REG_ND,     DMAR_CAP_ND)
    802                             | RT_BF_MAKE(VTD_BF_CAP_REG_AFL,    0)  /* Advanced Fault Logging not supported. */
    803                             | RT_BF_MAKE(VTD_BF_CAP_REG_RWBF,   0)  /* Software need not flush write-buffers. */
    804                             | RT_BF_MAKE(VTD_BF_CAP_REG_PLMR,   0)  /* Protected Low-Memory Region not supported. */
    805                             | RT_BF_MAKE(VTD_BF_CAP_REG_PHMR,   0)  /* Protected High-Memory Region not supported. */
    806                             | RT_BF_MAKE(VTD_BF_CAP_REG_CM,     1)  /** @todo Figure out if required when we impl. caching. */
    807                             | RT_BF_MAKE(VTD_BF_CAP_REG_SAGAW,  0)  /* 0 as Second-level Translation not supported. */
    808                             | RT_BF_MAKE(VTD_BF_CAP_REG_MGAW,   cGstPhysAddrBits - 1)
    809                             | RT_BF_MAKE(VTD_BF_CAP_REG_ZLR,    1)  /** @todo Zero-length read? */
    810                             | RT_BF_MAKE(VTD_BF_CAP_REG_FRO,    DMAR_MMIO_OFF_FRCD_LO_REG >> 4)
    811                             | RT_BF_MAKE(VTD_BF_CAP_REG_SLLPS,  DMAR_CAP_LARGE_PAGE_LVL)
    812                             | RT_BF_MAKE(VTD_BF_CAP_REG_PSI,    1)
    813                             | RT_BF_MAKE(VTD_BF_CAP_REG_NFR,    DMAR_FRCD_REG_COUNT - 1)
    814                             | RT_BF_MAKE(VTD_BF_CAP_REG_MAMV,   DMAR_CAP_MAMV)
    815                             | RT_BF_MAKE(VTD_BF_CAP_REG_DWD,    1)
    816                             | RT_BF_MAKE(VTD_BF_CAP_REG_FL1GP,  0)  /* 0 as First-level Translation not supported. */
    817                             | RT_BF_MAKE(VTD_BF_CAP_REG_PI,     0)  /* Posted Interrupts not supported. */
    818                             | RT_BF_MAKE(VTD_BF_CAP_REG_FL5LP,  0); /* 0 as First-level Translation not supported. */
    819         dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_CAP_REG, uCap);
     842        uint8_t const uMgaw  = cGstPhysAddrBits - 1;            /* Maximum guest address width. */
     843        uint8_t const uSagaw = vtdGetSupGstAddrWidth(uMgaw);    /* Supported adjust guest address width. */
     844
     845        pThis->fCap = RT_BF_MAKE(VTD_BF_CAP_REG_ND,     fNd)
     846                    | RT_BF_MAKE(VTD_BF_CAP_REG_AFL,    0)      /* Advanced fault logging not supported. */
     847                    | RT_BF_MAKE(VTD_BF_CAP_REG_RWBF,   0)      /* Software need not flush write-buffers. */
     848                    | RT_BF_MAKE(VTD_BF_CAP_REG_PLMR,   0)      /* Protected Low-Memory Region not supported. */
     849                    | RT_BF_MAKE(VTD_BF_CAP_REG_PHMR,   0)      /* Protected High-Memory Region not supported. */
     850                    | RT_BF_MAKE(VTD_BF_CAP_REG_CM,     1)      /** @todo Figure out if required when we impl. caching. */
     851                    | RT_BF_MAKE(VTD_BF_CAP_REG_SAGAW,  fSlts & uSagaw)
     852                    | RT_BF_MAKE(VTD_BF_CAP_REG_MGAW,   uMgaw)
     853                    | RT_BF_MAKE(VTD_BF_CAP_REG_ZLR,    1)      /** @todo Figure out if/how to support zero-length reads. */
     854                    | RT_BF_MAKE(VTD_BF_CAP_REG_FRO,    DMAR_MMIO_OFF_FRCD_LO_REG >> 4)
     855                    | RT_BF_MAKE(VTD_BF_CAP_REG_SLLPS,  fSlts & fSllps)
     856                    | RT_BF_MAKE(VTD_BF_CAP_REG_PSI,    fPsi)
     857                    | RT_BF_MAKE(VTD_BF_CAP_REG_NFR,    DMAR_FRCD_REG_COUNT - 1)
     858                    | RT_BF_MAKE(VTD_BF_CAP_REG_MAMV,   fPsi & fMamv)
     859                    | RT_BF_MAKE(VTD_BF_CAP_REG_DWD,    1)
     860                    | RT_BF_MAKE(VTD_BF_CAP_REG_FL1GP,  fFlts & fFl1gp)
     861                    | RT_BF_MAKE(VTD_BF_CAP_REG_PI,     0)      /* Posted Interrupts not supported. */
     862                    | RT_BF_MAKE(VTD_BF_CAP_REG_FL5LP,  fFlts & fFl5lp);
     863        dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_CAP_REG, pThis->fCap);
    820864    }
     865
    821866    /* ECAP_REG */
    822867    {
    823         uint64_t const uCap = RT_BF_MAKE(VTD_BF_ECAP_REG_C,      0)  /* Accesses don't snoop CPU cache. */
    824                             | RT_BF_MAKE(VTD_BF_ECAP_REG_QI,     1)
    825                             | RT_BF_MAKE(VTD_BF_ECAP_REG_DT,     0)  /* Device-TLBs not supported. */
    826                             | RT_BF_MAKE(VTD_BF_ECAP_REG_IR,     1)
    827                             | RT_BF_MAKE(VTD_BF_ECAP_REG_EIM,    0)  /* Extended Interrupt Mode (32-bit APIC ID) not supported. */
    828                             | RT_BF_MAKE(VTD_BF_ECAP_REG_PT,     1)
    829                             | RT_BF_MAKE(VTD_BF_ECAP_REG_SC,     0)  /* Snoop Control not supported. */
    830                             | RT_BF_MAKE(VTD_BF_ECAP_REG_IRO,    DMAR_MMIO_OFF_IVA_REG >> 4)
    831                             | RT_BF_MAKE(VTD_BF_ECAP_REG_MHMV,   DMAR_ECAP_MHMV)
    832                             | RT_BF_MAKE(VTD_BF_ECAP_REG_MTS,    0)  /* Memory Type not supported. */
    833                             | RT_BF_MAKE(VTD_BF_ECAP_REG_NEST,   0)  /* Nested Translation not supported. */
    834                             | RT_BF_MAKE(VTD_BF_ECAP_REG_PRS,    0)  /* Page Request not supported. */
    835                             | RT_BF_MAKE(VTD_BF_ECAP_REG_ERS,    0)  /* Execute Request not supported. */
    836                             | RT_BF_MAKE(VTD_BF_ECAP_REG_SRS,    0)  /* Supervisor Request not supported. */
    837                             | RT_BF_MAKE(VTD_BF_ECAP_REG_SRS,    0)  /* Supervisor Request not supported. */
    838                             | RT_BF_MAKE(VTD_BF_ECAP_REG_NWFS,   0)  /* 0 as DT not supported. */
    839                             | RT_BF_MAKE(VTD_BF_ECAP_REG_EAFS,   0)  /* 0 as SMTS not supported. */
    840                             | RT_BF_MAKE(VTD_BF_ECAP_REG_PSS,    0)  /* 0 as SMTS not supported. */
    841                             | RT_BF_MAKE(VTD_BF_ECAP_REG_PASID,  0)  /* 0 as SMTS not supported. */
    842                             | RT_BF_MAKE(VTD_BF_ECAP_REG_DIT,    0)  /* 0 as DT not supported. */
    843                             | RT_BF_MAKE(VTD_BF_ECAP_REG_PDS,    0)  /* 0 as DT not supported. */
    844                             | RT_BF_MAKE(VTD_BF_ECAP_REG_SMTS,   0)  /** @todo SMTS? Figure out if we can do this or requires PASID? */
    845                             | RT_BF_MAKE(VTD_BF_ECAP_REG_VCS,    0)  /* 0 as PASID not supported. */
    846                             | RT_BF_MAKE(VTD_BF_ECAP_REG_SLADS,  0)  /* 0 as SMTS not supported. */
    847                             | RT_BF_MAKE(VTD_BF_ECAP_REG_SLTS,   0)  /** @todo SLTS? Figure out if we can do this */
    848                             | RT_BF_MAKE(VTD_BF_ECAP_REG_FLTS,   0)  /** @todo FLTS? Figure out if we can do this */
    849                             | RT_BF_MAKE(VTD_BF_ECAP_REG_SMPWCS, 0)  /* 0 as SMTS not supported. */
    850                             | RT_BF_MAKE(VTD_BF_ECAP_REG_RPS,    0); /* 0 as SMTS not supported. */
    851         dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_ECAP_REG, uCap);
     868        uint8_t const  fIr     = 1;                             /* Interrupt remapping support. */
     869        uint8_t const  fMhmv   = 0xf;                           /* Maximum handle mask value. */
     870        uint16_t const offIro  = DMAR_MMIO_OFF_IVA_REG >> 4;    /* MMIO offset of IOTLB registers. */
     871        uint8_t const  fSrs    = 1;                             /* Supervisor request support. */
     872        uint8_t const  fEim    = 1;                             /* Extended interrupt mode.*/
     873
     874        pThis->fExtCap = RT_BF_MAKE(VTD_BF_ECAP_REG_C,      0)  /* Accesses don't snoop CPU cache. */
     875                       | RT_BF_MAKE(VTD_BF_ECAP_REG_QI,     1)
     876                       | RT_BF_MAKE(VTD_BF_ECAP_REG_DT,     0)  /* Device-TLBs not supported. */
     877                       | RT_BF_MAKE(VTD_BF_ECAP_REG_IR,     fIr)
     878                       | RT_BF_MAKE(VTD_BF_ECAP_REG_EIM,    fIr & fEim)
     879                       | RT_BF_MAKE(VTD_BF_ECAP_REG_PT,     fPt)
     880                       | RT_BF_MAKE(VTD_BF_ECAP_REG_SC,     0)  /* Snoop control not supported. */
     881                       | RT_BF_MAKE(VTD_BF_ECAP_REG_IRO,    offIro)
     882                       | RT_BF_MAKE(VTD_BF_ECAP_REG_MHMV,   fIr & fMhmv)
     883                       | RT_BF_MAKE(VTD_BF_ECAP_REG_MTS,    0)  /* Memory type not supported. */
     884                       | RT_BF_MAKE(VTD_BF_ECAP_REG_NEST,   fNest)
     885                       | RT_BF_MAKE(VTD_BF_ECAP_REG_PRS,    0)  /* 0 as DT not supported. */
     886                       | RT_BF_MAKE(VTD_BF_ECAP_REG_ERS,    0)  /* Execute request not supported. */
     887                       | RT_BF_MAKE(VTD_BF_ECAP_REG_SRS,    fSmts & fSrs)
     888                       | RT_BF_MAKE(VTD_BF_ECAP_REG_NWFS,   0)  /* 0 as DT not supported. */
     889                       | RT_BF_MAKE(VTD_BF_ECAP_REG_EAFS,   0)  /* 0 as PASID not supported. */
     890                       | RT_BF_MAKE(VTD_BF_ECAP_REG_PSS,    0)  /* 0 as PASID not supported. */
     891                       | RT_BF_MAKE(VTD_BF_ECAP_REG_PASID,  0)  /* PASID support. */
     892                       | RT_BF_MAKE(VTD_BF_ECAP_REG_DIT,    0)  /* 0 as DT not supported. */
     893                       | RT_BF_MAKE(VTD_BF_ECAP_REG_PDS,    0)  /* 0 as DT not supported. */
     894                       | RT_BF_MAKE(VTD_BF_ECAP_REG_SMTS,   fSmts)
     895                       | RT_BF_MAKE(VTD_BF_ECAP_REG_VCS,    0)  /* 0 as PASID not supported (commands seem PASID specific). */
     896                       | RT_BF_MAKE(VTD_BF_ECAP_REG_SLADS,  0)  /* Second-level accessed/dirty not supported. */
     897                       | RT_BF_MAKE(VTD_BF_ECAP_REG_SLTS,   fSlts)
     898                       | RT_BF_MAKE(VTD_BF_ECAP_REG_FLTS,   fFlts)
     899                       | RT_BF_MAKE(VTD_BF_ECAP_REG_SMPWCS, 0)  /* 0 as PASID not supported. */
     900                       | RT_BF_MAKE(VTD_BF_ECAP_REG_RPS,    0); /* 0 as PASID not supported. */
     901        dmarRegWriteRaw64(pThis, VTD_MMIO_OFF_ECAP_REG, pThis->fExtCap);
    852902    }
    853 }
    854 
    855 
    856 /**
    857  * Initializes all registers in the DMAR unit.
    858  *
    859  * @param   pDevIns     The IOMMU device instance.
    860  */
    861 static void dmarR3RegsInit(PPDMDEVINS pDevIns)
    862 {
    863     PDMAR pThis = PDMDEVINS_2_DATA(pDevIns, PDMAR);
    864     RT_ZERO(pThis->abRegs0);
    865     RT_ZERO(pThis->abRegs1);
    866 
    867     /* Initialize immutable registers prior to other registers. */
    868     dmarR3RegsInitImmutable(pDevIns);
    869 
     903
     904    /*
     905     * Initialize registers mutable by software.
     906     */
    870907    /* FECTL_REG */
    871908    {
     
    873910        dmarRegWriteRaw32(pThis, VTD_MMIO_OFF_FECTL_REG, uCtl);
    874911    }
     912
    875913    /* ICETL_REG */
    876914    {
     
    894932    RT_NOREF1(pDevIns);
    895933    LogFlowFunc(("\n"));
     934
     935    dmarR3RegsInit(pDevIns);
    896936}
    897937
     
    9941034    AssertRCReturn(rc, rc);
    9951035
    996 # ifdef VBOX_WITH_STATISTICS
     1036#ifdef VBOX_WITH_STATISTICS
    9971037    /*
    9981038     * Statistics.
     
    10181058    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemBulkWriteR3, STAMTYPE_COUNTER, "R3/MemBulkWrite", STAMUNIT_OCCURENCES, "Number of memory bulk write translation requests in R3.");
    10191059    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatMemBulkWriteRZ, STAMTYPE_COUNTER, "RZ/MemBulkWrite", STAMUNIT_OCCURENCES, "Number of memory bulk write translation requests in RZ.");
    1020 # endif
     1060#endif
    10211061
    10221062    /*
    1023      * Initialize all DMAR registers (order is important).
     1063     * Initialize registers.
    10241064     */
    10251065    dmarR3RegsInit(pDevIns);
    10261066
    1027     uint64_t const fCap     = dmarRegRead64(pThis, VTD_MMIO_OFF_CAP_REG);
    1028     uint64_t const fExtCap  = dmarRegRead64(pThis, VTD_MMIO_OFF_ECAP_REG);
    1029     uint8_t const  uMaxGstAddrBits = RT_BF_GET(fCap, VTD_BF_CAP_REG_MGAW) + 1;
    1030     uint8_t const  uSupGstAddrBits = vtdGetSupGstAddrBits(RT_BF_GET(fCap, VTD_BF_CAP_REG_SAGAW));
    1031     LogRel(("%s: CAP=%#RX64 ECAP=%#RX64 (MGAW=%u bits, SAGAW=%u bits)\n", DMAR_LOG_PFX, fCap, fExtCap, uMaxGstAddrBits,
    1032             uSupGstAddrBits));
     1067    uint8_t const cMaxGstAddrBits = RT_BF_GET(pThis->fCap, VTD_BF_CAP_REG_MGAW) + 1;
     1068    uint8_t const cSupGstAddrBits = vtdGetSupGstAddrBits(RT_BF_GET(pThis->fCap, VTD_BF_CAP_REG_SAGAW));
     1069    LogRel(("%s: CAP=%#RX64 ECAP=%#RX64 (MGAW=%u bits, SAGAW=%u bits)\n", DMAR_LOG_PFX, pThis->fCap, pThis->fExtCap,
     1070            cMaxGstAddrBits, cSupGstAddrBits));
    10331071    return VINF_SUCCESS;
    10341072}
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