1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/mm/ARM3/mminit.c 5 * PURPOSE: ARM Memory Manager Initialization 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #define MODULE_INVOLVED_IN_ARM3 16 #include "miarm.h" 17 #undef MmSystemRangeStart 18 19 /* GLOBALS ********************************************************************/ 20 21 // 22 // These are all registry-configurable, but by default, the memory manager will 23 // figure out the most appropriate values. 24 // 25 ULONG MmMaximumNonPagedPoolPercent; 26 SIZE_T MmSizeOfNonPagedPoolInBytes; 27 SIZE_T MmMaximumNonPagedPoolInBytes; 28 29 /* Some of the same values, in pages */ 30 PFN_NUMBER MmMaximumNonPagedPoolInPages; 31 32 // 33 // These numbers describe the discrete equation components of the nonpaged 34 // pool sizing algorithm. 35 // 36 // They are described on http://support.microsoft.com/default.aspx/kb/126402/ja 37 // along with the algorithm that uses them, which is implemented later below. 38 // 39 SIZE_T MmMinimumNonPagedPoolSize = 256 * 1024; 40 ULONG MmMinAdditionNonPagedPoolPerMb = 32 * 1024; 41 SIZE_T MmDefaultMaximumNonPagedPool = 1024 * 1024; 42 ULONG MmMaxAdditionNonPagedPoolPerMb = 400 * 1024; 43 44 // 45 // The memory layout (and especially variable names) of the NT kernel mode 46 // components can be a bit hard to twig, especially when it comes to the non 47 // paged area. 48 // 49 // There are really two components to the non-paged pool: 50 // 51 // - The initial nonpaged pool, sized dynamically up to a maximum. 52 // - The expansion nonpaged pool, sized dynamically up to a maximum. 53 // 54 // The initial nonpaged pool is physically continuous for performance, and 55 // immediately follows the PFN database, typically sharing the same PDE. It is 56 // a very small resource (32MB on a 1GB system), and capped at 128MB. 57 // 58 // Right now we call this the "ARM³ Nonpaged Pool" and it begins somewhere after 59 // the PFN database (which starts at 0xB0000000). 60 // 61 // The expansion nonpaged pool, on the other hand, can grow much bigger (400MB 62 // for a 1GB system). On ARM³ however, it is currently capped at 128MB. 63 // 64 // The address where the initial nonpaged pool starts is aptly named 65 // MmNonPagedPoolStart, and it describes a range of MmSizeOfNonPagedPoolInBytes 66 // bytes. 67 // 68 // Expansion nonpaged pool starts at an address described by the variable called 69 // MmNonPagedPoolExpansionStart, and it goes on for MmMaximumNonPagedPoolInBytes 70 // minus MmSizeOfNonPagedPoolInBytes bytes, always reaching MmNonPagedPoolEnd 71 // (because of the way it's calculated) at 0xFFBE0000. 72 // 73 // Initial nonpaged pool is allocated and mapped early-on during boot, but what 74 // about the expansion nonpaged pool? It is instead composed of special pages 75 // which belong to what are called System PTEs. These PTEs are the matter of a 76 // later discussion, but they are also considered part of the "nonpaged" OS, due 77 // to the fact that they are never paged out -- once an address is described by 78 // a System PTE, it is always valid, until the System PTE is torn down. 79 // 80 // System PTEs are actually composed of two "spaces", the system space proper, 81 // and the nonpaged pool expansion space. The latter, as we've already seen, 82 // begins at MmNonPagedPoolExpansionStart. Based on the number of System PTEs 83 // that the system will support, the remaining address space below this address 84 // is used to hold the system space PTEs. This address, in turn, is held in the 85 // variable named MmNonPagedSystemStart, which itself is never allowed to go 86 // below 0xEB000000 (thus creating an upper bound on the number of System PTEs). 87 // 88 // This means that 330MB are reserved for total nonpaged system VA, on top of 89 // whatever the initial nonpaged pool allocation is. 90 // 91 // The following URLs, valid as of April 23rd, 2008, support this evidence: 92 // 93 // http://www.cs.miami.edu/~burt/journal/NT/memory.html 94 // http://www.ditii.com/2007/09/28/windows-memory-management-x86-virtual-address-space/ 95 // 96 PVOID MmNonPagedSystemStart; 97 PVOID MmNonPagedPoolStart; 98 PVOID MmNonPagedPoolExpansionStart; 99 PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END; 100 101 // 102 // This is where paged pool starts by default 103 // 104 PVOID MmPagedPoolStart = MI_PAGED_POOL_START; 105 PVOID MmPagedPoolEnd; 106 107 // 108 // And this is its default size 109 // 110 SIZE_T MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE; 111 PFN_NUMBER MmSizeOfPagedPoolInPages = MI_MIN_INIT_PAGED_POOLSIZE / PAGE_SIZE; 112 113 // 114 // Session space starts at 0xBFFFFFFF and grows downwards 115 // By default, it includes an 8MB image area where we map win32k and video card 116 // drivers, followed by a 4MB area containing the session's working set. This is 117 // then followed by a 20MB mapped view area and finally by the session's paged 118 // pool, by default 16MB. 119 // 120 // On a normal system, this results in session space occupying the region from 121 // 0xBD000000 to 0xC0000000 122 // 123 // See miarm.h for the defines that determine the sizing of this region. On an 124 // NT system, some of these can be configured through the registry, but we don't 125 // support that yet. 126 // 127 PVOID MiSessionSpaceEnd; // 0xC0000000 128 PVOID MiSessionImageEnd; // 0xC0000000 129 PVOID MiSessionImageStart; // 0xBF800000 130 PVOID MiSessionSpaceWs; 131 PVOID MiSessionViewStart; // 0xBE000000 132 PVOID MiSessionPoolEnd; // 0xBE000000 133 PVOID MiSessionPoolStart; // 0xBD000000 134 PVOID MmSessionBase; // 0xBD000000 135 SIZE_T MmSessionSize; 136 SIZE_T MmSessionViewSize; 137 SIZE_T MmSessionPoolSize; 138 SIZE_T MmSessionImageSize; 139 140 /* 141 * These are the PTE addresses of the boundaries carved out above 142 */ 143 PMMPTE MiSessionImagePteStart; 144 PMMPTE MiSessionImagePteEnd; 145 PMMPTE MiSessionBasePte; 146 PMMPTE MiSessionLastPte; 147 148 // 149 // The system view space, on the other hand, is where sections that are memory 150 // mapped into "system space" end up. 151 // 152 // By default, it is a 16MB region, but we hack it to be 32MB for ReactOS 153 // 154 PVOID MiSystemViewStart; 155 SIZE_T MmSystemViewSize; 156 157 #if (_MI_PAGING_LEVELS == 2) 158 // 159 // A copy of the system page directory (the page directory associated with the 160 // System process) is kept (double-mapped) by the manager in order to lazily 161 // map paged pool PDEs into external processes when they fault on a paged pool 162 // address. 163 // 164 PFN_NUMBER MmSystemPageDirectory[PD_COUNT]; 165 PMMPDE MmSystemPagePtes; 166 #endif 167 168 // 169 // The system cache starts right after hyperspace. The first few pages are for 170 // keeping track of the system working set list. 171 // 172 // This should be 0xC0C00000 -- the cache itself starts at 0xC1000000 173 // 174 PMMWSL MmSystemCacheWorkingSetList = (PVOID)MI_SYSTEM_CACHE_WS_START; 175 176 // 177 // Windows NT seems to choose between 7000, 11000 and 50000 178 // On systems with more than 32MB, this number is then doubled, and further 179 // aligned up to a PDE boundary (4MB). 180 // 181 PFN_COUNT MmNumberOfSystemPtes; 182 183 // 184 // This is how many pages the PFN database will take up 185 // In Windows, this includes the Quark Color Table, but not in ARM³ 186 // 187 PFN_NUMBER MxPfnAllocation; 188 189 // 190 // Unlike the old ReactOS Memory Manager, ARM³ (and Windows) does not keep track 191 // of pages that are not actually valid physical memory, such as ACPI reserved 192 // regions, BIOS address ranges, or holes in physical memory address space which 193 // could indicate device-mapped I/O memory. 194 // 195 // In fact, the lack of a PFN entry for a page usually indicates that this is 196 // I/O space instead. 197 // 198 // A bitmap, called the PFN bitmap, keeps track of all page frames by assigning 199 // a bit to each. If the bit is set, then the page is valid physical RAM. 200 // 201 RTL_BITMAP MiPfnBitMap; 202 203 // 204 // This structure describes the different pieces of RAM-backed address space 205 // 206 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock; 207 208 // 209 // This is where we keep track of the most basic physical layout markers 210 // 211 PFN_NUMBER MmHighestPhysicalPage, MmLowestPhysicalPage = -1; 212 PFN_COUNT MmNumberOfPhysicalPages; 213 214 // 215 // The total number of pages mapped by the boot loader, which include the kernel 216 // HAL, boot drivers, registry, NLS files and other loader data structures is 217 // kept track of here. This depends on "LoaderPagesSpanned" being correct when 218 // coming from the loader. 219 // 220 // This number is later aligned up to a PDE boundary. 221 // 222 SIZE_T MmBootImageSize; 223 224 // 225 // These three variables keep track of the core separation of address space that 226 // exists between kernel mode and user mode. 227 // 228 ULONG_PTR MmUserProbeAddress; 229 PVOID MmHighestUserAddress; 230 PVOID MmSystemRangeStart; 231 232 /* And these store the respective highest PTE/PDE address */ 233 PMMPTE MiHighestUserPte; 234 PMMPDE MiHighestUserPde; 235 #if (_MI_PAGING_LEVELS >= 3) 236 PMMPTE MiHighestUserPpe; 237 #if (_MI_PAGING_LEVELS >= 4) 238 PMMPTE MiHighestUserPxe; 239 #endif 240 #endif 241 242 /* These variables define the system cache address space */ 243 PVOID MmSystemCacheStart = (PVOID)MI_SYSTEM_CACHE_START; 244 PVOID MmSystemCacheEnd; 245 ULONG MmSizeOfSystemCacheInPages; 246 MMSUPPORT MmSystemCacheWs; 247 248 // 249 // This is where hyperspace ends (followed by the system cache working set) 250 // 251 PVOID MmHyperSpaceEnd; 252 253 // 254 // Page coloring algorithm data 255 // 256 ULONG MmSecondaryColors; 257 ULONG MmSecondaryColorMask; 258 259 // 260 // Actual (registry-configurable) size of a GUI thread's stack 261 // 262 ULONG MmLargeStackSize = KERNEL_LARGE_STACK_SIZE; 263 264 // 265 // Before we have a PFN database, memory comes straight from our physical memory 266 // blocks, which is nice because it's guaranteed contiguous and also because once 267 // we take a page from here, the system doesn't see it anymore. 268 // However, once the fun is over, those pages must be re-integrated back into 269 // PFN society life, and that requires us keeping a copy of the original layout 270 // so that we can parse it later. 271 // 272 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor; 273 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor; 274 275 /* 276 * For each page's worth bytes of L2 cache in a given set/way line, the zero and 277 * free lists are organized in what is called a "color". 278 * 279 * This array points to the two lists, so it can be thought of as a multi-dimensional 280 * array of MmFreePagesByColor[2][MmSecondaryColors]. Since the number is dynamic, 281 * we describe the array in pointer form instead. 282 * 283 * On a final note, the color tables themselves are right after the PFN database. 284 */ 285 C_ASSERT(FreePageList == 1); 286 PMMCOLOR_TABLES MmFreePagesByColor[FreePageList + 1]; 287 288 /* An event used in Phase 0 before the rest of the system is ready to go */ 289 KEVENT MiTempEvent; 290 291 /* All the events used for memory threshold notifications */ 292 PKEVENT MiLowMemoryEvent; 293 PKEVENT MiHighMemoryEvent; 294 PKEVENT MiLowPagedPoolEvent; 295 PKEVENT MiHighPagedPoolEvent; 296 PKEVENT MiLowNonPagedPoolEvent; 297 PKEVENT MiHighNonPagedPoolEvent; 298 299 /* The actual thresholds themselves, in page numbers */ 300 PFN_NUMBER MmLowMemoryThreshold; 301 PFN_NUMBER MmHighMemoryThreshold; 302 PFN_NUMBER MiLowPagedPoolThreshold; 303 PFN_NUMBER MiHighPagedPoolThreshold; 304 PFN_NUMBER MiLowNonPagedPoolThreshold; 305 PFN_NUMBER MiHighNonPagedPoolThreshold; 306 307 /* 308 * This number determines how many free pages must exist, at minimum, until we 309 * start trimming working sets and flushing modified pages to obtain more free 310 * pages. 311 * 312 * This number changes if the system detects that this is a server product 313 */ 314 PFN_NUMBER MmMinimumFreePages = 26; 315 316 /* 317 * This number indicates how many pages we consider to be a low limit of having 318 * "plenty" of free memory. 319 * 320 * It is doubled on systems that have more than 63MB of memory 321 */ 322 PFN_NUMBER MmPlentyFreePages = 400; 323 324 /* These values store the type of system this is (small, med, large) and if server */ 325 ULONG MmProductType; 326 MM_SYSTEMSIZE MmSystemSize; 327 328 /* 329 * These values store the cache working set minimums and maximums, in pages 330 * 331 * The minimum value is boosted on systems with more than 24MB of RAM, and cut 332 * down to only 32 pages on embedded (<24MB RAM) systems. 333 * 334 * An extra boost of 2MB is given on systems with more than 33MB of RAM. 335 */ 336 PFN_NUMBER MmSystemCacheWsMinimum = 288; 337 PFN_NUMBER MmSystemCacheWsMaximum = 350; 338 339 /* FIXME: Move to cache/working set code later */ 340 BOOLEAN MmLargeSystemCache; 341 342 /* 343 * This value determines in how many fragments/chunks the subsection prototype 344 * PTEs should be allocated when mapping a section object. It is configurable in 345 * the registry through the MapAllocationFragment parameter. 346 * 347 * The default is 64KB on systems with more than 1GB of RAM, 32KB on systems with 348 * more than 256MB of RAM, and 16KB on systems with less than 256MB of RAM. 349 * 350 * The maximum it can be set to is 2MB, and the minimum is 4KB. 351 */ 352 SIZE_T MmAllocationFragment; 353 354 /* 355 * These two values track how much virtual memory can be committed, and when 356 * expansion should happen. 357 */ 358 // FIXME: They should be moved elsewhere since it's not an "init" setting? 359 SIZE_T MmTotalCommitLimit; 360 SIZE_T MmTotalCommitLimitMaximum; 361 362 /* 363 * These values tune certain user parameters. They have default values set here, 364 * as well as in the code, and can be overwritten by registry settings. 365 */ 366 SIZE_T MmHeapSegmentReserve = 1 * _1MB; 367 SIZE_T MmHeapSegmentCommit = 2 * PAGE_SIZE; 368 SIZE_T MmHeapDeCommitTotalFreeThreshold = 64 * _1KB; 369 SIZE_T MmHeapDeCommitFreeBlockThreshold = PAGE_SIZE; 370 SIZE_T MmMinimumStackCommitInBytes = 0; 371 372 /* Internal setting used for debugging memory descriptors */ 373 BOOLEAN MiDbgEnableMdDump = 374 #ifdef _ARM_ 375 TRUE; 376 #else 377 FALSE; 378 #endif 379 380 /* Number of memory descriptors in the loader block */ 381 ULONG MiNumberDescriptors = 0; 382 383 /* Number of free pages in the loader block */ 384 PFN_NUMBER MiNumberOfFreePages = 0; 385 386 /* Timeout value for critical sections (2.5 minutes) */ 387 ULONG MmCritsectTimeoutSeconds = 150; // NT value: 720 * 60 * 60; (30 days) 388 LARGE_INTEGER MmCriticalSectionTimeout; 389 390 // 391 // Throttling limits for Cc (in pages) 392 // Above top, we don't throttle 393 // Above bottom, we throttle depending on the amount of modified pages 394 // Otherwise, we throttle! 395 // 396 ULONG MmThrottleTop; 397 ULONG MmThrottleBottom; 398 399 /* PRIVATE FUNCTIONS **********************************************************/ 400 401 VOID 402 NTAPI 403 MiScanMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 404 { 405 PLIST_ENTRY ListEntry; 406 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; 407 PFN_NUMBER PageFrameIndex, FreePages = 0; 408 409 /* Loop the memory descriptors */ 410 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink; 411 ListEntry != &LoaderBlock->MemoryDescriptorListHead; 412 ListEntry = ListEntry->Flink) 413 { 414 /* Get the descriptor */ 415 Descriptor = CONTAINING_RECORD(ListEntry, 416 MEMORY_ALLOCATION_DESCRIPTOR, 417 ListEntry); 418 DPRINT("MD Type: %lx Base: %lx Count: %lx\n", 419 Descriptor->MemoryType, Descriptor->BasePage, Descriptor->PageCount); 420 421 /* Count this descriptor */ 422 MiNumberDescriptors++; 423 424 /* Check if this is invisible memory */ 425 if ((Descriptor->MemoryType == LoaderFirmwarePermanent) || 426 (Descriptor->MemoryType == LoaderSpecialMemory) || 427 (Descriptor->MemoryType == LoaderHALCachedMemory) || 428 (Descriptor->MemoryType == LoaderBBTMemory)) 429 { 430 /* Skip this descriptor */ 431 continue; 432 } 433 434 /* Check if this is bad memory */ 435 if (Descriptor->MemoryType != LoaderBad) 436 { 437 /* Count this in the total of pages */ 438 MmNumberOfPhysicalPages += (PFN_COUNT)Descriptor->PageCount; 439 } 440 441 /* Check if this is the new lowest page */ 442 if (Descriptor->BasePage < MmLowestPhysicalPage) 443 { 444 /* Update the lowest page */ 445 MmLowestPhysicalPage = Descriptor->BasePage; 446 } 447 448 /* Check if this is the new highest page */ 449 PageFrameIndex = Descriptor->BasePage + Descriptor->PageCount; 450 if (PageFrameIndex > MmHighestPhysicalPage) 451 { 452 /* Update the highest page */ 453 MmHighestPhysicalPage = PageFrameIndex - 1; 454 } 455 456 /* Check if this is free memory */ 457 if ((Descriptor->MemoryType == LoaderFree) || 458 (Descriptor->MemoryType == LoaderLoadedProgram) || 459 (Descriptor->MemoryType == LoaderFirmwareTemporary) || 460 (Descriptor->MemoryType == LoaderOsloaderStack)) 461 { 462 /* Count it too free pages */ 463 MiNumberOfFreePages += Descriptor->PageCount; 464 465 /* Check if this is the largest memory descriptor */ 466 if (Descriptor->PageCount > FreePages) 467 { 468 /* Remember it */ 469 MxFreeDescriptor = Descriptor; 470 FreePages = Descriptor->PageCount; 471 } 472 } 473 } 474 475 /* Save original values of the free descriptor, since it'll be 476 * altered by early allocations */ 477 MxOldFreeDescriptor = *MxFreeDescriptor; 478 } 479 480 PFN_NUMBER 481 NTAPI 482 INIT_FUNCTION 483 MxGetNextPage(IN PFN_NUMBER PageCount) 484 { 485 PFN_NUMBER Pfn; 486 487 /* Make sure we have enough pages */ 488 if (PageCount > MxFreeDescriptor->PageCount) 489 { 490 /* Crash the system */ 491 KeBugCheckEx(INSTALL_MORE_MEMORY, 492 MmNumberOfPhysicalPages, 493 MxFreeDescriptor->PageCount, 494 MxOldFreeDescriptor.PageCount, 495 PageCount); 496 } 497 498 /* Use our lowest usable free pages */ 499 Pfn = MxFreeDescriptor->BasePage; 500 MxFreeDescriptor->BasePage += PageCount; 501 MxFreeDescriptor->PageCount -= PageCount; 502 return Pfn; 503 } 504 505 VOID 506 NTAPI 507 INIT_FUNCTION 508 MiComputeColorInformation(VOID) 509 { 510 ULONG L2Associativity; 511 512 /* Check if no setting was provided already */ 513 if (!MmSecondaryColors) 514 { 515 /* Get L2 cache information */ 516 L2Associativity = KeGetPcr()->SecondLevelCacheAssociativity; 517 518 /* The number of colors is the number of cache bytes by set/way */ 519 MmSecondaryColors = KeGetPcr()->SecondLevelCacheSize; 520 if (L2Associativity) MmSecondaryColors /= L2Associativity; 521 } 522 523 /* Now convert cache bytes into pages */ 524 MmSecondaryColors >>= PAGE_SHIFT; 525 if (!MmSecondaryColors) 526 { 527 /* If there was no cache data from the KPCR, use the default colors */ 528 MmSecondaryColors = MI_SECONDARY_COLORS; 529 } 530 else 531 { 532 /* Otherwise, make sure there aren't too many colors */ 533 if (MmSecondaryColors > MI_MAX_SECONDARY_COLORS) 534 { 535 /* Set the maximum */ 536 MmSecondaryColors = MI_MAX_SECONDARY_COLORS; 537 } 538 539 /* Make sure there aren't too little colors */ 540 if (MmSecondaryColors < MI_MIN_SECONDARY_COLORS) 541 { 542 /* Set the default */ 543 MmSecondaryColors = MI_SECONDARY_COLORS; 544 } 545 546 /* Finally make sure the colors are a power of two */ 547 if (MmSecondaryColors & (MmSecondaryColors - 1)) 548 { 549 /* Set the default */ 550 MmSecondaryColors = MI_SECONDARY_COLORS; 551 } 552 } 553 554 /* Compute the mask and store it */ 555 MmSecondaryColorMask = MmSecondaryColors - 1; 556 KeGetCurrentPrcb()->SecondaryColorMask = MmSecondaryColorMask; 557 } 558 559 VOID 560 NTAPI 561 INIT_FUNCTION 562 MiInitializeColorTables(VOID) 563 { 564 ULONG i; 565 PMMPTE PointerPte, LastPte; 566 MMPTE TempPte = ValidKernelPte; 567 568 /* The color table starts after the ARM3 PFN database */ 569 MmFreePagesByColor[0] = (PMMCOLOR_TABLES)&MmPfnDatabase[MmHighestPhysicalPage + 1]; 570 571 /* Loop the PTEs. We have two color tables for each secondary color */ 572 PointerPte = MiAddressToPte(&MmFreePagesByColor[0][0]); 573 LastPte = MiAddressToPte((ULONG_PTR)MmFreePagesByColor[0] + 574 (2 * MmSecondaryColors * sizeof(MMCOLOR_TABLES)) 575 - 1); 576 while (PointerPte <= LastPte) 577 { 578 /* Check for valid PTE */ 579 if (PointerPte->u.Hard.Valid == 0) 580 { 581 /* Get a page and map it */ 582 TempPte.u.Hard.PageFrameNumber = MxGetNextPage(1); 583 MI_WRITE_VALID_PTE(PointerPte, TempPte); 584 585 /* Zero out the page */ 586 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE); 587 } 588 589 /* Next */ 590 PointerPte++; 591 } 592 593 /* Now set the address of the next list, right after this one */ 594 MmFreePagesByColor[1] = &MmFreePagesByColor[0][MmSecondaryColors]; 595 596 /* Now loop the lists to set them up */ 597 for (i = 0; i < MmSecondaryColors; i++) 598 { 599 /* Set both free and zero lists for each color */ 600 MmFreePagesByColor[ZeroedPageList][i].Flink = LIST_HEAD; 601 MmFreePagesByColor[ZeroedPageList][i].Blink = (PVOID)LIST_HEAD; 602 MmFreePagesByColor[ZeroedPageList][i].Count = 0; 603 MmFreePagesByColor[FreePageList][i].Flink = LIST_HEAD; 604 MmFreePagesByColor[FreePageList][i].Blink = (PVOID)LIST_HEAD; 605 MmFreePagesByColor[FreePageList][i].Count = 0; 606 } 607 } 608 609 #ifndef _M_AMD64 610 BOOLEAN 611 NTAPI 612 INIT_FUNCTION 613 MiIsRegularMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 614 IN PFN_NUMBER Pfn) 615 { 616 PLIST_ENTRY NextEntry; 617 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock; 618 619 /* Loop the memory descriptors */ 620 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink; 621 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead) 622 { 623 /* Get the memory descriptor */ 624 MdBlock = CONTAINING_RECORD(NextEntry, 625 MEMORY_ALLOCATION_DESCRIPTOR, 626 ListEntry); 627 628 /* Check if this PFN could be part of the block */ 629 if (Pfn >= (MdBlock->BasePage)) 630 { 631 /* Check if it really is part of the block */ 632 if (Pfn < (MdBlock->BasePage + MdBlock->PageCount)) 633 { 634 /* Check if the block is actually memory we don't map */ 635 if ((MdBlock->MemoryType == LoaderFirmwarePermanent) || 636 (MdBlock->MemoryType == LoaderBBTMemory) || 637 (MdBlock->MemoryType == LoaderSpecialMemory)) 638 { 639 /* We don't need PFN database entries for this memory */ 640 break; 641 } 642 643 /* This is memory we want to map */ 644 return TRUE; 645 } 646 } 647 else 648 { 649 /* Blocks are ordered, so if it's not here, it doesn't exist */ 650 break; 651 } 652 653 /* Get to the next descriptor */ 654 NextEntry = MdBlock->ListEntry.Flink; 655 } 656 657 /* Check if this PFN is actually from our free memory descriptor */ 658 if ((Pfn >= MxOldFreeDescriptor.BasePage) && 659 (Pfn < MxOldFreeDescriptor.BasePage + MxOldFreeDescriptor.PageCount)) 660 { 661 /* We use these pages for initial mappings, so we do want to count them */ 662 return TRUE; 663 } 664 665 /* Otherwise this isn't memory that we describe or care about */ 666 return FALSE; 667 } 668 669 VOID 670 NTAPI 671 INIT_FUNCTION 672 MiMapPfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 673 { 674 PFN_NUMBER FreePage, FreePageCount, PagesLeft, BasePage, PageCount; 675 PLIST_ENTRY NextEntry; 676 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock; 677 PMMPTE PointerPte, LastPte; 678 MMPTE TempPte = ValidKernelPte; 679 680 /* Get current page data, since we won't be using MxGetNextPage as it would corrupt our state */ 681 FreePage = MxFreeDescriptor->BasePage; 682 FreePageCount = MxFreeDescriptor->PageCount; 683 PagesLeft = 0; 684 685 /* Loop the memory descriptors */ 686 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink; 687 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead) 688 { 689 /* Get the descriptor */ 690 MdBlock = CONTAINING_RECORD(NextEntry, 691 MEMORY_ALLOCATION_DESCRIPTOR, 692 ListEntry); 693 if ((MdBlock->MemoryType == LoaderFirmwarePermanent) || 694 (MdBlock->MemoryType == LoaderBBTMemory) || 695 (MdBlock->MemoryType == LoaderSpecialMemory)) 696 { 697 /* These pages are not part of the PFN database */ 698 NextEntry = MdBlock->ListEntry.Flink; 699 continue; 700 } 701 702 /* Next, check if this is our special free descriptor we've found */ 703 if (MdBlock == MxFreeDescriptor) 704 { 705 /* Use the real numbers instead */ 706 BasePage = MxOldFreeDescriptor.BasePage; 707 PageCount = MxOldFreeDescriptor.PageCount; 708 } 709 else 710 { 711 /* Use the descriptor's numbers */ 712 BasePage = MdBlock->BasePage; 713 PageCount = MdBlock->PageCount; 714 } 715 716 /* Get the PTEs for this range */ 717 PointerPte = MiAddressToPte(&MmPfnDatabase[BasePage]); 718 LastPte = MiAddressToPte(((ULONG_PTR)&MmPfnDatabase[BasePage + PageCount]) - 1); 719 DPRINT("MD Type: %lx Base: %lx Count: %lx\n", MdBlock->MemoryType, BasePage, PageCount); 720 721 /* Loop them */ 722 while (PointerPte <= LastPte) 723 { 724 /* We'll only touch PTEs that aren't already valid */ 725 if (PointerPte->u.Hard.Valid == 0) 726 { 727 /* Use the next free page */ 728 TempPte.u.Hard.PageFrameNumber = FreePage; 729 ASSERT(FreePageCount != 0); 730 731 /* Consume free pages */ 732 FreePage++; 733 FreePageCount--; 734 if (!FreePageCount) 735 { 736 /* Out of memory */ 737 KeBugCheckEx(INSTALL_MORE_MEMORY, 738 MmNumberOfPhysicalPages, 739 FreePageCount, 740 MxOldFreeDescriptor.PageCount, 741 1); 742 } 743 744 /* Write out this PTE */ 745 PagesLeft++; 746 MI_WRITE_VALID_PTE(PointerPte, TempPte); 747 748 /* Zero this page */ 749 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE); 750 } 751 752 /* Next! */ 753 PointerPte++; 754 } 755 756 /* Do the next address range */ 757 NextEntry = MdBlock->ListEntry.Flink; 758 } 759 760 /* Now update the free descriptors to consume the pages we used up during the PFN allocation loop */ 761 MxFreeDescriptor->BasePage = FreePage; 762 MxFreeDescriptor->PageCount = FreePageCount; 763 } 764 765 VOID 766 NTAPI 767 INIT_FUNCTION 768 MiBuildPfnDatabaseFromPages(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 769 { 770 PMMPDE PointerPde; 771 PMMPTE PointerPte; 772 ULONG i, Count, j; 773 PFN_NUMBER PageFrameIndex, StartupPdIndex, PtePageIndex; 774 PMMPFN Pfn1, Pfn2; 775 ULONG_PTR BaseAddress = 0; 776 777 /* PFN of the startup page directory */ 778 StartupPdIndex = PFN_FROM_PTE(MiAddressToPde(PDE_BASE)); 779 780 /* Start with the first PDE and scan them all */ 781 PointerPde = MiAddressToPde(NULL); 782 Count = PD_COUNT * PDE_COUNT; 783 for (i = 0; i < Count; i++) 784 { 785 /* Check for valid PDE */ 786 if (PointerPde->u.Hard.Valid == 1) 787 { 788 /* Get the PFN from it */ 789 PageFrameIndex = PFN_FROM_PTE(PointerPde); 790 791 /* Do we want a PFN entry for this page? */ 792 if (MiIsRegularMemory(LoaderBlock, PageFrameIndex)) 793 { 794 /* Yes we do, set it up */ 795 Pfn1 = MiGetPfnEntry(PageFrameIndex); 796 Pfn1->u4.PteFrame = StartupPdIndex; 797 Pfn1->PteAddress = (PMMPTE)PointerPde; 798 Pfn1->u2.ShareCount++; 799 Pfn1->u3.e2.ReferenceCount = 1; 800 Pfn1->u3.e1.PageLocation = ActiveAndValid; 801 Pfn1->u3.e1.CacheAttribute = MiNonCached; 802 #if MI_TRACE_PFNS 803 Pfn1->PfnUsage = MI_USAGE_INIT_MEMORY; 804 memcpy(Pfn1->ProcessName, "Initial PDE", 16); 805 #endif 806 } 807 else 808 { 809 /* No PFN entry */ 810 Pfn1 = NULL; 811 } 812 813 /* Now get the PTE and scan the pages */ 814 PointerPte = MiAddressToPte(BaseAddress); 815 for (j = 0; j < PTE_COUNT; j++) 816 { 817 /* Check for a valid PTE */ 818 if (PointerPte->u.Hard.Valid == 1) 819 { 820 /* Increase the shared count of the PFN entry for the PDE */ 821 ASSERT(Pfn1 != NULL); 822 Pfn1->u2.ShareCount++; 823 824 /* Now check if the PTE is valid memory too */ 825 PtePageIndex = PFN_FROM_PTE(PointerPte); 826 if (MiIsRegularMemory(LoaderBlock, PtePageIndex)) 827 { 828 /* 829 * Only add pages above the end of system code or pages 830 * that are part of nonpaged pool 831 */ 832 if ((BaseAddress >= 0xA0000000) || 833 ((BaseAddress >= (ULONG_PTR)MmNonPagedPoolStart) && 834 (BaseAddress < (ULONG_PTR)MmNonPagedPoolStart + 835 MmSizeOfNonPagedPoolInBytes))) 836 { 837 /* Get the PFN entry and make sure it too is valid */ 838 Pfn2 = MiGetPfnEntry(PtePageIndex); 839 if ((MmIsAddressValid(Pfn2)) && 840 (MmIsAddressValid(Pfn2 + 1))) 841 { 842 /* Setup the PFN entry */ 843 Pfn2->u4.PteFrame = PageFrameIndex; 844 Pfn2->PteAddress = PointerPte; 845 Pfn2->u2.ShareCount++; 846 Pfn2->u3.e2.ReferenceCount = 1; 847 Pfn2->u3.e1.PageLocation = ActiveAndValid; 848 Pfn2->u3.e1.CacheAttribute = MiNonCached; 849 #if MI_TRACE_PFNS 850 Pfn2->PfnUsage = MI_USAGE_INIT_MEMORY; 851 memcpy(Pfn1->ProcessName, "Initial PTE", 16); 852 #endif 853 } 854 } 855 } 856 } 857 858 /* Next PTE */ 859 PointerPte++; 860 BaseAddress += PAGE_SIZE; 861 } 862 } 863 else 864 { 865 /* Next PDE mapped address */ 866 BaseAddress += PDE_MAPPED_VA; 867 } 868 869 /* Next PTE */ 870 PointerPde++; 871 } 872 } 873 874 VOID 875 NTAPI 876 INIT_FUNCTION 877 MiBuildPfnDatabaseZeroPage(VOID) 878 { 879 PMMPFN Pfn1; 880 PMMPDE PointerPde; 881 882 /* Grab the lowest page and check if it has no real references */ 883 Pfn1 = MiGetPfnEntry(MmLowestPhysicalPage); 884 if (!(MmLowestPhysicalPage) && !(Pfn1->u3.e2.ReferenceCount)) 885 { 886 /* Make it a bogus page to catch errors */ 887 PointerPde = MiAddressToPde(0xFFFFFFFF); 888 Pfn1->u4.PteFrame = PFN_FROM_PTE(PointerPde); 889 Pfn1->PteAddress = (PMMPTE)PointerPde; 890 Pfn1->u2.ShareCount++; 891 Pfn1->u3.e2.ReferenceCount = 0xFFF0; 892 Pfn1->u3.e1.PageLocation = ActiveAndValid; 893 Pfn1->u3.e1.CacheAttribute = MiNonCached; 894 } 895 } 896 897 VOID 898 NTAPI 899 INIT_FUNCTION 900 MiBuildPfnDatabaseFromLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 901 { 902 PLIST_ENTRY NextEntry; 903 PFN_NUMBER PageCount = 0; 904 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock; 905 PFN_NUMBER PageFrameIndex; 906 PMMPFN Pfn1; 907 PMMPTE PointerPte; 908 PMMPDE PointerPde; 909 KIRQL OldIrql; 910 911 /* Now loop through the descriptors */ 912 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink; 913 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead) 914 { 915 /* Get the current descriptor */ 916 MdBlock = CONTAINING_RECORD(NextEntry, 917 MEMORY_ALLOCATION_DESCRIPTOR, 918 ListEntry); 919 920 /* Read its data */ 921 PageCount = MdBlock->PageCount; 922 PageFrameIndex = MdBlock->BasePage; 923 924 /* Don't allow memory above what the PFN database is mapping */ 925 if (PageFrameIndex > MmHighestPhysicalPage) 926 { 927 /* Since they are ordered, everything past here will be larger */ 928 break; 929 } 930 931 /* On the other hand, the end page might be higher up... */ 932 if ((PageFrameIndex + PageCount) > (MmHighestPhysicalPage + 1)) 933 { 934 /* In which case we'll trim the descriptor to go as high as we can */ 935 PageCount = MmHighestPhysicalPage + 1 - PageFrameIndex; 936 MdBlock->PageCount = PageCount; 937 938 /* But if there's nothing left to trim, we got too high, so quit */ 939 if (!PageCount) break; 940 } 941 942 /* Now check the descriptor type */ 943 switch (MdBlock->MemoryType) 944 { 945 /* Check for bad RAM */ 946 case LoaderBad: 947 948 DPRINT1("You either have specified /BURNMEMORY or damaged RAM modules.\n"); 949 break; 950 951 /* Check for free RAM */ 952 case LoaderFree: 953 case LoaderLoadedProgram: 954 case LoaderFirmwareTemporary: 955 case LoaderOsloaderStack: 956 957 /* Get the last page of this descriptor. Note we loop backwards */ 958 PageFrameIndex += PageCount - 1; 959 Pfn1 = MiGetPfnEntry(PageFrameIndex); 960 961 /* Lock the PFN Database */ 962 OldIrql = MiAcquirePfnLock(); 963 while (PageCount--) 964 { 965 /* If the page really has no references, mark it as free */ 966 if (!Pfn1->u3.e2.ReferenceCount) 967 { 968 /* Add it to the free list */ 969 Pfn1->u3.e1.CacheAttribute = MiNonCached; 970 MiInsertPageInFreeList(PageFrameIndex); 971 } 972 973 /* Go to the next page */ 974 Pfn1--; 975 PageFrameIndex--; 976 } 977 978 /* Release PFN database */ 979 MiReleasePfnLock(OldIrql); 980 981 /* Done with this block */ 982 break; 983 984 /* Check for pages that are invisible to us */ 985 case LoaderFirmwarePermanent: 986 case LoaderSpecialMemory: 987 case LoaderBBTMemory: 988 989 /* And skip them */ 990 break; 991 992 default: 993 994 /* Map these pages with the KSEG0 mapping that adds 0x80000000 */ 995 PointerPte = MiAddressToPte(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT)); 996 Pfn1 = MiGetPfnEntry(PageFrameIndex); 997 while (PageCount--) 998 { 999 /* Check if the page is really unused */ 1000 PointerPde = MiAddressToPde(KSEG0_BASE + (PageFrameIndex << PAGE_SHIFT)); 1001 if (!Pfn1->u3.e2.ReferenceCount) 1002 { 1003 /* Mark it as being in-use */ 1004 Pfn1->u4.PteFrame = PFN_FROM_PTE(PointerPde); 1005 Pfn1->PteAddress = PointerPte; 1006 Pfn1->u2.ShareCount++; 1007 Pfn1->u3.e2.ReferenceCount = 1; 1008 Pfn1->u3.e1.PageLocation = ActiveAndValid; 1009 Pfn1->u3.e1.CacheAttribute = MiNonCached; 1010 #if MI_TRACE_PFNS 1011 Pfn1->PfnUsage = MI_USAGE_BOOT_DRIVER; 1012 #endif 1013 1014 /* Check for RAM disk page */ 1015 if (MdBlock->MemoryType == LoaderXIPRom) 1016 { 1017 /* Make it a pseudo-I/O ROM mapping */ 1018 Pfn1->u1.Flink = 0; 1019 Pfn1->u2.ShareCount = 0; 1020 Pfn1->u3.e2.ReferenceCount = 0; 1021 Pfn1->u3.e1.PageLocation = 0; 1022 Pfn1->u3.e1.Rom = 1; 1023 Pfn1->u4.InPageError = 0; 1024 Pfn1->u3.e1.PrototypePte = 1; 1025 } 1026 } 1027 1028 /* Advance page structures */ 1029 Pfn1++; 1030 PageFrameIndex++; 1031 PointerPte++; 1032 } 1033 break; 1034 } 1035 1036 /* Next descriptor entry */ 1037 NextEntry = MdBlock->ListEntry.Flink; 1038 } 1039 } 1040 1041 VOID 1042 NTAPI 1043 INIT_FUNCTION 1044 MiBuildPfnDatabaseSelf(VOID) 1045 { 1046 PMMPTE PointerPte, LastPte; 1047 PMMPFN Pfn1; 1048 1049 /* Loop the PFN database page */ 1050 PointerPte = MiAddressToPte(MiGetPfnEntry(MmLowestPhysicalPage)); 1051 LastPte = MiAddressToPte(MiGetPfnEntry(MmHighestPhysicalPage)); 1052 while (PointerPte <= LastPte) 1053 { 1054 /* Make sure the page is valid */ 1055 if (PointerPte->u.Hard.Valid == 1) 1056 { 1057 /* Get the PFN entry and just mark it referenced */ 1058 Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber); 1059 Pfn1->u2.ShareCount = 1; 1060 Pfn1->u3.e2.ReferenceCount = 1; 1061 #if MI_TRACE_PFNS 1062 Pfn1->PfnUsage = MI_USAGE_PFN_DATABASE; 1063 #endif 1064 } 1065 1066 /* Next */ 1067 PointerPte++; 1068 } 1069 } 1070 1071 VOID 1072 NTAPI 1073 INIT_FUNCTION 1074 MiInitializePfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 1075 { 1076 /* Scan memory and start setting up PFN entries */ 1077 MiBuildPfnDatabaseFromPages(LoaderBlock); 1078 1079 /* Add the zero page */ 1080 MiBuildPfnDatabaseZeroPage(); 1081 1082 /* Scan the loader block and build the rest of the PFN database */ 1083 MiBuildPfnDatabaseFromLoaderBlock(LoaderBlock); 1084 1085 /* Finally add the pages for the PFN database itself */ 1086 MiBuildPfnDatabaseSelf(); 1087 } 1088 #endif /* !_M_AMD64 */ 1089 1090 VOID 1091 NTAPI 1092 INIT_FUNCTION 1093 MmFreeLoaderBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 1094 { 1095 PLIST_ENTRY NextMd; 1096 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock; 1097 ULONG_PTR i; 1098 PFN_NUMBER BasePage, LoaderPages; 1099 PMMPFN Pfn1; 1100 KIRQL OldIrql; 1101 PPHYSICAL_MEMORY_RUN Buffer, Entry; 1102 1103 /* Loop the descriptors in order to count them */ 1104 i = 0; 1105 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; 1106 while (NextMd != &LoaderBlock->MemoryDescriptorListHead) 1107 { 1108 MdBlock = CONTAINING_RECORD(NextMd, 1109 MEMORY_ALLOCATION_DESCRIPTOR, 1110 ListEntry); 1111 i++; 1112 NextMd = MdBlock->ListEntry.Flink; 1113 } 1114 1115 /* Allocate a structure to hold the physical runs */ 1116 Buffer = ExAllocatePoolWithTag(NonPagedPool, 1117 i * sizeof(PHYSICAL_MEMORY_RUN), 1118 'lMmM'); 1119 ASSERT(Buffer != NULL); 1120 Entry = Buffer; 1121 1122 /* Loop the descriptors again */ 1123 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; 1124 while (NextMd != &LoaderBlock->MemoryDescriptorListHead) 1125 { 1126 /* Check what kind this was */ 1127 MdBlock = CONTAINING_RECORD(NextMd, 1128 MEMORY_ALLOCATION_DESCRIPTOR, 1129 ListEntry); 1130 switch (MdBlock->MemoryType) 1131 { 1132 /* Registry, NLS, and heap data */ 1133 case LoaderRegistryData: 1134 case LoaderOsloaderHeap: 1135 case LoaderNlsData: 1136 /* Are all a candidate for deletion */ 1137 Entry->BasePage = MdBlock->BasePage; 1138 Entry->PageCount = MdBlock->PageCount; 1139 Entry++; 1140 1141 /* We keep the rest */ 1142 default: 1143 break; 1144 } 1145 1146 /* Move to the next descriptor */ 1147 NextMd = MdBlock->ListEntry.Flink; 1148 } 1149 1150 /* Acquire the PFN lock */ 1151 OldIrql = MiAcquirePfnLock(); 1152 1153 /* Loop the runs */ 1154 LoaderPages = 0; 1155 while (--Entry >= Buffer) 1156 { 1157 /* See how many pages are in this run */ 1158 i = Entry->PageCount; 1159 BasePage = Entry->BasePage; 1160 1161 /* Loop each page */ 1162 Pfn1 = MiGetPfnEntry(BasePage); 1163 while (i--) 1164 { 1165 /* Check if it has references or is in any kind of list */ 1166 if (!(Pfn1->u3.e2.ReferenceCount) && (!Pfn1->u1.Flink)) 1167 { 1168 /* Set the new PTE address and put this page into the free list */ 1169 Pfn1->PteAddress = (PMMPTE)(BasePage << PAGE_SHIFT); 1170 MiInsertPageInFreeList(BasePage); 1171 LoaderPages++; 1172 } 1173 else if (BasePage) 1174 { 1175 /* It has a reference, so simply drop it */ 1176 ASSERT(MI_IS_PHYSICAL_ADDRESS(MiPteToAddress(Pfn1->PteAddress)) == FALSE); 1177 1178 /* Drop a dereference on this page, which should delete it */ 1179 Pfn1->PteAddress->u.Long = 0; 1180 MI_SET_PFN_DELETED(Pfn1); 1181 MiDecrementShareCount(Pfn1, BasePage); 1182 LoaderPages++; 1183 } 1184 1185 /* Move to the next page */ 1186 Pfn1++; 1187 BasePage++; 1188 } 1189 } 1190 1191 /* Release the PFN lock and flush the TLB */ 1192 DPRINT("Loader pages freed: %lx\n", LoaderPages); 1193 MiReleasePfnLock(OldIrql); 1194 KeFlushCurrentTb(); 1195 1196 /* Free our run structure */ 1197 ExFreePoolWithTag(Buffer, 'lMmM'); 1198 } 1199 1200 VOID 1201 NTAPI 1202 INIT_FUNCTION 1203 MiAdjustWorkingSetManagerParameters(IN BOOLEAN Client) 1204 { 1205 /* This function needs to do more work, for now, we tune page minimums */ 1206 1207 /* Check for a system with around 64MB RAM or more */ 1208 if (MmNumberOfPhysicalPages >= (63 * _1MB) / PAGE_SIZE) 1209 { 1210 /* Double the minimum amount of pages we consider for a "plenty free" scenario */ 1211 MmPlentyFreePages *= 2; 1212 } 1213 } 1214 1215 VOID 1216 NTAPI 1217 INIT_FUNCTION 1218 MiNotifyMemoryEvents(VOID) 1219 { 1220 /* Are we in a low-memory situation? */ 1221 if (MmAvailablePages < MmLowMemoryThreshold) 1222 { 1223 /* Clear high, set low */ 1224 if (KeReadStateEvent(MiHighMemoryEvent)) KeClearEvent(MiHighMemoryEvent); 1225 if (!KeReadStateEvent(MiLowMemoryEvent)) KeSetEvent(MiLowMemoryEvent, 0, FALSE); 1226 } 1227 else if (MmAvailablePages < MmHighMemoryThreshold) 1228 { 1229 /* We are in between, clear both */ 1230 if (KeReadStateEvent(MiHighMemoryEvent)) KeClearEvent(MiHighMemoryEvent); 1231 if (KeReadStateEvent(MiLowMemoryEvent)) KeClearEvent(MiLowMemoryEvent); 1232 } 1233 else 1234 { 1235 /* Clear low, set high */ 1236 if (KeReadStateEvent(MiLowMemoryEvent)) KeClearEvent(MiLowMemoryEvent); 1237 if (!KeReadStateEvent(MiHighMemoryEvent)) KeSetEvent(MiHighMemoryEvent, 0, FALSE); 1238 } 1239 } 1240 1241 NTSTATUS 1242 NTAPI 1243 INIT_FUNCTION 1244 MiCreateMemoryEvent(IN PUNICODE_STRING Name, 1245 OUT PKEVENT *Event) 1246 { 1247 PACL Dacl; 1248 HANDLE EventHandle; 1249 ULONG DaclLength; 1250 NTSTATUS Status; 1251 OBJECT_ATTRIBUTES ObjectAttributes; 1252 SECURITY_DESCRIPTOR SecurityDescriptor; 1253 1254 /* Create the SD */ 1255 Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, 1256 SECURITY_DESCRIPTOR_REVISION); 1257 if (!NT_SUCCESS(Status)) return Status; 1258 1259 /* One ACL with 3 ACEs, containing each one SID */ 1260 DaclLength = sizeof(ACL) + 1261 3 * sizeof(ACCESS_ALLOWED_ACE) + 1262 RtlLengthSid(SeLocalSystemSid) + 1263 RtlLengthSid(SeAliasAdminsSid) + 1264 RtlLengthSid(SeWorldSid); 1265 1266 /* Allocate space for the DACL */ 1267 Dacl = ExAllocatePoolWithTag(PagedPool, DaclLength, 'lcaD'); 1268 if (!Dacl) return STATUS_INSUFFICIENT_RESOURCES; 1269 1270 /* Setup the ACL inside it */ 1271 Status = RtlCreateAcl(Dacl, DaclLength, ACL_REVISION); 1272 if (!NT_SUCCESS(Status)) goto CleanUp; 1273 1274 /* Add query rights for everyone */ 1275 Status = RtlAddAccessAllowedAce(Dacl, 1276 ACL_REVISION, 1277 SYNCHRONIZE | EVENT_QUERY_STATE | READ_CONTROL, 1278 SeWorldSid); 1279 if (!NT_SUCCESS(Status)) goto CleanUp; 1280 1281 /* Full rights for the admin */ 1282 Status = RtlAddAccessAllowedAce(Dacl, 1283 ACL_REVISION, 1284 EVENT_ALL_ACCESS, 1285 SeAliasAdminsSid); 1286 if (!NT_SUCCESS(Status)) goto CleanUp; 1287 1288 /* As well as full rights for the system */ 1289 Status = RtlAddAccessAllowedAce(Dacl, 1290 ACL_REVISION, 1291 EVENT_ALL_ACCESS, 1292 SeLocalSystemSid); 1293 if (!NT_SUCCESS(Status)) goto CleanUp; 1294 1295 /* Set this DACL inside the SD */ 1296 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, 1297 TRUE, 1298 Dacl, 1299 FALSE); 1300 if (!NT_SUCCESS(Status)) goto CleanUp; 1301 1302 /* Setup the event attributes, making sure it's a permanent one */ 1303 InitializeObjectAttributes(&ObjectAttributes, 1304 Name, 1305 OBJ_KERNEL_HANDLE | OBJ_PERMANENT, 1306 NULL, 1307 &SecurityDescriptor); 1308 1309 /* Create the event */ 1310 Status = ZwCreateEvent(&EventHandle, 1311 EVENT_ALL_ACCESS, 1312 &ObjectAttributes, 1313 NotificationEvent, 1314 FALSE); 1315 CleanUp: 1316 /* Free the DACL */ 1317 ExFreePoolWithTag(Dacl, 'lcaD'); 1318 1319 /* Check if this is the success path */ 1320 if (NT_SUCCESS(Status)) 1321 { 1322 /* Add a reference to the object, then close the handle we had */ 1323 Status = ObReferenceObjectByHandle(EventHandle, 1324 EVENT_MODIFY_STATE, 1325 ExEventObjectType, 1326 KernelMode, 1327 (PVOID*)Event, 1328 NULL); 1329 ZwClose (EventHandle); 1330 } 1331 1332 /* Return status */ 1333 return Status; 1334 } 1335 1336 BOOLEAN 1337 NTAPI 1338 INIT_FUNCTION 1339 MiInitializeMemoryEvents(VOID) 1340 { 1341 UNICODE_STRING LowString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowMemoryCondition"); 1342 UNICODE_STRING HighString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighMemoryCondition"); 1343 UNICODE_STRING LowPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowPagedPoolCondition"); 1344 UNICODE_STRING HighPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighPagedPoolCondition"); 1345 UNICODE_STRING LowNonPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\LowNonPagedPoolCondition"); 1346 UNICODE_STRING HighNonPagedPoolString = RTL_CONSTANT_STRING(L"\\KernelObjects\\HighNonPagedPoolCondition"); 1347 NTSTATUS Status; 1348 1349 /* Check if we have a registry setting */ 1350 if (MmLowMemoryThreshold) 1351 { 1352 /* Convert it to pages */ 1353 MmLowMemoryThreshold *= (_1MB / PAGE_SIZE); 1354 } 1355 else 1356 { 1357 /* The low memory threshold is hit when we don't consider that we have "plenty" of free pages anymore */ 1358 MmLowMemoryThreshold = MmPlentyFreePages; 1359 1360 /* More than one GB of memory? */ 1361 if (MmNumberOfPhysicalPages > 0x40000) 1362 { 1363 /* Start at 32MB, and add another 16MB for each GB */ 1364 MmLowMemoryThreshold = (32 * _1MB) / PAGE_SIZE; 1365 MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x40000) >> 7); 1366 } 1367 else if (MmNumberOfPhysicalPages > 0x8000) 1368 { 1369 /* For systems with > 128MB RAM, add another 4MB for each 128MB */ 1370 MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x8000) >> 5); 1371 } 1372 1373 /* Don't let the minimum threshold go past 64MB */ 1374 MmLowMemoryThreshold = min(MmLowMemoryThreshold, (64 * _1MB) / PAGE_SIZE); 1375 } 1376 1377 /* Check if we have a registry setting */ 1378 if (MmHighMemoryThreshold) 1379 { 1380 /* Convert it into pages */ 1381 MmHighMemoryThreshold *= (_1MB / PAGE_SIZE); 1382 } 1383 else 1384 { 1385 /* Otherwise, the default is three times the low memory threshold */ 1386 MmHighMemoryThreshold = 3 * MmLowMemoryThreshold; 1387 ASSERT(MmHighMemoryThreshold > MmLowMemoryThreshold); 1388 } 1389 1390 /* Make sure high threshold is actually higher than the low */ 1391 MmHighMemoryThreshold = max(MmHighMemoryThreshold, MmLowMemoryThreshold); 1392 1393 /* Create the memory events for all the thresholds */ 1394 Status = MiCreateMemoryEvent(&LowString, &MiLowMemoryEvent); 1395 if (!NT_SUCCESS(Status)) return FALSE; 1396 Status = MiCreateMemoryEvent(&HighString, &MiHighMemoryEvent); 1397 if (!NT_SUCCESS(Status)) return FALSE; 1398 Status = MiCreateMemoryEvent(&LowPagedPoolString, &MiLowPagedPoolEvent); 1399 if (!NT_SUCCESS(Status)) return FALSE; 1400 Status = MiCreateMemoryEvent(&HighPagedPoolString, &MiHighPagedPoolEvent); 1401 if (!NT_SUCCESS(Status)) return FALSE; 1402 Status = MiCreateMemoryEvent(&LowNonPagedPoolString, &MiLowNonPagedPoolEvent); 1403 if (!NT_SUCCESS(Status)) return FALSE; 1404 Status = MiCreateMemoryEvent(&HighNonPagedPoolString, &MiHighNonPagedPoolEvent); 1405 if (!NT_SUCCESS(Status)) return FALSE; 1406 1407 /* Now setup the pool events */ 1408 MiInitializePoolEvents(); 1409 1410 /* Set the initial event state */ 1411 MiNotifyMemoryEvents(); 1412 return TRUE; 1413 } 1414 1415 VOID 1416 NTAPI 1417 INIT_FUNCTION 1418 MiAddHalIoMappings(VOID) 1419 { 1420 PVOID BaseAddress; 1421 PMMPDE PointerPde, LastPde; 1422 PMMPTE PointerPte; 1423 ULONG j; 1424 PFN_NUMBER PageFrameIndex; 1425 1426 /* HAL Heap address -- should be on a PDE boundary */ 1427 BaseAddress = (PVOID)MM_HAL_VA_START; 1428 ASSERT(MiAddressToPteOffset(BaseAddress) == 0); 1429 1430 /* Check how many PDEs the heap has */ 1431 PointerPde = MiAddressToPde(BaseAddress); 1432 LastPde = MiAddressToPde((PVOID)MM_HAL_VA_END); 1433 1434 while (PointerPde <= LastPde) 1435 { 1436 /* Does the HAL own this mapping? */ 1437 if ((PointerPde->u.Hard.Valid == 1) && 1438 (MI_IS_PAGE_LARGE(PointerPde) == FALSE)) 1439 { 1440 /* Get the PTE for it and scan each page */ 1441 PointerPte = MiAddressToPte(BaseAddress); 1442 for (j = 0 ; j < PTE_COUNT; j++) 1443 { 1444 /* Does the HAL own this page? */ 1445 if (PointerPte->u.Hard.Valid == 1) 1446 { 1447 /* Is the HAL using it for device or I/O mapped memory? */ 1448 PageFrameIndex = PFN_FROM_PTE(PointerPte); 1449 if (!MiGetPfnEntry(PageFrameIndex)) 1450 { 1451 /* FIXME: For PAT, we need to track I/O cache attributes for coherency */ 1452 DPRINT1("HAL I/O Mapping at %p is unsafe\n", BaseAddress); 1453 } 1454 } 1455 1456 /* Move to the next page */ 1457 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE); 1458 PointerPte++; 1459 } 1460 } 1461 else 1462 { 1463 /* Move to the next address */ 1464 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PDE_MAPPED_VA); 1465 } 1466 1467 /* Move to the next PDE */ 1468 PointerPde++; 1469 } 1470 } 1471 1472 VOID 1473 NTAPI 1474 MmDumpArmPfnDatabase(IN BOOLEAN StatusOnly) 1475 { 1476 ULONG i; 1477 PMMPFN Pfn1; 1478 PCHAR Consumer = "Unknown"; 1479 KIRQL OldIrql; 1480 ULONG ActivePages = 0, FreePages = 0, OtherPages = 0; 1481 #if MI_TRACE_PFNS 1482 ULONG UsageBucket[MI_USAGE_FREE_PAGE + 1] = {0}; 1483 PCHAR MI_USAGE_TEXT[MI_USAGE_FREE_PAGE + 1] = 1484 { 1485 "Not set", 1486 "Paged Pool", 1487 "Nonpaged Pool", 1488 "Nonpaged Pool Ex", 1489 "Kernel Stack", 1490 "Kernel Stack Ex", 1491 "System PTE", 1492 "VAD", 1493 "PEB/TEB", 1494 "Section", 1495 "Page Table", 1496 "Page Directory", 1497 "Old Page Table", 1498 "Driver Page", 1499 "Contiguous Alloc", 1500 "MDL", 1501 "Demand Zero", 1502 "Zero Loop", 1503 "Cache", 1504 "PFN Database", 1505 "Boot Driver", 1506 "Initial Memory", 1507 "Free Page" 1508 }; 1509 #endif 1510 // 1511 // Loop the PFN database 1512 // 1513 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 1514 for (i = 0; i <= MmHighestPhysicalPage; i++) 1515 { 1516 Pfn1 = MiGetPfnEntry(i); 1517 if (!Pfn1) continue; 1518 #if MI_TRACE_PFNS 1519 ASSERT(Pfn1->PfnUsage <= MI_USAGE_FREE_PAGE); 1520 #endif 1521 // 1522 // Get the page location 1523 // 1524 switch (Pfn1->u3.e1.PageLocation) 1525 { 1526 case ActiveAndValid: 1527 1528 Consumer = "Active and Valid"; 1529 ActivePages++; 1530 break; 1531 1532 case ZeroedPageList: 1533 1534 Consumer = "Zero Page List"; 1535 FreePages++; 1536 break;//continue; 1537 1538 case FreePageList: 1539 1540 Consumer = "Free Page List"; 1541 FreePages++; 1542 break;//continue; 1543 1544 default: 1545 1546 Consumer = "Other (ASSERT!)"; 1547 OtherPages++; 1548 break; 1549 } 1550 1551 #if MI_TRACE_PFNS 1552 /* Add into bucket */ 1553 UsageBucket[Pfn1->PfnUsage]++; 1554 #endif 1555 1556 // 1557 // Pretty-print the page 1558 // 1559 if (!StatusOnly) 1560 DbgPrint("0x%08p:\t%20s\t(%04d.%04d)\t[%16s - %16s])\n", 1561 i << PAGE_SHIFT, 1562 Consumer, 1563 Pfn1->u3.e2.ReferenceCount, 1564 Pfn1->u2.ShareCount == LIST_HEAD ? 0xFFFF : Pfn1->u2.ShareCount, 1565 #if MI_TRACE_PFNS 1566 MI_USAGE_TEXT[Pfn1->PfnUsage], 1567 Pfn1->ProcessName); 1568 #else 1569 "Page tracking", 1570 "is disabled"); 1571 #endif 1572 } 1573 1574 DbgPrint("Active: %5d pages\t[%6d KB]\n", ActivePages, (ActivePages << PAGE_SHIFT) / 1024); 1575 DbgPrint("Free: %5d pages\t[%6d KB]\n", FreePages, (FreePages << PAGE_SHIFT) / 1024); 1576 DbgPrint("Other: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1577 DbgPrint("-----------------------------------------\n"); 1578 #if MI_TRACE_PFNS 1579 OtherPages = UsageBucket[MI_USAGE_BOOT_DRIVER]; 1580 DbgPrint("Boot Images: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1581 OtherPages = UsageBucket[MI_USAGE_DRIVER_PAGE]; 1582 DbgPrint("System Drivers: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1583 OtherPages = UsageBucket[MI_USAGE_PFN_DATABASE]; 1584 DbgPrint("PFN Database: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1585 OtherPages = UsageBucket[MI_USAGE_PAGE_TABLE] + UsageBucket[MI_USAGE_PAGE_DIRECTORY] + UsageBucket[MI_USAGE_LEGACY_PAGE_DIRECTORY]; 1586 DbgPrint("Page Tables: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1587 OtherPages = UsageBucket[MI_USAGE_SYSTEM_PTE]; 1588 DbgPrint("System PTEs: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1589 OtherPages = UsageBucket[MI_USAGE_VAD]; 1590 DbgPrint("VADs: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1591 OtherPages = UsageBucket[MI_USAGE_CONTINOUS_ALLOCATION]; 1592 DbgPrint("Continuous Allocs: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1593 OtherPages = UsageBucket[MI_USAGE_MDL]; 1594 DbgPrint("MDLs: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1595 OtherPages = UsageBucket[MI_USAGE_NONPAGED_POOL] + UsageBucket[MI_USAGE_NONPAGED_POOL_EXPANSION]; 1596 DbgPrint("NonPaged Pool: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1597 OtherPages = UsageBucket[MI_USAGE_PAGED_POOL]; 1598 DbgPrint("Paged Pool: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1599 OtherPages = UsageBucket[MI_USAGE_DEMAND_ZERO]; 1600 DbgPrint("Demand Zero: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1601 OtherPages = UsageBucket[MI_USAGE_ZERO_LOOP]; 1602 DbgPrint("Zero Loop: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1603 OtherPages = UsageBucket[MI_USAGE_PEB_TEB]; 1604 DbgPrint("PEB/TEB: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1605 OtherPages = UsageBucket[MI_USAGE_KERNEL_STACK] + UsageBucket[MI_USAGE_KERNEL_STACK_EXPANSION]; 1606 DbgPrint("Kernel Stack: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1607 OtherPages = UsageBucket[MI_USAGE_INIT_MEMORY]; 1608 DbgPrint("Init Memory: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1609 OtherPages = UsageBucket[MI_USAGE_SECTION]; 1610 DbgPrint("Sections: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1611 OtherPages = UsageBucket[MI_USAGE_CACHE]; 1612 DbgPrint("Cache: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1613 OtherPages = UsageBucket[MI_USAGE_FREE_PAGE]; 1614 DbgPrint("Free: %5d pages\t[%6d KB]\n", OtherPages, (OtherPages << PAGE_SHIFT) / 1024); 1615 #endif 1616 KeLowerIrql(OldIrql); 1617 } 1618 1619 PPHYSICAL_MEMORY_DESCRIPTOR 1620 NTAPI 1621 INIT_FUNCTION 1622 MmInitializeMemoryLimits(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 1623 IN PBOOLEAN IncludeType) 1624 { 1625 PLIST_ENTRY NextEntry; 1626 ULONG Run = 0, InitialRuns; 1627 PFN_NUMBER NextPage = -1, PageCount = 0; 1628 PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer; 1629 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock; 1630 1631 // 1632 // Start with the maximum we might need 1633 // 1634 InitialRuns = MiNumberDescriptors; 1635 1636 // 1637 // Allocate the maximum we'll ever need 1638 // 1639 Buffer = ExAllocatePoolWithTag(NonPagedPool, 1640 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + 1641 sizeof(PHYSICAL_MEMORY_RUN) * 1642 (InitialRuns - 1), 1643 'lMmM'); 1644 if (!Buffer) return NULL; 1645 1646 // 1647 // For now that's how many runs we have 1648 // 1649 Buffer->NumberOfRuns = InitialRuns; 1650 1651 // 1652 // Now loop through the descriptors again 1653 // 1654 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink; 1655 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead) 1656 { 1657 // 1658 // Grab each one, and check if it's one we should include 1659 // 1660 MdBlock = CONTAINING_RECORD(NextEntry, 1661 MEMORY_ALLOCATION_DESCRIPTOR, 1662 ListEntry); 1663 if ((MdBlock->MemoryType < LoaderMaximum) && 1664 (IncludeType[MdBlock->MemoryType])) 1665 { 1666 // 1667 // Add this to our running total 1668 // 1669 PageCount += MdBlock->PageCount; 1670 1671 // 1672 // Check if the next page is described by the next descriptor 1673 // 1674 if (MdBlock->BasePage == NextPage) 1675 { 1676 // 1677 // Combine it into the same physical run 1678 // 1679 ASSERT(MdBlock->PageCount != 0); 1680 Buffer->Run[Run - 1].PageCount += MdBlock->PageCount; 1681 NextPage += MdBlock->PageCount; 1682 } 1683 else 1684 { 1685 // 1686 // Otherwise just duplicate the descriptor's contents 1687 // 1688 Buffer->Run[Run].BasePage = MdBlock->BasePage; 1689 Buffer->Run[Run].PageCount = MdBlock->PageCount; 1690 NextPage = Buffer->Run[Run].BasePage + Buffer->Run[Run].PageCount; 1691 1692 // 1693 // And in this case, increase the number of runs 1694 // 1695 Run++; 1696 } 1697 } 1698 1699 // 1700 // Try the next descriptor 1701 // 1702 NextEntry = MdBlock->ListEntry.Flink; 1703 } 1704 1705 // 1706 // We should not have been able to go past our initial estimate 1707 // 1708 ASSERT(Run <= Buffer->NumberOfRuns); 1709 1710 // 1711 // Our guess was probably exaggerated... 1712 // 1713 if (InitialRuns > Run) 1714 { 1715 // 1716 // Allocate a more accurately sized buffer 1717 // 1718 NewBuffer = ExAllocatePoolWithTag(NonPagedPool, 1719 sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + 1720 sizeof(PHYSICAL_MEMORY_RUN) * 1721 (Run - 1), 1722 'lMmM'); 1723 if (NewBuffer) 1724 { 1725 // 1726 // Copy the old buffer into the new, then free it 1727 // 1728 RtlCopyMemory(NewBuffer->Run, 1729 Buffer->Run, 1730 sizeof(PHYSICAL_MEMORY_RUN) * Run); 1731 ExFreePoolWithTag(Buffer, 'lMmM'); 1732 1733 // 1734 // Now use the new buffer 1735 // 1736 Buffer = NewBuffer; 1737 } 1738 } 1739 1740 // 1741 // Write the final numbers, and return it 1742 // 1743 Buffer->NumberOfRuns = Run; 1744 Buffer->NumberOfPages = PageCount; 1745 return Buffer; 1746 } 1747 1748 VOID 1749 NTAPI 1750 INIT_FUNCTION 1751 MiBuildPagedPool(VOID) 1752 { 1753 PMMPTE PointerPte; 1754 PMMPDE PointerPde; 1755 MMPDE TempPde = ValidKernelPde; 1756 PFN_NUMBER PageFrameIndex; 1757 KIRQL OldIrql; 1758 SIZE_T Size; 1759 ULONG BitMapSize; 1760 #if (_MI_PAGING_LEVELS >= 3) 1761 MMPPE TempPpe = ValidKernelPpe; 1762 PMMPPE PointerPpe; 1763 #elif (_MI_PAGING_LEVELS == 2) 1764 MMPTE TempPte = ValidKernelPte; 1765 1766 // 1767 // Get the page frame number for the system page directory 1768 // 1769 PointerPte = MiAddressToPte(PDE_BASE); 1770 ASSERT(PD_COUNT == 1); 1771 MmSystemPageDirectory[0] = PFN_FROM_PTE(PointerPte); 1772 1773 // 1774 // Allocate a system PTE which will hold a copy of the page directory 1775 // 1776 PointerPte = MiReserveSystemPtes(1, SystemPteSpace); 1777 ASSERT(PointerPte); 1778 MmSystemPagePtes = MiPteToAddress(PointerPte); 1779 1780 // 1781 // Make this system PTE point to the system page directory. 1782 // It is now essentially double-mapped. This will be used later for lazy 1783 // evaluation of PDEs accross process switches, similarly to how the Global 1784 // page directory array in the old ReactOS Mm is used (but in a less hacky 1785 // way). 1786 // 1787 TempPte = ValidKernelPte; 1788 ASSERT(PD_COUNT == 1); 1789 TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory[0]; 1790 MI_WRITE_VALID_PTE(PointerPte, TempPte); 1791 #endif 1792 1793 #ifdef _M_IX86 1794 // 1795 // Let's get back to paged pool work: size it up. 1796 // By default, it should be twice as big as nonpaged pool. 1797 // 1798 MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes; 1799 if (MmSizeOfPagedPoolInBytes > ((ULONG_PTR)MmNonPagedSystemStart - 1800 (ULONG_PTR)MmPagedPoolStart)) 1801 { 1802 // 1803 // On the other hand, we have limited VA space, so make sure that the VA 1804 // for paged pool doesn't overflow into nonpaged pool VA. Otherwise, set 1805 // whatever maximum is possible. 1806 // 1807 MmSizeOfPagedPoolInBytes = (ULONG_PTR)MmNonPagedSystemStart - 1808 (ULONG_PTR)MmPagedPoolStart; 1809 } 1810 #endif // _M_IX86 1811 1812 // 1813 // Get the size in pages and make sure paged pool is at least 32MB. 1814 // 1815 Size = MmSizeOfPagedPoolInBytes; 1816 if (Size < MI_MIN_INIT_PAGED_POOLSIZE) Size = MI_MIN_INIT_PAGED_POOLSIZE; 1817 Size = BYTES_TO_PAGES(Size); 1818 1819 // 1820 // Now check how many PTEs will be required for these many pages. 1821 // 1822 Size = (Size + (1024 - 1)) / 1024; 1823 1824 // 1825 // Recompute the page-aligned size of the paged pool, in bytes and pages. 1826 // 1827 MmSizeOfPagedPoolInBytes = Size * PAGE_SIZE * 1024; 1828 MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT; 1829 1830 #ifdef _M_IX86 1831 // 1832 // Let's be really sure this doesn't overflow into nonpaged system VA 1833 // 1834 ASSERT((MmSizeOfPagedPoolInBytes + (ULONG_PTR)MmPagedPoolStart) <= 1835 (ULONG_PTR)MmNonPagedSystemStart); 1836 #endif // _M_IX86 1837 1838 // 1839 // This is where paged pool ends 1840 // 1841 MmPagedPoolEnd = (PVOID)(((ULONG_PTR)MmPagedPoolStart + 1842 MmSizeOfPagedPoolInBytes) - 1); 1843 1844 // 1845 // Lock the PFN database 1846 // 1847 OldIrql = MiAcquirePfnLock(); 1848 1849 #if (_MI_PAGING_LEVELS >= 3) 1850 /* On these systems, there's no double-mapping, so instead, the PPEs 1851 * are setup to span the entire paged pool area, so there's no need for the 1852 * system PD */ 1853 for (PointerPpe = MiAddressToPpe(MmPagedPoolStart); 1854 PointerPpe <= MiAddressToPpe(MmPagedPoolEnd); 1855 PointerPpe++) 1856 { 1857 /* Check if the PPE is already valid */ 1858 if (!PointerPpe->u.Hard.Valid) 1859 { 1860 /* It is not, so map a fresh zeroed page */ 1861 TempPpe.u.Hard.PageFrameNumber = MiRemoveZeroPage(0); 1862 MI_WRITE_VALID_PPE(PointerPpe, TempPpe); 1863 } 1864 } 1865 #endif 1866 1867 // 1868 // So now get the PDE for paged pool and zero it out 1869 // 1870 PointerPde = MiAddressToPde(MmPagedPoolStart); 1871 RtlZeroMemory(PointerPde, 1872 (1 + MiAddressToPde(MmPagedPoolEnd) - PointerPde) * sizeof(MMPDE)); 1873 1874 // 1875 // Next, get the first and last PTE 1876 // 1877 PointerPte = MiAddressToPte(MmPagedPoolStart); 1878 MmPagedPoolInfo.FirstPteForPagedPool = PointerPte; 1879 MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd); 1880 1881 /* Allocate a page and map the first paged pool PDE */ 1882 MI_SET_USAGE(MI_USAGE_PAGED_POOL); 1883 MI_SET_PROCESS2("Kernel"); 1884 PageFrameIndex = MiRemoveZeroPage(0); 1885 TempPde.u.Hard.PageFrameNumber = PageFrameIndex; 1886 MI_WRITE_VALID_PDE(PointerPde, TempPde); 1887 #if (_MI_PAGING_LEVELS >= 3) 1888 /* Use the PPE of MmPagedPoolStart that was setup above */ 1889 // Bla = PFN_FROM_PTE(PpeAddress(MmPagedPool...)); 1890 1891 /* Initialize the PFN entry for it */ 1892 MiInitializePfnForOtherProcess(PageFrameIndex, 1893 (PMMPTE)PointerPde, 1894 PFN_FROM_PTE(MiAddressToPpe(MmPagedPoolStart))); 1895 #else 1896 /* Do it this way */ 1897 // Bla = MmSystemPageDirectory[(PointerPde - (PMMPTE)PDE_BASE) / PDE_COUNT] 1898 1899 /* Initialize the PFN entry for it */ 1900 MiInitializePfnForOtherProcess(PageFrameIndex, 1901 (PMMPTE)PointerPde, 1902 MmSystemPageDirectory[(PointerPde - (PMMPDE)PDE_BASE) / PDE_COUNT]); 1903 #endif 1904 1905 // 1906 // Release the PFN database lock 1907 // 1908 MiReleasePfnLock(OldIrql); 1909 1910 // 1911 // We only have one PDE mapped for now... at fault time, additional PDEs 1912 // will be allocated to handle paged pool growth. This is where they'll have 1913 // to start. 1914 // 1915 MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1; 1916 1917 // 1918 // We keep track of each page via a bit, so check how big the bitmap will 1919 // have to be (make sure to align our page count such that it fits nicely 1920 // into a 4-byte aligned bitmap. 1921 // 1922 // We'll also allocate the bitmap header itself part of the same buffer. 1923 // 1924 Size = Size * 1024; 1925 ASSERT(Size == MmSizeOfPagedPoolInPages); 1926 BitMapSize = (ULONG)Size; 1927 Size = sizeof(RTL_BITMAP) + (((Size + 31) / 32) * sizeof(ULONG)); 1928 1929 // 1930 // Allocate the allocation bitmap, which tells us which regions have not yet 1931 // been mapped into memory 1932 // 1933 MmPagedPoolInfo.PagedPoolAllocationMap = ExAllocatePoolWithTag(NonPagedPool, 1934 Size, 1935 TAG_MM); 1936 ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap); 1937 1938 // 1939 // Initialize it such that at first, only the first page's worth of PTEs is 1940 // marked as allocated (incidentially, the first PDE we allocated earlier). 1941 // 1942 RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap, 1943 (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1), 1944 BitMapSize); 1945 RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap); 1946 RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 1024); 1947 1948 // 1949 // We have a second bitmap, which keeps track of where allocations end. 1950 // Given the allocation bitmap and a base address, we can therefore figure 1951 // out which page is the last page of that allocation, and thus how big the 1952 // entire allocation is. 1953 // 1954 MmPagedPoolInfo.EndOfPagedPoolBitmap = ExAllocatePoolWithTag(NonPagedPool, 1955 Size, 1956 TAG_MM); 1957 ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap); 1958 RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap, 1959 (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1), 1960 BitMapSize); 1961 1962 // 1963 // Since no allocations have been made yet, there are no bits set as the end 1964 // 1965 RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap); 1966 1967 // 1968 // Initialize paged pool. 1969 // 1970 InitializePool(PagedPool, 0); 1971 1972 /* Initialize special pool */ 1973 MiInitializeSpecialPool(); 1974 1975 /* Default low threshold of 30MB or one fifth of paged pool */ 1976 MiLowPagedPoolThreshold = (30 * _1MB) >> PAGE_SHIFT; 1977 MiLowPagedPoolThreshold = min(MiLowPagedPoolThreshold, Size / 5); 1978 1979 /* Default high threshold of 60MB or 25% */ 1980 MiHighPagedPoolThreshold = (60 * _1MB) >> PAGE_SHIFT; 1981 MiHighPagedPoolThreshold = min(MiHighPagedPoolThreshold, (Size * 2) / 5); 1982 ASSERT(MiLowPagedPoolThreshold < MiHighPagedPoolThreshold); 1983 1984 /* Setup the global session space */ 1985 MiInitializeSystemSpaceMap(NULL); 1986 } 1987 1988 VOID 1989 NTAPI 1990 INIT_FUNCTION 1991 MiDbgDumpMemoryDescriptors(VOID) 1992 { 1993 PLIST_ENTRY NextEntry; 1994 PMEMORY_ALLOCATION_DESCRIPTOR Md; 1995 PFN_NUMBER TotalPages = 0; 1996 PCHAR 1997 MemType[] = 1998 { 1999 "ExceptionBlock ", 2000 "SystemBlock ", 2001 "Free ", 2002 "Bad ", 2003 "LoadedProgram ", 2004 "FirmwareTemporary ", 2005 "FirmwarePermanent ", 2006 "OsloaderHeap ", 2007 "OsloaderStack ", 2008 "SystemCode ", 2009 "HalCode ", 2010 "BootDriver ", 2011 "ConsoleInDriver ", 2012 "ConsoleOutDriver ", 2013 "StartupDpcStack ", 2014 "StartupKernelStack", 2015 "StartupPanicStack ", 2016 "StartupPcrPage ", 2017 "StartupPdrPage ", 2018 "RegistryData ", 2019 "MemoryData ", 2020 "NlsData ", 2021 "SpecialMemory ", 2022 "BBTMemory ", 2023 "LoaderReserve ", 2024 "LoaderXIPRom " 2025 }; 2026 2027 DPRINT1("Base\t\tLength\t\tType\n"); 2028 for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink; 2029 NextEntry != &KeLoaderBlock->MemoryDescriptorListHead; 2030 NextEntry = NextEntry->Flink) 2031 { 2032 Md = CONTAINING_RECORD(NextEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); 2033 DPRINT1("%08lX\t%08lX\t%s\n", Md->BasePage, Md->PageCount, MemType[Md->MemoryType]); 2034 TotalPages += Md->PageCount; 2035 } 2036 2037 DPRINT1("Total: %08lX (%lu MB)\n", (ULONG)TotalPages, (ULONG)(TotalPages * PAGE_SIZE) / 1024 / 1024); 2038 } 2039 2040 BOOLEAN 2041 NTAPI 2042 INIT_FUNCTION 2043 MmArmInitSystem(IN ULONG Phase, 2044 IN PLOADER_PARAMETER_BLOCK LoaderBlock) 2045 { 2046 ULONG i; 2047 BOOLEAN IncludeType[LoaderMaximum]; 2048 PVOID Bitmap; 2049 PPHYSICAL_MEMORY_RUN Run; 2050 PFN_NUMBER PageCount; 2051 #if DBG 2052 ULONG j; 2053 PMMPTE PointerPte, TestPte; 2054 MMPTE TempPte; 2055 #endif 2056 2057 /* Dump memory descriptors */ 2058 if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors(); 2059 2060 // 2061 // Instantiate memory that we don't consider RAM/usable 2062 // We use the same exclusions that Windows does, in order to try to be 2063 // compatible with WinLDR-style booting 2064 // 2065 for (i = 0; i < LoaderMaximum; i++) IncludeType[i] = TRUE; 2066 IncludeType[LoaderBad] = FALSE; 2067 IncludeType[LoaderFirmwarePermanent] = FALSE; 2068 IncludeType[LoaderSpecialMemory] = FALSE; 2069 IncludeType[LoaderBBTMemory] = FALSE; 2070 if (Phase == 0) 2071 { 2072 /* Count physical pages on the system */ 2073 MiScanMemoryDescriptors(LoaderBlock); 2074 2075 /* Initialize the phase 0 temporary event */ 2076 KeInitializeEvent(&MiTempEvent, NotificationEvent, FALSE); 2077 2078 /* Set all the events to use the temporary event for now */ 2079 MiLowMemoryEvent = &MiTempEvent; 2080 MiHighMemoryEvent = &MiTempEvent; 2081 MiLowPagedPoolEvent = &MiTempEvent; 2082 MiHighPagedPoolEvent = &MiTempEvent; 2083 MiLowNonPagedPoolEvent = &MiTempEvent; 2084 MiHighNonPagedPoolEvent = &MiTempEvent; 2085 2086 // 2087 // Default throttling limits for Cc 2088 // May be ajusted later on depending on system type 2089 // 2090 MmThrottleTop = 450; 2091 MmThrottleBottom = 127; 2092 2093 // 2094 // Define the basic user vs. kernel address space separation 2095 // 2096 MmSystemRangeStart = (PVOID)MI_DEFAULT_SYSTEM_RANGE_START; 2097 MmUserProbeAddress = (ULONG_PTR)MI_USER_PROBE_ADDRESS; 2098 MmHighestUserAddress = (PVOID)MI_HIGHEST_USER_ADDRESS; 2099 2100 /* Highest PTE and PDE based on the addresses above */ 2101 MiHighestUserPte = MiAddressToPte(MmHighestUserAddress); 2102 MiHighestUserPde = MiAddressToPde(MmHighestUserAddress); 2103 #if (_MI_PAGING_LEVELS >= 3) 2104 MiHighestUserPpe = MiAddressToPpe(MmHighestUserAddress); 2105 #if (_MI_PAGING_LEVELS >= 4) 2106 MiHighestUserPxe = MiAddressToPxe(MmHighestUserAddress); 2107 #endif 2108 #endif 2109 // 2110 // Get the size of the boot loader's image allocations and then round 2111 // that region up to a PDE size, so that any PDEs we might create for 2112 // whatever follows are separate from the PDEs that boot loader might've 2113 // already created (and later, we can blow all that away if we want to). 2114 // 2115 MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned; 2116 MmBootImageSize *= PAGE_SIZE; 2117 MmBootImageSize = (MmBootImageSize + PDE_MAPPED_VA - 1) & ~(PDE_MAPPED_VA - 1); 2118 ASSERT((MmBootImageSize % PDE_MAPPED_VA) == 0); 2119 2120 /* Initialize session space address layout */ 2121 MiInitializeSessionSpaceLayout(); 2122 2123 /* Set the based section highest address */ 2124 MmHighSectionBase = (PVOID)((ULONG_PTR)MmHighestUserAddress - 0x800000); 2125 2126 #if DBG 2127 /* The subection PTE format depends on things being 8-byte aligned */ 2128 ASSERT((sizeof(CONTROL_AREA) % 8) == 0); 2129 ASSERT((sizeof(SUBSECTION) % 8) == 0); 2130 2131 /* Prototype PTEs are assumed to be in paged pool, so check if the math works */ 2132 PointerPte = (PMMPTE)MmPagedPoolStart; 2133 MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte); 2134 TestPte = MiProtoPteToPte(&TempPte); 2135 ASSERT(PointerPte == TestPte); 2136 2137 /* Try the last nonpaged pool address */ 2138 PointerPte = (PMMPTE)MI_NONPAGED_POOL_END; 2139 MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte); 2140 TestPte = MiProtoPteToPte(&TempPte); 2141 ASSERT(PointerPte == TestPte); 2142 2143 /* Try a bunch of random addresses near the end of the address space */ 2144 PointerPte = (PMMPTE)((ULONG_PTR)MI_HIGHEST_SYSTEM_ADDRESS - 0x37FFF); 2145 for (j = 0; j < 20; j += 1) 2146 { 2147 MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte); 2148 TestPte = MiProtoPteToPte(&TempPte); 2149 ASSERT(PointerPte == TestPte); 2150 PointerPte++; 2151 } 2152 2153 /* Subsection PTEs are always in nonpaged pool, pick a random address to try */ 2154 PointerPte = (PMMPTE)((ULONG_PTR)MmNonPagedPoolStart + (MmSizeOfNonPagedPoolInBytes / 2)); 2155 MI_MAKE_SUBSECTION_PTE(&TempPte, PointerPte); 2156 TestPte = MiSubsectionPteToSubsection(&TempPte); 2157 ASSERT(PointerPte == TestPte); 2158 #endif 2159 2160 /* Loop all 8 standby lists */ 2161 for (i = 0; i < 8; i++) 2162 { 2163 /* Initialize them */ 2164 MmStandbyPageListByPriority[i].Total = 0; 2165 MmStandbyPageListByPriority[i].ListName = StandbyPageList; 2166 MmStandbyPageListByPriority[i].Flink = MM_EMPTY_LIST; 2167 MmStandbyPageListByPriority[i].Blink = MM_EMPTY_LIST; 2168 } 2169 2170 /* Initialize the user mode image list */ 2171 InitializeListHead(&MmLoadedUserImageList); 2172 2173 /* Initialize critical section timeout value (relative time is negative) */ 2174 MmCriticalSectionTimeout.QuadPart = MmCritsectTimeoutSeconds * (-10000000LL); 2175 2176 /* Initialize the paged pool mutex and the section commit mutex */ 2177 KeInitializeGuardedMutex(&MmPagedPoolMutex); 2178 KeInitializeGuardedMutex(&MmSectionCommitMutex); 2179 KeInitializeGuardedMutex(&MmSectionBasedMutex); 2180 2181 /* Initialize the Loader Lock */ 2182 KeInitializeMutant(&MmSystemLoadLock, FALSE); 2183 2184 /* Set the zero page event */ 2185 KeInitializeEvent(&MmZeroingPageEvent, SynchronizationEvent, FALSE); 2186 MmZeroingPageThreadActive = FALSE; 2187 2188 /* Initialize the dead stack S-LIST */ 2189 InitializeSListHead(&MmDeadStackSListHead); 2190 2191 // 2192 // Check if this is a machine with less than 19MB of RAM 2193 // 2194 PageCount = MmNumberOfPhysicalPages; 2195 if (PageCount < MI_MIN_PAGES_FOR_SYSPTE_TUNING) 2196 { 2197 // 2198 // Use the very minimum of system PTEs 2199 // 2200 MmNumberOfSystemPtes = 7000; 2201 } 2202 else 2203 { 2204 // 2205 // Use the default 2206 // 2207 MmNumberOfSystemPtes = 11000; 2208 if (PageCount > MI_MIN_PAGES_FOR_SYSPTE_BOOST) 2209 { 2210 // 2211 // Double the amount of system PTEs 2212 // 2213 MmNumberOfSystemPtes <<= 1; 2214 } 2215 if (PageCount > MI_MIN_PAGES_FOR_SYSPTE_BOOST_BOOST) 2216 { 2217 // 2218 // Double the amount of system PTEs 2219 // 2220 MmNumberOfSystemPtes <<= 1; 2221 } 2222 if (MmSpecialPoolTag != 0 && MmSpecialPoolTag != -1) 2223 { 2224 // 2225 // Add some extra PTEs for special pool 2226 // 2227 MmNumberOfSystemPtes += 0x6000; 2228 } 2229 } 2230 2231 DPRINT("System PTE count has been tuned to %lu (%lu bytes)\n", 2232 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE); 2233 2234 /* Check if no values are set for the heap limits */ 2235 if (MmHeapSegmentReserve == 0) 2236 { 2237 MmHeapSegmentReserve = 2 * _1MB; 2238 } 2239 2240 if (MmHeapSegmentCommit == 0) 2241 { 2242 MmHeapSegmentCommit = 2 * PAGE_SIZE; 2243 } 2244 2245 if (MmHeapDeCommitTotalFreeThreshold == 0) 2246 { 2247 MmHeapDeCommitTotalFreeThreshold = 64 * _1KB; 2248 } 2249 2250 if (MmHeapDeCommitFreeBlockThreshold == 0) 2251 { 2252 MmHeapDeCommitFreeBlockThreshold = PAGE_SIZE; 2253 } 2254 2255 /* Initialize the working set lock */ 2256 ExInitializePushLock(&MmSystemCacheWs.WorkingSetMutex); 2257 2258 /* Set commit limit */ 2259 MmTotalCommitLimit = (2 * _1GB) >> PAGE_SHIFT; 2260 MmTotalCommitLimitMaximum = MmTotalCommitLimit; 2261 2262 /* Has the allocation fragment been setup? */ 2263 if (!MmAllocationFragment) 2264 { 2265 /* Use the default value */ 2266 MmAllocationFragment = MI_ALLOCATION_FRAGMENT; 2267 if (PageCount < ((256 * _1MB) / PAGE_SIZE)) 2268 { 2269 /* On memory systems with less than 256MB, divide by 4 */ 2270 MmAllocationFragment = MI_ALLOCATION_FRAGMENT / 4; 2271 } 2272 else if (PageCount < (_1GB / PAGE_SIZE)) 2273 { 2274 /* On systems with less than 1GB, divide by 2 */ 2275 MmAllocationFragment = MI_ALLOCATION_FRAGMENT / 2; 2276 } 2277 } 2278 else 2279 { 2280 /* Convert from 1KB fragments to pages */ 2281 MmAllocationFragment *= _1KB; 2282 MmAllocationFragment = ROUND_TO_PAGES(MmAllocationFragment); 2283 2284 /* Don't let it past the maximum */ 2285 MmAllocationFragment = min(MmAllocationFragment, 2286 MI_MAX_ALLOCATION_FRAGMENT); 2287 2288 /* Don't let it too small either */ 2289 MmAllocationFragment = max(MmAllocationFragment, 2290 MI_MIN_ALLOCATION_FRAGMENT); 2291 } 2292 2293 /* Check for kernel stack size that's too big */ 2294 if (MmLargeStackSize > (KERNEL_LARGE_STACK_SIZE / _1KB)) 2295 { 2296 /* Sanitize to default value */ 2297 MmLargeStackSize = KERNEL_LARGE_STACK_SIZE; 2298 } 2299 else 2300 { 2301 /* Take the registry setting, and convert it into bytes */ 2302 MmLargeStackSize *= _1KB; 2303 2304 /* Now align it to a page boundary */ 2305 MmLargeStackSize = PAGE_ROUND_UP(MmLargeStackSize); 2306 2307 /* Sanity checks */ 2308 ASSERT(MmLargeStackSize <= KERNEL_LARGE_STACK_SIZE); 2309 ASSERT((MmLargeStackSize & (PAGE_SIZE - 1)) == 0); 2310 2311 /* Make sure it's not too low */ 2312 if (MmLargeStackSize < KERNEL_STACK_SIZE) MmLargeStackSize = KERNEL_STACK_SIZE; 2313 } 2314 2315 /* Compute color information (L2 cache-separated paging lists) */ 2316 MiComputeColorInformation(); 2317 2318 // Calculate the number of bytes for the PFN database 2319 // then add the color tables and convert to pages 2320 MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN); 2321 MxPfnAllocation += (MmSecondaryColors * sizeof(MMCOLOR_TABLES) * 2); 2322 MxPfnAllocation >>= PAGE_SHIFT; 2323 2324 // We have to add one to the count here, because in the process of 2325 // shifting down to the page size, we actually ended up getting the 2326 // lower aligned size (so say, 0x5FFFF bytes is now 0x5F pages). 2327 // Later on, we'll shift this number back into bytes, which would cause 2328 // us to end up with only 0x5F000 bytes -- when we actually want to have 2329 // 0x60000 bytes. 2330 MxPfnAllocation++; 2331 2332 /* Initialize the platform-specific parts */ 2333 MiInitMachineDependent(LoaderBlock); 2334 2335 // 2336 // Build the physical memory block 2337 // 2338 MmPhysicalMemoryBlock = MmInitializeMemoryLimits(LoaderBlock, 2339 IncludeType); 2340 2341 // 2342 // Allocate enough buffer for the PFN bitmap 2343 // Align it up to a 32-bit boundary 2344 // 2345 Bitmap = ExAllocatePoolWithTag(NonPagedPool, 2346 (((MmHighestPhysicalPage + 1) + 31) / 32) * 4, 2347 TAG_MM); 2348 if (!Bitmap) 2349 { 2350 // 2351 // This is critical 2352 // 2353 KeBugCheckEx(INSTALL_MORE_MEMORY, 2354 MmNumberOfPhysicalPages, 2355 MmLowestPhysicalPage, 2356 MmHighestPhysicalPage, 2357 0x101); 2358 } 2359 2360 // 2361 // Initialize it and clear all the bits to begin with 2362 // 2363 RtlInitializeBitMap(&MiPfnBitMap, 2364 Bitmap, 2365 (ULONG)MmHighestPhysicalPage + 1); 2366 RtlClearAllBits(&MiPfnBitMap); 2367 2368 // 2369 // Loop physical memory runs 2370 // 2371 for (i = 0; i < MmPhysicalMemoryBlock->NumberOfRuns; i++) 2372 { 2373 // 2374 // Get the run 2375 // 2376 Run = &MmPhysicalMemoryBlock->Run[i]; 2377 DPRINT("PHYSICAL RAM [0x%08p to 0x%08p]\n", 2378 Run->BasePage << PAGE_SHIFT, 2379 (Run->BasePage + Run->PageCount) << PAGE_SHIFT); 2380 2381 // 2382 // Make sure it has pages inside it 2383 // 2384 if (Run->PageCount) 2385 { 2386 // 2387 // Set the bits in the PFN bitmap 2388 // 2389 RtlSetBits(&MiPfnBitMap, (ULONG)Run->BasePage, (ULONG)Run->PageCount); 2390 } 2391 } 2392 2393 /* Look for large page cache entries that need caching */ 2394 MiSyncCachedRanges(); 2395 2396 /* Loop for HAL Heap I/O device mappings that need coherency tracking */ 2397 MiAddHalIoMappings(); 2398 2399 /* Set the initial resident page count */ 2400 MmResidentAvailablePages = MmAvailablePages - 32; 2401 2402 /* Initialize large page structures on PAE/x64, and MmProcessList on x86 */ 2403 MiInitializeLargePageSupport(); 2404 2405 /* Check if the registry says any drivers should be loaded with large pages */ 2406 MiInitializeDriverLargePageList(); 2407 2408 /* Relocate the boot drivers into system PTE space and fixup their PFNs */ 2409 MiReloadBootLoadedDrivers(LoaderBlock); 2410 2411 /* FIXME: Call out into Driver Verifier for initialization */ 2412 2413 /* Check how many pages the system has */ 2414 if (MmNumberOfPhysicalPages <= ((13 * _1MB) / PAGE_SIZE)) 2415 { 2416 /* Set small system */ 2417 MmSystemSize = MmSmallSystem; 2418 MmMaximumDeadKernelStacks = 0; 2419 } 2420 else if (MmNumberOfPhysicalPages <= ((19 * _1MB) / PAGE_SIZE)) 2421 { 2422 /* Set small system and add 100 pages for the cache */ 2423 MmSystemSize = MmSmallSystem; 2424 MmSystemCacheWsMinimum += 100; 2425 MmMaximumDeadKernelStacks = 2; 2426 } 2427 else 2428 { 2429 /* Set medium system and add 400 pages for the cache */ 2430 MmSystemSize = MmMediumSystem; 2431 MmSystemCacheWsMinimum += 400; 2432 MmMaximumDeadKernelStacks = 5; 2433 } 2434 2435 /* Check for less than 24MB */ 2436 if (MmNumberOfPhysicalPages < ((24 * _1MB) / PAGE_SIZE)) 2437 { 2438 /* No more than 32 pages */ 2439 MmSystemCacheWsMinimum = 32; 2440 } 2441 2442 /* Check for more than 32MB */ 2443 if (MmNumberOfPhysicalPages >= ((32 * _1MB) / PAGE_SIZE)) 2444 { 2445 /* Check for product type being "Wi" for WinNT */ 2446 if (MmProductType == '\0i\0W') 2447 { 2448 /* Then this is a large system */ 2449 MmSystemSize = MmLargeSystem; 2450 } 2451 else 2452 { 2453 /* For servers, we need 64MB to consider this as being large */ 2454 if (MmNumberOfPhysicalPages >= ((64 * _1MB) / PAGE_SIZE)) 2455 { 2456 /* Set it as large */ 2457 MmSystemSize = MmLargeSystem; 2458 } 2459 } 2460 } 2461 2462 /* Check for more than 33 MB */ 2463 if (MmNumberOfPhysicalPages > ((33 * _1MB) / PAGE_SIZE)) 2464 { 2465 /* Add another 500 pages to the cache */ 2466 MmSystemCacheWsMinimum += 500; 2467 } 2468 2469 /* Now setup the shared user data fields */ 2470 ASSERT(SharedUserData->NumberOfPhysicalPages == 0); 2471 SharedUserData->NumberOfPhysicalPages = MmNumberOfPhysicalPages; 2472 SharedUserData->LargePageMinimum = 0; 2473 2474 /* Check for workstation (Wi for WinNT) */ 2475 if (MmProductType == '\0i\0W') 2476 { 2477 /* Set Windows NT Workstation product type */ 2478 SharedUserData->NtProductType = NtProductWinNt; 2479 MmProductType = 0; 2480 2481 /* For this product, we wait till the last moment to throttle */ 2482 MmThrottleTop = 250; 2483 MmThrottleBottom = 30; 2484 } 2485 else 2486 { 2487 /* Check for LanMan server (La for LanmanNT) */ 2488 if (MmProductType == '\0a\0L') 2489 { 2490 /* This is a domain controller */ 2491 SharedUserData->NtProductType = NtProductLanManNt; 2492 } 2493 else 2494 { 2495 /* Otherwise it must be a normal server (Se for ServerNT) */ 2496 SharedUserData->NtProductType = NtProductServer; 2497 } 2498 2499 /* Set the product type, and make the system more aggressive with low memory */ 2500 MmProductType = 1; 2501 MmMinimumFreePages = 81; 2502 2503 /* We will throttle earlier to preserve memory */ 2504 MmThrottleTop = 450; 2505 MmThrottleBottom = 80; 2506 } 2507 2508 /* Update working set tuning parameters */ 2509 MiAdjustWorkingSetManagerParameters(!MmProductType); 2510 2511 /* Finetune the page count by removing working set and NP expansion */ 2512 MmResidentAvailablePages -= MiExpansionPoolPagesInitialCharge; 2513 MmResidentAvailablePages -= MmSystemCacheWsMinimum; 2514 MmResidentAvailableAtInit = MmResidentAvailablePages; 2515 if (MmResidentAvailablePages <= 0) 2516 { 2517 /* This should not happen */ 2518 DPRINT1("System cache working set too big\n"); 2519 return FALSE; 2520 } 2521 2522 /* Define limits for system cache */ 2523 #ifdef _M_AMD64 2524 MmSizeOfSystemCacheInPages = (MI_SYSTEM_CACHE_END - MI_SYSTEM_CACHE_START) / PAGE_SIZE; 2525 #else 2526 MmSizeOfSystemCacheInPages = ((ULONG_PTR)MI_PAGED_POOL_START - (ULONG_PTR)MI_SYSTEM_CACHE_START) / PAGE_SIZE; 2527 #endif 2528 MmSystemCacheEnd = (PVOID)((ULONG_PTR)MmSystemCacheStart + (MmSizeOfSystemCacheInPages * PAGE_SIZE) - 1); 2529 2530 /* Initialize the system cache */ 2531 //MiInitializeSystemCache(MmSystemCacheWsMinimum, MmAvailablePages); 2532 2533 /* Update the commit limit */ 2534 MmTotalCommitLimit = MmAvailablePages; 2535 if (MmTotalCommitLimit > 1024) MmTotalCommitLimit -= 1024; 2536 MmTotalCommitLimitMaximum = MmTotalCommitLimit; 2537 2538 /* Size up paged pool and build the shadow system page directory */ 2539 MiBuildPagedPool(); 2540 2541 /* Debugger physical memory support is now ready to be used */ 2542 MmDebugPte = MiAddressToPte(MiDebugMapping); 2543 2544 /* Initialize the loaded module list */ 2545 MiInitializeLoadedModuleList(LoaderBlock); 2546 } 2547 2548 // 2549 // Always return success for now 2550 // 2551 return TRUE; 2552 } 2553 2554 /* EOF */ 2555