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