diff --git a/reactos/ntoskrnl/mm/ARM3/contmem.c b/reactos/ntoskrnl/mm/ARM3/contmem.c index 0d7628bf88f..2f3eda954e2 100644 --- a/reactos/ntoskrnl/mm/ARM3/contmem.c +++ b/reactos/ntoskrnl/mm/ARM3/contmem.c @@ -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); // diff --git a/reactos/ntoskrnl/mm/ARM3/miarm.h b/reactos/ntoskrnl/mm/ARM3/miarm.h index 193eb04e698..4c5e3bc441b 100644 --- a/reactos/ntoskrnl/mm/ARM3/miarm.h +++ b/reactos/ntoskrnl/mm/ARM3/miarm.h @@ -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( diff --git a/reactos/ntoskrnl/mm/ARM3/pagfault.c b/reactos/ntoskrnl/mm/ARM3/pagfault.c index 7455a100af1..ceff13bcc8d 100644 --- a/reactos/ntoskrnl/mm/ARM3/pagfault.c +++ b/reactos/ntoskrnl/mm/ARM3/pagfault.c @@ -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); diff --git a/reactos/ntoskrnl/mm/ARM3/pfnlist.c b/reactos/ntoskrnl/mm/ARM3/pfnlist.c index ff17eb0b3c8..b70e191c030 100644 --- a/reactos/ntoskrnl/mm/ARM3/pfnlist.c +++ b/reactos/ntoskrnl/mm/ARM3/pfnlist.c @@ -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 */ diff --git a/reactos/ntoskrnl/mm/ARM3/procsup.c b/reactos/ntoskrnl/mm/ARM3/procsup.c index 8f1e6b732c1..e82a567d329 100644 --- a/reactos/ntoskrnl/mm/ARM3/procsup.c +++ b/reactos/ntoskrnl/mm/ARM3/procsup.c @@ -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;