ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

mminit.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            ntoskrnl/mm/ARM3/mminit.c
00005  * PURPOSE:         ARM Memory Manager Initialization
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 #define MODULE_INVOLVED_IN_ARM3
00016 #include "miarm.h"
00017 #undef MmSystemRangeStart
00018 
00019 /* GLOBALS ********************************************************************/
00020 
00021 //
00022 // These are all registry-configurable, but by default, the memory manager will
00023 // figure out the most appropriate values.
00024 //
00025 ULONG MmMaximumNonPagedPoolPercent;
00026 SIZE_T MmSizeOfNonPagedPoolInBytes;
00027 SIZE_T MmMaximumNonPagedPoolInBytes;
00028 
00029 /* Some of the same values, in pages */
00030 PFN_NUMBER MmMaximumNonPagedPoolInPages;
00031 
00032 //
00033 // These numbers describe the discrete equation components of the nonpaged
00034 // pool sizing algorithm.
00035 //
00036 // They are described on http://support.microsoft.com/default.aspx/kb/126402/ja
00037 // along with the algorithm that uses them, which is implemented later below.
00038 //
00039 SIZE_T MmMinimumNonPagedPoolSize = 256 * 1024;
00040 ULONG MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
00041 SIZE_T MmDefaultMaximumNonPagedPool = 1024 * 1024;
00042 ULONG MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
00043 
00044 //
00045 // The memory layout (and especially variable names) of the NT kernel mode
00046 // components can be a bit hard to twig, especially when it comes to the non
00047 // paged area.
00048 //
00049 // There are really two components to the non-paged pool:
00050 //
00051 // - The initial nonpaged pool, sized dynamically up to a maximum.
00052 // - The expansion nonpaged pool, sized dynamically up to a maximum.
00053 //
00054 // The initial nonpaged pool is physically continuous for performance, and
00055 // immediately follows the PFN database, typically sharing the same PDE. It is
00056 // a very small resource (32MB on a 1GB system), and capped at 128MB.
00057 //
00058 // Right now we call this the "ARM³ Nonpaged Pool" and it begins somewhere after
00059 // the PFN database (which starts at 0xB0000000).
00060 //
00061 // The expansion nonpaged pool, on the other hand, can grow much bigger (400MB
00062 // for a 1GB system). On ARM³ however, it is currently capped at 128MB.
00063 //
00064 // The address where the initial nonpaged pool starts is aptly named
00065 // MmNonPagedPoolStart, and it describes a range of MmSizeOfNonPagedPoolInBytes
00066 // bytes.
00067 //
00068 // Expansion nonpaged pool starts at an address described by the variable called
00069 // MmNonPagedPoolExpansionStart, and it goes on for MmMaximumNonPagedPoolInBytes
00070 // minus MmSizeOfNonPagedPoolInBytes bytes, always reaching MmNonPagedPoolEnd
00071 // (because of the way it's calculated) at 0xFFBE0000.
00072 //
00073 // Initial nonpaged pool is allocated and mapped early-on during boot, but what
00074 // about the expansion nonpaged pool? It is instead composed of special pages
00075 // which belong to what are called System PTEs. These PTEs are the matter of a
00076 // later discussion, but they are also considered part of the "nonpaged" OS, due
00077 // to the fact that they are never paged out -- once an address is described by
00078 // a System PTE, it is always valid, until the System PTE is torn down.
00079 //
00080 // System PTEs are actually composed of two "spaces", the system space proper,
00081 // and the nonpaged pool expansion space. The latter, as we've already seen,
00082 // begins at MmNonPagedPoolExpansionStart. Based on the number of System PTEs
00083 // that the system will support, the remaining address space below this address
00084 // is used to hold the system space PTEs. This address, in turn, is held in the
00085 // variable named MmNonPagedSystemStart, which itself is never allowed to go
00086 // below 0xEB000000 (thus creating an upper bound on the number of System PTEs).
00087 //
00088 // This means that 330MB are reserved for total nonpaged system VA, on top of
00089 // whatever the initial nonpaged pool allocation is.
00090 //
00091 // The following URLs, valid as of April 23rd, 2008, support this evidence:
00092 //
00093 // http://www.cs.miami.edu/~burt/journal/NT/memory.html
00094 // http://www.ditii.com/2007/09/28/windows-memory-management-x86-virtual-address-space/
00095 //
00096 PVOID MmNonPagedSystemStart;
00097 SIZE_T MiNonPagedSystemSize;
00098 PVOID MmNonPagedPoolStart;
00099 PVOID MmNonPagedPoolExpansionStart;
00100 PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
00101 
00102 //
00103 // This is where paged pool starts by default
00104 //
00105 PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
00106 PVOID MmPagedPoolEnd;
00107 
00108 //
00109 // And this is its default size
00110 //
00111 SIZE_T MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
00112 PFN_NUMBER MmSizeOfPagedPoolInPages = MI_MIN_INIT_PAGED_POOLSIZE / PAGE_SIZE;
00113 
00114 //
00115 // Session space starts at 0xBFFFFFFF and grows downwards
00116 // By default, it includes an 8MB image area where we map win32k and video card
00117 // drivers, followed by a 4MB area containing the session's working set. This is
00118 // then followed by a 20MB mapped view area and finally by the session's paged
00119 // pool, by default 16MB.
00120 //
00121 // On a normal system, this results in session space occupying the region from
00122 // 0xBD000000 to 0xC0000000
00123 //
00124 // See miarm.h for the defines that determine the sizing of this region. On an
00125 // NT system, some of these can be configured through the registry, but we don't
00126 // support that yet.
00127 //
00128 PVOID MiSessionSpaceEnd;    // 0xC0000000
00129 PVOID MiSessionImageEnd;    // 0xC0000000
00130 PVOID MiSessionImageStart;  // 0xBF800000
00131 PVOID MiSessionViewStart;   // 0xBE000000
00132 PVOID MiSessionPoolEnd;     // 0xBE000000
00133 PVOID MiSessionPoolStart;   // 0xBD000000
00134 PVOID MmSessionBase;        // 0xBD000000
00135 SIZE_T MmSessionSize;
00136 SIZE_T MmSessionViewSize;
00137 SIZE_T MmSessionPoolSize;
00138 SIZE_T MmSessionImageSize;
00139 
00140 /*
00141  * These are the PTE addresses of the boundaries carved out above
00142  */
00143 PMMPTE MiSessionImagePteStart;
00144 PMMPTE MiSessionImagePteEnd;
00145 PMMPTE MiSessionBasePte;
00146 PMMPTE MiSessionLastPte;
00147 
00148 //
00149 // The system view space, on the other hand, is where sections that are memory
00150 // mapped into "system space" end up.
00151 //
00152 // By default, it is a 16MB region, but we hack it to be 32MB for ReactOS
00153 //
00154 PVOID MiSystemViewStart;
00155 SIZE_T MmSystemViewSize;
00156 
00157 #if (_MI_PAGING_LEVELS == 2)
00158 //
00159 // A copy of the system page directory (the page directory associated with the
00160 // System process) is kept (double-mapped) by the manager in order to lazily
00161 // map paged pool PDEs into external processes when they fault on a paged pool
00162 // address.
00163 //
00164 PFN_NUMBER MmSystemPageDirectory[PD_COUNT];
00165 PMMPDE MmSystemPagePtes;
00166 #endif
00167 
00168 //
00169 // The system cache starts right after hyperspace. The first few pages are for
00170 // keeping track of the system working set list.
00171 //
00172 // This should be 0xC0C00000 -- the cache itself starts at 0xC1000000
00173 //
00174 PMMWSL MmSystemCacheWorkingSetList = (PVOID)MI_SYSTEM_CACHE_WS_START;
00175 
00176 //
00177 // Windows NT seems to choose between 7000, 11000 and 50000
00178 // On systems with more than 32MB, this number is then doubled, and further
00179 // aligned up to a PDE boundary (4MB).
00180 //
00181 PFN_COUNT MmNumberOfSystemPtes;
00182 
00183 //
00184 // This is how many pages the PFN database will take up
00185 // In Windows, this includes the Quark Color Table, but not in ARM³
00186 //
00187 PFN_NUMBER MxPfnAllocation;
00188 
00189 //
00190 // Unlike the old ReactOS Memory Manager, ARM³ (and Windows) does not keep track
00191 // of pages that are not actually valid physical memory, such as ACPI reserved
00192 // regions, BIOS address ranges, or holes in physical memory address space which
00193 // could indicate device-mapped I/O memory.
00194 //
00195 // In fact, the lack of a PFN entry for a page usually indicates that this is
00196 // I/O space instead.
00197 //
00198 // A bitmap, called the PFN bitmap, keeps track of all page frames by assigning
00199 // a bit to each. If the bit is set, then the page is valid physical RAM.
00200 //
00201 RTL_BITMAP MiPfnBitMap;
00202 
00203 //
00204 // This structure describes the different pieces of RAM-backed address space
00205 //
00206 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
00207 
00208 //
00209 // This is where we keep track of the most basic physical layout markers
00210 //
00211 PFN_NUMBER MmHighestPhysicalPage, MmLowestPhysicalPage = -1;
00212 PFN_COUNT MmNumberOfPhysicalPages;
00213 
00214 //
00215 // The total number of pages mapped by the boot loader, which include the kernel
00216 // HAL, boot drivers, registry, NLS files and other loader data structures is
00217 // kept track of here. This depends on "LoaderPagesSpanned" being correct when
00218 // coming from the loader.
00219 //
00220 // This number is later aligned up to a PDE boundary.
00221 //
00222 SIZE_T MmBootImageSize;
00223 
00224 //
00225 // These three variables keep track of the core separation of address space that
00226 // exists between kernel mode and user mode.
00227 //
00228 ULONG_PTR MmUserProbeAddress;
00229 PVOID MmHighestUserAddress;
00230 PVOID MmSystemRangeStart;
00231 
00232 /* And these store the respective highest PTE/PDE address */
00233 PMMPTE MiHighestUserPte;
00234 PMMPDE MiHighestUserPde;
00235 #if (_MI_PAGING_LEVELS >= 3)
00236 PMMPTE MiHighestUserPpe;
00237 #if (_MI_PAGING_LEVELS >= 4)
00238 PMMPTE MiHighestUserPxe;
00239 #endif
00240 #endif
00241 
00242 /* These variables define the system cache address space */
00243 PVOID MmSystemCacheStart;
00244 PVOID MmSystemCacheEnd;
00245 MMSUPPORT MmSystemCacheWs;
00246 
00247 //
00248 // This is where hyperspace ends (followed by the system cache working set)
00249 //
00250 PVOID MmHyperSpaceEnd;
00251 
00252 //
00253 // Page coloring algorithm data
00254 //
00255 ULONG MmSecondaryColors;
00256 ULONG MmSecondaryColorMask;
00257 
00258 //
00259 // Actual (registry-configurable) size of a GUI thread's stack
00260 //
00261 ULONG MmLargeStackSize = KERNEL_LARGE_STACK_SIZE;
00262 
00263 //
00264 // Before we have a PFN database, memory comes straight from our physical memory
00265 // blocks, which is nice because it's guaranteed contiguous and also because once
00266 // we take a page from here, the system doesn't see it anymore.
00267 // However, once the fun is over, those pages must be re-integrated back into
00268 // PFN society life, and that requires us keeping a copy of the original layout
00269 // so that we can parse it later.
00270 //
00271 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
00272 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
00273 
00274 /*
00275  * For each page's worth bytes of L2 cache in a given set/way line, the zero and
00276  * free lists are organized in what is called a "color".
00277  *
00278  * This array points to the two lists, so it can be thought of as a multi-dimensional
00279  * array of MmFreePagesByColor[2][MmSecondaryColors]. Since the number is dynamic,
00280  * we describe the array in pointer form instead.
00281  *
00282  * On a final note, the color tables themselves are right after the PFN database.
00283  */
00284 C_ASSERT(FreePageList == 1);
00285 PMMCOLOR_TABLES MmFreePagesByColor[FreePageList + 1];
00286 
00287 /* An event used in Phase 0 before the rest of the system is ready to go */
00288 KEVENT MiTempEvent;
00289 
00290 /* All the events used for memory threshold notifications */
00291 PKEVENT MiLowMemoryEvent;
00292 PKEVENT MiHighMemoryEvent;
00293 PKEVENT MiLowPagedPoolEvent;
00294 PKEVENT MiHighPagedPoolEvent;
00295 PKEVENT MiLowNonPagedPoolEvent;
00296 PKEVENT MiHighNonPagedPoolEvent;
00297 
00298 /* The actual thresholds themselves, in page numbers */
00299 PFN_NUMBER MmLowMemoryThreshold;
00300 PFN_NUMBER MmHighMemoryThreshold;
00301 PFN_NUMBER MiLowPagedPoolThreshold;
00302 PFN_NUMBER MiHighPagedPoolThreshold;
00303 PFN_NUMBER MiLowNonPagedPoolThreshold;
00304 PFN_NUMBER MiHighNonPagedPoolThreshold;
00305 
00306 /*
00307  * This number determines how many free pages must exist, at minimum, until we
00308  * start trimming working sets and flushing modified pages to obtain more free
00309  * pages.
00310  *
00311  * This number changes if the system detects that this is a server product
00312  */
00313 PFN_NUMBER MmMinimumFreePages = 26;
00314 
00315 /*
00316  * This number indicates how many pages we consider to be a low limit of having
00317  * "plenty" of free memory.
00318  *
00319  * It is doubled on systems that have more than 63MB of memory
00320  */
00321 PFN_NUMBER MmPlentyFreePages = 400;
00322 
00323 /* These values store the type of system this is (small, med, large) and if server */
00324 ULONG MmProductType;
00325 MM_SYSTEMSIZE MmSystemSize;
00326 
00327 /*
00328  * These values store the cache working set minimums and maximums, in pages
00329  *
00330  * The minimum value is boosted on systems with more than 24MB of RAM, and cut
00331  * down to only 32 pages on embedded (<24MB RAM) systems.
00332  *
00333  * An extra boost of 2MB is given on systems with more than 33MB of RAM.
00334  */
00335 PFN_NUMBER MmSystemCacheWsMinimum = 288;
00336 PFN_NUMBER MmSystemCacheWsMaximum = 350;
00337 
00338 /* FIXME: Move to cache/working set code later */
00339 BOOLEAN MmLargeSystemCache;
00340 
00341 /*
00342  * This value determines in how many fragments/chunks the subsection prototype
00343  * PTEs should be allocated when mapping a section object. It is configurable in
00344  * the registry through the MapAllocationFragment parameter.
00345  *
00346  * The default is 64KB on systems with more than 1GB of RAM, 32KB on systems with
00347  * more than 256MB of RAM, and 16KB on systems with less than 256MB of RAM.
00348  *
00349  * The maximum it can be set to is 2MB, and the minimum is 4KB.
00350  */
00351 SIZE_T MmAllocationFragment;
00352 
00353 /*
00354  * These two values track how much virtual memory can be committed, and when
00355  * expansion should happen.
00356  */
00357  // FIXME: They should be moved elsewhere since it's not an "init" setting?
00358 SIZE_T MmTotalCommitLimit;
00359 SIZE_T MmTotalCommitLimitMaximum;
00360 
00361 /* Internal setting used for debugging memory descriptors */
00362 BOOLEAN MiDbgEnableMdDump =
00363 #ifdef _ARM_
00364 TRUE;
00365 #else
00366 FALSE;
00367 #endif
00368 
00369 /* Number of memory descriptors in the loader block */
00370 ULONG MiNumberDescriptors = 0;
00371 
00372 /* Number of free pages in the loader block */
00373 PFN_NUMBER MiNumberOfFreePages = 0;
00374 
00375 
00376 /* PRIVATE FUNCTIONS **********************************************************/
00377 
00378 VOID
00379 NTAPI
00380 MiScanMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
00381 {
00382     PLIST_ENTRY ListEntry;
00383     PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
00384     PFN_NUMBER PageFrameIndex, FreePages = 0;
00385 
00386     /* Loop the memory descriptors */
00387     for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
00388          ListEntry != &LoaderBlock->MemoryDescriptorListHead;
00389          ListEntry = ListEntry->Flink)
00390     {
00391         /* Get the descriptor */
00392         Descriptor = CONTAINING_RECORD(ListEntry,
00393                                        MEMORY_ALLOCATION_DESCRIPTOR,
00394                                        ListEntry);
00395         DPRINT("MD Type: %lx Base: %lx Count: %lx\n",
00396             Descriptor->MemoryType, Descriptor->BasePage, Descriptor->PageCount);
00397 
00398         /* Count this descriptor */
00399         MiNumberDescriptors++;
00400 
00401         /* Check if this is invisible memory */
00402         if ((Descriptor->MemoryType == LoaderFirmwarePermanent) ||
00403             (Descriptor->MemoryType == LoaderSpecialMemory) ||
00404             (Descriptor->MemoryType == LoaderHALCachedMemory) ||
00405             (Descriptor->MemoryType == LoaderBBTMemory))
00406         {
00407             /* Skip this descriptor */
00408             continue;
00409         }
00410 
00411         /* Check if this is bad memory */
00412         if (Descriptor->MemoryType != LoaderBad)
00413         {
00414             /* Count this in the total of pages */
00415             MmNumberOfPhysicalPages += (PFN_COUNT)Descriptor->PageCount;
00416         }
00417 
00418         /* Check if this is the new lowest page */
00419         if (Descriptor->BasePage < MmLowestPhysicalPage)
00420         {
00421             /* Update the lowest page */
00422             MmLowestPhysicalPage = Descriptor->BasePage;
00423         }
00424 
00425         /* Check if this is the new highest page */
00426         PageFrameIndex = Descriptor->BasePage + Descriptor->PageCount;
00427         if (PageFrameIndex > MmHighestPhysicalPage)
00428         {
00429             /* Update the highest page */
00430             MmHighestPhysicalPage = PageFrameIndex - 1;
00431         }
00432 
00433         /* Check if this is free memory */
00434         if ((Descriptor->MemoryType == LoaderFree) ||
00435             (Descriptor->MemoryType == LoaderLoadedProgram) ||
00436             (Descriptor->MemoryType == LoaderFirmwareTemporary) ||
00437             (Descriptor->MemoryType == LoaderOsloaderStack))
00438         {
00439             /* Count it too free pages */
00440             MiNumberOfFreePages += Descriptor->PageCount;
00441 
00442             /* Check if this is the largest memory descriptor */
00443             if (Descriptor->PageCount > FreePages)
00444             {
00445                 /* Remember it */
00446                 MxFreeDescriptor = Descriptor;
00447                 FreePages = Descriptor->PageCount;
00448             }
00449         }
00450     }
00451 
00452     /* Save original values of the free descriptor, since it'll be
00453      * altered by early allocations */
00454     MxOldFreeDescriptor = *MxFreeDescriptor;
00455 }
00456 
00457 PFN_NUMBER
00458 NTAPI
00459 INIT_FUNCTION
00460 MxGetNextPage(IN PFN_NUMBER PageCount)
00461 {
00462     PFN_NUMBER Pfn;
00463 
00464     /* Make sure we have enough pages */
00465     if (PageCount > MxFreeDescriptor->PageCount)
00466     {
00467         /* Crash the system */
00468         KeBugCheckEx(INSTALL_MORE_MEMORY,
00469                      MmNumberOfPhysicalPages,
00470                      MxFreeDescriptor->PageCount,
00471                      MxOldFreeDescriptor.PageCount,
00472                      PageCount);
00473     }
00474 
00475     /* Use our lowest usable free pages */
00476     Pfn = MxFreeDescriptor->BasePage;
00477     MxFreeDescriptor->BasePage += PageCount;
00478     MxFreeDescriptor->PageCount -= PageCount;
00479     return Pfn;
00480 }
00481 
00482 VOID
00483 NTAPI
00484 INIT_FUNCTION
00485 MiComputeColorInformation(VOID)
00486 {
00487     ULONG L2Associativity;
00488 
00489     /* Check if no setting was provided already */
00490     if (!MmSecondaryColors)
00491     {
00492         /* Get L2 cache information */
00493         L2Associativity = KeGetPcr()->SecondLevelCacheAssociativity;
00494 
00495         /* The number of colors is the number of cache bytes by set/way */
00496         MmSecondaryColors = KeGetPcr()->SecondLevelCacheSize;
00497         if (L2Associativity) MmSecondaryColors /= L2Associativity;
00498     }
00499 
00500     /* Now convert cache bytes into pages */
00501     MmSecondaryColors >>= PAGE_SHIFT;
00502     if (!MmSecondaryColors)
00503     {
00504         /* If there was no cache data from the KPCR, use the default colors */
00505         MmSecondaryColors = MI_SECONDARY_COLORS;
00506     }
00507     else
00508     {
00509         /* Otherwise, make sure there aren't too many colors */
00510         if (MmSecondaryColors > MI_MAX_SECONDARY_COLORS)
00511         {
00512             /* Set the maximum */
00513             MmSecondaryColors = MI_MAX_SECONDARY_COLORS;
00514         }
00515 
00516         /* Make sure there aren't too little colors */
00517         if (MmSecondaryColors < MI_MIN_SECONDARY_COLORS)
00518         {
00519             /* Set the default */
00520             MmSecondaryColors = MI_SECONDARY_COLORS;
00521         }
00522 
00523         /* Finally make sure the colors are a power of two */
00524         if (MmSecondaryColors & (MmSecondaryColors - 1))
00525         {
00526             /* Set the default */
00527             MmSecondaryColors = MI_SECONDARY_COLORS;
00528         }
00529     }
00530 
00531     /* Compute the mask and store it */
00532     MmSecondaryColorMask = MmSecondaryColors - 1;
00533     KeGetCurrentPrcb()->SecondaryColorMask = MmSecondaryColorMask;
00534 }
00535 
00536 VOID
00537 NTAPI
00538 INIT_FUNCTION
00539 MiInitializeColorTables(VOID)
00540 {
00541     ULONG i;
00542     PMMPTE PointerPte, LastPte;
00543     MMPTE TempPte = ValidKernelPte;
00544 
00545     /* The color table starts after the ARM3 PFN database */
00546     MmFreePagesByColor[0] = (PMMCOLOR_TABLES)&MmPfnDatabase[MmHighestPhysicalPage + 1];
00547 
00548     /* Loop the PTEs. We have two color tables for each secondary color */
00549     PointerPte = MiAddressToPte(&MmFreePagesByColor[0][0]);
00550     LastPte = MiAddressToPte((ULONG_PTR)MmFreePagesByColor[0] +
00551                              (2 * MmSecondaryColors * sizeof(MMCOLOR_TABLES))
00552                              - 1);
00553     while (PointerPte <= LastPte)
00554     {
00555         /* Check for valid PTE */
00556         if (PointerPte->u.Hard.Valid == 0)
00557         {
00558             /* Get a page and map it */
00559             TempPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
00560             MI_WRITE_VALID_PTE(PointerPte, TempPte);
00561 
00562             /* Zero out the page */
00563             RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
00564         }
00565 
00566         /* Next */
00567         PointerPte++;
00568     }
00569 
00570     /* Now set the address of the next list, right after this one */
00571     MmFreePagesByColor[1] = &MmFreePagesByColor[0][MmSecondaryColors];
00572 
00573     /* Now loop the lists to set them up */
00574     for (i = 0; i < MmSecondaryColors; i++)
00575     {
00576         /* Set both free and zero lists for each color */
00577         MmFreePagesByColor[ZeroedPageList][i].Flink = LIST_HEAD;
00578         MmFreePagesByColor[ZeroedPageList][i].Blink = (PVOID)LIST_HEAD;
00579         MmFreePagesByColor[ZeroedPageList][i].Count = 0;
00580         MmFreePagesByColor[FreePageList][i].Flink = LIST_HEAD;
00581         MmFreePagesByColor[FreePageList][i].Blink = (PVOID)LIST_HEAD;
00582         MmFreePagesByColor[FreePageList][i].Count = 0;
00583     }
00584 }
00585 
00586 #ifndef _M_AMD64
00587 BOOLEAN
00588 NTAPI
00589 INIT_FUNCTION
00590 MiIsRegularMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
00591                   IN PFN_NUMBER Pfn)
00592 {
00593     PLIST_ENTRY NextEntry;
00594     PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
00595 
00596     /* Loop the memory descriptors */
00597     NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
00598     while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
00599     {
00600         /* Get the memory descriptor */
00601         MdBlock = CONTAINING_RECORD(NextEntry,
00602                                     MEMORY_ALLOCATION_DESCRIPTOR,
00603                                     ListEntry);
00604 
00605         /* Check if this PFN could be part of the block */
00606         if (Pfn >= (MdBlock->BasePage))
00607         {
00608             /* Check if it really is part of the block */
00609             if (Pfn < (MdBlock->BasePage + MdBlock->PageCount))
00610             {
00611                 /* Check if the block is actually memory we don't map */
00612                 if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
00613                     (MdBlock->MemoryType == LoaderBBTMemory) ||
00614                     (MdBlock->MemoryType == LoaderSpecialMemory))
00615                 {
00616                     /* We don't need PFN database entries for this memory */
00617                     break;
00618                 }
00619 
00620                 /* This is memory we want to map */
00621                 return TRUE;
00622             }
00623         }
00624         else
00625         {
00626             /* Blocks are ordered, so if it's not here, it doesn't exist */
00627             break;
00628         }
00629 
00630         /* Get to the next descriptor */
00631         NextEntry = MdBlock->ListEntry.Flink;
00632     }
00633 
00634     /* Check if this PFN is actually from our free memory descriptor */
00635     if ((Pfn >= MxOldFreeDescriptor.BasePage) &&
00636         (Pfn < MxOldFreeDescriptor.BasePage + MxOldFreeDescriptor.PageCount))
00637     {
00638         /* We use these pages for initial mappings, so we do want to count them */
00639         return TRUE;
00640     }
00641 
00642     /* Otherwise this isn't memory that we describe or care about */
00643     return FALSE;
00644 }
00645 
00646 VOID
00647 NTAPI
00648 INIT_FUNCTION
00649 MiMapPfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
00650 {
00651     PFN_NUMBER FreePage, FreePageCount, PagesLeft, BasePage, PageCount;
00652     PLIST_ENTRY NextEntry;
00653     PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
00654     PMMPTE PointerPte, LastPte;
00655     MMPTE TempPte = ValidKernelPte;
00656 
00657     /* Get current page data, since we won't be using MxGetNextPage as it would corrupt our state */
00658     FreePage = MxFreeDescriptor->BasePage;
00659     FreePageCount = MxFreeDescriptor->PageCount;
00660     PagesLeft = 0;
00661 
00662     /* Loop the memory descriptors */
00663     NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
00664     while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
00665     {
00666         /* Get the descriptor */
00667         MdBlock = CONTAINING_RECORD(NextEntry,
00668                                     MEMORY_ALLOCATION_DESCRIPTOR,
00669                                     ListEntry);
00670         if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
00671             (MdBlock->MemoryType == LoaderBBTMemory) ||
00672             (MdBlock->MemoryType == LoaderSpecialMemory))
00673         {
00674             /* These pages are not part of the PFN database */
00675             NextEntry = MdBlock->ListEntry.Flink;
00676             continue;
00677         }
00678 
00679         /* Next, check if this is our special free descriptor we've found */
00680         if (MdBlock == MxFreeDescriptor)
00681         {
00682             /* Use the real numbers instead */
00683             BasePage = MxOldFreeDescriptor.BasePage;
00684             PageCount = MxOldFreeDescriptor.PageCount;
00685         }
00686         else
00687         {
00688             /* Use the descriptor's numbers */
00689             BasePage = MdBlock->BasePage;
00690             PageCount = MdBlock->PageCount;
00691         }
00692 
00693         /* Get the PTEs for this range */
00694         PointerPte = MiAddressToPte(&MmPfnDatabase[BasePage]);
00695         LastPte = MiAddressToPte(((ULONG_PTR)&MmPfnDatabase[BasePage + PageCount]) - 1);
00696         DPRINT("MD Type: %lx Base: %lx Count: %lx\n", MdBlock->MemoryType, BasePage, PageCount);
00697 
00698         /* Loop them */
00699         while (PointerPte <= LastPte)
00700         {
00701             /* We'll only touch PTEs that aren't already valid */
00702             if (PointerPte->u.Hard.Valid == 0)
00703             {
00704                 /* Use the next free page */
00705                 TempPte.u.Hard.PageFrameNumber = FreePage;
00706                 ASSERT(FreePageCount != 0);
00707 
00708                 /* Consume free pages */
00709                 FreePage++;
00710                 FreePageCount--;
00711                 if (!FreePageCount)
00712                 {
00713                     /* Out of memory */
00714                     KeBugCheckEx(INSTALL_MORE_MEMORY,
00715                                  MmNumberOfPhysicalPages,
00716                                  FreePageCount,
00717                                  MxOldFreeDescriptor.PageCount,
00718                                  1);
00719                 }
00720 
00721                 /* Write out this PTE */
00722                 PagesLeft++;
00723                 MI_WRITE_VALID_PTE(PointerPte, TempPte);
00724 
00725                 /* Zero this page */
00726                 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE);
00727             }
00728 
00729             /* Next! */
00730             PointerPte++;
00731         }
00732 
00733         /* Do the next address range */
00734         NextEntry = MdBlock->ListEntry.Flink;
00735     }
00736 
00737     /* Now update the free descriptors to consume the pages we used up during the PFN allocation loop */
00738     MxFreeDescriptor->BasePage = FreePage;
00739     MxFreeDescriptor->PageCount = FreePageCount;
00740 }
00741 
00742 VOID
00743 NTAPI
00744 INIT_FUNCTION
00745 MiBuildPfnDatabaseFromPages(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
00746 {
00747     PMMPDE PointerPde;
00748     PMMPTE PointerPte;
00749     ULONG i, Count, j;
00750     PFN_NUMBER PageFrameIndex, StartupPdIndex, PtePageIndex;
00751     PMMPFN Pfn1, Pfn2;
00752     ULONG_PTR BaseAddress = 0;
00753 
00754     /* PFN of the startup page directory */
00755     StartupPdIndex = PFN_FROM_PTE(MiAddressToPde(PDE_BASE));
00756 
00757     /* Start with the first PDE and scan them all */
00758     PointerPde = MiAddressToPde(NULL);
00759     Count = PD_COUNT * PDE_COUNT;
00760     for (i = 0; i < Count; i++)
00761     {
00762         /* Check for valid PDE */
00763         if (PointerPde->u.Hard.Valid == 1)
00764         {
00765             /* Get the PFN from it */
00766             PageFrameIndex = PFN_FROM_PTE(PointerPde);
00767 
00768             /* Do we want a PFN entry for this page? */
00769             if (MiIsRegularMemory(LoaderBlock, PageFrameIndex))
00770             {
00771                 /* Yes we do, set it up */
00772                 Pfn1 = MiGetPfnEntry(PageFrameIndex);
00773                 Pfn1->u4.PteFrame = StartupPdIndex;
00774                 Pfn1->PteAddress = (PMMPTE)PointerPde;
00775                 Pfn1->u2.ShareCount++;
00776                 Pfn1->u3.e2.ReferenceCount = 1;
00777                 Pfn1->u3.e1.PageLocation = ActiveAndValid;
00778                 Pfn1->u3.e1.CacheAttribute = MiNonCached;
00779 #if MI_TRACE_PFNS
00780                 Pfn1->PfnUsage = MI_USAGE_INIT_MEMORY;
00781                 memcpy(Pfn1->ProcessName, "Initial PDE", 16);
00782 #endif
00783             }
00784             else
00785             {
00786                 /* No PFN entry */
00787                 Pfn1 = NULL;
00788             }
00789 
00790             /* Now get the PTE and scan the pages */
00791             PointerPte = MiAddressToPte(BaseAddress);
00792             for (j = 0; j < PTE_COUNT; j++)
00793             {
00794                 /* Check for a valid PTE */
00795                 if (PointerPte->u.Hard.Valid == 1)
00796                 {
00797                     /* Increase the shared count of the PFN entry for the PDE */
00798                     ASSERT(Pfn1 != NULL);
00799                     Pfn1->u2.ShareCount++;
00800 
00801                     /* Now check if the PTE is valid memory too */
00802                     PtePageIndex = PFN_FROM_PTE(PointerPte);
00803                     if (MiIsRegularMemory(LoaderBlock, PtePageIndex))
00804                     {
00805                         /*
00806                          * Only add pages above the end of system code or pages
00807                          * that are part of nonpaged pool
00808                          */
00809                         if ((BaseAddress >= 0xA0000000) ||
00810                             ((BaseAddress >= (ULONG_PTR)MmNonPagedPoolStart) &&
00811                              (BaseAddress < (ULONG_PTR)MmNonPagedPoolStart +
00812                                             MmSizeOfNonPagedPoolInBytes)))
00813                         {
00814                             /* Get the PFN entry and make sure it too is valid */
00815                             Pfn2 = MiGetPfnEntry(PtePageIndex);
00816                             if ((MmIsAddressValid(Pfn2)) &&
00817                                 (MmIsAddressValid(Pfn2 + 1)))
00818                             {
00819                                 /* Setup the PFN entry */
00820                                 Pfn2->u4.PteFrame = PageFrameIndex;
00821                                 Pfn2->PteAddress = PointerPte;
00822                                 Pfn2->u2.ShareCount++;
00823                                 Pfn2->u3.e2.ReferenceCount = 1;
00824                                 Pfn2->u3.e1.PageLocation = ActiveAndValid;
00825                                 Pfn2->u3.e1.CacheAttribute = MiNonCached;
00826 #if MI_TRACE_PFNS
00827                                 Pfn2->PfnUsage = MI_USAGE_INIT_MEMORY;
00828                                 memcpy(Pfn1->ProcessName, "Initial PTE", 16);
00829 #endif
00830                             }
00831                         }
00832                     }
00833                 }
00834 
00835                 /* Next PTE */
00836                 PointerPte++;
00837                 BaseAddress += PAGE_SIZE;
00838             }
00839         }
00840         else
00841         {
00842             /* Next PDE mapped address */
00843             BaseAddress += PDE_MAPPED_VA;
00844         }
00845 
00846         /* Next PTE */
00847         PointerPde++;
00848     }
00849 }
00850 
00851 VOID
00852 NTAPI
00853 INIT_FUNCTION
00854 MiBuildPfnDatabaseZeroPage(VOID)
00855 {
00856     PMMPFN Pfn1;
00857     PMMPDE PointerPde;
00858 
00859     /* Grab the lowest page and check if it has no real references */
00860     Pfn1 = MiGetPfnEntry(MmLowestPhysicalPage);
00861     if (!(MmLowestPhysicalPage) && !(Pfn1->u3.e2.ReferenceCount))
00862     {
00863         /* Make it a bogus page to catch errors */
00864         PointerPde = MiAddressToPde(0xFFFFFFFF);
00865         Pfn1->u4.PteFrame = PFN_FROM_PTE(PointerPde);
00866         Pfn1->PteAddress = (PMMPTE)PointerPde;
00867         Pfn1->u2.ShareCount++;
00868         Pfn1->u3.e2.ReferenceCount = 0xFFF0;
00869         Pfn1->u3.e1.PageLocation = ActiveAndValid;
00870         Pfn1->u3.e1.CacheAttribute = MiNonCached;
00871     }
00872 }
00873 
00874 VOID
00875 NTAPI
00876 INIT_FUNCTION
00877 MiBuildPfnDatabaseFromLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
00878 {
00879     PLIST_ENTRY NextEntry;
00880     PFN_NUMBER PageCount = 0;
00881     PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
00882     PFN_NUMBER PageFrameIndex;
00883     PMMPFN Pfn1;
00884     PMMPTE PointerPte;
00885     PMMPDE PointerPde;
00886     KIRQL OldIrql;
00887 
00888     /* Now loop through the descriptors */
00889     NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
00890     while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
00891     {
00892         /* Get the current descriptor */
00893         MdBlock = CONTAINING_RECORD(NextEntry,
00894                                     MEMORY_ALLOCATION_DESCRIPTOR,
00895                                     ListEntry);
00896 
00897         /* Read its data */
00898         PageCount = MdBlock->PageCount;
00899         PageFrameIndex = MdBlock->BasePage;
00900 
00901         /* Don't allow memory above what the PFN database is mapping */
00902         if (PageFrameIndex > MmHighestPhysicalPage)
00903         {
00904             /* Since they are ordered, everything past here will be larger */
00905             break;
00906         }
00907 
00908         /* On the other hand, the end page might be higher up... */
00909         if ((PageFrameIndex + PageCount) > (MmHighestPhysicalPage + 1))
00910         {
00911             /* In which case we'll trim the descriptor to go as high as we can */
00912             PageCount = MmHighestPhysicalPage + 1 - PageFrameIndex;
00913             MdBlock->PageCount = PageCount;
00914 
00915             /* But if there's nothing left to trim, we got too high, so quit */
00916             if (!PageCount) break;
00917         }
00918 
00919         /* Now check the descriptor type */
00920         switch (MdBlock->MemoryType)
00921         {
00922             /* Check for bad RAM */
00923             case LoaderBad:
00924 
00925                 DPRINT1("You either have specified /BURNMEMORY or damaged RAM modules.\n");
00926                 break;
00927 
00928             /* Check for free RAM */
00929             case LoaderFree:
00930             case LoaderLoadedProgram:
00931             case LoaderFirmwareTemporary:
00932             case LoaderOsloaderStack:
00933 
00934                 /* Get the last page of this descriptor. Note we loop backwards */
00935                 PageFrameIndex += PageCount - 1;
00936                 Pfn1 = MiGetPfnEntry(PageFrameIndex);
00937 
00938                 /* Lock the PFN Database */
00939                 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00940                 while (PageCount--)
00941                 {
00942                     /* If the page really has no references, mark it as free */
00943                     if (!Pfn1->u3.e2.ReferenceCount)
00944                     {
00945                         /* Add it to the free list */
00946                         Pfn1->u3.e1.CacheAttribute = MiNonCached;
00947                         MiInsertPageInFreeList(PageFrameIndex);
00948                     }
00949 
00950                     /* Go to the next page */
00951                     Pfn1--;
00952                     PageFrameIndex--;
00953                 }
00954 
00955                 /* Release PFN database */
00956                 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00957 
00958                 /* Done with this block */
00959                 break;
00960 
00961             /* Check for pages that are invisible to us */
00962             case LoaderFirmwarePermanent:
00963             case LoaderSpecialMemory:
00964             case LoaderBBTMemory:
00965 
00966                 /* And skip them */
00967                 break;
00968 
00969             default:
00970 
00971                 /* Map these pages with the KSEG0 mapping that adds 0x80000000 */
00972                 PointerPte = MiAddressToPte(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT));
00973                 Pfn1 = MiGetPfnEntry(PageFrameIndex);
00974                 while (PageCount--)
00975                 {
00976                     /* Check if the page is really unused */
00977                     PointerPde = MiAddressToPde(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT));
00978                     if (!Pfn1->u3.e2.ReferenceCount)
00979                     {
00980                         /* Mark it as being in-use */
00981                         Pfn1->u4.PteFrame = PFN_FROM_PTE(PointerPde);
00982                         Pfn1->PteAddress = PointerPte;
00983                         Pfn1->u2.ShareCount++;
00984                         Pfn1->u3.e2.ReferenceCount = 1;
00985                         Pfn1->u3.e1.PageLocation = ActiveAndValid;
00986                         Pfn1->u3.e1.CacheAttribute = MiNonCached;
00987 #if MI_TRACE_PFNS
00988                         Pfn1->PfnUsage = MI_USAGE_BOOT_DRIVER;
00989 #endif
00990 
00991                         /* Check for RAM disk page */
00992                         if (MdBlock->MemoryType == LoaderXIPRom)
00993                         {
00994                             /* Make it a pseudo-I/O ROM mapping */
00995                             Pfn1->u1.Flink = 0;
00996                             Pfn1->u2.ShareCount = 0;
00997                             Pfn1->u3.e2.ReferenceCount = 0;
00998                             Pfn1->u3.e1.PageLocation = 0;
00999                             Pfn1->u3.e1.Rom = 1;
01000                             Pfn1->u4.InPageError = 0;
01001                             Pfn1->u3.e1.PrototypePte = 1;
01002                         }
01003                     }
01004 
01005                     /* Advance page structures */
01006                     Pfn1++;
01007                     PageFrameIndex++;
01008                     PointerPte++;
01009                 }
01010                 break;
01011         }
01012 
01013         /* Next descriptor entry */
01014         NextEntry = MdBlock->ListEntry.Flink;
01015     }
01016 }
01017 
01018 VOID
01019 NTAPI
01020 INIT_FUNCTION
01021 MiBuildPfnDatabaseSelf(VOID)
01022 {
01023     PMMPTE PointerPte, LastPte;
01024     PMMPFN Pfn1;
01025 
01026     /* Loop the PFN database page */
01027     PointerPte = MiAddressToPte(MiGetPfnEntry(MmLowestPhysicalPage));
01028     LastPte = MiAddressToPte(MiGetPfnEntry(MmHighestPhysicalPage));
01029     while (PointerPte <= LastPte)
01030     {
01031         /* Make sure the page is valid */
01032         if (PointerPte->u.Hard.Valid == 1)
01033         {
01034             /* Get the PFN entry and just mark it referenced */
01035             Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
01036             Pfn1->u2.ShareCount = 1;
01037             Pfn1->u3.e2.ReferenceCount = 1;
01038 #if MI_TRACE_PFNS
01039             Pfn1->PfnUsage = MI_USAGE_PFN_DATABASE;
01040 #endif
01041         }
01042 
01043         /* Next */
01044         PointerPte++;
01045     }
01046 }
01047 
01048 VOID
01049 NTAPI
01050 INIT_FUNCTION
01051 MiInitializePfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
01052 {
01053     /* Scan memory and start setting up PFN entries */
01054     MiBuildPfnDatabaseFromPages(LoaderBlock);
01055 
01056     /* Add the zero page */
01057     MiBuildPfnDatabaseZeroPage();
01058 
01059     /* Scan the loader block and build the rest of the PFN database */
01060     MiBuildPfnDatabaseFromLoaderBlock(LoaderBlock);
01061 
01062     /* Finally add the pages for the PFN database itself */
01063     MiBuildPfnDatabaseSelf();
01064 }
01065 #endif /* !_M_AMD64 */
01066 
01067 VOID
01068 NTAPI
01069 INIT_FUNCTION
01070 MmFreeLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
01071 {
01072     PLIST_ENTRY NextMd;
01073     PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
01074     ULONG_PTR i;
01075     PFN_NUMBER BasePage, LoaderPages;
01076     PMMPFN Pfn1;
01077     KIRQL OldIrql;
01078     PPHYSICAL_MEMORY_RUN Buffer, Entry;
01079 
01080     /* Loop the descriptors in order to count them */
01081     i = 0;
01082     NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
01083     while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
01084     {
01085         MdBlock = CONTAINING_RECORD(NextMd,
01086                                     MEMORY_ALLOCATION_DESCRIPTOR,
01087                                     ListEntry);
01088         i++;
01089         NextMd = MdBlock->ListEntry.Flink;
01090     }
01091 
01092     /* Allocate a structure to hold the physical runs */
01093     Buffer = ExAllocatePoolWithTag(NonPagedPool,
01094                                    i * sizeof(PHYSICAL_MEMORY_RUN),
01095                                    'lMmM');
01096     ASSERT(Buffer != NULL);
01097     Entry = Buffer;
01098 
01099     /* Loop the descriptors again */
01100     NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
01101     while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
01102     {
01103         /* Check what kind this was */
01104         MdBlock = CONTAINING_RECORD(NextMd,
01105                                     MEMORY_ALLOCATION_DESCRIPTOR,
01106                                     ListEntry);
01107         switch (MdBlock->MemoryType)
01108         {
01109             /* Registry, NLS, and heap data */
01110             case LoaderRegistryData:
01111             case LoaderOsloaderHeap:
01112             case LoaderNlsData:
01113                 /* Are all a candidate for deletion */
01114                 Entry->BasePage = MdBlock->BasePage;
01115                 Entry->PageCount = MdBlock->PageCount;
01116                 Entry++;
01117 
01118             /* We keep the rest */
01119             default:
01120                 break;
01121         }
01122 
01123         /* Move to the next descriptor */
01124         NextMd = MdBlock->ListEntry.Flink;
01125     }
01126 
01127     /* Acquire the PFN lock */
01128     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01129 
01130     /* Loop the runs */
01131     LoaderPages = 0;
01132     while (--Entry >= Buffer)
01133     {
01134         /* See how many pages are in this run */
01135         i = Entry->PageCount;
01136         BasePage = Entry->BasePage;
01137 
01138         /* Loop each page */
01139         Pfn1 = MiGetPfnEntry(BasePage);
01140         while (i--)
01141         {
01142             /* Check if it has references or is in any kind of list */
01143             if (!(Pfn1->u3.e2.ReferenceCount) && (!Pfn1->u1.Flink))
01144             {
01145                 /* Set the new PTE address and put this page into the free list */
01146                 Pfn1->PteAddress = (PMMPTE)(BasePage << PAGE_SHIFT);
01147                 MiInsertPageInFreeList(BasePage);
01148                 LoaderPages++;
01149             }
01150             else if (BasePage)
01151             {
01152                 /* It has a reference, so simply drop it */
01153                 ASSERT(MI_IS_PHYSICAL_ADDRESS(MiPteToAddress(Pfn1->PteAddress)) == FALSE);
01154 
01155                 /* Drop a dereference on this page, which should delete it */
01156                 Pfn1->PteAddress->u.Long = 0;
01157                 MI_SET_PFN_DELETED(Pfn1);
01158                 MiDecrementShareCount(Pfn1, BasePage);
01159                 LoaderPages++;
01160             }
01161 
01162             /* Move to the next page */
01163             Pfn1++;
01164             BasePage++;
01165         }
01166     }
01167 
01168     /* Release the PFN lock and flush the TLB */
01169     DPRINT1("Loader pages freed: %lx\n", LoaderPages);
01170     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01171     KeFlushCurrentTb();
01172 
01173     /* Free our run structure */
01174     ExFreePool(Buffer);
01175 }
01176 
01177 VOID
01178 NTAPI
01179 INIT_FUNCTION
01180 MiAdjustWorkingSetManagerParameters(IN BOOLEAN Client)
01181 {
01182     /* This function needs to do more work, for now, we tune page minimums */
01183 
01184     /* Check for a system with around 64MB RAM or more */
01185     if (MmNumberOfPhysicalPages >= (63 * _1MB) / PAGE_SIZE)
01186     {
01187         /* Double the minimum amount of pages we consider for a "plenty free" scenario */
01188         MmPlentyFreePages *= 2;
01189     }
01190 }
01191 
01192 VOID
01193 NTAPI
01194 INIT_FUNCTION
01195 MiNotifyMemoryEvents(VOID)
01196 {
01197     /* Are we in a low-memory situation? */
01198     if (MmAvailablePages < MmLowMemoryThreshold)
01199     {
01200         /* Clear high, set low  */
01201         if (KeReadStateEvent(MiHighMemoryEvent)) KeClearEvent(MiHighMemoryEvent);
01202         if (!KeReadStateEvent(MiLowMemoryEvent)) KeSetEvent(MiLowMemoryEvent, 0, FALSE);
01203     }
01204     else if (MmAvailablePages < MmHighMemoryThreshold)
01205     {
01206         /* We are in between, clear both */
01207         if (KeReadStateEvent(MiHighMemoryEvent)) KeClearEvent(MiHighMemoryEvent);
01208         if (KeReadStateEvent(MiLowMemoryEvent)) KeClearEvent(MiLowMemoryEvent);
01209     }
01210     else
01211     {
01212         /* Clear low, set high  */
01213         if (KeReadStateEvent(MiLowMemoryEvent)) KeClearEvent(MiLowMemoryEvent);
01214         if (!KeReadStateEvent(MiHighMemoryEvent)) KeSetEvent(MiHighMemoryEvent, 0, FALSE);
01215     }
01216 }
01217 
01218 NTSTATUS
01219 NTAPI
01220 INIT_FUNCTION
01221 MiCreateMemoryEvent(IN PUNICODE_STRING Name,
01222                     OUT PKEVENT *Event)
01223 {
01224     PACL Dacl;
01225     HANDLE EventHandle;
01226     ULONG DaclLength;
01227     NTSTATUS Status;
01228     OBJECT_ATTRIBUTES ObjectAttributes;
01229     SECURITY_DESCRIPTOR SecurityDescriptor;
01230 
01231     /* Create the SD */
01232     Status = RtlCreateSecurityDescriptor(&SecurityDescriptor,
01233                                          SECURITY_DESCRIPTOR_REVISION);
01234     if (!NT_SUCCESS(Status)) return Status;
01235 
01236     /* One ACL with 3 ACEs, containing each one SID */
01237     DaclLength = sizeof(ACL) +
01238                  3 * sizeof(ACCESS_ALLOWED_ACE) +
01239                  RtlLengthSid(SeLocalSystemSid) +
01240                  RtlLengthSid(SeAliasAdminsSid) +
01241                  RtlLengthSid(SeWorldSid);
01242 
01243     /* Allocate space for the DACL */
01244     Dacl = ExAllocatePoolWithTag(PagedPool, DaclLength, 'lcaD');
01245     if (!Dacl) return STATUS_INSUFFICIENT_RESOURCES;
01246 
01247     /* Setup the ACL inside it */
01248     Status = RtlCreateAcl(Dacl, DaclLength, ACL_REVISION);
01249     if (!NT_SUCCESS(Status)) goto CleanUp;
01250 
01251     /* Add query rights for everyone */
01252     Status = RtlAddAccessAllowedAce(Dacl,
01253                                     ACL_REVISION,
01254                                     SYNCHRONIZE | EVENT_QUERY_STATE | READ_CONTROL,
01255                                     SeWorldSid);
01256     if (!NT_SUCCESS(Status)) goto CleanUp;
01257 
01258     /* Full rights for the admin */
01259     Status = RtlAddAccessAllowedAce(Dacl,
01260                                     ACL_REVISION,
01261                                     EVENT_ALL_ACCESS,
01262                                     SeAliasAdminsSid);
01263     if (!NT_SUCCESS(Status)) goto CleanUp;
01264 
01265     /* As well as full rights for the system */
01266     Status = RtlAddAccessAllowedAce(Dacl,
01267                                     ACL_REVISION,
01268                                     EVENT_ALL_ACCESS,
01269                                     SeLocalSystemSid);
01270     if (!NT_SUCCESS(Status)) goto CleanUp;
01271 
01272     /* Set this DACL inside the SD */
01273     Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor,
01274                                           TRUE,
01275                                           Dacl,
01276                                           FALSE);
01277     if (!NT_SUCCESS(Status)) goto CleanUp;
01278 
01279     /* Setup the event attributes, making sure it's a permanent one */
01280     InitializeObjectAttributes(&ObjectAttributes,
01281                                Name,
01282                                OBJ_KERNEL_HANDLE | OBJ_PERMANENT,
01283                                NULL,
01284                                &SecurityDescriptor);
01285 
01286     /* Create the event */
01287     Status = ZwCreateEvent(&EventHandle,
01288                            EVENT_ALL_ACCESS,
01289                            &ObjectAttributes,
01290                            NotificationEvent,
01291                            FALSE);
01292 CleanUp:
01293     /* Free the DACL */
01294     ExFreePoolWithTag(Dacl, 'lcaD');
01295 
01296     /* Check if this is the success path */
01297     if (NT_SUCCESS(Status))
01298     {
01299         /* Add a reference to the object, then close the handle we had */
01300         Status = ObReferenceObjectByHandle(EventHandle,
01301                                            EVENT_MODIFY_STATE,
01302                                            ExEventObjectType,
01303                                            KernelMode,
01304                                            (PVOID*)Event,
01305                                            NULL);
01306         ZwClose (EventHandle);
01307     }
01308 
01309     /* Return status */
01310     return Status;
01311 }
01312 
01313 BOOLEAN
01314 NTAPI
01315 INIT_FUNCTION
01316 MiInitializeMemoryEvents(VOID)
01317 {
01318     UNICODE_STRING LowString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowMemoryCondition");
01319     UNICODE_STRING HighString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighMemoryCondition");
01320     UNICODE_STRING LowPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowPagedPoolCondition");
01321     UNICODE_STRING HighPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighPagedPoolCondition");
01322     UNICODE_STRING LowNonPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowNonPagedPoolCondition");
01323     UNICODE_STRING HighNonPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighNonPagedPoolCondition");
01324     NTSTATUS Status;
01325 
01326     /* Check if we have a registry setting */
01327     if (MmLowMemoryThreshold)
01328     {
01329         /* Convert it to pages */
01330         MmLowMemoryThreshold *= (_1MB / PAGE_SIZE);
01331     }
01332     else
01333     {
01334         /* The low memory threshold is hit when we don't consider that we have "plenty" of free pages anymore */
01335         MmLowMemoryThreshold = MmPlentyFreePages;
01336 
01337         /* More than one GB of memory? */
01338         if (MmNumberOfPhysicalPages > 0x40000)
01339         {
01340             /* Start at 32MB, and add another 16MB for each GB */
01341             MmLowMemoryThreshold = (32 * _1MB) / PAGE_SIZE;
01342             MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x40000) >> 7);
01343         }
01344         else if (MmNumberOfPhysicalPages > 0x8000)
01345         {
01346             /* For systems with > 128MB RAM, add another 4MB for each 128MB */
01347             MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x8000) >> 5);
01348         }
01349 
01350         /* Don't let the minimum threshold go past 64MB */
01351         MmLowMemoryThreshold = min(MmLowMemoryThreshold, (64 * _1MB) / PAGE_SIZE);
01352     }
01353 
01354     /* Check if we have a registry setting */
01355     if (MmHighMemoryThreshold)
01356     {
01357         /* Convert it into pages */
01358         MmHighMemoryThreshold *= (_1MB / PAGE_SIZE);
01359     }
01360     else
01361     {
01362         /* Otherwise, the default is three times the low memory threshold */
01363         MmHighMemoryThreshold = 3 * MmLowMemoryThreshold;
01364         ASSERT(MmHighMemoryThreshold > MmLowMemoryThreshold);
01365     }
01366 
01367     /* Make sure high threshold is actually higher than the low */
01368     MmHighMemoryThreshold = max(MmHighMemoryThreshold, MmLowMemoryThreshold);
01369 
01370     /* Create the memory events for all the thresholds */
01371     Status = MiCreateMemoryEvent(&LowString, &MiLowMemoryEvent);
01372     if (!NT_SUCCESS(Status)) return FALSE;
01373     Status = MiCreateMemoryEvent(&HighString, &MiHighMemoryEvent);
01374     if (!NT_SUCCESS(Status)) return FALSE;
01375     Status = MiCreateMemoryEvent(&LowPagedPoolString, &MiLowPagedPoolEvent);
01376     if (!NT_SUCCESS(Status)) return FALSE;
01377     Status = MiCreateMemoryEvent(&HighPagedPoolString, &MiHighPagedPoolEvent);
01378     if (!NT_SUCCESS(Status)) return FALSE;
01379     Status = MiCreateMemoryEvent(&LowNonPagedPoolString, &MiLowNonPagedPoolEvent);
01380     if (!NT_SUCCESS(Status)) return FALSE;
01381     Status = MiCreateMemoryEvent(&HighNonPagedPoolString, &MiHighNonPagedPoolEvent);
01382     if (!NT_SUCCESS(Status)) return FALSE;
01383 
01384     /* Now setup the pool events */
01385     MiInitializePoolEvents();
01386 
01387     /* Set the initial event state */
01388     MiNotifyMemoryEvents();
01389     return TRUE;
01390 }
01391 
01392 VOID
01393 NTAPI
01394 INIT_FUNCTION
01395 MiAddHalIoMappings(VOID)
01396 {
01397     PVOID BaseAddress;
01398     PMMPDE PointerPde, LastPde;
01399     PMMPTE PointerPte;
01400     ULONG j;
01401     PFN_NUMBER PageFrameIndex;
01402 
01403     /* HAL Heap address -- should be on a PDE boundary */
01404     BaseAddress = (PVOID)MM_HAL_VA_START;
01405     ASSERT(MiAddressToPteOffset(BaseAddress) == 0);
01406 
01407     /* Check how many PDEs the heap has */
01408     PointerPde = MiAddressToPde(BaseAddress);
01409     LastPde = MiAddressToPde((PVOID)MM_HAL_VA_END);
01410 
01411     while (PointerPde <= LastPde)
01412     {
01413         /* Does the HAL own this mapping? */
01414         if ((PointerPde->u.Hard.Valid == 1) &&
01415             (MI_IS_PAGE_LARGE(PointerPde) == FALSE))
01416         {
01417             /* Get the PTE for it and scan each page */
01418             PointerPte = MiAddressToPte(BaseAddress);
01419             for (j = 0 ; j < PTE_COUNT; j++)
01420             {
01421                 /* Does the HAL own this page? */
01422                 if (PointerPte->u.Hard.Valid == 1)
01423                 {
01424                     /* Is the HAL using it for device or I/O mapped memory? */
01425                     PageFrameIndex = PFN_FROM_PTE(PointerPte);
01426                     if (!MiGetPfnEntry(PageFrameIndex))
01427                     {
01428                         /* FIXME: For PAT, we need to track I/O cache attributes for coherency */
01429                         DPRINT1("HAL I/O Mapping at %p is unsafe\n", BaseAddress);
01430                     }
01431                 }
01432 
01433                 /* Move to the next page */
01434                 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
01435                 PointerPte++;
01436             }
01437         }
01438         else
01439         {
01440             /* Move to the next address */
01441             BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PDE_MAPPED_VA);
01442         }
01443 
01444         /* Move to the next PDE */
01445         PointerPde++;
01446     }
01447 }
01448 
01449 VOID
01450 NTAPI
01451 MmDumpArmPfnDatabase(IN BOOLEAN StatusOnly)
01452 {
01453     ULONG i;
01454     PMMPFN Pfn1;
01455     PCHAR Consumer = "Unknown";
01456     KIRQL OldIrql;
01457     ULONG ActivePages = 0, FreePages = 0, OtherPages = 0;
01458 #if MI_TRACE_PFNS
01459     ULONG UsageBucket[MI_USAGE_FREE_PAGE + 1] = {0};
01460     PCHAR MI_USAGE_TEXT[MI_USAGE_FREE_PAGE + 1] =
01461     {
01462         "Not set",
01463         "Paged Pool",
01464         "Nonpaged Pool",
01465         "Nonpaged Pool Ex",
01466         "Kernel Stack",
01467         "Kernel Stack Ex",
01468         "System PTE",
01469         "VAD",
01470         "PEB/TEB",
01471         "Section",
01472         "Page Table",
01473         "Page Directory",
01474         "Old Page Table",
01475         "Driver Page",
01476         "Contiguous Alloc",
01477         "MDL",
01478         "Demand Zero",
01479         "Zero Loop",
01480         "Cache",
01481         "PFN Database",
01482         "Boot Driver",
01483         "Initial Memory",
01484         "Free Page"
01485     };
01486 #endif
01487     //
01488     // Loop the PFN database
01489     //
01490     KeRaiseIrql(HIGH_LEVEL, &OldIrql);
01491     for (i = 0; i <= MmHighestPhysicalPage; i++)
01492     {
01493         Pfn1 = MiGetPfnEntry(i);
01494         if (!Pfn1) continue;
01495 #if MI_TRACE_PFNS
01496         ASSERT(Pfn1->PfnUsage <= MI_USAGE_FREE_PAGE);
01497 #endif
01498         //
01499         // Get the page location
01500         //
01501         switch (Pfn1->u3.e1.PageLocation)
01502         {
01503             case ActiveAndValid:
01504 
01505                 Consumer = "Active and Valid";
01506                 ActivePages++;
01507                 break;
01508 
01509             case ZeroedPageList:
01510 
01511                 Consumer = "Zero Page List";
01512                 FreePages++;
01513                 break;//continue;
01514 
01515             case FreePageList:
01516 
01517                 Consumer = "Free Page List";
01518                 FreePages++;
01519                 break;//continue;
01520 
01521             default:
01522 
01523                 Consumer = "Other (ASSERT!)";
01524                 OtherPages++;
01525                 break;
01526         }
01527 
01528 #if MI_TRACE_PFNS
01529         /* Add into bucket */
01530         UsageBucket[Pfn1->PfnUsage]++;
01531 #endif
01532 
01533         //
01534         // Pretty-print the page
01535         //
01536         if (!StatusOnly)
01537         DbgPrint("0x%08p:\t%20s\t(%04d.%04d)\t[%16s - %16s])\n",
01538                  i << PAGE_SHIFT,
01539                  Consumer,
01540                  Pfn1->u3.e2.ReferenceCount,
01541                  Pfn1->u2.ShareCount == LIST_HEAD ? 0xFFFF : Pfn1->u2.ShareCount,
01542 #if MI_TRACE_PFNS
01543                  MI_USAGE_TEXT[Pfn1->PfnUsage],
01544                  Pfn1->ProcessName);
01545 #else
01546                  "Page tracking",
01547                  "is disabled");
01548 #endif
01549     }
01550 
01551     DbgPrint("Active:               %5d pages\t[%6d KB]\n", ActivePages,  (ActivePages    << PAGE_SHIFT) / 1024);
01552     DbgPrint("Free:                 %5d pages\t[%6d KB]\n", FreePages,    (FreePages      << PAGE_SHIFT) / 1024);
01553     DbgPrint("-----------------------------------------\n");
01554 #if MI_TRACE_PFNS
01555     OtherPages = UsageBucket[MI_USAGE_BOOT_DRIVER];
01556     DbgPrint("Boot Images:          %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01557     OtherPages = UsageBucket[MI_USAGE_DRIVER_PAGE];
01558     DbgPrint("System Drivers:       %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01559     OtherPages = UsageBucket[MI_USAGE_PFN_DATABASE];
01560     DbgPrint("PFN Database:         %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01561     OtherPages = UsageBucket[MI_USAGE_PAGE_TABLE] + UsageBucket[MI_USAGE_LEGACY_PAGE_DIRECTORY];
01562     DbgPrint("Page Tables:          %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01563     OtherPages = UsageBucket[MI_USAGE_NONPAGED_POOL] + UsageBucket[MI_USAGE_NONPAGED_POOL_EXPANSION];
01564     DbgPrint("NonPaged Pool:        %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01565     OtherPages = UsageBucket[MI_USAGE_PAGED_POOL];
01566     DbgPrint("Paged Pool:           %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01567     OtherPages = UsageBucket[MI_USAGE_KERNEL_STACK] + UsageBucket[MI_USAGE_KERNEL_STACK_EXPANSION];
01568     DbgPrint("Kernel Stack:         %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01569     OtherPages = UsageBucket[MI_USAGE_INIT_MEMORY];
01570     DbgPrint("Init Memory:          %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01571     OtherPages = UsageBucket[MI_USAGE_SECTION];
01572     DbgPrint("Sections:             %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01573     OtherPages = UsageBucket[MI_USAGE_CACHE];
01574     DbgPrint("Cache:                %5d pages\t[%6d KB]\n", OtherPages,   (OtherPages     << PAGE_SHIFT) / 1024);
01575 #endif
01576     KeLowerIrql(OldIrql);
01577 }
01578 
01579 PPHYSICAL_MEMORY_DESCRIPTOR
01580 NTAPI
01581 INIT_FUNCTION
01582 MmInitializeMemoryLimits(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
01583                          IN PBOOLEAN IncludeType)
01584 {
01585     PLIST_ENTRY NextEntry;
01586     ULONG Run = 0, InitialRuns;
01587     PFN_NUMBER NextPage = -1, PageCount = 0;
01588     PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer;
01589     PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
01590 
01591     //
01592     // Start with the maximum we might need
01593     //
01594     InitialRuns = MiNumberDescriptors;
01595 
01596     //
01597     // Allocate the maximum we'll ever need
01598     //
01599     Buffer = ExAllocatePoolWithTag(NonPagedPool,
01600                                    sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
01601                                    sizeof(PHYSICAL_MEMORY_RUN) *
01602                                    (InitialRuns - 1),
01603                                    'lMmM');
01604     if (!Buffer) return NULL;
01605 
01606     //
01607     // For now that's how many runs we have
01608     //
01609     Buffer->NumberOfRuns = InitialRuns;
01610 
01611     //
01612     // Now loop through the descriptors again
01613     //
01614     NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
01615     while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
01616     {
01617         //
01618         // Grab each one, and check if it's one we should include
01619         //
01620         MdBlock = CONTAINING_RECORD(NextEntry,
01621                                     MEMORY_ALLOCATION_DESCRIPTOR,
01622                                     ListEntry);
01623         if ((MdBlock->MemoryType < LoaderMaximum) &&
01624             (IncludeType[MdBlock->MemoryType]))
01625         {
01626             //
01627             // Add this to our running total
01628             //
01629             PageCount += MdBlock->PageCount;
01630 
01631             //
01632             // Check if the next page is described by the next descriptor
01633             //
01634             if (MdBlock->BasePage == NextPage)
01635             {
01636                 //
01637                 // Combine it into the same physical run
01638                 //
01639                 ASSERT(MdBlock->PageCount != 0);
01640                 Buffer->Run[Run - 1].PageCount += MdBlock->PageCount;
01641                 NextPage += MdBlock->PageCount;
01642             }
01643             else
01644             {
01645                 //
01646                 // Otherwise just duplicate the descriptor's contents
01647                 //
01648                 Buffer->Run[Run].BasePage = MdBlock->BasePage;
01649                 Buffer->Run[Run].PageCount = MdBlock->PageCount;
01650                 NextPage = Buffer->Run[Run].BasePage + Buffer->Run[Run].PageCount;
01651 
01652                 //
01653                 // And in this case, increase the number of runs
01654                 //
01655                 Run++;
01656             }
01657         }
01658 
01659         //
01660         // Try the next descriptor
01661         //
01662         NextEntry = MdBlock->ListEntry.Flink;
01663     }
01664 
01665     //
01666     // We should not have been able to go past our initial estimate
01667     //
01668     ASSERT(Run <= Buffer->NumberOfRuns);
01669 
01670     //
01671     // Our guess was probably exaggerated...
01672     //
01673     if (InitialRuns > Run)
01674     {
01675         //
01676         // Allocate a more accurately sized buffer
01677         //
01678         NewBuffer = ExAllocatePoolWithTag(NonPagedPool,
01679                                           sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
01680                                           sizeof(PHYSICAL_MEMORY_RUN) *
01681                                           (Run - 1),
01682                                           'lMmM');
01683         if (NewBuffer)
01684         {
01685             //
01686             // Copy the old buffer into the new, then free it
01687             //
01688             RtlCopyMemory(NewBuffer->Run,
01689                           Buffer->Run,
01690                           sizeof(PHYSICAL_MEMORY_RUN) * Run);
01691             ExFreePoolWithTag(Buffer, 'lMmM');
01692 
01693             //
01694             // Now use the new buffer
01695             //
01696             Buffer = NewBuffer;
01697         }
01698     }
01699 
01700     //
01701     // Write the final numbers, and return it
01702     //
01703     Buffer->NumberOfRuns = Run;
01704     Buffer->NumberOfPages = PageCount;
01705     return Buffer;
01706 }
01707 
01708 VOID
01709 NTAPI
01710 INIT_FUNCTION
01711 MiBuildPagedPool(VOID)
01712 {
01713     PMMPTE PointerPte;
01714     PMMPDE PointerPde;
01715     MMPDE TempPde = ValidKernelPde;
01716     PFN_NUMBER PageFrameIndex;
01717     KIRQL OldIrql;
01718     SIZE_T Size;
01719     ULONG BitMapSize;
01720 #if (_MI_PAGING_LEVELS >= 3)
01721     MMPPE TempPpe = ValidKernelPpe;
01722     PMMPPE PointerPpe;
01723 #elif (_MI_PAGING_LEVELS == 2)
01724     MMPTE TempPte = ValidKernelPte;
01725 
01726     //
01727     // Get the page frame number for the system page directory
01728     //
01729     PointerPte = MiAddressToPte(PDE_BASE);
01730     ASSERT(PD_COUNT == 1);
01731     MmSystemPageDirectory[0] = PFN_FROM_PTE(PointerPte);
01732 
01733     //
01734     // Allocate a system PTE which will hold a copy of the page directory
01735     //
01736     PointerPte = MiReserveSystemPtes(1, SystemPteSpace);
01737     ASSERT(PointerPte);
01738     MmSystemPagePtes = MiPteToAddress(PointerPte);
01739 
01740     //
01741     // Make this system PTE point to the system page directory.
01742     // It is now essentially double-mapped. This will be used later for lazy
01743     // evaluation of PDEs accross process switches, similarly to how the Global
01744     // page directory array in the old ReactOS Mm is used (but in a less hacky
01745     // way).
01746     //
01747     TempPte = ValidKernelPte;
01748     ASSERT(PD_COUNT == 1);
01749     TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory[0];
01750     MI_WRITE_VALID_PTE(PointerPte, TempPte);
01751 #endif
01752     //
01753     // Let's get back to paged pool work: size it up.
01754     // By default, it should be twice as big as nonpaged pool.
01755     //
01756     MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
01757     if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedSystemStart -
01758                                     (ULONG_PTR)MmPagedPoolStart))
01759     {
01760         //
01761         // On the other hand, we have limited VA space, so make sure that the VA
01762         // for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set
01763         // whatever maximum is possible.
01764         //
01765         MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedSystemStart -
01766                                    (ULONG_PTR)MmPagedPoolStart;
01767     }
01768 
01769     //
01770     // Get the size in pages and make sure paged pool is at least 32MB.
01771     //
01772     Size = MmSizeOfPagedPoolInBytes;
01773     if (Size < MI_MIN_INIT_PAGED_POOLSIZE) Size = MI_MIN_INIT_PAGED_POOLSIZE;
01774     Size = BYTES_TO_PAGES(Size);
01775 
01776     //
01777     // Now check how many PTEs will be required for these many pages.
01778     //
01779     Size = (Size + (1024 - 1)) / 1024;
01780 
01781     //
01782     // Recompute the page-aligned size of the paged pool, in bytes and pages.
01783     //
01784     MmSizeOfPagedPoolInBytes = Size * PAGE_SIZE * 1024;
01785     MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
01786 
01787     //
01788     // Let's be really sure this doesn't overflow into nonpaged system VA
01789     //
01790     ASSERT((MmSizeOfPagedPoolInBytes + (ULONG_PTR)MmPagedPoolStart) <=
01791            (ULONG_PTR)MmNonPagedSystemStart);
01792 
01793     //
01794     // This is where paged pool ends
01795     //
01796     MmPagedPoolEnd = (PVOID)(((ULONG_PTR)MmPagedPoolStart +
01797                               MmSizeOfPagedPoolInBytes) - 1);
01798 
01799     //
01800     // Lock the PFN database
01801     //
01802     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01803 
01804 #if (_MI_PAGING_LEVELS >= 3)
01805     /* On these systems, there's no double-mapping, so instead, the PPEs
01806      * are setup to span the entire paged pool area, so there's no need for the
01807      * system PD */
01808     for (PointerPpe = MiAddressToPpe(MmPagedPoolStart);
01809          PointerPpe <= MiAddressToPpe(MmPagedPoolEnd);
01810          PointerPpe++)
01811     {
01812         /* Check if the PPE is already valid */
01813         if (!PointerPpe->u.Hard.Valid)
01814         {
01815             /* It is not, so map a fresh zeroed page */
01816             TempPpe.u.Hard.PageFrameNumber = MiRemoveZeroPage(0);
01817             MI_WRITE_VALID_PPE(PointerPpe, TempPpe);
01818         }
01819     }
01820 #endif
01821 
01822     //
01823     // So now get the PDE for paged pool and zero it out
01824     //
01825     PointerPde = MiAddressToPde(MmPagedPoolStart);
01826     RtlZeroMemory(PointerPde,
01827                   (1 + MiAddressToPde(MmPagedPoolEnd) - PointerPde) * sizeof(MMPDE));
01828 
01829     //
01830     // Next, get the first and last PTE
01831     //
01832     PointerPte = MiAddressToPte(MmPagedPoolStart);
01833     MmPagedPoolInfo.FirstPteForPagedPool = PointerPte;
01834     MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
01835 
01836     /* Allocate a page and map the first paged pool PDE */
01837     MI_SET_USAGE(MI_USAGE_PAGED_POOL);
01838     MI_SET_PROCESS2("Kernel");
01839     PageFrameIndex = MiRemoveZeroPage(0);
01840     TempPde.u.Hard.PageFrameNumber = PageFrameIndex;
01841     MI_WRITE_VALID_PDE(PointerPde, TempPde);
01842 #if (_MI_PAGING_LEVELS >= 3)
01843     /* Use the PPE of MmPagedPoolStart that was setup above */
01844 //    Bla = PFN_FROM_PTE(PpeAddress(MmPagedPool...));
01845 
01846     /* Initialize the PFN entry for it */
01847     MiInitializePfnForOtherProcess(PageFrameIndex,
01848                                    (PMMPTE)PointerPde,
01849                                    PFN_FROM_PTE(MiAddressToPpe(MmPagedPoolStart)));
01850 #else
01851     /* Do it this way */
01852 //    Bla = MmSystemPageDirectory[(PointerPde - (PMMPTE)PDE_BASE) / PDE_COUNT]
01853 
01854     /* Initialize the PFN entry for it */
01855     MiInitializePfnForOtherProcess(PageFrameIndex,
01856                                    (PMMPTE)PointerPde,
01857                                    MmSystemPageDirectory[(PointerPde - (PMMPDE)PDE_BASE) / PDE_COUNT]);
01858 #endif
01859 
01860     //
01861     // Release the PFN database lock
01862     //
01863     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01864 
01865     //
01866     // We only have one PDE mapped for now... at fault time, additional PDEs
01867     // will be allocated to handle paged pool growth. This is where they'll have
01868     // to start.
01869     //
01870     MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1;
01871 
01872     //
01873     // We keep track of each page via a bit, so check how big the bitmap will
01874     // have to be (make sure to align our page count such that it fits nicely
01875     // into a 4-byte aligned bitmap.
01876     //
01877     // We'll also allocate the bitmap header itself part of the same buffer.
01878     //
01879     Size = Size * 1024;
01880     ASSERT(Size == MmSizeOfPagedPoolInPages);
01881     BitMapSize = (ULONG)Size;
01882     Size = sizeof(RTL_BITMAP) + (((Size + 31) / 32) * sizeof(ULONG));
01883 
01884     //
01885     // Allocate the allocation bitmap, which tells us which regions have not yet
01886     // been mapped into memory
01887     //
01888     MmPagedPoolInfo.PagedPoolAllocationMap = ExAllocatePoolWithTag(NonPagedPool,
01889                                                                    Size,
01890                                                                    '  mM');
01891     ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
01892 
01893     //
01894     // Initialize it such that at first, only the first page's worth of PTEs is
01895     // marked as allocated (incidentially, the first PDE we allocated earlier).
01896     //
01897     RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
01898                         (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
01899                         BitMapSize);
01900     RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
01901     RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 1024);
01902 
01903     //
01904     // We have a second bitmap, which keeps track of where allocations end.
01905     // Given the allocation bitmap and a base address, we can therefore figure
01906     // out which page is the last page of that allocation, and thus how big the
01907     // entire allocation is.
01908     //
01909     MmPagedPoolInfo.EndOfPagedPoolBitmap = ExAllocatePoolWithTag(NonPagedPool,
01910                                                                  Size,
01911                                                                  '  mM');
01912     ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
01913     RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
01914                         (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
01915                         BitMapSize);
01916 
01917     //
01918     // Since no allocations have been made yet, there are no bits set as the end
01919     //
01920     RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
01921 
01922     //
01923     // Initialize paged pool.
01924     //
01925     InitializePool(PagedPool, 0);
01926 
01927     /* Initialize special pool */
01928     MiInitializeSpecialPool();
01929 
01930     /* Default low threshold of 30MB or one fifth of paged pool */
01931     MiLowPagedPoolThreshold = (30 * _1MB) >> PAGE_SHIFT;
01932     MiLowPagedPoolThreshold = min(MiLowPagedPoolThreshold, Size / 5);
01933 
01934     /* Default high threshold of 60MB or 25% */
01935     MiHighPagedPoolThreshold = (60 * _1MB) >> PAGE_SHIFT;
01936     MiHighPagedPoolThreshold = min(MiHighPagedPoolThreshold, (Size * 2) / 5);
01937     ASSERT(MiLowPagedPoolThreshold < MiHighPagedPoolThreshold);
01938 
01939     /* Setup the global session space */
01940     MiInitializeSystemSpaceMap(NULL);
01941 }
01942 
01943 VOID
01944 NTAPI
01945 INIT_FUNCTION
01946 MiDbgDumpMemoryDescriptors(VOID)
01947 {
01948     PLIST_ENTRY NextEntry;
01949     PMEMORY_ALLOCATION_DESCRIPTOR Md;
01950     PFN_NUMBER TotalPages = 0;
01951     PCHAR
01952     MemType[] =
01953     {
01954         "ExceptionBlock    ",
01955         "SystemBlock       ",
01956         "Free              ",
01957         "Bad               ",
01958         "LoadedProgram     ",
01959         "FirmwareTemporary ",
01960         "FirmwarePermanent ",
01961         "OsloaderHeap      ",
01962         "OsloaderStack     ",
01963         "SystemCode        ",
01964         "HalCode           ",
01965         "BootDriver        ",
01966         "ConsoleInDriver   ",
01967         "ConsoleOutDriver  ",
01968         "StartupDpcStack   ",
01969         "StartupKernelStack",
01970         "StartupPanicStack ",
01971         "StartupPcrPage    ",
01972         "StartupPdrPage    ",
01973         "RegistryData      ",
01974         "MemoryData        ",
01975         "NlsData           ",
01976         "SpecialMemory     ",
01977         "BBTMemory         ",
01978         "LoaderReserve     ",
01979         "LoaderXIPRom      "
01980     };
01981 
01982     DPRINT1("Base\t\tLength\t\tType\n");
01983     for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink;
01984          NextEntry != &KeLoaderBlock->MemoryDescriptorListHead;
01985          NextEntry = NextEntry->Flink)
01986     {
01987         Md = CONTAINING_RECORD(NextEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
01988         DPRINT1("%08lX\t%08lX\t%s\n", Md->BasePage, Md->PageCount, MemType[Md->MemoryType]);
01989         TotalPages += Md->PageCount;
01990     }
01991 
01992     DPRINT1("Total: %08lX (%d MB)\n", (ULONG)TotalPages, (ULONG)(TotalPages * PAGE_SIZE) / 1024 / 1024);
01993 }
01994 
01995 BOOLEAN
01996 NTAPI
01997 INIT_FUNCTION
01998 MmArmInitSystem(IN ULONG Phase,
01999                 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
02000 {
02001     ULONG i;
02002     BOOLEAN IncludeType[LoaderMaximum];
02003     PVOID Bitmap;
02004     PPHYSICAL_MEMORY_RUN Run;
02005     PFN_NUMBER PageCount;
02006 
02007     /* Dump memory descriptors */
02008     if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors();
02009 
02010     //
02011     // Instantiate memory that we don't consider RAM/usable
02012     // We use the same exclusions that Windows does, in order to try to be
02013     // compatible with WinLDR-style booting
02014     //
02015     for (i = 0; i < LoaderMaximum; i++) IncludeType[i] = TRUE;
02016     IncludeType[LoaderBad] = FALSE;
02017     IncludeType[LoaderFirmwarePermanent] = FALSE;
02018     IncludeType[LoaderSpecialMemory] = FALSE;
02019     IncludeType[LoaderBBTMemory] = FALSE;
02020     if (Phase == 0)
02021     {
02022         /* Count physical pages on the system */
02023         MiScanMemoryDescriptors(LoaderBlock);
02024 
02025         /* Initialize the phase 0 temporary event */
02026         KeInitializeEvent(&MiTempEvent, NotificationEvent, FALSE);
02027 
02028         /* Set all the events to use the temporary event for now */
02029         MiLowMemoryEvent = &MiTempEvent;
02030         MiHighMemoryEvent = &MiTempEvent;
02031         MiLowPagedPoolEvent = &MiTempEvent;
02032         MiHighPagedPoolEvent = &MiTempEvent;
02033         MiLowNonPagedPoolEvent = &MiTempEvent;
02034         MiHighNonPagedPoolEvent = &MiTempEvent;
02035 
02036         //
02037         // Define the basic user vs. kernel address space separation
02038         //
02039         MmSystemRangeStart = (PVOID)MI_DEFAULT_SYSTEM_RANGE_START;
02040         MmUserProbeAddress = (ULONG_PTR)MI_HIGHEST_USER_ADDRESS;
02041         MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS;
02042 
02043         /* Highest PTE and PDE based on the addresses above */
02044         MiHighestUserPte = MiAddressToPte(MmHighestUserAddress);
02045         MiHighestUserPde = MiAddressToPde(MmHighestUserAddress);
02046 #if (_MI_PAGING_LEVELS >= 3)
02047         MiHighestUserPpe = MiAddressToPpe(MmHighestUserAddress);
02048 #if (_MI_PAGING_LEVELS >= 4)
02049         MiHighestUserPxe = MiAddressToPxe(MmHighestUserAddress);
02050 #endif
02051 #endif
02052         //
02053         // Get the size of the boot loader's image allocations and then round
02054         // that region up to a PDE size, so that any PDEs we might create for
02055         // whatever follows are separate from the PDEs that boot loader might've
02056         // already created (and later, we can blow all that away if we want to).
02057         //
02058         MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
02059         MmBootImageSize *= PAGE_SIZE;
02060         MmBootImageSize = (MmBootImageSize + PDE_MAPPED_VA - 1) & ~(PDE_MAPPED_VA - 1);
02061         ASSERT((MmBootImageSize % PDE_MAPPED_VA) == 0);
02062 
02063         /* Initialize session space address layout */
02064         MiInitializeSessionSpaceLayout();
02065         
02066         /* Set the based section highest address */
02067         MmHighSectionBase = (PVOID)((ULONG_PTR)MmHighestUserAddress - 0x800000);
02068 
02069         /* Loop all 8 standby lists */
02070         for (i = 0; i < 8; i++)
02071         {
02072             /* Initialize them */
02073             MmStandbyPageListByPriority[i].Total = 0;
02074             MmStandbyPageListByPriority[i].ListName = StandbyPageList;
02075             MmStandbyPageListByPriority[i].Flink = MM_EMPTY_LIST;
02076             MmStandbyPageListByPriority[i].Blink = MM_EMPTY_LIST;
02077         }
02078 
02079         /* Initialize the user mode image list */
02080         InitializeListHead(&MmLoadedUserImageList);
02081 
02082         /* Initialize the paged pool mutex and the section commit mutex */
02083         KeInitializeGuardedMutex(&MmPagedPoolMutex);
02084         KeInitializeGuardedMutex(&MmSectionCommitMutex);
02085         KeInitializeGuardedMutex(&MmSectionBasedMutex);
02086 
02087         /* Initialize the Loader Lock */
02088         KeInitializeMutant(&MmSystemLoadLock, FALSE);
02089 
02090         /* Set the zero page event */
02091         KeInitializeEvent(&MmZeroingPageEvent, SynchronizationEvent, FALSE);
02092         MmZeroingPageThreadActive = FALSE;
02093 
02094         /* Initialize the dead stack S-LIST */
02095         InitializeSListHead(&MmDeadStackSListHead);
02096 
02097         //
02098         // Check if this is a machine with less than 19MB of RAM
02099         //
02100         PageCount = MmNumberOfPhysicalPages;
02101         if (PageCount < MI_MIN_PAGES_FOR_SYSPTE_TUNING)
02102         {
02103             //
02104             // Use the very minimum of system PTEs
02105             //
02106             MmNumberOfSystemPtes = 7000;
02107         }
02108         else
02109         {
02110             //
02111             // Use the default, but check if we have more than 32MB of RAM
02112             //
02113             MmNumberOfSystemPtes = 11000;
02114             if (PageCount > MI_MIN_PAGES_FOR_SYSPTE_BOOST)
02115             {
02116                 //
02117                 // Double the amount of system PTEs
02118                 //
02119                 MmNumberOfSystemPtes <<= 1;
02120             }
02121         }
02122 
02123         DPRINT("System PTE count has been tuned to %d (%d bytes)\n",
02124                MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE);
02125 
02126         /* Initialize the working set lock */
02127         ExInitializePushLock(&MmSystemCacheWs.WorkingSetMutex);
02128 
02129         /* Set commit limit */
02130         MmTotalCommitLimit = 2 * _1GB;
02131         MmTotalCommitLimitMaximum = MmTotalCommitLimit;
02132 
02133         /* Has the allocation fragment been setup? */
02134         if (!MmAllocationFragment)
02135         {
02136             /* Use the default value */
02137             MmAllocationFragment = MI_ALLOCATION_FRAGMENT;
02138             if (PageCount < ((256 * _1MB) / PAGE_SIZE))
02139             {
02140                 /* On memory systems with less than 256MB, divide by 4 */
02141                 MmAllocationFragment = MI_ALLOCATION_FRAGMENT / 4;
02142             }
02143             else if (PageCount < (_1GB / PAGE_SIZE))
02144             {
02145                 /* On systems with less than 1GB, divide by 2 */
02146                 MmAllocationFragment = MI_ALLOCATION_FRAGMENT / 2;
02147             }
02148         }
02149         else
02150         {
02151             /* Convert from 1KB fragments to pages */
02152             MmAllocationFragment *= _1KB;
02153             MmAllocationFragment = ROUND_TO_PAGES(MmAllocationFragment);
02154 
02155             /* Don't let it past the maximum */
02156             MmAllocationFragment = min(MmAllocationFragment,
02157                                        MI_MAX_ALLOCATION_FRAGMENT);
02158 
02159             /* Don't let it too small either */
02160             MmAllocationFragment = max(MmAllocationFragment,
02161                                        MI_MIN_ALLOCATION_FRAGMENT);
02162         }
02163 
02164         /* Check for kernel stack size that's too big */
02165         if (MmLargeStackSize > (KERNEL_LARGE_STACK_SIZE / _1KB))
02166         {
02167             /* Sanitize to default value */
02168             MmLargeStackSize = KERNEL_LARGE_STACK_SIZE;
02169         }
02170         else
02171         {
02172             /* Take the registry setting, and convert it into bytes */
02173             MmLargeStackSize *= _1KB;
02174 
02175             /* Now align it to a page boundary */
02176             MmLargeStackSize = PAGE_ROUND_UP(MmLargeStackSize);
02177 
02178             /* Sanity checks */
02179             ASSERT(MmLargeStackSize <= KERNEL_LARGE_STACK_SIZE);
02180             ASSERT((MmLargeStackSize & (PAGE_SIZE - 1)) == 0);
02181 
02182             /* Make sure it's not too low */
02183             if (MmLargeStackSize < KERNEL_STACK_SIZE) MmLargeStackSize = KERNEL_STACK_SIZE;
02184         }
02185 
02186         /* Compute color information (L2 cache-separated paging lists) */
02187         MiComputeColorInformation();
02188 
02189         // Calculate the number of bytes for the PFN database
02190         // then add the color tables and convert to pages
02191         MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
02192         MxPfnAllocation += (MmSecondaryColors * sizeof(MMCOLOR_TABLES) * 2);
02193         MxPfnAllocation >>= PAGE_SHIFT;
02194 
02195         // We have to add one to the count here, because in the process of
02196         // shifting down to the page size, we actually ended up getting the
02197         // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages).
02198         // Later on, we'll shift this number back into bytes, which would cause
02199         // us to end up with only 0x5F000 bytes -- when we actually want to have
02200         // 0x60000 bytes.
02201         MxPfnAllocation++;
02202 
02203         /* Initialize the platform-specific parts */
02204         MiInitMachineDependent(LoaderBlock);
02205 
02206         //
02207         // Build the physical memory block
02208         //
02209         MmPhysicalMemoryBlock = MmInitializeMemoryLimits(LoaderBlock,
02210                                                          IncludeType);
02211 
02212         //
02213         // Allocate enough buffer for the PFN bitmap
02214         // Align it up to a 32-bit boundary
02215         //
02216         Bitmap = ExAllocatePoolWithTag(NonPagedPool,
02217                                        (((MmHighestPhysicalPage + 1) + 31) / 32) * 4,
02218                                        '  mM');
02219         if (!Bitmap)
02220         {
02221             //
02222             // This is critical
02223             //
02224             KeBugCheckEx(INSTALL_MORE_MEMORY,
02225                          MmNumberOfPhysicalPages,
02226                          MmLowestPhysicalPage,
02227                          MmHighestPhysicalPage,
02228                          0x101);
02229         }
02230 
02231         //
02232         // Initialize it and clear all the bits to begin with
02233         //
02234         RtlInitializeBitMap(&MiPfnBitMap,
02235                             Bitmap,
02236                             (ULONG)MmHighestPhysicalPage + 1);
02237         RtlClearAllBits(&MiPfnBitMap);
02238 
02239         //
02240         // Loop physical memory runs
02241         //
02242         for (i = 0; i < MmPhysicalMemoryBlock->NumberOfRuns; i++)
02243         {
02244             //
02245             // Get the run
02246             //
02247             Run = &MmPhysicalMemoryBlock->Run[i];
02248             DPRINT("PHYSICAL RAM [0x%08p to 0x%08p]\n",
02249                    Run->BasePage << PAGE_SHIFT,
02250                    (Run->BasePage + Run->PageCount) << PAGE_SHIFT);
02251 
02252             //
02253             // Make sure it has pages inside it
02254             //
02255             if (Run->PageCount)
02256             {
02257                 //
02258                 // Set the bits in the PFN bitmap
02259                 //
02260                 RtlSetBits(&MiPfnBitMap, (ULONG)Run->BasePage, (ULONG)Run->PageCount);
02261             }
02262         }
02263 
02264         /* Look for large page cache entries that need caching */
02265         MiSyncCachedRanges();
02266 
02267         /* Loop for HAL Heap I/O device mappings that need coherency tracking */
02268         MiAddHalIoMappings();
02269 
02270         /* Set the initial resident page count */
02271         MmResidentAvailablePages = MmAvailablePages - 32;
02272 
02273         /* Initialize large page structures on PAE/x64, and MmProcessList on x86 */
02274         MiInitializeLargePageSupport();
02275 
02276         /* Check if the registry says any drivers should be loaded with large pages */
02277         MiInitializeDriverLargePageList();
02278 
02279         /* Relocate the boot drivers into system PTE space and fixup their PFNs */
02280         MiReloadBootLoadedDrivers(LoaderBlock);
02281 
02282         /* FIXME: Call out into Driver Verifier for initialization  */
02283 
02284         /* Check how many pages the system has */
02285         if (MmNumberOfPhysicalPages <= ((13 * _1MB) / PAGE_SIZE))
02286         {
02287             /* Set small system */
02288             MmSystemSize = MmSmallSystem;
02289             MmMaximumDeadKernelStacks = 0;
02290         }
02291         else if (MmNumberOfPhysicalPages <= ((19 * _1MB) / PAGE_SIZE))
02292         {
02293             /* Set small system and add 100 pages for the cache */
02294             MmSystemSize = MmSmallSystem;
02295             MmSystemCacheWsMinimum += 100;
02296             MmMaximumDeadKernelStacks = 2;
02297         }
02298         else
02299         {
02300             /* Set medium system and add 400 pages for the cache */
02301             MmSystemSize = MmMediumSystem;
02302             MmSystemCacheWsMinimum += 400;
02303             MmMaximumDeadKernelStacks = 5;
02304         }
02305 
02306         /* Check for less than 24MB */
02307         if (MmNumberOfPhysicalPages < ((24 * _1MB) / PAGE_SIZE))
02308         {
02309             /* No more than 32 pages */
02310             MmSystemCacheWsMinimum = 32;
02311         }
02312 
02313         /* Check for more than 32MB */
02314         if (MmNumberOfPhysicalPages >= ((32 * _1MB) / PAGE_SIZE))
02315         {
02316             /* Check for product type being "Wi" for WinNT */
02317             if (MmProductType == '\0i\0W')
02318             {
02319                 /* Then this is a large system */
02320                 MmSystemSize = MmLargeSystem;
02321             }
02322             else
02323             {
02324                 /* For servers, we need 64MB to consider this as being large */
02325                 if (MmNumberOfPhysicalPages >= ((64 * _1MB) / PAGE_SIZE))
02326                 {
02327                     /* Set it as large */
02328                     MmSystemSize = MmLargeSystem;
02329                 }
02330             }
02331         }
02332 
02333         /* Check for more than 33 MB */
02334         if (MmNumberOfPhysicalPages > ((33 * _1MB) / PAGE_SIZE))
02335         {
02336             /* Add another 500 pages to the cache */
02337             MmSystemCacheWsMinimum += 500;
02338         }
02339 
02340         /* Now setup the shared user data fields */
02341         ASSERT(SharedUserData->NumberOfPhysicalPages == 0);
02342         SharedUserData->NumberOfPhysicalPages = MmNumberOfPhysicalPages;
02343         SharedUserData->LargePageMinimum = 0;
02344 
02345         /* Check for workstation (Wi for WinNT) */
02346         if (MmProductType == '\0i\0W')
02347         {
02348             /* Set Windows NT Workstation product type */
02349             SharedUserData->NtProductType = NtProductWinNt;
02350             MmProductType = 0;
02351         }
02352         else
02353         {
02354             /* Check for LanMan server */
02355             if (MmProductType == '\0a\0L')
02356             {
02357                 /* This is a domain controller */
02358                 SharedUserData->NtProductType = NtProductLanManNt;
02359             }
02360             else
02361             {
02362                 /* Otherwise it must be a normal server */
02363                 SharedUserData->NtProductType = NtProductServer;
02364             }
02365 
02366             /* Set the product type, and make the system more aggressive with low memory */
02367             MmProductType = 1;
02368             MmMinimumFreePages = 81;
02369         }
02370 
02371         /* Update working set tuning parameters */
02372         MiAdjustWorkingSetManagerParameters(!MmProductType);
02373 
02374         /* Finetune the page count by removing working set and NP expansion */
02375         MmResidentAvailablePages -= MiExpansionPoolPagesInitialCharge;
02376         MmResidentAvailablePages -= MmSystemCacheWsMinimum;
02377         MmResidentAvailableAtInit = MmResidentAvailablePages;
02378         if (MmResidentAvailablePages <= 0)
02379         {
02380             /* This should not happen */
02381             DPRINT1("System cache working set too big\n");
02382             return FALSE;
02383         }
02384 
02385         /* Initialize the system cache */
02386         //MiInitializeSystemCache(MmSystemCacheWsMinimum, MmAvailablePages);
02387 
02388         /* Update the commit limit */
02389         MmTotalCommitLimit = MmAvailablePages;
02390         if (MmTotalCommitLimit > 1024) MmTotalCommitLimit -= 1024;
02391         MmTotalCommitLimitMaximum = MmTotalCommitLimit;
02392 
02393         /* Size up paged pool and build the shadow system page directory */
02394         MiBuildPagedPool();
02395 
02396         /* Debugger physical memory support is now ready to be used */
02397         MmDebugPte = MiAddressToPte(MiDebugMapping);
02398 
02399         /* Initialize the loaded module list */
02400         MiInitializeLoadedModuleList(LoaderBlock);
02401     }
02402 
02403     //
02404     // Always return success for now
02405     //
02406     return TRUE;
02407 }
02408 
02409 /* EOF */

Generated on Fri May 25 2012 04:35:58 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.