1 /* 2 * COPYRIGHT: GPL, See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/mm/amd64/init.c 5 * PURPOSE: Memory Manager Initialization for amd64 6 * 7 * PROGRAMMERS: Timo kreuzer (timo.kreuzer@reactos.org) 8 * ReactOS Portable Systems Group 9 */ 10 11 /* INCLUDES ***************************************************************/ 12 13 #include <ntoskrnl.h> 14 //#define NDEBUG 15 #include <debug.h> 16 17 #include <mm/ARM3/miarm.h> 18 19 extern PMMPTE MmDebugPte; 20 21 /* Helper macros */ 22 #define IS_ALIGNED(addr, align) (((ULONG64)(addr) & (align - 1)) == 0) 23 #define IS_PAGE_ALIGNED(addr) IS_ALIGNED(addr, PAGE_SIZE) 24 25 /* GLOBALS *****************************************************************/ 26 27 /* Template PTE and PDE for a kernel page */ 28 MMPTE ValidKernelPde = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}}; 29 MMPTE ValidKernelPte = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}}; 30 31 /* The same, but for local pages */ 32 MMPTE ValidKernelPdeLocal = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}}; 33 MMPTE ValidKernelPteLocal = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}}; 34 35 /* Template PDE for a demand-zero page */ 36 MMPDE DemandZeroPde = {{MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS}}; 37 MMPTE DemandZeroPte = {{MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS}}; 38 39 /* Template PTE for prototype page */ 40 MMPTE PrototypePte = {{(MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) | 41 PTE_PROTOTYPE | (MI_PTE_LOOKUP_NEEDED << 32)}}; 42 43 /* Template PTE for decommited page */ 44 MMPTE MmDecommittedPte = {{MM_DECOMMIT << MM_PTE_SOFTWARE_PROTECTION_BITS}}; 45 46 /* Address ranges */ 47 PVOID MiSessionViewEnd; 48 PVOID MiSystemPteSpaceStart; 49 PVOID MiSystemPteSpaceEnd; 50 51 ULONG64 MxPfnSizeInBytes; 52 BOOLEAN MiIncludeType[LoaderMaximum]; 53 PFN_NUMBER MxFreePageBase; 54 ULONG64 MxFreePageCount = 0; 55 56 BOOLEAN MiPfnsInitialized = FALSE; 57 58 /* FUNCTIONS *****************************************************************/ 59 60 INIT_FUNCTION 61 VOID 62 NTAPI 63 MiInitializeSessionSpaceLayout(VOID) 64 { 65 MmSessionSize = MI_SESSION_SIZE; 66 MmSessionViewSize = MI_SESSION_VIEW_SIZE; 67 MmSessionPoolSize = MI_SESSION_POOL_SIZE; 68 MmSessionImageSize = MI_SESSION_IMAGE_SIZE; 69 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE; 70 71 /* Set up session space */ 72 MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END; 73 74 /* This is where we will load Win32k.sys and the video driver */ 75 MiSessionImageEnd = MiSessionSpaceEnd; 76 MiSessionImageStart = (PCHAR)MiSessionImageEnd - MmSessionImageSize; 77 78 /* The view starts right below the session working set (itself below 79 * the image area) */ 80 MiSessionViewEnd = (PVOID)MI_SESSION_VIEW_END; 81 MiSessionViewStart = (PCHAR)MiSessionViewEnd - MmSessionViewSize; 82 ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart)); 83 84 /* Session pool follows */ 85 MiSessionPoolEnd = MiSessionViewStart; 86 MiSessionPoolStart = (PCHAR)MiSessionPoolEnd - MmSessionPoolSize; 87 ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart)); 88 89 /* And it all begins here */ 90 MmSessionBase = MiSessionPoolStart; 91 92 /* System view space ends at session space, so now that we know where 93 * this is, we can compute the base address of system view space itself. */ 94 MiSystemViewStart = (PCHAR)MmSessionBase - MmSystemViewSize; 95 ASSERT(IS_PAGE_ALIGNED(MiSystemViewStart)); 96 97 /* Sanity checks */ 98 ASSERT(MiSessionViewEnd <= MiSessionImageStart); 99 ASSERT(MmSessionBase <= MiSessionPoolStart); 100 } 101 102 VOID 103 NTAPI 104 MiMapPPEs( 105 PVOID StartAddress, 106 PVOID EndAddress) 107 { 108 PMMPDE PointerPpe; 109 MMPDE TmplPde = ValidKernelPde; 110 111 /* Loop the PPEs */ 112 for (PointerPpe = MiAddressToPpe(StartAddress); 113 PointerPpe <= MiAddressToPpe(EndAddress); 114 PointerPpe++) 115 { 116 /* Check if its already mapped */ 117 if (!PointerPpe->u.Hard.Valid) 118 { 119 /* No, map it! */ 120 TmplPde.u.Hard.PageFrameNumber = MxGetNextPage(1); 121 MI_WRITE_VALID_PTE(PointerPpe, TmplPde); 122 123 /* Zero out the page table */ 124 RtlZeroMemory(MiPteToAddress(PointerPpe), PAGE_SIZE); 125 } 126 } 127 } 128 129 VOID 130 NTAPI 131 MiMapPDEs( 132 PVOID StartAddress, 133 PVOID EndAddress) 134 { 135 PMMPDE PointerPde; 136 MMPDE TmplPde = ValidKernelPde; 137 138 /* Loop the PDEs */ 139 for (PointerPde = MiAddressToPde(StartAddress); 140 PointerPde <= MiAddressToPde(EndAddress); 141 PointerPde++) 142 { 143 /* Check if its already mapped */ 144 if (!PointerPde->u.Hard.Valid) 145 { 146 /* No, map it! */ 147 TmplPde.u.Hard.PageFrameNumber = MxGetNextPage(1); 148 MI_WRITE_VALID_PTE(PointerPde, TmplPde); 149 150 /* Zero out the page table */ 151 RtlZeroMemory(MiPteToAddress(PointerPde), PAGE_SIZE); 152 } 153 } 154 } 155 156 VOID 157 NTAPI 158 MiMapPTEs( 159 PVOID StartAddress, 160 PVOID EndAddress) 161 { 162 PMMPTE PointerPte; 163 MMPTE TmplPte = ValidKernelPte; 164 165 /* Loop the PTEs */ 166 for (PointerPte = MiAddressToPte(StartAddress); 167 PointerPte <= MiAddressToPte(EndAddress); 168 PointerPte++) 169 { 170 /* Check if its already mapped */ 171 if (!PointerPte->u.Hard.Valid) 172 { 173 /* No, map it! */ 174 TmplPte.u.Hard.PageFrameNumber = MxGetNextPage(1); 175 MI_WRITE_VALID_PTE(PointerPte, TmplPte); 176 177 /* Zero out the page (FIXME: not always neccessary) */ 178 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE); 179 } 180 } 181 } 182 183 INIT_FUNCTION 184 VOID 185 NTAPI 186 MiInitializePageTable(VOID) 187 { 188 ULONG64 PxePhysicalAddress; 189 MMPTE TmplPte, *PointerPxe; 190 PFN_NUMBER PxePfn; 191 192 /* Get current directory base */ 193 PxePfn = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber; 194 PxePhysicalAddress = PxePfn << PAGE_SHIFT; 195 ASSERT(PxePhysicalAddress == __readcr3()); 196 197 /* Set directory base for the system process */ 198 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PxePhysicalAddress; 199 200 /* Enable global pages */ 201 __writecr4(__readcr4() | CR4_PGE); 202 ASSERT(__readcr4() & CR4_PGE); 203 204 /* Loop the user mode PXEs */ 205 for (PointerPxe = MiAddressToPxe(0); 206 PointerPxe <= MiAddressToPxe(MmHighestUserAddress); 207 PointerPxe++) 208 { 209 /* Zero the PXE, clear all mappings */ 210 PointerPxe->u.Long = 0; 211 } 212 213 /* Flush the TLB */ 214 KeFlushCurrentTb(); 215 216 /* Set up a template PTE */ 217 TmplPte.u.Long = 0; 218 TmplPte.u.Flush.Valid = 1; 219 TmplPte.u.Flush.Write = 1; 220 HyperTemplatePte = TmplPte; 221 222 /* Create PDPTs (72 KB) for shared system address space, 223 * skip page tables TODO: use global pages. */ 224 225 /* Loop the PXEs */ 226 for (PointerPxe = MiAddressToPxe((PVOID)HYPER_SPACE); 227 PointerPxe <= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS); 228 PointerPxe++) 229 { 230 /* Is the PXE already valid? */ 231 if (!PointerPxe->u.Hard.Valid) 232 { 233 /* It's not Initialize it */ 234 TmplPte.u.Flush.PageFrameNumber = MxGetNextPage(1); 235 *PointerPxe = TmplPte; 236 237 /* Zero the page. The PXE is the PTE for the PDPT. */ 238 RtlZeroMemory(MiPteToAddress(PointerPxe), PAGE_SIZE); 239 } 240 } 241 242 /* Map PPEs for paged pool */ 243 MiMapPPEs(MmPagedPoolStart, MmPagedPoolEnd); 244 245 /* Setup 1 PPE for hyper space */ 246 MiMapPPEs((PVOID)HYPER_SPACE, (PVOID)HYPER_SPACE_END); 247 248 /* Setup PPEs for system space view */ 249 MiMapPPEs(MiSystemViewStart, (PCHAR)MiSystemViewStart + MmSystemViewSize); 250 251 /* Setup the mapping PDEs */ 252 MiMapPDEs((PVOID)MI_MAPPING_RANGE_START, (PVOID)MI_MAPPING_RANGE_END); 253 254 /* Setup the mapping PTEs */ 255 MmFirstReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_START); 256 MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END); 257 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES; 258 259 /* Setup debug mapping PTE */ 260 MiMapPPEs((PVOID)MI_DEBUG_MAPPING, (PVOID)MI_DEBUG_MAPPING); 261 MiMapPDEs((PVOID)MI_DEBUG_MAPPING, (PVOID)MI_DEBUG_MAPPING); 262 MmDebugPte = MiAddressToPte((PVOID)MI_DEBUG_MAPPING); 263 264 /* Setup PDE and PTEs for VAD bitmap and working set list */ 265 MiMapPDEs((PVOID)MI_VAD_BITMAP, (PVOID)(MI_WORKING_SET_LIST + PAGE_SIZE - 1)); 266 MiMapPTEs((PVOID)MI_VAD_BITMAP, (PVOID)(MI_WORKING_SET_LIST + PAGE_SIZE - 1)); 267 } 268 269 INIT_FUNCTION 270 VOID 271 NTAPI 272 MiBuildNonPagedPool(VOID) 273 { 274 /* Check if this is a machine with less than 256MB of RAM, and no overide */ 275 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) && 276 !(MmSizeOfNonPagedPoolInBytes)) 277 { 278 /* Force the non paged pool to be 2MB so we can reduce RAM usage */ 279 MmSizeOfNonPagedPoolInBytes = 2 * 1024 * 1024; 280 } 281 282 /* Check if the user gave a ridicuously large nonpaged pool RAM size */ 283 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) > 284 (MmNumberOfPhysicalPages * 7 / 8)) 285 { 286 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */ 287 MmSizeOfNonPagedPoolInBytes = 0; 288 } 289 290 /* Check if no registry setting was set, or if the setting was too low */ 291 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize) 292 { 293 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */ 294 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize; 295 MmSizeOfNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) / 296 256 * MmMinAdditionNonPagedPoolPerMb; 297 } 298 299 /* Check if the registy setting or our dynamic calculation was too high */ 300 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE) 301 { 302 /* Set it to the maximum */ 303 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE; 304 } 305 306 /* Check if a percentage cap was set through the registry */ 307 if (MmMaximumNonPagedPoolPercent) 308 { 309 /* Don't feel like supporting this right now */ 310 UNIMPLEMENTED; 311 } 312 313 /* Page-align the nonpaged pool size */ 314 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1); 315 316 /* Now, check if there was a registry size for the maximum size */ 317 if (!MmMaximumNonPagedPoolInBytes) 318 { 319 /* Start with the default (1MB) and add 400 KB for each MB above 4 */ 320 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool; 321 MmMaximumNonPagedPoolInBytes += (MmNumberOfPhysicalPages - 1024) / 322 256 * MmMaxAdditionNonPagedPoolPerMb; 323 } 324 325 /* Don't let the maximum go too high */ 326 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE) 327 { 328 /* Set it to the upper limit */ 329 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE; 330 } 331 332 /* Convert nonpaged pool size from bytes to pages */ 333 MmMaximumNonPagedPoolInPages = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT; 334 335 /* Non paged pool starts after the PFN database */ 336 MmNonPagedPoolStart = MmPfnDatabase + MxPfnAllocation * PAGE_SIZE; 337 338 /* Calculate the nonpaged pool expansion start region */ 339 MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart + 340 MmSizeOfNonPagedPoolInBytes; 341 ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart)); 342 343 /* And this is where the none paged pool ends */ 344 MmNonPagedPoolEnd = (PCHAR)MmNonPagedPoolStart + MmMaximumNonPagedPoolInBytes; 345 ASSERT(MmNonPagedPoolEnd < (PVOID)MM_HAL_VA_START); 346 347 /* Map PPEs and PDEs for non paged pool (including expansion) */ 348 MiMapPPEs(MmNonPagedPoolStart, MmNonPagedPoolEnd); 349 MiMapPDEs(MmNonPagedPoolStart, MmNonPagedPoolEnd); 350 351 /* Map the nonpaged pool PTEs (without expansion) */ 352 MiMapPTEs(MmNonPagedPoolStart, (PCHAR)MmNonPagedPoolExpansionStart - 1); 353 354 /* Initialize the ARM3 nonpaged pool */ 355 MiInitializeNonPagedPool(); 356 MiInitializeNonPagedPoolThresholds(); 357 358 } 359 360 INIT_FUNCTION 361 VOID 362 NTAPI 363 MiBuildSystemPteSpace(VOID) 364 { 365 PMMPTE PointerPte; 366 SIZE_T NonPagedSystemSize; 367 368 /* Use the default number of system PTEs */ 369 MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES; 370 NonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE; 371 372 /* Put system PTEs at the start of the system VA space */ 373 MiSystemPteSpaceStart = MmNonPagedSystemStart; 374 MiSystemPteSpaceEnd = (PUCHAR)MiSystemPteSpaceStart + NonPagedSystemSize; 375 376 /* Map the PPEs and PDEs for the system PTEs */ 377 MiMapPPEs(MiSystemPteSpaceStart, MiSystemPteSpaceEnd); 378 MiMapPDEs(MiSystemPteSpaceStart, MiSystemPteSpaceEnd); 379 380 /* Initialize the system PTE space */ 381 PointerPte = MiAddressToPte(MiSystemPteSpaceStart); 382 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace); 383 384 /* Reserve system PTEs for zeroing PTEs and clear them */ 385 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES + 1, 386 SystemPteSpace); 387 RtlZeroMemory(MiFirstReservedZeroingPte, (MI_ZERO_PTES + 1) * sizeof(MMPTE)); 388 389 /* Set the counter to maximum */ 390 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES; 391 } 392 393 static 394 VOID 395 MiSetupPfnForPageTable( 396 PFN_NUMBER PageFrameIndex, 397 PMMPTE PointerPte) 398 { 399 PMMPFN Pfn; 400 PMMPDE PointerPde; 401 402 /* Get the pfn entry for this page */ 403 Pfn = MiGetPfnEntry(PageFrameIndex); 404 405 /* Check if it's valid memory */ 406 if ((PageFrameIndex <= MmHighestPhysicalPage) && 407 (MmIsAddressValid(Pfn)) && 408 (Pfn->u3.e1.PageLocation == ActiveAndValid)) 409 { 410 /* Setup the PFN entry */ 411 Pfn->u1.WsIndex = 0; 412 Pfn->u2.ShareCount++; 413 Pfn->PteAddress = PointerPte; 414 Pfn->OriginalPte = *PointerPte; 415 Pfn->u3.e1.PageLocation = ActiveAndValid; 416 Pfn->u3.e1.CacheAttribute = MiNonCached; 417 Pfn->u3.e2.ReferenceCount = 1; 418 Pfn->u4.PteFrame = PFN_FROM_PTE(MiAddressToPte(PointerPte)); 419 } 420 421 /* Increase the shared count of the PFN entry for the PDE */ 422 PointerPde = MiAddressToPde(MiPteToAddress(PointerPte)); 423 Pfn = MiGetPfnEntry(PFN_FROM_PTE(PointerPde)); 424 Pfn->u2.ShareCount++; 425 } 426 427 VOID 428 NTAPI 429 MiBuildPfnDatabaseFromPageTables(VOID) 430 { 431 PVOID Address = NULL; 432 PFN_NUMBER PageFrameIndex; 433 PMMPDE PointerPde; 434 PMMPTE PointerPte; 435 ULONG k, l; 436 PMMPFN Pfn; 437 #if (_MI_PAGING_LEVELS >= 3) 438 PMMPDE PointerPpe; 439 ULONG j; 440 #endif 441 #if (_MI_PAGING_LEVELS == 4) 442 PMMPDE PointerPxe; 443 ULONG i; 444 #endif 445 446 /* Manual setup of the top level page directory */ 447 #if (_MI_PAGING_LEVELS == 4) 448 PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PXE_BASE)); 449 #elif (_MI_PAGING_LEVELS == 3) 450 PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PPE_BASE)); 451 #else 452 PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(PDE_BASE)); 453 #endif 454 Pfn = MiGetPfnEntry(PageFrameIndex); 455 ASSERT(Pfn->u3.e1.PageLocation == ActiveAndValid); 456 Pfn->u1.WsIndex = 0; 457 Pfn->u2.ShareCount = 1; 458 Pfn->PteAddress = NULL; 459 Pfn->u3.e1.CacheAttribute = MiNonCached; 460 Pfn->u3.e2.ReferenceCount = 1; 461 Pfn->u4.PteFrame = 0; 462 463 #if (_MI_PAGING_LEVELS == 4) 464 /* Loop all PXEs in the PML4 */ 465 PointerPxe = MiAddressToPxe(Address); 466 for (i = 0; i < PXE_PER_PAGE; i++, PointerPxe++) 467 { 468 /* Skip invalid PXEs */ 469 if (!PointerPxe->u.Hard.Valid) continue; 470 471 /* Handle the PFN */ 472 PageFrameIndex = PFN_FROM_PXE(PointerPxe); 473 MiSetupPfnForPageTable(PageFrameIndex, PointerPxe); 474 475 /* Get starting VA for this PXE */ 476 Address = MiPxeToAddress(PointerPxe); 477 #endif 478 #if (_MI_PAGING_LEVELS >= 3) 479 /* Loop all PPEs in this PDP */ 480 PointerPpe = MiAddressToPpe(Address); 481 for (j = 0; j < PPE_PER_PAGE; j++, PointerPpe++) 482 { 483 /* Skip invalid PPEs */ 484 if (!PointerPpe->u.Hard.Valid) continue; 485 486 /* Handle the PFN */ 487 PageFrameIndex = PFN_FROM_PPE(PointerPpe); 488 MiSetupPfnForPageTable(PageFrameIndex, PointerPpe); 489 490 /* Get starting VA for this PPE */ 491 Address = MiPpeToAddress(PointerPpe); 492 #endif 493 /* Loop all PDEs in this PD */ 494 PointerPde = MiAddressToPde(Address); 495 for (k = 0; k < PDE_PER_PAGE; k++, PointerPde++) 496 { 497 /* Skip invalid PDEs */ 498 if (!PointerPde->u.Hard.Valid) continue; 499 500 /* Handle the PFN */ 501 PageFrameIndex = PFN_FROM_PDE(PointerPde); 502 MiSetupPfnForPageTable(PageFrameIndex, PointerPde); 503 504 /* Get starting VA for this PDE */ 505 Address = MiPdeToAddress(PointerPde); 506 507 /* Loop all PTEs in this PT */ 508 PointerPte = MiAddressToPte(Address); 509 for (l = 0; l < PTE_PER_PAGE; l++, PointerPte++) 510 { 511 /* Skip invalid PTEs */ 512 if (!PointerPte->u.Hard.Valid) continue; 513 514 /* Handle the PFN */ 515 PageFrameIndex = PFN_FROM_PTE(PointerPte); 516 MiSetupPfnForPageTable(PageFrameIndex, PointerPte); 517 } 518 } 519 #if (_MI_PAGING_LEVELS >= 3) 520 } 521 #endif 522 #if (_MI_PAGING_LEVELS == 4) 523 } 524 #endif 525 } 526 527 INIT_FUNCTION 528 VOID 529 NTAPI 530 MiAddDescriptorToDatabase( 531 PFN_NUMBER BasePage, 532 PFN_NUMBER PageCount, 533 TYPE_OF_MEMORY MemoryType) 534 { 535 PMMPFN Pfn; 536 KIRQL OldIrql; 537 538 ASSERT(!MiIsMemoryTypeInvisible(MemoryType)); 539 540 /* Check if the memory is free */ 541 if (MiIsMemoryTypeFree(MemoryType)) 542 { 543 /* Get the last pfn of this descriptor. Note we loop backwards */ 544 Pfn = &MmPfnDatabase[BasePage + PageCount - 1]; 545 546 /* Lock the PFN Database */ 547 OldIrql = MiAcquirePfnLock(); 548 549 /* Loop all pages */ 550 while (PageCount--) 551 { 552 /* Add it to the free list */ 553 Pfn->u3.e1.CacheAttribute = MiNonCached; 554 MiInsertPageInFreeList(BasePage + PageCount); 555 556 /* Go to the previous page */ 557 Pfn--; 558 } 559 560 /* Release PFN database */ 561 MiReleasePfnLock(OldIrql); 562 } 563 else if (MemoryType == LoaderXIPRom) 564 { 565 Pfn = &MmPfnDatabase[BasePage]; 566 while (PageCount--) 567 { 568 /* Make it a pseudo-I/O ROM mapping */ 569 Pfn->PteAddress = 0; 570 Pfn->u1.Flink = 0; 571 Pfn->u2.ShareCount = 0; 572 Pfn->u3.e1.PageLocation = 0; 573 Pfn->u3.e1.CacheAttribute = MiNonCached; 574 Pfn->u3.e1.Rom = 1; 575 Pfn->u3.e1.PrototypePte = 1; 576 Pfn->u3.e2.ReferenceCount = 0; 577 Pfn->u4.InPageError = 0; 578 Pfn->u4.PteFrame = 0; 579 580 /* Advance one */ 581 Pfn++; 582 } 583 } 584 else if (MemoryType == LoaderBad) 585 { 586 // FIXME: later 587 ASSERT(FALSE); 588 } 589 else 590 { 591 /* For now skip it */ 592 DbgPrint("Skipping BasePage=0x%lx, PageCount=0x%lx, MemoryType=%lx\n", 593 BasePage, PageCount, MemoryType); 594 Pfn = &MmPfnDatabase[BasePage]; 595 while (PageCount--) 596 { 597 /* Make an active PFN */ 598 Pfn->u3.e1.PageLocation = ActiveAndValid; 599 600 /* Advance one */ 601 Pfn++; 602 } 603 } 604 } 605 606 INIT_FUNCTION 607 VOID 608 NTAPI 609 MiBuildPfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 610 { 611 PLIST_ENTRY ListEntry; 612 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; 613 PFN_NUMBER BasePage, PageCount; 614 615 /* Map the PDEs and PPEs for the pfn database (ignore holes) */ 616 #if (_MI_PAGING_LEVELS >= 3) 617 MiMapPPEs(MmPfnDatabase, (PUCHAR)MmPfnDatabase + (MxPfnAllocation * PAGE_SIZE) - 1); 618 #endif 619 MiMapPDEs(MmPfnDatabase, (PUCHAR)MmPfnDatabase + (MxPfnAllocation * PAGE_SIZE) - 1); 620 621 /* First initialize the color tables */ 622 MiInitializeColorTables(); 623 624 /* Loop the memory descriptors */ 625 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink; 626 ListEntry != &LoaderBlock->MemoryDescriptorListHead; 627 ListEntry = ListEntry->Flink) 628 { 629 /* Get the descriptor */ 630 Descriptor = CONTAINING_RECORD(ListEntry, 631 MEMORY_ALLOCATION_DESCRIPTOR, 632 ListEntry); 633 634 /* Skip invisible memory */ 635 if (MiIsMemoryTypeInvisible(Descriptor->MemoryType)) continue; 636 637 /* If this is the free descriptor, use the copy instead */ 638 if (Descriptor == MxFreeDescriptor) Descriptor = &MxOldFreeDescriptor; 639 640 /* Get the range for this descriptor */ 641 BasePage = Descriptor->BasePage; 642 PageCount = Descriptor->PageCount; 643 644 /* Map the pages for the database */ 645 MiMapPTEs(&MmPfnDatabase[BasePage], 646 (PUCHAR)(&MmPfnDatabase[BasePage + PageCount]) - 1); 647 648 /* If this was the free descriptor, skip the next step */ 649 if (Descriptor == &MxOldFreeDescriptor) continue; 650 651 /* Add this descriptor to the database */ 652 MiAddDescriptorToDatabase(BasePage, PageCount, Descriptor->MemoryType); 653 } 654 655 /* At this point the whole pfn database is mapped. We are about to add the 656 pages from the free descriptor to the database, so from now on we cannot 657 use it anymore. */ 658 659 /* Now add the free descriptor */ 660 BasePage = MxFreeDescriptor->BasePage; 661 PageCount = MxFreeDescriptor->PageCount; 662 MiAddDescriptorToDatabase(BasePage, PageCount, LoaderFree); 663 664 /* And finally the memory we used */ 665 BasePage = MxOldFreeDescriptor.BasePage; 666 PageCount = MxFreeDescriptor->BasePage - BasePage; 667 MiAddDescriptorToDatabase(BasePage, PageCount, LoaderMemoryData); 668 669 /* Reset the descriptor back so we can create the correct memory blocks */ 670 *MxFreeDescriptor = MxOldFreeDescriptor; 671 } 672 673 INIT_FUNCTION 674 NTSTATUS 675 NTAPI 676 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 677 { 678 ASSERT(MxPfnAllocation != 0); 679 680 /* Set some hardcoded addresses */ 681 MmHyperSpaceEnd = (PVOID)HYPER_SPACE_END; 682 MmNonPagedSystemStart = (PVOID)MM_SYSTEM_SPACE_START; 683 MmPfnDatabase = (PVOID)MI_PFN_DATABASE; 684 MmWorkingSetList = (PVOID)MI_WORKING_SET_LIST; 685 686 687 // PrototypePte.u.Proto.Valid = 1 688 // PrototypePte.u.ReadOnly 689 // PrototypePte.u.Prototype 690 // PrototypePte.u.Protection = MM_READWRITE; 691 // PrototypePte.u.ProtoAddress 692 PrototypePte.u.Soft.PageFileHigh = MI_PTE_LOOKUP_NEEDED; 693 694 695 MiInitializePageTable(); 696 697 MiBuildNonPagedPool(); 698 699 MiBuildSystemPteSpace(); 700 701 /* Map the PFN database pages */ 702 MiBuildPfnDatabase(LoaderBlock); 703 704 /* Now process the page tables */ 705 MiBuildPfnDatabaseFromPageTables(); 706 707 /* PFNs are initialized now! */ 708 MiPfnsInitialized = TRUE; 709 710 /* Initialize the nonpaged pool */ 711 InitializePool(NonPagedPool, 0); 712 713 /* Initialize the balancer */ 714 MmInitializeBalancer((ULONG)MmAvailablePages, 0); 715 716 /* Make sure we have everything we need */ 717 ASSERT(MmPfnDatabase); 718 ASSERT(MmNonPagedSystemStart); 719 ASSERT(MmNonPagedPoolStart); 720 ASSERT(MmSizeOfNonPagedPoolInBytes); 721 ASSERT(MmMaximumNonPagedPoolInBytes); 722 ASSERT(MmNonPagedPoolExpansionStart); 723 ASSERT(MmHyperSpaceEnd); 724 ASSERT(MmNumberOfSystemPtes); 725 ASSERT(MiAddressToPde(MmNonPagedPoolStart)->u.Hard.Valid); 726 ASSERT(MiAddressToPte(MmNonPagedPoolStart)->u.Hard.Valid); 727 728 return STATUS_SUCCESS; 729 } 730