1 /* 2 * FreeLoader 3 * Copyright (C) 2006-2008 Aleksey Bragin <aleksey@reactos.org> 4 * Copyright (C) 2006-2009 Hervé Poussineau <hpoussin@reactos.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #include <freeldr.h> 22 23 #include <debug.h> 24 DBG_DEFAULT_CHANNEL(MEMORY); 25 26 PVOID PageLookupTableAddress = NULL; 27 PFN_NUMBER TotalPagesInLookupTable = 0; 28 PFN_NUMBER FreePagesInLookupTable = 0; 29 PFN_NUMBER LastFreePageHint = 0; 30 PFN_NUMBER MmLowestPhysicalPage = 0xFFFFFFFF; 31 PFN_NUMBER MmHighestPhysicalPage = 0; 32 33 PFREELDR_MEMORY_DESCRIPTOR BiosMemoryMap; 34 ULONG BiosMemoryMapEntryCount; 35 SIZE_T FrLdrImageSize; 36 37 #if DBG 38 typedef struct 39 { 40 TYPE_OF_MEMORY Type; 41 PCSTR TypeString; 42 } FREELDR_MEMORY_TYPE, *PFREELDR_MEMORY_TYPE; 43 44 FREELDR_MEMORY_TYPE MemoryTypeArray[] = 45 { 46 { LoaderMaximum, "Unknown memory" }, 47 { LoaderFree, "Free memory" }, 48 { LoaderBad, "Bad memory" }, 49 { LoaderLoadedProgram, "LoadedProgram" }, 50 { LoaderFirmwareTemporary, "FirmwareTemporary" }, 51 { LoaderFirmwarePermanent, "FirmwarePermanent" }, 52 { LoaderOsloaderHeap, "OsloaderHeap" }, 53 { LoaderOsloaderStack, "OsloaderStack" }, 54 { LoaderSystemCode, "SystemCode" }, 55 { LoaderHalCode, "HalCode" }, 56 { LoaderBootDriver, "BootDriver" }, 57 { LoaderRegistryData, "RegistryData" }, 58 { LoaderMemoryData, "MemoryData" }, 59 { LoaderNlsData, "NlsData" }, 60 { LoaderSpecialMemory, "SpecialMemory" }, 61 { LoaderReserve, "Reserve" }, 62 }; 63 ULONG MemoryTypeCount = sizeof(MemoryTypeArray) / sizeof(MemoryTypeArray[0]); 64 65 PCSTR 66 MmGetSystemMemoryMapTypeString( 67 TYPE_OF_MEMORY Type) 68 { 69 ULONG Index; 70 71 for (Index = 1; Index < MemoryTypeCount; Index++) 72 { 73 if (MemoryTypeArray[Index].Type == Type) 74 { 75 return MemoryTypeArray[Index].TypeString; 76 } 77 } 78 79 return MemoryTypeArray[0].TypeString; 80 } 81 82 VOID 83 DbgDumpMemoryMap( 84 PFREELDR_MEMORY_DESCRIPTOR List) 85 { 86 ULONG i; 87 88 DbgPrint("Dumping Memory map:\n"); 89 for (i = 0; List[i].PageCount != 0; i++) 90 { 91 DbgPrint("%02d %08x - %08x: %s\n", 92 i, 93 List[i].BasePage * PAGE_SIZE, 94 (List[i].BasePage + List[i].PageCount) * PAGE_SIZE, 95 MmGetSystemMemoryMapTypeString(List[i].MemoryType)); 96 } 97 DbgPrint("\n"); 98 } 99 #endif 100 101 ULONG 102 AddMemoryDescriptor( 103 IN OUT PFREELDR_MEMORY_DESCRIPTOR List, 104 IN ULONG MaxCount, 105 IN PFN_NUMBER BasePage, 106 IN PFN_NUMBER PageCount, 107 IN TYPE_OF_MEMORY MemoryType) 108 { 109 ULONG Index, DescriptCount; 110 PFN_NUMBER EndPage; 111 TRACE("AddMemoryDescriptor(0x%Ix, 0x%Ix, %u)\n", 112 BasePage, PageCount, MemoryType); 113 114 EndPage = BasePage + PageCount; 115 116 /* Skip over all descriptor below the new range */ 117 Index = 0; 118 while ((List[Index].PageCount != 0) && 119 ((List[Index].BasePage + List[Index].PageCount) <= BasePage)) 120 { 121 Index++; 122 } 123 124 /* Count the descriptors */ 125 DescriptCount = Index; 126 while (List[DescriptCount].PageCount != 0) 127 { 128 DescriptCount++; 129 } 130 131 /* Check if the existing range conflicts with the new range */ 132 while ((List[Index].PageCount != 0) && 133 (List[Index].BasePage < EndPage)) 134 { 135 TRACE("AddMemoryDescriptor conflict @%lu: new=[%lx:%lx], existing=[%lx,%lx]\n", 136 Index, BasePage, PageCount, List[Index].BasePage, List[Index].PageCount); 137 138 /* 139 * We have 4 overlapping cases: 140 * 141 * Case (a) (b) (c) (d) 142 * Existing range |---| |-----| |---| |---| 143 * New range |---| |---| |-----| |---| 144 * 145 */ 146 147 /* Check if the existing range starts before the new range (a)/(b) */ 148 if (List[Index].BasePage < BasePage) 149 { 150 /* Check if the existing range extends beyond the new range (b) */ 151 if (List[Index].BasePage + List[Index].PageCount > EndPage) 152 { 153 /* Split the descriptor */ 154 RtlMoveMemory(&List[Index + 1], 155 &List[Index], 156 (DescriptCount - Index) * sizeof(List[0])); 157 List[Index + 1].BasePage = EndPage; 158 List[Index + 1].PageCount = List[Index].BasePage + 159 List[Index].PageCount - 160 List[Index + 1].BasePage; 161 List[Index].PageCount = BasePage - List[Index].BasePage; 162 Index++; 163 DescriptCount++; 164 break; 165 } 166 else 167 { 168 /* Crop the existing range and continue with the next range */ 169 List[Index].PageCount = BasePage - List[Index].BasePage; 170 Index++; 171 } 172 } 173 /* Check if the existing range is fully covered by the new range (c) */ 174 else if ((List[Index].BasePage + List[Index].PageCount) <= 175 EndPage) 176 { 177 /* Delete this descriptor */ 178 RtlMoveMemory(&List[Index], 179 &List[Index + 1], 180 (DescriptCount - Index) * sizeof(List[0])); 181 DescriptCount--; 182 } 183 /* Otherwise the existing range ends after the new range (d) */ 184 else 185 { 186 /* Crop the existing range at the start and bail out */ 187 List[Index].PageCount -= EndPage - List[Index].BasePage; 188 List[Index].BasePage = EndPage; 189 break; 190 } 191 } 192 193 /* Make sure we can still add a new descriptor */ 194 if (DescriptCount >= MaxCount) 195 { 196 FrLdrBugCheckWithMessage( 197 MEMORY_INIT_FAILURE, 198 __FILE__, 199 __LINE__, 200 "Ran out of static memory descriptors!"); 201 } 202 203 /* Insert the new descriptor */ 204 if (Index < DescriptCount) 205 { 206 RtlMoveMemory(&List[Index + 1], 207 &List[Index], 208 (DescriptCount - Index) * sizeof(List[0])); 209 } 210 211 List[Index].BasePage = BasePage; 212 List[Index].PageCount = PageCount; 213 List[Index].MemoryType = MemoryType; 214 DescriptCount++; 215 216 #if 0 // only enable on demand! 217 DbgDumpMemoryMap(List); 218 #endif 219 return DescriptCount; 220 } 221 222 const FREELDR_MEMORY_DESCRIPTOR* 223 ArcGetMemoryDescriptor(const FREELDR_MEMORY_DESCRIPTOR* Current) 224 { 225 if (Current == NULL) 226 { 227 return BiosMemoryMap; 228 } 229 else 230 { 231 Current++; 232 if (Current->PageCount == 0) return NULL; 233 return Current; 234 } 235 } 236 237 static 238 VOID 239 MmCheckFreeldrImageFile(VOID) 240 { 241 #ifndef UEFIBOOT 242 PIMAGE_NT_HEADERS NtHeaders; 243 PIMAGE_FILE_HEADER FileHeader; 244 PIMAGE_OPTIONAL_HEADER OptionalHeader; 245 246 /* Get the NT headers */ 247 NtHeaders = RtlImageNtHeader(&__ImageBase); 248 if (!NtHeaders) 249 { 250 ERR("Could not get NtHeaders!\n"); 251 FrLdrBugCheckWithMessage( 252 FREELDR_IMAGE_CORRUPTION, 253 __FILE__, 254 __LINE__, 255 "Could not get NtHeaders!\n"); 256 } 257 258 /* Check the file header */ 259 FileHeader = &NtHeaders->FileHeader; 260 if ((FileHeader->Machine != IMAGE_FILE_MACHINE_NATIVE) || 261 (FileHeader->NumberOfSections != FREELDR_SECTION_COUNT) || 262 (FileHeader->PointerToSymbolTable != 0) || // Symbols stripped 263 (FileHeader->NumberOfSymbols != 0) || // "" "" 264 (FileHeader->SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))) 265 { 266 ERR("FreeLdr FileHeader is invalid.\n"); 267 FrLdrBugCheckWithMessage( 268 FREELDR_IMAGE_CORRUPTION, 269 __FILE__, 270 __LINE__, 271 "FreeLdr FileHeader is invalid.\n" 272 "Machine == 0x%lx, expected 0x%lx\n" 273 "NumberOfSections == 0x%lx, expected 0x%lx\n" 274 "PointerToSymbolTable == 0x%lx, expected 0\n" 275 "NumberOfSymbols == 0x%lx, expected 0\n" 276 "SizeOfOptionalHeader == 0x%lx, expected 0x%lx\n", 277 FileHeader->Machine, IMAGE_FILE_MACHINE_NATIVE, 278 FileHeader->NumberOfSections, FREELDR_SECTION_COUNT, 279 FileHeader->PointerToSymbolTable, 280 FileHeader->NumberOfSymbols, 281 FileHeader->SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)); 282 } 283 284 /* Check the optional header */ 285 OptionalHeader = &NtHeaders->OptionalHeader; 286 if ((OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) || 287 (OptionalHeader->Subsystem != IMAGE_SUBSYSTEM_NATIVE) || 288 (OptionalHeader->ImageBase != FREELDR_PE_BASE) || 289 (OptionalHeader->SizeOfImage > MAX_FREELDR_PE_SIZE) || 290 (OptionalHeader->SectionAlignment != OptionalHeader->FileAlignment)) 291 { 292 ERR("FreeLdr OptionalHeader is invalid.\n"); 293 FrLdrBugCheckWithMessage( 294 FREELDR_IMAGE_CORRUPTION, 295 __FILE__, 296 __LINE__, 297 "FreeLdr OptionalHeader is invalid.\n" 298 "Magic == 0x%lx, expected 0x%lx\n" 299 "Subsystem == 0x%lx, expected 1 (native)\n" 300 "ImageBase == 0x%lx, expected 0x%lx\n" 301 "SizeOfImage == 0x%lx, maximum 0x%lx\n" 302 "SectionAlignment 0x%lx doesn't match FileAlignment 0x%lx\n", 303 OptionalHeader->Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC, 304 OptionalHeader->Subsystem, 305 OptionalHeader->ImageBase, FREELDR_PE_BASE, 306 OptionalHeader->SizeOfImage, MAX_FREELDR_PE_SIZE, 307 OptionalHeader->SectionAlignment, OptionalHeader->FileAlignment); 308 } 309 310 /* Calculate the full image size */ 311 FrLdrImageSize = (ULONG_PTR)&__ImageBase + OptionalHeader->SizeOfImage - FREELDR_BASE; 312 #endif 313 } 314 315 BOOLEAN MmInitializeMemoryManager(VOID) 316 { 317 #if DBG 318 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL; 319 #endif 320 321 TRACE("Initializing Memory Manager.\n"); 322 323 /* Check the freeldr binary */ 324 MmCheckFreeldrImageFile(); 325 326 BiosMemoryMap = MachVtbl.GetMemoryMap(&BiosMemoryMapEntryCount); 327 328 #if DBG 329 // Dump the system memory map 330 TRACE("System Memory Map (Base Address, Length, Type):\n"); 331 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) 332 { 333 TRACE("%x\t %x\t %s\n", 334 MemoryDescriptor->BasePage * MM_PAGE_SIZE, 335 MemoryDescriptor->PageCount * MM_PAGE_SIZE, 336 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType)); 337 } 338 #endif 339 340 // Find address for the page lookup table 341 TotalPagesInLookupTable = MmGetAddressablePageCountIncludingHoles(); 342 PageLookupTableAddress = MmFindLocationForPageLookupTable(TotalPagesInLookupTable); 343 LastFreePageHint = MmHighestPhysicalPage; 344 345 if (PageLookupTableAddress == 0) 346 { 347 // If we get here then we probably couldn't 348 // find a contiguous chunk of memory big 349 // enough to hold the page lookup table 350 printf("Error initializing memory manager!\n"); 351 return FALSE; 352 } 353 354 // Initialize the page lookup table 355 MmInitPageLookupTable(PageLookupTableAddress, TotalPagesInLookupTable); 356 357 MmUpdateLastFreePageHint(PageLookupTableAddress, TotalPagesInLookupTable); 358 359 FreePagesInLookupTable = MmCountFreePagesInLookupTable(PageLookupTableAddress, 360 TotalPagesInLookupTable); 361 362 MmInitializeHeap(PageLookupTableAddress); 363 364 TRACE("Memory Manager initialized. 0x%x pages available.\n", FreePagesInLookupTable); 365 366 367 return TRUE; 368 } 369 370 371 PFN_NUMBER MmGetPageNumberFromAddress(PVOID Address) 372 { 373 return ((ULONG_PTR)Address) / MM_PAGE_SIZE; 374 } 375 376 PFN_NUMBER MmGetAddressablePageCountIncludingHoles(VOID) 377 { 378 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL; 379 PFN_NUMBER PageCount; 380 381 // 382 // Go through the whole memory map to get max address 383 // 384 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) 385 { 386 // 387 // Check if we got a higher end page address 388 // 389 if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > MmHighestPhysicalPage) 390 { 391 // 392 // Yes, remember it if this is real memory 393 // 394 if (MemoryDescriptor->MemoryType == LoaderFree) 395 MmHighestPhysicalPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount; 396 } 397 398 // 399 // Check if we got a higher (usable) start page address 400 // 401 if (MemoryDescriptor->BasePage < MmLowestPhysicalPage) 402 { 403 // 404 // Yes, remember it if this is real memory 405 // 406 MmLowestPhysicalPage = MemoryDescriptor->BasePage; 407 } 408 } 409 410 TRACE("lo/hi %lx %lx\n", MmLowestPhysicalPage, MmHighestPhysicalPage); 411 PageCount = MmHighestPhysicalPage - MmLowestPhysicalPage; 412 TRACE("MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", PageCount); 413 return PageCount; 414 } 415 416 PVOID MmFindLocationForPageLookupTable(PFN_NUMBER TotalPageCount) 417 { 418 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL; 419 SIZE_T PageLookupTableSize; 420 PFN_NUMBER RequiredPages; 421 PFN_NUMBER CandidateBasePage = 0; 422 PFN_NUMBER CandidatePageCount; 423 PFN_NUMBER PageLookupTableEndPage; 424 PVOID PageLookupTableMemAddress = NULL; 425 426 // Calculate how much pages we need to keep the page lookup table 427 PageLookupTableSize = TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM); 428 RequiredPages = PageLookupTableSize / MM_PAGE_SIZE; 429 430 // Search the highest memory block big enough to contain lookup table 431 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) 432 { 433 // Continue, if memory is not free 434 if (MemoryDescriptor->MemoryType != LoaderFree) continue; 435 436 // Continue, if the block is not big enough 437 if (MemoryDescriptor->PageCount < RequiredPages) continue; 438 439 // Continue, if it is not at a higher address than previous address 440 if (MemoryDescriptor->BasePage < CandidateBasePage) continue; 441 442 // Continue, if the address is too high 443 if (MemoryDescriptor->BasePage + RequiredPages >= MM_MAX_PAGE_LOADER) continue; 444 445 // Memory block is more suitable than the previous one 446 CandidateBasePage = MemoryDescriptor->BasePage; 447 CandidatePageCount = MemoryDescriptor->PageCount; 448 } 449 450 // Calculate the end address for the lookup table 451 PageLookupTableEndPage = min(CandidateBasePage + CandidatePageCount, 452 MM_MAX_PAGE_LOADER); 453 454 // Calculate the virtual address 455 PageLookupTableMemAddress = (PVOID)((PageLookupTableEndPage * PAGE_SIZE) 456 - PageLookupTableSize); 457 458 TRACE("MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress); 459 460 return PageLookupTableMemAddress; 461 } 462 463 VOID MmInitPageLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount) 464 { 465 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL; 466 PFN_NUMBER PageLookupTableStartPage; 467 PFN_NUMBER PageLookupTablePageCount; 468 469 TRACE("MmInitPageLookupTable()\n"); 470 471 // Mark every page as allocated initially 472 // We will go through and mark pages again according to the memory map 473 // But this will mark any holes not described in the map as allocated 474 MmMarkPagesInLookupTable(PageLookupTable, MmLowestPhysicalPage, TotalPageCount, LoaderFirmwarePermanent); 475 476 // Parse the whole memory map 477 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) 478 { 479 // Mark used pages in the lookup table 480 481 if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount <= TotalPageCount) 482 { 483 TRACE("Marking pages 0x%lx-0x%lx as type %s\n", 484 MemoryDescriptor->BasePage, 485 MemoryDescriptor->BasePage + MemoryDescriptor->PageCount, 486 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType)); 487 MmMarkPagesInLookupTable(PageLookupTable, 488 MemoryDescriptor->BasePage, 489 MemoryDescriptor->PageCount, 490 MemoryDescriptor->MemoryType); 491 } 492 else 493 TRACE("Ignoring pages 0x%lx-0x%lx (%s)\n", 494 MemoryDescriptor->BasePage, 495 MemoryDescriptor->BasePage + MemoryDescriptor->PageCount, 496 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType)); 497 } 498 499 // Mark the pages that the lookup table occupies as reserved 500 PageLookupTableStartPage = MmGetPageNumberFromAddress(PageLookupTable); 501 PageLookupTablePageCount = MmGetPageNumberFromAddress((PVOID)((ULONG_PTR)PageLookupTable + ROUND_UP(TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM), MM_PAGE_SIZE))) - PageLookupTableStartPage; 502 TRACE("Marking the page lookup table pages as reserved StartPage: 0x%x PageCount: 0x%x\n", PageLookupTableStartPage, PageLookupTablePageCount); 503 MmMarkPagesInLookupTable(PageLookupTable, PageLookupTableStartPage, PageLookupTablePageCount, LoaderFirmwareTemporary); 504 } 505 506 VOID MmMarkPagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY PageAllocated) 507 { 508 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 509 PFN_NUMBER Index; 510 TRACE("MmMarkPagesInLookupTable()\n"); 511 512 /* Validate the range */ 513 if ((StartPage < MmLowestPhysicalPage) || 514 ((StartPage + PageCount - 1) > MmHighestPhysicalPage)) 515 { 516 ERR("Memory (0x%lx:0x%lx) outside of lookup table! Valid range: 0x%lx-0x%lx.\n", 517 StartPage, PageCount, MmLowestPhysicalPage, MmHighestPhysicalPage); 518 return; 519 } 520 521 StartPage -= MmLowestPhysicalPage; 522 for (Index=StartPage; Index<(StartPage+PageCount); Index++) 523 { 524 #if 0 525 if ((Index <= (StartPage + 16)) || (Index >= (StartPage+PageCount-16))) 526 { 527 TRACE("Index = 0x%x StartPage = 0x%x PageCount = 0x%x\n", Index, StartPage, PageCount); 528 } 529 #endif 530 RealPageLookupTable[Index].PageAllocated = PageAllocated; 531 RealPageLookupTable[Index].PageAllocationLength = (PageAllocated != LoaderFree) ? 1 : 0; 532 } 533 TRACE("MmMarkPagesInLookupTable() Done\n"); 534 } 535 536 VOID MmAllocatePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY MemoryType) 537 { 538 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 539 PFN_NUMBER Index; 540 541 StartPage -= MmLowestPhysicalPage; 542 for (Index=StartPage; Index<(StartPage+PageCount); Index++) 543 { 544 RealPageLookupTable[Index].PageAllocated = MemoryType; 545 RealPageLookupTable[Index].PageAllocationLength = (Index == StartPage) ? PageCount : 0; 546 } 547 } 548 549 PFN_NUMBER MmCountFreePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount) 550 { 551 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 552 PFN_NUMBER Index; 553 PFN_NUMBER FreePageCount; 554 555 FreePageCount = 0; 556 for (Index=0; Index<TotalPageCount; Index++) 557 { 558 if (RealPageLookupTable[Index].PageAllocated == LoaderFree) 559 { 560 FreePageCount++; 561 } 562 } 563 564 return FreePageCount; 565 } 566 567 PFN_NUMBER MmFindAvailablePages(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, BOOLEAN FromEnd) 568 { 569 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 570 PFN_NUMBER AvailablePagesSoFar; 571 PFN_NUMBER Index; 572 573 if (LastFreePageHint > TotalPageCount) 574 { 575 LastFreePageHint = TotalPageCount; 576 } 577 578 AvailablePagesSoFar = 0; 579 if (FromEnd) 580 { 581 /* Allocate "high" (from end) pages */ 582 for (Index=LastFreePageHint-1; Index>0; Index--) 583 { 584 if (RealPageLookupTable[Index].PageAllocated != LoaderFree) 585 { 586 AvailablePagesSoFar = 0; 587 continue; 588 } 589 else 590 { 591 AvailablePagesSoFar++; 592 } 593 594 if (AvailablePagesSoFar >= PagesNeeded) 595 { 596 return Index + MmLowestPhysicalPage; 597 } 598 } 599 } 600 else 601 { 602 TRACE("Alloc low memory, LastFreePageHint 0x%x, TPC 0x%x\n", LastFreePageHint, TotalPageCount); 603 /* Allocate "low" pages */ 604 for (Index=1; Index < LastFreePageHint; Index++) 605 { 606 if (RealPageLookupTable[Index].PageAllocated != LoaderFree) 607 { 608 AvailablePagesSoFar = 0; 609 continue; 610 } 611 else 612 { 613 AvailablePagesSoFar++; 614 } 615 616 if (AvailablePagesSoFar >= PagesNeeded) 617 { 618 return Index - AvailablePagesSoFar + 1 + MmLowestPhysicalPage; 619 } 620 } 621 } 622 623 return 0; 624 } 625 626 PFN_NUMBER MmFindAvailablePagesBeforePage(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, PFN_NUMBER LastPage) 627 { 628 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 629 PFN_NUMBER AvailablePagesSoFar; 630 PFN_NUMBER Index; 631 632 if (LastPage > TotalPageCount) 633 { 634 return MmFindAvailablePages(PageLookupTable, TotalPageCount, PagesNeeded, TRUE); 635 } 636 637 AvailablePagesSoFar = 0; 638 for (Index=LastPage-1; Index>0; Index--) 639 { 640 if (RealPageLookupTable[Index].PageAllocated != LoaderFree) 641 { 642 AvailablePagesSoFar = 0; 643 continue; 644 } 645 else 646 { 647 AvailablePagesSoFar++; 648 } 649 650 if (AvailablePagesSoFar >= PagesNeeded) 651 { 652 return Index + MmLowestPhysicalPage; 653 } 654 } 655 656 return 0; 657 } 658 659 VOID MmUpdateLastFreePageHint(PVOID PageLookupTable, PFN_NUMBER TotalPageCount) 660 { 661 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 662 PFN_NUMBER Index; 663 664 for (Index=TotalPageCount-1; Index>0; Index--) 665 { 666 if (RealPageLookupTable[Index].PageAllocated == LoaderFree) 667 { 668 LastFreePageHint = Index + 1 + MmLowestPhysicalPage; 669 break; 670 } 671 } 672 } 673 674 BOOLEAN MmAreMemoryPagesAvailable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PVOID PageAddress, PFN_NUMBER PageCount) 675 { 676 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 677 PFN_NUMBER StartPage; 678 PFN_NUMBER Index; 679 680 StartPage = MmGetPageNumberFromAddress(PageAddress); 681 682 if (StartPage < MmLowestPhysicalPage) return FALSE; 683 684 StartPage -= MmLowestPhysicalPage; 685 686 // Make sure they aren't trying to go past the 687 // end of available memory 688 if ((StartPage + PageCount) > TotalPageCount) 689 { 690 return FALSE; 691 } 692 693 for (Index = StartPage; Index < (StartPage + PageCount); Index++) 694 { 695 // If this page is allocated then there obviously isn't 696 // memory available so return FALSE 697 if (RealPageLookupTable[Index].PageAllocated != LoaderFree) 698 { 699 return FALSE; 700 } 701 } 702 703 return TRUE; 704 } 705