VirtualBox

Changeset 100964 in vbox for trunk/src/VBox/VMM/VMMAll


Ignore:
Timestamp:
Aug 24, 2023 2:45:42 PM (16 months ago)
Author:
vboxsync
Message:

VMM/PGM: Some experiments wrt preseving ZERO page status as the (windows) guest zero's all memory prior to use. bugref:6385 bugref:10509

Location:
trunk/src/VBox/VMM/VMMAll
Files:
3 edited

Legend:

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

    r99891 r100964  
    7272static int pgmShwSyncLongModePDPtr(PVMCPUCC pVCpu, RTGCPTR64 GCPtr, X86PGPAEUINT uGstPml4e, X86PGPAEUINT uGstPdpe, PX86PDPAE *ppPD);
    7373static int pgmShwGetEPTPDPtr(PVMCPUCC pVCpu, RTGCPTR64 GCPtr, PEPTPDPT *ppPdpt, PEPTPD *ppPD);
     74#ifdef PGM_WITH_PAGE_ZEROING_DETECTION
     75static bool pgmHandlePageZeroingCode(PVMCPUCC pVCpu, PCPUMCTX pCtx);
     76#endif
    7477
    7578
     
    39313934
    39323935        cch = pfnOutput(pvArgOutput, szTmp, cch);
     3936#if 0
     3937        size_t cch2 = 0;
     3938        szTmp[cch2++] = '(';
     3939        cch2 += RTStrFormatNumber(&szTmp[cch2], (uintptr_t)pPage, 16, 18, 0, RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
     3940        szTmp[cch2++] = ')';
     3941        szTmp[cch2] = '\0';
     3942        cch += pfnOutput(pvArgOutput, szTmp, cch2);
     3943#endif
    39333944    }
    39343945    else
     
    40754086}
    40764087
     4088#ifdef PGM_WITH_PAGE_ZEROING_DETECTION
     4089
     4090/**
     4091 * Helper for checking whether XMM0 is zero, possibly retriving external state.
     4092 */
     4093static bool pgmHandlePageZeroingIsXmm0Zero(PVMCPUCC pVCpu, PCPUMCTX pCtx)
     4094{
     4095    if (pCtx->fExtrn & CPUMCTX_EXTRN_SSE_AVX)
     4096    {
     4097        int rc = CPUMImportGuestStateOnDemand(pVCpu, CPUMCTX_EXTRN_SSE_AVX);
     4098        AssertRCReturn(rc, false);
     4099    }
     4100    return pCtx->XState.x87.aXMM[0].au64[0] == 0
     4101        && pCtx->XState.x87.aXMM[0].au64[1] == 0
     4102        && pCtx->XState.x87.aXMM[0].au64[2] == 0
     4103        && pCtx->XState.x87.aXMM[0].au64[3] == 0;
     4104}
     4105
     4106
     4107/**
     4108 * Helper for comparing opcode bytes.
     4109 */
     4110static bool pgmHandlePageZeroingMatchOpcodes(PVMCPUCC pVCpu, PCPUMCTX pCtx, uint8_t const *pbOpcodes, uint32_t cbOpcodes)
     4111{
     4112    uint8_t abTmp[64];
     4113    AssertMsgReturn(cbOpcodes <= sizeof(abTmp), ("cbOpcodes=%#x\n", cbOpcodes), false);
     4114    int rc = PGMPhysSimpleReadGCPtr(pVCpu, abTmp, pCtx->rip + pCtx->cs.u64Base, cbOpcodes);
     4115    if (RT_SUCCESS(rc))
     4116        return memcmp(abTmp, pbOpcodes, cbOpcodes) == 0;
     4117    return false;
     4118}
     4119
     4120
     4121/**
     4122 * Called on faults on ZERO pages to check if the guest is trying to zero it.
     4123 *
     4124 * Since it's a waste of time to zero a ZERO page and it will cause an
     4125 * unnecessary page allocation, we'd like to detect and avoid this.
     4126 * If any known page zeroing code is detected, this function will update the CPU
     4127 * state to pretend the page was zeroed by the code.
     4128 *
     4129 * @returns true if page zeroing code was detected and CPU state updated to skip
     4130 *          the code.
     4131 * @param   pVCpu   The cross context virtual CPU structure of the calling EMT.
     4132 * @param   pCtx    The guest register context.
     4133 */
     4134static bool pgmHandlePageZeroingCode(PVMCPUCC pVCpu, PCPUMCTX pCtx)
     4135{
     4136    CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_EFER);
     4137
     4138    /*
     4139     * Sort by mode first.
     4140     */
     4141    if (CPUMIsGuestInLongModeEx(pCtx))
     4142    {
     4143        if (CPUMIsGuestIn64BitCodeEx(pCtx))
     4144        {
     4145            /*
     4146             * 64-bit code.
     4147             */
     4148            Log9(("pgmHandlePageZeroingCode: not page zeroing - 64-bit\n"));
     4149        }
     4150        else if (pCtx->cs.Attr.n.u1DefBig)
     4151            Log9(("pgmHandlePageZeroingCode: not page zeroing - 32-bit lm\n"));
     4152        else
     4153            Log9(("pgmHandlePageZeroingCode: not page zeroing - 16-bit lm\n"));
     4154    }
     4155    else if (CPUMIsGuestInPagedProtectedModeEx(pCtx))
     4156    {
     4157        if (pCtx->cs.Attr.n.u1DefBig)
     4158        {
     4159            /*
     4160             * 32-bit paged protected mode code.
     4161             */
     4162            CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX
     4163                                         | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RBP | CPUMCTX_EXTRN_RSI | CPUMCTX_EXTRN_RDI
     4164                                         | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS);
     4165
     4166            /* 1. Generic 'rep stosd' detection. */
     4167            static uint8_t const s_abRepStosD[] = { 0xf3, 0xab };
     4168            if (   pCtx->eax == 0
     4169                && pCtx->ecx == X86_PAGE_SIZE / 4
     4170                && !(pCtx->edi & X86_PAGE_OFFSET_MASK)
     4171                && pgmHandlePageZeroingMatchOpcodes(pVCpu, pCtx, s_abRepStosD, sizeof(s_abRepStosD)))
     4172            {
     4173                pCtx->ecx  = 0;
     4174                pCtx->edi += X86_PAGE_SIZE;
     4175                Log9(("pgmHandlePageZeroingCode: REP STOSD: eip=%RX32 -> %RX32\n", pCtx->eip, pCtx->eip + sizeof(s_abRepStosD)));
     4176                pCtx->eip += sizeof(s_abRepStosD);
     4177                return true;
     4178            }
     4179
     4180            /* 2. Windows 2000 sp4 KiXMMIZeroPageNoSave loop code: */
     4181            static uint8_t const s_abW2kSp4XmmZero[] =
     4182            {
     4183                0x0f, 0x2b, 0x01,
     4184                0x0f, 0x2b, 0x41, 0x10,
     4185                0x0f, 0x2b, 0x41, 0x20,
     4186                0x0f, 0x2b, 0x41, 0x30,
     4187                0x83, 0xc1, 0x40,
     4188                0x48,
     4189                0x75, 0xeb,
     4190            };
     4191            if (   pCtx->eax == 64
     4192                && !(pCtx->ecx & X86_PAGE_OFFSET_MASK)
     4193                && pgmHandlePageZeroingMatchOpcodes(pVCpu, pCtx, s_abW2kSp4XmmZero, sizeof(s_abW2kSp4XmmZero))
     4194                && pgmHandlePageZeroingIsXmm0Zero(pVCpu, pCtx))
     4195            {
     4196                pCtx->eax  = 1;
     4197                pCtx->ecx += X86_PAGE_SIZE;
     4198                Log9(("pgmHandlePageZeroingCode: w2k sp4 xmm: eip=%RX32 -> %RX32\n",
     4199                      pCtx->eip, pCtx->eip + sizeof(s_abW2kSp4XmmZero) - 3));
     4200                pCtx->eip += sizeof(s_abW2kSp4XmmZero) - 3;
     4201                return true;
     4202            }
     4203            Log9(("pgmHandlePageZeroingCode: not page zeroing - 32-bit\n"));
     4204        }
     4205        else if (!pCtx->eflags.Bits.u1VM)
     4206            Log9(("pgmHandlePageZeroingCode: not page zeroing - 16-bit\n"));
     4207        else
     4208            Log9(("pgmHandlePageZeroingCode: not page zeroing - v86\n"));
     4209    }
     4210    return false;
     4211}
     4212
     4213#endif /* PGM_WITH_PAGE_ZEROING_DETECTION */
  • trunk/src/VBox/VMM/VMMAll/PGMAllBth.h

    r100958 r100964  
    783783#   endif
    784784                AssertFatalMsg(!PGM_PAGE_IS_BALLOONED(pPage), ("Unexpected ballooned page at %RGp\n", GCPhys));
     785#  ifdef PGM_WITH_PAGE_ZEROING_DETECTION
     786                if (   PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ZERO
     787                    && (pvFault & X86_PAGE_OFFSET_MASK) == 0
     788                    && pgmHandlePageZeroingCode(pVCpu, pCtx))
     789                {
     790                    STAM_STATS({ pVCpu->pgmr0.s.pStatTrap0eAttributionR0 = &pVCpu->pgm.s.Stats.StatRZTrap0eTime2PageZeroing; });
     791                    return VINF_SUCCESS;
     792                }
     793#  endif
    785794                STAM_STATS({ pVCpu->pgmr0.s.pStatTrap0eAttributionR0 = &pVCpu->pgm.s.Stats.StatRZTrap0eTime2MakeWritable; });
    786795
     
    13131322            /* This is a read-only page. */
    13141323            AssertFatalMsg(!PGM_PAGE_IS_BALLOONED(pPage), ("Unexpected ballooned page at %RGp\n", GCPhysPage));
     1324#ifdef PGM_WITH_PAGE_ZEROING_DETECTION
     1325            if (   PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ZERO
     1326                && (GCPhysNestedFault & X86_PAGE_OFFSET_MASK) == 0
     1327                && pgmHandlePageZeroingCode(pVCpu, pCtx))
     1328            {
     1329                STAM_STATS({ pVCpu->pgmr0.s.pStatTrap0eAttributionR0 = &pVCpu->pgm.s.Stats.StatRZTrap0eTime2PageZeroing; });
     1330                return VINF_SUCCESS;
     1331            }
     1332#endif
    13151333            STAM_STATS({ pVCpu->pgmr0.s.pStatTrap0eAttributionR0 = &pVCpu->pgm.s.Stats.StatRZTrap0eTime2MakeWritable; });
    13161334
     
    16791697    }
    16801698# else
    1681   NOREF(GCPhysPage);
     1699    NOREF(GCPhysPage);
    16821700# endif
    1683 
    1684     STAM_PROFILE_START(&pVM->pgm.s.Stats.StatTrackDeref, a);
    1685     LogFlow(("SyncPageWorkerTrackDeref: Damn HCPhys=%RHp pShwPage->idx=%#x!!!\n", HCPhys, pShwPage->idx));
    16861701
    16871702    /** @todo If this turns out to be a bottle neck (*very* likely) two things can be done:
    16881703     *      1. have a medium sized HCPhys -> GCPhys TLB (hash?)
    16891704     *      2. write protect all shadowed pages. I.e. implement caching.
    1690      */
     1705     *
     1706     *  2023-08-24 bird: If we allow the ZeroPg to enter the shadow page tables,
     1707     *  this becomes a common occurence and we screw up. A better to the above would
     1708     *  be to have a parallel table that records the guest physical addresses of the
     1709     *  pages mapped by the shadow page table...  For nested page tables,
     1710     *  we can easily correleate a table entry to a page entry, so it won't be
     1711     *  needed for those.
     1712     */
     1713# if  PGM_TYPE_IS_NESTED_OR_EPT(PGM_SHW_TYPE) || !PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
     1714    /*
     1715     * For non-paged guest tables, EPT and nested tables we can figure out the
     1716     * physical page corresponding to the entry and dereference it.
     1717     * (This ASSUMES that shadow PTs won't be used ever be used out of place.)
     1718     */
     1719    if (   pShwPage->enmKind == PGMPOOLKIND_EPT_PT_FOR_PHYS
     1720        || pShwPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PHYS
     1721        || pShwPage->enmKind == PGMPOOLKIND_32BIT_PT_FOR_PHYS)
     1722    {
     1723        RTGCPHYS GCPhysNestedEntry = pShwPage->GCPhys + ((uint32_t)iPte << X86_PAGE_SHIFT);
     1724        if (!pShwPage->fA20Enabled)
     1725            GCPhysNestedEntry &= ~(uint64_t)RT_BIT_64(20);
     1726        PPGMPAGE const pPhysPage = pgmPhysGetPage(pVM, GCPhysNestedEntry);
     1727        AssertRelease(pPhysPage);
     1728        pgmTrackDerefGCPhys(pVM->pgm.s.CTX_SUFF(pPool), pShwPage, pPhysPage, iPte);
     1729    }
     1730    else
     1731        AssertMsgFailed(("enmKind=%d GCPhys=%RGp\n", pShwPage->enmKind, pShwPage->GCPhys));
     1732# endif
     1733
    16911734    /** @todo duplicated in the 2nd half of pgmPoolTracDerefGCPhysHint */
    16921735
     
    16941737     * Find the guest address.
    16951738     */
     1739    STAM_PROFILE_START(&pVM->pgm.s.Stats.StatTrackDeref, a);
     1740    LogFlow(("SyncPageWorkerTrackDeref(%d,%d): Damn HCPhys=%RHp pShwPage->idx=%#x!!!\n",
     1741             PGM_SHW_TYPE, PGM_GST_TYPE, HCPhys, pShwPage->idx));
    16961742    for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX);
    16971743         pRam;
     
    17501796
    17511797    /* write back */
    1752     Log2(("SyncPageWorkerTrackAddRef: u16=%#x->%#x  iPTDst=%#x\n", u16, PGM_PAGE_GET_TRACKING(pPage), iPTDst));
     1798    Log2(("SyncPageWorkerTrackAddRef: u16=%#x->%#x  iPTDst=%#x pPage=%p\n", u16, PGM_PAGE_GET_TRACKING(pPage), iPTDst, pPage));
    17531799    PGM_PAGE_SET_TRACKING(pVM, pPage, u16);
    17541800
     
    25742620        if (SHW_PTE_IS_P(*pPte))
    25752621        {
    2576             Log2(("SyncPageWorker: deref! *pPte=%RX64\n", SHW_PTE_LOG64(*pPte)));
     2622            Log2(("NestedSyncPageWorker: deref! *pPte=%RX64\n", SHW_PTE_LOG64(*pPte)));
    25772623            PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, SHW_PTE_GET_HCPHYS(*pPte), iPte, NIL_RTGCPHYS);
    25782624        }
     
    26502696        else if (SHW_PTE_GET_HCPHYS(*pPte) != SHW_PTE_GET_HCPHYS(Pte))
    26512697        {
    2652             Log2(("SyncPageWorker: deref! *pPte=%RX64 Pte=%RX64\n", SHW_PTE_LOG64(*pPte), SHW_PTE_LOG64(Pte)));
     2698            Log2(("NestedSyncPageWorker: deref! *pPte=%RX64 Pte=%RX64\n", SHW_PTE_LOG64(*pPte), SHW_PTE_LOG64(Pte)));
    26532699            PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, SHW_PTE_GET_HCPHYS(*pPte), iPte, NIL_RTGCPHYS);
    26542700            PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPte);
     
    26572703    else if (SHW_PTE_IS_P(*pPte))
    26582704    {
    2659         Log2(("SyncPageWorker: deref! *pPte=%RX64\n", SHW_PTE_LOG64(*pPte)));
     2705        Log2(("NestedSyncPageWorker: deref! *pPte=%RX64\n", SHW_PTE_LOG64(*pPte)));
    26602706        PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, SHW_PTE_GET_HCPHYS(*pPte), iPte, NIL_RTGCPHYS);
    26612707    }
     
    38493895                }
    38503896            }
     3897#  if !defined(VBOX_WITH_NEW_LAZY_PAGE_ALLOC) && !defined(PGM_WITH_PAGE_ZEROING_DETECTION) /* This code is too aggresive! */
    38513898            else if (   PGMIsUsingLargePages(pVM)
    38523899                     && PGM_A20_IS_ENABLED(pVCpu))
     
    38623909                    LogFlow(("pgmPhysAllocLargePage failed with %Rrc\n", rc));
    38633910            }
     3911#  endif
    38643912
    38653913            if (HCPhys != NIL_RTHCPHYS)
  • trunk/src/VBox/VMM/VMMAll/PGMAllPool.cpp

    r100577 r100964  
    37503750         * will be needed for this problem of course, but it will have to wait...
    37513751         */
     3752# ifndef VBOX_WITH_NEW_LAZY_PAGE_ALLOC /* end up guruing after pgmR0PhysAllocateLargePage otherwise. */
    37523753        if (    PGM_PAGE_IS_ZERO(pPhysPage)
    37533754            ||  PGM_PAGE_IS_BALLOONED(pPhysPage))
     3755# else
     3756        if (PGM_PAGE_IS_BALLOONED(pPhysPage))
     3757# endif
    37543758            rc = VINF_PGM_GCPHYS_ALIASED;
    37553759        else
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