Author: sir_richard
Date: Mon Nov 8 12:35:50 2010
New Revision: 49525
URL:
http://svn.reactos.org/svn/reactos?rev=49525&view=rev
Log:
[NTOS]: Assign a working set to the system process and correctly initialize its address
space.
[NTOS]: Assign the working set list address, system-wide, but per-process (in
hyperspace).
[NTOS]: Give every process its working set page, and store it. Build a bogus working set
list (MMWSL).
[NTOS]: Use the process working set list (MMWSL) to track page table references during
faults, just as Windows does.
[NTOS]: Correctly initialize the colored page list heads and assert their validity.
Modified:
trunk/reactos/ntoskrnl/include/internal/i386/mm.h
trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
Modified: trunk/reactos/ntoskrnl/include/internal/i386/mm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/i386/mm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/i386/mm.h [iso-8859-1] Mon Nov 8 12:35:50
2010
@@ -84,7 +84,11 @@
#define MI_MAPPING_RANGE_START (ULONG)HYPER_SPACE
#define MI_MAPPING_RANGE_END (MI_MAPPING_RANGE_START + \
MI_HYPERSPACE_PTES * PAGE_SIZE)
-#define MI_ZERO_PTE (PMMPTE)(MI_MAPPING_RANGE_END + \
+#define MI_DUMMY_PTE (PMMPTE)(MI_MAPPING_RANGE_END + \
+ PAGE_SIZE)
+#define MI_VAD_BITMAP (PMMPTE)(MI_DUMMY_PTE + \
+ PAGE_SIZE)
+#define MI_WORKING_SET_LIST (PMMPTE)(MI_VAD_BITMAP + \
PAGE_SIZE)
/* On x86, these two are the same */
Modified: trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/i386/init…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c [iso-8859-1] Mon Nov 8 12:35:50 2010
@@ -160,7 +160,9 @@
MMPTE TempPde, TempPte;
PVOID NonPagedPoolExpansionVa;
KIRQL OldIrql;
-
+ PMMPFN Pfn1;
+ ULONG Flags;
+
/* Check for kernel stack size that's too big */
if (MmLargeStackSize > (KERNEL_LARGE_STACK_SIZE / _1KB))
{
@@ -558,6 +560,9 @@
MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START);
MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END);
MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
+
+ /* Set the working set address */
+ MmWorkingSetList = (PVOID)MI_WORKING_SET_LIST;
//
// Reserve system PTEs for zeroing PTEs and clear them
@@ -571,6 +576,28 @@
//
MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
+ /* Lock PFN database */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Reset the ref/share count so that MmInitializeProcessAddressSpace works */
+ Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(MiAddressToPde(PDE_BASE)));
+ Pfn1->u2.ShareCount = 0;
+ Pfn1->u3.e2.ReferenceCount = 0;
+
+ /* Get a page for the working set list */
+ MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
+ MI_SET_PROCESS2("Kernel WS List");
+ PageFrameIndex = MiRemoveAnyPage(0);
+ TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+
+ /* Map the working set list */
+ PointerPte = MiAddressToPte(MmWorkingSetList);
+ MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+ /* Zero it out, and save the frame index */
+ RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
+ PsGetCurrentProcess()->WorkingSetPage = PageFrameIndex;
+
/* Check for Pentium LOCK errata */
if (KiI386PentiumLockErrataPresent)
{
@@ -581,6 +608,43 @@
PointerPte->u.Hard.WriteThrough = 1;
}
+ /* Release the lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Initialize the bogus address space */
+ Flags = 0;
+ MmInitializeProcessAddressSpace(PsGetCurrentProcess(), NULL, NULL, &Flags,
NULL);
+
+ /* Make sure the color lists are valid */
+ ASSERT(MmFreePagesByColor[0] < (PMMCOLOR_TABLES)PTE_BASE);
+ StartPde = MiAddressToPde(MmFreePagesByColor[0]);
+ ASSERT(StartPde->u.Hard.Valid == 1);
+ PointerPte = MiAddressToPte(MmFreePagesByColor[0]);
+ ASSERT(PointerPte->u.Hard.Valid == 1);
+ LastPte = MiAddressToPte((ULONG_PTR)&MmFreePagesByColor[1][MmSecondaryColors] -
1);
+ ASSERT(LastPte->u.Hard.Valid == 1);
+
+ /* Loop the color list PTEs */
+ while (PointerPte <= LastPte)
+ {
+ /* Get the PFN entry */
+ Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
+ if (!Pfn1->u3.e2.ReferenceCount)
+ {
+ /* Fill it out */
+ Pfn1->u4.PteFrame = PFN_FROM_PTE(StartPde);
+ Pfn1->PteAddress = PointerPte;
+ Pfn1->u2.ShareCount++;
+ Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+ Pfn1->u3.e1.CacheAttribute = MiCached;
+ }
+
+ /* Keep going */
+ PointerPte++;
+ }
+
+ /* All done */
return STATUS_SUCCESS;
}
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 Nov 8 12:35:50 2010
@@ -513,6 +513,7 @@
extern KEVENT MmZeroingPageEvent;
extern ULONG MmSystemPageColor;
extern ULONG MmProcessColorSeed;
+extern PMMWSL MmWorkingSetList;
//
// Figures out the hardware bits for a PTE
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pagfault.…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] Mon Nov 8 12:35:50 2010
@@ -991,6 +991,14 @@
MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
return Status;
}
+
+ /* Is this a user address? */
+ if (Address <= MM_HIGHEST_USER_ADDRESS)
+ {
+ /* Add an additional page table reference */
+ MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
+ ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <=
PTE_COUNT);
+ }
/* Did we get a prototype PTE back? */
if (!ProtoPte)
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 Nov 8 12:35:50 2010
@@ -19,6 +19,7 @@
/* GLOBALS ********************************************************************/
ULONG MmProcessColorSeed = 0x12345678;
+PMMWSL MmWorkingSetList;
/* PRIVATE FUNCTIONS **********************************************************/
@@ -892,6 +893,32 @@
return Status;
}
+VOID
+NTAPI
+MiInitializeWorkingSetList(IN PEPROCESS CurrentProcess)
+{
+ PMMPFN Pfn1;
+
+ /* Setup some bogus list data */
+ MmWorkingSetList->LastEntry = CurrentProcess->Vm.MinimumWorkingSetSize;
+ MmWorkingSetList->HashTable = NULL;
+ MmWorkingSetList->HashTableSize = 0;
+ MmWorkingSetList->NumberOfImageWaiters = 0;
+ MmWorkingSetList->Wsle = (PVOID)0xDEADBABE;
+ MmWorkingSetList->VadBitMapHint = 1;
+ MmWorkingSetList->HashTableStart = (PVOID)0xBADAB00B;
+ MmWorkingSetList->HighestPermittedHashAddress = (PVOID)0xCAFEBABE;
+ MmWorkingSetList->FirstFree = 1;
+ MmWorkingSetList->FirstDynamic = 2;
+ MmWorkingSetList->NextSlot = 3;
+ MmWorkingSetList->LastInitializedWsle = 4;
+
+ /* The rule is that the owner process is always in the FLINK of the PDE's PFN
entry */
+ Pfn1 = MiGetPfnEntry(MiAddressToPte(PDE_BASE)->u.Hard.PageFrameNumber);
+ ASSERT(Pfn1->u4.PteFrame == MiGetPfnEntryIndex(Pfn1));
+ Pfn1->u1.Event = (PKEVENT)CurrentProcess;
+}
+
NTSTATUS
NTAPI
MmInitializeProcessAddressSpace(IN PEPROCESS Process,
@@ -912,6 +939,7 @@
PWCHAR Source;
PCHAR Destination;
USHORT Length = 0;
+ MMPTE TempPte;
/* We should have a PDE */
ASSERT(Process->Pcb.DirectoryTableBase[0] != 0);
@@ -944,6 +972,22 @@
PointerPde = MiAddressToPde(HYPER_SPACE);
PageFrameNumber = PFN_FROM_PTE(PointerPde);
MiInitializePfn(PageFrameNumber, PointerPde, TRUE);
+
+ /* Setup the PFN for the PTE for the working set */
+ PointerPte = MiAddressToPte(MI_WORKING_SET_LIST);
+ MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, MM_READWRITE, 0);
+ ASSERT(PointerPte->u.Long != 0);
+ PageFrameNumber = PFN_FROM_PTE(PointerPte);
+ MI_WRITE_INVALID_PTE(PointerPte, DemandZeroPte);
+ MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
+ TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
+ MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+ /* Now initialize the working set list */
+ MiInitializeWorkingSetList(Process);
+
+ /* Sanity check */
+ ASSERT(Process->PhysicalVadRoot == NULL);
/* Release PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
@@ -1062,12 +1106,13 @@
OUT PULONG_PTR DirectoryTableBase)
{
KIRQL OldIrql;
- PFN_NUMBER PdeIndex, HyperIndex;
+ PFN_NUMBER PdeIndex, HyperIndex, WsListIndex;
PMMPTE PointerPte;
MMPTE TempPte, PdePte;
ULONG PdeOffset;
- PMMPTE SystemTable;
+ PMMPTE SystemTable, HyperTable;
ULONG Color;
+ PMMPFN Pfn1;
/* Choose a process color */
Process->NextPageColor = RtlRandom(&MmProcessColorSeed);
@@ -1105,6 +1150,21 @@
/* Zero it outside the PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
MiZeroPhysicalPage(HyperIndex);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ }
+
+ /* Get a zero page for the woring set list, if possible */
+ MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
+ Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+ WsListIndex = MiRemoveZeroPageSafe(Color);
+ if (!WsListIndex)
+ {
+ /* No zero pages, grab a free one */
+ WsListIndex = MiRemoveAnyPage(Color);
+
+ /* Zero it outside the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ MiZeroPhysicalPage(WsListIndex);
}
else
{
@@ -1117,11 +1177,42 @@
Process->AddressSpaceInitialized = 1;
/* Set the base directory pointers */
+ Process->WorkingSetPage = WsListIndex;
DirectoryTableBase[0] = PdeIndex << PAGE_SHIFT;
DirectoryTableBase[1] = HyperIndex << PAGE_SHIFT;
/* Make sure we don't already have a page directory setup */
ASSERT(Process->Pcb.DirectoryTableBase[0] == 0);
+
+ /* Get a PTE to map hyperspace */
+ PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
+ ASSERT(PointerPte != NULL);
+
+ /* Build it */
+ MI_MAKE_HARDWARE_PTE_KERNEL(&PdePte,
+ PointerPte,
+ MM_READWRITE,
+ HyperIndex);
+
+ /* Set it dirty and map it */
+ PdePte.u.Hard.Dirty = TRUE;
+ MI_WRITE_VALID_PTE(PointerPte, PdePte);
+
+ /* Now get hyperspace's page table */
+ HyperTable = MiPteToAddress(PointerPte);
+
+ /* Now write the PTE/PDE entry for the working set list index itself */
+ TempPte = ValidKernelPte;
+ TempPte.u.Hard.PageFrameNumber = WsListIndex;
+ PdeOffset = MiAddressToPteOffset(MmWorkingSetList);
+ HyperTable[PdeOffset] = TempPte;
+
+ /* Let go of the system PTE */
+ MiReleaseSystemPtes(PointerPte, 1, SystemPteSpace);
+
+ /* Save the PTE address of the page directory itself */
+ Pfn1 = MiGetPfnEntry(PdeIndex);
+ Pfn1->PteAddress = (PMMPTE)PDE_BASE;
/* Insert us into the Mm process list */
InsertTailList(&MmProcessList, &Process->MmProcessLinks);