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