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