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 extern ULONG MmArchLargePageSize
;
29 ULONGLONG PapMaximumPhysicalPage
, PapMinimumPhysicalPage
;
31 ULONG PapMinimumAllocationCount
;
33 BOOLEAN PapInitializationStatus
;
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
;
48 /* FUNCTIONS *****************************************************************/
52 _In_ ULONGLONG BasePage
57 /* Increase nesting depth */
58 ++MmDescriptorCallTreeCount
;
60 /* Set the maximum page to the truncated request */
61 if (BasePage
< PapMaximumPhysicalPage
)
63 PapMaximumPhysicalPage
= BasePage
;
66 /* Truncate mapped and allocated memory */
67 Status
= MmMdTruncateDescriptors(&MmMdlMappedAllocated
,
68 &MmMdlTruncatedMemory
,
70 if (NT_SUCCESS(Status
))
72 /* Truncate unmapped and allocated memory */
73 Status
= MmMdTruncateDescriptors(&MmMdlUnmappedAllocated
,
74 &MmMdlTruncatedMemory
,
76 if (NT_SUCCESS(Status
))
78 /* Truncate mapped and unallocated memory */
79 Status
= MmMdTruncateDescriptors(&MmMdlMappedUnallocated
,
80 &MmMdlTruncatedMemory
,
82 if (NT_SUCCESS(Status
))
84 /* Truncate unmapped and unallocated memory */
85 Status
= MmMdTruncateDescriptors(&MmMdlUnmappedUnallocated
,
86 &MmMdlTruncatedMemory
,
88 if (NT_SUCCESS(Status
))
90 /* Truncate reserved memory */
91 Status
= MmMdTruncateDescriptors(&MmMdlReservedAllocated
,
92 &MmMdlTruncatedMemory
,
99 /* Restore the nesting depth */
100 MmMdFreeGlobalDescriptors();
101 --MmDescriptorCallTreeCount
;
106 BlpMmInitializeConstraints (
110 NTSTATUS Status
, ReturnStatus
;
111 ULONGLONG LowestAddressValid
, HighestAddressValid
;
112 ULONGLONG LowestPage
, HighestPage
;
115 ReturnStatus
= STATUS_SUCCESS
;
117 /* Check for LOWMEM */
118 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
119 BcdLibraryInteger_AvoidLowPhysicalMemory
,
120 &LowestAddressValid
);
121 if (NT_SUCCESS(Status
))
123 /* Align the address */
124 LowestAddressValid
= (ULONG_PTR
)PAGE_ALIGN(LowestAddressValid
);
125 LowestPage
= LowestAddressValid
>> PAGE_SHIFT
;
127 /* Make sure it's below 4GB */
128 if (LowestPage
<= 0x100000)
130 PapMinimumPhysicalPage
= LowestPage
;
134 /* Check for MAXMEM */
135 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
136 BcdLibraryInteger_TruncatePhysicalMemory
,
137 &HighestAddressValid
);
138 if (NT_SUCCESS(Status
))
141 HighestPage
= HighestAddressValid
>> PAGE_SHIFT
;
143 /* Truncate memory above this page */
144 ReturnStatus
= MmPaTruncateMemory(HighestPage
);
147 /* Return back to the caller */
152 MmMdListPointerToName (_In_ PBL_MEMORY_DESCRIPTOR_LIST MdList
)
154 if (MdList
== &MmMdlUnmappedAllocated
)
156 return L
"UnmapAlloc";
158 else if (MdList
== &MmMdlUnmappedUnallocated
)
160 return L
"UnmapUnalloc";
162 else if (MdList
== &MmMdlMappedAllocated
)
166 else if (MdList
== &MmMdlMappedUnallocated
)
168 return L
"MapUnalloc";
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
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
;
193 /* Check if any parameters were not passed in correctly */
194 if (!(CurrentList
) || !(Request
) || (!(NewList
) && !(Descriptor
)))
196 return STATUS_INVALID_PARAMETER
;
199 /* Set failure by default */
200 Status
= STATUS_NO_MEMORY
;
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
)
206 NextEntry
= ListHead
->Blink
;
211 NextEntry
= ListHead
->Flink
;
215 /* Loop through the list */
217 while (NextEntry
!= ListHead
)
219 /* Grab a descriptor */
220 FoundDescriptor
= CONTAINING_RECORD(NextEntry
,
221 BL_MEMORY_DESCRIPTOR
,
224 /* See if it matches the request */
225 if (MmMdFindSatisfyingRegion(FoundDescriptor
,
229 &Request
->VirtualRange
,
238 /* It doesn't, move to the next appropriate entry */
241 NextEntry
= NextEntry
->Blink
;
245 NextEntry
= NextEntry
->Flink
;
249 /* Check if we exhausted the list */
250 if (NextEntry
== ListHead
)
255 /* Copy all the flags that are not request flag */
256 LocalDescriptor
.Flags
= (Request
->Flags
& 0xFFFF0000) |
257 (LocalDescriptor
.Flags
& 0x0000FFFF);
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
)))
264 /* Allocate the requested address from EFI */
265 EfiAddress
= LocalDescriptor
.BasePage
<< PAGE_SHIFT
;
266 Status
= EfiAllocatePages(AllocateAddress
,
267 (ULONG
)LocalDescriptor
.PageCount
,
269 if (!NT_SUCCESS(Status
))
271 EfiPrintf(L
"EFI memory allocation failure\r\n");
276 /* Remember we got memory from EFI */
280 /* Remove the descriptor from the original list it was on */
281 MmMdRemoveDescriptorFromList(CurrentList
, FoundDescriptor
);
283 /* Get the end pages */
284 LocalEndPage
= LocalDescriptor
.PageCount
+ LocalDescriptor
.BasePage
;
285 FoundEndPage
= FoundDescriptor
->PageCount
+ FoundDescriptor
->BasePage
;
287 /* Are we allocating from the virtual memory list? */
288 if (CurrentList
== &MmMdlMappedUnallocated
)
290 /* Check if the region matches perfectly */
291 if ((LocalDescriptor
.BasePage
== FoundDescriptor
->BasePage
) &&
292 (LocalEndPage
== FoundEndPage
))
294 /* Check if the original descriptor had the flag set */
295 if ((FoundDescriptor
->Flags
& 0x40000000) && (Descriptor
))
297 /* Make our local one have it too, even if not needed */
298 LocalDescriptor
.Flags
|= 0x40000000;
303 /* Write the 'incomplete mapping' flag */
304 FoundDescriptor
->Flags
|= 0x40000000;
307 /* Including on the local one if there's one passed in */
308 LocalDescriptor
.Flags
|= 0x40000000;
313 /* Does the memory we received not exactly fall onto the beginning of its descriptor? */
314 if (LocalDescriptor
.BasePage
!= FoundDescriptor
->BasePage
)
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
))
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
)
334 TempDescriptor
= MmMdInitByteGranularDescriptor(FoundDescriptor
->Flags
,
335 FoundDescriptor
->Type
,
338 FoundEndPage
- LocalEndPage
);
339 Status
= MmMdAddDescriptorToList(CurrentList
, TempDescriptor
, 0);
340 if (!NT_SUCCESS(Status
))
346 /* We got the memory we needed */
347 Status
= STATUS_SUCCESS
;
349 /* Are we supposed to insert it into a new list? */
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
;
359 /* Remember if it came from EFI */
362 FoundDescriptor
->Flags
|= BlMemoryFirmware
;
365 /* Add the descriptor to the requested list */
366 Status
= MmMdAddDescriptorToList(NewList
, FoundDescriptor
, 0);
370 /* Free the descriptor, nobody wants to know about it anymore */
371 MmMdFreeDescriptor(FoundDescriptor
);
374 /* Return the allocation region back */
375 RtlCopyMemory(Descriptor
, &LocalDescriptor
, sizeof(LocalDescriptor
));
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
390 /* Heap and page directory/table pages have a special flag */
391 if ((MemoryType
>= BlLoaderHeap
) && (MemoryType
<= BlLoaderReferencePage
))
393 Request
->Flags
|= BlMemorySpecial
;
396 /* Try to find a free region of RAM matching this range and request */
397 Request
->MemoryType
= BlConventionalMemory
;
398 Status
= MmPapAllocateRegionFromMdl(NewList
,
403 if (Status
== STATUS_NOT_FOUND
)
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");
409 /* Did we get the region we wanted? */
410 if (NT_SUCCESS(Status
))
412 /* All good, return back */
416 /* Are we failing due to some attributes? */
417 if (Request
->Flags
& BlMemoryValidAllocationAttributeMask
)
419 if (Request
->Flags
& BlMemoryLargePages
)
421 EfiPrintf(L
"large alloc fail not yet implemented %lx\r\n", Status
);
423 return STATUS_NOT_IMPLEMENTED
;
425 if (Request
->Flags
& BlMemoryFixed
)
427 EfiPrintf(L
"fixed alloc fail not yet implemented %lx\r\n", Status
);
429 return STATUS_NOT_IMPLEMENTED
;
433 /* Nope, just fail the entire call */
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
,
450 BL_PA_REQUEST Request
;
451 BL_MEMORY_DESCRIPTOR Descriptor
;
453 /* Increase nesting depth */
454 ++MmDescriptorCallTreeCount
;
456 /* Bail out if no address was specified */
459 Status
= STATUS_INVALID_PARAMETER
;
463 /* Bail out if no page count was passed in, or a bad list was specified */
465 ((NewList
!= &MmMdlUnmappedAllocated
) &&
466 (NewList
!= &MmMdlPersistentMemory
)))
468 Status
= STATUS_INVALID_PARAMETER
;
472 /* Bail out if the passed in range is invalid */
473 if ((Range
) && (Range
->Minimum
>= Range
->Maximum
))
475 Status
= STATUS_INVALID_PARAMETER
;
479 /* Adjust alignment as needed */
485 /* Clear the virtual range */
486 Request
.VirtualRange
.Minimum
= 0;
487 Request
.VirtualRange
.Maximum
= 0;
489 /* Check if a fixed allocation was requested*/
490 if (Attributes
& BlMemoryFixed
)
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;
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;
505 /* Otherwise, use any possible range of pages */
506 Request
.BaseRange
.Minimum
= PapMinimumPhysicalPage
;
507 Request
.BaseRange
.Maximum
= MAXULONG
>> PAGE_SHIFT
;
510 /* Check if no type was specified, or if it was invalid */
512 (RangeType
& ~(BL_MM_REQUEST_TOP_DOWN_TYPE
| BL_MM_REQUEST_DEFAULT_TYPE
)))
514 /* Use default type */
515 Request
.Type
= BL_MM_REQUEST_DEFAULT_TYPE
;
519 /* Use the requested type */
520 Request
.Type
= RangeType
;
523 /* Capture the other request parameters */
524 Request
.Alignment
= Alignment
;
525 Request
.Pages
= Pages
;
526 Request
.Flags
= Attributes
;
527 Status
= MmPaAllocatePages(NewList
,
529 &MmMdlUnmappedUnallocated
,
532 if (NT_SUCCESS(Status
))
534 /* We got a descriptor back, return its address */
535 BaseAddress
->QuadPart
= Descriptor
.BasePage
<< PAGE_SHIFT
;
539 /* Restore the nesting depth */
540 MmMdFreeGlobalDescriptors();
541 --MmDescriptorCallTreeCount
;
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
,
555 BL_PA_REQUEST Request
;
557 BL_MEMORY_DESCRIPTOR NewDescriptor
;
558 ULONG AllocationFlags
, CacheAttributes
, AddFlags
;
560 PBL_MEMORY_DESCRIPTOR_LIST MdList
;
561 PBL_MEMORY_DESCRIPTOR Descriptor
;
562 PVOID VirtualAddress
;
563 PHYSICAL_ADDRESS PhysicalAddress
;
565 /* Is the caller requesting less pages than allowed? */
566 if (!(Attributes
& BlMemoryFixed
) &&
568 (PageCount
< PapMinimumAllocationCount
))
570 /* Unless this is a fixed request, then adjust the original requirements */
571 PageCount
= PapMinimumAllocationCount
;
572 Alignment
= PapMinimumAllocationCount
;
575 /* Extract only the allocation attributes */
576 AllocationFlags
= Attributes
& BlMemoryValidAllocationAttributeMask
;
578 /* Check if the caller wants large pages */
579 if ((AllocationFlags
& BlMemoryLargePages
) && (MmArchLargePageSize
!= 1))
581 EfiPrintf(L
"Large pages not supported!\r\n");
583 return STATUS_NOT_IMPLEMENTED
;
586 /* Set an emty virtual range */
587 Request
.VirtualRange
.Minimum
= 0;
588 Request
.VirtualRange
.Maximum
= 0;
590 /* Check if the caller requested a range */
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;
596 /* Set the minimum and maximum, in pages */
597 Request
.BaseRange
.Minimum
= Range
->Minimum
>> PAGE_SHIFT
;
598 Request
.BaseRange
.Maximum
= Request
.BaseRange
.Minimum
+ PageRange
;
602 /* Initialize a range from the smallest page to the biggest */
603 Request
.BaseRange
.Minimum
= PapMinimumPhysicalPage
;
604 Request
.BaseRange
.Maximum
= 0xFFFFFFFF / PAGE_SIZE
;
607 /* Get the cache attributes */
608 CacheAttributes
= Attributes
& BlMemoryValidCacheAttributeMask
;
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
)))
614 /* Use what the caller wanted */
619 /* Use the default bottom-up type */
620 Request
.Type
= BL_MM_REQUEST_DEFAULT_TYPE
;
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
;
629 /* Allocate some free pages */
630 Status
= MmPaAllocatePages(NULL
,
632 &MmMdlUnmappedUnallocated
,
634 BlConventionalMemory
);
635 if (!NT_SUCCESS(Status
))
637 EfiPrintf(L
"Failed to get unmapped, unallocated memory!\r\n");
642 /* Initialize a descriptor for these pages, adding in the allocation flags */
643 Descriptor
= MmMdInitByteGranularDescriptor(AllocationFlags
|
645 BlConventionalMemory
,
646 NewDescriptor
.BasePage
,
647 NewDescriptor
.VirtualPage
,
648 NewDescriptor
.PageCount
);
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
,
657 if (Status
== STATUS_SUCCESS
)
659 /* Add the cache attributes now that the mapping worked */
660 Descriptor
->Flags
|= CacheAttributes
;
662 /* Update the virtual page now that we mapped it */
663 Descriptor
->VirtualPage
= (ULONG_PTR
)VirtualAddress
>> PAGE_SHIFT
;
665 /* Add this as a mapped region */
666 Status
= MmMdAddDescriptorToList(&MmMdlMappedUnallocated
,
668 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG
);
670 /* Make new descriptor that we'll add in firmware allocation tracker */
671 MdList
= &MmMdlFwAllocationTracker
;
672 Descriptor
= MmMdInitByteGranularDescriptor(0,
673 BlConventionalMemory
,
674 NewDescriptor
.BasePage
,
676 NewDescriptor
.PageCount
);
678 /* Do not coalesce */
683 /* We failed, free the physical pages */
684 Status
= MmFwFreePages(NewDescriptor
.BasePage
, NewDescriptor
.PageCount
);
685 if (!NT_SUCCESS(Status
))
687 /* We failed to free the pages, so this is still around */
688 MdList
= &MmMdlUnmappedAllocated
;
692 /* This is now back to unmapped/unallocated memory */
693 Descriptor
->Flags
= 0;
694 MdList
= &MmMdlUnmappedUnallocated
;
697 /* Coalesce the free descriptor */
698 AddFlags
= BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG
;
701 /* Either add to firmware list, or to unmapped list, then return result */
702 MmMdAddDescriptorToList(MdList
, Descriptor
, AddFlags
);
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
,
718 PHYSICAL_ADDRESS BaseAddress
;
719 BL_PA_REQUEST Request
;
720 PBL_MEMORY_DESCRIPTOR_LIST List
;
721 BL_MEMORY_DESCRIPTOR Descriptor
;
723 /* Increment nesting depth */
724 ++MmDescriptorCallTreeCount
;
727 List
= &MmMdlMappedAllocated
;
729 /* Check for missing parameters or invalid range */
730 if (!(PhysicalAddress
) ||
732 ((Range
) && (Range
->Minimum
>= Range
->Maximum
)))
734 Status
= STATUS_INVALID_PARAMETER
;
738 /* What translation mode are we using? */
739 if (MmTranslationType
!= BlNone
)
741 /* Use 1 page alignment if none was requested */
747 /* Check if we got a range */
750 /* We don't support virtual memory yet @TODO */
751 EfiPrintf(L
"virt range not yet implemented in %S\r\n", __FUNCTION__
);
753 Status
= STATUS_NOT_IMPLEMENTED
;
758 /* Use the entire range that's possible */
759 Request
.BaseRange
.Minimum
= PapMinimumPhysicalPage
;
760 Request
.BaseRange
.Maximum
= 0xFFFFFFFF >> PAGE_SHIFT
;
763 /* Check if a fixed allocation was requested */
764 if (Attributes
& BlMemoryFixed
)
766 /* We don't support virtual memory yet @TODO */
767 EfiPrintf(L
"fixed not yet implemented in %S\r\n", __FUNCTION__
);
769 Status
= STATUS_NOT_IMPLEMENTED
;
774 /* Check if kernel range was specifically requested */
775 if (Attributes
& BlMemoryKernelRange
)
777 /* Use the kernel range */
778 Request
.VirtualRange
.Minimum
= MmArchKsegAddressRange
.Minimum
>> PAGE_SHIFT
;
779 Request
.VirtualRange
.Maximum
= MmArchKsegAddressRange
.Maximum
>> PAGE_SHIFT
;
783 /* Set the virtual address range */
784 Request
.VirtualRange
.Minimum
= 0;
785 Request
.VirtualRange
.Maximum
= 0xFFFFFFFF >> PAGE_SHIFT
;
789 /* Check what type of allocation was requested */
790 if ((Type
) && !(Type
& ~(BL_MM_REQUEST_DEFAULT_TYPE
|
791 BL_MM_REQUEST_TOP_DOWN_TYPE
)))
793 /* Save it if it was valid */
798 /* Set the default */
799 Request
.Type
= BL_MM_REQUEST_DEFAULT_TYPE
;
802 /* Fill out the request of the request */
803 Request
.Flags
= Attributes
;
804 Request
.Alignment
= Alignment
;
805 Request
.Pages
= Pages
;
807 /* Try to allocate the pages */
808 Status
= MmPaAllocatePages(List
,
810 &MmMdlMappedUnallocated
,
813 if (!NT_SUCCESS(Status
))
815 /* Extend the physical allocator */
816 Status
= MmPapPageAllocatorExtend(Attributes
,
819 ((ULONG_PTR
)*PhysicalAddress
) >>
823 if (!NT_SUCCESS(Status
))
825 /* Fail since we're out of memory */
826 EfiPrintf(L
"EXTEND OUT OF MEMORY: %lx\r\n", Status
);
827 Status
= STATUS_NO_MEMORY
;
831 /* Try the allocation again now */
832 Status
= MmPaAllocatePages(&MmMdlMappedAllocated
,
834 &MmMdlMappedUnallocated
,
837 if (!NT_SUCCESS(Status
))
839 /* Fail since we're out of memory */
840 EfiPrintf(L
"PALLOC OUT OF MEMORY: %lx\r\n", Status
);
845 /* Return the allocated address */
846 *PhysicalAddress
= (PVOID
)((ULONG_PTR
)Descriptor
.VirtualPage
<< PAGE_SHIFT
);
850 /* Check if this is a fixed allocation */
851 BaseAddress
.QuadPart
= (Attributes
& BlMemoryFixed
) ?
852 (ULONG_PTR
)*PhysicalAddress
: 0;
854 /* Allocate the pages */
855 Status
= MmPapAllocatePhysicalPagesInRange(&BaseAddress
,
860 (&MmMdlMappedAllocated
!=
861 &MmMdlPersistentMemory
) ?
862 &MmMdlUnmappedAllocated
:
863 &MmMdlMappedAllocated
,
867 /* Return the allocated address */
868 *PhysicalAddress
= (PVOID
)BaseAddress
.LowPart
;
872 /* Restore the nesting depth */
873 MmMdFreeGlobalDescriptors();
874 --MmDescriptorCallTreeCount
;
880 __in PBL_MEMORY_DATA BootMemoryData
,
881 __in ULONG MinimumAllocationCount
885 ULONG ExistingDescriptors
, FinalOffset
;
886 PBL_MEMORY_DESCRIPTOR Descriptor
, NewDescriptor
;
888 /* Initialize physical allocator variables */
889 PapMaximumPhysicalPage
= 0xFFFFFFFFFFFFF;
890 PapMinimumAllocationCount
= MinimumAllocationCount
;
891 PapMinimumPhysicalPage
= 0;
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
);
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
))
912 PLIST_ENTRY listHead
, nextEntry
;
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
)
920 Descriptor
= CONTAINING_RECORD(nextEntry
, BL_MEMORY_DESCRIPTOR
, ListEntry
);
922 EfiPrintf(L
"Type: %08lX Flags: %08lX Base: 0x%016I64X End: 0x%016I64X\r\n",
925 Descriptor
->BasePage
<< PAGE_SHIFT
,
926 (Descriptor
->BasePage
+ Descriptor
->PageCount
) << PAGE_SHIFT
);
928 nextEntry
= nextEntry
->Flink
;
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
939 FinalOffset
= BootMemoryData
->MdListOffset
+ BootMemoryData
->DescriptorOffset
;
940 Descriptor
= (PBL_MEMORY_DESCRIPTOR
)((ULONG_PTR
)BootMemoryData
+ FinalOffset
-
941 FIELD_OFFSET(BL_MEMORY_DESCRIPTOR
, BasePage
));
943 /* Scan all of them */
944 ExistingDescriptors
= BootMemoryData
->DescriptorCount
;
945 while (ExistingDescriptors
!= 0)
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
,
954 if (!NT_SUCCESS(Status
))
956 return STATUS_INVALID_PARAMETER
;
959 /* Build a descriptor for it */
960 NewDescriptor
= MmMdInitByteGranularDescriptor(Descriptor
->Flags
,
962 Descriptor
->BasePage
,
963 Descriptor
->VirtualPage
,
964 Descriptor
->PageCount
);
967 return STATUS_NO_MEMORY
;
970 /* And add this region to the reserved & allocated MDL */
971 Status
= MmMdAddDescriptorToList(&MmMdlReservedAllocated
, NewDescriptor
, 0);
972 if (!NT_SUCCESS(Status
))
977 /* Move on to the next descriptor */
978 ExistingDescriptors
--;
979 Descriptor
= (PBL_MEMORY_DESCRIPTOR
)((ULONG_PTR
)Descriptor
+ BootMemoryData
->DescriptorSize
);
982 /* We are done, so check for any RAM constraints which will make us truncate memory */
983 Status
= BlpMmInitializeConstraints();
984 if (NT_SUCCESS(Status
))
986 /* The Page Allocator has initialized */
987 PapInitializationStatus
= TRUE
;
988 Status
= STATUS_SUCCESS
;
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
1005 /* Call the physical allocator */
1006 return MmPapAllocatePhysicalPagesInRange(Address
,
1011 &MmMdlUnmappedAllocated
,
1017 MmPapFreePhysicalPages (
1018 _In_ ULONG WhichList
,
1019 _In_ ULONGLONG PageCount
,
1020 _In_ PHYSICAL_ADDRESS Address
1023 PBL_MEMORY_DESCRIPTOR Descriptor
;
1025 ULONG DescriptorFlags
, Flags
;
1026 BOOLEAN DontFree
, HasPageData
;
1027 BL_LIBRARY_PARAMETERS LibraryParameters
;
1030 /* Set some defaults */
1031 Flags
= BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG
;
1033 HasPageData
= FALSE
;
1035 /* Only page-aligned addresses are accepted */
1036 if (Address
.QuadPart
& (PAGE_SIZE
- 1))
1038 EfiPrintf(L
"free mem fail 1\r\n");
1039 return STATUS_INVALID_PARAMETER
;
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
,
1049 EfiPrintf(L
"free mem fail 2\r\n");
1050 return STATUS_INVALID_PARAMETER
;
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
))
1058 EfiPrintf(L
"free mem fail 3\r\n");
1059 return STATUS_INVALID_PARAMETER
;
1062 /* Check if this is persistent memory in teardown status */
1063 if ((PapInitializationStatus
== 2) &&
1064 (DescriptorFlags
& BlMemoryPersistent
))
1066 /* Then we should keep it */
1071 /* Mark it as non-persistent, since we're freeing it */
1072 Descriptor
->Flags
&= ~BlMemoryPersistent
;
1075 /* Check if this memory contains paging data */
1076 if ((Descriptor
->Type
== BlLoaderPageDirectory
) ||
1077 (Descriptor
->Type
== BlLoaderReferencePage
))
1082 /* Check if a page count was given */
1085 /* The pages must fit within the descriptor */
1086 if ((PageCount
+ Page
- Descriptor
->BasePage
) > Descriptor
->PageCount
)
1088 EfiPrintf(L
"free mem fail 4\r\n");
1089 return STATUS_INVALID_PARAMETER
;
1094 /* No page count given, so the address must be at the beginning then */
1095 if (Descriptor
->BasePage
!= Page
)
1097 EfiPrintf(L
"free mem fail 5\r\n");
1098 return STATUS_INVALID_PARAMETER
;
1101 /* And we'll use the page count in the descriptor */
1102 PageCount
= Descriptor
->PageCount
;
1105 /* Copy library parameters since we will read them */
1106 RtlCopyMemory(&LibraryParameters
,
1107 &BlpLibraryParameters
,
1108 sizeof(LibraryParameters
));
1110 /* Check if this is teardown */
1111 if (PapInitializationStatus
== 2)
1113 EfiPrintf(L
"Case 2 not yet handled!\r\n");
1114 return STATUS_NOT_SUPPORTED
;
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
))
1123 EfiPrintf(L
"Freeing zero data not yet handled!\r\n");
1124 return STATUS_NOT_SUPPORTED
;
1128 /* Now call into firmware to actually free the physical pages */
1129 Status
= MmFwFreePages(Page
, PageCount
);
1130 if (!NT_SUCCESS(Status
))
1132 EfiPrintf(L
"free mem fail 6\r\n");
1136 /* Remove the firmware flags */
1137 Descriptor
->Flags
&= ~(BlMemoryNonFirmware
|
1139 BlMemoryPersistent
);
1141 /* If we're not actually freeing, don't coalesce with anyone nearby */
1144 Flags
|= BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG
;
1147 /* Check if the entire allocation is being freed */
1148 if (PageCount
== Descriptor
->PageCount
)
1150 /* Remove the descriptor from the allocated list */
1151 MmMdRemoveDescriptorFromList(&MmMdlUnmappedAllocated
, Descriptor
);
1153 /* Mark the entire descriptor as free */
1154 Descriptor
->Type
= BlConventionalMemory
;
1158 /* Init a descriptor for what we're actually freeing */
1159 Descriptor
= MmMdInitByteGranularDescriptor(Descriptor
->Flags
,
1160 BlConventionalMemory
,
1166 return STATUS_NO_MEMORY
;
1169 /* Remove the region from the existing descriptor */
1170 Status
= MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedAllocated
,
1171 BL_MM_REMOVE_PHYSICAL_REGION_FLAG
,
1175 if (!NT_SUCCESS(Status
))
1181 /* Add the new descriptor into in the list (or the old, repurposed one) */
1182 Descriptor
->Flags
&= ~BlMemoryCoalesced
;
1183 return MmMdAddDescriptorToList(&MmMdlUnmappedUnallocated
, Descriptor
, Flags
);
1187 BlMmFreePhysicalPages (
1188 _In_ PHYSICAL_ADDRESS Address
1191 /* Call the physical allocator */
1192 return MmPapFreePhysicalPages(BL_MM_INCLUDE_UNMAPPED_ALLOCATED
, 0, Address
);
1198 _In_ ULONG WhichList
1201 PHYSICAL_ADDRESS PhysicalAddress
;
1203 /* Handle virtual memory scenario */
1204 if (MmTranslationType
!= BlNone
)
1206 EfiPrintf(L
"Unimplemented free virtual path: %p %lx\r\n", Address
, WhichList
);
1207 return STATUS_SUCCESS
;
1210 /* Physical memory should be in the unmapped allocated list */
1211 if (WhichList
!= BL_MM_INCLUDE_PERSISTENT_MEMORY
)
1213 WhichList
= BL_MM_INCLUDE_UNMAPPED_ALLOCATED
;
1216 /* Free it from there */
1217 PhysicalAddress
.QuadPart
= (ULONG_PTR
)Address
;
1218 return MmPapFreePhysicalPages(WhichList
, 0, PhysicalAddress
);
1223 _In_ PLIST_ENTRY MemoryMap
,
1224 _In_ PBL_IMAGE_PARAMETERS MemoryParameters
,
1225 _In_ ULONG WhichTypes
,
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
;
1236 /* Initialize the firmware list if we use it */
1237 MmMdInitializeListHead(&FirmwareMdList
);
1239 /* Make sure we got our input parameters */
1240 if (!(MemoryMap
) || !(MemoryParameters
))
1242 return STATUS_INVALID_PARAMETER
;
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
))
1249 return STATUS_INVALID_PARAMETER
;
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
))
1256 return STATUS_INVALID_PARAMETER
;
1259 /* Initialize the memory map list */
1260 InitializeListHead(MemoryMap
);
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
;
1274 /* Begin the attempt loop */
1278 /* Count how many entries we will need */
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
);
1289 /* Plus firmware entries */
1292 /* Free the previous entries, if any */
1293 MmMdFreeList(&FirmwareMdList
);
1295 /* Get the firmware map, coalesced */
1296 Status
= MmFwGetMemoryMap(&FirmwareMdList
,
1297 BL_MM_FLAG_REQUEST_COALESCING
);
1298 if (!NT_SUCCESS(Status
))
1303 /* We overwrite, since this type is exclusive */
1304 MdListCount
= MmMdCountList(&FirmwareMdList
);
1307 /* Plus firmware entries-2 */
1310 /* Free the previous entries, if any */
1311 MmMdFreeList(&FirmwareMdList
);
1313 /* Get the firmware map, uncoalesced */
1314 Status
= MmFwGetMemoryMap(&FirmwareMdList
, 0);
1315 if (!NT_SUCCESS(Status
))
1320 /* We overwrite, since this type is exclusive */
1321 MdListCount
= MmMdCountList(&FirmwareMdList
);
1324 /* If there's no descriptors, we're done */
1327 Status
= STATUS_SUCCESS
;
1331 /* Check if the buffer we have is big enough */
1332 if (MemoryParameters
->BufferSize
>=
1333 (sizeof(BL_MEMORY_DESCRIPTOR
) * MdListCount
))
1338 /* It's not, allocate it, with a slack of 4 extra descriptors */
1339 MdListSize
= sizeof(BL_MEMORY_DESCRIPTOR
) * (MdListCount
+ 4);
1341 /* Except if we weren't asked to */
1342 if (!(Flags
& BL_MM_ADD_DESCRIPTOR_ALLOCATE_FLAG
))
1344 MemoryParameters
->BufferSize
= MdListSize
;
1345 Status
= STATUS_BUFFER_TOO_SMALL
;
1349 /* Has it been less than 4 times we've tried this? */
1350 if (++LoopCount
<= 4)
1352 /* Free the previous attempt, if any */
1353 if (MemoryParameters
->BufferSize
)
1355 BlMmFreeHeap(MemoryParameters
->Buffer
);
1358 /* Allocate a new buffer */
1359 MemoryParameters
->BufferSize
= MdListSize
;
1360 MemoryParameters
->Buffer
= BlMmAllocateHeap(MdListSize
);
1361 if (MemoryParameters
->Buffer
)
1368 /* If we got here, we're out of memory after 4 attempts */
1369 Status
= STATUS_NO_MEMORY
;
1373 /* We should have a buffer by now... */
1374 if (MemoryParameters
->Buffer
)
1377 RtlZeroMemory(MemoryParameters
->Buffer
,
1378 MdListCount
* sizeof(BL_MEMORY_DESCRIPTOR
));
1381 /* Initialize our list of descriptors */
1382 MmMdInitializeList(&FullMdList
, 0, MemoryMap
);
1385 /* Handle mapped, allocated */
1388 Status
= MmMdCopyList(&FullMdList
,
1389 &MmMdlMappedAllocated
,
1390 MemoryParameters
->Buffer
,
1396 /* Handle mapped, unallocated */
1399 Status
= MmMdCopyList(&FullMdList
,
1400 &MmMdlMappedUnallocated
,
1401 MemoryParameters
->Buffer
,
1407 /* Handle unmapped, allocated */
1410 Status
= MmMdCopyList(&FullMdList
,
1411 &MmMdlUnmappedAllocated
,
1412 MemoryParameters
->Buffer
,
1418 /* Handle unmapped, unallocated */
1421 Status
= MmMdCopyList(&FullMdList
,
1422 &MmMdlUnmappedUnallocated
,
1423 MemoryParameters
->Buffer
,
1429 /* Handle reserved, allocated */
1432 Status
= MmMdCopyList(&FullMdList
,
1433 &MmMdlReservedAllocated
,
1434 MemoryParameters
->Buffer
,
1443 Status
= MmMdCopyList(&FullMdList
,
1445 MemoryParameters
->Buffer
,
1451 /* Handle truncated */
1454 Status
= MmMdCopyList(&FullMdList
,
1455 &MmMdlTruncatedMemory
,
1456 MemoryParameters
->Buffer
,
1462 /* Handle persistent */
1465 Status
= MmMdCopyList(&FullMdList
,
1466 &MmMdlPersistentMemory
,
1467 MemoryParameters
->Buffer
,
1473 /* Handle firmware */
1476 Status
= MmMdCopyList(&FullMdList
,
1478 MemoryParameters
->Buffer
,
1484 /* Handle firmware2 */
1487 Status
= MmMdCopyList(&FullMdList
,
1489 MemoryParameters
->Buffer
,
1495 /* Add up the final size */
1496 Status
= RtlULongLongToULong(Used
* sizeof(BL_MEMORY_DESCRIPTOR
),
1497 &MemoryParameters
->ActualSize
);
1500 MmMdFreeList(&FirmwareMdList
);
1505 MmPaReleaseSelfMapPages (
1506 _In_ PHYSICAL_ADDRESS Address
1509 PBL_MEMORY_DESCRIPTOR Descriptor
;
1513 /* Only page-aligned addresses are accepted */
1514 if (Address
.QuadPart
& (PAGE_SIZE
- 1))
1516 EfiPrintf(L
"free mem fail 1\r\n");
1517 return STATUS_INVALID_PARAMETER
;
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
,
1525 if (!(Descriptor
) || (Descriptor
->BasePage
!= BasePage
))
1527 return STATUS_INVALID_PARAMETER
;
1530 /* Free the physical pages */
1531 Status
= MmFwFreePages(BasePage
, Descriptor
->PageCount
);
1532 if (!NT_SUCCESS(Status
))
1537 /* Remove the firmware flags */
1538 Descriptor
->Flags
&= ~(BlMemoryNonFirmware
|
1540 BlMemoryPersistent
);
1542 /* Set it as free memory */
1543 Descriptor
->Type
= BlConventionalMemory
;
1545 /* Create a new descriptor that's free memory, covering the old range */
1546 Descriptor
= MmMdInitByteGranularDescriptor(0,
1547 BlConventionalMemory
,
1550 Descriptor
->PageCount
);
1553 return STATUS_NO_MEMORY
;
1556 /* Insert it into the virtual free list */
1557 return MmMdAddDescriptorToList(&MmMdlFreeVirtual
,
1559 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG
|
1560 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG
);
1564 MmPaReserveSelfMapPages (
1565 _Inout_ PPHYSICAL_ADDRESS PhysicalAddress
,
1566 _In_ ULONG Alignment
,
1567 _In_ ULONG PageCount
1571 BL_PA_REQUEST Request
;
1572 BL_MEMORY_DESCRIPTOR Descriptor
;
1574 /* Increment descriptor usage count */
1575 ++MmDescriptorCallTreeCount
;
1577 /* Bail if we don't have an address */
1578 if (!PhysicalAddress
)
1580 Status
= STATUS_INVALID_PARAMETER
;
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
;
1593 Status
= MmPaAllocatePages(&MmMdlUnmappedUnallocated
,
1595 &MmMdlUnmappedUnallocated
,
1598 if (!NT_SUCCESS(Status
))
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
,
1609 if (!NT_SUCCESS(Status
))
1614 /* Return the physical address */
1615 PhysicalAddress
->QuadPart
= Descriptor
.BasePage
<< PAGE_SHIFT
;
1618 /* Free global descriptors and reduce the count by one */
1619 MmMdFreeGlobalDescriptors();
1620 --MmDescriptorCallTreeCount
;
1625 MmSelectMappingAddress (
1626 _Out_ PVOID
* MappingAddress
,
1627 _In_ PVOID PreferredAddress
,
1628 _In_ ULONGLONG Size
,
1629 _In_ ULONG AllocationAttributes
,
1631 _In_ PHYSICAL_ADDRESS PhysicalAddress
1634 BL_PA_REQUEST Request
;
1636 BL_MEMORY_DESCRIPTOR NewDescriptor
;
1638 /* Are we in physical mode? */
1639 if (MmTranslationType
== BlNone
)
1641 /* Just return the physical address as the mapping address */
1642 PreferredAddress
= (PVOID
)PhysicalAddress
.LowPart
;
1646 /* If no physical address, or caller wants a fixed address... */
1647 if ((PhysicalAddress
.QuadPart
== -1) || (Flags
& BlMemoryFixed
))
1649 /* Then just return the preferred address */
1653 /* Check which range of virtual memory should be used */
1654 if (AllocationAttributes
& BlMemoryKernelRange
)
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
;
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
;
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
);
1676 /* Allocate the physical pages */
1677 Status
= MmPaAllocatePages(NULL
,
1681 BlConventionalMemory
);
1682 if (!NT_SUCCESS(Status
))
1687 /* Return the address we got back */
1688 PreferredAddress
= (PVOID
)((ULONG_PTR
)NewDescriptor
.BasePage
<< PAGE_SHIFT
);
1690 /* Check if the existing physical address was not aligned */
1691 if (PhysicalAddress
.QuadPart
!= -1)
1693 /* Add the offset to the returned virtual address */
1694 PreferredAddress
= (PVOID
)((ULONG_PTR
)PreferredAddress
+
1695 BYTE_OFFSET(PhysicalAddress
.QuadPart
));
1699 /* Return the mapping address and success */
1700 *MappingAddress
= PreferredAddress
;
1701 return STATUS_SUCCESS
;