VirtualBox

Changeset 47786 in vbox


Ignore:
Timestamp:
Aug 16, 2013 8:59:32 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
88047
Message:

PGM: Added a new page type for the VT-x APIC access page MMIO alias instead of abusing the MMIO2 aliasing. There are important differences, we can safely access the MMIO2 page when aliased and save time doing so, while the alias created by IOMMMIOMapMMIOHCPage must not be accessed outside the VT-x execution AFAIK.

Location:
trunk/src/VBox/VMM
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp

    r47719 r47786  
    424424void pgmHandlerPhysicalResetAliasedPage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhysPage, bool fDoAccounting)
    425425{
    426     Assert(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO);
     426    Assert(   PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
     427           || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO);
    427428    Assert(PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
    428429
     
    495496        if (RT_SUCCESS(rc))
    496497        {
    497             /* Reset MMIO2 for MMIO pages to MMIO, since this aliasing is our business.
     498            /* Reset aliased MMIO pages to MMIO, since this aliasing is our business.
    498499               (We don't flip MMIO to RAM though, that's PGMPhys.cpp's job.)  */
    499             if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO)
     500            if (   PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
     501                || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO)
    500502            {
    501503                Assert(pCur->cAliasedPages > 0);
     
    888890                        while (cLeft-- > 0)
    889891                        {
    890                             if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO)
     892                            if (   PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
     893                                || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO)
    891894                            {
    892895                                Assert(pCur->cAliasedPages > 0);
     
    11341137
    11351138/**
    1136  * Replaces an MMIO page with an arbitrary HC page.
    1137  *
    1138  * This is a worker for IOMMMIOMapMMIO2Page that works in a similar way to
    1139  * PGMHandlerPhysicalPageTempOff but for an MMIO page. Since an MMIO page has no
    1140  * backing, the caller must provide a replacement page. For various reasons the
    1141  * replacement page must be an MMIO2 page.
     1139 * Replaces an MMIO page with an arbitrary HC page in the shadow page tables.
     1140 *
     1141 * This differs from PGMHandlerPhysicalPageAlias in that the page doesn't need
     1142 * to be a known MMIO2 page and that only shadow paging may access the page.
     1143 * The latter distinction is important because the only use for this feature is
     1144 * for mapping the special APIC access page that VT-x uses to detect APIC MMIO
     1145 * operations, the page is shared between all guest CPUs and actually not
     1146 * written to. At least at the moment.
    11421147 *
    11431148 * The caller must do required page table modifications. You can get away
     
    11471152 * Call PGMHandlerPhysicalReset() to restore the MMIO page.
    11481153 *
    1149  * The caller may still get handler callback even after this call and must be
    1150  * able to deal correctly with such calls. The reason for these callbacks are
    1151  * either that we're executing in the recompiler (which doesn't know about this
    1152  * arrangement) or that we've been restored from saved state (where we won't
    1153  * save the change).
    11541154 *
    11551155 * @returns VBox status code.
     
    11941194            {
    11951195                pgmUnlock(pVM);
    1196                 AssertMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO,
     1196                AssertMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO,
    11971197                                ("GCPhysPage=%RGp %R[pgmpage]\n", GCPhysPage, pPage),
    11981198                                VERR_PGM_PHYS_NOT_MMIO2);
     
    12031203            /*
    12041204             * Do the actual remapping here.
    1205              * This page now serves as an alias for the backing memory specified.
     1205             * This page now serves as an alias for the backing memory
     1206             * specified as far as shadow paging is concerned.
    12061207             */
    12071208            LogFlow(("PGMHandlerPhysicalPageAlias: %RGp (%R[pgmpage]) alias for %RHp\n",
    12081209                     GCPhysPage, pPage, HCPhysPageRemap));
    12091210            PGM_PAGE_SET_HCPHYS(pVM, pPage, HCPhysPageRemap);
    1210             PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_MMIO2_ALIAS_MMIO);
     1211            PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_SPECIAL_ALIAS_MMIO);
    12111212            PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ALLOCATED);
    1212             /** @todo hack alert
    1213              *  This needs to be done properly. Currently we get away with it as the recompiler directly calls
    1214              *  IOM read and write functions. Access through PGMPhysRead/Write will crash the process.
    1215              */
    12161213            PGM_PAGE_SET_PAGEID(pVM, pPage, NIL_GMM_PAGEID);
    12171214            PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
  • trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp

    r47739 r47786  
    571571    PGM_LOCK_ASSERT_OWNER(pVM);
    572572    AssertMsg(PGM_PAGE_IS_ZERO(pPage) || PGM_PAGE_IS_SHARED(pPage), ("%R[pgmpage] %RGp\n", pPage, GCPhys));
    573     Assert(!PGM_PAGE_IS_MMIO(pPage));
     573    Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage));
    574574
    575575# ifdef PGM_WITH_LARGE_PAGES
     
    620620    PGM_LOCK_ASSERT_OWNER(pVM);
    621621    AssertMsg(PGM_PAGE_IS_ZERO(pPage) || PGM_PAGE_IS_SHARED(pPage), ("%R[pgmpage] %RGp\n", pPage, GCPhys));
    622     Assert(!PGM_PAGE_IS_MMIO(pPage));
     622    Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage));
    623623
    624624    uint32_t iHandyPage = --pVM->pgm.s.cHandyPages;
     
    10281028
    10291029    /*
    1030      * Special case: ZERO and MMIO2 pages.
    1031      */
     1030     * Special cases: MMIO2, ZERO and specially aliased MMIO pages.
     1031     */
     1032    if (   PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2
     1033        || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO)
     1034    {
     1035        /* Fend off the VT-x APIC access page hack. */
     1036        AssertLogRelReturn(PGM_PAGE_GET_PAGEID(pPage) == NIL_GMM_PAGEID, VERR_PGM_MAP_MMIO2_ALIAS_MMIO);
     1037
     1038        /* Decode the page id to a page in a MMIO2 ram range. */
     1039        uint8_t  idMmio2 = PGM_MMIO2_PAGEID_GET_MMIO2_ID(PGM_PAGE_GET_PAGEID(pPage));
     1040        uint32_t iPage   = PGM_MMIO2_PAGEID_GET_IDX(PGM_PAGE_GET_PAGEID(pPage));
     1041        AssertLogRelReturn((uint8_t)(idMmio2 - 1U)< RT_ELEMENTS(pVM->pgm.s.CTX_SUFF(apMmio2Ranges)),
     1042                            VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
     1043        PPGMMMIO2RANGE pMmio2Range = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[idMmio2 - 1];
     1044        AssertLogRelReturn(pMmio2Range, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
     1045        AssertLogRelReturn(pMmio2Range->idMmio2 == idMmio2, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
     1046        AssertLogRelReturn(iPage < (pMmio2Range->RamRange.cb >> PAGE_SHIFT), VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
     1047        *ppv = (uint8_t *)pMmio2Range->RamRange.pvR3 + ((uintptr_t)iPage << PAGE_SHIFT);
     1048        *ppMap = NULL;
     1049        return VINF_SUCCESS;
     1050    }
     1051
    10321052    const uint32_t idChunk = PGM_PAGE_GET_CHUNKID(pPage);
    10331053    if (idChunk == NIL_GMM_CHUNKID)
    10341054    {
    1035         AssertMsgReturn(PGM_PAGE_GET_PAGEID(pPage) == NIL_GMM_PAGEID, ("pPage=%R[pgmpage]\n", pPage), VERR_PGM_PHYS_PAGE_MAP_IPE_1);
    1036         if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2)
    1037         {
    1038             /* Lookup the MMIO2 range and use pvR3 to calc the address. */
    1039             PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
    1040             AssertMsgReturn(pRam || !pRam->pvR3, ("pRam=%p pPage=%R[pgmpage]\n", pRam, pPage), VERR_PGM_PHYS_PAGE_MAP_IPE_2);
    1041             *ppv = (void *)((uintptr_t)pRam->pvR3 + (uintptr_t)((GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK) - pRam->GCPhys));
    1042         }
    1043         else if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO)
    1044         {
    1045             /** @todo deal with aliased MMIO2 pages somehow...
    1046              * One solution would be to seed MMIO2 pages to GMM and get unique Page IDs for
    1047              * them, that would also avoid this mess. It would actually be kind of
    1048              * elegant... */
    1049             AssertLogRelMsgFailedReturn(("%RGp\n", GCPhys), VERR_PGM_MAP_MMIO2_ALIAS_MMIO);
    1050         }
    1051         else
    1052         {
    1053             /** @todo handle MMIO2 */
    1054             AssertMsgReturn(PGM_PAGE_IS_ZERO(pPage), ("pPage=%R[pgmpage]\n", pPage), VERR_PGM_PHYS_PAGE_MAP_IPE_3);
    1055             AssertMsgReturn(PGM_PAGE_GET_HCPHYS(pPage) == pVM->pgm.s.HCPhysZeroPg,
    1056                             ("pPage=%R[pgmpage]\n", pPage),
     1055        AssertMsgReturn(PGM_PAGE_GET_PAGEID(pPage) == NIL_GMM_PAGEID, ("pPage=%R[pgmpage]\n", pPage),
     1056                        VERR_PGM_PHYS_PAGE_MAP_IPE_1);
     1057        if (!PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
     1058        {
     1059            AssertMsgReturn(PGM_PAGE_IS_ZERO(pPage), ("pPage=%R[pgmpage]\n", pPage),
     1060                            VERR_PGM_PHYS_PAGE_MAP_IPE_3);
     1061            AssertMsgReturn(PGM_PAGE_GET_HCPHYS(pPage)== pVM->pgm.s.HCPhysZeroPg, ("pPage=%R[pgmpage]\n", pPage),
    10571062                            VERR_PGM_PHYS_PAGE_MAP_IPE_4);
    10581063            *ppv = pVM->pgm.s.CTXALLSUFF(pvZeroPg);
     1064        }
     1065        else
     1066        {
     1067            static uint8_t s_abPlayItSafe[0x1000*2];  /* I don't dare return the zero page at the moment. */
     1068            *ppv = (uint8_t *)((uintptr_t)&s_abPlayItSafe[0x1000] & ~(uintptr_t)0xfff);
    10591069        }
    10601070        *ppMap = NULL;
     
    16841694    if (RT_SUCCESS(rc))
    16851695    {
    1686         if (RT_UNLIKELY(PGM_PAGE_IS_MMIO(pPage)))
     1696        if (RT_UNLIKELY(PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage)))
    16871697            rc = VERR_PGM_PHYS_PAGE_RESERVED;
    16881698        else
     
    17161726        /* MMIO pages doesn't have any readable backing. */
    17171727        PPGMPAGE pPage = pTlbe->pPage;
    1718         if (RT_UNLIKELY(PGM_PAGE_IS_MMIO(pPage)))
     1728        if (RT_UNLIKELY(PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage)))
    17191729            rc = VERR_PGM_PHYS_PAGE_RESERVED;
    17201730        else
     
    20992109    PPGMPHYSHANDLER pPhys = NULL;
    21002110#endif
    2101     if (PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_ALL)
     2111    if (   PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_ALL
     2112        || PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
    21022113    {
    21032114#ifdef IN_RING3
     
    22362247                 * Any ALL access handlers?
    22372248                 */
    2238                 if (RT_UNLIKELY(PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)))
     2249                if (RT_UNLIKELY(   PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)
     2250                                || PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage)))
    22392251                {
    22402252                    int rc = pgmPhysReadHandler(pVM, pPage, pRam->GCPhys + off, pvBuf, cb);
     
    23352347     * the heavy usage of full page handlers in the page pool.
    23362348     */
    2337     if (    !PGM_PAGE_HAS_ACTIVE_VIRTUAL_HANDLERS(pPage)
    2338         ||  PGM_PAGE_IS_MMIO(pPage) /* screw virtual handlers on MMIO pages */)
     2349    if (   !PGM_PAGE_HAS_ACTIVE_VIRTUAL_HANDLERS(pPage)
     2350        || PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage) /* screw virtual handlers on MMIO pages */)
    23392351    {
    23402352        PPGMPHYSHANDLER pCur = pgmHandlerPhysicalLookup(pVM, GCPhys);
     
    23562368#else  /* IN_RING3 */
    23572369            Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cbRange, pPage, R3STRING(pCur->pszDesc) ));
    2358             if (!PGM_PAGE_IS_MMIO(pPage))
     2370            if (!PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
    23592371                rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &pvDst, &PgMpLck);
    23602372            else
     
    24042416        }
    24052417        /* else: the handler is somewhere else in the page, deal with it below. */
    2406         Assert(!PGM_PAGE_IS_MMIO(pPage)); /* MMIO handlers are all PAGE_SIZEed! */
     2418        Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)); /* MMIO handlers are all PAGE_SIZEed! */
    24072419    }
    24082420    /*
     
    27712783                 * Any active WRITE or ALL access handlers?
    27722784                 */
    2773                 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
     2785                if (   PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
     2786                    || PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
    27742787                {
    27752788                    int rc = pgmPhysWriteHandler(pVM, pPage, pRam->GCPhys + off, pvBuf, cb);
     
    40394052        if (PGM_PAGE_IS_BALLOONED(pPage))
    40404053            rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
     4054        else if (PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
     4055            rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
    40414056        else if (   !PGM_PAGE_HAS_ANY_HANDLERS(pPage)
    40424057                 || (fByPassHandlers && !PGM_PAGE_IS_MMIO(pPage)) )
     
    41514166        if (PGM_PAGE_IS_BALLOONED(pPage))
    41524167            rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
     4168        else if (PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
     4169            rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
    41534170        else if (   !PGM_PAGE_HAS_ANY_HANDLERS(pPage)
    41544171                 || (fByPassHandlers && !PGM_PAGE_IS_MMIO(pPage)) )
  • trunk/src/VBox/VMM/VMMR3/FTM.cpp

    r46788 r47786  
    717717
    718718    case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
     719    case PGMPAGETYPE_SPECIAL_ALIAS_MMIO:
    719720        AssertFailed();
    720721        break;
  • trunk/src/VBox/VMM/VMMR3/PGM.cpp

    r46420 r47786  
    39523952                    default:
    39533953                        AssertFailed();
     3954                    case PGMPAGETYPE_MMIO:
    39543955                    case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
    3955                     case PGMPAGETYPE_MMIO:
     3956                    case PGMPAGETYPE_SPECIAL_ALIAS_MMIO:
    39563957                        if (fIncZeroPgs)
    39573958                        {
  • trunk/src/VBox/VMM/VMMR3/PGMDbg.cpp

    r46220 r47786  
    661661                if (   (   !PGM_PAGE_IS_ZERO(pPage)
    662662                        || fAllZero)
    663                     && !PGM_PAGE_IS_MMIO(pPage)
    664                     && PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO2_ALIAS_MMIO
     663                    && !PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)
    665664                    && !PGM_PAGE_IS_BALLOONED(pPage))
    666665                {
     
    807806                && (   !PGM_PAGE_IS_ZERO(pPage)
    808807                    || fAllZero)
    809                 && !PGM_PAGE_IS_MMIO(pPage)
    810                 && PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO2_ALIAS_MMIO
     808                && !PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)
    811809                && !PGM_PAGE_IS_BALLOONED(pPage))
    812810            {
  • trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp

    r45618 r47786  
    144144                 * delegate the job to EMT.
    145145                 */
    146                 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
     146                if (   PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)
     147                    || PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
    147148                {
    148149                    pgmUnlock(pVM);
     
    151152                                                   pVM, &GCPhys, pvBuf, cbRead);
    152153                }
    153                 Assert(!PGM_PAGE_IS_MMIO(pPage));
     154                Assert(!PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage));
    154155
    155156                /*
     
    282283                 */
    283284                if (    PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
    284                     ||  PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
     285                    ||  PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
     286                    ||  PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
    285287                {
    286288                    if (    PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
     
    295297                    }
    296298                }
    297                 Assert(!PGM_PAGE_IS_MMIO(pPage));
     299                Assert(!PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage));
    298300
    299301                /*
     
    378380        AssertFatalRC(rc2);
    379381        PPGMPAGE pPage = pTlbe->pPage;
    380         if (PGM_PAGE_IS_MMIO(pPage))
     382        if (PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
    381383        {
    382384            PGMPhysReleasePageMappingLock(pVM, pLock);
     
    449451    {
    450452        PPGMPAGE pPage = pTlbe->pPage;
    451         if (PGM_PAGE_IS_MMIO(pPage))
     453        if (PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
    452454            rc = VERR_PGM_PHYS_PAGE_RESERVED;
    453455        else
     
    552554#if 1
    553555        /* MMIO pages doesn't have any readable backing. */
    554         if (PGM_PAGE_IS_MMIO(pPage))
     556        if (PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
    555557            rc = VERR_PGM_PHYS_PAGE_RESERVED;
    556558#else
     
    19791981
    19801982                    case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
     1983                    case PGMPAGETYPE_SPECIAL_ALIAS_MMIO: /** @todo perhaps leave the special page alone?  I don't think VT-x copes with this code. */
    19811984                        pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT),
    19821985                                                           true /*fDoAccounting*/);
     
    20322035
    20332036                    case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
     2037                    case PGMPAGETYPE_SPECIAL_ALIAS_MMIO: /** @todo perhaps leave the special page alone?  I don't think VT-x copes with this code. */
    20342038                        pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT),
    20352039                                                           true /*fDoAccounting*/);
     
    21272131
    21282132                case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
     2133                case PGMPAGETYPE_SPECIAL_ALIAS_MMIO:
    21292134                case PGMPAGETYPE_MMIO2:
    21302135                case PGMPAGETYPE_ROM_SHADOW: /* handled by pgmR3PhysRomReset. */
     
    21492154    return VINF_SUCCESS;
    21502155}
     2156
    21512157
    21522158/**
     
    23632369                {
    23642370                    PPGMPAGE    pPage    = &pRam->aPages[iPage];
    2365                     if (    PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO
     2371                    if (   !PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)
    23662372                        /*|| not-out-of-action later */)
    23672373                    {
    23682374                        fAllMMIO = false;
    2369                         Assert(PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO2_ALIAS_MMIO);
    23702375                        AssertMsgFailed(("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
    23712376                        break;
    23722377                    }
    2373                     Assert(PGM_PAGE_IS_ZERO(pPage));
     2378                    Assert(   PGM_PAGE_IS_ZERO(pPage)
     2379                           || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
     2380                           || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO);
    23742381                    pPage++;
    23752382                }
     
    24092416                {
    24102417                    PPGMPAGE pPage = &pRam->aPages[iPage];
    2411                     AssertMsg(PGM_PAGE_IS_MMIO(pPage), ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
    2412                     AssertMsg(PGM_PAGE_IS_ZERO(pPage), ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
    2413                     if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO)
     2418                    AssertMsg(   (PGM_PAGE_IS_MMIO(pPage) && PGM_PAGE_IS_ZERO(pPage))
     2419                              || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
     2420                              || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO,
     2421                              ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
     2422                    if (PGM_PAGE_IS_MMIO_OR_ALIAS(pPage))
    24142423                        PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_RAM);
    24152424                }
     
    24882497 * @param   pszDesc         The description.
    24892498 */
    2490 VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc)
     2499VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags,
     2500                                      void **ppv, const char *pszDesc)
    24912501{
    24922502    /*
     
    25062516    const uint32_t cPages = cb >> PAGE_SHIFT;
    25072517    AssertLogRelReturn(((RTGCPHYS)cPages << PAGE_SHIFT) == cb, VERR_INVALID_PARAMETER);
    2508     AssertLogRelReturn(cPages <= INT32_MAX / 2, VERR_NO_MEMORY);
     2518    AssertLogRelReturn(cPages <= PGM_MMIO2_MAX_PAGE_COUNT, VERR_NO_MEMORY);
    25092519
    25102520    /*
     
    25172527            return VERR_NO_MEMORY;
    25182528    }
     2529
     2530    /*
     2531     * Allocate an MMIO2 range ID (not freed on failure).
     2532     * The zero ID is not used as it could be confused with NIL_GMM_PAGEID.
     2533     */
     2534    pgmLock(pVM);
     2535    uint8_t idMmio2 = pVM->pgm.s.cMmio2Regions + 1;
     2536    if (idMmio2 > PGM_MMIO2_MAX_RANGES)
     2537    {
     2538        pgmUnlock(pVM);
     2539        AssertLogRelFailedReturn(VERR_PGM_TOO_MANY_MMIO2_RANGES);
     2540    }
     2541    pVM->pgm.s.cMmio2Regions = idMmio2;
     2542    pgmUnlock(pVM);
    25192543
    25202544    /*
     
    25492573                pNew->iRegion               = iRegion;
    25502574                pNew->idSavedState          = UINT8_MAX;
     2575                pNew->idMmio2               = idMmio2;
    25512576                pNew->RamRange.pSelfR0      = MMHyperCCToR0(pVM, &pNew->RamRange);
    25522577                pNew->RamRange.pSelfRC      = MMHyperCCToRC(pVM, &pNew->RamRange);
     
    25632588                {
    25642589                    PGM_PAGE_INIT(&pNew->RamRange.aPages[iPage],
    2565                                   paPages[iPage].Phys, NIL_GMM_PAGEID,
     2590                                  paPages[iPage].Phys,
     2591                                  PGM_MMIO2_PAGEID_MAKE(idMmio2, iPage),
    25662592                                  PGMPAGETYPE_MMIO2, PGM_PAGE_STATE_ALLOCATED);
    25672593                }
     
    25752601                 * Since there is no particular order, just push it.
    25762602                 */
     2603                /** @todo we can save us the linked list now, just search the lookup table... */
    25772604                pgmLock(pVM);
     2605                Assert(pVM->pgm.s.apMmio2RangesR3[idMmio2] == NULL);
     2606                Assert(pVM->pgm.s.apMmio2RangesR0[idMmio2] == NIL_RTR0PTR);
    25782607                pNew->pNextR3 = pVM->pgm.s.pMmio2RangesR3;
    25792608                pVM->pgm.s.pMmio2RangesR3 = pNew;
     2609                pVM->pgm.s.apMmio2RangesR3[idMmio2] = pNew;
     2610                pVM->pgm.s.apMmio2RangesR0[idMmio2] = MMHyperCCToR0(pVM, pNew);
    25802611                pgmUnlock(pVM);
    25812612
     
    26502681                pVM->pgm.s.pMmio2RangesR3 = pNext;
    26512682            pCur->pNextR3 = NULL;
     2683
     2684            uint8_t idMmio2 = pCur->idMmio2;
     2685            Assert(pVM->pgm.s.apMmio2RangesR3[idMmio2] == pCur);
     2686            pVM->pgm.s.apMmio2RangesR3[idMmio2] = NULL;
     2687            pVM->pgm.s.apMmio2RangesR0[idMmio2] = NIL_RTR0PTR;
    26522688
    26532689            /*
  • trunk/src/VBox/VMM/VMMR3/PGMSavedState.cpp

    r44528 r47786  
    103103/** The CRC-32 for a zero half page. */
    104104#define PGM_STATE_CRC32_ZERO_HALF_PAGE  UINT32_C(0xf1e8ba9e)
     105
     106
     107
     108/** @name Old Page types used in older saved states.
     109 * @{  */
     110/** Old saved state: The usual invalid zero entry. */
     111#define PGMPAGETYPE_OLD_INVALID             0
     112/** Old saved state: RAM page. (RWX) */
     113#define PGMPAGETYPE_OLD_RAM                 1
     114/** Old saved state: MMIO2 page. (RWX) */
     115#define PGMPAGETYPE_OLD_MMIO2               1
     116/** Old saved state: MMIO2 page aliased over an MMIO page. (RWX)
     117 * See PGMHandlerPhysicalPageAlias(). */
     118#define PGMPAGETYPE_OLD_MMIO2_ALIAS_MMIO    2
     119/** Old saved state: Shadowed ROM. (RWX) */
     120#define PGMPAGETYPE_OLD_ROM_SHADOW          3
     121/** Old saved state: ROM page. (R-X) */
     122#define PGMPAGETYPE_OLD_ROM                 4
     123/** Old saved state: MMIO page. (---) */
     124#define PGMPAGETYPE_OLD_MMIO                5
     125/** @}  */
    105126
    106127
     
    11561177
    11571178                        case PGMPAGETYPE_MMIO:
     1179                        case PGMPAGETYPE_SPECIAL_ALIAS_MMIO:
    11581180                            paLSPages[iPage].fZero   = 0;
    11591181                            paLSPages[iPage].fShared = 0;
     
    21722194
    21732195/**
     2196 * Compares a page with an old save type value.
     2197 *
     2198 * @returns true if equal, false if not.
     2199 * @param   pPage           The page to compare.
     2200 * @param   uOldType        The old type value from the saved state.
     2201 */
     2202DECLINLINE(bool) pgmR3CompareNewAndOldPageTypes(PPGMPAGE pPage, uint8_t uOldType)
     2203{
     2204    uint8_t uOldPageType;
     2205    switch (PGM_PAGE_GET_TYPE(pPage))
     2206    {
     2207        case PGMPAGETYPE_INVALID:               uOldPageType = PGMPAGETYPE_OLD_INVALID; break;
     2208        case PGMPAGETYPE_RAM:                   uOldPageType = PGMPAGETYPE_OLD_RAM; break;
     2209        case PGMPAGETYPE_MMIO2:                 uOldPageType = PGMPAGETYPE_OLD_MMIO2; break;
     2210        case PGMPAGETYPE_MMIO2_ALIAS_MMIO:      uOldPageType = PGMPAGETYPE_OLD_MMIO2_ALIAS_MMIO; break;
     2211        case PGMPAGETYPE_ROM_SHADOW:            uOldPageType = PGMPAGETYPE_OLD_ROM_SHADOW; break;
     2212        case PGMPAGETYPE_ROM:                   uOldPageType = PGMPAGETYPE_OLD_ROM; break;
     2213        case PGMPAGETYPE_SPECIAL_ALIAS_MMIO:    /* fall thru */
     2214        case PGMPAGETYPE_MMIO:                  uOldPageType = PGMPAGETYPE_OLD_MMIO; break;
     2215        default:
     2216            AssertFailed();
     2217            uOldPageType = PGMPAGETYPE_OLD_INVALID;
     2218            break;
     2219    }
     2220    return uOldPageType == uOldType;
     2221}
     2222
     2223
     2224/**
    21742225 * Loads a page without any bits in the saved state, i.e. making sure it's
    21752226 * really zero.
     
    21772228 * @returns VBox status code.
    21782229 * @param   pVM             Pointer to the VM.
    2179  * @param   uType           The page type or PGMPAGETYPE_INVALID (old saved
     2230 * @param   uOldType        The page type or PGMPAGETYPE_OLD_INVALID (old saved
    21802231 *                          state).
    21812232 * @param   pPage           The guest page tracking structure.
     
    21832234 * @param   pRam            The ram range (logging).
    21842235 */
    2185 static int pgmR3LoadPageZeroOld(PVM pVM, uint8_t uType, PPGMPAGE pPage, RTGCPHYS GCPhys, PPGMRAMRANGE pRam)
    2186 {
    2187     if (    PGM_PAGE_GET_TYPE(pPage) != uType
    2188         &&  uType != PGMPAGETYPE_INVALID)
     2236static int pgmR3LoadPageZeroOld(PVM pVM, uint8_t uOldType, PPGMPAGE pPage, RTGCPHYS GCPhys, PPGMRAMRANGE pRam)
     2237{
     2238    if (   uOldType != PGMPAGETYPE_OLD_INVALID
     2239        && !pgmR3CompareNewAndOldPageTypes(pPage, uOldType))
    21892240        return VERR_SSM_UNEXPECTED_DATA;
    21902241
     
    22072258 * @param   pVM             Pointer to the VM.
    22082259 * @param   pSSM            The SSM handle.
    2209  * @param   uType           The page type or PGMPAGETYEP_INVALID (old saved
     2260 * @param   uOldType        The page type or PGMPAGETYPE_OLD_INVALID (old saved
    22102261 *                          state).
    22112262 * @param   pPage           The guest page tracking structure.
     
    22132264 * @param   pRam            The ram range (logging).
    22142265 */
    2215 static int pgmR3LoadPageBitsOld(PVM pVM, PSSMHANDLE pSSM, uint8_t uType, PPGMPAGE pPage, RTGCPHYS GCPhys, PPGMRAMRANGE pRam)
     2266static int pgmR3LoadPageBitsOld(PVM pVM, PSSMHANDLE pSSM, uint8_t uOldType, PPGMPAGE pPage, RTGCPHYS GCPhys, PPGMRAMRANGE pRam)
    22162267{
    22172268    /*
    22182269     * Match up the type, dealing with MMIO2 aliases (dropped).
    22192270     */
    2220     AssertLogRelMsgReturn(   PGM_PAGE_GET_TYPE(pPage) == uType
    2221                           || uType == PGMPAGETYPE_INVALID
     2271    AssertLogRelMsgReturn(   uOldType == PGMPAGETYPE_INVALID
     2272                          || pgmR3CompareNewAndOldPageTypes(pPage, uOldType)
    22222273                          /* kudge for the expanded PXE bios (r67885) - @bugref{5687}: */
    2223                           || (   uType == PGMPAGETYPE_RAM
     2274                          || (   uOldType == PGMPAGETYPE_OLD_RAM
    22242275                              && GCPhys >= 0xed000
    22252276                              && GCPhys <= 0xeffff
     
    22512302 * @param   pVM             Pointer to the VM.
    22522303 * @param   pSSM            The SSM handle.
    2253  * @param   uType           The page type.
     2304 * @param   uOldType        The page type.
    22542305 * @param   pPage           The page.
    22552306 * @param   GCPhys          The page address.
    22562307 * @param   pRam            The RAM range (for error messages).
    22572308 */
    2258 static int pgmR3LoadPageOld(PVM pVM, PSSMHANDLE pSSM, uint8_t uType, PPGMPAGE pPage, RTGCPHYS GCPhys, PPGMRAMRANGE pRam)
     2309static int pgmR3LoadPageOld(PVM pVM, PSSMHANDLE pSSM, uint8_t uOldType, PPGMPAGE pPage, RTGCPHYS GCPhys, PPGMRAMRANGE pRam)
    22592310{
    22602311    uint8_t uState;
     
    22622313    AssertLogRelMsgRCReturn(rc, ("pPage=%R[pgmpage] GCPhys=%#x %s rc=%Rrc\n", pPage, GCPhys, pRam->pszDesc, rc), rc);
    22632314    if (uState == 0 /* zero */)
    2264         rc = pgmR3LoadPageZeroOld(pVM, uType, pPage, GCPhys, pRam);
     2315        rc = pgmR3LoadPageZeroOld(pVM, uOldType, pPage, GCPhys, pRam);
    22652316    else if (uState == 1)
    2266         rc = pgmR3LoadPageBitsOld(pVM, pSSM, uType, pPage, GCPhys, pRam);
     2317        rc = pgmR3LoadPageBitsOld(pVM, pSSM, uOldType, pPage, GCPhys, pRam);
    22672318    else
    22682319        rc = VERR_PGM_INVALID_SAVED_PAGE_STATE;
    2269     AssertLogRelMsgRCReturn(rc, ("pPage=%R[pgmpage] uState=%d uType=%d GCPhys=%RGp %s rc=%Rrc\n",
    2270                                  pPage, uState, uType, GCPhys, pRam->pszDesc, rc),
     2320    AssertLogRelMsgRCReturn(rc, ("pPage=%R[pgmpage] uState=%d uOldType=%d GCPhys=%RGp %s rc=%Rrc\n",
     2321                                 pPage, uState, uOldType, GCPhys, pRam->pszDesc, rc),
    22712322                            rc);
    22722323    return VINF_SUCCESS;
     
    24402491                RTGCPHYS const  GCPhysPage = ((RTGCPHYS)iPage << PAGE_SHIFT) + pRam->GCPhys;
    24412492                PPGMPAGE        pPage      = &pRam->aPages[iPage];
    2442                 uint8_t         uType;
    2443                 rc = SSMR3GetU8(pSSM, &uType);
     2493                uint8_t         uOldType;
     2494                rc = SSMR3GetU8(pSSM, &uOldType);
    24442495                AssertLogRelMsgRCReturn(rc, ("pPage=%R[pgmpage] iPage=%#x GCPhysPage=%#x %s\n", pPage, iPage, GCPhysPage, pRam->pszDesc), rc);
    2445                 if (uType == PGMPAGETYPE_ROM_SHADOW)
     2496                if (uOldType == PGMPAGETYPE_OLD_ROM_SHADOW)
    24462497                    rc = pgmR3LoadShadowedRomPageOld(pVM, pSSM, pPage, GCPhysPage, pRam);
    24472498                else
    2448                     rc = pgmR3LoadPageOld(pVM, pSSM, uType, pPage, GCPhysPage, pRam);
     2499                    rc = pgmR3LoadPageOld(pVM, pSSM, uOldType, pPage, GCPhysPage, pRam);
    24492500                AssertLogRelMsgRCReturn(rc, ("rc=%Rrc iPage=%#x GCPhysPage=%#x %s\n", rc, iPage, GCPhysPage, pRam->pszDesc), rc);
    24502501            }
     
    24942545                        if (fPresent)
    24952546                        {
    2496                             if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO)
     2547                            if (   PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO
     2548                                || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO)
    24972549                                rc = pgmR3LoadPageToDevNullOld(pSSM);
    24982550                            else
  • trunk/src/VBox/VMM/include/PGMInternal.h

    r47526 r47786  
    731731        uint64_t    u10PteIdx           : 10;
    732732
    733         /** The GMM page ID. */
     733        /** The GMM page ID.
     734         * @remarks In the current implementation, MMIO2 and pages aliased to
     735         *          MMIO2 pages will be exploiting this field to calculate the
     736         *          ring-3 mapping address corresponding to the page.
     737         *          Later we may consider including MMIO2 management into GMM. */
    734738        uint32_t    idPage;
    735739        /** Usage tracking (page pool). */
     
    962966
    963967/**
    964  * Checks if the page is marked for MMIO.
     968 * Checks if the page is marked for MMIO, no MMIO2 aliasing.
    965969 * @returns true/false.
    966970 * @param   a_pPage     Pointer to the physical guest page tracking structure.
    967971 */
    968972#define PGM_PAGE_IS_MMIO(a_pPage)               ( (a_pPage)->s.uTypeY == PGMPAGETYPE_MMIO )
     973
     974/**
     975 * Checks if the page is marked for MMIO, including both aliases.
     976 * @returns true/false.
     977 * @param   a_pPage     Pointer to the physical guest page tracking structure.
     978 */
     979#define PGM_PAGE_IS_MMIO_OR_ALIAS(a_pPage)      (   (a_pPage)->s.uTypeY == PGMPAGETYPE_MMIO \
     980                                                 || (a_pPage)->s.uTypeY == PGMPAGETYPE_MMIO2_ALIAS_MMIO \
     981                                                 || (a_pPage)->s.uTypeY == PGMPAGETYPE_SPECIAL_ALIAS_MMIO \
     982                                                 )
     983
     984/**
     985 * Checks if the page is marked for MMIO, including special aliases.
     986 * @returns true/false.
     987 * @param   a_pPage     Pointer to the physical guest page tracking structure.
     988 */
     989#define PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(a_pPage) (   (a_pPage)->s.uTypeY == PGMPAGETYPE_MMIO \
     990                                                    || (a_pPage)->s.uTypeY == PGMPAGETYPE_SPECIAL_ALIAS_MMIO )
     991
     992/**
     993 * Checks if the page is a special aliased MMIO page.
     994 * @returns true/false.
     995 * @param   a_pPage     Pointer to the physical guest page tracking structure.
     996 */
     997#define PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(a_pPage) ( (a_pPage)->s.uTypeY == PGMPAGETYPE_SPECIAL_ALIAS_MMIO )
    969998
    970999/**
     
    15851614    /** The saved state range ID. */
    15861615    uint8_t                             idSavedState;
     1616    /** MMIO2 range identifier, for page IDs (PGMPAGE::s.idPage). */
     1617    uint8_t                             idMmio2;
    15871618    /** Alignment padding for putting the ram range on a PGMPAGE alignment boundary. */
    1588     uint8_t                             abAlignment[HC_ARCH_BITS == 32 ? 12 : 12];
     1619    uint8_t                             abAlignment[HC_ARCH_BITS == 32 ? 11 : 11];
    15891620    /** Live save per page tracking data. */
    15901621    R3PTRTYPE(PPGMLIVESAVEMMIO2PAGE)    paLSPages;
     
    15951626typedef PGMMMIO2RANGE *PPGMMMIO2RANGE;
    15961627
     1628/** @name Intenal MMIO2 constants.
     1629 * @{ */
     1630/** The maximum number of MMIO2 ranges. */
     1631#define PGM_MMIO2_MAX_RANGES                        8
     1632/** The maximum number of pages in a MMIO2 range. */
     1633#define PGM_MMIO2_MAX_PAGE_COUNT                    UINT32_C(0x00ffffff)
     1634/** Makes a MMIO2 page ID out of a MMIO2 range ID and page index number. */
     1635#define PGM_MMIO2_PAGEID_MAKE(a_idMmio2, a_iPage)   ( ((uint32_t)(a_idMmio2) << 24) | (uint32_t)(a_iPage) )
     1636/** Gets the MMIO2 range ID from an MMIO2 page ID.  */
     1637#define PGM_MMIO2_PAGEID_GET_MMIO2_ID(a_idPage)     ( (uint8_t)((a_idPage) >> 24) )
     1638/** Gets the MMIO2 page index from an MMIO2 page ID.  */
     1639#define PGM_MMIO2_PAGEID_GET_IDX(a_idPage)          ( ((a_idPage) & UINT32_C(0x00ffffff)) )
     1640/** @} */
    15971641
    15981642
     
    30873131    /** Set if PCI passthrough is enabled. */
    30883132    bool                            fPciPassthrough;
     3133    /** The number of MMIO2 regions (serves as the next MMIO2 ID). */
     3134    uint8_t                         cMmio2Regions;
    30893135    /** Alignment padding that makes the next member start on a 8 byte boundary. */
    3090     bool                            afAlignment1[3];
     3136    bool                            afAlignment1[2];
    30913137
    30923138    /** Indicates that PGMR3FinalizeMappings has been called and that further
     
    31443190    R3PTRTYPE(PPGMMODEDATA)         paModeData;
    31453191    RTR3PTR                         R3PtrAlignment0;
     3192    /** MMIO2 lookup array for ring-3.  Indexed by idMmio2 minus 1.  */
     3193    R3PTRTYPE(PPGMMMIO2RANGE)       apMmio2RangesR3[PGM_MMIO2_MAX_RANGES];
    31463194
    31473195    /** RAM range TLB for R0. */
     
    31633211    R0PTRTYPE(PPGMROMRANGE)         pRomRangesR0;
    31643212    RTR0PTR                         R0PtrAlignment0;
    3165 
     3213    /** MMIO2 lookup array for ring-3.  Indexed by idMmio2 minus 1.  */
     3214    R0PTRTYPE(PPGMMMIO2RANGE)       apMmio2RangesR0[PGM_MMIO2_MAX_RANGES];
    31663215
    31673216    /** RAM range TLB for RC. */
  • trunk/src/VBox/VMM/include/internal/pgm.h

    r44528 r47786  
    4646     * See PGMHandlerPhysicalPageAlias(). */
    4747    PGMPAGETYPE_MMIO2_ALIAS_MMIO,
     48    /** Special page aliased over an MMIO page. (RWX)
     49     * See PGMHandlerPhysicalPageAliasHC(), but this is generally only used for
     50     * VT-x's APIC access page at the moment.  Treated as MMIO by everyone except
     51     * the shadow paging code. */
     52    PGMPAGETYPE_SPECIAL_ALIAS_MMIO,
    4853    /** Shadowed ROM. (RWX) */
    4954    PGMPAGETYPE_ROM_SHADOW,
     
    5560    PGMPAGETYPE_END
    5661} PGMPAGETYPE;
    57 AssertCompile(PGMPAGETYPE_END <= 7);
     62AssertCompile(PGMPAGETYPE_END == 8);
    5863
    5964VMMDECL(PGMPAGETYPE) PGMPhysGetPageType(PVM pVM, RTGCPHYS GCPhys);
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