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