Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmminit.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
1.7.6.1
|