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 VOID 61 NTAPI 62 INIT_FUNCTION 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 VOID 184 NTAPI 185 INIT_FUNCTION 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 VOID 270 NTAPI 271 INIT_FUNCTION 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 VOID 361 NTAPI 362 INIT_FUNCTION 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 VOID 528 NTAPI 529 INIT_FUNCTION 530 MiAddDescriptorToDatabase( 531 PFN_NUMBER BasePage, 532 PFN_NUMBER PageCount, 533 TYPE_OF_MEMORY MemoryType) 534 { 535 PMMPFN Pfn; 536 537 ASSERT(!MiIsMemoryTypeInvisible(MemoryType)); 538 539 /* Check if the memory is free */ 540 if (MiIsMemoryTypeFree(MemoryType)) 541 { 542 /* Get the last pfn of this descriptor. Note we loop backwards */ 543 Pfn = &MmPfnDatabase[BasePage + PageCount - 1]; 544 545 /* Loop all pages */ 546 while (PageCount--) 547 { 548 /* Add it to the free list */ 549 Pfn->u3.e1.CacheAttribute = MiNonCached; 550 MiInsertPageInFreeList(BasePage + PageCount); 551 552 /* Go to the previous page */ 553 Pfn--; 554 } 555 } 556 else if (MemoryType == LoaderXIPRom) 557 { 558 Pfn = &MmPfnDatabase[BasePage]; 559 while (PageCount--) 560 { 561 /* Make it a pseudo-I/O ROM mapping */ 562 Pfn->PteAddress = 0; 563 Pfn->u1.Flink = 0; 564 Pfn->u2.ShareCount = 0; 565 Pfn->u3.e1.PageLocation = 0; 566 Pfn->u3.e1.CacheAttribute = MiNonCached; 567 Pfn->u3.e1.Rom = 1; 568 Pfn->u3.e1.PrototypePte = 1; 569 Pfn->u3.e2.ReferenceCount = 0; 570 Pfn->u4.InPageError = 0; 571 Pfn->u4.PteFrame = 0; 572 573 /* Advance one */ 574 Pfn++; 575 } 576 } 577 else if (MemoryType == LoaderBad) 578 { 579 // FIXME: later 580 ASSERT(FALSE); 581 } 582 else 583 { 584 /* For now skip it */ 585 DbgPrint("Skipping BasePage=0x%lx, PageCount=0x%lx, MemoryType=%lx\n", 586 BasePage, PageCount, MemoryType); 587 Pfn = &MmPfnDatabase[BasePage]; 588 while (PageCount--) 589 { 590 /* Make an active PFN */ 591 Pfn->u3.e1.PageLocation = ActiveAndValid; 592 593 /* Advance one */ 594 Pfn++; 595 } 596 } 597 } 598 599 VOID 600 NTAPI 601 INIT_FUNCTION 602 MiBuildPfnDatabase(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 603 { 604 PLIST_ENTRY ListEntry; 605 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; 606 PFN_NUMBER BasePage, PageCount; 607 608 /* Map the PDEs and PPEs for the pfn database (ignore holes) */ 609 #if (_MI_PAGING_LEVELS >= 3) 610 MiMapPPEs(MmPfnDatabase, (PUCHAR)MmPfnDatabase + (MxPfnAllocation * PAGE_SIZE) - 1); 611 #endif 612 MiMapPDEs(MmPfnDatabase, (PUCHAR)MmPfnDatabase + (MxPfnAllocation * PAGE_SIZE) - 1); 613 614 /* First initialize the color tables */ 615 MiInitializeColorTables(); 616 617 /* Loop the memory descriptors */ 618 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink; 619 ListEntry != &LoaderBlock->MemoryDescriptorListHead; 620 ListEntry = ListEntry->Flink) 621 { 622 /* Get the descriptor */ 623 Descriptor = CONTAINING_RECORD(ListEntry, 624 MEMORY_ALLOCATION_DESCRIPTOR, 625 ListEntry); 626 627 /* Skip invisible memory */ 628 if (MiIsMemoryTypeInvisible(Descriptor->MemoryType)) continue; 629 630 /* If this is the free descriptor, use the copy instead */ 631 if (Descriptor == MxFreeDescriptor) Descriptor = &MxOldFreeDescriptor; 632 633 /* Get the range for this descriptor */ 634 BasePage = Descriptor->BasePage; 635 PageCount = Descriptor->PageCount; 636 637 /* Map the pages for the database */ 638 MiMapPTEs(&MmPfnDatabase[BasePage], 639 (PUCHAR)(&MmPfnDatabase[BasePage + PageCount]) - 1); 640 641 /* If this was the free descriptor, skip the next step */ 642 if (Descriptor == &MxOldFreeDescriptor) continue; 643 644 /* Add this descriptor to the database */ 645 MiAddDescriptorToDatabase(BasePage, PageCount, Descriptor->MemoryType); 646 } 647 648 /* At this point the whole pfn database is mapped. We are about to add the 649 pages from the free descriptor to the database, so from now on we cannot 650 use it anymore. */ 651 652 /* Now add the free descriptor */ 653 BasePage = MxFreeDescriptor->BasePage; 654 PageCount = MxFreeDescriptor->PageCount; 655 MiAddDescriptorToDatabase(BasePage, PageCount, LoaderFree); 656 657 /* And finally the memory we used */ 658 BasePage = MxOldFreeDescriptor.BasePage; 659 PageCount = MxFreeDescriptor->BasePage - BasePage; 660 MiAddDescriptorToDatabase(BasePage, PageCount, LoaderMemoryData); 661 662 /* Reset the descriptor back so we can create the correct memory blocks */ 663 *MxFreeDescriptor = MxOldFreeDescriptor; 664 } 665 666 NTSTATUS 667 NTAPI 668 INIT_FUNCTION 669 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 670 { 671 KIRQL OldIrql; 672 673 ASSERT(MxPfnAllocation != 0); 674 675 /* Set some hardcoded addresses */ 676 MmHyperSpaceEnd = (PVOID)HYPER_SPACE_END; 677 MmNonPagedSystemStart = (PVOID)MM_SYSTEM_SPACE_START; 678 MmPfnDatabase = (PVOID)MI_PFN_DATABASE; 679 MmWorkingSetList = (PVOID)MI_WORKING_SET_LIST; 680 681 682 // PrototypePte.u.Proto.Valid = 1 683 // PrototypePte.u.ReadOnly 684 // PrototypePte.u.Prototype 685 // PrototypePte.u.Protection = MM_READWRITE; 686 // PrototypePte.u.ProtoAddress 687 PrototypePte.u.Soft.PageFileHigh = MI_PTE_LOOKUP_NEEDED; 688 689 690 MiInitializePageTable(); 691 692 MiBuildNonPagedPool(); 693 694 MiBuildSystemPteSpace(); 695 696 /* Need to be at DISPATCH_LEVEL for MiInsertPageInFreeList */ 697 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 698 699 /* Map the PFN database pages */ 700 MiBuildPfnDatabase(LoaderBlock); 701 702 /* Now process the page tables */ 703 MiBuildPfnDatabaseFromPageTables(); 704 705 /* PFNs are initialized now! */ 706 MiPfnsInitialized = TRUE; 707 708 //KeLowerIrql(OldIrql); 709 710 /* Need to be at DISPATCH_LEVEL for InitializePool */ 711 //KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 712 713 /* Initialize the nonpaged pool */ 714 InitializePool(NonPagedPool, 0); 715 716 KeLowerIrql(OldIrql); 717 718 /* Initialize the balancer */ 719 MmInitializeBalancer((ULONG)MmAvailablePages, 0); 720 721 /* Make sure we have everything we need */ 722 ASSERT(MmPfnDatabase); 723 ASSERT(MmNonPagedSystemStart); 724 ASSERT(MmNonPagedPoolStart); 725 ASSERT(MmSizeOfNonPagedPoolInBytes); 726 ASSERT(MmMaximumNonPagedPoolInBytes); 727 ASSERT(MmNonPagedPoolExpansionStart); 728 ASSERT(MmHyperSpaceEnd); 729 ASSERT(MmNumberOfSystemPtes); 730 ASSERT(MiAddressToPde(MmNonPagedPoolStart)->u.Hard.Valid); 731 ASSERT(MiAddressToPte(MmNonPagedPoolStart)->u.Hard.Valid); 732 733 return STATUS_SUCCESS; 734 } 735