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 */