diff --git a/reactos/ntoskrnl/mm/ARM3/procsup.c b/reactos/ntoskrnl/mm/ARM3/procsup.c index 387c3d21612..e5ad64d65ab 100644 --- a/reactos/ntoskrnl/mm/ARM3/procsup.c +++ b/reactos/ntoskrnl/mm/ARM3/procsup.c @@ -199,6 +199,9 @@ MmDeleteTeb(IN PEPROCESS Process, ASSERT(VadTree->NumberGenericTableElements >= 1); MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree); + /* Delete the pages */ + MiDeleteVirtualAddresses((ULONG_PTR)Teb, TebEnd, NULL); + /* Release the working set */ MiUnlockProcessWorkingSet(Process, Thread); @@ -219,7 +222,7 @@ MmDeleteKernelStack(IN PVOID StackBase, IN BOOLEAN GuiStack) { PMMPTE PointerPte; - PFN_NUMBER PageFrameNumber;//, PageTableFrameNumber; + PFN_NUMBER PageFrameNumber, PageTableFrameNumber; PFN_COUNT StackPages; PMMPFN Pfn1;//, Pfn2; ULONG i; @@ -253,13 +256,14 @@ MmDeleteKernelStack(IN PVOID StackBase, /* 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! +#if 1 // 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); + //Pfn2 = MiGetPfnEntry(PageTableFrameNumber); /* Remove a shared reference, since the page is going away */ - MiDecrementShareCount(Pfn2, PageTableFrameNumber); + DPRINT("SystemPTE PDE: %lx\n", PageTableFrameNumber); + //MiDecrementShareCount(Pfn2, PageTableFrameNumber); #endif /* Set the special pending delete marker */ MI_SET_PFN_DELETED(Pfn1); @@ -1340,6 +1344,102 @@ MmCleanProcessAddressSpace(IN PEPROCESS Process) MmUnlockAddressSpace(&Process->Vm); } +VOID +NTAPI +MmDeleteProcessAddressSpace2(IN PEPROCESS Process) +{ + PMMPFN Pfn1, Pfn2; + KIRQL OldIrql; + PFN_NUMBER PageFrameIndex; + PULONG PageDir; + ULONG i; + + //ASSERT(Process->CommitCharge == 0); + + /* Delete the shared user data section (Should be done in clean, not delete) */ + ASSERT(MmHighestUserAddress > (PVOID)USER_SHARED_DATA); + KeAttachProcess(&Process->Pcb); + //DPRINT1("Killing shared user data page no longer works -- has someone changed ARM3 in a way to make this fail now?\n"); + //MiDeleteVirtualAddresses(USER_SHARED_DATA, USER_SHARED_DATA, NULL); + //DPRINT1("Done\n"); + KeDetachProcess(); + + /* Acquire the PFN lock */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + + /* Check for fully initialized process */ + if (Process->AddressSpaceInitialized == 2) + { + /* Map the PDE */ + PageDir = MmCreateHyperspaceMapping(Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT); + for (i = 0; i < ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i++) + { + /* Loop all page tables */ + if (PageDir[i] != 0) + { + /* Check if they are RosMm-owned */ + if (MI_IS_ROS_PFN(MiGetPfnEntry(PageDir[i] >> PAGE_SHIFT))) + { + /* Free them through the RosMm ABI */ + //DPRINT1("Freeing MC_SYSTEM: %lx\n", PageDir[i]); + MmReleasePageMemoryConsumer(MC_SYSTEM, PageDir[i] >> PAGE_SHIFT); + } + } + } + + /* Unmap the PDE */ + //DPRINT1("Done\n"); + MmDeleteHyperspaceMapping(PageDir); + + /* Map the working set page and its page table */ + Pfn1 = MiGetPfnEntry(Process->WorkingSetPage); + Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame); + + /* Nuke it */ + MI_SET_PFN_DELETED(Pfn1); + MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame); + MiDecrementShareCount(Pfn1, Process->WorkingSetPage); + ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); + + /* Now map hyperspace and its page table */ + PageFrameIndex = Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT; + Pfn1 = MiGetPfnEntry(PageFrameIndex); + Pfn2 = MiGetPfnEntry(Pfn1->u4.PteFrame); + + /* Nuke it */ + MI_SET_PFN_DELETED(Pfn1); + MiDecrementShareCount(Pfn2, Pfn1->u4.PteFrame); + MiDecrementShareCount(Pfn1, PageFrameIndex); + ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); + + /* Finally, nuke the PDE itself */ + PageFrameIndex = Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT; + Pfn1 = MiGetPfnEntry(PageFrameIndex); + MI_SET_PFN_DELETED(Pfn1); + MiDecrementShareCount(Pfn1, PageFrameIndex); + MiDecrementShareCount(Pfn1, PageFrameIndex); + + /* HACK: In Richard's original patch this ASSERT did work */ + //DPRINT1("Ref count: %lx %lx\n", Pfn1->u3.e2.ReferenceCount, Pfn1->u2.ShareCount); + //ASSERT((Pfn1->u3.e2.ReferenceCount == 0) || (Pfn1->u3.e1.WriteInProgress)); + } + else + { + /* A partly-initialized process should never exit through here */ + ASSERT(FALSE); + } + + /* Release the PFN lock */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + + /* No support for sessions yet */ + ASSERT(Process->Session == 0); + + /* Clear out the PDE pages */ + Process->Pcb.DirectoryTableBase[0] = 0; + Process->Pcb.DirectoryTableBase[1] = 0; +} + /* SESSION CODE TO MOVE TO SESSION.C ******************************************/ KGUARDED_MUTEX MiSessionIdMutex; diff --git a/reactos/ntoskrnl/mm/ARM3/virtual.c b/reactos/ntoskrnl/mm/ARM3/virtual.c index 33837040179..c9ad11ec69e 100644 --- a/reactos/ntoskrnl/mm/ARM3/virtual.c +++ b/reactos/ntoskrnl/mm/ARM3/virtual.c @@ -264,8 +264,21 @@ MiDeletePte(IN PMMPTE PointerPte, /* Drop the share count */ MiDecrementShareCount(Pfn1, PageFrameIndex); - /* No fork yet */ - if (PointerPte <= MiHighestUserPte) ASSERT(PrototypePte == Pfn1->PteAddress); + /* Either a fork, or this is the shared user data page */ + if (PointerPte <= MiHighestUserPte) + { + /* If it's not the shared user page, then crash, since there's no fork() yet */ + if ((PAGE_ALIGN(VirtualAddress) != (PVOID)USER_SHARED_DATA) || + (MmHighestUserAddress <= (PVOID)USER_SHARED_DATA)) + { + /* Must be some sort of memory corruption */ + KeBugCheckEx(MEMORY_MANAGEMENT, + 0x400, + (ULONG_PTR)PointerPte, + (ULONG_PTR)PrototypePte, + (ULONG_PTR)Pfn1->PteAddress); + } + } } else { @@ -284,7 +297,8 @@ MiDeletePte(IN PMMPTE PointerPte, ASSERT(Pfn1->u2.ShareCount == 1); /* FIXME: Drop the reference on the page table. For now, leak it until RosMM is gone */ - //MiDecrementShareCount(MiGetPfnEntry(Pfn1->u4.PteFrame), Pfn1->u4.PteFrame); + //DPRINT1("Dropping a ref...\n"); + MiDecrementShareCount(MiGetPfnEntry(Pfn1->u4.PteFrame), Pfn1->u4.PteFrame); /* Mark the PFN for deletion and dereference what should be the last ref */ MI_SET_PFN_DELETED(Pfn1); @@ -312,6 +326,7 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va, KIRQL OldIrql; BOOLEAN AddressGap = FALSE; PSUBSECTION Subsection; + PUSHORT UsedPageTableEntries; /* Get out if this is a fake VAD, RosMm will free the marea pages */ if ((Vad) && (Vad->u.VadFlags.Spare == 1)) return; @@ -368,6 +383,7 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va, /* Now we should have a valid PDE, mapped in, and still have some VA */ ASSERT(PointerPde->u.Hard.Valid == 1); ASSERT(Va <= EndingAddress); + UsedPageTableEntries = &MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Va)]; /* Check if this is a section VAD with gaps in it */ if ((AddressGap) && (LastPrototypePte)) @@ -397,6 +413,11 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va, TempPte = *PointerPte; if (TempPte.u.Long) { + DPRINT("Decrement used PTEs by address: %lx\n", Va); + (*UsedPageTableEntries)--; + ASSERT((*UsedPageTableEntries) < PTE_COUNT); + DPRINT("Refs: %lx\n", (*UsedPageTableEntries)); + /* Check if the PTE is actually mapped in */ if (TempPte.u.Long & 0xFFFFFC01) { @@ -456,6 +477,22 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va, /* The PDE should still be valid at this point */ 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)) + { + DPRINT("They are!\n"); + if (PointerPde->u.Long != 0) + { + DPRINT("PDE active: %lx in %16s\n", PointerPde->u.Hard.PageFrameNumber, CurrentProcess->ImageFileName); + + /* Delete the PTE proper */ + MiDeletePte(PointerPde, + MiPteToAddress(PointerPde), + CurrentProcess, + NULL); + } + } + /* Release the lock and get out if we're done */ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); if (Va > EndingAddress) return; diff --git a/reactos/ntoskrnl/mm/amd64/page.c b/reactos/ntoskrnl/mm/amd64/page.c index de5dd773d14..ab31c4789dc 100644 --- a/reactos/ntoskrnl/mm/amd64/page.c +++ b/reactos/ntoskrnl/mm/amd64/page.c @@ -188,29 +188,6 @@ MmDeletePageTablePfn(PFN_NUMBER PageFrameNumber, ULONG Level) } } -VOID -NTAPI -MmDeleteProcessPageDirectory(PEPROCESS Process) -{ - PFN_NUMBER TableBasePfn; - PMMPTE PageDir; - - /* Get the page directory PFN */ - TableBasePfn = Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT; - - /* Map the page directory in hyperspace */ - PageDir = (PMMPTE)MmCreateHyperspaceMapping(TableBasePfn); - - /* Free the hyperspace mapping page (ARM3) */ - //MmDeletePageTablePfn(PageDir[ADDR_TO_PDE_OFFSET(HYPERSPACE)].u.Hard.PageFrameNumber, 3); - - /* Delete the hyperspace mapping */ - MmDeleteHyperspaceMapping(PageDir); - - /* Recursively free the page directories */ - MmDeletePageTablePfn(TableBasePfn, 4); -} - static PMMPTE MiGetPteForProcess( diff --git a/reactos/ntoskrnl/mm/i386/page.c b/reactos/ntoskrnl/mm/i386/page.c index 24c69cfdcc5..72b04e5e755 100644 --- a/reactos/ntoskrnl/mm/i386/page.c +++ b/reactos/ntoskrnl/mm/i386/page.c @@ -198,62 +198,6 @@ ProtectToPTE(ULONG flProtect) return(Attributes); } -VOID -FORCEINLINE -MmDeletePageDirectoryEntry(PMMPDE PointerPde) -{ - KIRQL OldIrql; - PMMPFN Page; - - Page = MiGetPfnEntry(PointerPde->u.Hard.PageFrameNumber); - - /* This should not be a legacy allocation*/ - ASSERT(MI_IS_ROS_PFN(Page) == FALSE); - - OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); - - /* Free it using the ARM3 API */ - MI_SET_PFN_DELETED(Page); - MiDecrementShareCount(Page, PointerPde->u.Hard.PageFrameNumber); - - KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); -} - -VOID -NTAPI -MmDeleteProcessPageDirectory(PEPROCESS Process) -{ - PMMPDE PdeBase, PointerPde; - ULONG PdeOffset; - KIRQL OldIrql; - - /* Map the page directory in hyperspace */ - PdeBase = MiMapPageInHyperSpace(PsGetCurrentProcess(), - Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT, - &OldIrql); - - /* Loop the user land page directory */ - for (PdeOffset = 0; PdeOffset < MiGetPdeOffset(MmSystemRangeStart); PdeOffset++) - { - PointerPde = PdeBase + PdeOffset; - /* Check if a valid PDE exists here */ - if (PointerPde->u.Hard.Valid) - { - /* Free the page that backs it */ - MmDeletePageDirectoryEntry(PointerPde); - } - } - - /* Free the hyperspace mapping page (ARM3) */ - MmDeletePageDirectoryEntry(PdeBase + MiGetPdeOffset(HYPERSPACE)); - - /* Delete the hyperspace mapping */ - MiUnmapPageInHyperSpace(PsGetCurrentProcess(), PdeBase, OldIrql); - - /* Free the PDE page itself (ARM3) */ - MmDeletePageDirectoryEntry((PMMPDE)&Process->Pcb.DirectoryTableBase[0]); -} - /* Taken from ARM3/pagfault.c */ BOOLEAN FORCEINLINE diff --git a/reactos/ntoskrnl/mm/marea.c b/reactos/ntoskrnl/mm/marea.c index 6e214395660..b6e62d811e8 100644 --- a/reactos/ntoskrnl/mm/marea.c +++ b/reactos/ntoskrnl/mm/marea.c @@ -994,6 +994,10 @@ MmMapMemoryArea(PVOID BaseAddress, } } +VOID +NTAPI +MmDeleteProcessAddressSpace2(IN PEPROCESS Process); + NTSTATUS NTAPI MmDeleteProcessAddressSpace(PEPROCESS Process) @@ -1036,11 +1040,10 @@ MmDeleteProcessAddressSpace(PEPROCESS Process) } } - MmDeleteProcessPageDirectory(Process); - MmUnlockAddressSpace(&Process->Vm); DPRINT("Finished MmReleaseMmInfo()\n"); + MmDeleteProcessAddressSpace2(Process); return(STATUS_SUCCESS); }