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