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/i... ============================================================================== --- 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?re... ============================================================================== --- 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.c... ============================================================================== --- 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);