[NTOS]: Make MM init read MmProductType to determine what SKU of ReactOS this is...
authorSir Richard <sir_richard@svn.reactos.org>
Sat, 20 Feb 2010 21:48:36 +0000 (21:48 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Sat, 20 Feb 2010 21:48:36 +0000 (21:48 +0000)
[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

reactos/ntoskrnl/config/cmdata.c
reactos/ntoskrnl/mm/ARM3/i386/init.c
reactos/ntoskrnl/mm/ARM3/miarm.h
reactos/ntoskrnl/mm/ARM3/mminit.c
reactos/ntoskrnl/mm/ARM3/mmsup.c
reactos/ntoskrnl/mm/ARM3/pfnlist.c
reactos/ntoskrnl/mm/ARM3/pool.c
reactos/ntoskrnl/mm/freelist.c
reactos/ntoskrnl/mm/mminit.c

index 76c4bbe..b3df10c 100644 (file)
 #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
     },
index bdbda30..250324c 100644 (file)
@@ -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);
index f37bd29..e5b4c1b 100644 (file)
@@ -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
 );
 
index 0609961..89d082e 100644 (file)
@@ -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);
     }
     
     //
index 6fc2827..b84c7a0 100644 (file)
 #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;
 }
 
index 5765d92..cf13be1 100644 (file)
 
 /* 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
index 111180c..bd2f826 100644 (file)
@@ -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;
index 38c708f..395157b 100644 (file)
@@ -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;
index cdaec0a..6a34924 100644 (file)
@@ -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
          */