From: Sir Richard Date: Sat, 20 Feb 2010 21:48:36 +0000 (+0000) Subject: [NTOS]: Make MM init read MmProductType to determine what SKU of ReactOS this is... X-Git-Tag: ReactOS-0.3.11-CLT2010~8^2~119 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=23323a725029fd1d453a4bc4298ad1a8bccf5dc3 [NTOS]: Make MM init read MmProductType to determine what SKU of ReactOS this is, instead of assuming Server. If you want to go back to the old behavior, you need to change "WinNT" to "ServerNT" in the hivesys under Product Type. [NTOS]: Configure the MmSystemSize variable properly based on SKU and RAM. Previously, ReactOS told all drivers and applications you were running on a system with < 13MB RAM. [NTOS]: Initialize thresholds for low and high memory (in pages), low and high paged pool memory, and low and high nonpaged pool memory. These are described in the source. [NTOS]: Initialize events for each of those thresholds, and populate the \KernelObject\xxxCondition events that are documented in MSDN for driver and app developers. [NTOS]: Define some internal thresholds to use later, representing the minimum number of free pages under we go berserk, and the minimum number of free pages that we consider "plenty". [NTOS]: Rename MiRemoveFromList to MiUnlinkFreeOrZeroedPage (Windows name). Make the function handle MmAvailablePages decrement, instead of having the caller do it. [NTOS]: Remove run-time initialization of the PFN lists, just initialize them statically (also fixes the fact we forgot to initialize their names). [NTOS]: Move some more initialization code to ARM3 instead of mm. [NTOS]: Read ProductType from registry into MmProductType instead of dummy value. Remove duplicate "Mirroring" variable read. svn path=/trunk/; revision=45638 --- diff --git a/reactos/ntoskrnl/config/cmdata.c b/reactos/ntoskrnl/config/cmdata.c index 76c4bbe1f48..b3df10ce438 100644 --- a/reactos/ntoskrnl/config/cmdata.c +++ b/reactos/ntoskrnl/config/cmdata.c @@ -11,11 +11,12 @@ #include "ntoskrnl.h" #define NDEBUG #include "debug.h" - + /* GLOBALS *******************************************************************/ ULONG DummyData; ULONG CmNtGlobalFlag; +extern ULONG MmProductType; WCHAR CmDefaultLanguageId[12]; ULONG CmDefaultLanguageIdLength = sizeof(CmDefaultLanguageId); @@ -264,14 +265,6 @@ CM_SYSTEM_CONTROL_VECTOR CmControlVector[] = NULL }, - { - L"Session Manager\\Memory Management", - L"Mirroring", - &DummyData, - NULL, - NULL - }, - { L"Session Manager\\Memory Management", L"SystemViewSize", @@ -667,7 +660,7 @@ CM_SYSTEM_CONTROL_VECTOR CmControlVector[] = { L"ProductOptions", L"ProductType", - &DummyData, + &MmProductType, NULL, NULL }, diff --git a/reactos/ntoskrnl/mm/ARM3/i386/init.c b/reactos/ntoskrnl/mm/ARM3/i386/init.c index bdbda30fbbe..250324ca65f 100644 --- a/reactos/ntoskrnl/mm/ARM3/i386/init.c +++ b/reactos/ntoskrnl/mm/ARM3/i386/init.c @@ -404,6 +404,9 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock) DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex); DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex + MxPfnAllocation); + /* Convert nonpaged pool size from bytes to pages */ + MmMaximumNonPagedPoolInPages = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT; + // // Now we need some pages to create the page tables for the NP system VA // which includes system PTEs and expansion NP @@ -496,10 +499,9 @@ MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock) ASSERT(MiAddressToPte(MmNonPagedSystemStart) < MiAddressToPte(MmNonPagedPoolExpansionStart)); - // - // Now go ahead and initialize the ARM³ nonpaged pool - // - MiInitializeArmPool(); + /* Now go ahead and initialize the nonpaged pool */ + MiInitializeNonPagedPool(); + MiInitializeNonPagedPoolThresholds(); /* Map the PFN database pages */ MiMapPfnDatabase(LoaderBlock); diff --git a/reactos/ntoskrnl/mm/ARM3/miarm.h b/reactos/ntoskrnl/mm/ARM3/miarm.h index f37bd29a3c4..e5b4c1b7780 100644 --- a/reactos/ntoskrnl/mm/ARM3/miarm.h +++ b/reactos/ntoskrnl/mm/ARM3/miarm.h @@ -168,6 +168,8 @@ extern MMPTE ValidKernelPte; extern ULONG MmSizeOfNonPagedPoolInBytes; extern ULONG MmMaximumNonPagedPoolInBytes; +extern PFN_NUMBER MmMaximumNonPagedPoolInPages; +extern PFN_NUMBER MmSizeOfPagedPoolInPages; extern PVOID MmNonPagedSystemStart; extern PVOID MmNonPagedPoolStart; extern PVOID MmNonPagedPoolExpansionStart; @@ -217,6 +219,22 @@ extern ULONG MmNumberOfSystemPtes; extern ULONG MmMaximumNonPagedPoolPercent; extern ULONG MmLargeStackSize; extern PMMCOLOR_TABLES MmFreePagesByColor[FreePageList + 1]; +extern ULONG MmProductType; +extern MM_SYSTEMSIZE MmSystemSize; +extern PKEVENT MiLowMemoryEvent; +extern PKEVENT MiHighMemoryEvent; +extern PKEVENT MiLowPagedPoolEvent; +extern PKEVENT MiHighPagedPoolEvent; +extern PKEVENT MiLowNonPagedPoolEvent; +extern PKEVENT MiHighNonPagedPoolEvent; +extern PFN_NUMBER MmLowMemoryThreshold; +extern PFN_NUMBER MmHighMemoryThreshold; +extern PFN_NUMBER MiLowPagedPoolThreshold; +extern PFN_NUMBER MiHighPagedPoolThreshold; +extern PFN_NUMBER MiLowNonPagedPoolThreshold; +extern PFN_NUMBER MiHighNonPagedPoolThreshold; +extern PFN_NUMBER MmMinimumFreePages; +extern PFN_NUMBER MmPlentyFreePages; #define MI_PFN_TO_PFNENTRY(x) (&MmPfnDatabase[1][x]) #define MI_PFNENTRY_TO_PFN(x) (x - MmPfnDatabase[1]) @@ -258,6 +276,12 @@ MiInitializePfnDatabase( IN PLOADER_PARAMETER_BLOCK LoaderBlock ); +BOOLEAN +NTAPI +MiInitializeMemoryEvents( + VOID +); + PFN_NUMBER NTAPI MxGetNextPage( @@ -296,7 +320,19 @@ MmArmAccessFault( VOID NTAPI -MiInitializeArmPool( +MiInitializeNonPagedPool( + VOID +); + +VOID +NTAPI +MiInitializeNonPagedPoolThresholds( + VOID +); + +VOID +NTAPI +MiInitializePoolEvents( VOID ); @@ -389,7 +425,7 @@ MiInsertInListTail( VOID NTAPI -MiRemoveFromList( +MiUnlinkFreeOrZeroedPage( IN PMMPFN Entry ); diff --git a/reactos/ntoskrnl/mm/ARM3/mminit.c b/reactos/ntoskrnl/mm/ARM3/mminit.c index 0609961afe6..89d082e4f95 100644 --- a/reactos/ntoskrnl/mm/ARM3/mminit.c +++ b/reactos/ntoskrnl/mm/ARM3/mminit.c @@ -26,6 +26,9 @@ ULONG MmMaximumNonPagedPoolPercent; ULONG MmSizeOfNonPagedPoolInBytes; ULONG MmMaximumNonPagedPoolInBytes; +/* Some of the same values, in pages */ +PFN_NUMBER MmMaximumNonPagedPoolInPages; + // // These numbers describe the discrete equation components of the nonpaged // pool sizing algorithm. @@ -258,6 +261,46 @@ MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor; C_ASSERT(FreePageList == 1); PMMCOLOR_TABLES MmFreePagesByColor[FreePageList + 1]; +/* An event used in Phase 0 before the rest of the system is ready to go */ +KEVENT MiTempEvent; + +/* All the events used for memory threshold notifications */ +PKEVENT MiLowMemoryEvent; +PKEVENT MiHighMemoryEvent; +PKEVENT MiLowPagedPoolEvent; +PKEVENT MiHighPagedPoolEvent; +PKEVENT MiLowNonPagedPoolEvent; +PKEVENT MiHighNonPagedPoolEvent; + +/* The actual thresholds themselves, in page numbers */ +PFN_NUMBER MmLowMemoryThreshold; +PFN_NUMBER MmHighMemoryThreshold; +PFN_NUMBER MiLowPagedPoolThreshold; +PFN_NUMBER MiHighPagedPoolThreshold; +PFN_NUMBER MiLowNonPagedPoolThreshold; +PFN_NUMBER MiHighNonPagedPoolThreshold; + +/* + * This number determines how many free pages must exist, at minimum, until we + * start trimming working sets and flushing modified pages to obtain more free + * pages. + * + * This number changes if the system detects that this is a server product + */ +PFN_NUMBER MmMinimumFreePages = 26; + +/* + * This number indicates how many pages we consider to be a low limit of having + * "plenty" of free memory. + * + * It is doubled on systems that have more than 63MB of memory + */ +PFN_NUMBER MmPlentyFreePages = 400; + +/* These values store the type of system this is (small, med, large) and if server */ +ULONG MmProductType; +MM_SYSTEMSIZE MmSystemSize; + /* PRIVATE FUNCTIONS **********************************************************/ // @@ -905,6 +948,217 @@ MiInitializePfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock) MiBuildPfnDatabaseSelf(); } +VOID +NTAPI +MiAdjustWorkingSetManagerParameters(IN BOOLEAN Client) +{ + /* This function needs to do more work, for now, we tune page minimums */ + + /* Check for a system with around 64MB RAM or more */ + if (MmNumberOfPhysicalPages >= (63 * _1MB) / PAGE_SIZE) + { + /* Double the minimum amount of pages we consider for a "plenty free" scenario */ + MmPlentyFreePages *= 2; + } +} + +VOID +NTAPI +MiNotifyMemoryEvents(VOID) +{ + /* Are we in a low-memory situation? */ + if (MmAvailablePages < MmLowMemoryThreshold) + { + /* Clear high, set low */ + if (KeReadStateEvent(MiHighMemoryEvent)) KeClearEvent(MiHighMemoryEvent); + if (!KeReadStateEvent(MiLowMemoryEvent)) KeSetEvent(MiLowMemoryEvent, 0, FALSE); + } + else if (MmAvailablePages < MmHighMemoryThreshold) + { + /* We are in between, clear both */ + if (KeReadStateEvent(MiHighMemoryEvent)) KeClearEvent(MiHighMemoryEvent); + if (KeReadStateEvent(MiLowMemoryEvent)) KeClearEvent(MiLowMemoryEvent); + } + else + { + /* Clear low, set high */ + if (KeReadStateEvent(MiLowMemoryEvent)) KeClearEvent(MiLowMemoryEvent); + if (!KeReadStateEvent(MiHighMemoryEvent)) KeSetEvent(MiHighMemoryEvent, 0, FALSE); + } +} + +NTSTATUS +NTAPI +MiCreateMemoryEvent(IN PUNICODE_STRING Name, + OUT PKEVENT *Event) +{ + PACL Dacl; + HANDLE EventHandle; + ULONG DaclLength; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + SECURITY_DESCRIPTOR SecurityDescriptor; + + /* Create the SD */ + Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION); + if (!NT_SUCCESS(Status)) return Status; + + /* One ACL with 3 ACEs, containing each one SID */ + DaclLength = sizeof(ACL) + + 3 * sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid(SeLocalSystemSid) + + RtlLengthSid(SeAliasAdminsSid) + + RtlLengthSid(SeWorldSid); + + /* Allocate space for the DACL */ + Dacl = ExAllocatePoolWithTag(PagedPool, DaclLength, 'lcaD'); + if (!Dacl) return STATUS_INSUFFICIENT_RESOURCES; + + /* Setup the ACL inside it */ + Status = RtlCreateAcl(Dacl, DaclLength, ACL_REVISION); + if (!NT_SUCCESS(Status)) goto CleanUp; + + /* Add query rights for everyone */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + SYNCHRONIZE | EVENT_QUERY_STATE | READ_CONTROL, + SeWorldSid); + if (!NT_SUCCESS(Status)) goto CleanUp; + + /* Full rights for the admin */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + EVENT_ALL_ACCESS, + SeAliasAdminsSid); + if (!NT_SUCCESS(Status)) goto CleanUp; + + /* As well as full rights for the system */ + Status = RtlAddAccessAllowedAce(Dacl, + ACL_REVISION, + EVENT_ALL_ACCESS, + SeLocalSystemSid); + if (!NT_SUCCESS(Status)) goto CleanUp; + + /* Set this DACL inside the SD */ + Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, + TRUE, + Dacl, + FALSE); + if (!NT_SUCCESS(Status)) goto CleanUp; + + /* Setup the event attributes, making sure it's a permanent one */ + InitializeObjectAttributes(&ObjectAttributes, + Name, + OBJ_KERNEL_HANDLE | OBJ_PERMANENT, + NULL, + &SecurityDescriptor); + + /* Create the event */ + Status = ZwCreateEvent(&EventHandle, + EVENT_ALL_ACCESS, + &ObjectAttributes, + NotificationEvent, + FALSE); +CleanUp: + /* Free the DACL */ + ExFreePool(Dacl); + + /* Check if this is the success path */ + if (NT_SUCCESS(Status)) + { + /* Add a reference to the object, then close the handle we had */ + Status = ObReferenceObjectByHandle(EventHandle, + EVENT_MODIFY_STATE, + ExEventObjectType, + KernelMode, + (PVOID*)Event, + NULL); + ZwClose (EventHandle); + } + + /* Return status */ + return Status; +} + +BOOLEAN +NTAPI +MiInitializeMemoryEvents(VOID) +{ + UNICODE_STRING LowString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowMemoryCondition"); + UNICODE_STRING HighString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighMemoryCondition"); + UNICODE_STRING LowPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowPagedPoolCondition"); + UNICODE_STRING HighPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighPagedPoolCondition"); + UNICODE_STRING LowNonPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowNonPagedPoolCondition"); + UNICODE_STRING HighNonPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighNonPagedPoolCondition"); + NTSTATUS Status; + + /* Check if we have a registry setting */ + if (MmLowMemoryThreshold) + { + /* Convert it to pages */ + MmLowMemoryThreshold *= (_1MB / PAGE_SIZE); + } + else + { + /* The low memory threshold is hit when we don't consider that we have "plenty" of free pages anymore */ + MmLowMemoryThreshold = MmPlentyFreePages; + + /* More than one GB of memory? */ + if (MmNumberOfPhysicalPages > 0x40000) + { + /* Start at 32MB, and add another 16MB for each GB */ + MmLowMemoryThreshold = (32 * _1MB) / PAGE_SIZE; + MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x40000) >> 7); + } + else if (MmNumberOfPhysicalPages > 0x8000) + { + /* For systems with > 128MB RAM, add another 4MB for each 128MB */ + MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x8000) >> 5); + } + + /* Don't let the minimum threshold go past 64MB */ + MmLowMemoryThreshold = min(MmLowMemoryThreshold, (64 * _1MB) / PAGE_SIZE); + } + + /* Check if we have a registry setting */ + if (MmHighMemoryThreshold) + { + /* Convert it into pages */ + MmHighMemoryThreshold *= (_1MB / PAGE_SIZE); + } + else + { + /* Otherwise, the default is three times the low memory threshold */ + MmHighMemoryThreshold = 3 * MmLowMemoryThreshold; + ASSERT(MmHighMemoryThreshold > MmLowMemoryThreshold); + } + + /* Make sure high threshold is actually higher than the low */ + MmHighMemoryThreshold = max(MmHighMemoryThreshold, MmLowMemoryThreshold); + + /* Create the memory events for all the thresholds */ + Status = MiCreateMemoryEvent(&LowString, &MiLowMemoryEvent); + if (!NT_SUCCESS(Status)) return FALSE; + Status = MiCreateMemoryEvent(&HighString, &MiHighMemoryEvent); + if (!NT_SUCCESS(Status)) return FALSE; + Status = MiCreateMemoryEvent(&LowPagedPoolString, &MiLowPagedPoolEvent); + if (!NT_SUCCESS(Status)) return FALSE; + Status = MiCreateMemoryEvent(&HighPagedPoolString, &MiHighPagedPoolEvent); + if (!NT_SUCCESS(Status)) return FALSE; + Status = MiCreateMemoryEvent(&LowNonPagedPoolString, &MiLowNonPagedPoolEvent); + if (!NT_SUCCESS(Status)) return FALSE; + Status = MiCreateMemoryEvent(&HighNonPagedPoolString, &MiHighNonPagedPoolEvent); + if (!NT_SUCCESS(Status)) return FALSE; + + /* Now setup the pool events */ + MiInitializePoolEvents(); + + /* Set the initial event state */ + MiNotifyMemoryEvents(); + return TRUE; +} + VOID NTAPI MmDumpArmPfnDatabase(VOID) @@ -1324,10 +1578,14 @@ MiBuildPagedPool(VOID) // InitializePool(PagedPool, 0); - // - // Initialize the paged pool mutex - // - KeInitializeGuardedMutex(&MmPagedPoolMutex); + /* Default low threshold of 30MB or one fifth of paged pool */ + MiLowPagedPoolThreshold = (30 * _1MB) >> PAGE_SHIFT; + MiLowPagedPoolThreshold = min(MiLowPagedPoolThreshold, Size / 5); + + /* Default high threshold of 60MB or 25% */ + MiHighPagedPoolThreshold = (60 * _1MB) >> PAGE_SHIFT; + MiHighPagedPoolThreshold = min(MiHighPagedPoolThreshold, (Size * 2) / 5); + ASSERT(MiLowPagedPoolThreshold < MiHighPagedPoolThreshold); } NTSTATUS @@ -1353,6 +1611,17 @@ MmArmInitSystem(IN ULONG Phase, IncludeType[LoaderBBTMemory] = FALSE; if (Phase == 0) { + /* Initialize the phase 0 temporary event */ + KeInitializeEvent(&MiTempEvent, NotificationEvent, FALSE); + + /* Set all the events to use the temporary event for now */ + MiLowMemoryEvent = &MiTempEvent; + MiHighMemoryEvent = &MiTempEvent; + MiLowPagedPoolEvent = &MiTempEvent; + MiHighPagedPoolEvent = &MiTempEvent; + MiLowNonPagedPoolEvent = &MiTempEvent; + MiHighNonPagedPoolEvent = &MiTempEvent; + // // Define the basic user vs. kernel address space separation // @@ -1433,6 +1702,16 @@ MmArmInitSystem(IN ULONG Phase, MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase - MmSystemViewSize); + + /* Initialize the user mode image list */ + InitializeListHead(&MmLoadedUserImageList); + + /* Initialize the paged pool mutex */ + KeInitializeGuardedMutex(&MmPagedPoolMutex); + + /* Initialize the Loader Lock */ + KeInitializeMutant(&MmSystemLoadLock, FALSE); + // // Count physical pages on the system // @@ -1538,6 +1817,77 @@ MmArmInitSystem(IN ULONG Phase, // Size up paged pool and build the shadow system page directory // MiBuildPagedPool(); + + /* Check how many pages the system has */ + if (MmNumberOfPhysicalPages <= (13 * _1MB)) + { + /* Set small system */ + MmSystemSize = MmSmallSystem; + } + else if (MmNumberOfPhysicalPages <= (19 * _1MB)) + { + /* Set small system */ + MmSystemSize = MmSmallSystem; + } + else + { + /* Set medium system */ + MmSystemSize = MmMediumSystem; + } + + /* Check for more than 32MB */ + if (MmNumberOfPhysicalPages >= ((32 * _1MB) / PAGE_SIZE)) + { + /* Check for product type being "Wi" for WinNT */ + if (MmProductType == '\0i\0W') + { + /* Then this is a large system */ + MmSystemSize = MmLargeSystem; + } + else + { + /* For servers, we need 64MB to consider this as being large */ + if (MmNumberOfPhysicalPages >= ((64 * _1MB) / PAGE_SIZE)) + { + /* Set it as large */ + MmSystemSize = MmLargeSystem; + } + } + } + + /* Now setup the shared user data fields */ + ASSERT(SharedUserData->NumberOfPhysicalPages == 0); + SharedUserData->NumberOfPhysicalPages = MmNumberOfPhysicalPages; + SharedUserData->LargePageMinimum = 0; + + /* Check for workstation (Wi for WinNT) */ + if (MmProductType == '\0i\0W') + { + /* Set Windows NT Workstation product type */ + SharedUserData->NtProductType = NtProductWinNt; + MmProductType = 0; + } + else + { + /* Check for LanMan server */ + if (MmProductType == '\0a\0L') + { + /* This is a domain controller */ + SharedUserData->NtProductType = NtProductLanManNt; + } + else + { + /* Otherwise it must be a normal server */ + SharedUserData->NtProductType = NtProductServer; + } + + /* Set the product type, and make the system more aggressive with low memory */ + MmProductType = 1; + MmMinimumFreePages = 81; + } + + /* Update working set tuning parameters */ + MiAdjustWorkingSetManagerParameters(!MmProductType); } // diff --git a/reactos/ntoskrnl/mm/ARM3/mmsup.c b/reactos/ntoskrnl/mm/ARM3/mmsup.c index 6fc28279a2e..b84c7a0492b 100644 --- a/reactos/ntoskrnl/mm/ARM3/mmsup.c +++ b/reactos/ntoskrnl/mm/ARM3/mmsup.c @@ -16,11 +16,6 @@ #define MODULE_INVOLVED_IN_ARM3 #include "../ARM3/miarm.h" -/* GLOBALS ********************************************************************/ - -BOOLEAN IsThisAnNtAsSystem = FALSE; -MM_SYSTEMSIZE MmSystemSize = MmSmallSystem; - /* PUBLIC FUNCTIONS ***********************************************************/ /* @@ -137,10 +132,8 @@ BOOLEAN NTAPI MmIsThisAnNtAsSystem(VOID) { - // - // Return if this is a server system - // - return IsThisAnNtAsSystem; + /* Return if this is a server system */ + return MmProductType; } /* @@ -150,9 +143,7 @@ MM_SYSTEMSIZE NTAPI MmQuerySystemSize(VOID) { - // - // Return the low, medium or high memory system type - // + /* Return the low, medium or high memory system type */ return MmSystemSize; } diff --git a/reactos/ntoskrnl/mm/ARM3/pfnlist.c b/reactos/ntoskrnl/mm/ARM3/pfnlist.c index 5765d92fedc..cf13be1e002 100644 --- a/reactos/ntoskrnl/mm/ARM3/pfnlist.c +++ b/reactos/ntoskrnl/mm/ARM3/pfnlist.c @@ -18,12 +18,25 @@ /* GLOBALS ********************************************************************/ -MMPFNLIST MmZeroedPageListHead; -MMPFNLIST MmFreePageListHead; -MMPFNLIST MmStandbyPageListHead; -MMPFNLIST MmModifiedPageListHead; -MMPFNLIST MmModifiedNoWritePageListHead; +MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD}; +MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD}; +MMPFNLIST MmStandbyPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD}; +MMPFNLIST MmModifiedPageListHead = {0, ModifiedPageList, LIST_HEAD, LIST_HEAD}; +MMPFNLIST MmModifiedNoWritePageListHead = {0, ModifiedNoWritePageList, LIST_HEAD, LIST_HEAD}; +MMPFNLIST MmBadPageListHead = {0, BadPageList, LIST_HEAD, LIST_HEAD}; +MMPFNLIST MmRomPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD}; +PMMPFNLIST MmPageLocationList[] = +{ + &MmZeroedPageListHead, + &MmFreePageListHead, + &MmStandbyPageListHead, + &MmModifiedPageListHead, + &MmModifiedNoWritePageListHead, + &MmBadPageListHead, + NULL, + NULL +}; /* FUNCTIONS ******************************************************************/ VOID @@ -57,25 +70,28 @@ MiInsertInListTail(IN PMMPFNLIST ListHead, VOID NTAPI -MiRemoveFromList(IN PMMPFN Entry) +MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry) { PFN_NUMBER OldFlink, OldBlink; PMMPFNLIST ListHead; + MMLISTS ListName; - /* Find the list for this */ - if (Entry->u3.e1.PageLocation == ZeroedPageList) - { - ListHead = &MmZeroedPageListHead; - } - else if (Entry->u3.e1.PageLocation == FreePageList) - { - ListHead = &MmFreePageListHead; - } - else - { - ListHead = NULL; - ASSERT(ListHead != NULL); - } + /* Make sure the PFN lock is held */ + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + + /* Make sure the PFN entry isn't in-use */ + ASSERT(Entry->u3.e1.WriteInProgress == 0); + ASSERT(Entry->u3.e1.ReadInProgress == 0); + + /* Find the list for this entry, make sure it's the free or zero list */ + ListHead = MmPageLocationList[Entry->u3.e1.PageLocation]; + ListName = ListHead->ListName; + ASSERT(ListHead != NULL); + ASSERT(ListName <= FreePageList); + + /* Remove one count */ + ASSERT(ListHead->Total != 0); + ListHead->Total--; /* Get the forward and back pointers */ OldFlink = Entry->u1.Flink; @@ -106,8 +122,27 @@ MiRemoveFromList(IN PMMPFN Entry) } /* We are not on a list anymore */ - ListHead->Total--; Entry->u1.Flink = Entry->u2.Blink = 0; + + /* FIXME: Deal with color list */ + + /* See if we hit any thresholds */ + if (MmAvailablePages == MmHighMemoryThreshold) + { + /* Clear the high memory event */ + KeClearEvent(MiHighMemoryEvent); + } + else if (MmAvailablePages == MmLowMemoryThreshold) + { + /* Signal the low memory event */ + KeSetEvent(MiLowMemoryEvent, 0, FALSE); + } + + /* One less page */ + if (--MmAvailablePages < MmMinimumFreePages) + { + /* FIXME: Should wake up the MPW and working set manager, if we had one */ + } } PMMPFN diff --git a/reactos/ntoskrnl/mm/ARM3/pool.c b/reactos/ntoskrnl/mm/ARM3/pool.c index 111180c9f13..bd2f826c6d2 100644 --- a/reactos/ntoskrnl/mm/ARM3/pool.c +++ b/reactos/ntoskrnl/mm/ARM3/pool.c @@ -31,7 +31,97 @@ ULONG MmSpecialPoolTag; VOID NTAPI -MiInitializeArmPool(VOID) +MiInitializeNonPagedPoolThresholds(VOID) +{ + PFN_NUMBER Size = MmMaximumNonPagedPoolInPages; + + /* Default low threshold of 8MB or one third of nonpaged pool */ + MiLowNonPagedPoolThreshold = (8 * _1MB) >> PAGE_SHIFT; + MiLowNonPagedPoolThreshold = min(MiLowNonPagedPoolThreshold, Size / 3); + + /* Default high threshold of 20MB or 50% */ + MiHighNonPagedPoolThreshold = (20 * _1MB) >> PAGE_SHIFT; + MiHighNonPagedPoolThreshold = min(MiHighNonPagedPoolThreshold, Size / 2); + ASSERT(MiLowNonPagedPoolThreshold < MiHighNonPagedPoolThreshold); +} + +VOID +NTAPI +MiInitializePoolEvents(VOID) +{ + KIRQL OldIrql; + PFN_NUMBER FreePoolInPages; + + /* Lock paged pool */ + KeAcquireGuardedMutex(&MmPagedPoolMutex); + + /* Total size of the paged pool minus the allocated size, is free */ + FreePoolInPages = MmSizeOfPagedPoolInPages - MmPagedPoolInfo.AllocatedPagedPool; + + /* Check the initial state high state */ + if (FreePoolInPages >= MiHighPagedPoolThreshold) + { + /* We have plenty of pool */ + KeSetEvent(MiHighPagedPoolEvent, 0, FALSE); + } + else + { + /* We don't */ + KeClearEvent(MiHighPagedPoolEvent); + } + + /* Check the initial low state */ + if (FreePoolInPages <= MiLowPagedPoolThreshold) + { + /* We're very low in free pool memory */ + KeSetEvent(MiLowPagedPoolEvent, 0, FALSE); + } + else + { + /* We're not */ + KeClearEvent(MiLowPagedPoolEvent); + } + + /* Release the paged pool lock */ + KeReleaseGuardedMutex(&MmPagedPoolMutex); + + /* Now it's time for the nonpaged pool lock */ + OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock); + + /* Free pages are the maximum minus what's been allocated */ + FreePoolInPages = MmMaximumNonPagedPoolInPages - MmAllocatedNonPagedPool; + + /* Check if we have plenty */ + if (FreePoolInPages >= MiHighNonPagedPoolThreshold) + { + /* We do, set the event */ + KeSetEvent(MiHighNonPagedPoolEvent, 0, FALSE); + } + else + { + /* We don't, clear the event */ + KeClearEvent(MiHighNonPagedPoolEvent); + } + + /* Check if we have very little */ + if (FreePoolInPages <= MiLowNonPagedPoolThreshold) + { + /* We do, set the event */ + KeSetEvent(MiLowNonPagedPoolEvent, 0, FALSE); + } + else + { + /* We don't, clear it */ + KeClearEvent(MiLowNonPagedPoolEvent); + } + + /* We're done, release the nonpaged pool lock */ + KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql); +} + +VOID +NTAPI +MiInitializeNonPagedPool(VOID) { ULONG i; PFN_NUMBER PoolPages; diff --git a/reactos/ntoskrnl/mm/freelist.c b/reactos/ntoskrnl/mm/freelist.c index 38c708f6d10..395157bf697 100644 --- a/reactos/ntoskrnl/mm/freelist.c +++ b/reactos/ntoskrnl/mm/freelist.c @@ -244,15 +244,10 @@ MiFindContiguousPages(IN PFN_NUMBER LowestPfn, EndPfn = Pfn1 - SizeInPages + 1; do { - // - // One less free page - // - MmAvailablePages--; - // // This PFN is now a used page, set it up // - MiRemoveFromList(Pfn1); + MiUnlinkFreeOrZeroedPage(Pfn1); Pfn1->u3.e2.ReferenceCount = 1; // @@ -639,12 +634,6 @@ MmInitializePageList(VOID) PLIST_ENTRY NextEntry; ULONG NrSystemPages = 0; - /* Initialize the page lists */ - MmFreePageListHead.Flink = MmFreePageListHead.Blink = LIST_HEAD; - MmZeroedPageListHead.Flink = MmZeroedPageListHead.Blink = LIST_HEAD; - MmZeroedPageListHead.Total = 0; - MmFreePageListHead.Total = 0; - /* This is what a used page looks like */ RtlZeroMemory(&UsedPage, sizeof(UsedPage)); UsedPage.u3.e1.PageLocation = ActiveAndValid; diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index cdaec0aa11b..6a3492415c0 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -402,25 +402,11 @@ MmInitSystem(IN ULONG Phase, MiInitializeUserPfnBitmap(); MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory); - /* Initialize the user mode image list */ - InitializeListHead(&MmLoadedUserImageList); - - /* Initialize the Loader Lock */ - KeInitializeMutant(&MmSystemLoadLock, FALSE); - /* Reload boot drivers */ MiReloadBootLoadedDrivers(LoaderBlock); /* Initialize the loaded module list */ MiInitializeLoadedModuleList(LoaderBlock); - - /* Setup shared user data settings that NT does as well */ - ASSERT(SharedUserData->NumberOfPhysicalPages == 0); - SharedUserData->NumberOfPhysicalPages = MmNumberOfPhysicalPages; - SharedUserData->LargePageMinimum = 0; - - /* For now, we assume that we're always Server */ - SharedUserData->NtProductType = NtProductServer; } else if (Phase == 1) { @@ -454,6 +440,9 @@ MmInitSystem(IN ULONG Phase, TempPte.u.Hard.PageFrameNumber = PageFrameNumber; *MmSharedUserDataPte = TempPte; + /* Setup the memory threshold events */ + if (!MiInitializeMemoryEvents()) return FALSE; + /* * Unmap low memory */