[NTOSKRNL]: Fix a stupid bug in MiProtectVirtualMemory which was causing empty PTEs whose protection was being set to remain zero PTEs, instead of demand-zero PTEs, but still acquire a page table reference. When they were later touched in the page fault code, and made into demand-zero PTEs, they'd get referenced again, thus Aleksey hacked away all the referencing code to work around this (causing PDEs to disappear...)

[NTOSKRNL]: Restore the page table reference counting mechanism, and put it in a macro to be cleaner. Also use macros for testing PD boundaries, instead of math-by-hand.

svn path=/trunk/; revision=57229
This commit is contained in:
Alex Ionescu 2012-09-03 16:29:31 +00:00
parent 5547667b67
commit 706b25f988
4 changed files with 54 additions and 34 deletions

View file

@ -1619,6 +1619,41 @@ MiReferenceUnusedPageAndBumpLockCount(IN PMMPFN Pfn1)
} }
} }
FORCEINLINE
VOID
MiIncrementPageTableReferences(IN PVOID Address)
{
PUSHORT RefCount;
RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
*RefCount += 1;
ASSERT(*RefCount <= PTE_PER_PAGE);
}
FORCEINLINE
VOID
MiDecrementPageTableReferences(IN PVOID Address)
{
PUSHORT RefCount;
RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
*RefCount -= 1;
ASSERT(*RefCount < PTE_PER_PAGE);
}
FORCEINLINE
USHORT
MiQueryPageTableReferences(IN PVOID Address)
{
PUSHORT RefCount;
RefCount = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)];
return *RefCount;
}
BOOLEAN BOOLEAN
NTAPI NTAPI
MmArmInitSystem( MmArmInitSystem(

View file

@ -1684,8 +1684,7 @@ UserFault:
if (Address <= MM_HIGHEST_USER_ADDRESS) if (Address <= MM_HIGHEST_USER_ADDRESS)
{ {
/* Add an additional page table reference */ /* Add an additional page table reference */
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++; MiIncrementPageTableReferences(Address);
ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
} }
/* Did we get a prototype PTE back? */ /* Did we get a prototype PTE back? */

View file

@ -1821,7 +1821,6 @@ MiSetProtectionOnSection(IN PEPROCESS Process,
PMMPDE PointerPde; PMMPDE PointerPde;
PMMPFN Pfn1; PMMPFN Pfn1;
ULONG ProtectionMask, QuotaCharge = 0; ULONG ProtectionMask, QuotaCharge = 0;
PUSHORT UsedPageTableEntries;
PETHREAD Thread = PsGetCurrentThread(); PETHREAD Thread = PsGetCurrentThread();
PAGED_CODE(); PAGED_CODE();
@ -1914,9 +1913,7 @@ MiSetProtectionOnSection(IN PEPROCESS Process,
// This used to be a zero PTE and it no longer is, so we must add a // This used to be a zero PTE and it no longer is, so we must add a
// reference to the pagetable. // reference to the pagetable.
// //
UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))]; MiIncrementPageTableReferences(MiPteToAddress(PointerPte));
(*UsedPageTableEntries)++;
ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
// //
// Create the demand-zero prototype PTE // Create the demand-zero prototype PTE

View file

@ -589,10 +589,8 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va,
TempPte = *PointerPte; TempPte = *PointerPte;
if (TempPte.u.Long) if (TempPte.u.Long)
{ {
DPRINT("Decrement used PTEs by address: %lx\n", Va); *UsedPageTableEntries -= 1;
(*UsedPageTableEntries)--;
ASSERT((*UsedPageTableEntries) < PTE_COUNT); ASSERT((*UsedPageTableEntries) < PTE_COUNT);
DPRINT("Refs: %lx\n", (*UsedPageTableEntries));
/* Check if the PTE is actually mapped in */ /* Check if the PTE is actually mapped in */
if (TempPte.u.Long & 0xFFFFFC01) if (TempPte.u.Long & 0xFFFFFC01)
@ -653,14 +651,10 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va,
/* The PDE should still be valid at this point */ /* The PDE should still be valid at this point */
ASSERT(PointerPde->u.Hard.Valid == 1); ASSERT(PointerPde->u.Hard.Valid == 1);
DPRINT("Should check if handles for: %p are zero (PDE: %lx)\n", Va, PointerPde->u.Hard.PageFrameNumber); if (*UsedPageTableEntries == 0)
if (!(*UsedPageTableEntries))
{ {
DPRINT("They are!\n");
if (PointerPde->u.Long != 0) if (PointerPde->u.Long != 0)
{ {
DPRINT("PDE active: %lx in %16s\n", PointerPde->u.Hard.PageFrameNumber, CurrentProcess->ImageFileName);
/* Delete the PTE proper */ /* Delete the PTE proper */
MiDeletePte(PointerPde, MiDeletePte(PointerPde,
MiPteToAddress(PointerPde), MiPteToAddress(PointerPde),
@ -1880,7 +1874,6 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
ULONG_PTR StartingAddress, EndingAddress; ULONG_PTR StartingAddress, EndingAddress;
PMMPTE PointerPde, PointerPte, LastPte; PMMPTE PointerPde, PointerPte, LastPte;
MMPTE PteContents; MMPTE PteContents;
//PUSHORT UsedPageTableEntries;
PMMPFN Pfn1; PMMPFN Pfn1;
ULONG ProtectionMask, OldProtect; ULONG ProtectionMask, OldProtect;
BOOLEAN Committed; BOOLEAN Committed;
@ -2050,24 +2043,23 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
while (PointerPte <= LastPte) while (PointerPte <= LastPte)
{ {
/* Check if we've crossed a PDE boundary and make the new PDE valid too */ /* Check if we've crossed a PDE boundary and make the new PDE valid too */
if ((((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)) == 0) if (MiIsPteOnPdeBoundary(PointerPte))
{ {
PointerPde = MiAddressToPte(PointerPte); PointerPde = MiAddressToPte(PointerPte);
MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL); MiMakePdeExistAndMakeValid(PointerPde, Process, MM_NOIRQL);
} }
/* Capture the PTE and see what we're dealing with */ /* Capture the PTE and check if it was empty */
PteContents = *PointerPte; PteContents = *PointerPte;
if (PteContents.u.Long == 0) if (PteContents.u.Long == 0)
{ {
/* This used to be a zero PTE and it no longer is, so we must add a /* This used to be a zero PTE and it no longer is, so we must add a
reference to the pagetable. */ reference to the pagetable. */
//UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))]; MiIncrementPageTableReferences(MiPteToAddress(PointerPte));
//(*UsedPageTableEntries)++;
//ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
DPRINT1("HACK: Not increasing UsedPageTableEntries count!\n");
} }
else if (PteContents.u.Hard.Valid == 1)
/* Check what kind of PTE we are dealing with */
if (PteContents.u.Hard.Valid == 1)
{ {
/* Get the PFN entry */ /* Get the PFN entry */
Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents)); Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(&PteContents));
@ -2080,8 +2072,11 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
(NewAccessProtection & PAGE_GUARD)) (NewAccessProtection & PAGE_GUARD))
{ {
/* The page should be in the WS and we should make it transition now */ /* The page should be in the WS and we should make it transition now */
UNIMPLEMENTED; DPRINT1("Making valid page invalid is not yet supported!\n");
//continue; Status = STATUS_NOT_IMPLEMENTED;
/* Unlock the working set */
MiUnlockProcessWorkingSetUnsafe(Process, Thread);
goto FailPath;
} }
/* Write the protection mask and write it with a TLB flush */ /* Write the protection mask and write it with a TLB flush */
@ -2270,7 +2265,6 @@ MiDecommitPages(IN PVOID StartingAddress,
ULONG PteCount = 0; ULONG PteCount = 0;
PMMPFN Pfn1; PMMPFN Pfn1;
MMPTE PteContents; MMPTE PteContents;
PUSHORT UsedPageTableEntries;
PETHREAD CurrentThread = PsGetCurrentThread(); PETHREAD CurrentThread = PsGetCurrentThread();
// //
@ -2292,7 +2286,7 @@ MiDecommitPages(IN PVOID StartingAddress,
// //
// Check if we've crossed a PDE boundary // Check if we've crossed a PDE boundary
// //
if ((((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1)) == 0) if (MiIsPteOnPdeBoundary(PointerPte))
{ {
// //
// Get the new PDE and flush the valid PTEs we had built up until // Get the new PDE and flush the valid PTEs we had built up until
@ -2383,9 +2377,7 @@ MiDecommitPages(IN PVOID StartingAddress,
// This used to be a zero PTE and it no longer is, so we must add a // This used to be a zero PTE and it no longer is, so we must add a
// reference to the pagetable. // reference to the pagetable.
// //
UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(StartingAddress)]; MiIncrementPageTableReferences(StartingAddress);
(*UsedPageTableEntries)++;
ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
// //
// Next, we account for decommitted PTEs and make the PTE as such // Next, we account for decommitted PTEs and make the PTE as such
@ -3648,7 +3640,6 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
PMEMORY_AREA MemoryArea; PMEMORY_AREA MemoryArea;
PFN_NUMBER PageCount; PFN_NUMBER PageCount;
PMMVAD Vad, FoundVad; PMMVAD Vad, FoundVad;
PUSHORT UsedPageTableEntries;
NTSTATUS Status; NTSTATUS Status;
PMMSUPPORT AddressSpace; PMMSUPPORT AddressSpace;
PVOID PBaseAddress; PVOID PBaseAddress;
@ -4268,7 +4259,7 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
// //
// Have we crossed into a new page table? // Have we crossed into a new page table?
// //
if (!(((ULONG_PTR)PointerPte) & (SYSTEM_PD_SIZE - 1))) if (MiIsPteOnPdeBoundary(PointerPte))
{ {
// //
// Get the PDE and now make it valid too // Get the PDE and now make it valid too
@ -4286,9 +4277,7 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
// First increment the count of pages in the page table for this // First increment the count of pages in the page table for this
// process // process
// //
UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(MiPteToAddress(PointerPte))]; MiIncrementPageTableReferences(MiPteToAddress(PointerPte));
(*UsedPageTableEntries)++;
ASSERT((*UsedPageTableEntries) <= PTE_COUNT);
// //
// And now write the invalid demand-zero PTE as requested // And now write the invalid demand-zero PTE as requested