1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Library 4 * FILE: boot/environ/lib/mm/pagealloc.c 5 * PURPOSE: Boot Library Memory Manager Page Allocator 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bl.h" 12 #include "bcd.h" 13 14 typedef struct _BL_PA_REQUEST 15 { 16 BL_ADDRESS_RANGE BaseRange; 17 BL_ADDRESS_RANGE VirtualRange; 18 ULONG Type; 19 ULONGLONG Pages; 20 ULONG MemoryType; 21 ULONG Alignment; 22 ULONG Flags; 23 } BL_PA_REQUEST, *PBL_PA_REQUEST; 24 25 /* DATA VARIABLES ************************************************************/ 26 27 extern ULONG MmArchLargePageSize; 28 29 ULONGLONG PapMaximumPhysicalPage, PapMinimumPhysicalPage; 30 31 ULONG PapMinimumAllocationCount; 32 33 BOOLEAN PapInitializationStatus; 34 35 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappedAllocated; 36 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappedUnallocated; 37 BL_MEMORY_DESCRIPTOR_LIST MmMdlFwAllocationTracker; 38 BL_MEMORY_DESCRIPTOR_LIST MmMdlUnmappedAllocated; 39 BL_MEMORY_DESCRIPTOR_LIST MmMdlUnmappedUnallocated; 40 BL_MEMORY_DESCRIPTOR_LIST MmMdlReservedAllocated; 41 BL_MEMORY_DESCRIPTOR_LIST MmMdlBadMemory; 42 BL_MEMORY_DESCRIPTOR_LIST MmMdlTruncatedMemory; 43 BL_MEMORY_DESCRIPTOR_LIST MmMdlPersistentMemory; 44 BL_MEMORY_DESCRIPTOR_LIST MmMdlCompleteBadMemory; 45 BL_MEMORY_DESCRIPTOR_LIST MmMdlFreeVirtual; 46 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappingTrackers; 47 48 /* FUNCTIONS *****************************************************************/ 49 50 NTSTATUS 51 MmPaTruncateMemory ( 52 _In_ ULONGLONG BasePage 53 ) 54 { 55 NTSTATUS Status; 56 57 /* Increase nesting depth */ 58 ++MmDescriptorCallTreeCount; 59 60 /* Set the maximum page to the truncated request */ 61 if (BasePage < PapMaximumPhysicalPage) 62 { 63 PapMaximumPhysicalPage = BasePage; 64 } 65 66 /* Truncate mapped and allocated memory */ 67 Status = MmMdTruncateDescriptors(&MmMdlMappedAllocated, 68 &MmMdlTruncatedMemory, 69 BasePage); 70 if (NT_SUCCESS(Status)) 71 { 72 /* Truncate unmapped and allocated memory */ 73 Status = MmMdTruncateDescriptors(&MmMdlUnmappedAllocated, 74 &MmMdlTruncatedMemory, 75 BasePage); 76 if (NT_SUCCESS(Status)) 77 { 78 /* Truncate mapped and unallocated memory */ 79 Status = MmMdTruncateDescriptors(&MmMdlMappedUnallocated, 80 &MmMdlTruncatedMemory, 81 BasePage); 82 if (NT_SUCCESS(Status)) 83 { 84 /* Truncate unmapped and unallocated memory */ 85 Status = MmMdTruncateDescriptors(&MmMdlUnmappedUnallocated, 86 &MmMdlTruncatedMemory, 87 BasePage); 88 if (NT_SUCCESS(Status)) 89 { 90 /* Truncate reserved memory */ 91 Status = MmMdTruncateDescriptors(&MmMdlReservedAllocated, 92 &MmMdlTruncatedMemory, 93 BasePage); 94 } 95 } 96 } 97 } 98 99 /* Restore the nesting depth */ 100 MmMdFreeGlobalDescriptors(); 101 --MmDescriptorCallTreeCount; 102 return Status; 103 } 104 105 NTSTATUS 106 BlpMmInitializeConstraints ( 107 VOID 108 ) 109 { 110 NTSTATUS Status, ReturnStatus; 111 ULONGLONG LowestAddressValid, HighestAddressValid; 112 ULONGLONG LowestPage, HighestPage; 113 114 /* Assume success */ 115 ReturnStatus = STATUS_SUCCESS; 116 117 /* Check for LOWMEM */ 118 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData, 119 BcdLibraryInteger_AvoidLowPhysicalMemory, 120 &LowestAddressValid); 121 if (NT_SUCCESS(Status)) 122 { 123 /* Align the address */ 124 LowestAddressValid = (ULONG_PTR)PAGE_ALIGN(LowestAddressValid); 125 LowestPage = LowestAddressValid >> PAGE_SHIFT; 126 127 /* Make sure it's below 4GB */ 128 if (LowestPage <= 0x100000) 129 { 130 PapMinimumPhysicalPage = LowestPage; 131 } 132 } 133 134 /* Check for MAXMEM */ 135 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData, 136 BcdLibraryInteger_TruncatePhysicalMemory, 137 &HighestAddressValid); 138 if (NT_SUCCESS(Status)) 139 { 140 /* Get the page */ 141 HighestPage = HighestAddressValid >> PAGE_SHIFT; 142 143 /* Truncate memory above this page */ 144 ReturnStatus = MmPaTruncateMemory(HighestPage); 145 } 146 147 /* Return back to the caller */ 148 return ReturnStatus; 149 } 150 151 PWCHAR 152 MmMdListPointerToName (_In_ PBL_MEMORY_DESCRIPTOR_LIST MdList) 153 { 154 if (MdList == &MmMdlUnmappedAllocated) 155 { 156 return L"UnmapAlloc"; 157 } 158 else if (MdList == &MmMdlUnmappedUnallocated) 159 { 160 return L"UnmapUnalloc"; 161 } 162 else if (MdList == &MmMdlMappedAllocated) 163 { 164 return L"MapAlloc"; 165 } 166 else if (MdList == &MmMdlMappedUnallocated) 167 { 168 return L"MapUnalloc"; 169 } 170 else 171 { 172 return L"Other"; 173 } 174 } 175 176 NTSTATUS 177 MmPapAllocateRegionFromMdl ( 178 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList, 179 _Out_opt_ PBL_MEMORY_DESCRIPTOR Descriptor, 180 _In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList, 181 _In_ PBL_PA_REQUEST Request, 182 _In_ BL_MEMORY_TYPE Type 183 ) 184 { 185 NTSTATUS Status; 186 BL_MEMORY_DESCRIPTOR LocalDescriptor = {{0}}; 187 PBL_MEMORY_DESCRIPTOR FoundDescriptor, TempDescriptor; 188 PLIST_ENTRY ListHead, NextEntry; 189 BOOLEAN TopDown, GotFwPages; 190 EFI_PHYSICAL_ADDRESS EfiAddress; 191 ULONGLONG LocalEndPage, FoundEndPage, LocalVirtualEndPage; 192 193 /* Check if any parameters were not passed in correctly */ 194 if (!(CurrentList) || !(Request) || (!(NewList) && !(Descriptor))) 195 { 196 return STATUS_INVALID_PARAMETER; 197 } 198 199 /* Set failure by default */ 200 Status = STATUS_NO_MEMORY; 201 202 /* Take the head and next entry in the list, as appropriate */ 203 ListHead = CurrentList->First; 204 if (Request->Type & BL_MM_REQUEST_TOP_DOWN_TYPE) 205 { 206 NextEntry = ListHead->Blink; 207 TopDown = TRUE; 208 } 209 else 210 { 211 NextEntry = ListHead->Flink; 212 TopDown = FALSE; 213 } 214 215 /* Loop through the list */ 216 GotFwPages = FALSE; 217 while (NextEntry != ListHead) 218 { 219 /* Grab a descriptor */ 220 FoundDescriptor = CONTAINING_RECORD(NextEntry, 221 BL_MEMORY_DESCRIPTOR, 222 ListEntry); 223 224 /* See if it matches the request */ 225 if (MmMdFindSatisfyingRegion(FoundDescriptor, 226 &LocalDescriptor, 227 Request->Pages, 228 &Request->BaseRange, 229 &Request->VirtualRange, 230 TopDown, 231 Request->MemoryType, 232 Request->Flags, 233 Request->Alignment)) 234 { 235 break; 236 } 237 238 /* It doesn't, move to the next appropriate entry */ 239 if (TopDown) 240 { 241 NextEntry = NextEntry->Blink; 242 } 243 else 244 { 245 NextEntry = NextEntry->Flink; 246 } 247 } 248 249 /* Check if we exhausted the list */ 250 if (NextEntry == ListHead) 251 { 252 return Status; 253 } 254 255 /* Copy all the flags that are not request flag */ 256 LocalDescriptor.Flags = (Request->Flags & 0xFFFF0000) | 257 (LocalDescriptor.Flags & 0x0000FFFF); 258 259 /* Are we using the physical memory list, and are we OK with using firmware? */ 260 if ((CurrentList == &MmMdlUnmappedUnallocated) && 261 !((Request->Flags & BlMemoryNonFirmware) || 262 (LocalDescriptor.Flags & BlMemoryNonFirmware))) 263 { 264 /* Allocate the requested address from EFI */ 265 EfiAddress = LocalDescriptor.BasePage << PAGE_SHIFT; 266 Status = EfiAllocatePages(AllocateAddress, 267 (ULONG)LocalDescriptor.PageCount, 268 &EfiAddress); 269 if (!NT_SUCCESS(Status)) 270 { 271 EfiPrintf(L"EFI memory allocation failure\r\n"); 272 EfiStall(10000000); 273 return Status; 274 } 275 276 /* Remember we got memory from EFI */ 277 GotFwPages = TRUE; 278 } 279 280 /* Remove the descriptor from the original list it was on */ 281 MmMdRemoveDescriptorFromList(CurrentList, FoundDescriptor); 282 283 /* Get the end pages */ 284 LocalEndPage = LocalDescriptor.PageCount + LocalDescriptor.BasePage; 285 FoundEndPage = FoundDescriptor->PageCount + FoundDescriptor->BasePage; 286 287 /* Are we allocating from the virtual memory list? */ 288 if (CurrentList == &MmMdlMappedUnallocated) 289 { 290 /* Check if the region matches perfectly */ 291 if ((LocalDescriptor.BasePage == FoundDescriptor->BasePage) && 292 (LocalEndPage == FoundEndPage)) 293 { 294 /* Check if the original descriptor had the flag set */ 295 if ((FoundDescriptor->Flags & 0x40000000) && (Descriptor)) 296 { 297 /* Make our local one have it too, even if not needed */ 298 LocalDescriptor.Flags |= 0x40000000; 299 } 300 } 301 else 302 { 303 /* Write the 'incomplete mapping' flag */ 304 FoundDescriptor->Flags |= 0x40000000; 305 if (Descriptor) 306 { 307 /* Including on the local one if there's one passed in */ 308 LocalDescriptor.Flags |= 0x40000000; 309 } 310 } 311 } 312 313 /* Does the memory we received not exactly fall onto the beginning of its descriptor? */ 314 if (LocalDescriptor.BasePage != FoundDescriptor->BasePage) 315 { 316 TempDescriptor = MmMdInitByteGranularDescriptor(FoundDescriptor->Flags, 317 FoundDescriptor->Type, 318 FoundDescriptor->BasePage, 319 FoundDescriptor->VirtualPage, 320 LocalDescriptor.BasePage - 321 FoundDescriptor->BasePage); 322 Status = MmMdAddDescriptorToList(CurrentList, TempDescriptor, 0); 323 if (!NT_SUCCESS(Status)) 324 { 325 return Status; 326 } 327 } 328 329 /* Does the memory we received not exactly fall onto the end of its descriptor? */ 330 LocalVirtualEndPage = LocalDescriptor.VirtualPage ? 331 LocalDescriptor.VirtualPage + LocalDescriptor.PageCount : 0; 332 if (LocalEndPage != FoundEndPage) 333 { 334 TempDescriptor = MmMdInitByteGranularDescriptor(FoundDescriptor->Flags, 335 FoundDescriptor->Type, 336 LocalEndPage, 337 LocalVirtualEndPage, 338 FoundEndPage - LocalEndPage); 339 Status = MmMdAddDescriptorToList(CurrentList, TempDescriptor, 0); 340 if (!NT_SUCCESS(Status)) 341 { 342 return Status; 343 } 344 } 345 346 /* We got the memory we needed */ 347 Status = STATUS_SUCCESS; 348 349 /* Are we supposed to insert it into a new list? */ 350 if (NewList) 351 { 352 /* Copy the allocated region descriptor into the one we found */ 353 FoundDescriptor->BaseAddress = LocalDescriptor.BaseAddress; 354 FoundDescriptor->VirtualPage = LocalDescriptor.VirtualPage; 355 FoundDescriptor->PageCount = LocalDescriptor.PageCount; 356 FoundDescriptor->Type = Type; 357 FoundDescriptor->Flags = LocalDescriptor.Flags; 358 359 /* Remember if it came from EFI */ 360 if (GotFwPages) 361 { 362 FoundDescriptor->Flags |= BlMemoryFirmware; 363 } 364 365 /* Add the descriptor to the requested list */ 366 Status = MmMdAddDescriptorToList(NewList, FoundDescriptor, 0); 367 } 368 else 369 { 370 /* Free the descriptor, nobody wants to know about it anymore */ 371 MmMdFreeDescriptor(FoundDescriptor); 372 } 373 374 /* Return the allocation region back */ 375 RtlCopyMemory(Descriptor, &LocalDescriptor, sizeof(LocalDescriptor)); 376 return Status; 377 } 378 379 NTSTATUS 380 MmPaAllocatePages ( 381 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList, 382 _In_ PBL_MEMORY_DESCRIPTOR Descriptor, 383 _In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList, 384 _In_ PBL_PA_REQUEST Request, 385 _In_ BL_MEMORY_TYPE MemoryType 386 ) 387 { 388 NTSTATUS Status; 389 390 /* Heap and page directory/table pages have a special flag */ 391 if ((MemoryType >= BlLoaderHeap) && (MemoryType <= BlLoaderReferencePage)) 392 { 393 Request->Flags |= BlMemorySpecial; 394 } 395 396 /* Try to find a free region of RAM matching this range and request */ 397 Request->MemoryType = BlConventionalMemory; 398 Status = MmPapAllocateRegionFromMdl(NewList, 399 Descriptor, 400 CurrentList, 401 Request, 402 MemoryType); 403 if (Status == STATUS_NOT_FOUND) 404 { 405 /* Need to re-synchronize the memory map and check other lists */ 406 EfiPrintf(L"No RAM found -- backup plan not yet implemented\r\n"); 407 } 408 409 /* Did we get the region we wanted? */ 410 if (NT_SUCCESS(Status)) 411 { 412 /* All good, return back */ 413 return Status; 414 } 415 416 /* Are we failing due to some attributes? */ 417 if (Request->Flags & BlMemoryValidAllocationAttributeMask) 418 { 419 if (Request->Flags & BlMemoryLargePages) 420 { 421 EfiPrintf(L"large alloc fail not yet implemented %lx\r\n", Status); 422 EfiStall(1000000); 423 return STATUS_NOT_IMPLEMENTED; 424 } 425 if (Request->Flags & BlMemoryFixed) 426 { 427 EfiPrintf(L"fixed alloc fail not yet implemented %lx\r\n", Status); 428 EfiStall(1000000); 429 return STATUS_NOT_IMPLEMENTED; 430 } 431 } 432 433 /* Nope, just fail the entire call */ 434 return Status; 435 } 436 437 NTSTATUS 438 MmPapAllocatePhysicalPagesInRange ( 439 _Inout_ PPHYSICAL_ADDRESS BaseAddress, 440 _In_ BL_MEMORY_TYPE MemoryType, 441 _In_ ULONGLONG Pages, 442 _In_ ULONG Attributes, 443 _In_ ULONG Alignment, 444 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList, 445 _In_opt_ PBL_ADDRESS_RANGE Range, 446 _In_ ULONG RangeType 447 ) 448 { 449 NTSTATUS Status; 450 BL_PA_REQUEST Request; 451 BL_MEMORY_DESCRIPTOR Descriptor; 452 453 /* Increase nesting depth */ 454 ++MmDescriptorCallTreeCount; 455 456 /* Bail out if no address was specified */ 457 if (!BaseAddress) 458 { 459 Status = STATUS_INVALID_PARAMETER; 460 goto Quickie; 461 } 462 463 /* Bail out if no page count was passed in, or a bad list was specified */ 464 if (!(Pages) || 465 ((NewList != &MmMdlUnmappedAllocated) && 466 (NewList != &MmMdlPersistentMemory))) 467 { 468 Status = STATUS_INVALID_PARAMETER; 469 goto Quickie; 470 } 471 472 /* Bail out if the passed in range is invalid */ 473 if ((Range) && (Range->Minimum >= Range->Maximum)) 474 { 475 Status = STATUS_INVALID_PARAMETER; 476 goto Quickie; 477 } 478 479 /* Adjust alignment as needed */ 480 if (!Alignment) 481 { 482 Alignment = 1; 483 } 484 485 /* Clear the virtual range */ 486 Request.VirtualRange.Minimum = 0; 487 Request.VirtualRange.Maximum = 0; 488 489 /* Check if a fixed allocation was requested*/ 490 if (Attributes & BlMemoryFixed) 491 { 492 /* Force the only available range to be the passed in address */ 493 Request.BaseRange.Minimum = BaseAddress->QuadPart >> PAGE_SHIFT; 494 Request.BaseRange.Maximum = Request.BaseRange.Minimum + Pages - 1; 495 } 496 else if (Range) 497 { 498 /* Otherwise, a manual range was specified, use it */ 499 Request.BaseRange.Minimum = Range->Minimum >> PAGE_SHIFT; 500 Request.BaseRange.Maximum = Request.BaseRange.Minimum + 501 (Range->Maximum >> PAGE_SHIFT) - 1; 502 } 503 else 504 { 505 /* Otherwise, use any possible range of pages */ 506 Request.BaseRange.Minimum = PapMinimumPhysicalPage; 507 Request.BaseRange.Maximum = MAXULONG >> PAGE_SHIFT; 508 } 509 510 /* Check if no type was specified, or if it was invalid */ 511 if (!(RangeType) || 512 (RangeType & ~(BL_MM_REQUEST_TOP_DOWN_TYPE | BL_MM_REQUEST_DEFAULT_TYPE))) 513 { 514 /* Use default type */ 515 Request.Type = BL_MM_REQUEST_DEFAULT_TYPE; 516 } 517 else 518 { 519 /* Use the requested type */ 520 Request.Type = RangeType; 521 } 522 523 /* Capture the other request parameters */ 524 Request.Alignment = Alignment; 525 Request.Pages = Pages; 526 Request.Flags = Attributes; 527 Status = MmPaAllocatePages(NewList, 528 &Descriptor, 529 &MmMdlUnmappedUnallocated, 530 &Request, 531 MemoryType); 532 if (NT_SUCCESS(Status)) 533 { 534 /* We got a descriptor back, return its address */ 535 BaseAddress->QuadPart = Descriptor.BasePage << PAGE_SHIFT; 536 } 537 538 Quickie: 539 /* Restore the nesting depth */ 540 MmMdFreeGlobalDescriptors(); 541 --MmDescriptorCallTreeCount; 542 return Status; 543 } 544 545 NTSTATUS 546 MmPapPageAllocatorExtend ( 547 _In_ ULONG Attributes, 548 _In_ ULONG Alignment, 549 _In_ ULONGLONG PageCount, 550 _In_ ULONGLONG VirtualPage, 551 _In_opt_ PBL_ADDRESS_RANGE Range, 552 _In_opt_ ULONG Type 553 ) 554 { 555 BL_PA_REQUEST Request; 556 ULONGLONG PageRange; 557 BL_MEMORY_DESCRIPTOR NewDescriptor; 558 ULONG AllocationFlags, CacheAttributes, AddFlags; 559 NTSTATUS Status; 560 PBL_MEMORY_DESCRIPTOR_LIST MdList; 561 PBL_MEMORY_DESCRIPTOR Descriptor; 562 PVOID VirtualAddress; 563 PHYSICAL_ADDRESS PhysicalAddress; 564 565 /* Is the caller requesting less pages than allowed? */ 566 if (!(Attributes & BlMemoryFixed) && 567 !(Range) && 568 (PageCount < PapMinimumAllocationCount)) 569 { 570 /* Unless this is a fixed request, then adjust the original requirements */ 571 PageCount = PapMinimumAllocationCount; 572 Alignment = PapMinimumAllocationCount; 573 } 574 575 /* Extract only the allocation attributes */ 576 AllocationFlags = Attributes & BlMemoryValidAllocationAttributeMask; 577 578 /* Check if the caller wants large pages */ 579 if ((AllocationFlags & BlMemoryLargePages) && (MmArchLargePageSize != 1)) 580 { 581 EfiPrintf(L"Large pages not supported!\r\n"); 582 EfiStall(10000000); 583 return STATUS_NOT_IMPLEMENTED; 584 } 585 586 /* Set an emty virtual range */ 587 Request.VirtualRange.Minimum = 0; 588 Request.VirtualRange.Maximum = 0; 589 590 /* Check if the caller requested a range */ 591 if (Range) 592 { 593 /* Calculate it size in pages, minus a page as this is a 0-based range */ 594 PageRange = ((Range->Maximum - Range->Minimum) >> PAGE_SHIFT) - 1; 595 596 /* Set the minimum and maximum, in pages */ 597 Request.BaseRange.Minimum = Range->Minimum >> PAGE_SHIFT; 598 Request.BaseRange.Maximum = Request.BaseRange.Minimum + PageRange; 599 } 600 else 601 { 602 /* Initialize a range from the smallest page to the biggest */ 603 Request.BaseRange.Minimum = PapMinimumPhysicalPage; 604 Request.BaseRange.Maximum = 0xFFFFFFFF / PAGE_SIZE; 605 } 606 607 /* Get the cache attributes */ 608 CacheAttributes = Attributes & BlMemoryValidCacheAttributeMask; 609 610 /* Check if the caller requested a valid allocation type */ 611 if ((Type) && !(Type & ~(BL_MM_REQUEST_DEFAULT_TYPE | 612 BL_MM_REQUEST_TOP_DOWN_TYPE))) 613 { 614 /* Use what the caller wanted */ 615 Request.Type = Type; 616 } 617 else 618 { 619 /* Use the default bottom-up type */ 620 Request.Type = BL_MM_REQUEST_DEFAULT_TYPE; 621 } 622 623 /* Use the original protection and type, but ignore other attributes */ 624 Request.Flags = Attributes & ~(BlMemoryValidAllocationAttributeMask | 625 BlMemoryValidCacheAttributeMask); 626 Request.Alignment = Alignment; 627 Request.Pages = PageCount; 628 629 /* Allocate some free pages */ 630 Status = MmPaAllocatePages(NULL, 631 &NewDescriptor, 632 &MmMdlUnmappedUnallocated, 633 &Request, 634 BlConventionalMemory); 635 if (!NT_SUCCESS(Status)) 636 { 637 EfiPrintf(L"Failed to get unmapped, unallocated memory!\r\n"); 638 EfiStall(10000000); 639 return Status; 640 } 641 642 /* Initialize a descriptor for these pages, adding in the allocation flags */ 643 Descriptor = MmMdInitByteGranularDescriptor(AllocationFlags | 644 NewDescriptor.Flags, 645 BlConventionalMemory, 646 NewDescriptor.BasePage, 647 NewDescriptor.VirtualPage, 648 NewDescriptor.PageCount); 649 650 /* Now map a virtual address for these physical pages */ 651 VirtualAddress = (PVOID)((ULONG_PTR)VirtualPage << PAGE_SHIFT); 652 PhysicalAddress.QuadPart = NewDescriptor.BasePage << PAGE_SHIFT; 653 Status = BlMmMapPhysicalAddressEx(&VirtualAddress, 654 AllocationFlags | CacheAttributes, 655 NewDescriptor.PageCount << PAGE_SHIFT, 656 PhysicalAddress); 657 if (Status == STATUS_SUCCESS) 658 { 659 /* Add the cache attributes now that the mapping worked */ 660 Descriptor->Flags |= CacheAttributes; 661 662 /* Update the virtual page now that we mapped it */ 663 Descriptor->VirtualPage = (ULONG_PTR)VirtualAddress >> PAGE_SHIFT; 664 665 /* Add this as a mapped region */ 666 Status = MmMdAddDescriptorToList(&MmMdlMappedUnallocated, 667 Descriptor, 668 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG); 669 670 /* Make new descriptor that we'll add in firmware allocation tracker */ 671 MdList = &MmMdlFwAllocationTracker; 672 Descriptor = MmMdInitByteGranularDescriptor(0, 673 BlConventionalMemory, 674 NewDescriptor.BasePage, 675 0, 676 NewDescriptor.PageCount); 677 678 /* Do not coalesce */ 679 AddFlags = 0; 680 } 681 else 682 { 683 /* We failed, free the physical pages */ 684 Status = MmFwFreePages(NewDescriptor.BasePage, NewDescriptor.PageCount); 685 if (!NT_SUCCESS(Status)) 686 { 687 /* We failed to free the pages, so this is still around */ 688 MdList = &MmMdlUnmappedAllocated; 689 } 690 else 691 { 692 /* This is now back to unmapped/unallocated memory */ 693 Descriptor->Flags = 0; 694 MdList = &MmMdlUnmappedUnallocated; 695 } 696 697 /* Coalesce the free descriptor */ 698 AddFlags = BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG; 699 } 700 701 /* Either add to firmware list, or to unmapped list, then return result */ 702 MmMdAddDescriptorToList(MdList, Descriptor, AddFlags); 703 return Status; 704 } 705 706 NTSTATUS 707 MmPapAllocatePagesInRange ( 708 _Inout_ PVOID* PhysicalAddress, 709 _In_ BL_MEMORY_TYPE MemoryType, 710 _In_ ULONGLONG Pages, 711 _In_ ULONG Attributes, 712 _In_ ULONG Alignment, 713 _In_opt_ PBL_ADDRESS_RANGE Range, 714 _In_ ULONG Type 715 ) 716 { 717 NTSTATUS Status; 718 PHYSICAL_ADDRESS BaseAddress; 719 BL_PA_REQUEST Request; 720 PBL_MEMORY_DESCRIPTOR_LIST List; 721 BL_MEMORY_DESCRIPTOR Descriptor; 722 723 /* Increment nesting depth */ 724 ++MmDescriptorCallTreeCount; 725 726 /* Default list */ 727 List = &MmMdlMappedAllocated; 728 729 /* Check for missing parameters or invalid range */ 730 if (!(PhysicalAddress) || 731 !(Pages) || 732 ((Range) && (Range->Minimum >= Range->Maximum))) 733 { 734 Status = STATUS_INVALID_PARAMETER; 735 goto Exit; 736 } 737 738 /* What translation mode are we using? */ 739 if (MmTranslationType != BlNone) 740 { 741 /* Use 1 page alignment if none was requested */ 742 if (!Alignment) 743 { 744 Alignment = 1; 745 } 746 747 /* Check if we got a range */ 748 if (Range) 749 { 750 /* We don't support virtual memory yet @TODO */ 751 EfiPrintf(L"virt range not yet implemented in %S\r\n", __FUNCTION__); 752 EfiStall(1000000); 753 Status = STATUS_NOT_IMPLEMENTED; 754 goto Exit; 755 } 756 else 757 { 758 /* Use the entire range that's possible */ 759 Request.BaseRange.Minimum = PapMinimumPhysicalPage; 760 Request.BaseRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT; 761 } 762 763 /* Check if a fixed allocation was requested */ 764 if (Attributes & BlMemoryFixed) 765 { 766 /* We don't support virtual memory yet @TODO */ 767 EfiPrintf(L"fixed not yet implemented in %S\r\n", __FUNCTION__); 768 EfiStall(1000000); 769 Status = STATUS_NOT_IMPLEMENTED; 770 goto Exit; 771 } 772 else 773 { 774 /* Check if kernel range was specifically requested */ 775 if (Attributes & BlMemoryKernelRange) 776 { 777 /* Use the kernel range */ 778 Request.VirtualRange.Minimum = MmArchKsegAddressRange.Minimum >> PAGE_SHIFT; 779 Request.VirtualRange.Maximum = MmArchKsegAddressRange.Maximum >> PAGE_SHIFT; 780 } 781 else 782 { 783 /* Set the virtual address range */ 784 Request.VirtualRange.Minimum = 0; 785 Request.VirtualRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT; 786 } 787 } 788 789 /* Check what type of allocation was requested */ 790 if ((Type) && !(Type & ~(BL_MM_REQUEST_DEFAULT_TYPE | 791 BL_MM_REQUEST_TOP_DOWN_TYPE))) 792 { 793 /* Save it if it was valid */ 794 Request.Type = Type; 795 } 796 else 797 { 798 /* Set the default */ 799 Request.Type = BL_MM_REQUEST_DEFAULT_TYPE; 800 } 801 802 /* Fill out the request of the request */ 803 Request.Flags = Attributes; 804 Request.Alignment = Alignment; 805 Request.Pages = Pages; 806 807 /* Try to allocate the pages */ 808 Status = MmPaAllocatePages(List, 809 &Descriptor, 810 &MmMdlMappedUnallocated, 811 &Request, 812 MemoryType); 813 if (!NT_SUCCESS(Status)) 814 { 815 /* Extend the physical allocator */ 816 Status = MmPapPageAllocatorExtend(Attributes, 817 Alignment, 818 Pages, 819 ((ULONG_PTR)*PhysicalAddress) >> 820 PAGE_SHIFT, 821 Range, 822 Type); 823 if (!NT_SUCCESS(Status)) 824 { 825 /* Fail since we're out of memory */ 826 EfiPrintf(L"EXTEND OUT OF MEMORY: %lx\r\n", Status); 827 Status = STATUS_NO_MEMORY; 828 goto Exit; 829 } 830 831 /* Try the allocation again now */ 832 Status = MmPaAllocatePages(&MmMdlMappedAllocated, 833 &Descriptor, 834 &MmMdlMappedUnallocated, 835 &Request, 836 MemoryType); 837 if (!NT_SUCCESS(Status)) 838 { 839 /* Fail since we're out of memory */ 840 EfiPrintf(L"PALLOC OUT OF MEMORY: %lx\r\n", Status); 841 goto Exit; 842 } 843 } 844 845 /* Return the allocated address */ 846 *PhysicalAddress = (PVOID)((ULONG_PTR)Descriptor.VirtualPage << PAGE_SHIFT); 847 } 848 else 849 { 850 /* Check if this is a fixed allocation */ 851 BaseAddress.QuadPart = (Attributes & BlMemoryFixed) ? 852 (ULONG_PTR)*PhysicalAddress : 0; 853 854 /* Allocate the pages */ 855 Status = MmPapAllocatePhysicalPagesInRange(&BaseAddress, 856 MemoryType, 857 Pages, 858 Attributes, 859 Alignment, 860 (&MmMdlMappedAllocated != 861 &MmMdlPersistentMemory) ? 862 &MmMdlUnmappedAllocated : 863 &MmMdlMappedAllocated, 864 Range, 865 Type); 866 867 /* Return the allocated address */ 868 *PhysicalAddress = PhysicalAddressToPtr(BaseAddress); 869 } 870 871 Exit: 872 /* Restore the nesting depth */ 873 MmMdFreeGlobalDescriptors(); 874 --MmDescriptorCallTreeCount; 875 return Status; 876 } 877 878 NTSTATUS 879 MmPaInitialize ( 880 __in PBL_MEMORY_DATA BootMemoryData, 881 __in ULONG MinimumAllocationCount 882 ) 883 { 884 NTSTATUS Status; 885 ULONG ExistingDescriptors, FinalOffset; 886 PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor; 887 888 /* Initialize physical allocator variables */ 889 PapMaximumPhysicalPage = 0xFFFFFFFFFFFFF; 890 PapMinimumAllocationCount = MinimumAllocationCount; 891 PapMinimumPhysicalPage = 0; 892 893 /* Initialize all the lists */ 894 MmMdInitializeListHead(&MmMdlMappedAllocated); 895 MmMdInitializeListHead(&MmMdlMappedUnallocated); 896 MmMdInitializeListHead(&MmMdlFwAllocationTracker); 897 MmMdInitializeListHead(&MmMdlUnmappedAllocated); 898 MmMdInitializeListHead(&MmMdlReservedAllocated); 899 MmMdInitializeListHead(&MmMdlBadMemory); 900 MmMdInitializeListHead(&MmMdlTruncatedMemory); 901 MmMdInitializeListHead(&MmMdlPersistentMemory); 902 MmMdInitializeListHead(&MmMdlUnmappedUnallocated); 903 MmMdInitializeListHead(&MmMdlCompleteBadMemory); 904 905 /* Get the BIOS memory map */ 906 Status = MmFwGetMemoryMap(&MmMdlUnmappedUnallocated, 907 BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS | 908 BL_MM_FLAG_REQUEST_COALESCING); 909 if (NT_SUCCESS(Status)) 910 { 911 #if 0 912 PLIST_ENTRY listHead, nextEntry; 913 914 /* Loop the NT firmware memory list */ 915 EfiPrintf(L"NT MEMORY MAP\n\r\n"); 916 listHead = &MmMdlUnmappedUnallocated.ListHead; 917 nextEntry = listHead->Flink; 918 while (listHead != nextEntry) 919 { 920 Descriptor = CONTAINING_RECORD(nextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); 921 922 EfiPrintf(L"Type: %08lX Flags: %08lX Base: 0x%016I64X End: 0x%016I64X\r\n", 923 Descriptor->Type, 924 Descriptor->Flags, 925 Descriptor->BasePage << PAGE_SHIFT, 926 (Descriptor->BasePage + Descriptor->PageCount) << PAGE_SHIFT); 927 928 nextEntry = nextEntry->Flink; 929 } 930 #endif 931 932 /* 933 * Because BL supports cross x86-x64 application launches and a LIST_ENTRY 934 * is of variable size, care must be taken here to ensure that we see a 935 * consistent view of descriptors. BL uses some offset magic to figure out 936 * where the data actually starts, since everything is ULONGLONG past the 937 * LIST_ENTRY itself 938 */ 939 FinalOffset = BootMemoryData->MdListOffset + BootMemoryData->DescriptorOffset; 940 Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)BootMemoryData + FinalOffset - 941 FIELD_OFFSET(BL_MEMORY_DESCRIPTOR, BasePage)); 942 943 /* Scan all of them */ 944 ExistingDescriptors = BootMemoryData->DescriptorCount; 945 while (ExistingDescriptors != 0) 946 { 947 /* Remove this region from our free memory MDL */ 948 //EfiPrintf(L"Handling existing descriptor: %llx %llx\r\n", Descriptor->BasePage, Descriptor->PageCount); 949 Status = MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedUnallocated, 950 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 951 Descriptor->BasePage, 952 Descriptor->PageCount, 953 NULL); 954 if (!NT_SUCCESS(Status)) 955 { 956 return STATUS_INVALID_PARAMETER; 957 } 958 959 /* Build a descriptor for it */ 960 NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags, 961 Descriptor->Type, 962 Descriptor->BasePage, 963 Descriptor->VirtualPage, 964 Descriptor->PageCount); 965 if (!NewDescriptor) 966 { 967 return STATUS_NO_MEMORY; 968 } 969 970 /* And add this region to the reserved & allocated MDL */ 971 Status = MmMdAddDescriptorToList(&MmMdlReservedAllocated, NewDescriptor, 0); 972 if (!NT_SUCCESS(Status)) 973 { 974 return Status; 975 } 976 977 /* Move on to the next descriptor */ 978 ExistingDescriptors--; 979 Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)Descriptor + BootMemoryData->DescriptorSize); 980 } 981 982 /* We are done, so check for any RAM constraints which will make us truncate memory */ 983 Status = BlpMmInitializeConstraints(); 984 if (NT_SUCCESS(Status)) 985 { 986 /* The Page Allocator has initialized */ 987 PapInitializationStatus = TRUE; 988 Status = STATUS_SUCCESS; 989 } 990 } 991 992 /* Return status */ 993 return Status; 994 } 995 996 NTSTATUS 997 BlMmAllocatePhysicalPages( 998 _In_ PPHYSICAL_ADDRESS Address, 999 _In_ BL_MEMORY_TYPE MemoryType, 1000 _In_ ULONGLONG PageCount, 1001 _In_ ULONG Attributes, 1002 _In_ ULONG Alignment 1003 ) 1004 { 1005 /* Call the physical allocator */ 1006 return MmPapAllocatePhysicalPagesInRange(Address, 1007 MemoryType, 1008 PageCount, 1009 Attributes, 1010 Alignment, 1011 &MmMdlUnmappedAllocated, 1012 NULL, 1013 0); 1014 } 1015 1016 NTSTATUS 1017 MmPapFreePhysicalPages ( 1018 _In_ ULONG WhichList, 1019 _In_ ULONGLONG PageCount, 1020 _In_ PHYSICAL_ADDRESS Address 1021 ) 1022 { 1023 PBL_MEMORY_DESCRIPTOR Descriptor; 1024 ULONGLONG Page; 1025 ULONG DescriptorFlags, Flags; 1026 BOOLEAN DontFree, HasPageData; 1027 BL_LIBRARY_PARAMETERS LibraryParameters; 1028 NTSTATUS Status; 1029 1030 /* Set some defaults */ 1031 Flags = BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG; 1032 DontFree = FALSE; 1033 HasPageData = FALSE; 1034 1035 /* Only page-aligned addresses are accepted */ 1036 if (Address.QuadPart & (PAGE_SIZE - 1)) 1037 { 1038 EfiPrintf(L"free mem fail 1\r\n"); 1039 return STATUS_INVALID_PARAMETER; 1040 } 1041 1042 /* Try to find the descriptor containing this address */ 1043 Page = Address.QuadPart >> PAGE_SHIFT; 1044 Descriptor = MmMdFindDescriptor(WhichList, 1045 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 1046 Page); 1047 if (!Descriptor) 1048 { 1049 EfiPrintf(L"free mem fail 2\r\n"); 1050 return STATUS_INVALID_PARAMETER; 1051 } 1052 1053 /* If a page count was given, it must match, unless it's coalesced */ 1054 DescriptorFlags = Descriptor->Flags; 1055 if (!(DescriptorFlags & BlMemoryCoalesced) && 1056 (PageCount) && (PageCount != Descriptor->PageCount)) 1057 { 1058 EfiPrintf(L"free mem fail 3\r\n"); 1059 return STATUS_INVALID_PARAMETER; 1060 } 1061 1062 /* Check if this is persistent memory in teardown status */ 1063 if ((PapInitializationStatus == 2) && 1064 (DescriptorFlags & BlMemoryPersistent)) 1065 { 1066 /* Then we should keep it */ 1067 DontFree = TRUE; 1068 } 1069 else 1070 { 1071 /* Mark it as non-persistent, since we're freeing it */ 1072 Descriptor->Flags &= ~BlMemoryPersistent; 1073 } 1074 1075 /* Check if this memory contains paging data */ 1076 if ((Descriptor->Type == BlLoaderPageDirectory) || 1077 (Descriptor->Type == BlLoaderReferencePage)) 1078 { 1079 HasPageData = TRUE; 1080 } 1081 1082 /* Check if a page count was given */ 1083 if (PageCount) 1084 { 1085 /* The pages must fit within the descriptor */ 1086 if ((PageCount + Page - Descriptor->BasePage) > Descriptor->PageCount) 1087 { 1088 EfiPrintf(L"free mem fail 4\r\n"); 1089 return STATUS_INVALID_PARAMETER; 1090 } 1091 } 1092 else 1093 { 1094 /* No page count given, so the address must be at the beginning then */ 1095 if (Descriptor->BasePage != Page) 1096 { 1097 EfiPrintf(L"free mem fail 5\r\n"); 1098 return STATUS_INVALID_PARAMETER; 1099 } 1100 1101 /* And we'll use the page count in the descriptor */ 1102 PageCount = Descriptor->PageCount; 1103 } 1104 1105 /* Copy library parameters since we will read them */ 1106 RtlCopyMemory(&LibraryParameters, 1107 &BlpLibraryParameters, 1108 sizeof(LibraryParameters)); 1109 1110 /* Check if this is teardown */ 1111 if (PapInitializationStatus == 2) 1112 { 1113 EfiPrintf(L"Case 2 not yet handled!\r\n"); 1114 return STATUS_NOT_SUPPORTED; 1115 } 1116 else if (!DontFree) 1117 { 1118 /* Caller wants memory to be freed -- should we zero it? */ 1119 if (!(HasPageData) && 1120 (LibraryParameters.LibraryFlags & 1121 BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE)) 1122 { 1123 EfiPrintf(L"Freeing zero data not yet handled!\r\n"); 1124 return STATUS_NOT_SUPPORTED; 1125 } 1126 } 1127 1128 /* Now call into firmware to actually free the physical pages */ 1129 Status = MmFwFreePages(Page, PageCount); 1130 if (!NT_SUCCESS(Status)) 1131 { 1132 EfiPrintf(L"free mem fail 6\r\n"); 1133 return Status; 1134 } 1135 1136 /* Remove the firmware flags */ 1137 Descriptor->Flags &= ~(BlMemoryNonFirmware | 1138 BlMemoryFirmware | 1139 BlMemoryPersistent); 1140 1141 /* If we're not actually freeing, don't coalesce with anyone nearby */ 1142 if (DontFree) 1143 { 1144 Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG; 1145 } 1146 1147 /* Check if the entire allocation is being freed */ 1148 if (PageCount == Descriptor->PageCount) 1149 { 1150 /* Remove the descriptor from the allocated list */ 1151 MmMdRemoveDescriptorFromList(&MmMdlUnmappedAllocated, Descriptor); 1152 1153 /* Mark the entire descriptor as free */ 1154 Descriptor->Type = BlConventionalMemory; 1155 } 1156 else 1157 { 1158 /* Init a descriptor for what we're actually freeing */ 1159 Descriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags, 1160 BlConventionalMemory, 1161 Page, 1162 0, 1163 PageCount); 1164 if (!Descriptor) 1165 { 1166 return STATUS_NO_MEMORY; 1167 } 1168 1169 /* Remove the region from the existing descriptor */ 1170 Status = MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedAllocated, 1171 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 1172 Page, 1173 PageCount, 1174 NULL); 1175 if (!NT_SUCCESS(Status)) 1176 { 1177 return Status; 1178 } 1179 } 1180 1181 /* Add the new descriptor into in the list (or the old, repurposed one) */ 1182 Descriptor->Flags &= ~BlMemoryCoalesced; 1183 return MmMdAddDescriptorToList(&MmMdlUnmappedUnallocated, Descriptor, Flags); 1184 } 1185 1186 NTSTATUS 1187 BlMmFreePhysicalPages ( 1188 _In_ PHYSICAL_ADDRESS Address 1189 ) 1190 { 1191 /* Call the physical allocator */ 1192 return MmPapFreePhysicalPages(BL_MM_INCLUDE_UNMAPPED_ALLOCATED, 0, Address); 1193 } 1194 1195 NTSTATUS 1196 MmPapFreePages ( 1197 _In_ PVOID Address, 1198 _In_ ULONG WhichList 1199 ) 1200 { 1201 PHYSICAL_ADDRESS PhysicalAddress; 1202 1203 /* Handle virtual memory scenario */ 1204 if (MmTranslationType != BlNone) 1205 { 1206 EfiPrintf(L"Unimplemented free virtual path: %p %lx\r\n", Address, WhichList); 1207 return STATUS_SUCCESS; 1208 } 1209 1210 /* Physical memory should be in the unmapped allocated list */ 1211 if (WhichList != BL_MM_INCLUDE_PERSISTENT_MEMORY) 1212 { 1213 WhichList = BL_MM_INCLUDE_UNMAPPED_ALLOCATED; 1214 } 1215 1216 /* Free it from there */ 1217 PhysicalAddress.QuadPart = (ULONG_PTR)Address; 1218 return MmPapFreePhysicalPages(WhichList, 0, PhysicalAddress); 1219 } 1220 1221 NTSTATUS 1222 BlMmGetMemoryMap ( 1223 _In_ PLIST_ENTRY MemoryMap, 1224 _In_ PBL_BUFFER_DESCRIPTOR MemoryParameters, 1225 _In_ ULONG WhichTypes, 1226 _In_ ULONG Flags 1227 ) 1228 { 1229 BL_MEMORY_DESCRIPTOR_LIST FirmwareMdList, FullMdList; 1230 BOOLEAN DoFirmware, DoPersistent, DoTruncated, DoBad; 1231 BOOLEAN DoReserved, DoUnmapUnalloc, DoUnmapAlloc; 1232 BOOLEAN DoMapAlloc, DoMapUnalloc, DoFirmware2; 1233 ULONG LoopCount, MdListCount, MdListSize, Used; 1234 NTSTATUS Status; 1235 1236 /* Initialize the firmware list if we use it */ 1237 MmMdInitializeListHead(&FirmwareMdList); 1238 1239 /* Make sure we got our input parameters */ 1240 if (!(MemoryMap) || !(MemoryParameters)) 1241 { 1242 return STATUS_INVALID_PARAMETER; 1243 } 1244 1245 /* Either ask for firmware memory, or don't. Not neither */ 1246 if ((WhichTypes & ~BL_MM_INCLUDE_NO_FIRMWARE_MEMORY) && 1247 (WhichTypes & ~BL_MM_INCLUDE_ONLY_FIRMWARE_MEMORY)) 1248 { 1249 return STATUS_INVALID_PARAMETER; 1250 } 1251 1252 /* Either ask for firmware memory, or don't. Not both */ 1253 if ((WhichTypes & BL_MM_INCLUDE_NO_FIRMWARE_MEMORY) && 1254 (WhichTypes & BL_MM_INCLUDE_ONLY_FIRMWARE_MEMORY)) 1255 { 1256 return STATUS_INVALID_PARAMETER; 1257 } 1258 1259 /* Initialize the memory map list */ 1260 InitializeListHead(MemoryMap); 1261 1262 /* Check which types of memory to dump */ 1263 DoFirmware = WhichTypes & BL_MM_INCLUDE_FIRMWARE_MEMORY; 1264 DoPersistent = WhichTypes & BL_MM_INCLUDE_PERSISTENT_MEMORY; 1265 DoTruncated = WhichTypes & BL_MM_INCLUDE_TRUNCATED_MEMORY; 1266 DoBad = WhichTypes & BL_MM_INCLUDE_BAD_MEMORY; 1267 DoReserved = WhichTypes & BL_MM_INCLUDE_RESERVED_ALLOCATED; 1268 DoUnmapUnalloc = WhichTypes & BL_MM_INCLUDE_UNMAPPED_UNALLOCATED; 1269 DoUnmapAlloc = WhichTypes & BL_MM_INCLUDE_UNMAPPED_ALLOCATED; 1270 DoMapAlloc = WhichTypes & BL_MM_INCLUDE_MAPPED_ALLOCATED; 1271 DoMapUnalloc = WhichTypes & BL_MM_INCLUDE_MAPPED_UNALLOCATED; 1272 DoFirmware2 = WhichTypes & BL_MM_INCLUDE_FIRMWARE_MEMORY_2; 1273 1274 /* Begin the attempt loop */ 1275 LoopCount = 0; 1276 while (TRUE) 1277 { 1278 /* Count how many entries we will need */ 1279 MdListCount = 0; 1280 if (DoMapAlloc) MdListCount = MmMdCountList(&MmMdlMappedAllocated); 1281 if (DoMapUnalloc) MdListCount += MmMdCountList(&MmMdlMappedUnallocated); 1282 if (DoUnmapAlloc) MdListCount += MmMdCountList(&MmMdlUnmappedAllocated); 1283 if (DoUnmapUnalloc) MdListCount += MmMdCountList(&MmMdlUnmappedUnallocated); 1284 if (DoReserved) MdListCount += MmMdCountList(&MmMdlReservedAllocated); 1285 if (DoBad) MdListCount += MmMdCountList(&MmMdlBadMemory); 1286 if (DoTruncated) MdListCount += MmMdCountList(&MmMdlTruncatedMemory); 1287 if (DoPersistent) MdListCount += MmMdCountList(&MmMdlPersistentMemory); 1288 1289 /* Plus firmware entries */ 1290 if (DoFirmware) 1291 { 1292 /* Free the previous entries, if any */ 1293 MmMdFreeList(&FirmwareMdList); 1294 1295 /* Get the firmware map, coalesced */ 1296 Status = MmFwGetMemoryMap(&FirmwareMdList, 1297 BL_MM_FLAG_REQUEST_COALESCING); 1298 if (!NT_SUCCESS(Status)) 1299 { 1300 goto Quickie; 1301 } 1302 1303 /* We overwrite, since this type is exclusive */ 1304 MdListCount = MmMdCountList(&FirmwareMdList); 1305 } 1306 1307 /* Plus firmware entries-2 */ 1308 if (DoFirmware2) 1309 { 1310 /* Free the previous entries, if any */ 1311 MmMdFreeList(&FirmwareMdList); 1312 1313 /* Get the firmware map, uncoalesced */ 1314 Status = MmFwGetMemoryMap(&FirmwareMdList, 0); 1315 if (!NT_SUCCESS(Status)) 1316 { 1317 goto Quickie; 1318 } 1319 1320 /* We overwrite, since this type is exclusive */ 1321 MdListCount = MmMdCountList(&FirmwareMdList); 1322 } 1323 1324 /* If there's no descriptors, we're done */ 1325 if (!MdListCount) 1326 { 1327 Status = STATUS_SUCCESS; 1328 goto Quickie; 1329 } 1330 1331 /* Check if the buffer we have is big enough */ 1332 if (MemoryParameters->BufferSize >= 1333 (sizeof(BL_MEMORY_DESCRIPTOR) * MdListCount)) 1334 { 1335 break; 1336 } 1337 1338 /* It's not, allocate it, with a slack of 4 extra descriptors */ 1339 MdListSize = sizeof(BL_MEMORY_DESCRIPTOR) * (MdListCount + 4); 1340 1341 /* Except if we weren't asked to */ 1342 if (!(Flags & BL_MM_ADD_DESCRIPTOR_ALLOCATE_FLAG)) 1343 { 1344 MemoryParameters->BufferSize = MdListSize; 1345 Status = STATUS_BUFFER_TOO_SMALL; 1346 goto Quickie; 1347 } 1348 1349 /* Has it been less than 4 times we've tried this? */ 1350 if (++LoopCount <= 4) 1351 { 1352 /* Free the previous attempt, if any */ 1353 if (MemoryParameters->BufferSize) 1354 { 1355 BlMmFreeHeap(MemoryParameters->Buffer); 1356 } 1357 1358 /* Allocate a new buffer */ 1359 MemoryParameters->BufferSize = MdListSize; 1360 MemoryParameters->Buffer = BlMmAllocateHeap(MdListSize); 1361 if (MemoryParameters->Buffer) 1362 { 1363 /* Try again */ 1364 continue; 1365 } 1366 } 1367 1368 /* If we got here, we're out of memory after 4 attempts */ 1369 Status = STATUS_NO_MEMORY; 1370 goto Quickie; 1371 } 1372 1373 /* We should have a buffer by now... */ 1374 if (MemoryParameters->Buffer) 1375 { 1376 /* Zero it out */ 1377 RtlZeroMemory(MemoryParameters->Buffer, 1378 MdListCount * sizeof(BL_MEMORY_DESCRIPTOR)); 1379 } 1380 1381 /* Initialize our list of descriptors */ 1382 MmMdInitializeList(&FullMdList, 0, MemoryMap); 1383 Used = 0; 1384 1385 /* Handle mapped, allocated */ 1386 if (DoMapAlloc) 1387 { 1388 Status = MmMdCopyList(&FullMdList, 1389 &MmMdlMappedAllocated, 1390 MemoryParameters->Buffer, 1391 &Used, 1392 MdListCount, 1393 Flags); 1394 } 1395 1396 /* Handle mapped, unallocated */ 1397 if (DoMapUnalloc) 1398 { 1399 Status = MmMdCopyList(&FullMdList, 1400 &MmMdlMappedUnallocated, 1401 MemoryParameters->Buffer, 1402 &Used, 1403 MdListCount, 1404 Flags); 1405 } 1406 1407 /* Handle unmapped, allocated */ 1408 if (DoUnmapAlloc) 1409 { 1410 Status = MmMdCopyList(&FullMdList, 1411 &MmMdlUnmappedAllocated, 1412 MemoryParameters->Buffer, 1413 &Used, 1414 MdListCount, 1415 Flags); 1416 } 1417 1418 /* Handle unmapped, unallocated */ 1419 if (DoUnmapUnalloc) 1420 { 1421 Status = MmMdCopyList(&FullMdList, 1422 &MmMdlUnmappedUnallocated, 1423 MemoryParameters->Buffer, 1424 &Used, 1425 MdListCount, 1426 Flags); 1427 } 1428 1429 /* Handle reserved, allocated */ 1430 if (DoReserved) 1431 { 1432 Status = MmMdCopyList(&FullMdList, 1433 &MmMdlReservedAllocated, 1434 MemoryParameters->Buffer, 1435 &Used, 1436 MdListCount, 1437 Flags); 1438 } 1439 1440 /* Handle bad */ 1441 if (DoBad) 1442 { 1443 Status = MmMdCopyList(&FullMdList, 1444 &MmMdlBadMemory, 1445 MemoryParameters->Buffer, 1446 &Used, 1447 MdListCount, 1448 Flags); 1449 } 1450 1451 /* Handle truncated */ 1452 if (DoTruncated) 1453 { 1454 Status = MmMdCopyList(&FullMdList, 1455 &MmMdlTruncatedMemory, 1456 MemoryParameters->Buffer, 1457 &Used, 1458 MdListCount, 1459 Flags); 1460 } 1461 1462 /* Handle persistent */ 1463 if (DoPersistent) 1464 { 1465 Status = MmMdCopyList(&FullMdList, 1466 &MmMdlPersistentMemory, 1467 MemoryParameters->Buffer, 1468 &Used, 1469 MdListCount, 1470 Flags); 1471 } 1472 1473 /* Handle firmware */ 1474 if (DoFirmware) 1475 { 1476 Status = MmMdCopyList(&FullMdList, 1477 &FirmwareMdList, 1478 MemoryParameters->Buffer, 1479 &Used, 1480 MdListCount, 1481 Flags); 1482 } 1483 1484 /* Handle firmware2 */ 1485 if (DoFirmware2) 1486 { 1487 Status = MmMdCopyList(&FullMdList, 1488 &FirmwareMdList, 1489 MemoryParameters->Buffer, 1490 &Used, 1491 MdListCount, 1492 Flags); 1493 } 1494 1495 /* Add up the final size */ 1496 Status = RtlULongLongToULong(Used * sizeof(BL_MEMORY_DESCRIPTOR), 1497 &MemoryParameters->ActualSize); 1498 1499 Quickie: 1500 MmMdFreeList(&FirmwareMdList); 1501 return Status; 1502 } 1503 1504 NTSTATUS 1505 MmPaReleaseSelfMapPages ( 1506 _In_ PHYSICAL_ADDRESS Address 1507 ) 1508 { 1509 PBL_MEMORY_DESCRIPTOR Descriptor; 1510 ULONGLONG BasePage; 1511 NTSTATUS Status; 1512 1513 /* Only page-aligned addresses are accepted */ 1514 if (Address.QuadPart & (PAGE_SIZE - 1)) 1515 { 1516 EfiPrintf(L"free mem fail 1\r\n"); 1517 return STATUS_INVALID_PARAMETER; 1518 } 1519 1520 /* Get the base page, and find a descriptor that matches */ 1521 BasePage = Address.QuadPart >> PAGE_SHIFT; 1522 Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_UNALLOCATED, 1523 BL_MM_REMOVE_PHYSICAL_REGION_FLAG, 1524 BasePage); 1525 if (!(Descriptor) || (Descriptor->BasePage != BasePage)) 1526 { 1527 return STATUS_INVALID_PARAMETER; 1528 } 1529 1530 /* Free the physical pages */ 1531 Status = MmFwFreePages(BasePage, Descriptor->PageCount); 1532 if (!NT_SUCCESS(Status)) 1533 { 1534 return Status; 1535 } 1536 1537 /* Remove the firmware flags */ 1538 Descriptor->Flags &= ~(BlMemoryNonFirmware | 1539 BlMemoryFirmware | 1540 BlMemoryPersistent); 1541 1542 /* Set it as free memory */ 1543 Descriptor->Type = BlConventionalMemory; 1544 1545 /* Create a new descriptor that's free memory, covering the old range */ 1546 Descriptor = MmMdInitByteGranularDescriptor(0, 1547 BlConventionalMemory, 1548 BasePage, 1549 0, 1550 Descriptor->PageCount); 1551 if (!Descriptor) 1552 { 1553 return STATUS_NO_MEMORY; 1554 } 1555 1556 /* Insert it into the virtual free list */ 1557 return MmMdAddDescriptorToList(&MmMdlFreeVirtual, 1558 Descriptor, 1559 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG | 1560 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG); 1561 } 1562 1563 NTSTATUS 1564 MmPaReserveSelfMapPages ( 1565 _Inout_ PPHYSICAL_ADDRESS PhysicalAddress, 1566 _In_ ULONG Alignment, 1567 _In_ ULONG PageCount 1568 ) 1569 { 1570 NTSTATUS Status; 1571 BL_PA_REQUEST Request; 1572 BL_MEMORY_DESCRIPTOR Descriptor; 1573 1574 /* Increment descriptor usage count */ 1575 ++MmDescriptorCallTreeCount; 1576 1577 /* Bail if we don't have an address */ 1578 if (!PhysicalAddress) 1579 { 1580 Status = STATUS_INVALID_PARAMETER; 1581 goto Quickie; 1582 } 1583 1584 /* Make a request for the required number of self-map pages */ 1585 Request.BaseRange.Minimum = PapMinimumPhysicalPage; 1586 Request.BaseRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT; 1587 Request.VirtualRange.Minimum = 0; 1588 Request.VirtualRange.Maximum = 0; 1589 Request.Pages = PageCount; 1590 Request.Alignment = Alignment; 1591 Request.Type = BL_MM_REQUEST_DEFAULT_TYPE; 1592 Request.Flags = 0;; 1593 Status = MmPaAllocatePages(&MmMdlUnmappedUnallocated, 1594 &Descriptor, 1595 &MmMdlUnmappedUnallocated, 1596 &Request, 1597 BlLoaderSelfMap); 1598 if (!NT_SUCCESS(Status)) 1599 { 1600 goto Quickie; 1601 } 1602 1603 /* Remove this region from free virtual memory */ 1604 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual, 1605 BL_MM_REMOVE_VIRTUAL_REGION_FLAG, 1606 Descriptor.BasePage, 1607 Descriptor.PageCount, 1608 0); 1609 if (!NT_SUCCESS(Status)) 1610 { 1611 goto Quickie; 1612 } 1613 1614 /* Return the physical address */ 1615 PhysicalAddress->QuadPart = Descriptor.BasePage << PAGE_SHIFT; 1616 1617 Quickie: 1618 /* Free global descriptors and reduce the count by one */ 1619 MmMdFreeGlobalDescriptors(); 1620 --MmDescriptorCallTreeCount; 1621 return Status; 1622 } 1623 1624 NTSTATUS 1625 MmSelectMappingAddress ( 1626 _Out_ PVOID* MappingAddress, 1627 _In_ PVOID PreferredAddress, 1628 _In_ ULONGLONG Size, 1629 _In_ ULONG AllocationAttributes, 1630 _In_ ULONG Flags, 1631 _In_ PHYSICAL_ADDRESS PhysicalAddress 1632 ) 1633 { 1634 BL_PA_REQUEST Request; 1635 NTSTATUS Status; 1636 BL_MEMORY_DESCRIPTOR NewDescriptor; 1637 1638 /* Are we in physical mode? */ 1639 if (MmTranslationType == BlNone) 1640 { 1641 /* Just return the physical address as the mapping address */ 1642 PreferredAddress = PhysicalAddressToPtr(PhysicalAddress); 1643 goto Success; 1644 } 1645 1646 /* If no physical address, or caller wants a fixed address... */ 1647 if ((PhysicalAddress.QuadPart == -1) || (Flags & BlMemoryFixed)) 1648 { 1649 /* Then just return the preferred address */ 1650 goto Success; 1651 } 1652 1653 /* Check which range of virtual memory should be used */ 1654 if (AllocationAttributes & BlMemoryKernelRange) 1655 { 1656 /* Use kernel range */ 1657 Request.BaseRange.Minimum = MmArchKsegAddressRange.Minimum >> PAGE_SHIFT; 1658 Request.BaseRange.Maximum = MmArchKsegAddressRange.Maximum >> PAGE_SHIFT; 1659 Request.Type = BL_MM_REQUEST_DEFAULT_TYPE; 1660 } 1661 else 1662 { 1663 /* User user/application range */ 1664 Request.BaseRange.Minimum = 0 >> PAGE_SHIFT; 1665 Request.BaseRange.Maximum = MmArchTopOfApplicationAddressSpace >> PAGE_SHIFT; 1666 Request.Type = BL_MM_REQUEST_TOP_DOWN_TYPE; 1667 } 1668 1669 /* Build a request */ 1670 Request.VirtualRange.Minimum = 0; 1671 Request.VirtualRange.Maximum = 0; 1672 Request.Flags = AllocationAttributes & BlMemoryLargePages; 1673 Request.Alignment = 1; 1674 Request.Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(PhysicalAddress.LowPart, Size); 1675 1676 /* Allocate the physical pages */ 1677 Status = MmPaAllocatePages(NULL, 1678 &NewDescriptor, 1679 &MmMdlFreeVirtual, 1680 &Request, 1681 BlConventionalMemory); 1682 if (!NT_SUCCESS(Status)) 1683 { 1684 return Status; 1685 } 1686 1687 /* Return the address we got back */ 1688 PreferredAddress = (PVOID)((ULONG_PTR)NewDescriptor.BasePage << PAGE_SHIFT); 1689 1690 /* Check if the existing physical address was not aligned */ 1691 if (PhysicalAddress.QuadPart != -1) 1692 { 1693 /* Add the offset to the returned virtual address */ 1694 PreferredAddress = (PVOID)((ULONG_PTR)PreferredAddress + 1695 BYTE_OFFSET(PhysicalAddress.QuadPart)); 1696 } 1697 1698 Success: 1699 /* Return the mapping address and success */ 1700 *MappingAddress = PreferredAddress; 1701 return STATUS_SUCCESS; 1702 } 1703