bb2f66a1afdbb73c96ead98140b1ecbaadf96ca0
[reactos.git] / reactos / boot / environ / lib / mm / descriptor.c
1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/mm/descriptor.c
5 * PURPOSE: Boot Library Memory Manager Descriptor Manager
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12
13 /* DATA VARIABLES ************************************************************/
14
15 BL_MEMORY_DESCRIPTOR MmStaticMemoryDescriptors[512];
16 ULONG MmGlobalMemoryDescriptorCount;
17 PBL_MEMORY_DESCRIPTOR MmGlobalMemoryDescriptors;
18 ULONG MmGlobalMemoryDescriptorsUsed;
19 PBL_MEMORY_DESCRIPTOR MmDynamicMemoryDescriptors;
20 ULONG MmDynamicMemoryDescriptorCount;
21
22 BL_MEMORY_TYPE MmPlatformMemoryTypePrecedence[] =
23 {
24 BlReservedMemory,
25 BlUnusableMemory,
26 BlDeviceIoMemory,
27 BlDevicePortMemory,
28 BlPalMemory,
29 BlEfiRuntimeMemory,
30 BlAcpiNvsMemory,
31 BlAcpiReclaimMemory,
32 BlEfiBootMemory
33 };
34
35 /* FUNCTIONS *****************************************************************/
36
37 /* The order is Conventional > Other > System > Loader > Application */
38 BOOLEAN
39 MmMdpHasPrecedence (
40 _In_ BL_MEMORY_TYPE Type1,
41 _In_ BL_MEMORY_TYPE Type2
42 )
43 {
44 BL_MEMORY_CLASS Class1, Class2;
45 ULONG i, j;
46
47 /* Descriptor is free RAM -- it precedes */
48 if (Type1 == BlConventionalMemory)
49 {
50 return TRUE;
51 }
52
53 /* It isn't free RAM, but the comparator is -- it succeeds it */
54 if (Type2 == BlConventionalMemory)
55 {
56 return FALSE;
57 }
58
59 /* Descriptor is not system, application, or loader class -- it precedes */
60 Class1 = Type1 >> BL_MEMORY_CLASS_SHIFT;
61 if ((Class1 != BlSystemClass) &&
62 (Class1 != BlApplicationClass) &&
63 (Class1 != BlLoaderClass))
64 {
65 return TRUE;
66 }
67
68 /* It isn't one of those classes, but the comparator it -- it succeeds it */
69 Class2 = Type2 >> BL_MEMORY_CLASS_SHIFT;
70 if ((Class2 != BlSystemClass) &&
71 (Class2 != BlApplicationClass) &&
72 (Class2 != BlLoaderClass))
73 {
74 return FALSE;
75 }
76
77 /* Descriptor is system class */
78 if (Class1 == BlSystemClass)
79 {
80 /* And so is the other guy... */
81 if (Class2 == BlSystemClass)
82 {
83 i = 0;
84 j = 0;
85
86 /* Scan for the descriptor's system precedence index */
87 do
88 {
89 if (MmPlatformMemoryTypePrecedence[j] == Type1)
90 {
91 break;
92 }
93 } while (++j < RTL_NUMBER_OF(MmPlatformMemoryTypePrecedence));
94
95 /* Use an invalid index if one wasn't found */
96 if (j == RTL_NUMBER_OF(MmPlatformMemoryTypePrecedence))
97 {
98 j = 0xFFFFFFFF;
99 }
100
101 /* Now scan for the comparator's system precedence index */
102 while (MmPlatformMemoryTypePrecedence[i] != Type2)
103 {
104 /* Use an invalid index if one wasn't found */
105 if (++i >= RTL_NUMBER_OF(MmPlatformMemoryTypePrecedence))
106 {
107 i = 0xFFFFFFFF;
108 break;
109 }
110 }
111
112 /* Does the current have a valid index? */
113 if (j != 0xFFFFFFFF)
114 {
115 /* Yes, what about the comparator? */
116 if (i != 0xFFFFFFFF)
117 {
118 /* Let the indexes fight! */
119 return i >= j;
120 }
121
122 /* Succeed the comparator, its index is unknown */
123 return FALSE;
124 }
125 }
126
127 /* The comparator isn't system, so it precedes it */
128 return TRUE;
129 }
130
131 /* Descriptor is not system class, but comparator is -- it succeeds it */
132 if (Class2 == BlSystemClass)
133 {
134 return FALSE;
135 }
136
137 /* Descriptor is loader class -- it precedes */
138 if (Class1 == BlLoaderClass)
139 {
140 return TRUE;
141 }
142
143 /* It isn't loader class -- if the other guy is, succeed it */
144 return Class2 != BlLoaderClass;
145 }
146
147 VOID
148 MmMdpSwitchToDynamicDescriptors (
149 _In_ ULONG Count
150 )
151 {
152 EfiPrintf(L"Dynamic switch NOT SUPPORTED!!!\r\n");
153 EfiStall(10000000);
154 }
155
156 NTSTATUS
157 MmMdFreeDescriptor (
158 _In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor
159 )
160 {
161 NTSTATUS Status;
162
163 /* Check if this is a valid static descriptor */
164 if (((MmDynamicMemoryDescriptors) &&
165 (MemoryDescriptor >= MmDynamicMemoryDescriptors) &&
166 (MemoryDescriptor < (MmDynamicMemoryDescriptors + MmDynamicMemoryDescriptorCount))) ||
167 ((MemoryDescriptor >= MmStaticMemoryDescriptors) && (MemoryDescriptor < &MmStaticMemoryDescriptors[511])))
168 {
169 /* It's a global/static descriptor, so just zero it */
170 RtlZeroMemory(MemoryDescriptor, sizeof(BL_MEMORY_DESCRIPTOR));
171 Status = STATUS_SUCCESS;
172 }
173 else
174 {
175 /* It's a dynamic descriptor, so free it */
176 EfiPrintf(L"Freeing dynamic descriptors not yet supported\r\n");
177 EfiStall(10000000);
178 Status = STATUS_NOT_IMPLEMENTED;
179 }
180
181 /* Done */
182 return Status;
183 }
184
185 VOID
186 MmMdpSaveCurrentListPointer (
187 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
188 _In_ PLIST_ENTRY Current
189 )
190 {
191 /* Make sure that this is not a global descriptor and not the first one */
192 if (((Current < &MmGlobalMemoryDescriptors->ListEntry) ||
193 (Current >= &MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorCount].ListEntry)) &&
194 (Current != MdList->First))
195 {
196 /* Save this as the current pointer */
197 MdList->This = Current;
198 }
199 }
200
201 ULONG
202 MmMdCountList (
203 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList
204 )
205 {
206 PLIST_ENTRY First, NextEntry;
207 ULONG Count;
208
209 /* Iterate the list */
210 for (Count = 0, First = MdList->First, NextEntry = First->Flink;
211 NextEntry != First;
212 NextEntry = NextEntry->Flink, Count++);
213
214 /* Return the count */
215 return Count;
216 }
217
218 VOID
219 MmMdInitializeList (
220 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
221 _In_ ULONG Type,
222 _In_ PLIST_ENTRY ListHead
223 )
224 {
225 /* Check if a list was specified */
226 if (ListHead)
227 {
228 /* Use it */
229 MdList->First = ListHead;
230 }
231 else
232 {
233 /* Otherwise, use the internal, built-in list */
234 InitializeListHead(&MdList->ListHead);
235 MdList->First = &MdList->ListHead;
236 }
237
238 /* Set the type */
239 MdList->Type = Type;
240
241 /* Initialize current iterator to nothing */
242 MdList->This = NULL;
243 }
244
245 NTSTATUS
246 MmMdCopyList (
247 _In_ PBL_MEMORY_DESCRIPTOR_LIST DestinationList,
248 _In_ PBL_MEMORY_DESCRIPTOR_LIST SourceList,
249 _In_opt_ PBL_MEMORY_DESCRIPTOR ListDescriptor,
250 _Out_ PULONG ActualCount,
251 _In_ ULONG Count,
252 _In_ ULONG Flags
253 )
254 {
255 NTSTATUS Status;
256 PULONG Used;
257 PLIST_ENTRY First, NextEntry;
258 PBL_MEMORY_DESCRIPTOR Descriptor;
259
260 /* Both parameters must be present */
261 if (!(DestinationList) || !(SourceList))
262 {
263 return STATUS_INVALID_PARAMETER;
264 }
265
266 /* Assume success */
267 Status = STATUS_SUCCESS;
268
269 /* Check if a descriptor is being used to store the list */
270 if (ListDescriptor)
271 {
272 /* See how big it is */
273 Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG;
274 Used = ActualCount;
275 }
276 else
277 {
278 /* We are using our internal descriptors instead */
279 Used = &MmGlobalMemoryDescriptorsUsed;
280 ++MmDescriptorCallTreeCount;
281
282 /* Use as many as are available */
283 Count = MmGlobalMemoryDescriptorCount;
284 ListDescriptor = MmGlobalMemoryDescriptors;
285 }
286
287 /* Never truncate descriptors during a list copy */
288 Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_TRUNCATE_FLAG;
289
290 /* Iterate through the list */
291 First = SourceList->First;
292 NextEntry = First->Flink;
293 while ((NextEntry != First) && (NT_SUCCESS(Status)))
294 {
295 /* Make sure there's still space */
296 if (Count <= *Used)
297 {
298 Status = STATUS_NO_MEMORY;
299 break;
300 }
301
302 /* Get the current descriptor */
303 Descriptor = CONTAINING_RECORD(NextEntry,
304 BL_MEMORY_DESCRIPTOR,
305 ListEntry);
306
307 /* Copy it into one of the descriptors we have */
308 RtlCopyMemory(&ListDescriptor[*Used],
309 Descriptor,
310 sizeof(*Descriptor));
311
312 /* Add it to the list we have */
313 Status = MmMdAddDescriptorToList(DestinationList,
314 &ListDescriptor[*Used],
315 Flags);
316 ++*Used;
317
318 /* Move to the next entry */
319 NextEntry = NextEntry->Flink;
320 }
321
322 /* Check if the global descriptors were used */
323 if (ListDescriptor == MmGlobalMemoryDescriptors)
324 {
325 /* Unwind our usage */
326 MmMdFreeGlobalDescriptors();
327 --MmDescriptorCallTreeCount;
328 }
329
330 /* Return back to caller */
331 return Status;
332 }
333
334 VOID
335 MmMdRemoveDescriptorFromList (
336 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
337 _In_ PBL_MEMORY_DESCRIPTOR Entry
338 )
339 {
340 /* Remove the entry */
341 RemoveEntryList(&Entry->ListEntry);
342
343 /* Check if this was the current link */
344 if (MdList->This == &Entry->ListEntry)
345 {
346 /* Remove the current link and set the next one */
347 MdList->This = NULL;
348 MmMdpSaveCurrentListPointer(MdList, Entry->ListEntry.Blink);
349 }
350 }
351
352 VOID
353 MmMdFreeList(
354 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList
355 )
356 {
357 PLIST_ENTRY FirstEntry, NextEntry;
358 PBL_MEMORY_DESCRIPTOR Entry;
359
360 /* Go over every descriptor from the top */
361 FirstEntry = MdList->First;
362 NextEntry = FirstEntry->Flink;
363 while (NextEntry != FirstEntry)
364 {
365 /* Remove and free each one */
366 Entry = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
367 NextEntry = NextEntry->Flink;
368 MmMdRemoveDescriptorFromList(MdList, Entry);
369 MmMdFreeDescriptor(Entry);
370 }
371 }
372
373 PBL_MEMORY_DESCRIPTOR
374 MmMdInitByteGranularDescriptor (
375 _In_ ULONG Flags,
376 _In_ BL_MEMORY_TYPE Type,
377 _In_ ULONGLONG BasePage,
378 _In_ ULONGLONG VirtualPage,
379 _In_ ULONGLONG PageCount
380 )
381 {
382 PBL_MEMORY_DESCRIPTOR MemoryDescriptor;
383
384 /* If we're out of descriptors, bail out */
385 if (MmGlobalMemoryDescriptorsUsed >= MmGlobalMemoryDescriptorCount)
386 {
387 EfiPrintf(L"Out of descriptors!\r\n");
388 return NULL;
389 }
390
391 /* Take one of the available descriptors and fill it out */
392 MemoryDescriptor = &MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorsUsed];
393 MemoryDescriptor->BaseAddress = BasePage;
394 MemoryDescriptor->VirtualPage = VirtualPage;
395 MemoryDescriptor->PageCount = PageCount;
396 MemoryDescriptor->Flags = Flags;
397 MemoryDescriptor->Type = Type;
398 InitializeListHead(&MemoryDescriptor->ListEntry);
399
400 /* Increment the count and return the descriptor */
401 MmGlobalMemoryDescriptorsUsed++;
402 return MemoryDescriptor;
403 }
404
405 BOOLEAN
406 MmMdpTruncateDescriptor (
407 __in PBL_MEMORY_DESCRIPTOR_LIST MdList,
408 __in PBL_MEMORY_DESCRIPTOR MemoryDescriptor,
409 __in ULONG Flags
410 )
411 {
412 PBL_MEMORY_DESCRIPTOR NextDescriptor, PreviousDescriptor;
413 PLIST_ENTRY NextEntry, PreviousEntry;
414 ULONGLONG EndPage, PreviousEndPage;// , NextEndPage;
415
416 /* Get the next descriptor */
417 NextEntry = MemoryDescriptor->ListEntry.Flink;
418 NextDescriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
419
420 /* Get the previous descriptor */
421 PreviousEntry = MemoryDescriptor->ListEntry.Blink;
422 PreviousDescriptor = CONTAINING_RECORD(PreviousEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
423
424 /* Calculate end pages */
425 EndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
426 //NextEndPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
427 PreviousEndPage = PreviousDescriptor->BasePage + PreviousDescriptor->PageCount;
428
429 /* Check for backward overlap */
430 if ((PreviousEntry != MdList->First) && (MemoryDescriptor->BasePage < PreviousEndPage))
431 {
432 EfiPrintf(L"Overlap detected -- this is unexpected on x86/x64 platforms\r\n");
433 }
434
435 /* Check for forward overlap */
436 if ((NextEntry != MdList->First) && (NextDescriptor->BasePage < EndPage))
437 {
438 EfiPrintf(L"Overlap detected -- this is unexpected on x86/x64 platforms\r\n");
439 }
440
441 /* Nothing to do */
442 return FALSE;
443 }
444
445 BOOLEAN
446 MmMdpCoalesceDescriptor (
447 __in PBL_MEMORY_DESCRIPTOR_LIST MdList,
448 __in PBL_MEMORY_DESCRIPTOR MemoryDescriptor,
449 __in ULONG Flags
450 )
451 {
452 PBL_MEMORY_DESCRIPTOR NextDescriptor, PreviousDescriptor;
453 PLIST_ENTRY NextEntry, PreviousEntry;
454 ULONGLONG EndPage, PreviousEndPage, PreviousMappedEndPage, MappedEndPage;
455
456 /* Get the next descriptor */
457 NextEntry = MemoryDescriptor->ListEntry.Flink;
458 NextDescriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
459
460 /* Get the previous descriptor */
461 PreviousEntry = MemoryDescriptor->ListEntry.Blink;
462 PreviousDescriptor = CONTAINING_RECORD(PreviousEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
463
464 /* Calculate end pages */
465 EndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
466 MappedEndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
467 PreviousMappedEndPage = PreviousDescriptor->VirtualPage + PreviousDescriptor->PageCount;
468 PreviousEndPage = PreviousDescriptor->BasePage + PreviousDescriptor->PageCount;
469 PreviousMappedEndPage = PreviousDescriptor->VirtualPage + PreviousDescriptor->PageCount;
470
471 /* Check if the previous entry touches the current entry, and is compatible */
472 if ((PreviousEntry != MdList->First) &&
473 (PreviousDescriptor->Type == MemoryDescriptor->Type) &&
474 ((PreviousDescriptor->Flags ^ MemoryDescriptor->Flags) & 0x1B19FFFF) &&
475 (PreviousEndPage == MemoryDescriptor->BasePage) &&
476 ((!(MemoryDescriptor->VirtualPage) && !(PreviousDescriptor->VirtualPage)) ||
477 ((MemoryDescriptor->VirtualPage) && (PreviousDescriptor->VirtualPage) &&
478 (PreviousMappedEndPage == MemoryDescriptor->VirtualPage))))
479 {
480 EfiPrintf(L"Previous descriptor coalescable!\r\n");
481 }
482
483 /* CHeck if the current entry touches the next entry, and is compatible */
484 if ((NextEntry != MdList->First) &&
485 (NextDescriptor->Type == MemoryDescriptor->Type) &&
486 ((NextDescriptor->Flags ^ MemoryDescriptor->Flags) & 0x1B19FFFF) &&
487 (EndPage == NextDescriptor->BasePage) &&
488 ((!(MemoryDescriptor->VirtualPage) && !(PreviousDescriptor->VirtualPage)) ||
489 ((MemoryDescriptor->VirtualPage) && (PreviousDescriptor->VirtualPage) &&
490 (MappedEndPage == NextDescriptor->VirtualPage))))
491 {
492 EfiPrintf(L"Next descriptor coalescable!\r\n");
493 }
494
495 /* Nothing to do */
496 return FALSE;
497 }
498
499 NTSTATUS
500 MmMdAddDescriptorToList (
501 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
502 _In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor,
503 _In_ ULONG Flags
504 )
505 {
506 PLIST_ENTRY ThisEntry, FirstEntry;
507 PBL_MEMORY_DESCRIPTOR ThisDescriptor;
508
509 /* Arguments must be present */
510 if (!(MdList) || !(MemoryDescriptor))
511 {
512 return STATUS_INVALID_PARAMETER;
513 }
514
515 /* Check if coalescing is forcefully disabled */
516 if (Flags & BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG)
517 {
518 /* Then we won't be coalescing */
519 Flags &= BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG;
520 }
521 else
522 {
523 /* Coalesce if the descriptor requires it */
524 if (MemoryDescriptor->Flags & BlMemoryCoalesced)
525 {
526 Flags |= BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG;
527 }
528 }
529
530 /* Check if truncation is forcefully disabled */
531 if (Flags & BL_MM_ADD_DESCRIPTOR_NEVER_TRUNCATE_FLAG)
532 {
533 Flags &= ~BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG;
534 }
535
536 /* Update the current list pointer if the descriptor requires it */
537 if (MemoryDescriptor->Flags & BlMemoryUpdate)
538 {
539 Flags |= BL_MM_ADD_DESCRIPTOR_UPDATE_LIST_POINTER_FLAG;
540 }
541
542 /* Get the current descriptor */
543 ThisEntry = MdList->This;
544 ThisDescriptor = CONTAINING_RECORD(ThisEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
545
546 /* Also get the first descriptor */
547 FirstEntry = MdList->First;
548
549 /* Check if there's no current pointer, or if it's higher than the new one */
550 if (!(ThisEntry) ||
551 (MemoryDescriptor->BaseAddress <= ThisDescriptor->BaseAddress))
552 {
553 /* Start at the first descriptor instead, since current is past us */
554 ThisEntry = FirstEntry->Flink;
555 ThisDescriptor = CONTAINING_RECORD(ThisEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
556 }
557
558 /* Loop until we find the right location to insert */
559 while (1)
560 {
561 /* Have we gotten back to the first entry? */
562 if (ThisEntry == FirstEntry)
563 {
564 /* Then we didn't find a good match, so insert it right here */
565 InsertTailList(FirstEntry, &MemoryDescriptor->ListEntry);
566
567 /* Do we have to truncate? */
568 if (Flags & BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG)
569 {
570 /* Do it and then exit */
571 if (MmMdpTruncateDescriptor(MdList, MemoryDescriptor, Flags))
572 {
573 return STATUS_SUCCESS;
574 }
575 }
576
577 /* Do we have to coalesce? */
578 if (Flags & BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG)
579 {
580 /* Do it and then exit */
581 if (MmMdpCoalesceDescriptor(MdList, MemoryDescriptor, Flags))
582 {
583 return STATUS_SUCCESS;
584 }
585 }
586
587 /* Do we have to update the current pointer? */
588 if (Flags & BL_MM_ADD_DESCRIPTOR_UPDATE_LIST_POINTER_FLAG)
589 {
590 /* Do it */
591 MmMdpSaveCurrentListPointer(MdList, &MemoryDescriptor->ListEntry);
592 }
593
594 /* We're done */
595 return STATUS_SUCCESS;
596 }
597
598 /* Is the new descriptor below this address, and has precedence over it? */
599 if ((MemoryDescriptor->BaseAddress < ThisDescriptor->BaseAddress) &&
600 (MmMdpHasPrecedence(MemoryDescriptor->Type, ThisDescriptor->Type)))
601 {
602 /* Then insert right here */
603 InsertTailList(ThisEntry, &MemoryDescriptor->ListEntry);
604 return STATUS_SUCCESS;
605 }
606
607 /* Try the next descriptor */
608 ThisEntry = ThisEntry->Flink;
609 ThisDescriptor = CONTAINING_RECORD(ThisEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
610 }
611 }
612
613 NTSTATUS
614 MmMdRemoveRegionFromMdlEx (
615 __in PBL_MEMORY_DESCRIPTOR_LIST MdList,
616 __in ULONG Flags,
617 __in ULONGLONG BasePage,
618 __in ULONGLONG PageCount,
619 __in PBL_MEMORY_DESCRIPTOR_LIST NewMdList
620 )
621 {
622 BOOLEAN HaveNewList, UseVirtualPage;
623 NTSTATUS Status;
624 PLIST_ENTRY ListHead, NextEntry;
625 PBL_MEMORY_DESCRIPTOR Descriptor;
626 BL_MEMORY_DESCRIPTOR NewDescriptor;
627 ULONGLONG RegionSize;
628 ULONGLONG FoundBasePage, FoundEndPage, FoundPageCount, EndPage;
629
630 /* Set initial status */
631 Status = STATUS_SUCCESS;
632
633 /* Check if removed descriptors should go into a new list */
634 if (NewMdList != NULL)
635 {
636 /* Initialize it */
637 MmMdInitializeListHead(NewMdList);
638 NewMdList->Type = MdList->Type;
639
640 /* Remember for later */
641 HaveNewList = TRUE;
642 }
643 else
644 {
645 /* For later */
646 HaveNewList = FALSE;
647 }
648
649 /* Is the region being removed physical? */
650 UseVirtualPage = FALSE;
651 if (!(Flags & BL_MM_REMOVE_VIRTUAL_REGION_FLAG))
652 {
653 /* Is this a list of virtual descriptors? */
654 if (MdList->Type == BlMdVirtual)
655 {
656 /* Request is nonsensical, fail */
657 Status = STATUS_INVALID_PARAMETER;
658 goto Quickie;
659 }
660 }
661 else
662 {
663 /* Is this a list of physical descriptors? */
664 if (MdList->Type == BlMdPhysical)
665 {
666 /* We'll have to use the virtual page instead */
667 UseVirtualPage = TRUE;
668 }
669 }
670
671 /* Loop the list*/
672 ListHead = MdList->First;
673 NextEntry = ListHead->Flink;
674 while (NextEntry != ListHead)
675 {
676 /* Get the descriptor */
677 Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
678
679 /* Extract range details */
680 FoundBasePage = UseVirtualPage ? Descriptor->VirtualPage : Descriptor->BasePage;
681 FoundPageCount = Descriptor->PageCount;
682 FoundEndPage = FoundBasePage + FoundPageCount;
683 EndPage = PageCount + BasePage;
684
685 /* Make a copy of the original descriptor */
686 RtlCopyMemory(&NewDescriptor, NextEntry, sizeof(NewDescriptor));
687
688 /* Check if the region to be removed starts after the found region starts */
689 if ((BasePage > FoundBasePage) || (FoundBasePage >= EndPage))
690 {
691 /* Check if the region ends after the found region */
692 if ((BasePage >= FoundEndPage) || (FoundEndPage > EndPage))
693 {
694 /* Check if the found region starts after the region or ends before the region */
695 if ((FoundBasePage >= BasePage) || (EndPage >= FoundEndPage))
696 {
697 /* This descriptor doesn't cover any part of the range -- nothing to do */
698 NOTHING;
699 }
700 else
701 {
702 /* This descriptor fully covers the entire allocation */
703 FoundBasePage = Descriptor->BasePage;
704 FoundPageCount = BasePage - FoundBasePage;
705
706 /* This is how many pages we will eat away from the descriptor */
707 RegionSize = FoundPageCount + PageCount;
708
709 /* Update the descriptor to account for the consumed pages */
710 Descriptor->BasePage += RegionSize;
711 Descriptor->PageCount -= RegionSize;
712 if (Descriptor->VirtualPage)
713 {
714 Descriptor->VirtualPage += RegionSize;
715 }
716
717 /* Initialize a descriptor for the start of the region */
718 Descriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
719 Descriptor->Type,
720 FoundBasePage,
721 Descriptor->VirtualPage,
722 FoundPageCount);
723 if (!Descriptor)
724 {
725 Status = STATUS_NO_MEMORY;
726 goto Quickie;
727 }
728
729 /* Add it into the list */
730 Status = MmMdAddDescriptorToList(MdList, Descriptor, Flags);
731 if (!NT_SUCCESS(Status))
732 {
733 Status = STATUS_NO_MEMORY;
734 goto Quickie;
735 }
736 }
737 }
738 else
739 {
740 /* This descriptor contains the entire allocation */
741 RegionSize = FoundEndPage - BasePage;
742 Descriptor->PageCount -= RegionSize;
743 }
744
745 /* Keep going */
746 NextEntry = NextEntry->Flink;
747 }
748 else
749 {
750 /*
751 * This descriptor contains the end of the allocation. It may:
752 *
753 * - Contain the full allocation (i.e.: the start is aligned)
754 * - Contain parts of the end of the allocation (i.e.: the end is beyond)
755 * - Contain the entire tail end of the allocation (i..e:the end is within)
756 *
757 * So first, figure out if we cover the entire end or not
758 */
759 if (EndPage < FoundEndPage)
760 {
761 /* The allocation goes past the end of this descriptor */
762 FoundEndPage = EndPage;
763 }
764
765 /* This is how many pages we will eat away from the descriptor */
766 RegionSize = FoundEndPage - FoundBasePage;
767
768 /* Update the descriptor to account for the consumed pages */
769 Descriptor->BasePage += RegionSize;
770 Descriptor->PageCount -= RegionSize;
771 if (Descriptor->VirtualPage)
772 {
773 Descriptor->VirtualPage += RegionSize;
774 }
775
776 /* Go to the next entry */
777 NextEntry = NextEntry->Flink;
778
779 /* Check if the descriptor is now empty */
780 if (!Descriptor->PageCount)
781 {
782 /* Remove it */
783 MmMdRemoveDescriptorFromList(MdList, Descriptor);
784 MmMdFreeDescriptor(Descriptor);
785
786 /* Check if we're supposed to insert it into a new list */
787 if (HaveNewList)
788 {
789 EfiPrintf(L"Not yet implemented\r\n");
790 Status = STATUS_NOT_IMPLEMENTED;
791 goto Quickie;
792 }
793 }
794 }
795 }
796
797 Quickie:
798 /* Check for failure cleanup */
799 if (!NT_SUCCESS(Status))
800 {
801 /* Did we have to build a new list? */
802 if (HaveNewList)
803 {
804 /* Free and re-initialize it */
805 MmMdFreeList(NewMdList);
806 MmMdInitializeListHead(NewMdList);
807 NewMdList->Type = MdList->Type;
808 }
809 }
810
811 return Status;
812 }
813
814 PBL_MEMORY_DESCRIPTOR
815 MmMdFindDescriptorFromMdl (
816 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
817 _In_ ULONG Flags,
818 _In_ ULONGLONG Page
819 )
820 {
821 BOOLEAN IsVirtual;
822 PLIST_ENTRY NextEntry, ListHead;
823 PBL_MEMORY_DESCRIPTOR Current;
824 ULONGLONG BasePage;
825
826 /* Assume physical */
827 IsVirtual = FALSE;
828
829 /* Check if the caller wants physical memory */
830 if (!(Flags & BL_MM_REMOVE_VIRTUAL_REGION_FLAG))
831 {
832 /* Check if this is a virtual memory list */
833 if (MdList->Type == BlMdVirtual)
834 {
835 /* We won't find anything */
836 return NULL;
837 }
838 }
839 else if (MdList->Type == BlMdPhysical)
840 {
841 /* Otherwise, caller wants virtual, but this is a physical list */
842 IsVirtual = TRUE;
843 NextEntry = MdList->First->Flink;
844 }
845
846 /* Check if this is a physical search */
847 if (!IsVirtual)
848 {
849 /* Check if we can use the current pointer */
850 NextEntry = MdList->This;
851 if (!NextEntry)
852 {
853 /* We can't -- start at the beginning */
854 NextEntry = MdList->First->Flink;
855 }
856 else
857 {
858 /* If the page is below the current pointer, restart */
859 Current = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
860 if (Page < Current->BasePage)
861 {
862 NextEntry = MdList->First->Flink;
863 }
864 }
865 }
866
867 /* Loop the list of descriptors */
868 ListHead = MdList->First;
869 while (NextEntry != ListHead)
870 {
871 /* Get the current one */
872 Current = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
873
874 /* Check if we are looking for virtual memory */
875 if (IsVirtual)
876 {
877 /* Use the base address */
878 BasePage = Current->VirtualPage;
879 }
880 else
881 {
882 /* Use the page */
883 BasePage = Current->BasePage;
884 }
885
886 /* If this is a virtual descriptor, make sure it has a base address */
887 if ((!(IsVirtual) || (BasePage)) &&
888 (BasePage <= Page) &&
889 (Page < (BasePage + Current->PageCount)))
890 {
891 /* The descriptor fits the page being requested */
892 return Current;
893 }
894
895 /* Try the next one */
896 NextEntry = NextEntry->Flink;
897 }
898
899 /* Nothing found if we're here */
900 return NULL;
901 }
902
903 PBL_MEMORY_DESCRIPTOR
904 MmMdFindDescriptor (
905 _In_ ULONG WhichList,
906 _In_ ULONG Flags,
907 _In_ ULONGLONG Page
908 )
909 {
910 PBL_MEMORY_DESCRIPTOR FoundDescriptor;
911
912 /* Check if the caller is looking for mapped, allocated memory */
913 if (WhichList & BL_MM_INCLUDE_MAPPED_ALLOCATED)
914 {
915 /* Find a descriptor in that list */
916 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlMappedAllocated, Flags, Page);
917 if (FoundDescriptor)
918 {
919 /* Got it */
920 return FoundDescriptor;
921 }
922 }
923
924 /* Check if the caller is looking for mapped, unallocated memory */
925 if (WhichList & BL_MM_INCLUDE_MAPPED_UNALLOCATED)
926 {
927 /* Find a descriptor in that list */
928 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlMappedUnallocated, Flags, Page);
929 if (FoundDescriptor)
930 {
931 /* Got it */
932 return FoundDescriptor;
933 }
934 }
935
936 /* Check if the caller is looking for unmapped, allocated memory */
937 if (WhichList & BL_MM_INCLUDE_UNMAPPED_ALLOCATED)
938 {
939 /* Find a descriptor in that list */
940 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlUnmappedAllocated, Flags, Page);
941 if (FoundDescriptor)
942 {
943 /* Got it */
944 return FoundDescriptor;
945 }
946 }
947
948 /* Check if the caller is looking for unmapped, unallocated memory */
949 if (WhichList & BL_MM_INCLUDE_UNMAPPED_UNALLOCATED)
950 {
951 /* Find a descriptor in that list */
952 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlUnmappedUnallocated, Flags, Page);
953 if (FoundDescriptor)
954 {
955 /* Got it */
956 return FoundDescriptor;
957 }
958 }
959
960 /* Check if the caller is looking for reserved, allocated memory */
961 if (WhichList & BL_MM_INCLUDE_RESERVED_ALLOCATED)
962 {
963 /* Find a descriptor in that list */
964 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlReservedAllocated, Flags, Page);
965 if (FoundDescriptor)
966 {
967 /* Got it */
968 return FoundDescriptor;
969 }
970 }
971
972 /* Check if the caller is looking for bad memory */
973 if (WhichList & BL_MM_INCLUDE_BAD_MEMORY)
974 {
975 /* Find a descriptor in that list */
976 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlBadMemory, Flags, Page);
977 if (FoundDescriptor)
978 {
979 /* Got it */
980 return FoundDescriptor;
981 }
982 }
983
984 /* Check if the caller is looking for truncated memory */
985 if (WhichList & BL_MM_INCLUDE_TRUNCATED_MEMORY)
986 {
987 /* Find a descriptor in that list */
988 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlTruncatedMemory, Flags, Page);
989 if (FoundDescriptor)
990 {
991 /* Got it */
992 return FoundDescriptor;
993 }
994 }
995
996 /* Check if the caller is looking for persistent memory */
997 if (WhichList & BL_MM_INCLUDE_PERSISTENT_MEMORY)
998 {
999 /* Find a descriptor in that list */
1000 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlPersistentMemory, Flags, Page);
1001 if (FoundDescriptor)
1002 {
1003 /* Got it */
1004 return FoundDescriptor;
1005 }
1006 }
1007
1008 /* Nothing if we got here */
1009 return NULL;
1010 }
1011
1012 BOOLEAN
1013 MmMdFindSatisfyingRegion (
1014 _In_ PBL_MEMORY_DESCRIPTOR Descriptor,
1015 _Out_ PBL_MEMORY_DESCRIPTOR NewDescriptor,
1016 _In_ ULONGLONG Pages,
1017 _In_ PBL_ADDRESS_RANGE BaseRange,
1018 _In_ PBL_ADDRESS_RANGE VirtualRange,
1019 _In_ BOOLEAN TopDown,
1020 _In_ BL_MEMORY_TYPE MemoryType,
1021 _In_ ULONG Flags,
1022 _In_ ULONG Alignment
1023 )
1024 {
1025 ULONGLONG BaseMin, BaseMax, AlignedMin;
1026 ULONGLONG VirtualPage, BasePage;
1027 ULONGLONG BaseDelta, AlignedBase;
1028 ULONGLONG VirtualMin, VirtualMax;
1029
1030 /* Extract the minimum and maximum range */
1031 BaseMin = BaseRange->Minimum;
1032 BaseMax = BaseRange->Maximum;
1033
1034 /* Don't go below where the descriptor starts */
1035 if (BaseMin < Descriptor->BasePage)
1036 {
1037 BaseMin = Descriptor->BasePage;
1038 }
1039
1040 /* Don't go beyond where the descriptor ends */
1041 if (BaseMax > (Descriptor->BasePage + Descriptor->PageCount - 1))
1042 {
1043 BaseMax = (Descriptor->BasePage + Descriptor->PageCount - 1);
1044 }
1045
1046 /* Check for start overflow */
1047 if (BaseMin > BaseMax)
1048 {
1049 return FALSE;
1050 }
1051
1052 /* Align the base as required */
1053 if (Alignment != 1)
1054 {
1055 AlignedMin = ALIGN_UP_BY(BaseMin, Alignment);
1056 }
1057 else
1058 {
1059 AlignedMin = BaseMin;
1060 }
1061
1062 /* Check for range overflow */
1063 if (((AlignedMin + Pages - 1) < AlignedMin) || ((AlignedMin + Pages - 1) > BaseMax))
1064 {
1065 return FALSE;
1066 }
1067
1068 /* Check if this was a top-down request */
1069 if (TopDown)
1070 {
1071 /* Then get the highest page possible */
1072 BasePage = BaseMax - Pages + 1;
1073 if (Alignment != 1)
1074 {
1075 /* Align it as needed */
1076 AlignedBase = ALIGN_DOWN_BY(BasePage, Alignment);
1077 }
1078 else
1079 {
1080 AlignedBase = BasePage;
1081 }
1082
1083 /* Calculate the delta between max address and our aligned base */
1084 BaseDelta = BasePage - AlignedBase;
1085 BasePage -= BaseDelta;
1086 }
1087 else
1088 {
1089 /* Otherwise, get the lowest page possible */
1090 BasePage = AlignedMin;
1091 BaseDelta = 0;
1092 }
1093
1094 /* If a virtual address range was passed in, this must be a virtual descriptor */
1095 if (((VirtualRange->Minimum) || (VirtualRange->Maximum)) &&
1096 !(Descriptor->VirtualPage))
1097 {
1098 return FALSE;
1099 }
1100
1101 /* Any mapped page already? */
1102 if (Descriptor->VirtualPage)
1103 {
1104 /* Get virtual min/max */
1105 VirtualMin = VirtualRange->Minimum;
1106 VirtualMax = VirtualRange->Maximum;
1107
1108 /* Don't go below where the descriptor maps */
1109 if (VirtualMin <= Descriptor->VirtualPage)
1110 {
1111 VirtualMin = Descriptor->VirtualPage;
1112 }
1113
1114 /* Don't go above where the descriptor maps */
1115 if (VirtualMax >= (Descriptor->VirtualPage + Descriptor->PageCount - 1))
1116 {
1117 VirtualMax = Descriptor->VirtualPage + Descriptor->PageCount - 1;
1118 }
1119
1120 /* Don't let the base overflow */
1121 if (VirtualMin > VirtualMax)
1122 {
1123 return 0;
1124 }
1125
1126 /* Adjust the base by the alignment delta */
1127 VirtualMin += AlignedMin - BaseMin;
1128
1129 /* Check that the bounds don't overflow or underflow */
1130 if (((VirtualMin + Pages - 1) < VirtualMin) ||
1131 ((VirtualMin + Pages - 1) > VirtualMax))
1132 {
1133 return 0;
1134 }
1135
1136 /* Finally, pick the correct address based on direction */
1137 if (TopDown)
1138 {
1139 /* Highest possible base address, aligned */
1140 VirtualPage = VirtualMax - Pages + 1 - BaseDelta;
1141 }
1142 else
1143 {
1144 /* Lowest possible base address, aligned */
1145 VirtualPage = VirtualMin;
1146 }
1147 }
1148 else
1149 {
1150 /* Nothing to worry about */
1151 VirtualPage = 0;
1152 }
1153
1154 /* Bail out if the memory type attributes don't match */
1155 if ((((Flags & 0xFF) & (Descriptor->Flags & 0xFF)) != (Flags & 0xFF)) ||
1156 (((Flags & 0xFF00) & (Descriptor->Flags & 0xFF00)) != (Flags & 0xFF00)))
1157 {
1158 EfiPrintf(L"Incorrect memory attributes\r\n");
1159 return FALSE;
1160 }
1161
1162 /* Bail out if the allocation flags don't match */
1163 if (((Flags ^ Descriptor->Flags) & (BlMemoryRuntime | BlMemoryBelow1MB | BlMemoryLargePages)))
1164 {
1165 //EfiPrintf(L"Incorrect memory allocation flags\r\n");
1166 return FALSE;
1167 }
1168
1169 /* Bail out if the type doesn't match */
1170 if (Descriptor->Type != MemoryType)
1171 {
1172 //EfiPrintf(L"Incorrect descriptor type: %lx %lx\r\n", Descriptor->Type, MemoryType);
1173 return FALSE;
1174 }
1175
1176 /* We have a matching region, fill out the descriptor for it */
1177 NewDescriptor->BasePage = BasePage;
1178 NewDescriptor->PageCount = Pages;
1179 NewDescriptor->Type = Descriptor->Type;
1180 NewDescriptor->VirtualPage = VirtualPage;
1181 NewDescriptor->Flags = Descriptor->Flags;
1182 //EfiPrintf(L"Found a matching descriptor: %08I64X with %08I64X pages\r\n", BasePage, Pages);
1183 return TRUE;
1184 }
1185
1186 VOID
1187 MmMdFreeGlobalDescriptors (
1188 VOID
1189 )
1190 {
1191 PBL_MEMORY_DESCRIPTOR Descriptor, OldDescriptor;
1192 ULONG Index = 0;
1193 PLIST_ENTRY OldFlink, OldBlink;
1194
1195 /* Make sure we're not int middle of a call using a descriptor */
1196 if (MmDescriptorCallTreeCount != 1)
1197 {
1198 return;
1199 }
1200
1201 /* Loop every current global descriptor */
1202 while (Index < MmGlobalMemoryDescriptorsUsed)
1203 {
1204 /* Does it have any valid pages? */
1205 OldDescriptor = &MmGlobalMemoryDescriptors[Index];
1206 if (OldDescriptor->PageCount)
1207 {
1208 /* Allocate a copy of it */
1209 Descriptor = BlMmAllocateHeap(sizeof(*Descriptor));
1210 if (!Descriptor)
1211 {
1212 return;
1213 }
1214
1215 /* Save the links */
1216 OldBlink = OldDescriptor->ListEntry.Blink;
1217 OldFlink = OldDescriptor->ListEntry.Flink;
1218
1219 /* Make the copy */
1220 *Descriptor = *OldDescriptor;
1221
1222 /* Fix the links */
1223 OldBlink->Flink = &Descriptor->ListEntry;
1224 OldFlink->Blink = &Descriptor->ListEntry;
1225
1226 /* Zero the descriptor */
1227 RtlZeroMemory(OldDescriptor, sizeof(*OldDescriptor));
1228 }
1229
1230 /* Keep going */
1231 Index++;
1232 }
1233
1234 /* All global descriptors freed */
1235 MmGlobalMemoryDescriptorsUsed = 0;
1236 }
1237
1238 VOID
1239 MmMdInitialize (
1240 _In_ ULONG Phase,
1241 _In_ PBL_LIBRARY_PARAMETERS LibraryParameters
1242 )
1243 {
1244 /* Are we in phase 1? */
1245 if (Phase != 0)
1246 {
1247 /* Switch to dynamic descriptors if we have too many */
1248 if (LibraryParameters->DescriptorCount > RTL_NUMBER_OF(MmStaticMemoryDescriptors))
1249 {
1250 MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
1251 }
1252 }
1253 else
1254 {
1255 /* In phase 0, start with a pool of 512 static descriptors */
1256 MmGlobalMemoryDescriptorCount = RTL_NUMBER_OF(MmStaticMemoryDescriptors);
1257 MmGlobalMemoryDescriptors = MmStaticMemoryDescriptors;
1258 RtlZeroMemory(MmStaticMemoryDescriptors, sizeof(MmStaticMemoryDescriptors));
1259 MmGlobalMemoryDescriptorsUsed = 0;
1260 }
1261 }