Author: sir_richard
Date: Tue Oct 19 17:07:11 2010
New Revision: 49206
URL:
http://svn.reactos.org/svn/reactos?rev=49206&view=rev
Log:
[NTOS]: Add support for unmapping ARM3 sections, destroying segments and control areas,
and clearing out subsection PTEs.
[NTOS]: Add support to MiDeletePte/MiDeleteVirtualAddresses to handle Section VADs.
[NTOS]: Add support to MiDeletePte to handle valid, prototype PTEs.
[NTOS]: Add MEM_TOP_DOWN support to ARM3 section code.
[NTOS]: Add support for unmapping currently mapped ARM3 section views at process
termination.
[NTOS]: Use the new ARM3 section code for mapping the NLS section in the system (tests the
system-view mapping code) and in each new process (tests the data-mapping code). Section
is correctly unmapped at process termination time!
Modified:
trunk/reactos/ntoskrnl/ex/init.c
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
trunk/reactos/ntoskrnl/mm/ARM3/section.c
trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
Modified: trunk/reactos/ntoskrnl/ex/init.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/init.c?rev=492…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/init.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ex/init.c [iso-8859-1] Tue Oct 19 17:07:11 2010
@@ -296,7 +296,7 @@
NULL,
&SectionSize,
PAGE_READWRITE,
- SEC_COMMIT,
+ SEC_COMMIT | 0x1,
NULL);
if (!NT_SUCCESS(Status))
{
@@ -319,7 +319,7 @@
}
/* Map the NLS Section in system space */
- Status = MmMapViewInSystemSpace(ExpNlsSectionPointer,
+ Status = MmMapViewInSystemSpace((PVOID)((ULONG_PTR)ExpNlsSectionPointer | 0x1),
&SectionBase,
&ExpNlsTableSize);
if (!NT_SUCCESS(Status))
@@ -349,7 +349,7 @@
SectionBase = NULL;
/* Map the section in the system process */
- Status = MmMapViewOfSection(ExpNlsSectionPointer,
+ Status = MmMapViewOfSection((PVOID)((ULONG_PTR)ExpNlsSectionPointer | 0x1),
PsGetCurrentProcess(),
&SectionBase,
0L,
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] Tue Oct 19 17:07:11 2010
@@ -832,6 +832,22 @@
KeLeaveGuardedRegion();
}
+//
+// Returns the ProtoPTE inside a VAD for the given VPN
+//
+FORCEINLINE
+PMMPTE
+MI_GET_PROTOTYPE_PTE_FOR_VPN(IN PMMVAD Vad,
+ IN ULONG_PTR Vpn)
+{
+ PMMPTE ProtoPte;
+
+ /* Find the offset within the VAD's prototype PTEs */
+ ProtoPte = Vad->FirstPrototypePte + ((Vpn - Vad->StartingVpn) *
sizeof(MMPTE));
+ ASSERT(ProtoPte <= Vad->LastContiguousPte);
+ return ProtoPte;
+}
+
BOOLEAN
NTAPI
MmArmInitSystem(
@@ -1224,6 +1240,27 @@
IN PVOID PageTableVirtualAddress,
IN PEPROCESS CurrentProcess
);
+
+ULONG
+NTAPI
+MiMakeSystemAddressValidPfn(
+ IN PVOID VirtualAddress,
+ IN KIRQL OldIrql
+);
+
+VOID
+NTAPI
+MiRemoveMappedView(
+ IN PEPROCESS CurrentProcess,
+ IN PMMVAD Vad
+);
+
+PSUBSECTION
+NTAPI
+MiLocateSubsection(
+ IN PMMVAD Vad,
+ IN ULONG_PTR Vpn
+);
//
// MiRemoveZeroPage will use inline code to zero out the page manually if only
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] Tue Oct 19 17:07:11 2010
@@ -581,7 +581,7 @@
//
// Map NLS Tables
//
- Status = MmMapViewOfSection(ExpNlsSectionPointer,
+ Status = MmMapViewOfSection((PVOID)((ULONG_PTR)ExpNlsSectionPointer | 0x1),
(PEPROCESS)Process,
&TableBase,
0,
@@ -1186,17 +1186,25 @@
ASSERT(VadTree->NumberGenericTableElements >= 1);
MiRemoveNode((PMMADDRESS_NODE)Vad, VadTree);
- /* Only PEB/TEB VADs supported for now */
- ASSERT(Vad->u.VadFlags.PrivateMemory == 1);
+ /* Only regular VADs supported for now */
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);
+ /* Check if this is a section VAD */
+ if (!(Vad->u.VadFlags.PrivateMemory) && (Vad->ControlArea))
+ {
+ /* Remove the view */
+ MiRemoveMappedView(Process, Vad);
+ }
+ else
+ {
+ /* Delete the addresses */
+ MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
+ (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE
- 1),
+ Vad);
+
+ /* Release the working set */
+ MiUnlockProcessWorkingSet(Process, Thread);
+ }
/* Skip ARM3 fake VADs, they'll be freed by MmDeleteProcessAddresSpace */
if (Vad->u.VadFlags.Spare == 1)
Modified: trunk/reactos/ntoskrnl/mm/ARM3/section.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/section.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] Tue Oct 19 17:07:11 2010
@@ -391,6 +391,188 @@
/* Release the PFN lock and return success */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
return STATUS_SUCCESS;
+}
+
+PSUBSECTION
+NTAPI
+MiLocateSubsection(IN PMMVAD Vad,
+ IN ULONG_PTR Vpn)
+{
+ PSUBSECTION Subsection;
+ PCONTROL_AREA ControlArea;
+ ULONG PteOffset;
+
+ /* Get the control area */
+ ControlArea = Vad->ControlArea;
+ ASSERT(ControlArea->u.Flags.Rom == 0);
+ ASSERT(ControlArea->u.Flags.Image == 0);
+ ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
+
+ /* Get the subsection */
+ Subsection = (PSUBSECTION)(ControlArea + 1);
+
+ /* We only support single-subsection segments */
+ ASSERT(Subsection->SubsectionBase != NULL);
+ ASSERT(Vad->FirstPrototypePte >= Subsection->SubsectionBase);
+ ASSERT(Vad->FirstPrototypePte <
&Subsection->SubsectionBase[Subsection->PtesInSubsection]);
+
+ /* Compute the PTE offset */
+ PteOffset = (ULONG_PTR)Vpn - Vad->StartingVpn;
+ PteOffset += Vad->FirstPrototypePte - Subsection->SubsectionBase;
+
+ /* Again, we only support single-subsection segments */
+ ASSERT(PteOffset < 0xF0000000);
+ ASSERT(PteOffset < Subsection->PtesInSubsection);
+
+ /* Return the subsection */
+ return Subsection;
+}
+
+VOID
+NTAPI
+MiSegmentDelete(IN PSEGMENT Segment)
+{
+ PCONTROL_AREA ControlArea;
+ SEGMENT_FLAGS SegmentFlags;
+ PSUBSECTION Subsection;
+ PMMPTE PointerPte, LastPte, PteForProto;
+ MMPTE TempPte;
+ KIRQL OldIrql;
+
+ /* Capture data */
+ SegmentFlags = Segment->SegmentFlags;
+ ControlArea = Segment->ControlArea;
+
+ /* Make sure control area is on the right delete path */
+ ASSERT(ControlArea->u.Flags.BeingDeleted == 1);
+ ASSERT(ControlArea->WritableUserReferences == 0);
+
+ /* These things are not supported yet */
+ ASSERT(ControlArea->DereferenceList.Flink == NULL);
+ ASSERT(!(ControlArea->u.Flags.Image) & !(ControlArea->u.Flags.File));
+ ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
+ ASSERT(ControlArea->u.Flags.Rom == 0);
+
+ /* Get the subsection and PTEs for this segment */
+ Subsection = (PSUBSECTION)(ControlArea + 1);
+ PointerPte = Subsection->SubsectionBase;
+ LastPte = PointerPte + Segment->NonExtendedPtes;
+
+ /* Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Check if the master PTE is invalid */
+ PteForProto = MiAddressToPte(PointerPte);
+ if (!PteForProto->u.Hard.Valid)
+ {
+ /* Fault it in */
+ MiMakeSystemAddressValidPfn(PointerPte, OldIrql);
+ }
+
+ /* Loop all the segment PTEs */
+ while (PointerPte < LastPte)
+ {
+ /* Check if it's time to switch master PTEs if we passed a PDE boundary */
+ if (!((ULONG_PTR)PointerPte & (PD_SIZE - 1)) &&
+ (PointerPte != Subsection->SubsectionBase))
+ {
+ /* Check if the master PTE is invalid */
+ PteForProto = MiAddressToPte(PointerPte);
+ if (!PteForProto->u.Hard.Valid)
+ {
+ /* Fault it in */
+ MiMakeSystemAddressValidPfn(PointerPte, OldIrql);
+ }
+ }
+
+ /* This should be a prototype PTE */
+ TempPte = *PointerPte;
+ ASSERT(SegmentFlags.LargePages == 0);
+ ASSERT(TempPte.u.Hard.Valid == 0);
+ ASSERT(TempPte.u.Soft.Prototype == 1);
+
+ /* Zero the PTE and keep going */
+ PointerPte->u.Long = 0;
+ PointerPte++;
+ }
+
+ /* Release the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Free the structures */
+ ExFreePool(ControlArea);
+ ExFreePool(Segment);
+}
+
+VOID
+NTAPI
+MiCheckControlArea(IN PCONTROL_AREA ControlArea,
+ IN KIRQL OldIrql)
+{
+ BOOLEAN DeleteSegment = FALSE;
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ /* Check if this is the last reference or view */
+ if (!(ControlArea->NumberOfMappedViews) &&
+ !(ControlArea->NumberOfSectionReferences))
+ {
+ /* There should be no more user references either */
+ ASSERT(ControlArea->NumberOfUserReferences == 0);
+
+ /* Not yet supported */
+ ASSERT(ControlArea->FilePointer == NULL);
+
+ /* The control area is being destroyed */
+ ControlArea->u.Flags.BeingDeleted = TRUE;
+ DeleteSegment = TRUE;
+ }
+
+ /* Release the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Delete the segment if needed */
+ if (DeleteSegment)
+ {
+ /* No more user write references at all */
+ ASSERT(ControlArea->WritableUserReferences == 0);
+ MiSegmentDelete(ControlArea->Segment);
+ }
+}
+
+VOID
+NTAPI
+MiRemoveMappedView(IN PEPROCESS CurrentProcess,
+ IN PMMVAD Vad)
+{
+ KIRQL OldIrql;
+ PCONTROL_AREA ControlArea;
+
+ /* Get the control area */
+ ControlArea = Vad->ControlArea;
+
+ /* We only support non-extendable, non-image, pagefile-backed regular sections */
+ ASSERT(Vad->u.VadFlags.VadType == VadNone);
+ ASSERT(Vad->u2.VadFlags2.ExtendableFile == FALSE);
+ ASSERT(ControlArea);
+ ASSERT(ControlArea->FilePointer == NULL);
+
+ /* Delete the actual virtual memory pages */
+ MiDeleteVirtualAddresses(Vad->StartingVpn << PAGE_SHIFT,
+ (Vad->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
+ Vad);
+
+ /* Release the working set */
+ MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
+
+ /* Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Remove references */
+ ControlArea->NumberOfMappedViews--;
+ ControlArea->NumberOfUserReferences--;
+
+ /* Check if it should be destroyed */
+ MiCheckControlArea(ControlArea, OldIrql);
}
NTSTATUS
@@ -505,7 +687,6 @@
/* These flags/parameters are not supported */
ASSERT((AllocationType & MEM_DOS_LIM) == 0);
ASSERT((AllocationType & MEM_RESERVE) == 0);
- ASSERT((AllocationType & MEM_TOP_DOWN) == 0);
ASSERT(Process->VmTopDown == 0);
ASSERT(Section->u.Flags.CopyOnWrite == FALSE);
ASSERT(ZeroBits == 0);
@@ -553,13 +734,28 @@
/* Did the caller specify an address? */
if (!(*BaseAddress))
{
- /* No, find an address bottom-up */
- Status = MiFindEmptyAddressRangeInTree(*ViewSize,
- _64K,
- &Process->VadRoot,
-
(PMMADDRESS_NODE*)&Process->VadFreeHint,
- &StartAddress);
- ASSERT(NT_SUCCESS(Status));
+ /* Which way should we search? */
+ if (AllocationType & MEM_TOP_DOWN)
+ {
+ /* No, find an address top-down */
+ Status = MiFindEmptyAddressRangeDownTree(*ViewSize,
+ (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
+ _64K,
+ &Process->VadRoot,
+ &StartAddress,
+
(PMMADDRESS_NODE*)&Process->VadFreeHint);
+ ASSERT(NT_SUCCESS(Status));
+ }
+ else
+ {
+ /* No, find an address bottom-up */
+ Status = MiFindEmptyAddressRangeInTree(*ViewSize,
+ _64K,
+ &Process->VadRoot,
+
(PMMADDRESS_NODE*)&Process->VadFreeHint,
+ &StartAddress);
+ ASSERT(NT_SUCCESS(Status));
+ }
}
else
{
@@ -1179,8 +1375,11 @@
SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE |
SEC_NO_CHANGE)))
{
- DPRINT1("Bogus allocation attribute: %lx\n", AllocationAttributes);
- return STATUS_INVALID_PARAMETER_6;
+ if (!(AllocationAttributes & 1))
+ {
+ DPRINT1("Bogus allocation attribute: %lx\n",
AllocationAttributes);
+ return STATUS_INVALID_PARAMETER_6;
+ }
}
/* Check for no allocation type */
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] Tue Oct 19 17:07:11 2010
@@ -62,6 +62,46 @@
/* This flag will be useful later when we do better locking */
LockChange = TRUE;
+ }
+
+ /* Let caller know what the lock state is */
+ return LockChange;
+}
+
+ULONG
+NTAPI
+MiMakeSystemAddressValidPfn(IN PVOID VirtualAddress,
+ IN KIRQL OldIrql)
+{
+ NTSTATUS Status;
+ BOOLEAN LockChange = FALSE;
+
+ /* Must be e kernel address */
+ ASSERT(VirtualAddress > MM_HIGHEST_USER_ADDRESS);
+
+ /* Check if the page is valid */
+ while (!MmIsAddressValid(VirtualAddress))
+ {
+ /* Release the PFN database */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Fault it in */
+ Status = MmAccessFault(FALSE, VirtualAddress, KernelMode, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ /* This should not fail */
+ KeBugCheckEx(KERNEL_DATA_INPAGE_ERROR,
+ 3,
+ Status,
+ 0,
+ (ULONG_PTR)VirtualAddress);
+ }
+
+ /* This flag will be useful later when we do better locking */
+ LockChange = TRUE;
+
+ /* Lock the PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
}
/* Let caller know what the lock state is */
@@ -169,11 +209,13 @@
NTAPI
MiDeletePte(IN PMMPTE PointerPte,
IN PVOID VirtualAddress,
- IN PEPROCESS CurrentProcess)
+ IN PEPROCESS CurrentProcess,
+ IN PMMPTE PrototypePte)
{
PMMPFN Pfn1;
MMPTE TempPte;
PFN_NUMBER PageFrameIndex;
+ PMMPDE PointerPde;
/* PFN lock must be held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
@@ -183,39 +225,74 @@
/* We only support valid PTEs for now */
ASSERT(TempPte.u.Hard.Valid == 1);
- ASSERT(TempPte.u.Soft.Prototype == 0);
- ASSERT(TempPte.u.Soft.Transition == 0);
+ if (TempPte.u.Hard.Valid == 0)
+ {
+ /* Invalid PTEs not supported yet */
+ ASSERT(TempPte.u.Soft.Prototype == 0);
+ ASSERT(TempPte.u.Soft.Transition == 0);
+ }
/* Get the PFN entry */
PageFrameIndex = PFN_FROM_PTE(&TempPte);
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--;
+ /* Check if this is a valid, prototype PTE */
+ if (Pfn1->u3.e1.PrototypePte == 1)
+ {
+ /* Get the PDE and make sure it's faulted in */
+ PointerPde = MiAddressToPde(PointerPte);
+ if (PointerPde->u.Hard.Valid == 0)
+ {
+#if (_MI_PAGING_LEVELS == 2)
+ /* Could be paged pool access from a new process -- synchronize the page
directories */
+ if (!NT_SUCCESS(MiCheckPdeForPagedPool(VirtualAddress)))
+ {
+#endif
+ /* The PDE must be valid at this point */
+ KeBugCheckEx(MEMORY_MANAGEMENT,
+ 0x61940,
+ (ULONG_PTR)PointerPte,
+ PointerPte->u.Long,
+ (ULONG_PTR)VirtualAddress);
+ }
+#if (_MI_PAGING_LEVELS == 2)
+ }
+#endif
+ /* FIXME: Drop the reference on the page table. For now, leak it until RosMM is
gone */
+ //MiDecrementShareCount(MiGetPfnEntry(PFN_FROM_PTE(PointerPde)),
PFN_FROM_PDE(PointerPde));
+
+ /* Drop the share count */
+ MiDecrementShareCount(Pfn1, PageFrameIndex);
+
+ /* No fork yet */
+ if (PointerPte <= MiHighestUserPte) ASSERT(PrototypePte ==
Pfn1->PteAddress);
+ }
+ else
+ {
+ /* 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;
@@ -228,27 +305,34 @@
IN ULONG_PTR EndingAddress,
IN PMMVAD Vad)
{
- PMMPTE PointerPte, PointerPde;
+ PMMPTE PointerPte, PointerPde, PrototypePte, LastPrototypePte;
MMPTE TempPte;
PEPROCESS CurrentProcess;
KIRQL OldIrql;
+ BOOLEAN AddressGap = FALSE;
+ PSUBSECTION Subsection;
+
+ /* Get out if this is a fake VAD, RosMm will free the marea pages */
+ if ((Vad) && (Vad->u.VadFlags.Spare == 1)) return;
/* 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)
- {
- /* 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); memory_area fuckers
- }
-
+ /* Check if this is a section VAD or a VM VAD */
+ if (!(Vad) || (Vad->u.VadFlags.PrivateMemory) || !(Vad->FirstPrototypePte))
+ {
+ /* Don't worry about prototypes */
+ PrototypePte = LastPrototypePte = NULL;
+ }
+ else
+ {
+ /* Get the prototype PTE */
+ PrototypePte = Vad->FirstPrototypePte;
+ LastPrototypePte = Vad->FirstPrototypePte + 1;
+ }
+
/* In all cases, we don't support fork() yet */
ASSERT(CurrentProcess->CloneRoot == NULL);
@@ -256,8 +340,11 @@
while (TRUE)
{
/* First keep going until we find a valid PDE */
- while (PointerPde->u.Long == 0)
- {
+ while (!PointerPde->u.Long)
+ {
+ /* There are gaps in the address space */
+ AddressGap = TRUE;
+
/* Still no valid PDE, try the next 4MB (or whatever) */
PointerPde++;
@@ -270,7 +357,7 @@
}
/* Now check if the PDE is mapped in */
- if (PointerPde->u.Hard.Valid == 0)
+ if (!PointerPde->u.Hard.Valid)
{
/* It isn't, so map it in */
PointerPte = MiPteToAddress(PointerPde);
@@ -280,6 +367,26 @@
/* Now we should have a valid PDE, mapped in, and still have some VA */
ASSERT(PointerPde->u.Hard.Valid == 1);
ASSERT(Va <= EndingAddress);
+
+ /* Check if this is a section VAD with gaps in it */
+ if ((AddressGap) && (LastPrototypePte))
+ {
+ /* We need to skip to the next correct prototype PTE */
+ PrototypePte = MI_GET_PROTOTYPE_PTE_FOR_VPN(Vad, Va >> PAGE_SHIFT);
+
+ /* And we need the subsection to skip to the next last prototype PTE */
+ Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
+ if (Subsection)
+ {
+ /* Found it! */
+ LastPrototypePte =
&Subsection->SubsectionBase[Subsection->PtesInSubsection];
+ }
+ else
+ {
+ /* No more subsections, we are done with prototype PTEs */
+ PrototypePte = NULL;
+ }
+ }
/* Lock the PFN Database while we delete the PTEs */
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
@@ -292,11 +399,41 @@
/* 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);
+ /* Are we dealing with section VAD? */
+ if ((LastPrototypePte) && (PrototypePte >
LastPrototypePte))
+ {
+ /* We need to skip to the next correct prototype PTE */
+ PrototypePte = MI_GET_PROTOTYPE_PTE_FOR_VPN(Vad, Va >>
PAGE_SHIFT);
+
+ /* And we need the subsection to skip to the next last prototype
PTE */
+ Subsection = MiLocateSubsection(Vad, Va >> PAGE_SHIFT);
+ if (Subsection)
+ {
+ /* Found it! */
+ LastPrototypePte =
&Subsection->SubsectionBase[Subsection->PtesInSubsection];
+ }
+ else
+ {
+ /* No more subsections, we are done with prototype PTEs */
+ PrototypePte = NULL;
+ }
+ }
- /* Delete the PTE proper */
- MiDeletePte(PointerPte, (PVOID)Va, CurrentProcess);
+ /* Check for prototype PTE */
+ if ((TempPte.u.Hard.Valid == 0) &&
+ (TempPte.u.Soft.Prototype == 1))
+ {
+ /* Just nuke it */
+ PointerPte->u.Long = 0;
+ }
+ else
+ {
+ /* Delete the PTE proper */
+ MiDeletePte(PointerPte,
+ (PVOID)Va,
+ CurrentProcess,
+ PrototypePte);
+ }
}
else
{
@@ -308,6 +445,7 @@
/* Update the address and PTE for it */
Va += PAGE_SIZE;
PointerPte++;
+ PrototypePte++;
/* Making sure the PDE is still valid */
ASSERT(PointerPde->u.Hard.Valid == 1);
@@ -323,6 +461,7 @@
/* Otherwise, we exited because we hit a new PDE boundary, so start over */
PointerPde = MiAddressToPde(Va);
+ AddressGap = FALSE;
}
}