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