[BOOTMGR]: Fix bug in test.
[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 while (1);
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"Dynamic descriptors not yet supported\r\n");
177 Status = STATUS_NOT_IMPLEMENTED;
178 }
179
180 /* Done */
181 return Status;
182 }
183
184 VOID
185 MmMdpSaveCurrentListPointer (
186 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
187 _In_ PLIST_ENTRY Current
188 )
189 {
190 /* Make sure that this is not a global descriptor and not the first one */
191 if (((Current < &MmGlobalMemoryDescriptors->ListEntry) ||
192 (Current >= &MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorCount].ListEntry)) &&
193 (Current != MdList->First))
194 {
195 /* Save this as the current pointer */
196 MdList->This = Current;
197 }
198 }
199
200 ULONG
201 MmMdCountList (
202 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList
203 )
204 {
205 PLIST_ENTRY First, NextEntry;
206 ULONG Count;
207
208 /* Iterate the list */
209 for (Count = 0, First = MdList->First, NextEntry = First->Flink;
210 NextEntry != First;
211 NextEntry = NextEntry->Flink, Count++);
212
213 /* Return the count */
214 return Count;
215 }
216
217 VOID
218 MmMdInitializeList (
219 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
220 _In_ ULONG Type,
221 _In_ PLIST_ENTRY ListHead
222 )
223 {
224 /* Check if a list was specified */
225 if (ListHead)
226 {
227 /* Use it */
228 MdList->First = ListHead;
229 }
230 else
231 {
232 /* Otherwise, use the internal, built-in list */
233 InitializeListHead(&MdList->ListHead);
234 MdList->First = &MdList->ListHead;
235 }
236
237 /* Set the type */
238 MdList->Type = Type;
239
240 /* Initialize current iterator to nothing */
241 MdList->This = NULL;
242 }
243
244 NTSTATUS
245 MmMdCopyList (
246 _In_ PBL_MEMORY_DESCRIPTOR_LIST DestinationList,
247 _In_ PBL_MEMORY_DESCRIPTOR_LIST SourceList,
248 _In_opt_ PBL_MEMORY_DESCRIPTOR ListDescriptor,
249 _Out_ PULONG ActualCount,
250 _In_ ULONG Count,
251 _In_ ULONG Flags
252 )
253 {
254 NTSTATUS Status;
255 PULONG Used;
256 PLIST_ENTRY First, NextEntry;
257 PBL_MEMORY_DESCRIPTOR Descriptor;
258
259 /* Both parameters must be present */
260 if (!(DestinationList) || !(SourceList))
261 {
262 return STATUS_INVALID_PARAMETER;
263 }
264
265 /* Assume success */
266 Status = STATUS_SUCCESS;
267
268 /* Check if a descriptor is being used to store the list */
269 if (ListDescriptor)
270 {
271 /* See how big it is */
272 Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG;
273 Used = ActualCount;
274 }
275 else
276 {
277 /* We are using our internal descriptors instead */
278 Used = &MmGlobalMemoryDescriptorsUsed;
279 ++MmDescriptorCallTreeCount;
280
281 /* Use as many as are available */
282 Count = MmGlobalMemoryDescriptorCount;
283 ListDescriptor = MmGlobalMemoryDescriptors;
284 }
285
286 /* Never truncate descriptors during a list copy */
287 Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_TRUNCATE_FLAG;
288
289 /* Iterate through the list */
290 First = SourceList->First;
291 NextEntry = First->Flink;
292 while ((NextEntry != First) && (NT_SUCCESS(Status)))
293 {
294 /* Make sure there's still space */
295 if (Count <= *Used)
296 {
297 Status = STATUS_NO_MEMORY;
298 break;
299 }
300
301 /* Get the current descriptor */
302 Descriptor = CONTAINING_RECORD(NextEntry,
303 BL_MEMORY_DESCRIPTOR,
304 ListEntry);
305
306 /* Copy it into one of the descriptors we have */
307 RtlCopyMemory(&ListDescriptor[*Used],
308 Descriptor,
309 sizeof(*Descriptor));
310
311 /* Add it to the list we have */
312 Status = MmMdAddDescriptorToList(DestinationList,
313 &ListDescriptor[*Used],
314 Flags);
315 ++*Used;
316
317 /* Move to the next entry */
318 NextEntry = NextEntry->Flink;
319 }
320
321 /* Check if the global descriptors were used */
322 if (ListDescriptor == MmGlobalMemoryDescriptors)
323 {
324 /* Unwind our usage */
325 MmMdFreeGlobalDescriptors();
326 --MmDescriptorCallTreeCount;
327 }
328
329 /* Return back to caller */
330 return Status;
331 }
332
333 VOID
334 MmMdRemoveDescriptorFromList (
335 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
336 _In_ PBL_MEMORY_DESCRIPTOR Entry
337 )
338 {
339 /* Remove the entry */
340 RemoveEntryList(&Entry->ListEntry);
341
342 /* Check if this was the current link */
343 if (MdList->This == &Entry->ListEntry)
344 {
345 /* Remove the current link and set the next one */
346 MdList->This = NULL;
347 MmMdpSaveCurrentListPointer(MdList, Entry->ListEntry.Blink);
348 }
349 }
350
351 VOID
352 MmMdFreeList(
353 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList
354 )
355 {
356 PLIST_ENTRY FirstEntry, NextEntry;
357 PBL_MEMORY_DESCRIPTOR Entry;
358
359 /* Go over every descriptor from the top */
360 FirstEntry = MdList->First;
361 NextEntry = FirstEntry->Flink;
362 while (NextEntry != FirstEntry)
363 {
364 /* Remove and free each one */
365 Entry = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
366 NextEntry = NextEntry->Flink;
367 MmMdRemoveDescriptorFromList(MdList, Entry);
368 MmMdFreeDescriptor(Entry);
369 }
370 }
371
372 PBL_MEMORY_DESCRIPTOR
373 MmMdInitByteGranularDescriptor (
374 _In_ ULONG Flags,
375 _In_ BL_MEMORY_TYPE Type,
376 _In_ ULONGLONG BasePage,
377 _In_ ULONGLONG VirtualPage,
378 _In_ ULONGLONG PageCount
379 )
380 {
381 PBL_MEMORY_DESCRIPTOR MemoryDescriptor;
382
383 /* If we're out of descriptors, bail out */
384 if (MmGlobalMemoryDescriptorsUsed >= MmGlobalMemoryDescriptorCount)
385 {
386 EfiPrintf(L"Out of descriptors!\r\n");
387 return NULL;
388 }
389
390 /* Take one of the available descriptors and fill it out */
391 MemoryDescriptor = &MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorsUsed];
392 MemoryDescriptor->BaseAddress = BasePage;
393 MemoryDescriptor->VirtualPage = VirtualPage;
394 MemoryDescriptor->PageCount = PageCount;
395 MemoryDescriptor->Flags = Flags;
396 MemoryDescriptor->Type = Type;
397 InitializeListHead(&MemoryDescriptor->ListEntry);
398
399 /* Increment the count and return the descriptor */
400 MmGlobalMemoryDescriptorsUsed++;
401 return MemoryDescriptor;
402 }
403
404 BOOLEAN
405 MmMdpTruncateDescriptor (
406 __in PBL_MEMORY_DESCRIPTOR_LIST MdList,
407 __in PBL_MEMORY_DESCRIPTOR MemoryDescriptor,
408 __in ULONG Flags
409 )
410 {
411 PBL_MEMORY_DESCRIPTOR NextDescriptor, PreviousDescriptor;
412 PLIST_ENTRY NextEntry, PreviousEntry;
413 ULONGLONG EndPage, PreviousEndPage;// , NextEndPage;
414
415 /* Get the next descriptor */
416 NextEntry = MemoryDescriptor->ListEntry.Flink;
417 NextDescriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
418
419 /* Get the previous descriptor */
420 PreviousEntry = MemoryDescriptor->ListEntry.Blink;
421 PreviousDescriptor = CONTAINING_RECORD(PreviousEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
422
423 /* Calculate end pages */
424 EndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
425 //NextEndPage = NextDescriptor->BasePage + NextDescriptor->PageCount;
426 PreviousEndPage = PreviousDescriptor->BasePage + PreviousDescriptor->PageCount;
427
428 /* Check for backward overlap */
429 if ((PreviousEntry != MdList->First) && (MemoryDescriptor->BasePage < PreviousEndPage))
430 {
431 EfiPrintf(L"Overlap detected -- this is unexpected on x86/x64 platforms\r\n");
432 }
433
434 /* Check for forward overlap */
435 if ((NextEntry != MdList->First) && (NextDescriptor->BasePage < EndPage))
436 {
437 EfiPrintf(L"Overlap detected -- this is unexpected on x86/x64 platforms\r\n");
438 }
439
440 /* Nothing to do */
441 return FALSE;
442 }
443
444 BOOLEAN
445 MmMdpCoalesceDescriptor (
446 __in PBL_MEMORY_DESCRIPTOR_LIST MdList,
447 __in PBL_MEMORY_DESCRIPTOR MemoryDescriptor,
448 __in ULONG Flags
449 )
450 {
451 PBL_MEMORY_DESCRIPTOR NextDescriptor, PreviousDescriptor;
452 PLIST_ENTRY NextEntry, PreviousEntry;
453 ULONGLONG EndPage, PreviousEndPage, PreviousMappedEndPage, MappedEndPage;
454
455 /* Get the next descriptor */
456 NextEntry = MemoryDescriptor->ListEntry.Flink;
457 NextDescriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
458
459 /* Get the previous descriptor */
460 PreviousEntry = MemoryDescriptor->ListEntry.Blink;
461 PreviousDescriptor = CONTAINING_RECORD(PreviousEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
462
463 /* Calculate end pages */
464 EndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
465 MappedEndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount;
466 PreviousMappedEndPage = PreviousDescriptor->VirtualPage + PreviousDescriptor->PageCount;
467 PreviousEndPage = PreviousDescriptor->BasePage + PreviousDescriptor->PageCount;
468 PreviousMappedEndPage = PreviousDescriptor->VirtualPage + PreviousDescriptor->PageCount;
469
470 /* Check if the previous entry touches the current entry, and is compatible */
471 if ((PreviousEntry != MdList->First) &&
472 (PreviousDescriptor->Type == MemoryDescriptor->Type) &&
473 ((PreviousDescriptor->Flags ^ MemoryDescriptor->Flags) & 0x1B19FFFF) &&
474 (PreviousEndPage == MemoryDescriptor->BasePage) &&
475 ((!(MemoryDescriptor->VirtualPage) && !(PreviousDescriptor->VirtualPage)) ||
476 ((MemoryDescriptor->VirtualPage) && (PreviousDescriptor->VirtualPage) &&
477 (PreviousMappedEndPage == MemoryDescriptor->VirtualPage))))
478 {
479 EfiPrintf(L"Previous descriptor coalescable!\r\n");
480 }
481
482 /* CHeck if the current entry touches the next entry, and is compatible */
483 if ((NextEntry != MdList->First) &&
484 (NextDescriptor->Type == MemoryDescriptor->Type) &&
485 ((NextDescriptor->Flags ^ MemoryDescriptor->Flags) & 0x1B19FFFF) &&
486 (EndPage == NextDescriptor->BasePage) &&
487 ((!(MemoryDescriptor->VirtualPage) && !(PreviousDescriptor->VirtualPage)) ||
488 ((MemoryDescriptor->VirtualPage) && (PreviousDescriptor->VirtualPage) &&
489 (MappedEndPage == NextDescriptor->VirtualPage))))
490 {
491 EfiPrintf(L"Next descriptor coalescable!\r\n");
492 }
493
494 /* Nothing to do */
495 return FALSE;
496 }
497
498 NTSTATUS
499 MmMdAddDescriptorToList (
500 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
501 _In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor,
502 _In_ ULONG Flags
503 )
504 {
505 PLIST_ENTRY ThisEntry, FirstEntry;
506 PBL_MEMORY_DESCRIPTOR ThisDescriptor;
507
508 /* Arguments must be present */
509 if (!(MdList) || !(MemoryDescriptor))
510 {
511 return STATUS_INVALID_PARAMETER;
512 }
513
514 /* Check if coalescing is forcefully disabled */
515 if (Flags & BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG)
516 {
517 /* Then we won't be coalescing */
518 Flags &= BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG;
519 }
520 else
521 {
522 /* Coalesce if the descriptor requires it */
523 if (MemoryDescriptor->Flags & BlMemoryCoalesced)
524 {
525 Flags |= BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG;
526 }
527 }
528
529 /* Check if truncation is forcefully disabled */
530 if (Flags & BL_MM_ADD_DESCRIPTOR_NEVER_TRUNCATE_FLAG)
531 {
532 Flags &= ~BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG;
533 }
534
535 /* Update the current list pointer if the descriptor requires it */
536 if (MemoryDescriptor->Flags & BlMemoryUpdate)
537 {
538 Flags |= BL_MM_ADD_DESCRIPTOR_UPDATE_LIST_POINTER_FLAG;
539 }
540
541 /* Get the current descriptor */
542 ThisEntry = MdList->This;
543 ThisDescriptor = CONTAINING_RECORD(ThisEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
544
545 /* Also get the first descriptor */
546 FirstEntry = MdList->First;
547
548 /* Check if there's no current pointer, or if it's higher than the new one */
549 if (!(ThisEntry) ||
550 (MemoryDescriptor->BaseAddress <= ThisDescriptor->BaseAddress))
551 {
552 /* Start at the first descriptor instead, since current is past us */
553 ThisEntry = FirstEntry->Flink;
554 ThisDescriptor = CONTAINING_RECORD(ThisEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
555 }
556
557 /* Loop until we find the right location to insert */
558 while (1)
559 {
560 /* Have we gotten back to the first entry? */
561 if (ThisEntry == FirstEntry)
562 {
563 /* Then we didn't find a good match, so insert it right here */
564 InsertTailList(FirstEntry, &MemoryDescriptor->ListEntry);
565
566 /* Do we have to truncate? */
567 if (Flags & BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG)
568 {
569 /* Do it and then exit */
570 if (MmMdpTruncateDescriptor(MdList, MemoryDescriptor, Flags))
571 {
572 return STATUS_SUCCESS;
573 }
574 }
575
576 /* Do we have to coalesce? */
577 if (Flags & BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG)
578 {
579 /* Do it and then exit */
580 if (MmMdpCoalesceDescriptor(MdList, MemoryDescriptor, Flags))
581 {
582 return STATUS_SUCCESS;
583 }
584 }
585
586 /* Do we have to update the current pointer? */
587 if (Flags & BL_MM_ADD_DESCRIPTOR_UPDATE_LIST_POINTER_FLAG)
588 {
589 /* Do it */
590 MmMdpSaveCurrentListPointer(MdList, &MemoryDescriptor->ListEntry);
591 }
592
593 /* We're done */
594 return STATUS_SUCCESS;
595 }
596
597 /* Is the new descriptor below this address, and has precedence over it? */
598 if ((MemoryDescriptor->BaseAddress < ThisDescriptor->BaseAddress) &&
599 (MmMdpHasPrecedence(MemoryDescriptor->Type, ThisDescriptor->Type)))
600 {
601 /* Then insert right here */
602 InsertTailList(ThisEntry, &MemoryDescriptor->ListEntry);
603 return STATUS_SUCCESS;
604 }
605
606 /* Try the next descriptor */
607 ThisEntry = ThisEntry->Flink;
608 ThisDescriptor = CONTAINING_RECORD(ThisEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
609 }
610 }
611
612 NTSTATUS
613 MmMdRemoveRegionFromMdlEx (
614 __in PBL_MEMORY_DESCRIPTOR_LIST MdList,
615 __in ULONG Flags,
616 __in ULONGLONG BasePage,
617 __in ULONGLONG PageCount,
618 __in PBL_MEMORY_DESCRIPTOR_LIST NewMdList
619 )
620 {
621 BOOLEAN HaveNewList, UseVirtualPage;
622 NTSTATUS Status;
623 PLIST_ENTRY ListHead, NextEntry;
624 PBL_MEMORY_DESCRIPTOR Descriptor;
625 BL_MEMORY_DESCRIPTOR NewDescriptor;
626 ULONGLONG RegionSize;
627 ULONGLONG FoundBasePage, FoundEndPage, FoundPageCount, EndPage;
628
629 /* Set initial status */
630 Status = STATUS_SUCCESS;
631
632 /* Check if removed descriptors should go into a new list */
633 if (NewMdList != NULL)
634 {
635 /* Initialize it */
636 MmMdInitializeListHead(NewMdList);
637 NewMdList->Type = MdList->Type;
638
639 /* Remember for later */
640 HaveNewList = TRUE;
641 }
642 else
643 {
644 /* For later */
645 HaveNewList = FALSE;
646 }
647
648 /* Is the region being removed physical? */
649 UseVirtualPage = FALSE;
650 if (!(Flags & BL_MM_REMOVE_VIRTUAL_REGION_FLAG))
651 {
652 /* Is this a list of virtual descriptors? */
653 if (MdList->Type == BlMdVirtual)
654 {
655 /* Request is nonsensical, fail */
656 Status = STATUS_INVALID_PARAMETER;
657 goto Quickie;
658 }
659 }
660 else
661 {
662 /* Is this a list of physical descriptors? */
663 if (MdList->Type == BlMdPhysical)
664 {
665 /* We'll have to use the virtual page instead */
666 UseVirtualPage = TRUE;
667 }
668 }
669
670 /* Loop the list*/
671 ListHead = MdList->First;
672 NextEntry = ListHead->Flink;
673 while (NextEntry != ListHead)
674 {
675 /* Get the descriptor */
676 Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
677
678 /* Extract range details */
679 FoundBasePage = UseVirtualPage ? Descriptor->VirtualPage : Descriptor->BasePage;
680 FoundPageCount = Descriptor->PageCount;
681 FoundEndPage = FoundBasePage + FoundPageCount;
682 EndPage = PageCount + BasePage;
683 //EarlyPrint(L"Looking for Region 0x%08I64X-0x%08I64X in 0x%08I64X-0x%08I64X\r\n", BasePage, EndPage, FoundBasePage, FoundEndPage);
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 */
698 //EarlyPrint(L"No part of this descriptor contains the region\r\n");
699 }
700 else
701 {
702 /* This descriptor covers the head of the allocation */
703 //EarlyPrint(L"Descriptor covers the head of the region\r\n");
704 }
705 }
706 else
707 {
708 /* This descriptor contains the entire allocation */
709 //EarlyPrint(L"Descriptor contains the entire region\r\n");
710 }
711
712 /* Keep going */
713 NextEntry = NextEntry->Flink;
714 }
715 else
716 {
717 /*
718 * This descriptor contains the end of the allocation. It may:
719 *
720 * - Contain the full allocation (i.e.: the start is aligned)
721 * - Contain parts of the end of the allocation (i.e.: the end is beyond)
722 * - Contain the entire tail end of the allocation (i..e:the end is within)
723 *
724 * So first, figure out if we cover the entire end or not
725 */
726 if (EndPage > FoundEndPage)
727 {
728 /* The allocation goes past the end of this descriptor */
729 EndPage = FoundEndPage;
730 }
731
732 /* This is how many pages we will eat away from the descriptor */
733 RegionSize = EndPage - FoundBasePage;
734
735 /* Update the descriptor to account for the consumed pages */
736 Descriptor->BasePage += RegionSize;
737 Descriptor->PageCount -= RegionSize;
738 if (Descriptor->VirtualPage)
739 {
740 Descriptor->VirtualPage += RegionSize;
741 }
742
743 /* Go to the next entry */
744 NextEntry = NextEntry->Flink;
745
746 /* Check if the descriptor is now empty */
747 if (!Descriptor->PageCount)
748 {
749 /* Remove it */
750 //EarlyPrint(L"Entire descriptor consumed\r\n");
751 MmMdRemoveDescriptorFromList(MdList, Descriptor);
752 MmMdFreeDescriptor(Descriptor);
753
754 /* Check if we're supposed to insert it into a new list */
755 if (HaveNewList)
756 {
757 EfiPrintf(L"Not yet implemented\r\n");
758 Status = STATUS_NOT_IMPLEMENTED;
759 goto Quickie;
760 }
761 }
762 }
763 }
764
765 Quickie:
766 /* Check for failure cleanup */
767 if (!NT_SUCCESS(Status))
768 {
769 /* Did we have to build a new list? */
770 if (HaveNewList)
771 {
772 /* Free and re-initialize it */
773 MmMdFreeList(NewMdList);
774 MmMdInitializeListHead(NewMdList);
775 NewMdList->Type = MdList->Type;
776 }
777 }
778
779 return Status;
780 }
781
782 PBL_MEMORY_DESCRIPTOR
783 MmMdFindDescriptorFromMdl (
784 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
785 _In_ ULONG Flags,
786 _In_ ULONGLONG Page
787 )
788 {
789 BOOLEAN IsVirtual;
790 PLIST_ENTRY NextEntry, ListHead;
791 PBL_MEMORY_DESCRIPTOR Current;
792 ULONGLONG BasePage;
793
794 /* Assume physical */
795 IsVirtual = FALSE;
796
797 /* Check if the caller wants physical memory */
798 if (!(Flags & BL_MM_REMOVE_VIRTUAL_REGION_FLAG))
799 {
800 /* Check if this is a virtual memory list */
801 if (MdList->Type == BlMdVirtual)
802 {
803 /* We won't find anything */
804 return NULL;
805 }
806 }
807 else if (MdList->Type == BlMdPhysical)
808 {
809 /* Otherwise, caller wants virtual, but this is a physical list */
810 IsVirtual = TRUE;
811 NextEntry = MdList->First->Flink;
812 }
813
814 /* Check if this is a physical search */
815 if (!IsVirtual)
816 {
817 /* Check if we can use the current pointer */
818 NextEntry = MdList->This;
819 if (!NextEntry)
820 {
821 /* We can't -- start at the beginning */
822 NextEntry = MdList->First->Flink;
823 }
824 else
825 {
826 /* If the page is below the current pointer, restart */
827 Current = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
828 if (Page < Current->BasePage)
829 {
830 NextEntry = MdList->First->Flink;
831 }
832 }
833 }
834
835 /* Loop the list of descriptors */
836 ListHead = MdList->First;
837 while (NextEntry != ListHead)
838 {
839 /* Get the current one */
840 Current = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
841
842 /* Check if we are looking for virtual memory */
843 if (IsVirtual)
844 {
845 /* Use the base address */
846 BasePage = Current->VirtualPage;
847 }
848 else
849 {
850 /* Use the page */
851 BasePage = Current->BasePage;
852 }
853
854 /* If this is a virtual descriptor, make sure it has a base address */
855 if ((!(IsVirtual) || (BasePage)) &&
856 (BasePage <= Page) &&
857 (Page < (BasePage + Current->PageCount)))
858 {
859 /* The descriptor fits the page being requested */
860 return Current;
861 }
862
863 /* Try the next one */
864 NextEntry = NextEntry->Flink;
865 }
866
867 /* Nothing found if we're here */
868 return NULL;
869 }
870
871 PBL_MEMORY_DESCRIPTOR
872 MmMdFindDescriptor (
873 _In_ ULONG WhichList,
874 _In_ ULONG Flags,
875 _In_ ULONGLONG Page
876 )
877 {
878 PBL_MEMORY_DESCRIPTOR FoundDescriptor;
879
880 /* Check if the caller is looking for mapped, allocated memory */
881 if (WhichList & BL_MM_INCLUDE_MAPPED_ALLOCATED)
882 {
883 /* Find a descriptor in that list */
884 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlMappedAllocated, Flags, Page);
885 if (FoundDescriptor)
886 {
887 /* Got it */
888 return FoundDescriptor;
889 }
890 }
891
892 /* Check if the caller is looking for mapped, unallocated memory */
893 if (WhichList & BL_MM_INCLUDE_MAPPED_UNALLOCATED)
894 {
895 /* Find a descriptor in that list */
896 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlMappedUnallocated, Flags, Page);
897 if (FoundDescriptor)
898 {
899 /* Got it */
900 return FoundDescriptor;
901 }
902 }
903
904 /* Check if the caller is looking for unmapped, allocated memory */
905 if (WhichList & BL_MM_INCLUDE_UNMAPPED_ALLOCATED)
906 {
907 /* Find a descriptor in that list */
908 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlUnmappedAllocated, Flags, Page);
909 if (FoundDescriptor)
910 {
911 /* Got it */
912 return FoundDescriptor;
913 }
914 }
915
916 /* Check if the caller is looking for unmapped, unallocated memory */
917 if (WhichList & BL_MM_INCLUDE_UNMAPPED_UNALLOCATED)
918 {
919 /* Find a descriptor in that list */
920 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlUnmappedUnallocated, Flags, Page);
921 if (FoundDescriptor)
922 {
923 /* Got it */
924 return FoundDescriptor;
925 }
926 }
927
928 /* Check if the caller is looking for reserved, allocated memory */
929 if (WhichList & BL_MM_INCLUDE_RESERVED_ALLOCATED)
930 {
931 /* Find a descriptor in that list */
932 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlReservedAllocated, Flags, Page);
933 if (FoundDescriptor)
934 {
935 /* Got it */
936 return FoundDescriptor;
937 }
938 }
939
940 /* Check if the caller is looking for bad memory */
941 if (WhichList & BL_MM_INCLUDE_BAD_MEMORY)
942 {
943 /* Find a descriptor in that list */
944 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlBadMemory, Flags, Page);
945 if (FoundDescriptor)
946 {
947 /* Got it */
948 return FoundDescriptor;
949 }
950 }
951
952 /* Check if the caller is looking for truncated memory */
953 if (WhichList & BL_MM_INCLUDE_TRUNCATED_MEMORY)
954 {
955 /* Find a descriptor in that list */
956 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlTruncatedMemory, Flags, Page);
957 if (FoundDescriptor)
958 {
959 /* Got it */
960 return FoundDescriptor;
961 }
962 }
963
964 /* Check if the caller is looking for persistent memory */
965 if (WhichList & BL_MM_INCLUDE_PERSISTENT_MEMORY)
966 {
967 /* Find a descriptor in that list */
968 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlPersistentMemory, Flags, Page);
969 if (FoundDescriptor)
970 {
971 /* Got it */
972 return FoundDescriptor;
973 }
974 }
975
976 /* Nothing if we got here */
977 return NULL;
978 }
979
980 BOOLEAN
981 MmMdFindSatisfyingRegion (
982 _In_ PBL_MEMORY_DESCRIPTOR Descriptor,
983 _Out_ PBL_MEMORY_DESCRIPTOR NewDescriptor,
984 _In_ ULONGLONG Pages,
985 _In_ PBL_ADDRESS_RANGE BaseRange,
986 _In_ PBL_ADDRESS_RANGE VirtualRange,
987 _In_ BOOLEAN TopDown,
988 _In_ BL_MEMORY_TYPE MemoryType,
989 _In_ ULONG Flags,
990 _In_ ULONG Alignment
991 )
992 {
993 ULONGLONG BaseMin, BaseMax;
994 ULONGLONG VirtualPage, BasePage;
995
996 /* Extract the minimum and maximum range */
997 BaseMin = BaseRange->Minimum;
998 BaseMax = BaseRange->Maximum;
999
1000 /* Don't go below where the descriptor starts */
1001 if (BaseMin < Descriptor->BasePage)
1002 {
1003 BaseMin = Descriptor->BasePage;
1004 }
1005
1006 /* Don't go beyond where the descriptor ends */
1007 if (BaseMax > (Descriptor->BasePage + Descriptor->PageCount - 1))
1008 {
1009 BaseMax = (Descriptor->BasePage + Descriptor->PageCount - 1);
1010 }
1011
1012 /* Check for start overflow */
1013 if (BaseMin > BaseMax)
1014 {
1015 EfiPrintf(L"Descriptor overflow\r\n");
1016 return FALSE;
1017 }
1018
1019 /* Align the base as required */
1020 if (Alignment != 1)
1021 {
1022 BaseMin = ALIGN_UP_BY(BaseMin, Alignment);
1023 }
1024
1025 /* Check for range overflow */
1026 if (((BaseMin + Pages - 1) < BaseMin) || ((BaseMin + Pages - 1) > BaseMax))
1027 {
1028 return FALSE;
1029 }
1030
1031 /* Check if this was a top-down request */
1032 if (TopDown)
1033 {
1034 /* Then get the highest page possible */
1035 BasePage = BaseMax - Pages + 1;
1036 if (Alignment != 1)
1037 {
1038 /* Align it as needed */
1039 BasePage = ALIGN_DOWN_BY(BasePage, Alignment);
1040 }
1041 }
1042 else
1043 {
1044 /* Otherwise, get the lowest page possible */
1045 BasePage = BaseMin;
1046 }
1047
1048 /* If a virtual address range was passed in, this must be a virtual descriptor */
1049 if (((VirtualRange->Minimum) || (VirtualRange->Maximum)) &&
1050 !(Descriptor->VirtualPage))
1051 {
1052 return FALSE;
1053 }
1054
1055 /* Any mapped page already? */
1056 if (Descriptor->VirtualPage)
1057 {
1058 EfiPrintf(L"Virtual memory not yet supported\r\n");
1059 return FALSE;
1060 }
1061 else
1062 {
1063 /* Nothing to worry about */
1064 VirtualPage = 0;
1065 }
1066
1067 /* Bail out if the memory type attributes don't match */
1068 if ((((Flags & 0xFF) & (Descriptor->Flags & 0xFF)) != (Flags & 0xFF)) ||
1069 (((Flags & 0xFF00) & (Descriptor->Flags & 0xFF00)) != (Flags & 0xFF00)))
1070 {
1071 EfiPrintf(L"Incorrect memory attributes\r\n");
1072 return FALSE;
1073 }
1074
1075 /* Bail out if the allocation flags don't match */
1076 if (((Flags ^ Descriptor->Flags) & (BlMemoryRuntime | BlMemoryReserved | BlMemoryUnknown)))
1077 {
1078 //EfiPrintf(L"Incorrect memory allocation flags\r\n");
1079 return FALSE;
1080 }
1081
1082 /* Bail out if the type doesn't match */
1083 if (Descriptor->Type != MemoryType)
1084 {
1085 //EfiPrintf(L"Incorrect descriptor type: %lx %lx\r\n", Descriptor->Type, MemoryType);
1086 return FALSE;
1087 }
1088
1089 /* We have a matching region, fill out the descriptor for it */
1090 NewDescriptor->BasePage = BasePage;
1091 NewDescriptor->PageCount = Pages;
1092 NewDescriptor->Type = Descriptor->Type;
1093 NewDescriptor->VirtualPage = VirtualPage;
1094 NewDescriptor->Flags = Descriptor->Flags;
1095 //EfiPrintf(L"Found a matching descriptor: %08I64X with %08I64X pages\r\n", BasePage, Pages);
1096 return TRUE;
1097 }
1098
1099 VOID
1100 MmMdFreeGlobalDescriptors (
1101 VOID
1102 )
1103 {
1104 PBL_MEMORY_DESCRIPTOR Descriptor, OldDescriptor;
1105 ULONG Index = 0;
1106 PLIST_ENTRY OldFlink, OldBlink;
1107
1108 /* Make sure we're not int middle of a call using a descriptor */
1109 if (MmDescriptorCallTreeCount != 1)
1110 {
1111 return;
1112 }
1113
1114 /* Loop every current global descriptor */
1115 while (Index < MmGlobalMemoryDescriptorsUsed)
1116 {
1117 /* Does it have any valid pageS? */
1118 OldDescriptor = &MmGlobalMemoryDescriptors[Index];
1119 if (OldDescriptor->PageCount)
1120 {
1121 /* Allocate a copy of it */
1122 Descriptor = BlMmAllocateHeap(sizeof(*Descriptor));
1123 if (!Descriptor)
1124 {
1125 return;
1126 }
1127
1128 /* Save the links */
1129 OldBlink = OldDescriptor->ListEntry.Blink;
1130 OldFlink = OldDescriptor->ListEntry.Flink;
1131
1132 /* Make the copy */
1133 *Descriptor = *OldDescriptor;
1134
1135 /* Fix the links */
1136 OldBlink->Flink = &Descriptor->ListEntry;
1137 OldFlink->Blink = &Descriptor->ListEntry;
1138
1139 /* Zero the descriptor */
1140 RtlZeroMemory(OldDescriptor, sizeof(*OldDescriptor));
1141 }
1142
1143 /* Keep going */
1144 Index++;
1145 }
1146
1147 /* All global descriptors freed */
1148 MmGlobalMemoryDescriptorsUsed = 0;
1149 }
1150
1151 VOID
1152 MmMdInitialize (
1153 _In_ ULONG Phase,
1154 _In_ PBL_LIBRARY_PARAMETERS LibraryParameters
1155 )
1156 {
1157 /* Are we in phase 1? */
1158 if (Phase != 0)
1159 {
1160 /* Switch to dynamic descriptors if we have too many */
1161 if (LibraryParameters->DescriptorCount > RTL_NUMBER_OF(MmStaticMemoryDescriptors))
1162 {
1163 MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
1164 }
1165 }
1166 else
1167 {
1168 /* In phase 0, start with a pool of 512 static descriptors */
1169 MmGlobalMemoryDescriptorCount = RTL_NUMBER_OF(MmStaticMemoryDescriptors);
1170 MmGlobalMemoryDescriptors = MmStaticMemoryDescriptors;
1171 RtlZeroMemory(MmStaticMemoryDescriptors, sizeof(MmStaticMemoryDescriptors));
1172 MmGlobalMemoryDescriptorsUsed = 0;
1173 }
1174 }