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)
9 /* INCLUDES ******************************************************************/
14 typedef struct _BL_PA_REQUEST
16 BL_ADDRESS_RANGE BaseRange
;
17 BL_ADDRESS_RANGE VirtualRange
;
23 } BL_PA_REQUEST
, *PBL_PA_REQUEST
;
25 /* DATA VARIABLES ************************************************************/
27 ULONGLONG PapMaximumPhysicalPage
, PapMinimumPhysicalPage
;
29 ULONG PapMinimumAllocationCount
;
31 BOOLEAN PapInitializationStatus
;
33 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappedAllocated
;
34 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappedUnallocated
;
35 BL_MEMORY_DESCRIPTOR_LIST MmMdlFwAllocationTracker
;
36 BL_MEMORY_DESCRIPTOR_LIST MmMdlUnmappedAllocated
;
37 BL_MEMORY_DESCRIPTOR_LIST MmMdlUnmappedUnallocated
;
38 BL_MEMORY_DESCRIPTOR_LIST MmMdlReservedAllocated
;
39 BL_MEMORY_DESCRIPTOR_LIST MmMdlBadMemory
;
40 BL_MEMORY_DESCRIPTOR_LIST MmMdlTruncatedMemory
;
41 BL_MEMORY_DESCRIPTOR_LIST MmMdlPersistentMemory
;
42 BL_MEMORY_DESCRIPTOR_LIST MmMdlCompleteBadMemory
;
43 BL_MEMORY_DESCRIPTOR_LIST MmMdlFreeVirtual
;
44 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappingTrackers
;
46 /* FUNCTIONS *****************************************************************/
49 BlpMmInitializeConstraints (
54 ULONGLONG LowestAddressValid
, HighestAddressValid
;
56 /* Check for LOWMEM */
57 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
58 BcdLibraryInteger_AvoidLowPhysicalMemory
,
60 if (NT_SUCCESS(Status
))
62 EfiPrintf(L
"/LOWMEM not supported\r\n");
63 return STATUS_NOT_IMPLEMENTED
;
66 /* Check for MAXMEM */
67 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
68 BcdLibraryInteger_TruncatePhysicalMemory
,
69 &HighestAddressValid
);
70 if (NT_SUCCESS(Status
))
72 EfiPrintf(L
"/MAXMEM not supported\r\n");
73 return STATUS_NOT_IMPLEMENTED
;
76 /* Return back to the caller */
77 return STATUS_SUCCESS
;
81 MmPapAllocateRegionFromMdl (
82 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList
,
83 _Out_opt_ PBL_MEMORY_DESCRIPTOR Descriptor
,
84 _In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList
,
85 _In_ PBL_PA_REQUEST Request
,
86 _In_ BL_MEMORY_TYPE Type
90 BL_MEMORY_DESCRIPTOR LocalDescriptor
= {{0}};
91 PBL_MEMORY_DESCRIPTOR FoundDescriptor
, TempDescriptor
;
92 PLIST_ENTRY ListHead
, NextEntry
;
93 BOOLEAN TopDown
, GotFwPages
;
94 EFI_PHYSICAL_ADDRESS EfiAddress
;
95 ULONGLONG LocalEndPage
, FoundEndPage
, LocalVirtualEndPage
;
97 /* Check if any parameters were not passed in correctly */
98 if (!(CurrentList
) || !(Request
) || (!(NewList
) && !(Descriptor
)))
100 return STATUS_INVALID_PARAMETER
;
103 /* Set failure by default */
104 Status
= STATUS_NO_MEMORY
;
106 /* Take the head and next entry in the list, as appropriate */
107 ListHead
= CurrentList
->First
;
108 if (Request
->Type
& BL_MM_REQUEST_TOP_DOWN_TYPE
)
110 NextEntry
= ListHead
->Blink
;
115 NextEntry
= ListHead
->Flink
;
119 /* Loop through the list */
121 while (NextEntry
!= ListHead
)
123 /* Grab a descriptor */
124 FoundDescriptor
= CONTAINING_RECORD(NextEntry
,
125 BL_MEMORY_DESCRIPTOR
,
128 /* See if it matches the request */
129 if (MmMdFindSatisfyingRegion(FoundDescriptor
,
133 &Request
->VirtualRange
,
139 /* It does, get out */
143 /* It doesn't, move to the next appropriate entry */
146 NextEntry
= NextEntry
->Blink
;
150 NextEntry
= NextEntry
->Flink
;
154 /* Check if we exhausted the list */
155 if (NextEntry
== ListHead
)
157 EfiPrintf(L
"No matching memory found\r\n");
161 /* Copy all the flags that are not request flag */
162 LocalDescriptor
.Flags
= (Request
->Flags
& 0xFFFF0000) |
163 (LocalDescriptor
.Flags
& 0x0000FFFF);
165 /* Are we using the physical memory list, and are we OK with using firmware? */
166 if ((CurrentList
== &MmMdlUnmappedUnallocated
) &&
167 !((Request
->Flags
& BlMemoryNonFirmware
) ||
168 (LocalDescriptor
.Flags
& BlMemoryNonFirmware
)))
170 /* Allocate the requested address from EFI */
171 EfiAddress
= LocalDescriptor
.BasePage
<< PAGE_SHIFT
;
172 Status
= EfiAllocatePages(AllocateAddress
,
173 (ULONG
)LocalDescriptor
.PageCount
,
175 if (!NT_SUCCESS(Status
))
177 EfiPrintf(L
"EFI memory allocation failure\r\n");
181 /* Remember we got memory from EFI */
185 /* Remove the descriptor from the original list it was on */
186 MmMdRemoveDescriptorFromList(CurrentList
, FoundDescriptor
);
188 /* Are we allocating from the virtual memory list? */
189 if (CurrentList
== &MmMdlMappedUnallocated
)
191 EfiPrintf(L
"not yet implemented in %S\r\n", __FUNCTION__
);
193 return STATUS_NOT_IMPLEMENTED
;
196 /* Does the memory we received not exactly fall onto the beginning of its descriptor? */
197 if (LocalDescriptor
.BasePage
!= FoundDescriptor
->BasePage
)
199 TempDescriptor
= MmMdInitByteGranularDescriptor(FoundDescriptor
->Flags
,
200 FoundDescriptor
->Type
,
201 FoundDescriptor
->BasePage
,
202 FoundDescriptor
->VirtualPage
,
203 LocalDescriptor
.BasePage
-
204 FoundDescriptor
->BasePage
);
205 Status
= MmMdAddDescriptorToList(CurrentList
, TempDescriptor
, 0);
206 if (!NT_SUCCESS(Status
))
212 /* Does the memory we received not exactly fall onto the end of its descriptor? */
213 LocalEndPage
= LocalDescriptor
.PageCount
+ LocalDescriptor
.BasePage
;
214 FoundEndPage
= FoundDescriptor
->PageCount
+ FoundDescriptor
->BasePage
;
215 LocalVirtualEndPage
= LocalDescriptor
.VirtualPage
?
216 LocalDescriptor
.VirtualPage
+ LocalDescriptor
.PageCount
: 0;
217 if (LocalEndPage
!= FoundEndPage
)
219 TempDescriptor
= MmMdInitByteGranularDescriptor(FoundDescriptor
->Flags
,
220 FoundDescriptor
->Type
,
223 FoundEndPage
- LocalEndPage
);
224 Status
= MmMdAddDescriptorToList(CurrentList
, TempDescriptor
, 0);
225 if (!NT_SUCCESS(Status
))
231 /* We got the memory we needed */
232 Status
= STATUS_SUCCESS
;
234 /* Are we supposed to insert it into a new list? */
237 /* Copy the allocated region descriptor into the one we found */
238 FoundDescriptor
->BaseAddress
= LocalDescriptor
.BaseAddress
;
239 FoundDescriptor
->VirtualPage
= LocalDescriptor
.VirtualPage
;
240 FoundDescriptor
->PageCount
= LocalDescriptor
.PageCount
;
241 FoundDescriptor
->Type
= Type
;
242 FoundDescriptor
->Flags
= LocalDescriptor
.Flags
;
244 /* Remember if it came from EFI */
247 FoundDescriptor
->Flags
|= BlMemoryFirmware
;
250 /* Add the descriptor to the requested list */
251 Status
= MmMdAddDescriptorToList(NewList
, FoundDescriptor
, 0);
255 /* Free the descriptor, nobody wants to know about it anymore */
256 MmMdFreeDescriptor(FoundDescriptor
);
259 /* Return the allocation region back */
260 RtlCopyMemory(Descriptor
, &LocalDescriptor
, sizeof(LocalDescriptor
));
266 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList
,
267 _In_ PBL_MEMORY_DESCRIPTOR Descriptor
,
268 _In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList
,
269 _In_ PBL_PA_REQUEST Request
,
270 _In_ BL_MEMORY_TYPE MemoryType
275 /* Heap and page directory/table pages have a special flag */
276 if ((MemoryType
>= BlLoaderHeap
) && (MemoryType
<= BlLoaderReferencePage
))
278 Request
->Flags
|= BlMemorySpecial
;
281 /* Try to find a free region of RAM matching this range and request */
282 Request
->MemoryType
= BlConventionalMemory
;
283 Status
= MmPapAllocateRegionFromMdl(NewList
,
288 if (Status
== STATUS_NOT_FOUND
)
290 /* Need to re-synchronize the memory map and check other lists */
291 EfiPrintf(L
"No RAM found -- backup plan not yet implemented\r\n");
294 /* Did we get the region we wanted? */
295 if (NT_SUCCESS(Status
))
297 /* All good, return back */
301 /* Are we failing due to some attributes? */
302 if (Request
->Flags
& BlMemoryValidAllocationAttributeMask
)
304 EfiPrintf(L
"not yet implemented in %S\r\n", __FUNCTION__
);
306 return STATUS_NOT_IMPLEMENTED
;
309 /* Nope, just fail the entire call */
314 MmPapAllocatePhysicalPagesInRange (
315 _Inout_ PPHYSICAL_ADDRESS BaseAddress
,
316 _In_ BL_MEMORY_TYPE MemoryType
,
317 _In_ ULONGLONG Pages
,
318 _In_ ULONG Attributes
,
319 _In_ ULONG Alignment
,
320 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList
,
321 _In_opt_ PBL_ADDRESS_RANGE Range
,
326 BL_PA_REQUEST Request
;
327 BL_MEMORY_DESCRIPTOR Descriptor
;
329 /* Increase nesting depth */
330 ++MmDescriptorCallTreeCount
;
332 /* Bail out if no address was specified */
335 Status
= STATUS_INVALID_PARAMETER
;
339 /* Bail out if no page count was passed in, or a bad list was specified */
341 ((NewList
!= &MmMdlUnmappedAllocated
) &&
342 (NewList
!= &MmMdlPersistentMemory
)))
344 Status
= STATUS_INVALID_PARAMETER
;
348 /* Bail out if the passed in range is invalid */
349 if ((Range
) && (Range
->Minimum
>= Range
->Maximum
))
351 Status
= STATUS_INVALID_PARAMETER
;
355 /* Adjust alignment as needed */
361 /* Clear the virtual range */
362 Request
.VirtualRange
.Minimum
= 0;
363 Request
.VirtualRange
.Maximum
= 0;
365 /* Check if a fixed allocation was requested*/
366 if (Attributes
& BlMemoryFixed
)
368 /* Force the only available range to be the passed in address */
369 Request
.BaseRange
.Minimum
= BaseAddress
->QuadPart
>> PAGE_SHIFT
;
370 Request
.BaseRange
.Maximum
= Request
.BaseRange
.Minimum
+ Pages
- 1;
374 /* Otherwise, a manual range was specified, use it */
375 Request
.BaseRange
.Minimum
= Range
->Minimum
>> PAGE_SHIFT
;
376 Request
.BaseRange
.Maximum
= Request
.BaseRange
.Minimum
+
377 (Range
->Maximum
>> PAGE_SHIFT
) - 1;
381 /* Otherwise, use any possible range of pages */
382 Request
.BaseRange
.Minimum
= PapMinimumPhysicalPage
;
383 Request
.BaseRange
.Maximum
= MAXULONG
>> PAGE_SHIFT
;
386 /* Check if no type was specified, or if it was invalid */
388 (RangeType
& ~(BL_MM_REQUEST_TOP_DOWN_TYPE
| BL_MM_REQUEST_DEFAULT_TYPE
)))
390 /* Use default type */
391 Request
.Type
= BL_MM_REQUEST_DEFAULT_TYPE
;
395 /* Use the requested type */
396 Request
.Type
= RangeType
;
399 /* Capture the other request parameters */
400 Request
.Alignment
= Alignment
;
401 Request
.Pages
= Pages
;
402 Request
.Flags
= Attributes
;
403 Status
= MmPaAllocatePages(NewList
,
405 &MmMdlUnmappedUnallocated
,
408 if (NT_SUCCESS(Status
))
410 /* We got a descriptor back, return its address */
411 BaseAddress
->QuadPart
= Descriptor
.BasePage
<< PAGE_SHIFT
;
415 /* Restore the nesting depth */
416 MmMdFreeGlobalDescriptors();
417 --MmDescriptorCallTreeCount
;
422 MmPapAllocatePagesInRange (
423 _Inout_ PVOID
* PhysicalAddress
,
424 _In_ BL_MEMORY_TYPE MemoryType
,
425 _In_ ULONGLONG Pages
,
426 _In_ ULONG Attributes
,
427 _In_ ULONG Alignment
,
428 _In_opt_ PBL_ADDRESS_RANGE Range
,
433 PHYSICAL_ADDRESS BaseAddress
;
434 BL_PA_REQUEST Request
;
435 PBL_MEMORY_DESCRIPTOR_LIST List
;
436 BL_MEMORY_DESCRIPTOR Descriptor
;
438 /* Increment nesting depth */
439 ++MmDescriptorCallTreeCount
;
442 List
= &MmMdlMappedAllocated
;
444 /* Check for missing parameters or invalid range */
445 if (!(PhysicalAddress
) ||
447 ((Range
) && (Range
->Minimum
>= Range
->Maximum
)))
449 Status
= STATUS_INVALID_PARAMETER
;
453 /* What translation mode are we using? */
454 if (MmTranslationType
!= BlNone
)
456 /* Use 1 page alignment if none was requested */
462 /* Check if we got a range */
465 /* We don't support virtual memory yet @TODO */
466 EfiPrintf(L
"not yet implemented in %S\r\n", __FUNCTION__
);
468 Status
= STATUS_NOT_IMPLEMENTED
;
473 Request
.BaseRange
.Minimum
= PapMinimumPhysicalPage
;
474 Request
.BaseRange
.Maximum
= (4 * 1024 * 1024) >> PAGE_SHIFT
;
477 /* Check if a fixed allocation was requested */
478 if (Attributes
& BlMemoryFixed
)
480 /* We don't support virtual memory yet @TODO */
481 EfiPrintf(L
"not yet implemented in %S\r\n", __FUNCTION__
);
483 Status
= STATUS_NOT_IMPLEMENTED
;
488 /* Check if non-fixed was specifically requested */
489 if (Attributes
& BlMemoryNonFixed
)
491 /* We don't support virtual memory yet @TODO */
492 EfiPrintf(L
"not yet implemented in %S\r\n", __FUNCTION__
);
494 Status
= STATUS_NOT_IMPLEMENTED
;
498 /* Set the virtual address range */
499 Request
.VirtualRange
.Minimum
= 0;
500 Request
.VirtualRange
.Maximum
= (4 * 1024 * 1024) >> PAGE_SHIFT
;
503 /* Check what type of allocation was requested */
509 /* If it was invalid, set the default */
510 if (Type
& ~(BL_MM_REQUEST_DEFAULT_TYPE
| BL_MM_REQUEST_TOP_DOWN_TYPE
))
512 Request
.Type
= BL_MM_REQUEST_DEFAULT_TYPE
;
517 /* Set the default */
518 Request
.Type
= BL_MM_REQUEST_DEFAULT_TYPE
;
521 /* Fill out the request of the request */
522 Request
.Flags
= Attributes
;
523 Request
.Alignment
= Alignment
;
524 Request
.Pages
= Pages
;
526 /* Try to allocate the pages */
527 Status
= MmPaAllocatePages(List
,
529 &MmMdlMappedUnallocated
,
532 if (!NT_SUCCESS(Status
))
534 /* We don't support virtual memory yet @TODO */
535 EfiPrintf(L
"Need to extend PA allocator\r\n");
537 Status
= STATUS_NOT_IMPLEMENTED
;
541 /* Return the allocated address */
542 *PhysicalAddress
= (PVOID
)((ULONG_PTR
)Descriptor
.VirtualPage
<< PAGE_SHIFT
);
546 /* Check if this is a fixed allocation */
547 BaseAddress
.QuadPart
= (Attributes
& BlMemoryFixed
) ? (ULONG_PTR
)*PhysicalAddress
: 0;
549 /* Allocate the pages */
550 Status
= MmPapAllocatePhysicalPagesInRange(&BaseAddress
,
555 (&MmMdlMappedAllocated
!=
556 &MmMdlPersistentMemory
) ?
557 &MmMdlUnmappedAllocated
:
558 &MmMdlMappedAllocated
,
562 /* Return the allocated address */
563 *PhysicalAddress
= (PVOID
)BaseAddress
.LowPart
;
567 /* Restore the nesting depth */
568 MmMdFreeGlobalDescriptors();
569 --MmDescriptorCallTreeCount
;
575 __in PBL_MEMORY_DATA BootMemoryData
,
576 __in ULONG MinimumAllocationCount
580 ULONG ExistingDescriptors
, FinalOffset
;
581 PBL_MEMORY_DESCRIPTOR Descriptor
, NewDescriptor
;
583 /* Initialize physical allocator variables */
584 PapMaximumPhysicalPage
= 0xFFFFFFFFFFFFF;
585 PapMinimumAllocationCount
= MinimumAllocationCount
;
586 PapMinimumPhysicalPage
= 0;
588 /* Initialize all the lists */
589 MmMdInitializeListHead(&MmMdlMappedAllocated
);
590 MmMdInitializeListHead(&MmMdlMappedUnallocated
);
591 MmMdInitializeListHead(&MmMdlFwAllocationTracker
);
592 MmMdInitializeListHead(&MmMdlUnmappedAllocated
);
593 MmMdInitializeListHead(&MmMdlReservedAllocated
);
594 MmMdInitializeListHead(&MmMdlBadMemory
);
595 MmMdInitializeListHead(&MmMdlTruncatedMemory
);
596 MmMdInitializeListHead(&MmMdlPersistentMemory
);
597 MmMdInitializeListHead(&MmMdlUnmappedUnallocated
);
598 MmMdInitializeListHead(&MmMdlCompleteBadMemory
);
600 /* Get the BIOS memory map */
601 Status
= MmFwGetMemoryMap(&MmMdlUnmappedUnallocated
,
602 BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS
|
603 BL_MM_FLAG_REQUEST_COALESCING
);
604 if (NT_SUCCESS(Status
))
607 PLIST_ENTRY listHead
, nextEntry
;
609 /* Loop the NT firmware memory list */
610 EfiPrintf(L
"NT MEMORY MAP\n\r\n");
611 listHead
= &MmMdlUnmappedUnallocated
.ListHead
;
612 nextEntry
= listHead
->Flink
;
613 while (listHead
!= nextEntry
)
615 Descriptor
= CONTAINING_RECORD(nextEntry
, BL_MEMORY_DESCRIPTOR
, ListEntry
);
617 EfiPrintf(L
"Type: %08lX Flags: %08lX Base: 0x%016I64X End: 0x%016I64X\r\n",
620 Descriptor
->BasePage
<< PAGE_SHIFT
,
621 (Descriptor
->BasePage
+ Descriptor
->PageCount
) << PAGE_SHIFT
);
623 nextEntry
= nextEntry
->Flink
;
628 * Because BL supports cross x86-x64 application launches and a LIST_ENTRY
629 * is of variable size, care must be taken here to ensure that we see a
630 * consistent view of descriptors. BL uses some offset magic to figure out
631 * where the data actually starts, since everything is ULONGLONG past the
634 FinalOffset
= BootMemoryData
->MdListOffset
+ BootMemoryData
->DescriptorOffset
;
635 Descriptor
= (PBL_MEMORY_DESCRIPTOR
)((ULONG_PTR
)BootMemoryData
+ FinalOffset
-
636 FIELD_OFFSET(BL_MEMORY_DESCRIPTOR
, BasePage
));
638 /* Scan all of them */
639 ExistingDescriptors
= BootMemoryData
->DescriptorCount
;
640 while (ExistingDescriptors
!= 0)
642 /* Remove this region from our free memory MDL */
643 //EfiPrintf(L"Handling existing descriptor: %llx %llx\r\n", Descriptor->BasePage, Descriptor->PageCount);
644 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedUnallocated
,
645 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
646 Descriptor
->BasePage
,
647 Descriptor
->PageCount
,
649 if (!NT_SUCCESS(Status
))
651 return STATUS_INVALID_PARAMETER
;
654 /* Build a descriptor for it */
655 NewDescriptor
= MmMdInitByteGranularDescriptor(Descriptor
->Flags
,
657 Descriptor
->BasePage
,
658 Descriptor
->VirtualPage
,
659 Descriptor
->PageCount
);
662 return STATUS_NO_MEMORY
;
665 /* And add this region to the reserved & allocated MDL */
666 Status
= MmMdAddDescriptorToList(&MmMdlReservedAllocated
, NewDescriptor
, 0);
667 if (!NT_SUCCESS(Status
))
672 /* Move on to the next descriptor */
673 ExistingDescriptors
--;
674 Descriptor
= (PBL_MEMORY_DESCRIPTOR
)((ULONG_PTR
)Descriptor
+ BootMemoryData
->DescriptorSize
);
677 /* We are done, so check for any RAM constraints which will make us truncate memory */
678 Status
= BlpMmInitializeConstraints();
679 if (NT_SUCCESS(Status
))
681 /* The Page Allocator has initialized */
682 PapInitializationStatus
= TRUE
;
683 Status
= STATUS_SUCCESS
;
692 BlMmAllocatePhysicalPages(
693 _In_ PPHYSICAL_ADDRESS Address
,
694 _In_ BL_MEMORY_TYPE MemoryType
,
695 _In_ ULONGLONG PageCount
,
696 _In_ ULONG Attributes
,
700 /* Call the physical allocator */
701 return MmPapAllocatePhysicalPagesInRange(Address
,
706 &MmMdlUnmappedAllocated
,
712 MmPapFreePhysicalPages (
713 _In_ ULONG WhichList
,
714 _In_ ULONGLONG PageCount
,
715 _In_ PHYSICAL_ADDRESS Address
718 PBL_MEMORY_DESCRIPTOR Descriptor
;
720 ULONG DescriptorFlags
, Flags
;
721 BOOLEAN DontFree
, HasPageData
;
722 BL_LIBRARY_PARAMETERS LibraryParameters
;
725 /* Set some defaults */
726 Flags
= BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG
;
730 /* Only page-aligned addresses are accepted */
731 if (Address
.QuadPart
& (PAGE_SIZE
- 1))
733 EfiPrintf(L
"free mem fail 1\r\n");
734 return STATUS_INVALID_PARAMETER
;
737 /* Try to find the descriptor containing this address */
738 Page
= Address
.QuadPart
>> PAGE_SHIFT
;
739 Descriptor
= MmMdFindDescriptor(WhichList
,
740 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
744 EfiPrintf(L
"free mem fail 2\r\n");
745 return STATUS_INVALID_PARAMETER
;
748 /* If a page count was given, it must match, unless it's coalesced */
749 DescriptorFlags
= Descriptor
->Flags
;
750 if (!(DescriptorFlags
& BlMemoryCoalesced
) &&
751 (PageCount
) && (PageCount
!= Descriptor
->PageCount
))
753 EfiPrintf(L
"free mem fail 3\r\n");
754 return STATUS_INVALID_PARAMETER
;
757 /* Check if this is persistent memory in teardown status */
758 if ((PapInitializationStatus
== 2) &&
759 (DescriptorFlags
& BlMemoryPersistent
))
761 /* Then we should keep it */
766 /* Mark it as non-persistent, since we're freeing it */
767 Descriptor
->Flags
&= ~BlMemoryPersistent
;
770 /* Check if this memory contains paging data */
771 if ((Descriptor
->Type
== BlLoaderPageDirectory
) ||
772 (Descriptor
->Type
== BlLoaderReferencePage
))
777 /* Check if a page count was given */
780 /* The pages must fit within the descriptor */
781 if ((PageCount
+ Page
- Descriptor
->BasePage
) > Descriptor
->PageCount
)
783 EfiPrintf(L
"free mem fail 4\r\n");
784 return STATUS_INVALID_PARAMETER
;
789 /* No page count given, so the address must be at the beginning then */
790 if (Descriptor
->BasePage
!= Page
)
792 EfiPrintf(L
"free mem fail 5\r\n");
793 return STATUS_INVALID_PARAMETER
;
796 /* And we'll use the page count in the descriptor */
797 PageCount
= Descriptor
->PageCount
;
800 /* Copy library parameters since we will read them */
801 RtlCopyMemory(&LibraryParameters
,
802 &BlpLibraryParameters
,
803 sizeof(LibraryParameters
));
805 /* Check if this is teardown */
806 if (PapInitializationStatus
== 2)
808 EfiPrintf(L
"Case 2 not yet handled!\r\n");
809 return STATUS_NOT_SUPPORTED
;
813 /* Caller wants memory to be freed -- should we zero it? */
814 if (!(HasPageData
) &&
815 (LibraryParameters
.LibraryFlags
&
816 BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE
))
818 EfiPrintf(L
"Freeing zero data not yet handled!\r\n");
819 return STATUS_NOT_SUPPORTED
;
823 /* Now call into firmware to actually free the physical pages */
824 Status
= MmFwFreePages(Page
, PageCount
);
825 if (!NT_SUCCESS(Status
))
827 EfiPrintf(L
"free mem fail 6\r\n");
831 /* Remove the firmware flags */
832 Descriptor
->Flags
&= ~(BlMemoryNonFirmware
|
836 /* If we're not actually freeing, don't coalesce with anyone nearby */
839 Flags
|= BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG
;
842 /* Check if the entire allocation is being freed */
843 if (PageCount
== Descriptor
->PageCount
)
845 /* Remove the descriptor from the allocated list */
846 MmMdRemoveDescriptorFromList(&MmMdlUnmappedAllocated
, Descriptor
);
848 /* Mark the entire descriptor as free */
849 Descriptor
->Type
= BlConventionalMemory
;
853 /* Init a descriptor for what we're actually freeing */
854 Descriptor
= MmMdInitByteGranularDescriptor(Descriptor
->Flags
,
855 BlConventionalMemory
,
861 return STATUS_NO_MEMORY
;
864 /* Remove the region from the existing descriptor */
865 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedAllocated
,
866 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
870 if (!NT_SUCCESS(Status
))
876 /* Add the new descriptor into in the list (or the old, repurposed one) */
877 Descriptor
->Flags
&= ~BlMemoryCoalesced
;
878 return MmMdAddDescriptorToList(&MmMdlUnmappedUnallocated
, Descriptor
, Flags
);
882 BlMmFreePhysicalPages (
883 _In_ PHYSICAL_ADDRESS Address
886 /* Call the physical allocator */
887 return MmPapFreePhysicalPages(BL_MM_INCLUDE_UNMAPPED_ALLOCATED
, 0, Address
);
896 PHYSICAL_ADDRESS PhysicalAddress
;
898 /* Handle virtual memory scenario */
899 if (MmTranslationType
!= BlNone
)
901 EfiPrintf(L
"Unimplemented virtual path\r\n");
902 return STATUS_SUCCESS
;
905 /* Physical memory should be in the unmapped allocated list */
906 if (WhichList
!= BL_MM_INCLUDE_PERSISTENT_MEMORY
)
908 WhichList
= BL_MM_INCLUDE_UNMAPPED_ALLOCATED
;
911 /* Free it from there */
912 PhysicalAddress
.QuadPart
= (ULONG_PTR
)Address
;
913 return MmPapFreePhysicalPages(WhichList
, 0, PhysicalAddress
);
918 _In_ PLIST_ENTRY MemoryMap
,
919 _In_ PBL_IMAGE_PARAMETERS MemoryParameters
,
920 _In_ ULONG WhichTypes
,
924 BL_MEMORY_DESCRIPTOR_LIST FirmwareMdList
, FullMdList
;
925 BOOLEAN DoFirmware
, DoPersistent
, DoTruncated
, DoBad
;
926 BOOLEAN DoReserved
, DoUnmapUnalloc
, DoUnmapAlloc
;
927 BOOLEAN DoMapAlloc
, DoMapUnalloc
, DoFirmware2
;
928 ULONG LoopCount
, MdListCount
, MdListSize
, Used
;
931 /* Initialize the firmware list if we use it */
932 MmMdInitializeListHead(&FirmwareMdList
);
934 /* Make sure we got our input parameters */
935 if (!(MemoryMap
) || !(MemoryParameters
))
937 return STATUS_INVALID_PARAMETER
;
940 /* Either ask for firmware memory, or don't. Not neither */
941 if ((WhichTypes
& ~BL_MM_INCLUDE_NO_FIRMWARE_MEMORY
) &&
942 (WhichTypes
& ~BL_MM_INCLUDE_ONLY_FIRMWARE_MEMORY
))
944 return STATUS_INVALID_PARAMETER
;
947 /* Either ask for firmware memory, or don't. Not both */
948 if ((WhichTypes
& BL_MM_INCLUDE_NO_FIRMWARE_MEMORY
) &&
949 (WhichTypes
& BL_MM_INCLUDE_ONLY_FIRMWARE_MEMORY
))
951 return STATUS_INVALID_PARAMETER
;
954 /* Initialize the memory map list */
955 InitializeListHead(MemoryMap
);
957 /* Check which types of memory to dump */
958 DoFirmware
= WhichTypes
& BL_MM_INCLUDE_FIRMWARE_MEMORY
;
959 DoPersistent
= WhichTypes
& BL_MM_INCLUDE_PERSISTENT_MEMORY
;
960 DoTruncated
= WhichTypes
& BL_MM_INCLUDE_TRUNCATED_MEMORY
;
961 DoBad
= WhichTypes
& BL_MM_INCLUDE_BAD_MEMORY
;
962 DoReserved
= WhichTypes
& BL_MM_INCLUDE_RESERVED_ALLOCATED
;
963 DoUnmapUnalloc
= WhichTypes
& BL_MM_INCLUDE_UNMAPPED_UNALLOCATED
;
964 DoUnmapAlloc
= WhichTypes
& BL_MM_INCLUDE_UNMAPPED_ALLOCATED
;
965 DoMapAlloc
= WhichTypes
& BL_MM_INCLUDE_MAPPED_ALLOCATED
;
966 DoMapUnalloc
= WhichTypes
& BL_MM_INCLUDE_MAPPED_UNALLOCATED
;
967 DoFirmware2
= WhichTypes
& BL_MM_INCLUDE_FIRMWARE_MEMORY_2
;
969 /* Begin the attempt loop */
973 /* Count how many entries we will need */
975 if (DoMapAlloc
) MdListCount
= MmMdCountList(&MmMdlMappedAllocated
);
976 if (DoMapUnalloc
) MdListCount
+= MmMdCountList(&MmMdlMappedUnallocated
);
977 if (DoUnmapAlloc
) MdListCount
+= MmMdCountList(&MmMdlUnmappedAllocated
);
978 if (DoUnmapUnalloc
) MdListCount
+= MmMdCountList(&MmMdlUnmappedUnallocated
);
979 if (DoReserved
) MdListCount
+= MmMdCountList(&MmMdlReservedAllocated
);
980 if (DoBad
) MdListCount
+= MmMdCountList(&MmMdlBadMemory
);
981 if (DoTruncated
) MdListCount
+= MmMdCountList(&MmMdlTruncatedMemory
);
982 if (DoPersistent
) MdListCount
+= MmMdCountList(&MmMdlPersistentMemory
);
984 /* Plus firmware entries */
987 /* Free the previous entries, if any */
988 MmMdFreeList(&FirmwareMdList
);
990 /* Get the firmware map, coalesced */
991 Status
= MmFwGetMemoryMap(&FirmwareMdList
,
992 BL_MM_FLAG_REQUEST_COALESCING
);
993 if (!NT_SUCCESS(Status
))
998 /* We overwrite, since this type is exclusive */
999 MdListCount
= MmMdCountList(&FirmwareMdList
);
1002 /* Plus firmware entries-2 */
1005 /* Free the previous entries, if any */
1006 MmMdFreeList(&FirmwareMdList
);
1008 /* Get the firmware map, uncoalesced */
1009 Status
= MmFwGetMemoryMap(&FirmwareMdList
, 0);
1010 if (!NT_SUCCESS(Status
))
1015 /* We overwrite, since this type is exclusive */
1016 MdListCount
= MmMdCountList(&FirmwareMdList
);
1019 /* If there's no descriptors, we're done */
1022 Status
= STATUS_SUCCESS
;
1026 /* Check if the buffer we have is big enough */
1027 if (MemoryParameters
->BufferSize
>=
1028 (sizeof(BL_MEMORY_DESCRIPTOR
) * MdListCount
))
1033 /* It's not, allocate it, with a slack of 4 extra descriptors */
1034 MdListSize
= sizeof(BL_MEMORY_DESCRIPTOR
) * (MdListCount
+ 4);
1036 /* Except if we weren't asked to */
1037 if (!(Flags
& BL_MM_ADD_DESCRIPTOR_ALLOCATE_FLAG
))
1039 MemoryParameters
->BufferSize
= MdListSize
;
1040 Status
= STATUS_BUFFER_TOO_SMALL
;
1044 /* Has it been less than 4 times we've tried this? */
1045 if (++LoopCount
<= 4)
1047 /* Free the previous attempt, if any */
1048 if (MemoryParameters
->BufferSize
)
1050 BlMmFreeHeap(MemoryParameters
->Buffer
);
1053 /* Allocate a new buffer */
1054 MemoryParameters
->BufferSize
= MdListSize
;
1055 MemoryParameters
->Buffer
= BlMmAllocateHeap(MdListSize
);
1056 if (MemoryParameters
->Buffer
)
1063 /* If we got here, we're out of memory after 4 attempts */
1064 Status
= STATUS_NO_MEMORY
;
1068 /* We should have a buffer by now... */
1069 if (MemoryParameters
->Buffer
)
1072 RtlZeroMemory(MemoryParameters
->Buffer
,
1073 MdListCount
* sizeof(BL_MEMORY_DESCRIPTOR
));
1076 /* Initialize our list of descriptors */
1077 MmMdInitializeList(&FullMdList
, 0, MemoryMap
);
1080 /* Handle mapped, allocated */
1083 Status
= MmMdCopyList(&FullMdList
,
1084 &MmMdlMappedAllocated
,
1085 MemoryParameters
->Buffer
,
1091 /* Handle mapped, unallocated */
1094 Status
= MmMdCopyList(&FullMdList
,
1095 &MmMdlMappedUnallocated
,
1096 MemoryParameters
->Buffer
,
1102 /* Handle unmapped, allocated */
1105 Status
= MmMdCopyList(&FullMdList
,
1106 &MmMdlUnmappedAllocated
,
1107 MemoryParameters
->Buffer
,
1113 /* Handle unmapped, unallocated */
1116 Status
= MmMdCopyList(&FullMdList
,
1117 &MmMdlUnmappedUnallocated
,
1118 MemoryParameters
->Buffer
,
1124 /* Handle reserved, allocated */
1127 Status
= MmMdCopyList(&FullMdList
,
1128 &MmMdlReservedAllocated
,
1129 MemoryParameters
->Buffer
,
1138 Status
= MmMdCopyList(&FullMdList
,
1140 MemoryParameters
->Buffer
,
1146 /* Handle truncated */
1149 Status
= MmMdCopyList(&FullMdList
,
1150 &MmMdlTruncatedMemory
,
1151 MemoryParameters
->Buffer
,
1157 /* Handle persistent */
1160 Status
= MmMdCopyList(&FullMdList
,
1161 &MmMdlPersistentMemory
,
1162 MemoryParameters
->Buffer
,
1168 /* Handle firmware */
1171 Status
= MmMdCopyList(&FullMdList
,
1173 MemoryParameters
->Buffer
,
1179 /* Handle firmware2 */
1182 Status
= MmMdCopyList(&FullMdList
,
1184 MemoryParameters
->Buffer
,
1190 /* Add up the final size */
1191 Status
= RtlULongLongToULong(Used
* sizeof(BL_MEMORY_DESCRIPTOR
),
1192 &MemoryParameters
->ActualSize
);
1195 MmMdFreeList(&FirmwareMdList
);
1200 MmPaReleaseSelfMapPages (
1201 _In_ PHYSICAL_ADDRESS Address
1204 PBL_MEMORY_DESCRIPTOR Descriptor
;
1208 /* Only page-aligned addresses are accepted */
1209 if (Address
.QuadPart
& (PAGE_SIZE
- 1))
1211 EfiPrintf(L
"free mem fail 1\r\n");
1212 return STATUS_INVALID_PARAMETER
;
1215 /* Get the base page, and find a descriptor that matches */
1216 BasePage
= Address
.QuadPart
>> PAGE_SHIFT
;
1217 Descriptor
= MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_UNALLOCATED
,
1218 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
1220 if (!(Descriptor
) || (Descriptor
->BasePage
!= BasePage
))
1222 return STATUS_INVALID_PARAMETER
;
1225 /* Free the physical pages */
1226 Status
= MmFwFreePages(BasePage
, Descriptor
->PageCount
);
1227 if (!NT_SUCCESS(Status
))
1232 /* Remove the firmware flags */
1233 Descriptor
->Flags
&= ~(BlMemoryNonFirmware
|
1235 BlMemoryPersistent
);
1237 /* Set it as free memory */
1238 Descriptor
->Type
= BlConventionalMemory
;
1240 /* Create a new descriptor that's free memory, covering the old range */
1241 Descriptor
= MmMdInitByteGranularDescriptor(0,
1242 BlConventionalMemory
,
1245 Descriptor
->PageCount
);
1248 return STATUS_NO_MEMORY
;
1251 /* Insert it into the virtual free list */
1252 return MmMdAddDescriptorToList(&MmMdlFreeVirtual
,
1254 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG
|
1255 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG
);
1259 MmPaReserveSelfMapPages (
1260 _Inout_ PPHYSICAL_ADDRESS PhysicalAddress
,
1261 _In_ ULONG Alignment
,
1262 _In_ ULONG PageCount
1266 BL_PA_REQUEST Request
;
1267 BL_MEMORY_DESCRIPTOR Descriptor
;
1269 /* Increment descriptor usage count */
1270 ++MmDescriptorCallTreeCount
;
1272 /* Bail if we don't have an address */
1273 if (!PhysicalAddress
)
1275 Status
= STATUS_INVALID_PARAMETER
;
1279 /* Make a request for the required number of self-map pages */
1280 Request
.BaseRange
.Minimum
= PapMinimumPhysicalPage
;
1281 Request
.BaseRange
.Maximum
= 0xFFFFFFFF >> PAGE_SHIFT
;
1282 Request
.VirtualRange
.Minimum
= 0;
1283 Request
.VirtualRange
.Maximum
= 0;
1284 Request
.Pages
= PageCount
;
1285 Request
.Alignment
= Alignment
;
1286 Request
.Type
= BL_MM_REQUEST_DEFAULT_TYPE
;
1288 Status
= MmPaAllocatePages(&MmMdlUnmappedUnallocated
,
1290 &MmMdlUnmappedUnallocated
,
1293 if (!NT_SUCCESS(Status
))
1298 /* Remove this region from free virtual memory */
1299 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual
,
1300 BL_MM_REMOVE_VIRTUAL_REGION_FLAG
,
1301 Descriptor
.BasePage
,
1302 Descriptor
.PageCount
,
1304 if (!NT_SUCCESS(Status
))
1309 /* Return the physical address */
1310 PhysicalAddress
->QuadPart
= Descriptor
.BasePage
<< PAGE_SHIFT
;
1313 /* Free global descriptors and reduce the count by one */
1314 MmMdFreeGlobalDescriptors();
1315 --MmDescriptorCallTreeCount
;