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