[BOOTLIB]: Make the EfiPrintf with __FUNCTION__ work also on GCC. Also, on MSVC ...
[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 ULONGLONG PapMaximumPhysicalPage, PapMinimumPhysicalPage;
28
29 ULONG PapMinimumAllocationCount;
30
31 BOOLEAN PapInitializationStatus;
32
33 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappedAllocated;
34 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappedUnallocated;
35 BL_MEMORY_DESCRIPTOR_LIST MmMdlFwAllocationTracker;
36 BL_MEMORY_DESCRIPTOR_LIST MmMdlUnmappedAllocated;
37 BL_MEMORY_DESCRIPTOR_LIST MmMdlUnmappedUnallocated;
38 BL_MEMORY_DESCRIPTOR_LIST MmMdlReservedAllocated;
39 BL_MEMORY_DESCRIPTOR_LIST MmMdlBadMemory;
40 BL_MEMORY_DESCRIPTOR_LIST MmMdlTruncatedMemory;
41 BL_MEMORY_DESCRIPTOR_LIST MmMdlPersistentMemory;
42 BL_MEMORY_DESCRIPTOR_LIST MmMdlCompleteBadMemory;
43 BL_MEMORY_DESCRIPTOR_LIST MmMdlFreeVirtual;
44 BL_MEMORY_DESCRIPTOR_LIST MmMdlMappingTrackers;
45
46 /* FUNCTIONS *****************************************************************/
47
48 NTSTATUS
49 BlpMmInitializeConstraints (
50 VOID
51 )
52 {
53 NTSTATUS Status;
54 ULONGLONG LowestAddressValid, HighestAddressValid;
55
56 /* Check for LOWMEM */
57 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
58 BcdLibraryInteger_AvoidLowPhysicalMemory,
59 &LowestAddressValid);
60 if (NT_SUCCESS(Status))
61 {
62 EfiPrintf(L"/LOWMEM not supported\r\n");
63 return STATUS_NOT_IMPLEMENTED;
64 }
65
66 /* Check for MAXMEM */
67 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
68 BcdLibraryInteger_TruncatePhysicalMemory,
69 &HighestAddressValid);
70 if (NT_SUCCESS(Status))
71 {
72 EfiPrintf(L"/MAXMEM not supported\r\n");
73 return STATUS_NOT_IMPLEMENTED;
74 }
75
76 /* Return back to the caller */
77 return STATUS_SUCCESS;
78 }
79
80 NTSTATUS
81 MmPapAllocateRegionFromMdl (
82 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList,
83 _Out_opt_ PBL_MEMORY_DESCRIPTOR Descriptor,
84 _In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList,
85 _In_ PBL_PA_REQUEST Request,
86 _In_ BL_MEMORY_TYPE Type
87 )
88 {
89 NTSTATUS Status;
90 BL_MEMORY_DESCRIPTOR LocalDescriptor = {{0}};
91 PBL_MEMORY_DESCRIPTOR FoundDescriptor, TempDescriptor;
92 PLIST_ENTRY ListHead, NextEntry;
93 BOOLEAN TopDown, GotFwPages;
94 EFI_PHYSICAL_ADDRESS EfiAddress;
95 ULONGLONG LocalEndPage, FoundEndPage, LocalVirtualEndPage;
96
97 /* Check if any parameters were not passed in correctly */
98 if ( !(CurrentList) || !(Request) || (!(NewList) && !(Descriptor)))
99 {
100 return STATUS_INVALID_PARAMETER;
101 }
102
103 /* Set failure by default */
104 Status = STATUS_NO_MEMORY;
105
106 /* Take the head and next entry in the list, as appropriate */
107 ListHead = CurrentList->First;
108 if (Request->Type & BL_MM_REQUEST_TOP_DOWN_TYPE)
109 {
110 NextEntry = ListHead->Blink;
111 TopDown = TRUE;
112 }
113 else
114 {
115 NextEntry = ListHead->Flink;
116 TopDown = FALSE;
117 }
118
119 /* Loop through the list */
120 GotFwPages = FALSE;
121 while (NextEntry != ListHead)
122 {
123 /* Grab a descriptor */
124 FoundDescriptor = CONTAINING_RECORD(NextEntry,
125 BL_MEMORY_DESCRIPTOR,
126 ListEntry);
127
128 /* See if it matches the request */
129 if (MmMdFindSatisfyingRegion(FoundDescriptor,
130 &LocalDescriptor,
131 Request->Pages,
132 &Request->BaseRange,
133 &Request->VirtualRange,
134 TopDown,
135 Request->MemoryType,
136 Request->Flags,
137 Request->Alignment))
138 {
139 /* It does, get out */
140 break;
141 }
142
143 /* It doesn't, move to the next appropriate entry */
144 if (TopDown)
145 {
146 NextEntry = NextEntry->Blink;
147 }
148 else
149 {
150 NextEntry = NextEntry->Flink;
151 }
152 }
153
154 /* Check if we exhausted the list */
155 if (NextEntry == ListHead)
156 {
157 EfiPrintf(L"No matching memory found\r\n");
158 return Status;
159 }
160
161 /* Copy all the flags that are not request flag */
162 LocalDescriptor.Flags = (Request->Flags & 0xFFFF0000) |
163 (LocalDescriptor.Flags & 0x0000FFFF);
164
165 /* Are we using the physical memory list, and are we OK with using firmware? */
166 if ((CurrentList == &MmMdlUnmappedUnallocated) &&
167 !((Request->Flags & BlMemoryNonFirmware) ||
168 (LocalDescriptor.Flags & BlMemoryNonFirmware)))
169 {
170 /* Allocate the requested address from EFI */
171 EfiAddress = LocalDescriptor.BasePage << PAGE_SHIFT;
172 Status = EfiAllocatePages(AllocateAddress,
173 (ULONG)LocalDescriptor.PageCount,
174 &EfiAddress);
175 if (!NT_SUCCESS(Status))
176 {
177 EfiPrintf(L"EFI memory allocation failure\r\n");
178 return Status;
179 }
180
181 /* Remember we got memory from EFI */
182 GotFwPages = TRUE;
183 }
184
185 /* Remove the descriptor from the original list it was on */
186 MmMdRemoveDescriptorFromList(CurrentList, FoundDescriptor);
187
188 /* Are we allocating from the virtual memory list? */
189 if (CurrentList == &MmMdlMappedUnallocated)
190 {
191 EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
192 EfiStall(1000000);
193 return STATUS_NOT_IMPLEMENTED;
194 }
195
196 /* Does the memory we received not exactly fall onto the beginning of its descriptor? */
197 if (LocalDescriptor.BasePage != FoundDescriptor->BasePage)
198 {
199 TempDescriptor = MmMdInitByteGranularDescriptor(FoundDescriptor->Flags,
200 FoundDescriptor->Type,
201 FoundDescriptor->BasePage,
202 FoundDescriptor->VirtualPage,
203 LocalDescriptor.BasePage -
204 FoundDescriptor->BasePage);
205 Status = MmMdAddDescriptorToList(CurrentList, TempDescriptor, 0);
206 if (!NT_SUCCESS(Status))
207 {
208 return Status;
209 }
210 }
211
212 /* Does the memory we received not exactly fall onto the end of its descriptor? */
213 LocalEndPage = LocalDescriptor.PageCount + LocalDescriptor.BasePage;
214 FoundEndPage = FoundDescriptor->PageCount + FoundDescriptor->BasePage;
215 LocalVirtualEndPage = LocalDescriptor.VirtualPage ?
216 LocalDescriptor.VirtualPage + LocalDescriptor.PageCount : 0;
217 if (LocalEndPage != FoundEndPage)
218 {
219 TempDescriptor = MmMdInitByteGranularDescriptor(FoundDescriptor->Flags,
220 FoundDescriptor->Type,
221 LocalEndPage,
222 LocalVirtualEndPage,
223 FoundEndPage - LocalEndPage);
224 Status = MmMdAddDescriptorToList(CurrentList, TempDescriptor, 0);
225 if (!NT_SUCCESS(Status))
226 {
227 return Status;
228 }
229 }
230
231 /* We got the memory we needed */
232 Status = STATUS_SUCCESS;
233
234 /* Are we supposed to insert it into a new list? */
235 if (NewList)
236 {
237 /* Copy the allocated region descriptor into the one we found */
238 FoundDescriptor->BaseAddress = LocalDescriptor.BaseAddress;
239 FoundDescriptor->VirtualPage = LocalDescriptor.VirtualPage;
240 FoundDescriptor->PageCount = LocalDescriptor.PageCount;
241 FoundDescriptor->Type = Type;
242 FoundDescriptor->Flags = LocalDescriptor.Flags;
243
244 /* Remember if it came from EFI */
245 if (GotFwPages)
246 {
247 FoundDescriptor->Flags |= BlMemoryFirmware;
248 }
249
250 /* Add the descriptor to the requested list */
251 Status = MmMdAddDescriptorToList(NewList, FoundDescriptor, 0);
252 }
253 else
254 {
255 /* Free the descriptor, nobody wants to know about it anymore */
256 MmMdFreeDescriptor(FoundDescriptor);
257 }
258
259 /* Return the allocation region back */
260 RtlCopyMemory(Descriptor, &LocalDescriptor, sizeof(LocalDescriptor));
261 return Status;
262 }
263
264 NTSTATUS
265 MmPaAllocatePages (
266 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList,
267 _In_ PBL_MEMORY_DESCRIPTOR Descriptor,
268 _In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList,
269 _In_ PBL_PA_REQUEST Request,
270 _In_ BL_MEMORY_TYPE MemoryType
271 )
272 {
273 NTSTATUS Status;
274
275 /* Heap and page directory/table pages have a special flag */
276 if ((MemoryType >= BlLoaderHeap) && (MemoryType <= BlLoaderReferencePage))
277 {
278 Request->Flags |= BlMemorySpecial;
279 }
280
281 /* Try to find a free region of RAM matching this range and request */
282 Request->MemoryType = BlConventionalMemory;
283 Status = MmPapAllocateRegionFromMdl(NewList,
284 Descriptor,
285 CurrentList,
286 Request,
287 MemoryType);
288 if (Status == STATUS_NOT_FOUND)
289 {
290 /* Need to re-synchronize the memory map and check other lists */
291 EfiPrintf(L"No RAM found -- backup plan not yet implemented\r\n");
292 }
293
294 /* Did we get the region we wanted? */
295 if (NT_SUCCESS(Status))
296 {
297 /* All good, return back */
298 return Status;
299 }
300
301 /* Nope, we have to hunt for it elsewhere */
302 EfiPrintf(L"TODO\r\n");
303 return Status;
304 }
305
306 NTSTATUS
307 MmPapAllocatePhysicalPagesInRange (
308 _Inout_ PPHYSICAL_ADDRESS BaseAddress,
309 _In_ BL_MEMORY_TYPE MemoryType,
310 _In_ ULONGLONG Pages,
311 _In_ ULONG Attributes,
312 _In_ ULONG Alignment,
313 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList,
314 _In_opt_ PBL_ADDRESS_RANGE Range,
315 _In_ ULONG RangeType
316 )
317 {
318 NTSTATUS Status;
319 BL_PA_REQUEST Request;
320 BL_MEMORY_DESCRIPTOR Descriptor;
321
322 /* Increase nesting depth */
323 ++MmDescriptorCallTreeCount;
324
325 /* Bail out if no address was specified */
326 if (!BaseAddress)
327 {
328 Status = STATUS_INVALID_PARAMETER;
329 goto Quickie;
330 }
331
332 /* Bail out if no page count was passed in, or a bad list was specified */
333 if (!(Pages) ||
334 ((NewList != &MmMdlUnmappedAllocated) &&
335 (NewList != &MmMdlPersistentMemory)))
336 {
337 Status = STATUS_INVALID_PARAMETER;
338 goto Quickie;
339 }
340
341 /* Bail out if the passed in range is invalid */
342 if ((Range) && (Range->Minimum >= Range->Maximum))
343 {
344 Status = STATUS_INVALID_PARAMETER;
345 goto Quickie;
346 }
347
348 /* Adjust alignment as needed */
349 if (!Alignment)
350 {
351 Alignment = 1;
352 }
353
354 /* Clear the virtual range */
355 Request.VirtualRange.Minimum = 0;
356 Request.VirtualRange.Maximum = 0;
357
358 /* Check if a fixed allocation was requested*/
359 if (Attributes & BlMemoryFixed)
360 {
361 /* Force the only available range to be the passed in address */
362 Request.BaseRange.Minimum = BaseAddress->QuadPart >> PAGE_SHIFT;
363 Request.BaseRange.Maximum = Request.BaseRange.Minimum + Pages - 1;
364 }
365 else if (Range)
366 {
367 /* Otherwise, a manual range was specified, use it */
368 Request.BaseRange.Minimum = Range->Minimum >> PAGE_SHIFT;
369 Request.BaseRange.Maximum = Request.BaseRange.Minimum +
370 (Range->Maximum >> PAGE_SHIFT) - 1;
371 }
372 else
373 {
374 /* Otherwise, use any possible range of pages */
375 Request.BaseRange.Minimum = PapMinimumPhysicalPage;
376 Request.BaseRange.Maximum = MAXULONG >> PAGE_SHIFT;
377 }
378
379 /* Check if no type was specified, or if it was invalid */
380 if (!(RangeType) ||
381 (RangeType & ~(BL_MM_REQUEST_TOP_DOWN_TYPE | BL_MM_REQUEST_DEFAULT_TYPE)))
382 {
383 /* Use default type */
384 Request.Type = BL_MM_REQUEST_DEFAULT_TYPE;
385 }
386 else
387 {
388 /* Use the requested type */
389 Request.Type = RangeType;
390 }
391
392 /* Capture the other request parameters */
393 Request.Alignment = Alignment;
394 Request.Pages = Pages;
395 Request.Flags = Attributes;
396 Status = MmPaAllocatePages(NewList,
397 &Descriptor,
398 &MmMdlUnmappedUnallocated,
399 &Request,
400 MemoryType);
401 if (NT_SUCCESS(Status))
402 {
403 /* We got a descriptor back, return its address */
404 BaseAddress->QuadPart = Descriptor.BasePage << PAGE_SHIFT;
405 }
406
407 Quickie:
408 /* Restore the nesting depth */
409 MmMdFreeGlobalDescriptors();
410 --MmDescriptorCallTreeCount;
411 return Status;
412 }
413
414 NTSTATUS
415 MmPapAllocatePagesInRange (
416 _Inout_ PVOID* PhysicalAddress,
417 _In_ BL_MEMORY_TYPE MemoryType,
418 _In_ ULONGLONG Pages,
419 _In_ ULONG Attributes,
420 _In_ ULONG Alignment,
421 _In_opt_ PBL_ADDRESS_RANGE Range,
422 _In_ ULONG Type
423 )
424 {
425 NTSTATUS Status;
426 PHYSICAL_ADDRESS BaseAddress;
427
428 /* Increment nesting depth */
429 ++MmDescriptorCallTreeCount;
430
431 /* Check for missing parameters or invalid range */
432 if (!(PhysicalAddress) ||
433 !(Pages) ||
434 ((Range) && (Range->Minimum >= Range->Maximum)))
435 {
436 Status = STATUS_INVALID_PARAMETER;
437 goto Exit;
438 }
439
440 /* What translation mode are we using? */
441 if (MmTranslationType != BlNone)
442 {
443 /* We don't support virtual memory yet @TODO */
444 EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
445 EfiStall(1000000);
446 Status = STATUS_NOT_IMPLEMENTED;
447 goto Exit;
448 }
449 else
450 {
451 /* Check if this is a fixed allocation */
452 BaseAddress.QuadPart = (Attributes & BlMemoryFixed) ? (ULONG_PTR)*PhysicalAddress : 0;
453
454 /* Allocate the pages */
455 Status = MmPapAllocatePhysicalPagesInRange(&BaseAddress,
456 MemoryType,
457 Pages,
458 Attributes,
459 Alignment,
460 (&MmMdlMappedAllocated !=
461 &MmMdlPersistentMemory) ?
462 &MmMdlUnmappedAllocated :
463 &MmMdlMappedAllocated,
464 Range,
465 Type);
466
467 /* Return the allocated address */
468 *PhysicalAddress = (PVOID)BaseAddress.LowPart;
469 }
470
471 Exit:
472 /* Restore the nesting depth */
473 MmMdFreeGlobalDescriptors();
474 --MmDescriptorCallTreeCount;
475 return Status;
476 }
477
478 NTSTATUS
479 MmPaInitialize (
480 __in PBL_MEMORY_DATA BootMemoryData,
481 __in ULONG MinimumAllocationCount
482 )
483 {
484 NTSTATUS Status;
485 ULONG ExistingDescriptors, FinalOffset;
486 PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor;
487
488 /* Initialize physical allocator variables */
489 PapMaximumPhysicalPage = 0xFFFFFFFFFFFFF;
490 PapMinimumAllocationCount = MinimumAllocationCount;
491 PapMinimumPhysicalPage = 0;
492
493 /* Initialize all the lists */
494 MmMdInitializeListHead(&MmMdlMappedAllocated);
495 MmMdInitializeListHead(&MmMdlMappedUnallocated);
496 MmMdInitializeListHead(&MmMdlFwAllocationTracker);
497 MmMdInitializeListHead(&MmMdlUnmappedAllocated);
498 MmMdInitializeListHead(&MmMdlReservedAllocated);
499 MmMdInitializeListHead(&MmMdlBadMemory);
500 MmMdInitializeListHead(&MmMdlTruncatedMemory);
501 MmMdInitializeListHead(&MmMdlPersistentMemory);
502 MmMdInitializeListHead(&MmMdlUnmappedUnallocated);
503 MmMdInitializeListHead(&MmMdlCompleteBadMemory);
504
505 /* Get the BIOS memory map */
506 Status = MmFwGetMemoryMap(&MmMdlUnmappedUnallocated,
507 BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS |
508 BL_MM_FLAG_REQUEST_COALESCING);
509 if (NT_SUCCESS(Status))
510 {
511 #if 0
512 PLIST_ENTRY listHead, nextEntry;
513
514 /* Loop the NT firmware memory list */
515 EfiPrintf(L"NT MEMORY MAP\n\r\n");
516 listHead = &MmMdlUnmappedUnallocated.ListHead;
517 nextEntry = listHead->Flink;
518 while (listHead != nextEntry)
519 {
520 Descriptor = CONTAINING_RECORD(nextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
521
522 EfiPrintf(L"Type: %08lX Flags: %08lX Base: 0x%016I64X End: 0x%016I64X\r\n",
523 Descriptor->Type,
524 Descriptor->Flags,
525 Descriptor->BasePage << PAGE_SHIFT,
526 (Descriptor->BasePage + Descriptor->PageCount) << PAGE_SHIFT);
527
528 nextEntry = nextEntry->Flink;
529 }
530 #endif
531
532 /*
533 * Because BL supports cross x86-x64 application launches and a LIST_ENTRY
534 * is of variable size, care must be taken here to ensure that we see a
535 * consistent view of descriptors. BL uses some offset magic to figure out
536 * where the data actually starts, since everything is ULONGLONG past the
537 * LIST_ENTRY itself
538 */
539 FinalOffset = BootMemoryData->MdListOffset + BootMemoryData->DescriptorOffset;
540 Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)BootMemoryData + FinalOffset -
541 FIELD_OFFSET(BL_MEMORY_DESCRIPTOR, BasePage));
542
543 /* Scan all of them */
544 ExistingDescriptors = BootMemoryData->DescriptorCount;
545 while (ExistingDescriptors != 0)
546 {
547 /* Remove this region from our free memory MDL */
548 Status = MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedUnallocated,
549 BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
550 Descriptor->BasePage,
551 Descriptor->PageCount,
552 NULL);
553 if (!NT_SUCCESS(Status))
554 {
555 return STATUS_INVALID_PARAMETER;
556 }
557
558 /* Build a descriptor for it */
559 NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
560 Descriptor->Type,
561 Descriptor->BasePage,
562 Descriptor->VirtualPage,
563 Descriptor->PageCount);
564 if (!NewDescriptor)
565 {
566 return STATUS_NO_MEMORY;
567 }
568
569 /* And add this region to the reserved & allocated MDL */
570 Status = MmMdAddDescriptorToList(&MmMdlReservedAllocated, NewDescriptor, 0);
571 if (!NT_SUCCESS(Status))
572 {
573 return Status;
574 }
575
576 /* Move on to the next descriptor */
577 ExistingDescriptors--;
578 Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)Descriptor + BootMemoryData->DescriptorSize);
579 }
580
581 /* We are done, so check for any RAM constraints which will make us truncate memory */
582 Status = BlpMmInitializeConstraints();
583 if (NT_SUCCESS(Status))
584 {
585 /* The Page Allocator has initialized */
586 PapInitializationStatus = TRUE;
587 Status = STATUS_SUCCESS;
588 }
589 }
590
591 /* Return status */
592 return Status;
593 }
594
595 NTSTATUS
596 BlMmAllocatePhysicalPages(
597 _In_ PPHYSICAL_ADDRESS Address,
598 _In_ BL_MEMORY_TYPE MemoryType,
599 _In_ ULONGLONG PageCount,
600 _In_ ULONG Attributes,
601 _In_ ULONG Alignment
602 )
603 {
604 /* Call the physical allocator */
605 return MmPapAllocatePhysicalPagesInRange(Address,
606 MemoryType,
607 PageCount,
608 Attributes,
609 Alignment,
610 &MmMdlUnmappedAllocated,
611 NULL,
612 0);
613 }
614
615 NTSTATUS
616 MmPapFreePhysicalPages (
617 _In_ ULONG WhichList,
618 _In_ ULONGLONG PageCount,
619 _In_ PHYSICAL_ADDRESS Address
620 )
621 {
622 PBL_MEMORY_DESCRIPTOR Descriptor;
623 ULONGLONG Page;
624 ULONG DescriptorFlags, Flags;
625 BOOLEAN DontFree, HasPageData;
626 BL_LIBRARY_PARAMETERS LibraryParameters;
627 NTSTATUS Status;
628
629 /* Set some defaults */
630 Flags = BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG;
631 DontFree = FALSE;
632 HasPageData = FALSE;
633
634 /* Only page-aligned addresses are accepted */
635 if (Address.QuadPart & (PAGE_SIZE - 1))
636 {
637 EfiPrintf(L"free mem fail 1\r\n");
638 return STATUS_INVALID_PARAMETER;
639 }
640
641 /* Try to find the descriptor containing this address */
642 Page = Address.QuadPart >> PAGE_SHIFT;
643 Descriptor = MmMdFindDescriptor(WhichList,
644 BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
645 Page);
646 if (!Descriptor)
647 {
648 EfiPrintf(L"free mem fail 2\r\n");
649 return STATUS_INVALID_PARAMETER;
650 }
651
652 /* If a page count was given, it must match, unless it's coalesced */
653 DescriptorFlags = Descriptor->Flags;
654 if (!(DescriptorFlags & BlMemoryCoalesced) &&
655 (PageCount) && (PageCount != Descriptor->PageCount))
656 {
657 EfiPrintf(L"free mem fail 3\r\n");
658 return STATUS_INVALID_PARAMETER;
659 }
660
661 /* Check if this is persistent memory in teardown status */
662 if ((PapInitializationStatus == 2) &&
663 (DescriptorFlags & BlMemoryPersistent))
664 {
665 /* Then we should keep it */
666 DontFree = TRUE;
667 }
668 else
669 {
670 /* Mark it as non-persistent, since we're freeing it */
671 Descriptor->Flags &= ~BlMemoryPersistent;
672 }
673
674 /* Check if this memory contains paging data */
675 if ((Descriptor->Type == BlLoaderPageDirectory) ||
676 (Descriptor->Type == BlLoaderReferencePage))
677 {
678 HasPageData = TRUE;
679 }
680
681 /* Check if a page count was given */
682 if (PageCount)
683 {
684 /* The pages must fit within the descriptor */
685 if ((PageCount + Page - Descriptor->BasePage) > Descriptor->PageCount)
686 {
687 EfiPrintf(L"free mem fail 4\r\n");
688 return STATUS_INVALID_PARAMETER;
689 }
690 }
691 else
692 {
693 /* No page count given, so the address must be at the beginning then */
694 if (Descriptor->BasePage != Page)
695 {
696 EfiPrintf(L"free mem fail 5\r\n");
697 return STATUS_INVALID_PARAMETER;
698 }
699
700 /* And we'll use the page count in the descriptor */
701 PageCount = Descriptor->PageCount;
702 }
703
704 /* Copy library parameters since we will read them */
705 RtlCopyMemory(&LibraryParameters,
706 &BlpLibraryParameters,
707 sizeof(LibraryParameters));
708
709 /* Check if this is teardown */
710 if (PapInitializationStatus == 2)
711 {
712 EfiPrintf(L"Case 2 not yet handled!\r\n");
713 return STATUS_NOT_SUPPORTED;
714 }
715 else if (!DontFree)
716 {
717 /* Caller wants memory to be freed -- should we zero it? */
718 if (!(HasPageData) &&
719 (LibraryParameters.LibraryFlags &
720 BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE))
721 {
722 EfiPrintf(L"Freeing zero data not yet handled!\r\n");
723 return STATUS_NOT_SUPPORTED;
724 }
725 }
726
727 /* Now call into firmware to actually free the physical pages */
728 Status = MmFwFreePages(Page, PageCount);
729 if (!NT_SUCCESS(Status))
730 {
731 EfiPrintf(L"free mem fail 6\r\n");
732 return Status;
733 }
734
735 /* Remove the firmware flags */
736 Descriptor->Flags &= ~(BlMemoryNonFirmware |
737 BlMemoryFirmware |
738 BlMemoryPersistent);
739
740 /* If we're not actually freeing, don't coalesce with anyone nearby */
741 if (DontFree)
742 {
743 Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG;
744 }
745
746 /* Check if the entire allocation is being free*/
747 if (PageCount == Descriptor->PageCount)
748 {
749 /* Remove the descriptor from the allocated list */
750 MmMdRemoveDescriptorFromList(&MmMdlUnmappedAllocated, Descriptor);
751
752 /* Mark the entire descriptor as free */
753 Descriptor->Type = BlConventionalMemory;
754 }
755 else
756 {
757 /* Init a descriptor for what we're actually freeing */
758 Descriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
759 BlConventionalMemory,
760 Page,
761 0,
762 PageCount);
763 if (!Descriptor)
764 {
765 return STATUS_NO_MEMORY;
766 }
767
768 /* Remove the region from the existing descriptor */
769 Status = MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedAllocated,
770 BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
771 Page,
772 PageCount,
773 NULL);
774 if (!NT_SUCCESS(Status))
775 {
776 return Status;
777 }
778 }
779
780 /* Add the new descriptor into in the list (or the old, repurposed one) */
781 Descriptor->Flags &= ~BlMemoryCoalesced;
782 return MmMdAddDescriptorToList(&MmMdlUnmappedUnallocated, Descriptor, Flags);
783 }
784
785 NTSTATUS
786 BlMmFreePhysicalPages (
787 _In_ PHYSICAL_ADDRESS Address
788 )
789 {
790 /* Call the physical allocator */
791 return MmPapFreePhysicalPages(BL_MM_INCLUDE_UNMAPPED_ALLOCATED, 0, Address);
792 }
793
794 NTSTATUS
795 MmPapFreePages (
796 _In_ PVOID Address,
797 _In_ ULONG WhichList
798 )
799 {
800 PHYSICAL_ADDRESS PhysicalAddress;
801
802 /* Handle virtual memory scenario */
803 if (MmTranslationType != BlNone)
804 {
805 EfiPrintf(L"Unimplemented virtual path\r\n");
806 return STATUS_SUCCESS;
807 }
808
809 /* Physical memory should be in the unmapped allocated list */
810 if (WhichList != BL_MM_INCLUDE_PERSISTENT_MEMORY)
811 {
812 WhichList = BL_MM_INCLUDE_UNMAPPED_ALLOCATED;
813 }
814
815 /* Free it from there */
816 PhysicalAddress.QuadPart = (ULONG_PTR)Address;
817 return MmPapFreePhysicalPages(WhichList, 0, PhysicalAddress);
818 }
819
820 NTSTATUS
821 BlMmGetMemoryMap (
822 _In_ PLIST_ENTRY MemoryMap,
823 _In_ PBL_IMAGE_PARAMETERS MemoryParameters,
824 _In_ ULONG WhichTypes,
825 _In_ ULONG Flags
826 )
827 {
828 BL_MEMORY_DESCRIPTOR_LIST FirmwareMdList, FullMdList;
829 BOOLEAN DoFirmware, DoPersistent, DoTruncated, DoBad;
830 BOOLEAN DoReserved, DoUnmapUnalloc, DoUnmapAlloc;
831 BOOLEAN DoMapAlloc, DoMapUnalloc, DoFirmware2;
832 ULONG LoopCount, MdListCount, MdListSize, Used;
833 NTSTATUS Status;
834
835 /* Initialize the firmware list if we use it */
836 MmMdInitializeListHead(&FirmwareMdList);
837
838 /* Make sure we got our input parameters */
839 if (!(MemoryMap) || !(MemoryParameters))
840 {
841 return STATUS_INVALID_PARAMETER;
842 }
843
844 /* Either ask for firmware memory, or don't. Not neither */
845 if ((WhichTypes & ~BL_MM_INCLUDE_NO_FIRMWARE_MEMORY) &&
846 (WhichTypes & ~BL_MM_INCLUDE_ONLY_FIRMWARE_MEMORY))
847 {
848 return STATUS_INVALID_PARAMETER;
849 }
850
851 /* Either ask for firmware memory, or don't. Not both */
852 if ((WhichTypes & BL_MM_INCLUDE_NO_FIRMWARE_MEMORY) &&
853 (WhichTypes & BL_MM_INCLUDE_ONLY_FIRMWARE_MEMORY))
854 {
855 return STATUS_INVALID_PARAMETER;
856 }
857
858 /* Initialize the memory map list */
859 InitializeListHead(MemoryMap);
860
861 /* Check which types of memory to dump */
862 DoFirmware = WhichTypes & BL_MM_INCLUDE_FIRMWARE_MEMORY;
863 DoPersistent = WhichTypes & BL_MM_INCLUDE_PERSISTENT_MEMORY;
864 DoTruncated = WhichTypes & BL_MM_INCLUDE_TRUNCATED_MEMORY;
865 DoBad = WhichTypes & BL_MM_INCLUDE_BAD_MEMORY;
866 DoReserved = WhichTypes & BL_MM_INCLUDE_RESERVED_ALLOCATED;
867 DoUnmapUnalloc = WhichTypes & BL_MM_INCLUDE_UNMAPPED_UNALLOCATED;
868 DoUnmapAlloc = WhichTypes & BL_MM_INCLUDE_UNMAPPED_ALLOCATED;
869 DoMapAlloc = WhichTypes & BL_MM_INCLUDE_MAPPED_ALLOCATED;
870 DoMapUnalloc = WhichTypes & BL_MM_INCLUDE_MAPPED_UNALLOCATED;
871 DoFirmware2 = WhichTypes & BL_MM_INCLUDE_FIRMWARE_MEMORY_2;
872
873 /* Begin the attempt loop */
874 LoopCount = 0;
875 while (TRUE)
876 {
877 /* Count how many entries we will need */
878 MdListCount = 0;
879 if (DoMapAlloc) MdListCount = MmMdCountList(&MmMdlMappedAllocated);
880 if (DoMapUnalloc) MdListCount += MmMdCountList(&MmMdlMappedUnallocated);
881 if (DoUnmapAlloc) MdListCount += MmMdCountList(&MmMdlUnmappedAllocated);
882 if (DoUnmapUnalloc) MdListCount += MmMdCountList(&MmMdlUnmappedUnallocated);
883 if (DoReserved) MdListCount += MmMdCountList(&MmMdlReservedAllocated);
884 if (DoBad) MdListCount += MmMdCountList(&MmMdlBadMemory);
885 if (DoTruncated) MdListCount += MmMdCountList(&MmMdlTruncatedMemory);
886 if (DoPersistent) MdListCount += MmMdCountList(&MmMdlPersistentMemory);
887
888 /* Plus firmware entries */
889 if (DoFirmware)
890 {
891 /* Free the previous entries, if any */
892 MmMdFreeList(&FirmwareMdList);
893
894 /* Get the firmware map, coalesced */
895 Status = MmFwGetMemoryMap(&FirmwareMdList,
896 BL_MM_FLAG_REQUEST_COALESCING);
897 if (!NT_SUCCESS(Status))
898 {
899 goto Quickie;
900 }
901
902 /* We overwrite, since this type is exclusive */
903 MdListCount = MmMdCountList(&FirmwareMdList);
904 }
905
906 /* Plus firmware entries-2 */
907 if (DoFirmware2)
908 {
909 /* Free the previous entries, if any */
910 MmMdFreeList(&FirmwareMdList);
911
912 /* Get the firmware map, uncoalesced */
913 Status = MmFwGetMemoryMap(&FirmwareMdList, 0);
914 if (!NT_SUCCESS(Status))
915 {
916 goto Quickie;
917 }
918
919 /* We overwrite, since this type is exclusive */
920 MdListCount = MmMdCountList(&FirmwareMdList);
921 }
922
923 /* If there's no descriptors, we're done */
924 if (!MdListCount)
925 {
926 Status = STATUS_SUCCESS;
927 goto Quickie;
928 }
929
930 /* Check if the buffer we have is big enough */
931 if (MemoryParameters->BufferSize >=
932 (sizeof(BL_MEMORY_DESCRIPTOR) * MdListCount))
933 {
934 break;
935 }
936
937 /* It's not, allocate it, with a slack of 4 extra descriptors */
938 MdListSize = sizeof(BL_MEMORY_DESCRIPTOR) * (MdListCount + 4);
939
940 /* Except if we weren't asked to */
941 if (!(Flags & BL_MM_ADD_DESCRIPTOR_ALLOCATE_FLAG))
942 {
943 MemoryParameters->BufferSize = MdListSize;
944 Status = STATUS_BUFFER_TOO_SMALL;
945 goto Quickie;
946 }
947
948 /* Has it been less than 4 times we've tried this? */
949 if (++LoopCount <= 4)
950 {
951 /* Free the previous attempt, if any */
952 if (MemoryParameters->BufferSize)
953 {
954 BlMmFreeHeap(MemoryParameters->Buffer);
955 }
956
957 /* Allocate a new buffer */
958 MemoryParameters->BufferSize = MdListSize;
959 MemoryParameters->Buffer = BlMmAllocateHeap(MdListSize);
960 if (MemoryParameters->Buffer)
961 {
962 /* Try again */
963 continue;
964 }
965 }
966
967 /* If we got here, we're out of memory after 4 attempts */
968 Status = STATUS_NO_MEMORY;
969 goto Quickie;
970 }
971
972 /* We should have a buffer by now... */
973 if (MemoryParameters->Buffer)
974 {
975 /* Zero it out */
976 RtlZeroMemory(MemoryParameters->Buffer,
977 MdListCount * sizeof(BL_MEMORY_DESCRIPTOR));
978 }
979
980 /* Initialize our list of descriptors */
981 MmMdInitializeList(&FullMdList, 0, MemoryMap);
982 Used = 0;
983
984 /* Handle mapped, allocated */
985 if (DoMapAlloc)
986 {
987 Status = MmMdCopyList(&FullMdList,
988 &MmMdlMappedAllocated,
989 MemoryParameters->Buffer,
990 &Used,
991 MdListCount,
992 Flags);
993 }
994
995 /* Handle mapped, unallocated */
996 if (DoMapUnalloc)
997 {
998 Status = MmMdCopyList(&FullMdList,
999 &MmMdlMappedUnallocated,
1000 MemoryParameters->Buffer,
1001 &Used,
1002 MdListCount,
1003 Flags);
1004 }
1005
1006 /* Handle unmapped, allocated */
1007 if (DoUnmapAlloc)
1008 {
1009 Status = MmMdCopyList(&FullMdList,
1010 &MmMdlUnmappedAllocated,
1011 MemoryParameters->Buffer,
1012 &Used,
1013 MdListCount,
1014 Flags);
1015 }
1016
1017 /* Handle unmapped, unallocated */
1018 if (DoUnmapUnalloc)
1019 {
1020 Status = MmMdCopyList(&FullMdList,
1021 &MmMdlUnmappedUnallocated,
1022 MemoryParameters->Buffer,
1023 &Used,
1024 MdListCount,
1025 Flags);
1026 }
1027
1028 /* Handle reserved, allocated */
1029 if (DoReserved)
1030 {
1031 Status = MmMdCopyList(&FullMdList,
1032 &MmMdlReservedAllocated,
1033 MemoryParameters->Buffer,
1034 &Used,
1035 MdListCount,
1036 Flags);
1037 }
1038
1039 /* Handle bad */
1040 if (DoBad)
1041 {
1042 Status = MmMdCopyList(&FullMdList,
1043 &MmMdlBadMemory,
1044 MemoryParameters->Buffer,
1045 &Used,
1046 MdListCount,
1047 Flags);
1048 }
1049
1050 /* Handle truncated */
1051 if (DoTruncated)
1052 {
1053 Status = MmMdCopyList(&FullMdList,
1054 &MmMdlTruncatedMemory,
1055 MemoryParameters->Buffer,
1056 &Used,
1057 MdListCount,
1058 Flags);
1059 }
1060
1061 /* Handle persistent */
1062 if (DoPersistent)
1063 {
1064 Status = MmMdCopyList(&FullMdList,
1065 &MmMdlPersistentMemory,
1066 MemoryParameters->Buffer,
1067 &Used,
1068 MdListCount,
1069 Flags);
1070 }
1071
1072 /* Handle firmware */
1073 if (DoFirmware)
1074 {
1075 Status = MmMdCopyList(&FullMdList,
1076 &FirmwareMdList,
1077 MemoryParameters->Buffer,
1078 &Used,
1079 MdListCount,
1080 Flags);
1081 }
1082
1083 /* Handle firmware2 */
1084 if (DoFirmware2)
1085 {
1086 Status = MmMdCopyList(&FullMdList,
1087 &FirmwareMdList,
1088 MemoryParameters->Buffer,
1089 &Used,
1090 MdListCount,
1091 Flags);
1092 }
1093
1094 /* Add up the final size */
1095 Status = RtlULongLongToULong(Used * sizeof(BL_MEMORY_DESCRIPTOR),
1096 &MemoryParameters->ActualSize);
1097
1098 Quickie:
1099 MmMdFreeList(&FirmwareMdList);
1100 return Status;
1101 }
1102
1103 NTSTATUS
1104 MmPaReleaseSelfMapPages (
1105 _In_ PHYSICAL_ADDRESS Address
1106 )
1107 {
1108 PBL_MEMORY_DESCRIPTOR Descriptor;
1109 ULONGLONG BasePage;
1110 NTSTATUS Status;
1111
1112 /* Only page-aligned addresses are accepted */
1113 if (Address.QuadPart & (PAGE_SIZE - 1))
1114 {
1115 EfiPrintf(L"free mem fail 1\r\n");
1116 return STATUS_INVALID_PARAMETER;
1117 }
1118
1119 /* Get the base page, and find a descriptor that matches */
1120 BasePage = Address.QuadPart >> PAGE_SHIFT;
1121 Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_UNALLOCATED,
1122 BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
1123 BasePage);
1124 if (!(Descriptor) || (Descriptor->BasePage != BasePage))
1125 {
1126 return STATUS_INVALID_PARAMETER;
1127 }
1128
1129 /* Free the physical pages */
1130 Status = MmFwFreePages(BasePage, Descriptor->PageCount);
1131 if (!NT_SUCCESS(Status))
1132 {
1133 return Status;
1134 }
1135
1136 /* Remove the firmware flags */
1137 Descriptor->Flags &= ~(BlMemoryNonFirmware |
1138 BlMemoryFirmware |
1139 BlMemoryPersistent);
1140
1141 /* Set it as free memory */
1142 Descriptor->Type = BlConventionalMemory;
1143
1144 /* Create a new descriptor that's free memory, covering the old range */
1145 Descriptor = MmMdInitByteGranularDescriptor(0,
1146 BlConventionalMemory,
1147 BasePage,
1148 0,
1149 Descriptor->PageCount);
1150 if (!Descriptor)
1151 {
1152 return STATUS_NO_MEMORY;
1153 }
1154
1155 /* Insert it into the virtual free list */
1156 return MmMdAddDescriptorToList(&MmMdlFreeVirtual,
1157 Descriptor,
1158 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG |
1159 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
1160 }
1161
1162 NTSTATUS
1163 MmPaReserveSelfMapPages (
1164 _Inout_ PPHYSICAL_ADDRESS PhysicalAddress,
1165 _In_ ULONG Alignment,
1166 _In_ ULONG PageCount
1167 )
1168 {
1169 NTSTATUS Status;
1170 BL_PA_REQUEST Request;
1171 BL_MEMORY_DESCRIPTOR Descriptor;
1172
1173 /* Increment descriptor usage count */
1174 ++MmDescriptorCallTreeCount;
1175
1176 /* Bail if we don't have an address */
1177 if (!PhysicalAddress)
1178 {
1179 Status = STATUS_INVALID_PARAMETER;
1180 goto Quickie;
1181 }
1182
1183 /* Make a request for the required number of self-map pages */
1184 Request.BaseRange.Minimum = PapMinimumPhysicalPage;
1185 Request.BaseRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT;
1186 Request.VirtualRange.Minimum = 0;
1187 Request.VirtualRange.Maximum = 0;
1188 Request.Pages = PageCount;
1189 Request.Alignment = Alignment;
1190 Request.Type = BL_MM_REQUEST_DEFAULT_TYPE;
1191 Request.Flags = 0;;
1192 Status = MmPaAllocatePages(&MmMdlUnmappedUnallocated,
1193 &Descriptor,
1194 &MmMdlUnmappedUnallocated,
1195 &Request,
1196 BlLoaderSelfMap);
1197 if (!NT_SUCCESS(Status))
1198 {
1199 goto Quickie;
1200 }
1201
1202 /* Remove this region from free virtual memory */
1203 Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
1204 BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
1205 Descriptor.BasePage,
1206 Descriptor.PageCount,
1207 0);
1208 if (!NT_SUCCESS(Status))
1209 {
1210 goto Quickie;
1211 }
1212
1213 /* Return the physical address */
1214 PhysicalAddress->QuadPart = Descriptor.BasePage << PAGE_SHIFT;
1215
1216 Quickie:
1217 /* Free global descriptors and reduce the count by one */
1218 MmMdFreeGlobalDescriptors();
1219 --MmDescriptorCallTreeCount;
1220 return Status;
1221 }
1222