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