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