Virtual memory works baby! Virtual Heap at 0x80000000 fully enabled. Next up, EFI...
[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 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 = (PVOID)BaseAddress.LowPart;
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_IMAGE_PARAMETERS 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 = (PVOID)PhysicalAddress.LowPart;
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 }