1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/mm/ARM3/i386/init.c 5 * PURPOSE: ARM Memory Manager Initialization for x86 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 <mm/ARM3/miarm.h> 17 18 /* GLOBALS ********************************************************************/ 19 20 /* Template PTE and PDE for a kernel page */ 21 /* FIXME: These should be PTE_GLOBAL */ 22 MMPTE ValidKernelPde = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}}; 23 MMPTE ValidKernelPte = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}}; 24 25 /* The same, but for local pages */ 26 MMPTE ValidKernelPdeLocal = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}}; 27 MMPTE ValidKernelPteLocal = {{PTE_VALID|PTE_READWRITE|PTE_DIRTY|PTE_ACCESSED}}; 28 29 /* Template PDE for a demand-zero page */ 30 MMPDE DemandZeroPde = {{MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS}}; 31 MMPTE DemandZeroPte = {{MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS}}; 32 33 /* Template PTE for prototype page */ 34 MMPTE PrototypePte = {{(MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) | 35 PTE_PROTOTYPE | (MI_PTE_LOOKUP_NEEDED << PAGE_SHIFT)}}; 36 37 /* Template PTE for decommited page */ 38 MMPTE MmDecommittedPte = {{MM_DECOMMIT << MM_PTE_SOFTWARE_PROTECTION_BITS}}; 39 40 /* PRIVATE FUNCTIONS **********************************************************/ 41 42 CODE_SEG("INIT") 43 VOID 44 NTAPI 45 MiInitializeSessionSpaceLayout(VOID) 46 { 47 // 48 // Set the size of session view, pool, and image 49 // 50 MmSessionSize = MI_SESSION_SIZE; 51 MmSessionViewSize = MI_SESSION_VIEW_SIZE; 52 MmSessionPoolSize = MI_SESSION_POOL_SIZE; 53 MmSessionImageSize = MI_SESSION_IMAGE_SIZE; 54 55 // 56 // Set the size of system view 57 // 58 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE; 59 60 // 61 // This is where it all ends 62 // 63 MiSessionImageEnd = (PVOID)PTE_BASE; 64 65 // 66 // This is where we will load Win32k.sys and the video driver 67 // 68 MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd - 69 MmSessionImageSize); 70 71 // 72 // So the view starts right below the session working set (itself below 73 // the image area) 74 // 75 MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionImageEnd - 76 MmSessionImageSize - 77 MI_SESSION_WORKING_SET_SIZE - 78 MmSessionViewSize); 79 80 // 81 // Session pool follows 82 // 83 MiSessionPoolEnd = MiSessionViewStart; 84 MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd - 85 MmSessionPoolSize); 86 87 // 88 // And it all begins here 89 // 90 MmSessionBase = MiSessionPoolStart; 91 92 // 93 // Sanity check that our math is correct 94 // 95 ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE); 96 97 // 98 // Session space ends wherever image session space ends 99 // 100 MiSessionSpaceEnd = MiSessionImageEnd; 101 102 // 103 // System view space ends at session space, so now that we know where 104 // this is, we can compute the base address of system view space itself. 105 // 106 MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase - 107 MmSystemViewSize); 108 109 /* Compute the PTE addresses for all the addresses we carved out */ 110 MiSessionImagePteStart = MiAddressToPte(MiSessionImageStart); 111 MiSessionImagePteEnd = MiAddressToPte(MiSessionImageEnd); 112 MiSessionBasePte = MiAddressToPte(MmSessionBase); 113 MiSessionSpaceWs = (PVOID)((ULONG_PTR)MiSessionViewStart + MmSessionViewSize); 114 MiSessionLastPte = MiAddressToPte(MiSessionSpaceEnd); 115 116 /* Initialize session space */ 117 MmSessionSpace = (PMM_SESSION_SPACE)((ULONG_PTR)MmSessionBase + 118 MmSessionSize - 119 MmSessionImageSize - 120 MM_ALLOCATION_GRANULARITY); 121 } 122 123 CODE_SEG("INIT") 124 VOID 125 NTAPI 126 MiComputeNonPagedPoolVa(IN ULONG FreePages) 127 { 128 IN PFN_NUMBER PoolPages; 129 130 /* Check if this is a machine with less than 256MB of RAM, and no overide */ 131 if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) && 132 !(MmSizeOfNonPagedPoolInBytes)) 133 { 134 /* Force the non paged pool to be 2MB so we can reduce RAM usage */ 135 MmSizeOfNonPagedPoolInBytes = 2 * _1MB; 136 } 137 138 /* Hyperspace ends here */ 139 MmHyperSpaceEnd = (PVOID)((ULONG_PTR)MmSystemCacheWorkingSetList - 1); 140 141 /* Check if the user gave a ridicuously large nonpaged pool RAM size */ 142 if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) > (FreePages * 7 / 8)) 143 { 144 /* More than 7/8ths of RAM was dedicated to nonpaged pool, ignore! */ 145 MmSizeOfNonPagedPoolInBytes = 0; 146 } 147 148 /* Check if no registry setting was set, or if the setting was too low */ 149 if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize) 150 { 151 /* Start with the minimum (256 KB) and add 32 KB for each MB above 4 */ 152 MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize; 153 MmSizeOfNonPagedPoolInBytes += (FreePages - 1024) / 256 * MmMinAdditionNonPagedPoolPerMb; 154 } 155 156 /* Check if the registy setting or our dynamic calculation was too high */ 157 if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE) 158 { 159 /* Set it to the maximum */ 160 MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE; 161 } 162 163 /* Check if a percentage cap was set through the registry */ 164 if (MmMaximumNonPagedPoolPercent) UNIMPLEMENTED; 165 166 /* Page-align the nonpaged pool size */ 167 MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1); 168 169 /* Now, check if there was a registry size for the maximum size */ 170 if (!MmMaximumNonPagedPoolInBytes) 171 { 172 /* Start with the default (1MB) */ 173 MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool; 174 175 /* Add space for PFN database */ 176 MmMaximumNonPagedPoolInBytes += (ULONG) 177 PAGE_ALIGN((MmHighestPhysicalPage + 1) * sizeof(MMPFN)); 178 179 /* Check if the machine has more than 512MB of free RAM */ 180 if (FreePages >= 0x1F000) 181 { 182 /* Add 200KB for each MB above 4 */ 183 MmMaximumNonPagedPoolInBytes += (FreePages - 1024) / 256 * 184 (MmMaxAdditionNonPagedPoolPerMb / 2); 185 if (MmMaximumNonPagedPoolInBytes < MI_MAX_NONPAGED_POOL_SIZE) 186 { 187 /* Make it at least 128MB since this machine has a lot of RAM */ 188 MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE; 189 } 190 } 191 else 192 { 193 /* Add 400KB for each MB above 4 */ 194 MmMaximumNonPagedPoolInBytes += (FreePages - 1024) / 256 * 195 MmMaxAdditionNonPagedPoolPerMb; 196 } 197 } 198 199 /* Make sure there's at least 16 pages + the PFN available for expansion */ 200 PoolPages = MmSizeOfNonPagedPoolInBytes + (PAGE_SIZE * 16) + 201 ((ULONG)PAGE_ALIGN(MmHighestPhysicalPage + 1) * sizeof(MMPFN)); 202 if (MmMaximumNonPagedPoolInBytes < PoolPages) 203 { 204 /* The maximum should be at least high enough to cover all the above */ 205 MmMaximumNonPagedPoolInBytes = PoolPages; 206 } 207 208 /* Systems with 2GB of kernel address space get double the size */ 209 PoolPages = MI_MAX_NONPAGED_POOL_SIZE * 2; 210 211 /* On the other hand, make sure that PFN + nonpaged pool doesn't get too big */ 212 if (MmMaximumNonPagedPoolInBytes > PoolPages) 213 { 214 /* Trim it down to the maximum architectural limit (256MB) */ 215 MmMaximumNonPagedPoolInBytes = PoolPages; 216 } 217 218 /* Check if this is a system with > 128MB of non paged pool */ 219 if (MmMaximumNonPagedPoolInBytes > MI_MAX_NONPAGED_POOL_SIZE) 220 { 221 /* Check if the initial size is less than the extra 128MB boost */ 222 if (MmSizeOfNonPagedPoolInBytes < (MmMaximumNonPagedPoolInBytes - 223 MI_MAX_NONPAGED_POOL_SIZE)) 224 { 225 /* FIXME: Should check if the initial pool can be expanded */ 226 227 /* Assume no expansion possible, check ift he maximum is too large */ 228 if (MmMaximumNonPagedPoolInBytes > (MmSizeOfNonPagedPoolInBytes + 229 MI_MAX_NONPAGED_POOL_SIZE)) 230 { 231 /* Set it to the initial value plus the boost */ 232 MmMaximumNonPagedPoolInBytes = MmSizeOfNonPagedPoolInBytes + 233 MI_MAX_NONPAGED_POOL_SIZE; 234 } 235 } 236 } 237 } 238 239 CODE_SEG("INIT") 240 NTSTATUS 241 NTAPI 242 MiInitMachineDependent(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 243 { 244 PFN_NUMBER PageFrameIndex; 245 PMMPTE StartPde, EndPde, PointerPte, LastPte; 246 MMPTE TempPde, TempPte; 247 PVOID NonPagedPoolExpansionVa; 248 SIZE_T NonPagedSystemSize; 249 KIRQL OldIrql; 250 PMMPFN Pfn1; 251 ULONG Flags; 252 253 #if defined(_GLOBAL_PAGES_ARE_AWESOME_) 254 255 /* Check for global bit */ 256 if (KeFeatureBits & KF_GLOBAL_PAGE) 257 { 258 /* Set it on the template PTE and PDE */ 259 ValidKernelPte.u.Hard.Global = TRUE; 260 ValidKernelPde.u.Hard.Global = TRUE; 261 } 262 263 #endif 264 265 /* Now templates are ready */ 266 TempPte = ValidKernelPte; 267 TempPde = ValidKernelPde; 268 269 // 270 // Set CR3 for the system process 271 // 272 PointerPte = MiAddressToPde(PDE_BASE); 273 PageFrameIndex = PFN_FROM_PTE(PointerPte) << PAGE_SHIFT; 274 PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameIndex; 275 276 // 277 // Blow away user-mode 278 // 279 StartPde = MiAddressToPde(0); 280 EndPde = MiAddressToPde(KSEG0_BASE); 281 RtlZeroMemory(StartPde, (EndPde - StartPde) * sizeof(MMPTE)); 282 283 /* Compute non paged pool limits and size */ 284 MiComputeNonPagedPoolVa(MiNumberOfFreePages); 285 286 // 287 // Now calculate the nonpaged pool expansion VA region 288 // 289 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 290 MmMaximumNonPagedPoolInBytes + 291 MmSizeOfNonPagedPoolInBytes); 292 MmNonPagedPoolStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolStart); 293 NonPagedPoolExpansionVa = MmNonPagedPoolStart; 294 DPRINT("NP Pool has been tuned to: %lu bytes and %lu bytes\n", 295 MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes); 296 297 // 298 // Now calculate the nonpaged system VA region, which includes the 299 // nonpaged pool expansion (above) and the system PTEs. Note that it is 300 // then aligned to a PDE boundary (4MB). 301 // 302 NonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE; 303 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolStart - 304 NonPagedSystemSize); 305 MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart & 306 ~(PDE_MAPPED_VA - 1)); 307 308 // 309 // Don't let it go below the minimum 310 // 311 if (MmNonPagedSystemStart < (PVOID)0xEB000000) 312 { 313 // 314 // This is a hard-coded limit in the Windows NT address space 315 // 316 MmNonPagedSystemStart = (PVOID)0xEB000000; 317 318 // 319 // Reduce the amount of system PTEs to reach this point 320 // 321 MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolStart - 322 (ULONG_PTR)MmNonPagedSystemStart) >> 323 PAGE_SHIFT; 324 MmNumberOfSystemPtes--; 325 ASSERT(MmNumberOfSystemPtes > 1000); 326 } 327 328 // 329 // Check if we are in a situation where the size of the paged pool 330 // is so large that it overflows into nonpaged pool 331 // 332 if (MmSizeOfPagedPoolInBytes > 333 ((ULONG_PTR)MmNonPagedSystemStart - (ULONG_PTR)MmPagedPoolStart)) 334 { 335 // 336 // We need some recalculations here 337 // 338 DPRINT1("Paged pool is too big!\n"); 339 } 340 341 // 342 // Normally, the PFN database should start after the loader images. 343 // This is already the case in ReactOS, but for now we want to co-exist 344 // with the old memory manager, so we'll create a "Shadow PFN Database" 345 // instead, and arbitrarly start it at 0xB0000000. 346 // 347 MmPfnDatabase = (PVOID)0xB0000000; 348 ASSERT(((ULONG_PTR)MmPfnDatabase & (PDE_MAPPED_VA - 1)) == 0); 349 350 // 351 // Non paged pool comes after the PFN database 352 // 353 MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase + 354 (MxPfnAllocation << PAGE_SHIFT)); 355 356 // 357 // Now we actually need to get these many physical pages. Nonpaged pool 358 // is actually also physically contiguous (but not the expansion) 359 // 360 PageFrameIndex = MxGetNextPage(MxPfnAllocation + 361 (MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT)); 362 ASSERT(PageFrameIndex != 0); 363 DPRINT("PFN DB PA PFN begins at: %lx\n", PageFrameIndex); 364 DPRINT("NP PA PFN begins at: %lx\n", PageFrameIndex + MxPfnAllocation); 365 366 /* Convert nonpaged pool size from bytes to pages */ 367 MmMaximumNonPagedPoolInPages = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT; 368 369 // 370 // Now we need some pages to create the page tables for the NP system VA 371 // which includes system PTEs and expansion NP 372 // 373 StartPde = MiAddressToPde(MmNonPagedSystemStart); 374 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolEnd - 1)); 375 while (StartPde <= EndPde) 376 { 377 // 378 // Get a page 379 // 380 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1); 381 MI_WRITE_VALID_PTE(StartPde, TempPde); 382 383 // 384 // Zero out the page table 385 // 386 PointerPte = MiPteToAddress(StartPde); 387 RtlZeroMemory(PointerPte, PAGE_SIZE); 388 389 // 390 // Next 391 // 392 StartPde++; 393 } 394 395 // 396 // Now we need pages for the page tables which will map initial NP 397 // 398 StartPde = MiAddressToPde(MmPfnDatabase); 399 EndPde = MiAddressToPde((PVOID)((ULONG_PTR)MmNonPagedPoolStart + 400 MmSizeOfNonPagedPoolInBytes - 1)); 401 while (StartPde <= EndPde) 402 { 403 // 404 // Get a page 405 // 406 TempPde.u.Hard.PageFrameNumber = MxGetNextPage(1); 407 MI_WRITE_VALID_PTE(StartPde, TempPde); 408 409 // 410 // Zero out the page table 411 // 412 PointerPte = MiPteToAddress(StartPde); 413 RtlZeroMemory(PointerPte, PAGE_SIZE); 414 415 // 416 // Next 417 // 418 StartPde++; 419 } 420 421 MmSubsectionBase = (ULONG_PTR)MmNonPagedPoolStart; 422 423 // 424 // Now remember where the expansion starts 425 // 426 MmNonPagedPoolExpansionStart = NonPagedPoolExpansionVa; 427 428 // 429 // Last step is to actually map the nonpaged pool 430 // 431 PointerPte = MiAddressToPte(MmNonPagedPoolStart); 432 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolStart + 433 MmSizeOfNonPagedPoolInBytes - 1)); 434 while (PointerPte <= LastPte) 435 { 436 // 437 // Use one of our contigous pages 438 // 439 TempPte.u.Hard.PageFrameNumber = PageFrameIndex++; 440 MI_WRITE_VALID_PTE(PointerPte++, TempPte); 441 } 442 443 // 444 // Sanity check: make sure we have properly defined the system PTE space 445 // 446 ASSERT(MiAddressToPte(MmNonPagedSystemStart) < 447 MiAddressToPte(MmNonPagedPoolExpansionStart)); 448 449 /* Now go ahead and initialize the nonpaged pool */ 450 MiInitializeNonPagedPool(); 451 MiInitializeNonPagedPoolThresholds(); 452 453 /* Map the PFN database pages */ 454 MiMapPfnDatabase(LoaderBlock); 455 456 /* Initialize the color tables */ 457 MiInitializeColorTables(); 458 459 /* Build the PFN Database */ 460 MiInitializePfnDatabase(LoaderBlock); 461 MmInitializeBalancer(MmAvailablePages, 0); 462 463 // 464 // Reset the descriptor back so we can create the correct memory blocks 465 // 466 *MxFreeDescriptor = MxOldFreeDescriptor; 467 468 // 469 // Initialize the nonpaged pool 470 // 471 InitializePool(NonPagedPool, 0); 472 473 // 474 // We PDE-aligned the nonpaged system start VA, so haul some extra PTEs! 475 // 476 PointerPte = MiAddressToPte(MmNonPagedSystemStart); 477 MmNumberOfSystemPtes = MiAddressToPte(MmNonPagedPoolExpansionStart) - 478 PointerPte; 479 MmNumberOfSystemPtes--; 480 DPRINT("Final System PTE count: %lu (%lu bytes)\n", 481 MmNumberOfSystemPtes, MmNumberOfSystemPtes * PAGE_SIZE); 482 483 // 484 // Create the system PTE space 485 // 486 MiInitializeSystemPtes(PointerPte, MmNumberOfSystemPtes, SystemPteSpace); 487 488 /* Get the PDE For hyperspace */ 489 StartPde = MiAddressToPde(HYPER_SPACE); 490 491 /* Lock PFN database */ 492 OldIrql = MiAcquirePfnLock(); 493 494 /* Allocate a page for hyperspace and create it */ 495 MI_SET_USAGE(MI_USAGE_PAGE_TABLE); 496 MI_SET_PROCESS2("Kernel"); 497 PageFrameIndex = MiRemoveAnyPage(0); 498 TempPde = ValidKernelPdeLocal; 499 TempPde.u.Hard.PageFrameNumber = PageFrameIndex; 500 MI_WRITE_VALID_PTE(StartPde, TempPde); 501 502 /* Flush the TLB */ 503 KeFlushCurrentTb(); 504 505 /* Release the lock */ 506 MiReleasePfnLock(OldIrql); 507 508 // 509 // Zero out the page table now 510 // 511 PointerPte = MiAddressToPte(HYPER_SPACE); 512 RtlZeroMemory(PointerPte, PAGE_SIZE); 513 514 // 515 // Setup the mapping PTEs 516 // 517 MmFirstReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_START); 518 MmLastReservedMappingPte = MiAddressToPte(MI_MAPPING_RANGE_END); 519 MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES; 520 521 /* Set the working set address */ 522 MmWorkingSetList = (PVOID)MI_WORKING_SET_LIST; 523 524 // 525 // Reserve system PTEs for zeroing PTEs and clear them 526 // 527 MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES + 1, 528 SystemPteSpace); 529 RtlZeroMemory(MiFirstReservedZeroingPte, (MI_ZERO_PTES + 1) * sizeof(MMPTE)); 530 531 // 532 // Set the counter to maximum to boot with 533 // 534 MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES; 535 536 /* Lock PFN database */ 537 OldIrql = MiAcquirePfnLock(); 538 539 /* Reset the ref/share count so that MmInitializeProcessAddressSpace works */ 540 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(MiAddressToPde(PDE_BASE))); 541 Pfn1->u2.ShareCount = 0; 542 Pfn1->u3.e2.ReferenceCount = 0; 543 544 /* Get a page for the working set list */ 545 MI_SET_USAGE(MI_USAGE_PAGE_TABLE); 546 MI_SET_PROCESS2("Kernel WS List"); 547 PageFrameIndex = MiRemoveAnyPage(0); 548 TempPte = ValidKernelPteLocal; 549 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 550 551 /* Map the working set list */ 552 PointerPte = MiAddressToPte(MmWorkingSetList); 553 MI_WRITE_VALID_PTE(PointerPte, TempPte); 554 555 /* Zero it out, and save the frame index */ 556 RtlZeroMemory(MiPteToAddress(PointerPte), PAGE_SIZE); 557 PsGetCurrentProcess()->WorkingSetPage = PageFrameIndex; 558 559 /* Check for Pentium LOCK errata */ 560 if (KiI386PentiumLockErrataPresent) 561 { 562 /* Mark the 1st IDT page as Write-Through to prevent a lockup 563 on a F00F instruction. 564 See http://www.rcollins.org/Errata/Dec97/F00FBug.html */ 565 PointerPte = MiAddressToPte(KeGetPcr()->IDT); 566 PointerPte->u.Hard.WriteThrough = 1; 567 } 568 569 /* Release the lock */ 570 MiReleasePfnLock(OldIrql); 571 572 /* Initialize the bogus address space */ 573 Flags = 0; 574 MmInitializeProcessAddressSpace(PsGetCurrentProcess(), NULL, NULL, &Flags, NULL); 575 576 /* Make sure the color lists are valid */ 577 ASSERT(MmFreePagesByColor[0] < (PMMCOLOR_TABLES)PTE_BASE); 578 StartPde = MiAddressToPde(MmFreePagesByColor[0]); 579 ASSERT(StartPde->u.Hard.Valid == 1); 580 PointerPte = MiAddressToPte(MmFreePagesByColor[0]); 581 ASSERT(PointerPte->u.Hard.Valid == 1); 582 LastPte = MiAddressToPte((ULONG_PTR)&MmFreePagesByColor[1][MmSecondaryColors] - 1); 583 ASSERT(LastPte->u.Hard.Valid == 1); 584 585 /* Loop the color list PTEs */ 586 while (PointerPte <= LastPte) 587 { 588 /* Get the PFN entry */ 589 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte)); 590 if (!Pfn1->u3.e2.ReferenceCount) 591 { 592 /* Fill it out */ 593 Pfn1->u4.PteFrame = PFN_FROM_PTE(StartPde); 594 Pfn1->PteAddress = PointerPte; 595 Pfn1->u2.ShareCount++; 596 Pfn1->u3.e2.ReferenceCount = 1; 597 Pfn1->u3.e1.PageLocation = ActiveAndValid; 598 Pfn1->u3.e1.CacheAttribute = MiCached; 599 } 600 601 /* Keep going */ 602 PointerPte++; 603 } 604 605 /* All done */ 606 return STATUS_SUCCESS; 607 } 608 609 /* EOF */ 610