Testers: Please pay attention to this build and test it fully:

[NTOS]: Implement MiDecrementShareCount (to start replacing MmReleasePageMemoryConsumer calls for pages that were grabbed through ARM3, not Mm).
[NTOS]: Implement MiInitializePfn (to initialize pages grabbed through ARM3/MiRemoveAnyPage instead of Mm/MmAllocPage).
[NTOS]: For stack pages, use new ARM3 PFN alloc/free routines, as a first test/beginning of the new ARM3 ABI.
[NTOS]: Implement and start using the Pending-Deletion PFN flag.
[NTOS]: As a result, for stack pages, the Transition page state will now be seen, and the new routine for re-inserting pages into the free list will now be used. Tracking of page table references is also done now for these pages (but we don't free the PT since this doesn't seem safe yet).


svn path=/trunk/; revision=47424
This commit is contained in:
Sir Richard 2010-05-29 18:33:50 +00:00
parent 00fbba2fb4
commit c916ce9d20
5 changed files with 188 additions and 23 deletions

View file

@ -502,6 +502,9 @@ MiFreeContiguousMemory(IN PVOID BaseAddress)
ASSERT(Pfn1->u4.VerifierAllocation == 0);
ASSERT(Pfn1->u3.e1.PrototypePte == 0);
/* Set the special pending delete marker */
MI_SET_PFN_DELETED(Pfn1);
/* Keep going for assertions */
PointerPte++;
} while (Pfn1++->u3.e1.EndOfAllocation == 0);
@ -531,12 +534,11 @@ MiFreeContiguousMemory(IN PVOID BaseAddress)
// Loop all the pages
//
LastPage = PageFrameIndex + PageCount;
Pfn1 = MiGetPfnEntry(PageFrameIndex);
do
{
//
// Free each one, and move on
//
MmReleasePageMemoryConsumer(MC_NPPOOL, PageFrameIndex++);
/* Decrement the share count and move on */
MiDecrementShareCount(Pfn1++, PageFrameIndex++);
} while (PageFrameIndex < LastPage);
//

View file

@ -119,6 +119,12 @@
//
#define MI_MAKE_SOFTWARE_PTE(p, x) ((p)->u.Long = (x << MM_PTE_SOFTWARE_PROTECTION_BITS))
//
// Marks a PTE as deleted
//
#define MI_SET_PFN_DELETED(x) ((x)->PteAddress = (PMMPTE)((ULONG_PTR)(x)->PteAddress | 1))
#define MI_IS_PFN_DELETED(x) ((ULONG_PTR)((x)->PteAddress) & 1)
//
// Special values for LoadedImports
//
@ -585,6 +591,21 @@ MiAllocatePfn(
IN ULONG Protection
);
VOID
NTAPI
MiInitializePfn(
IN PFN_NUMBER PageFrameIndex,
IN PMMPTE PointerPte,
IN BOOLEAN Modified
);
VOID
NTAPI
MiDecrementShareCount(
IN PMMPFN Pfn1,
IN PFN_NUMBER PageFrameIndex
);
PFN_NUMBER
NTAPI
MiRemoveAnyPage(

View file

@ -91,7 +91,7 @@ MiResolveDemandZeroFault(IN PVOID Address,
{
PFN_NUMBER PageFrameNumber;
MMPTE TempPte;
DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
DPRINT1("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
Address,
Process);

View file

@ -561,4 +561,126 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
}
}
VOID
NTAPI
MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
IN PMMPTE PointerPte,
IN BOOLEAN Modified)
{
PMMPFN Pfn1;
NTSTATUS Status;
PMMPTE PointerPtePte;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* Setup the PTE */
Pfn1 = MiGetPfnEntry(PageFrameIndex);
Pfn1->PteAddress = PointerPte;
/* Check if this PFN is part of a valid address space */
if (PointerPte->u.Hard.Valid == 1)
{
/* FIXME: TODO */
ASSERT(FALSE);
}
/* Otherwise this is a fresh page -- set it up */
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
Pfn1->u3.e2.ReferenceCount = 1;
Pfn1->u2.ShareCount = 1;
Pfn1->u3.e1.PageLocation = ActiveAndValid;
ASSERT(Pfn1->u3.e1.Rom == 0);
Pfn1->u3.e1.Modified = Modified;
/* Get the page table for the PTE */
PointerPtePte = MiAddressToPte(PointerPte);
if (PointerPtePte->u.Hard.Valid == 0)
{
/* Make sure the PDE gets paged in properly */
Status = MiCheckPdeForPagedPool(PointerPte);
if (!NT_SUCCESS(Status))
{
/* Crash */
KeBugCheckEx(MEMORY_MANAGEMENT,
0x61940,
(ULONG_PTR)PointerPte,
(ULONG_PTR)PointerPtePte->u.Long,
(ULONG_PTR)MiPteToAddress(PointerPte));
}
}
/* Get the PFN for the page table */
PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
ASSERT(PageFrameIndex != 0);
Pfn1->u4.PteFrame = PageFrameIndex;
/* Increase its share count so we don't get rid of it */
Pfn1 = MiGetPfnEntry(PageFrameIndex);
Pfn1->u2.ShareCount++;
}
VOID
NTAPI
MiDecrementShareCount(IN PMMPFN Pfn1,
IN PFN_NUMBER PageFrameIndex)
{
ASSERT(PageFrameIndex > 0);
ASSERT(MiGetPfnEntry(PageFrameIndex) != NULL);
ASSERT(Pfn1 == MiGetPfnEntry(PageFrameIndex));
/* Page must be in-use */
if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
(Pfn1->u3.e1.PageLocation != StandbyPageList))
{
/* Otherwise we have PFN corruption */
KeBugCheckEx(PFN_LIST_CORRUPT,
0x99,
PageFrameIndex,
Pfn1->u3.e1.PageLocation,
0);
}
/* Check if the share count is now 0 */
ASSERT(Pfn1->u2.ShareCount < 0xF000000);
if (!--Pfn1->u2.ShareCount)
{
/* ReactOS does not handle these */
ASSERT(Pfn1->u3.e1.PrototypePte == 0);
/* Put the page in transition */
Pfn1->u3.e1.PageLocation = TransitionPage;
/* PFN lock must be held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* Page should at least have one reference */
ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
if (Pfn1->u3.e2.ReferenceCount == 1)
{
/* In ReactOS, this path should always be hit with a deleted PFN */
ASSERT(MI_IS_PFN_DELETED(Pfn1) == TRUE);
/* Clear the last reference */
Pfn1->u3.e2.ReferenceCount = 0;
/*
* OriginalPte is used by AweReferenceCount in ReactOS, but either
* ways we shouldn't be seeing RMAP entries at this point
*/
ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
ASSERT(Pfn1->OriginalPte.u.Long == 0);
/* Mark the page temporarily as valid, we're going to make it free soon */
Pfn1->u3.e1.PageLocation = ActiveAndValid;
/* Bring it back into the free list */
MiInsertPageInFreeList(PageFrameIndex);
}
else
{
/* Otherwise, just drop the reference count */
InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
}
}
}
/* EOF */

View file

@ -31,8 +31,10 @@ MmDeleteKernelStack(IN PVOID StackBase,
IN BOOLEAN GuiStack)
{
PMMPTE PointerPte;
PFN_NUMBER StackPages;
PFN_NUMBER StackPages, PageFrameNumber;//, PageTableFrameNumber;
PMMPFN Pfn1;//, Pfn2;
ULONG i;
KIRQL OldIrql;
//
// This should be the guard page, so decrement by one
@ -46,6 +48,9 @@ MmDeleteKernelStack(IN PVOID StackBase,
StackPages = BYTES_TO_PAGES(GuiStack ?
KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
/* Acquire the PFN lock */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
//
// Loop them
//
@ -56,10 +61,22 @@ MmDeleteKernelStack(IN PVOID StackBase,
//
if (PointerPte->u.Hard.Valid == 1)
{
//
// Nuke it
//
MmReleasePageMemoryConsumer(MC_NPPOOL, PFN_FROM_PTE(PointerPte));
/* Get the PTE's page */
PageFrameNumber = PFN_FROM_PTE(PointerPte);
Pfn1 = MiGetPfnEntry(PageFrameNumber);
#if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
/* Now get the page of the page table mapping it */
PageTableFrameNumber = Pfn1->u4.PteFrame;
Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
/* Remove a shared reference, since the page is going away */
MiDecrementShareCount(Pfn2, PageTableFrameNumber);
#endif
/* Set the special pending delete marker */
Pfn1->PteAddress = (PMMPTE)((ULONG_PTR)Pfn1->PteAddress | 1);
/* And now delete the actual stack page */
MiDecrementShareCount(Pfn1, PageFrameNumber);
}
//
@ -73,6 +90,9 @@ MmDeleteKernelStack(IN PVOID StackBase,
//
ASSERT(PointerPte->u.Hard.Valid == 0);
/* Release the PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
//
// Release the PTEs
//
@ -154,15 +174,14 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
//
PointerPte++;
//
// Get a page
//
PageFrameIndex = MmAllocPage(MC_NPPOOL);
TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
/* Get a page */
PageFrameIndex = MiRemoveAnyPage(0);
//
// Write it
//
/* Initialize the PFN entry for this page */
MiInitializePfn(PageFrameIndex, PointerPte, 1);
/* Write the valid PTE */
TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
ASSERT(PointerPte->u.Hard.Valid == 0);
ASSERT(TempPte.u.Hard.Valid == 1);
*PointerPte = TempPte;
@ -250,13 +269,14 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
//
while (LimitPte >= NewLimitPte)
{
//
// Get a page
//
PageFrameIndex = MmAllocPage(MC_NPPOOL);
TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
/* Get a page */
PageFrameIndex = MiRemoveAnyPage(0);
/* Initialize the PFN entry for this page */
MiInitializePfn(PageFrameIndex, LimitPte, 1);
/* Write the valid PTE */
TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
ASSERT(LimitPte->u.Hard.Valid == 0);
ASSERT(TempPte.u.Hard.Valid == 1);
*LimitPte-- = TempPte;