[BOOTMGR]: Fix bug in test.
[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"Virtual memory not yet supported\r\n");
192 return STATUS_NOT_IMPLEMENTED;
193 }
194
195 /* Does the memory we received not exactly fall onto the beginning of its descriptor? */
196 if (LocalDescriptor.BasePage != FoundDescriptor->BasePage)
197 {
198 TempDescriptor = MmMdInitByteGranularDescriptor(FoundDescriptor->Flags,
199 FoundDescriptor->Type,
200 FoundDescriptor->BasePage,
201 FoundDescriptor->VirtualPage,
202 LocalDescriptor.BasePage -
203 FoundDescriptor->BasePage);
204 Status = MmMdAddDescriptorToList(CurrentList, TempDescriptor, 0);
205 if (!NT_SUCCESS(Status))
206 {
207 return Status;
208 }
209 }
210
211 /* Does the memory we received not exactly fall onto the end of its descriptor? */
212 LocalEndPage = LocalDescriptor.PageCount + LocalDescriptor.BasePage;
213 FoundEndPage = FoundDescriptor->PageCount + FoundDescriptor->BasePage;
214 LocalVirtualEndPage = LocalDescriptor.VirtualPage ?
215 LocalDescriptor.VirtualPage + LocalDescriptor.PageCount : 0;
216 if (LocalEndPage != FoundEndPage)
217 {
218 TempDescriptor = MmMdInitByteGranularDescriptor(FoundDescriptor->Flags,
219 FoundDescriptor->Type,
220 LocalEndPage,
221 LocalVirtualEndPage,
222 FoundEndPage - LocalEndPage);
223 Status = MmMdAddDescriptorToList(CurrentList, TempDescriptor, 0);
224 if (!NT_SUCCESS(Status))
225 {
226 return Status;
227 }
228 }
229
230 /* We got the memory we needed */
231 Status = STATUS_SUCCESS;
232
233 /* Are we supposed to insert it into a new list? */
234 if (NewList)
235 {
236 /* Copy the allocated region descriptor into the one we found */
237 FoundDescriptor->BaseAddress = LocalDescriptor.BaseAddress;
238 FoundDescriptor->VirtualPage = LocalDescriptor.VirtualPage;
239 FoundDescriptor->PageCount = LocalDescriptor.PageCount;
240 FoundDescriptor->Type = Type;
241 FoundDescriptor->Flags = LocalDescriptor.Flags;
242
243 /* Remember if it came from EFI */
244 if (GotFwPages)
245 {
246 FoundDescriptor->Flags |= BlMemoryFirmware;
247 }
248
249 /* Add the descriptor to the requested list */
250 Status = MmMdAddDescriptorToList(NewList, FoundDescriptor, 0);
251 }
252 else
253 {
254 /* Free the descriptor, nobody wants to know about it anymore */
255 MmMdFreeDescriptor(FoundDescriptor);
256 }
257
258 /* Return the allocation region back */
259 RtlCopyMemory(Descriptor, &LocalDescriptor, sizeof(LocalDescriptor));
260 return Status;
261 }
262
263 NTSTATUS
264 MmPaAllocatePages (
265 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList,
266 _In_ PBL_MEMORY_DESCRIPTOR Descriptor,
267 _In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList,
268 _In_ PBL_PA_REQUEST Request,
269 _In_ BL_MEMORY_TYPE MemoryType
270 )
271 {
272 NTSTATUS Status;
273
274 /* Heap and page directory/table pages have a special flag */
275 if ((MemoryType >= BlLoaderHeap) && (MemoryType <= BlLoaderReferencePage))
276 {
277 Request->Flags |= BlMemorySpecial;
278 }
279
280 /* Try to find a free region of RAM matching this range and request */
281 Request->MemoryType = BlConventionalMemory;
282 Status = MmPapAllocateRegionFromMdl(NewList,
283 Descriptor,
284 CurrentList,
285 Request,
286 MemoryType);
287 if (Status == STATUS_NOT_FOUND)
288 {
289 /* Need to re-synchronize the memory map and check other lists */
290 EfiPrintf(L"No RAM found -- backup plan not yet implemented\r\n");
291 }
292
293 /* Did we get the region we wanted? */
294 if (NT_SUCCESS(Status))
295 {
296 /* All good, return back */
297 return Status;
298 }
299
300 /* Nope, we have to hunt for it elsewhere */
301 EfiPrintf(L"TODO\r\n");
302 return Status;
303 }
304
305 NTSTATUS
306 MmPapAllocatePhysicalPagesInRange (
307 _Inout_ PPHYSICAL_ADDRESS BaseAddress,
308 _In_ BL_MEMORY_TYPE MemoryType,
309 _In_ ULONGLONG Pages,
310 _In_ ULONG Attributes,
311 _In_ ULONG Alignment,
312 _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList,
313 _In_opt_ PBL_ADDRESS_RANGE Range,
314 _In_ ULONG RangeType
315 )
316 {
317 NTSTATUS Status;
318 BL_PA_REQUEST Request;
319 BL_MEMORY_DESCRIPTOR Descriptor;
320
321 /* Increase nesting depth */
322 ++MmDescriptorCallTreeCount;
323
324 /* Bail out if no address was specified */
325 if (!BaseAddress)
326 {
327 Status = STATUS_INVALID_PARAMETER;
328 goto Quickie;
329 }
330
331 /* Bail out if no page count was passed in, or a bad list was specified */
332 if (!(Pages) ||
333 ((NewList != &MmMdlUnmappedAllocated) &&
334 (NewList != &MmMdlPersistentMemory)))
335 {
336 Status = STATUS_INVALID_PARAMETER;
337 goto Quickie;
338 }
339
340 /* Bail out if the passed in range is invalid */
341 if ((Range) && (Range->Minimum >= Range->Maximum))
342 {
343 Status = STATUS_INVALID_PARAMETER;
344 goto Quickie;
345 }
346
347 /* Adjust alignment as needed */
348 if (!Alignment)
349 {
350 Alignment = 1;
351 }
352
353 /* Clear the virtual range */
354 Request.VirtualRange.Minimum = 0;
355 Request.VirtualRange.Maximum = 0;
356
357 /* Check if a fixed allocation was requested*/
358 if (Attributes & BlMemoryFixed)
359 {
360 /* Force the only available range to be the passed in address */
361 Request.BaseRange.Minimum = BaseAddress->QuadPart >> PAGE_SHIFT;
362 Request.BaseRange.Maximum = Request.BaseRange.Minimum + Pages - 1;
363 }
364 else if (Range)
365 {
366 /* Otherwise, a manual range was specified, use it */
367 Request.BaseRange.Minimum = Range->Minimum >> PAGE_SHIFT;
368 Request.BaseRange.Maximum = Request.BaseRange.Minimum +
369 (Range->Maximum >> PAGE_SHIFT) - 1;
370 }
371 else
372 {
373 /* Otherwise, use any possible range of pages */
374 Request.BaseRange.Minimum = PapMinimumPhysicalPage;
375 Request.BaseRange.Maximum = MAXULONG >> PAGE_SHIFT;
376 }
377
378 /* Check if no type was specified, or if it was invalid */
379 if (!(RangeType) ||
380 (RangeType & ~(BL_MM_REQUEST_TOP_DOWN_TYPE | BL_MM_REQUEST_DEFAULT_TYPE)))
381 {
382 /* Use default type */
383 Request.Type = BL_MM_REQUEST_DEFAULT_TYPE;
384 }
385 else
386 {
387 /* Use the requested type */
388 Request.Type = RangeType;
389 }
390
391 /* Capture the other request parameters */
392 Request.Alignment = Alignment;
393 Request.Pages = Pages;
394 Request.Flags = Attributes;
395 Status = MmPaAllocatePages(NewList,
396 &Descriptor,
397 &MmMdlUnmappedUnallocated,
398 &Request,
399 MemoryType);
400 if (NT_SUCCESS(Status))
401 {
402 /* We got a descriptor back, return its address */
403 BaseAddress->QuadPart = Descriptor.BasePage << PAGE_SHIFT;
404 }
405
406 Quickie:
407 /* Restore the nesting depth */
408 MmMdFreeGlobalDescriptors();
409 --MmDescriptorCallTreeCount;
410 return Status;
411 }
412
413 NTSTATUS
414 MmPapAllocatePagesInRange (
415 _Inout_ PVOID* PhysicalAddress,
416 _In_ BL_MEMORY_TYPE MemoryType,
417 _In_ ULONGLONG Pages,
418 _In_ ULONG Attributes,
419 _In_ ULONG Alignment,
420 _In_opt_ PBL_ADDRESS_RANGE Range,
421 _In_ ULONG Type
422 )
423 {
424 NTSTATUS Status;
425 PHYSICAL_ADDRESS BaseAddress;
426
427 /* Increment nesting depth */
428 ++MmDescriptorCallTreeCount;
429
430 /* Check for missing parameters or invalid range */
431 if (!(PhysicalAddress) ||
432 !(Pages) ||
433 ((Range) && (Range->Minimum >= Range->Maximum)))
434 {
435 Status = STATUS_INVALID_PARAMETER;
436 goto Exit;
437 }
438
439 /* What translation mode are we using? */
440 if (MmTranslationType != BlNone)
441 {
442 /* We don't support virtual memory yet */
443 Status = STATUS_NOT_IMPLEMENTED;
444 goto Exit;
445 }
446 else
447 {
448 /* Check if this is a fixed allocation */
449 BaseAddress.QuadPart = (Attributes & BlMemoryFixed) ? (ULONG_PTR)*PhysicalAddress : 0;
450
451 /* Allocate the pages */
452 Status = MmPapAllocatePhysicalPagesInRange(&BaseAddress,
453 MemoryType,
454 Pages,
455 Attributes,
456 Alignment,
457 (&MmMdlMappedAllocated !=
458 &MmMdlPersistentMemory) ?
459 &MmMdlUnmappedAllocated :
460 &MmMdlMappedAllocated,
461 Range,
462 Type);
463
464 /* Return the allocated address */
465 *PhysicalAddress = (PVOID)BaseAddress.LowPart;
466 }
467
468 Exit:
469 /* Restore the nesting depth */
470 MmMdFreeGlobalDescriptors();
471 --MmDescriptorCallTreeCount;
472 return Status;
473 }
474
475 NTSTATUS
476 MmPaInitialize (
477 __in PBL_MEMORY_DATA BootMemoryData,
478 __in ULONG MinimumAllocationCount
479 )
480 {
481 NTSTATUS Status;
482 ULONG ExistingDescriptors, FinalOffset;
483 PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor;
484
485 /* Initialize physical allocator variables */
486 PapMaximumPhysicalPage = 0xFFFFFFFFFFFFF;
487 PapMinimumAllocationCount = MinimumAllocationCount;
488 PapMinimumPhysicalPage = 0;
489
490 /* Initialize all the lists */
491 MmMdInitializeListHead(&MmMdlMappedAllocated);
492 MmMdInitializeListHead(&MmMdlMappedUnallocated);
493 MmMdInitializeListHead(&MmMdlFwAllocationTracker);
494 MmMdInitializeListHead(&MmMdlUnmappedAllocated);
495 MmMdInitializeListHead(&MmMdlReservedAllocated);
496 MmMdInitializeListHead(&MmMdlBadMemory);
497 MmMdInitializeListHead(&MmMdlTruncatedMemory);
498 MmMdInitializeListHead(&MmMdlPersistentMemory);
499 MmMdInitializeListHead(&MmMdlUnmappedUnallocated);
500 MmMdInitializeListHead(&MmMdlCompleteBadMemory);
501
502 /* Get the BIOS memory map */
503 Status = MmFwGetMemoryMap(&MmMdlUnmappedUnallocated,
504 BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS |
505 BL_MM_FLAG_REQUEST_COALESCING);
506 if (NT_SUCCESS(Status))
507 {
508 #if 0
509 PLIST_ENTRY listHead, nextEntry;
510
511 /* Loop the NT firmware memory list */
512 EfiPrintf(L"NT MEMORY MAP\n\r\n");
513 listHead = &MmMdlUnmappedUnallocated.ListHead;
514 nextEntry = listHead->Flink;
515 while (listHead != nextEntry)
516 {
517 Descriptor = CONTAINING_RECORD(nextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
518
519 EfiPrintf(L"Type: %08lX Flags: %08lX Base: 0x%016I64X End: 0x%016I64X\r\n",
520 Descriptor->Type,
521 Descriptor->Flags,
522 Descriptor->BasePage << PAGE_SHIFT,
523 (Descriptor->BasePage + Descriptor->PageCount) << PAGE_SHIFT);
524
525 nextEntry = nextEntry->Flink;
526 }
527 #endif
528
529 /*
530 * Because BL supports cross x86-x64 application launches and a LIST_ENTRY
531 * is of variable size, care must be taken here to ensure that we see a
532 * consistent view of descriptors. BL uses some offset magic to figure out
533 * where the data actually starts, since everything is ULONGLONG past the
534 * LIST_ENTRY itself
535 */
536 FinalOffset = BootMemoryData->MdListOffset + BootMemoryData->DescriptorOffset;
537 Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)BootMemoryData + FinalOffset -
538 FIELD_OFFSET(BL_MEMORY_DESCRIPTOR, BasePage));
539
540 /* Scan all of them */
541 ExistingDescriptors = BootMemoryData->DescriptorCount;
542 while (ExistingDescriptors != 0)
543 {
544 /* Remove this region from our free memory MDL */
545 Status = MmMdRemoveRegionFromMdlEx(&MmMdlUnmappedUnallocated,
546 0x40000000,
547 Descriptor->BasePage,
548 Descriptor->PageCount,
549 NULL);
550 if (!NT_SUCCESS(Status))
551 {
552 return STATUS_INVALID_PARAMETER;
553 }
554
555 /* Build a descriptor for it */
556 NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
557 Descriptor->Type,
558 Descriptor->BasePage,
559 Descriptor->VirtualPage,
560 Descriptor->PageCount);
561 if (!NewDescriptor)
562 {
563 return STATUS_NO_MEMORY;
564 }
565
566 /* And add this region to the reserved & allocated MDL */
567 Status = MmMdAddDescriptorToList(&MmMdlReservedAllocated, NewDescriptor, 0);
568 if (!NT_SUCCESS(Status))
569 {
570 return Status;
571 }
572
573 /* Move on to the next descriptor */
574 ExistingDescriptors--;
575 Descriptor = (PBL_MEMORY_DESCRIPTOR)((ULONG_PTR)Descriptor + BootMemoryData->DescriptorSize);
576 }
577
578 /* We are done, so check for any RAM constraints which will make us truncate memory */
579 Status = BlpMmInitializeConstraints();
580 if (NT_SUCCESS(Status))
581 {
582 /* The Page Allocator has initialized */
583 PapInitializationStatus = TRUE;
584 Status = STATUS_SUCCESS;
585 }
586 }
587
588 /* Return status */
589 return Status;
590 }
591
592 NTSTATUS
593 BlMmAllocatePhysicalPages(
594 _In_ PPHYSICAL_ADDRESS Address,
595 _In_ BL_MEMORY_TYPE MemoryType,
596 _In_ ULONGLONG PageCount,
597 _In_ ULONG Attributes,
598 _In_ ULONG Alignment
599 )
600 {
601 /* Call the physical allocator */
602 return MmPapAllocatePhysicalPagesInRange(Address,
603 MemoryType,
604 PageCount,
605 Attributes,
606 Alignment,
607 &MmMdlUnmappedAllocated,
608 NULL,
609 0);
610 }
611
612 NTSTATUS
613 MmPapFreePhysicalPages (
614 _In_ ULONG WhichList,
615 _In_ ULONGLONG PageCount,
616 _In_ PHYSICAL_ADDRESS Address
617 )
618 {
619 PBL_MEMORY_DESCRIPTOR Descriptor;
620 ULONGLONG Page;
621 ULONG DescriptorFlags, Flags;
622 BOOLEAN DontFree, HasPageData;
623 BL_LIBRARY_PARAMETERS LibraryParameters;
624 NTSTATUS Status;
625
626 /* Set some defaults */
627 Flags = BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG;
628 DontFree = FALSE;
629 HasPageData = FALSE;
630
631 /* Only page-aligned addresses a re accepted */
632 if (Address.QuadPart & (PAGE_SIZE - 1))
633 {
634 EfiPrintf(L"free mem fail 1\r\n");
635 return STATUS_INVALID_PARAMETER;
636 }
637
638 /* Try to find the descriptor containing this address */
639 Page = Address.QuadPart >> PAGE_SHIFT;
640 Descriptor = MmMdFindDescriptor(WhichList,
641 BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
642 Page);
643 if (!Descriptor)
644 {
645 EfiPrintf(L"free mem fail 2\r\n");
646 return STATUS_INVALID_PARAMETER;
647 }
648
649 /* If a page count was given, it must match, unless it's coalesced */
650 DescriptorFlags = Descriptor->Flags;
651 if (!(DescriptorFlags & BlMemoryCoalesced) &&
652 (PageCount) && (PageCount != Descriptor->PageCount))
653 {
654 EfiPrintf(L"free mem fail 3\r\n");
655 return STATUS_INVALID_PARAMETER;
656 }
657
658 /* Check if this is persistent memory in teardown status */
659 if ((PapInitializationStatus == 2) &&
660 (DescriptorFlags & BlMemoryPersistent))
661 {
662 /* Then we should keep it */
663 DontFree = TRUE;
664 }
665 else
666 {
667 /* Mark it as non-persistent, since we're freeing it */
668 Descriptor->Flags &= ~BlMemoryPersistent;
669 }
670
671 /* Check if this memory contains paging data */
672 if ((Descriptor->Type == BlLoaderPageDirectory) ||
673 (Descriptor->Type == BlLoaderReferencePage))
674 {
675 HasPageData = TRUE;
676 }
677
678 /* Check if a page count was given */
679 if (PageCount)
680 {
681 /* The pages must fit within the descriptor */
682 if ((PageCount + Page - Descriptor->BasePage) > Descriptor->PageCount)
683 {
684 EfiPrintf(L"free mem fail 4\r\n");
685 return STATUS_INVALID_PARAMETER;
686 }
687 }
688 else
689 {
690 /* No page count given, so the address must be at the beginning then */
691 if (Descriptor->BasePage != Page)
692 {
693 EfiPrintf(L"free mem fail 5\r\n");
694 return STATUS_INVALID_PARAMETER;
695 }
696
697 /* And we'll use the page count in the descriptor */
698 PageCount = Descriptor->PageCount;
699 }
700
701 /* Copy library parameters since we will read them */
702 RtlCopyMemory(&LibraryParameters,
703 &BlpLibraryParameters,
704 sizeof(LibraryParameters));
705
706 /* Check if this is teardown */
707 if (PapInitializationStatus == 2)
708 {
709 EfiPrintf(L"Case 2 not yet handled!\r\n");
710 return STATUS_NOT_SUPPORTED;
711 }
712 else if (!DontFree)
713 {
714 /* Caller wants memory to be freed -- should we zero it? */
715 if (!(HasPageData) &
716 (LibraryParameters.LibraryFlags &
717 BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE))
718 {
719 EfiPrintf(L"Freeing zero data not yet handled!\r\n");
720 return STATUS_NOT_SUPPORTED;
721 }
722 }
723
724 /* Now call into firmware to actually free the physical pages */
725 Status = MmFwFreePages(Page, PageCount);
726 if (!NT_SUCCESS(Status))
727 {
728 EfiPrintf(L"free mem fail 6\r\n");
729 return Status;
730 }
731
732 /* Remove the firmware flags */
733 Descriptor->Flags &= ~(BlMemoryNonFirmware |
734 BlMemoryFirmware |
735 BlMemoryPersistent);
736
737 /* If we're not actually freeing, don't coalesce with anyone nearby */
738 if (DontFree)
739 {
740 Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG;
741 }
742
743 /* TBD */
744 EfiPrintf(L"Leaking memory: %p!\r\n", Address.QuadPart);
745 return STATUS_SUCCESS;
746 }
747
748 NTSTATUS
749 BlMmFreePhysicalPages (
750 _In_ PHYSICAL_ADDRESS Address
751 )
752 {
753 /* Call the physical allocator */
754 return MmPapFreePhysicalPages(BL_MM_INCLUDE_UNMAPPED_ALLOCATED, 0, Address);
755 }
756
757 NTSTATUS
758 MmPapFreePages (
759 _In_ PVOID Address,
760 _In_ ULONG WhichList
761 )
762 {
763 PHYSICAL_ADDRESS PhysicalAddress;
764
765 /* Handle virtual memory scenario */
766 if (MmTranslationType != BlNone)
767 {
768 EfiPrintf(L"Unimplemented virtual path\r\n");
769 return STATUS_SUCCESS;
770 }
771
772 /* Physical memory should be in the unmapped allocated list */
773 if (WhichList != BL_MM_INCLUDE_PERSISTENT_MEMORY)
774 {
775 WhichList = BL_MM_INCLUDE_UNMAPPED_ALLOCATED;
776 }
777
778 /* Free it from there */
779 PhysicalAddress.QuadPart = (ULONG_PTR)Address;
780 return MmPapFreePhysicalPages(WhichList, 0, PhysicalAddress);
781 }
782
783 NTSTATUS
784 BlMmGetMemoryMap (
785 _In_ PLIST_ENTRY MemoryMap,
786 _In_ PBL_IMAGE_PARAMETERS MemoryParameters,
787 _In_ ULONG WhichTypes,
788 _In_ ULONG Flags
789 )
790 {
791 BL_MEMORY_DESCRIPTOR_LIST FirmwareMdList, FullMdList;
792 BOOLEAN DoFirmware, DoPersistent, DoTruncated, DoBad;
793 BOOLEAN DoReserved, DoUnmapUnalloc, DoUnmapAlloc;
794 BOOLEAN DoMapAlloc, DoMapUnalloc, DoFirmware2;
795 ULONG LoopCount, MdListCount, MdListSize, Used;
796 NTSTATUS Status;
797
798 /* Initialize the firmware list if we use it */
799 MmMdInitializeListHead(&FirmwareMdList);
800
801 /* Make sure we got our input parameters */
802 if (!(MemoryMap) || !(MemoryParameters))
803 {
804 return STATUS_INVALID_PARAMETER;
805 }
806
807 /* Either ask for firmware memory, or don't. Not neither */
808 if ((WhichTypes & ~BL_MM_INCLUDE_NO_FIRMWARE_MEMORY) &&
809 (WhichTypes & ~BL_MM_INCLUDE_ONLY_FIRMWARE_MEMORY))
810 {
811 return STATUS_INVALID_PARAMETER;
812 }
813
814 /* Either ask for firmware memory, or don't. Not both */
815 if ((WhichTypes & BL_MM_INCLUDE_NO_FIRMWARE_MEMORY) &&
816 (WhichTypes & BL_MM_INCLUDE_ONLY_FIRMWARE_MEMORY))
817 {
818 return STATUS_INVALID_PARAMETER;
819 }
820
821 /* Initialize the memory map list */
822 InitializeListHead(MemoryMap);
823
824 /* Check which types of memory to dump */
825 DoFirmware = WhichTypes & BL_MM_INCLUDE_FIRMWARE_MEMORY;
826 DoPersistent = WhichTypes & BL_MM_INCLUDE_PERSISTENT_MEMORY;
827 DoTruncated = WhichTypes & BL_MM_INCLUDE_TRUNCATED_MEMORY;
828 DoBad = WhichTypes & BL_MM_INCLUDE_BAD_MEMORY;
829 DoReserved = WhichTypes & BL_MM_INCLUDE_RESERVED_ALLOCATED;
830 DoUnmapUnalloc = WhichTypes & BL_MM_INCLUDE_UNMAPPED_UNALLOCATED;
831 DoUnmapAlloc = WhichTypes & BL_MM_INCLUDE_UNMAPPED_ALLOCATED;
832 DoMapAlloc = WhichTypes & BL_MM_INCLUDE_MAPPED_ALLOCATED;
833 DoMapUnalloc = WhichTypes & BL_MM_INCLUDE_MAPPED_UNALLOCATED;
834 DoFirmware2 = WhichTypes & BL_MM_INCLUDE_FIRMWARE_MEMORY_2;
835
836 /* Begin the attempt loop */
837 LoopCount = 0;
838 while (TRUE)
839 {
840 /* Count how many entries we will need */
841 MdListCount = 0;
842 if (DoMapAlloc) MdListCount = MmMdCountList(&MmMdlMappedAllocated);
843 if (DoMapUnalloc) MdListCount += MmMdCountList(&MmMdlMappedUnallocated);
844 if (DoUnmapAlloc) MdListCount += MmMdCountList(&MmMdlUnmappedAllocated);
845 if (DoUnmapUnalloc) MdListCount += MmMdCountList(&MmMdlUnmappedUnallocated);
846 if (DoReserved) MdListCount += MmMdCountList(&MmMdlReservedAllocated);
847 if (DoBad) MdListCount += MmMdCountList(&MmMdlBadMemory);
848 if (DoTruncated) MdListCount += MmMdCountList(&MmMdlTruncatedMemory);
849 if (DoPersistent) MdListCount += MmMdCountList(&MmMdlPersistentMemory);
850
851 /* Plus firmware entries */
852 if (DoFirmware)
853 {
854 /* Free the previous entries, if any */
855 MmMdFreeList(&FirmwareMdList);
856
857 /* Get the firmware map */
858 Status = MmFwGetMemoryMap(&FirmwareMdList, 2);
859 if (!NT_SUCCESS(Status))
860 {
861 goto Quickie;
862 }
863
864 /* We overwrite, since this type is exclusive */
865 MdListCount = MmMdCountList(&FirmwareMdList);
866 }
867
868 /* Plus firmware entries-2 */
869 if (DoFirmware2)
870 {
871 /* Free the previous entries, if any */
872 MmMdFreeList(&FirmwareMdList);
873
874 /* Get the firmware map */
875 Status = MmFwGetMemoryMap(&FirmwareMdList, 0);
876 if (!NT_SUCCESS(Status))
877 {
878 goto Quickie;
879 }
880
881 /* We overwrite, since this type is exclusive */
882 MdListCount = MmMdCountList(&FirmwareMdList);
883 }
884
885 /* If there's no descriptors, we're done */
886 if (!MdListCount)
887 {
888 Status = STATUS_SUCCESS;
889 goto Quickie;
890 }
891
892 /* Check if the buffer we have is big enough */
893 if (MemoryParameters->BufferSize >=
894 (sizeof(BL_MEMORY_DESCRIPTOR) * MdListCount))
895 {
896 break;
897 }
898
899 /* It's not, allocate it, with a slack of 4 extra descriptors */
900 MdListSize = sizeof(BL_MEMORY_DESCRIPTOR) * (MdListCount + 4);
901
902 /* Except if we weren't asked to */
903 if (!(Flags & BL_MM_ADD_DESCRIPTOR_ALLOCATE_FLAG))
904 {
905 MemoryParameters->BufferSize = MdListSize;
906 Status = STATUS_BUFFER_TOO_SMALL;
907 goto Quickie;
908 }
909
910 /* Has it been less than 4 times we've tried this? */
911 if (++LoopCount <= 4)
912 {
913 /* Free the previous attempt, if any */
914 if (MemoryParameters->BufferSize)
915 {
916 BlMmFreeHeap(MemoryParameters->Buffer);
917 }
918
919 /* Allocate a new buffer */
920 MemoryParameters->BufferSize = MdListSize;
921 MemoryParameters->Buffer = BlMmAllocateHeap(MdListSize);
922 if (MemoryParameters->Buffer)
923 {
924 /* Try again */
925 continue;
926 }
927 }
928
929 /* If we got here, we're out of memory after 4 attempts */
930 Status = STATUS_NO_MEMORY;
931 goto Quickie;
932 }
933
934 /* We should have a buffer by now... */
935 if (MemoryParameters->Buffer)
936 {
937 /* Zero it out */
938 RtlZeroMemory(MemoryParameters->Buffer,
939 MdListCount * sizeof(BL_MEMORY_DESCRIPTOR));
940 }
941
942 /* Initialize our list of descriptors */
943 MmMdInitializeList(&FullMdList, 0, MemoryMap);
944 Used = 0;
945
946 /* Handle mapped, allocated */
947 if (DoMapAlloc)
948 {
949 Status = MmMdCopyList(&FullMdList,
950 &MmMdlMappedAllocated,
951 MemoryParameters->Buffer,
952 &Used,
953 MdListCount,
954 Flags);
955 }
956
957 /* Handle mapped, unallocated */
958 if (DoMapUnalloc)
959 {
960 Status = MmMdCopyList(&FullMdList,
961 &MmMdlMappedUnallocated,
962 MemoryParameters->Buffer,
963 &Used,
964 MdListCount,
965 Flags);
966 }
967
968 /* Handle unmapped, allocated */
969 if (DoUnmapAlloc)
970 {
971 Status = MmMdCopyList(&FullMdList,
972 &MmMdlUnmappedAllocated,
973 MemoryParameters->Buffer,
974 &Used,
975 MdListCount,
976 Flags);
977 }
978
979 /* Handle unmapped, unallocated */
980 if (DoUnmapUnalloc)
981 {
982 Status = MmMdCopyList(&FullMdList,
983 &MmMdlUnmappedUnallocated,
984 MemoryParameters->Buffer,
985 &Used,
986 MdListCount,
987 Flags);
988 }
989
990 /* Handle reserved, allocated */
991 if (DoReserved)
992 {
993 Status = MmMdCopyList(&FullMdList,
994 &MmMdlReservedAllocated,
995 MemoryParameters->Buffer,
996 &Used,
997 MdListCount,
998 Flags);
999 }
1000
1001 /* Handle bad */
1002 if (DoBad)
1003 {
1004 Status = MmMdCopyList(&FullMdList,
1005 &MmMdlBadMemory,
1006 MemoryParameters->Buffer,
1007 &Used,
1008 MdListCount,
1009 Flags);
1010 }
1011
1012 /* Handle truncated */
1013 if (DoTruncated)
1014 {
1015 Status = MmMdCopyList(&FullMdList,
1016 &MmMdlTruncatedMemory,
1017 MemoryParameters->Buffer,
1018 &Used,
1019 MdListCount,
1020 Flags);
1021 }
1022
1023 /* Handle persistent */
1024 if (DoPersistent)
1025 {
1026 Status = MmMdCopyList(&FullMdList,
1027 &MmMdlPersistentMemory,
1028 MemoryParameters->Buffer,
1029 &Used,
1030 MdListCount,
1031 Flags);
1032 }
1033
1034 /* Handle firmware */
1035 if (DoFirmware)
1036 {
1037 Status = MmMdCopyList(&FullMdList,
1038 &FirmwareMdList,
1039 MemoryParameters->Buffer,
1040 &Used,
1041 MdListCount,
1042 Flags);
1043 }
1044
1045 /* Handle firmware2 */
1046 if (DoFirmware2)
1047 {
1048 Status = MmMdCopyList(&FullMdList,
1049 &FirmwareMdList,
1050 MemoryParameters->Buffer,
1051 &Used,
1052 MdListCount,
1053 Flags);
1054 }
1055
1056 /* Add up the final size */
1057 Status = RtlULongLongToULong(Used * sizeof(BL_MEMORY_DESCRIPTOR),
1058 &MemoryParameters->ActualSize);
1059
1060 Quickie:
1061 MmMdFreeList(&FirmwareMdList);
1062 return Status;
1063 }