xref: /reactos/boot/environ/lib/mm/pagealloc.c (revision cc439606)
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