Author: sir_richard
Date: Mon Oct 18 13:10:54 2010
New Revision: 49193
URL: http://svn.reactos.org/svn/reactos?rev=49193&view=rev
Log:
[NTOS]: Complete the VAD-to-MAREA Synchronization hack by removing fake MAREAs that were added when inserting real VADs. To do this, we have to track the fake MAREA associated with a VAD, so we overload the FirstProtoTypePte field in the VAD, if this is NOT a section VAD (which we don't use yet). We'll figure something out for section VADs later.
[NTOS]: Now that VAD and MAREA views are synchronized, remove the VAD limit and let VADs be created at any address. Also do not create an arbitrary 16MB VAD memory area anymore. This basically now allows for as many PEB/TEBs as can fit in the address space, fixing the recent known regression that limited the number of threads a process could have.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c
trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Mon Oct 18 13:10:54 2010
@@ -45,9 +45,7 @@
#define MM_HIGHEST_VAD_ADDRESS \
(PVOID)((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (16 * PAGE_SIZE))
-
-/* The range 0x10000->0x7FEFFFFF is reserved for the ROSMM MAREA Allocator */
-#define MI_LOWEST_VAD_ADDRESS (PVOID)0x7FF00000
+#define MI_LOWEST_VAD_ADDRESS (PVOID)MM_LOWEST_USER_ADDRESS
#endif /* !_M_AMD64 */
Modified: trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/procsup.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] Mon Oct 18 13:10:54 2010
@@ -29,14 +29,14 @@
NTSTATUS Status;
PMEMORY_AREA MemoryArea;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
- PVOID AllocatedBase = (PVOID)MI_LOWEST_VAD_ADDRESS;
+ PVOID AllocatedBase = (PVOID)USER_SHARED_DATA;
BoundaryAddressMultiple.QuadPart = 0;
Status = MmCreateMemoryArea(&Process->Vm,
MEMORY_AREA_OWNED_BY_ARM3,
&AllocatedBase,
((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - 1) -
- (ULONG_PTR)MI_LOWEST_VAD_ADDRESS,
+ (ULONG_PTR)USER_SHARED_DATA,
PAGE_READWRITE,
&MemoryArea,
TRUE,
@@ -141,6 +141,8 @@
Process->VadRoot.NodeHint = Vad;
Vad->ControlArea = NULL; // For Memory-Area hack
Vad->FirstPrototypePte = NULL;
+ DPRINT("VAD: %p\n", Vad);
+ DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
/* Release the working set */
@@ -150,7 +152,6 @@
KeReleaseGuardedMutex(&Process->AddressCreationLock);
/* Return the status */
- DPRINT("Allocated PEB/TEB at: 0x%p for %16s\n", *Base, Process->ImageFileName);
return Status;
}
Modified: trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/vadnode.c [iso-8859-1] Mon Oct 18 13:10:54 2010
@@ -100,35 +100,16 @@
{
/* Insert it into the tree */
RtlpInsertAvlTreeNode(Table, NewNode, Parent, Result);
-}
-
-VOID
-NTAPI
-MiInsertVad(IN PMMVAD Vad,
- IN PEPROCESS Process)
-{
- TABLE_SEARCH_RESULT Result;
- PMMADDRESS_NODE Parent = NULL;
-
- /* Validate the VAD and set it as the current hint */
- ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
- Process->VadRoot.NodeHint = Vad;
-
- /* Find the parent VAD and where this child should be inserted */
- Result = RtlpFindAvlTableNodeOrParent(&Process->VadRoot, (PVOID)Vad->StartingVpn, &Parent);
- ASSERT(Result != TableFoundNode);
- ASSERT((Parent != NULL) || (Result == TableEmptyTree));
-
- /* Do the actual insert operation */
- MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
-
+
/* Now insert an ARM3 MEMORY_AREA for this node, unless the insert was already from the MEMORY_AREA code */
+ PMMVAD Vad = (PMMVAD)NewNode;
if (Vad->u.VadFlags.Spare == 0)
{
NTSTATUS Status;
PMEMORY_AREA MemoryArea;
PHYSICAL_ADDRESS BoundaryAddressMultiple;
SIZE_T Size;
+ PEPROCESS Process = CONTAINING_RECORD(Table, EPROCESS, VadRoot);
PVOID AllocatedBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
BoundaryAddressMultiple.QuadPart = 0;
Size = ((Vad->EndingVpn + 1) - Vad->StartingVpn) << PAGE_SHIFT;
@@ -142,7 +123,41 @@
0,
BoundaryAddressMultiple);
ASSERT(NT_SUCCESS(Status));
- }
+
+ /* Check if this is VM VAD */
+ if (Vad->ControlArea == NULL)
+ {
+ /* We store the reactos MEMORY_AREA here */
+ DPRINT("Storing %p in %p\n", MemoryArea, Vad);
+ Vad->FirstPrototypePte = (PMMPTE)MemoryArea;
+ }
+ else
+ {
+ /* This is a section VAD, this code doesn't happen yet */
+ ASSERT(FALSE);
+ }
+ }
+}
+
+VOID
+NTAPI
+MiInsertVad(IN PMMVAD Vad,
+ IN PEPROCESS Process)
+{
+ TABLE_SEARCH_RESULT Result;
+ PMMADDRESS_NODE Parent = NULL;
+
+ /* Validate the VAD and set it as the current hint */
+ ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
+ Process->VadRoot.NodeHint = Vad;
+
+ /* Find the parent VAD and where this child should be inserted */
+ Result = RtlpFindAvlTableNodeOrParent(&Process->VadRoot, (PVOID)Vad->StartingVpn, &Parent);
+ ASSERT(Result != TableFoundNode);
+ ASSERT((Parent != NULL) || (Result == TableEmptyTree));
+
+ /* Do the actual insert operation */
+ MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
}
VOID
@@ -162,6 +177,38 @@
/* Get a new hint, unless we're empty now, in which case nothing */
if (!Table->NumberGenericTableElements) Table->NodeHint = NULL;
else Table->NodeHint = Table->BalancedRoot.RightChild;
+ }
+
+ /* Free the node from ReactOS view as well */
+ PMMVAD Vad = (PMMVAD)Node;
+ if (Vad->u.VadFlags.Spare == 0)
+ {
+ PMEMORY_AREA MemoryArea;
+ PEPROCESS Process;
+
+ /* Check if this is VM VAD */
+ if (Vad->ControlArea == NULL)
+ {
+ /* We store the ReactOS MEMORY_AREA here */
+ MemoryArea = (PMEMORY_AREA)Vad->FirstPrototypePte;
+ if (MemoryArea)
+ {
+ /* Get the process */
+ Process = CONTAINING_RECORD(Table, EPROCESS, VadRoot);
+
+ /* We only create fake memory-areas for ARM3 VADs */
+ ASSERT(MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3);
+ ASSERT(MemoryArea->Vad == NULL);
+
+ /* Free it */
+ MmFreeMemoryArea(&Process->Vm, MemoryArea, NULL, NULL);
+ }
+ }
+ else
+ {
+ /* This is a section VAD, this code doesn't happen yet */
+ ASSERT(FALSE);
+ }
}
}
Modified: trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/virtual.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Mon Oct 18 13:10:54 2010
@@ -241,12 +241,12 @@
/* We usually only get a VAD when it's not a VM address */
if (Vad)
{
+ /* Get out if this is a fake VAD, RosMm will free the marea pages */
+ if (Vad->u.VadFlags.Spare == 1) return;
+
/* At process deletion, we may get a VAD, but it should be a VM VAD */
ASSERT(Vad->u.VadFlags.PrivateMemory);
- ASSERT(Vad->FirstPrototypePte == NULL);
-
- /* Get out if this is a fake VAD, RosMm will free the marea pages */
- if (Vad->u.VadFlags.Spare == 1) return;
+ //ASSERT(Vad->FirstPrototypePte == NULL); memory_area fuckers
}
/* In all cases, we don't support fork() yet */
Author: sir_richard
Date: Sun Oct 17 20:11:04 2010
New Revision: 49188
URL: http://svn.reactos.org/svn/reactos?rev=49188&view=rev
Log:
[NTOS]: Fix brainfart (an interesting bug we would've never hit, but a bug nevertheless).
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/virtual.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Sun Oct 17 20:11:04 2010
@@ -323,7 +323,7 @@
/* Otherwise, we exited because we hit a new PDE boundary, so start over */
PointerPde = MiAddressToPde(Va);
- } while (TRUE);
+ }
}
LONG
Author: sir_richard
Date: Sun Oct 17 20:02:17 2010
New Revision: 49187
URL: http://svn.reactos.org/svn/reactos?rev=49187&view=rev
Log:
[NTOS]: Use MI_SET_PFN_DELETED where we missed it.
[NTOS]: Implement support for deleting user-mode pageable VM addresses. Now when cleaning up the process address space, MiDeleteVirtualAddresses is called for the VADs, so this will now actually free the PEB/TEB pages that were previously getting leaked for each thread/process (a known regression I introduced when moving to VADs for PEB/TEB).
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Sun Oct 17 20:02:17 2010
@@ -1205,6 +1205,21 @@
IN ULONG Protect
);
+VOID
+NTAPI
+MiDeleteVirtualAddresses(
+ IN ULONG_PTR Va,
+ IN ULONG_PTR EndingAddress,
+ IN PMMVAD Vad
+);
+
+ULONG
+NTAPI
+MiMakeSystemAddressValid(
+ IN PVOID PageTableVirtualAddress,
+ IN PEPROCESS CurrentProcess
+);
+
//
// MiRemoveZeroPage will use inline code to zero out the page manually if only
// free pages are available. In some scenarios, we don't/can't run that piece of
Modified: trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/procsup.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] Sun Oct 17 20:02:17 2010
@@ -139,6 +139,8 @@
/* Insert the VAD */
ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
Process->VadRoot.NodeHint = Vad;
+ Vad->ControlArea = NULL; // For Memory-Area hack
+ Vad->FirstPrototypePte = NULL;
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
/* Release the working set */
@@ -258,7 +260,7 @@
MiDecrementShareCount(Pfn2, PageTableFrameNumber);
#endif
/* Set the special pending delete marker */
- Pfn1->PteAddress = (PMMPTE)((ULONG_PTR)Pfn1->PteAddress | 1);
+ MI_SET_PFN_DELETED(Pfn1);
/* And now delete the actual stack page */
MiDecrementShareCount(Pfn1, PageFrameNumber);
@@ -1174,7 +1176,6 @@
/* Enumerate the VADs */
VadTree = &Process->VadRoot;
- DPRINT("Cleaning up VADs: %d\n", VadTree->NumberGenericTableElements);
while (VadTree->NumberGenericTableElements)
{
/* Grab the current VAD */
@@ -1186,11 +1187,15 @@
/* Remove this VAD from the tree */
ASSERT(VadTree->NumberGenericTableElements >= 1);
MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
- DPRINT("Moving on: %d\n", VadTree->NumberGenericTableElements);
/* Only PEB/TEB VADs supported for now */
ASSERT(Vad->u.VadFlags.PrivateMemory == 1);
ASSERT(Vad->u.VadFlags.VadType == VadNone);
+
+ /* Delete the addresses */
+ MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
+ (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
+ Vad);
/* Release the working set */
MiUnlockProcessWorkingSet(Process, Thread);
Modified: trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/virtual.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Sun Oct 17 20:02:17 2010
@@ -28,6 +28,45 @@
OUT PULONG OldAccessProtection OPTIONAL);
/* PRIVATE FUNCTIONS **********************************************************/
+
+ULONG
+NTAPI
+MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress,
+ IN PEPROCESS CurrentProcess)
+{
+ NTSTATUS Status;
+ BOOLEAN LockChange = FALSE;
+
+ /* Must be a non-pool page table, since those are double-mapped already */
+ ASSERT(PageTableVirtualAddress > MM_HIGHEST_USER_ADDRESS);
+ ASSERT((PageTableVirtualAddress < MmPagedPoolStart) ||
+ (PageTableVirtualAddress > MmPagedPoolEnd));
+
+ /* Working set lock or PFN lock should be held */
+ ASSERT(KeAreAllApcsDisabled() == TRUE);
+
+ /* Check if the page table is valid */
+ while (!MmIsAddressValid(PageTableVirtualAddress))
+ {
+ /* Fault it in */
+ Status = MmAccessFault(FALSE, PageTableVirtualAddress, KernelMode, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ /* This should not fail */
+ KeBugCheckEx(KERNEL_DATA_INPAGE_ERROR,
+ 1,
+ Status,
+ (ULONG_PTR)CurrentProcess,
+ (ULONG_PTR)PageTableVirtualAddress);
+ }
+
+ /* This flag will be useful later when we do better locking */
+ LockChange = TRUE;
+ }
+
+ /* Let caller know what the lock state is */
+ return LockChange;
+}
PFN_NUMBER
NTAPI
@@ -126,6 +165,167 @@
return ActualPages;
}
+VOID
+NTAPI
+MiDeletePte(IN PMMPTE PointerPte,
+ IN PVOID VirtualAddress,
+ IN PEPROCESS CurrentProcess)
+{
+ PMMPFN Pfn1;
+ MMPTE PteContents;
+ PFN_NUMBER PageFrameIndex;
+
+ /* PFN lock must be held */
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ /* Capture the PTE */
+ PteContents = *PointerPte;
+
+ /* We only support valid PTEs for now */
+ ASSERT(PteContents.u.Hard.Valid == 1);
+ ASSERT(PteContents.u.Soft.Prototype == 0);
+ ASSERT(PteContents.u.Soft.Transition == 0);
+
+ /* Get the PFN entry */
+ PageFrameIndex = PFN_FROM_PTE(&PteContents);
+ Pfn1 = MiGetPfnEntry(PageFrameIndex);
+
+ /* We don't support deleting prototype PTEs for now */
+ ASSERT(Pfn1->u3.e1.PrototypePte == 0);
+
+ /* Make sure the saved PTE address is valid */
+ if ((PMMPTE)((ULONG_PTR)Pfn1->PteAddress & ~0x1) != PointerPte)
+ {
+ /* The PFN entry is illegal, or invalid */
+ KeBugCheckEx(MEMORY_MANAGEMENT,
+ 0x401,
+ (ULONG_PTR)PointerPte,
+ PointerPte->u.Long,
+ (ULONG_PTR)Pfn1->PteAddress);
+ }
+
+ /* There should only be 1 shared reference count */
+ 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);
+
+ /* Mark the PFN for deletion and dereference what should be the last ref */
+ MI_SET_PFN_DELETED(Pfn1);
+ MiDecrementShareCount(Pfn1, PageFrameIndex);
+
+ /* We should eventually do this */
+ //CurrentProcess->NumberOfPrivatePages--;
+
+ /* Destroy the PTE and flush the TLB */
+ PointerPte->u.Long = 0;
+ KeFlushCurrentTb();
+}
+
+VOID
+NTAPI
+MiDeleteVirtualAddresses(IN ULONG_PTR Va,
+ IN ULONG_PTR EndingAddress,
+ IN PMMVAD Vad)
+{
+ PMMPTE PointerPte, PointerPde;
+ MMPTE TempPte;
+ PEPROCESS CurrentProcess;
+ KIRQL OldIrql;
+
+ /* Grab the process and PTE/PDE for the address being deleted */
+ CurrentProcess = PsGetCurrentProcess();
+ PointerPde = MiAddressToPde(Va);
+ PointerPte = MiAddressToPte(Va);
+
+ /* We usually only get a VAD when it's not a VM address */
+ if (Vad)
+ {
+ /* At process deletion, we may get a VAD, but it should be a VM VAD */
+ ASSERT(Vad->u.VadFlags.PrivateMemory);
+ ASSERT(Vad->FirstPrototypePte == NULL);
+
+ /* Get out if this is a fake VAD, RosMm will free the marea pages */
+ if (Vad->u.VadFlags.Spare == 1) return;
+ }
+
+ /* In all cases, we don't support fork() yet */
+ ASSERT(CurrentProcess->CloneRoot == NULL);
+
+ /* Loop the PTE for each VA */
+ while (TRUE)
+ {
+ /* First keep going until we find a valid PDE */
+ while (PointerPde->u.Long == 0)
+ {
+ /* Still no valid PDE, try the next 4MB (or whatever) */
+ PointerPde++;
+
+ /* Update the PTE on this new boundary */
+ PointerPte = MiPteToAddress(PointerPde);
+
+ /* Check if all the PDEs are invalid, so there's nothing to free */
+ Va = (ULONG_PTR)MiPteToAddress(PointerPte);
+ if (Va > EndingAddress) return;
+ }
+
+ /* Now check if the PDE is mapped in */
+ if (PointerPde->u.Hard.Valid == 0)
+ {
+ /* It isn't, so map it in */
+ PointerPte = MiPteToAddress(PointerPde);
+ MiMakeSystemAddressValid(PointerPte, CurrentProcess);
+ }
+
+ /* Now we should have a valid PDE, mapped in, and still have some VA */
+ ASSERT(PointerPde->u.Hard.Valid == 1);
+ ASSERT(Va <= EndingAddress);
+
+ /* Lock the PFN Database while we delete the PTEs */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ do
+ {
+ /* Capture the PDE and make sure it exists */
+ TempPte = *PointerPte;
+ if (TempPte.u.Long)
+ {
+ /* Check if the PTE is actually mapped in */
+ if (TempPte.u.Long & 0xFFFFFC01)
+ {
+ /* It is, we don't support prototype PTEs for now though */
+ ASSERT(TempPte.u.Soft.Prototype == 0);
+
+ /* Delete the PTE proper */
+ MiDeletePte(PointerPte, (PVOID)Va, CurrentProcess);
+ }
+ else
+ {
+ /* The PTE was never mapped, just nuke it here */
+ PointerPte->u.Long = 0;
+ }
+ }
+
+ /* Update the address and PTE for it */
+ Va += PAGE_SIZE;
+ PointerPte++;
+
+ /* Making sure the PDE is still valid */
+ ASSERT(PointerPde->u.Hard.Valid == 1);
+ }
+ while ((Va & (PDE_MAPPED_VA - 1)) && (Va <= EndingAddress));
+
+ /* The PDE should still be valid at this point */
+ ASSERT(PointerPde->u.Hard.Valid == 1);
+
+ /* Release the lock and get out if we're done */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ if (Va > EndingAddress) return;
+
+ /* Otherwise, we exited because we hit a new PDE boundary, so start over */
+ PointerPde = MiAddressToPde(Va);
+ } while (TRUE);
+}
+
LONG
MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo,
OUT PBOOLEAN HaveBadAddress,