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 PIMAGE_NT_HEADERS NtHeaders; 242 PIMAGE_FILE_HEADER FileHeader; 243 PIMAGE_OPTIONAL_HEADER OptionalHeader; 244 245 /* Get the NT headers */ 246 NtHeaders = RtlImageNtHeader(&__ImageBase); 247 if (!NtHeaders) 248 { 249 ERR("Could not get NtHeaders!\n"); 250 FrLdrBugCheckWithMessage( 251 FREELDR_IMAGE_CORRUPTION, 252 __FILE__, 253 __LINE__, 254 "Could not get NtHeaders!\n"); 255 } 256 257 /* Check the file header */ 258 FileHeader = &NtHeaders->FileHeader; 259 if ((FileHeader->Machine != IMAGE_FILE_MACHINE_NATIVE) || 260 (FileHeader->NumberOfSections != FREELDR_SECTION_COUNT) || 261 (FileHeader->PointerToSymbolTable != 0) || // Symbols stripped 262 (FileHeader->NumberOfSymbols != 0) || // "" "" 263 (FileHeader->SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))) 264 { 265 ERR("FreeLdr FileHeader is invalid.\n"); 266 FrLdrBugCheckWithMessage( 267 FREELDR_IMAGE_CORRUPTION, 268 __FILE__, 269 __LINE__, 270 "FreeLdr FileHeader is invalid.\n" 271 "Machine == 0x%lx, expected 0x%lx\n" 272 "NumberOfSections == 0x%lx, expected 0x%lx\n" 273 "PointerToSymbolTable == 0x%lx, expected 0\n" 274 "NumberOfSymbols == 0x%lx, expected 0\n" 275 "SizeOfOptionalHeader == 0x%lx, expected 0x%lx\n", 276 FileHeader->Machine, IMAGE_FILE_MACHINE_NATIVE, 277 FileHeader->NumberOfSections, FREELDR_SECTION_COUNT, 278 FileHeader->PointerToSymbolTable, 279 FileHeader->NumberOfSymbols, 280 FileHeader->SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)); 281 } 282 283 /* Check the optional header */ 284 OptionalHeader = &NtHeaders->OptionalHeader; 285 if ((OptionalHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) || 286 (OptionalHeader->Subsystem != IMAGE_SUBSYSTEM_NATIVE) || 287 (OptionalHeader->ImageBase != FREELDR_PE_BASE) || 288 (OptionalHeader->SizeOfImage > MAX_FREELDR_PE_SIZE) || 289 (OptionalHeader->SectionAlignment != OptionalHeader->FileAlignment)) 290 { 291 ERR("FreeLdr OptionalHeader is invalid.\n"); 292 FrLdrBugCheckWithMessage( 293 FREELDR_IMAGE_CORRUPTION, 294 __FILE__, 295 __LINE__, 296 "FreeLdr OptionalHeader is invalid.\n" 297 "Magic == 0x%lx, expected 0x%lx\n" 298 "Subsystem == 0x%lx, expected 1 (native)\n" 299 "ImageBase == 0x%lx, expected 0x%lx\n" 300 "SizeOfImage == 0x%lx, maximum 0x%lx\n" 301 "SectionAlignment 0x%lx doesn't match FileAlignment 0x%lx\n", 302 OptionalHeader->Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC, 303 OptionalHeader->Subsystem, 304 OptionalHeader->ImageBase, FREELDR_PE_BASE, 305 OptionalHeader->SizeOfImage, MAX_FREELDR_PE_SIZE, 306 OptionalHeader->SectionAlignment, OptionalHeader->FileAlignment); 307 } 308 309 /* Calculate the full image size */ 310 FrLdrImageSize = (ULONG_PTR)&__ImageBase + OptionalHeader->SizeOfImage - FREELDR_BASE; 311 } 312 313 BOOLEAN MmInitializeMemoryManager(VOID) 314 { 315 #if DBG 316 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL; 317 #endif 318 319 TRACE("Initializing Memory Manager.\n"); 320 321 /* Check the freeldr binary */ 322 MmCheckFreeldrImageFile(); 323 324 BiosMemoryMap = MachVtbl.GetMemoryMap(&BiosMemoryMapEntryCount); 325 326 #if DBG 327 // Dump the system memory map 328 TRACE("System Memory Map (Base Address, Length, Type):\n"); 329 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) 330 { 331 TRACE("%x\t %x\t %s\n", 332 MemoryDescriptor->BasePage * MM_PAGE_SIZE, 333 MemoryDescriptor->PageCount * MM_PAGE_SIZE, 334 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType)); 335 } 336 #endif 337 338 // Find address for the page lookup table 339 TotalPagesInLookupTable = MmGetAddressablePageCountIncludingHoles(); 340 PageLookupTableAddress = MmFindLocationForPageLookupTable(TotalPagesInLookupTable); 341 LastFreePageHint = MmHighestPhysicalPage; 342 343 if (PageLookupTableAddress == 0) 344 { 345 // If we get here then we probably couldn't 346 // find a contiguous chunk of memory big 347 // enough to hold the page lookup table 348 printf("Error initializing memory manager!\n"); 349 return FALSE; 350 } 351 352 // Initialize the page lookup table 353 MmInitPageLookupTable(PageLookupTableAddress, TotalPagesInLookupTable); 354 355 MmUpdateLastFreePageHint(PageLookupTableAddress, TotalPagesInLookupTable); 356 357 FreePagesInLookupTable = MmCountFreePagesInLookupTable(PageLookupTableAddress, 358 TotalPagesInLookupTable); 359 360 MmInitializeHeap(PageLookupTableAddress); 361 362 TRACE("Memory Manager initialized. 0x%x pages available.\n", FreePagesInLookupTable); 363 364 365 return TRUE; 366 } 367 368 369 PFN_NUMBER MmGetPageNumberFromAddress(PVOID Address) 370 { 371 return ((ULONG_PTR)Address) / MM_PAGE_SIZE; 372 } 373 374 PFN_NUMBER MmGetAddressablePageCountIncludingHoles(VOID) 375 { 376 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL; 377 PFN_NUMBER PageCount; 378 379 // 380 // Go through the whole memory map to get max address 381 // 382 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) 383 { 384 // 385 // Check if we got a higher end page address 386 // 387 if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount > MmHighestPhysicalPage) 388 { 389 // 390 // Yes, remember it if this is real memory 391 // 392 if (MemoryDescriptor->MemoryType == LoaderFree) 393 MmHighestPhysicalPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount; 394 } 395 396 // 397 // Check if we got a higher (usable) start page address 398 // 399 if (MemoryDescriptor->BasePage < MmLowestPhysicalPage) 400 { 401 // 402 // Yes, remember it if this is real memory 403 // 404 MmLowestPhysicalPage = MemoryDescriptor->BasePage; 405 } 406 } 407 408 TRACE("lo/hi %lx %lx\n", MmLowestPhysicalPage, MmHighestPhysicalPage); 409 PageCount = MmHighestPhysicalPage - MmLowestPhysicalPage; 410 TRACE("MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", PageCount); 411 return PageCount; 412 } 413 414 PVOID MmFindLocationForPageLookupTable(PFN_NUMBER TotalPageCount) 415 { 416 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL; 417 SIZE_T PageLookupTableSize; 418 PFN_NUMBER RequiredPages; 419 PFN_NUMBER CandidateBasePage = 0; 420 PFN_NUMBER CandidatePageCount; 421 PFN_NUMBER PageLookupTableEndPage; 422 PVOID PageLookupTableMemAddress = NULL; 423 424 // Calculate how much pages we need to keep the page lookup table 425 PageLookupTableSize = TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM); 426 RequiredPages = PageLookupTableSize / MM_PAGE_SIZE; 427 428 // Search the highest memory block big enough to contain lookup table 429 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) 430 { 431 // Continue, if memory is not free 432 if (MemoryDescriptor->MemoryType != LoaderFree) continue; 433 434 // Continue, if the block is not big enough 435 if (MemoryDescriptor->PageCount < RequiredPages) continue; 436 437 // Continue, if it is not at a higher address than previous address 438 if (MemoryDescriptor->BasePage < CandidateBasePage) continue; 439 440 // Continue, if the address is too high 441 if (MemoryDescriptor->BasePage + RequiredPages >= MM_MAX_PAGE) continue; 442 443 // Memory block is more suitable than the previous one 444 CandidateBasePage = MemoryDescriptor->BasePage; 445 CandidatePageCount = MemoryDescriptor->PageCount; 446 } 447 448 // Calculate the end address for the lookup table 449 PageLookupTableEndPage = min(CandidateBasePage + CandidatePageCount, 450 MM_MAX_PAGE); 451 452 // Calculate the virtual address 453 PageLookupTableMemAddress = (PVOID)((PageLookupTableEndPage * PAGE_SIZE) 454 - PageLookupTableSize); 455 456 TRACE("MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress); 457 458 return PageLookupTableMemAddress; 459 } 460 461 VOID MmInitPageLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount) 462 { 463 const FREELDR_MEMORY_DESCRIPTOR* MemoryDescriptor = NULL; 464 PFN_NUMBER PageLookupTableStartPage; 465 PFN_NUMBER PageLookupTablePageCount; 466 467 TRACE("MmInitPageLookupTable()\n"); 468 469 // Mark every page as allocated initially 470 // We will go through and mark pages again according to the memory map 471 // But this will mark any holes not described in the map as allocated 472 MmMarkPagesInLookupTable(PageLookupTable, MmLowestPhysicalPage, TotalPageCount, LoaderFirmwarePermanent); 473 474 // Parse the whole memory map 475 while ((MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor)) != NULL) 476 { 477 // Mark used pages in the lookup table 478 479 if (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount <= TotalPageCount) 480 { 481 TRACE("Marking pages 0x%lx-0x%lx as type %s\n", 482 MemoryDescriptor->BasePage, 483 MemoryDescriptor->BasePage + MemoryDescriptor->PageCount, 484 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType)); 485 MmMarkPagesInLookupTable(PageLookupTable, 486 MemoryDescriptor->BasePage, 487 MemoryDescriptor->PageCount, 488 MemoryDescriptor->MemoryType); 489 } 490 else 491 TRACE("Ignoring pages 0x%lx-0x%lx (%s)\n", 492 MemoryDescriptor->BasePage, 493 MemoryDescriptor->BasePage + MemoryDescriptor->PageCount, 494 MmGetSystemMemoryMapTypeString(MemoryDescriptor->MemoryType)); 495 } 496 497 // Mark the pages that the lookup table occupies as reserved 498 PageLookupTableStartPage = MmGetPageNumberFromAddress(PageLookupTable); 499 PageLookupTablePageCount = MmGetPageNumberFromAddress((PVOID)((ULONG_PTR)PageLookupTable + ROUND_UP(TotalPageCount * sizeof(PAGE_LOOKUP_TABLE_ITEM), MM_PAGE_SIZE))) - PageLookupTableStartPage; 500 TRACE("Marking the page lookup table pages as reserved StartPage: 0x%x PageCount: 0x%x\n", PageLookupTableStartPage, PageLookupTablePageCount); 501 MmMarkPagesInLookupTable(PageLookupTable, PageLookupTableStartPage, PageLookupTablePageCount, LoaderFirmwareTemporary); 502 } 503 504 VOID MmMarkPagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY PageAllocated) 505 { 506 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 507 PFN_NUMBER Index; 508 TRACE("MmMarkPagesInLookupTable()\n"); 509 510 /* Validate the range */ 511 if ((StartPage < MmLowestPhysicalPage) || 512 ((StartPage + PageCount - 1) > MmHighestPhysicalPage)) 513 { 514 ERR("Memory (0x%lx:0x%lx) outside of lookup table! Valid range: 0x%lx-0x%lx.\n", 515 StartPage, PageCount, MmLowestPhysicalPage, MmHighestPhysicalPage); 516 return; 517 } 518 519 StartPage -= MmLowestPhysicalPage; 520 for (Index=StartPage; Index<(StartPage+PageCount); Index++) 521 { 522 #if 0 523 if ((Index <= (StartPage + 16)) || (Index >= (StartPage+PageCount-16))) 524 { 525 TRACE("Index = 0x%x StartPage = 0x%x PageCount = 0x%x\n", Index, StartPage, PageCount); 526 } 527 #endif 528 RealPageLookupTable[Index].PageAllocated = PageAllocated; 529 RealPageLookupTable[Index].PageAllocationLength = (PageAllocated != LoaderFree) ? 1 : 0; 530 } 531 TRACE("MmMarkPagesInLookupTable() Done\n"); 532 } 533 534 VOID MmAllocatePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER StartPage, PFN_NUMBER PageCount, TYPE_OF_MEMORY MemoryType) 535 { 536 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 537 PFN_NUMBER Index; 538 539 StartPage -= MmLowestPhysicalPage; 540 for (Index=StartPage; Index<(StartPage+PageCount); Index++) 541 { 542 RealPageLookupTable[Index].PageAllocated = MemoryType; 543 RealPageLookupTable[Index].PageAllocationLength = (Index == StartPage) ? PageCount : 0; 544 } 545 } 546 547 PFN_NUMBER MmCountFreePagesInLookupTable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount) 548 { 549 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 550 PFN_NUMBER Index; 551 PFN_NUMBER FreePageCount; 552 553 FreePageCount = 0; 554 for (Index=0; Index<TotalPageCount; Index++) 555 { 556 if (RealPageLookupTable[Index].PageAllocated == LoaderFree) 557 { 558 FreePageCount++; 559 } 560 } 561 562 return FreePageCount; 563 } 564 565 PFN_NUMBER MmFindAvailablePages(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, BOOLEAN FromEnd) 566 { 567 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 568 PFN_NUMBER AvailablePagesSoFar; 569 PFN_NUMBER Index; 570 571 if (LastFreePageHint > TotalPageCount) 572 { 573 LastFreePageHint = TotalPageCount; 574 } 575 576 AvailablePagesSoFar = 0; 577 if (FromEnd) 578 { 579 /* Allocate "high" (from end) pages */ 580 for (Index=LastFreePageHint-1; Index>0; Index--) 581 { 582 if (RealPageLookupTable[Index].PageAllocated != LoaderFree) 583 { 584 AvailablePagesSoFar = 0; 585 continue; 586 } 587 else 588 { 589 AvailablePagesSoFar++; 590 } 591 592 if (AvailablePagesSoFar >= PagesNeeded) 593 { 594 return Index + MmLowestPhysicalPage; 595 } 596 } 597 } 598 else 599 { 600 TRACE("Alloc low memory, LastFreePageHint 0x%x, TPC 0x%x\n", LastFreePageHint, TotalPageCount); 601 /* Allocate "low" pages */ 602 for (Index=1; Index < LastFreePageHint; Index++) 603 { 604 if (RealPageLookupTable[Index].PageAllocated != LoaderFree) 605 { 606 AvailablePagesSoFar = 0; 607 continue; 608 } 609 else 610 { 611 AvailablePagesSoFar++; 612 } 613 614 if (AvailablePagesSoFar >= PagesNeeded) 615 { 616 return Index - AvailablePagesSoFar + 1 + MmLowestPhysicalPage; 617 } 618 } 619 } 620 621 return 0; 622 } 623 624 PFN_NUMBER MmFindAvailablePagesBeforePage(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PFN_NUMBER PagesNeeded, PFN_NUMBER LastPage) 625 { 626 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 627 PFN_NUMBER AvailablePagesSoFar; 628 PFN_NUMBER Index; 629 630 if (LastPage > TotalPageCount) 631 { 632 return MmFindAvailablePages(PageLookupTable, TotalPageCount, PagesNeeded, TRUE); 633 } 634 635 AvailablePagesSoFar = 0; 636 for (Index=LastPage-1; Index>0; Index--) 637 { 638 if (RealPageLookupTable[Index].PageAllocated != LoaderFree) 639 { 640 AvailablePagesSoFar = 0; 641 continue; 642 } 643 else 644 { 645 AvailablePagesSoFar++; 646 } 647 648 if (AvailablePagesSoFar >= PagesNeeded) 649 { 650 return Index + MmLowestPhysicalPage; 651 } 652 } 653 654 return 0; 655 } 656 657 VOID MmUpdateLastFreePageHint(PVOID PageLookupTable, PFN_NUMBER TotalPageCount) 658 { 659 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 660 PFN_NUMBER Index; 661 662 for (Index=TotalPageCount-1; Index>0; Index--) 663 { 664 if (RealPageLookupTable[Index].PageAllocated == LoaderFree) 665 { 666 LastFreePageHint = Index + 1 + MmLowestPhysicalPage; 667 break; 668 } 669 } 670 } 671 672 BOOLEAN MmAreMemoryPagesAvailable(PVOID PageLookupTable, PFN_NUMBER TotalPageCount, PVOID PageAddress, PFN_NUMBER PageCount) 673 { 674 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTable; 675 PFN_NUMBER StartPage; 676 PFN_NUMBER Index; 677 678 StartPage = MmGetPageNumberFromAddress(PageAddress); 679 680 if (StartPage < MmLowestPhysicalPage) return FALSE; 681 682 StartPage -= MmLowestPhysicalPage; 683 684 // Make sure they aren't trying to go past the 685 // end of available memory 686 if ((StartPage + PageCount) > TotalPageCount) 687 { 688 return FALSE; 689 } 690 691 for (Index = StartPage; Index < (StartPage + PageCount); Index++) 692 { 693 // If this page is allocated then there obviously isn't 694 // memory available so return FALSE 695 if (RealPageLookupTable[Index].PageAllocated != LoaderFree) 696 { 697 return FALSE; 698 } 699 } 700 701 return TRUE; 702 } 703