[BOOTLIB]: Clarify some attributes now that their meaning is clearer.
[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
684 /* Make a copy of the original descriptor */
685 RtlCopyMemory(&NewDescriptor, NextEntry, sizeof(NewDescriptor));
686
687 /* Check if the region to be removed starts after the found region starts */
688 if ((BasePage > FoundBasePage) || (FoundBasePage >= EndPage))
689 {
690 /* Check if the region ends after the found region */
691 if ((BasePage >= FoundEndPage) || (FoundEndPage > EndPage))
692 {
693 /* Check if the found region starts after the region or ends before the region */
694 if ((FoundBasePage >= BasePage) || (EndPage >= FoundEndPage))
695 {
696 /* This descriptor doesn't cover any part of the range -- nothing to do */
697 NOTHING;
698 }
699 else
700 {
701 /* This descriptor fully covers the entire allocation */
702 FoundBasePage = Descriptor->BasePage;
703 FoundPageCount = BasePage - FoundBasePage;
704
705 /* This is how many pages we will eat away from the descriptor */
706 RegionSize = FoundPageCount + PageCount;
707
708 /* Update the descriptor to account for the consumed pages */
709 Descriptor->BasePage += RegionSize;
710 Descriptor->PageCount -= RegionSize;
711 if (Descriptor->VirtualPage)
712 {
713 Descriptor->VirtualPage += RegionSize;
714 }
715
716 /* Initialize a descriptor for the start of the region */
717 Descriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
718 Descriptor->Type,
719 FoundBasePage,
720 Descriptor->VirtualPage,
721 FoundPageCount);
722 if (!Descriptor)
723 {
724 Status = STATUS_NO_MEMORY;
725 goto Quickie;
726 }
727
728 /* Add it into the list */
729 Status = MmMdAddDescriptorToList(MdList, Descriptor, Flags);
730 if (!NT_SUCCESS(Status))
731 {
732 Status = STATUS_NO_MEMORY;
733 goto Quickie;
734 }
735 }
736 }
737 else
738 {
739 /* This descriptor contains the entire allocation */
740 RegionSize = FoundEndPage - BasePage;
741 Descriptor->PageCount -= RegionSize;
742 }
743
744 /* Keep going */
745 NextEntry = NextEntry->Flink;
746 }
747 else
748 {
749 /*
750 * This descriptor contains the end of the allocation. It may:
751 *
752 * - Contain the full allocation (i.e.: the start is aligned)
753 * - Contain parts of the end of the allocation (i.e.: the end is beyond)
754 * - Contain the entire tail end of the allocation (i..e:the end is within)
755 *
756 * So first, figure out if we cover the entire end or not
757 */
758 if (EndPage < FoundEndPage)
759 {
760 /* The allocation goes past the end of this descriptor */
761 FoundEndPage = EndPage;
762 }
763
764 /* This is how many pages we will eat away from the descriptor */
765 RegionSize = FoundEndPage - FoundBasePage;
766
767 /* Update the descriptor to account for the consumed pages */
768 Descriptor->BasePage += RegionSize;
769 Descriptor->PageCount -= RegionSize;
770 if (Descriptor->VirtualPage)
771 {
772 Descriptor->VirtualPage += RegionSize;
773 }
774
775 /* Go to the next entry */
776 NextEntry = NextEntry->Flink;
777
778 /* Check if the descriptor is now empty */
779 if (!Descriptor->PageCount)
780 {
781 /* Remove it */
782 MmMdRemoveDescriptorFromList(MdList, Descriptor);
783 MmMdFreeDescriptor(Descriptor);
784
785 /* Check if we're supposed to insert it into a new list */
786 if (HaveNewList)
787 {
788 EfiPrintf(L"Not yet implemented\r\n");
789 Status = STATUS_NOT_IMPLEMENTED;
790 goto Quickie;
791 }
792 }
793 }
794 }
795
796 Quickie:
797 /* Check for failure cleanup */
798 if (!NT_SUCCESS(Status))
799 {
800 /* Did we have to build a new list? */
801 if (HaveNewList)
802 {
803 /* Free and re-initialize it */
804 MmMdFreeList(NewMdList);
805 MmMdInitializeListHead(NewMdList);
806 NewMdList->Type = MdList->Type;
807 }
808 }
809
810 return Status;
811 }
812
813 PBL_MEMORY_DESCRIPTOR
814 MmMdFindDescriptorFromMdl (
815 _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
816 _In_ ULONG Flags,
817 _In_ ULONGLONG Page
818 )
819 {
820 BOOLEAN IsVirtual;
821 PLIST_ENTRY NextEntry, ListHead;
822 PBL_MEMORY_DESCRIPTOR Current;
823 ULONGLONG BasePage;
824
825 /* Assume physical */
826 IsVirtual = FALSE;
827
828 /* Check if the caller wants physical memory */
829 if (!(Flags & BL_MM_REMOVE_VIRTUAL_REGION_FLAG))
830 {
831 /* Check if this is a virtual memory list */
832 if (MdList->Type == BlMdVirtual)
833 {
834 /* We won't find anything */
835 return NULL;
836 }
837 }
838 else if (MdList->Type == BlMdPhysical)
839 {
840 /* Otherwise, caller wants virtual, but this is a physical list */
841 IsVirtual = TRUE;
842 NextEntry = MdList->First->Flink;
843 }
844
845 /* Check if this is a physical search */
846 if (!IsVirtual)
847 {
848 /* Check if we can use the current pointer */
849 NextEntry = MdList->This;
850 if (!NextEntry)
851 {
852 /* We can't -- start at the beginning */
853 NextEntry = MdList->First->Flink;
854 }
855 else
856 {
857 /* If the page is below the current pointer, restart */
858 Current = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
859 if (Page < Current->BasePage)
860 {
861 NextEntry = MdList->First->Flink;
862 }
863 }
864 }
865
866 /* Loop the list of descriptors */
867 ListHead = MdList->First;
868 while (NextEntry != ListHead)
869 {
870 /* Get the current one */
871 Current = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
872
873 /* Check if we are looking for virtual memory */
874 if (IsVirtual)
875 {
876 /* Use the base address */
877 BasePage = Current->VirtualPage;
878 }
879 else
880 {
881 /* Use the page */
882 BasePage = Current->BasePage;
883 }
884
885 /* If this is a virtual descriptor, make sure it has a base address */
886 if ((!(IsVirtual) || (BasePage)) &&
887 (BasePage <= Page) &&
888 (Page < (BasePage + Current->PageCount)))
889 {
890 /* The descriptor fits the page being requested */
891 return Current;
892 }
893
894 /* Try the next one */
895 NextEntry = NextEntry->Flink;
896 }
897
898 /* Nothing found if we're here */
899 return NULL;
900 }
901
902 PBL_MEMORY_DESCRIPTOR
903 MmMdFindDescriptor (
904 _In_ ULONG WhichList,
905 _In_ ULONG Flags,
906 _In_ ULONGLONG Page
907 )
908 {
909 PBL_MEMORY_DESCRIPTOR FoundDescriptor;
910
911 /* Check if the caller is looking for mapped, allocated memory */
912 if (WhichList & BL_MM_INCLUDE_MAPPED_ALLOCATED)
913 {
914 /* Find a descriptor in that list */
915 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlMappedAllocated, Flags, Page);
916 if (FoundDescriptor)
917 {
918 /* Got it */
919 return FoundDescriptor;
920 }
921 }
922
923 /* Check if the caller is looking for mapped, unallocated memory */
924 if (WhichList & BL_MM_INCLUDE_MAPPED_UNALLOCATED)
925 {
926 /* Find a descriptor in that list */
927 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlMappedUnallocated, Flags, Page);
928 if (FoundDescriptor)
929 {
930 /* Got it */
931 return FoundDescriptor;
932 }
933 }
934
935 /* Check if the caller is looking for unmapped, allocated memory */
936 if (WhichList & BL_MM_INCLUDE_UNMAPPED_ALLOCATED)
937 {
938 /* Find a descriptor in that list */
939 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlUnmappedAllocated, Flags, Page);
940 if (FoundDescriptor)
941 {
942 /* Got it */
943 return FoundDescriptor;
944 }
945 }
946
947 /* Check if the caller is looking for unmapped, unallocated memory */
948 if (WhichList & BL_MM_INCLUDE_UNMAPPED_UNALLOCATED)
949 {
950 /* Find a descriptor in that list */
951 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlUnmappedUnallocated, Flags, Page);
952 if (FoundDescriptor)
953 {
954 /* Got it */
955 return FoundDescriptor;
956 }
957 }
958
959 /* Check if the caller is looking for reserved, allocated memory */
960 if (WhichList & BL_MM_INCLUDE_RESERVED_ALLOCATED)
961 {
962 /* Find a descriptor in that list */
963 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlReservedAllocated, Flags, Page);
964 if (FoundDescriptor)
965 {
966 /* Got it */
967 return FoundDescriptor;
968 }
969 }
970
971 /* Check if the caller is looking for bad memory */
972 if (WhichList & BL_MM_INCLUDE_BAD_MEMORY)
973 {
974 /* Find a descriptor in that list */
975 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlBadMemory, Flags, Page);
976 if (FoundDescriptor)
977 {
978 /* Got it */
979 return FoundDescriptor;
980 }
981 }
982
983 /* Check if the caller is looking for truncated memory */
984 if (WhichList & BL_MM_INCLUDE_TRUNCATED_MEMORY)
985 {
986 /* Find a descriptor in that list */
987 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlTruncatedMemory, Flags, Page);
988 if (FoundDescriptor)
989 {
990 /* Got it */
991 return FoundDescriptor;
992 }
993 }
994
995 /* Check if the caller is looking for persistent memory */
996 if (WhichList & BL_MM_INCLUDE_PERSISTENT_MEMORY)
997 {
998 /* Find a descriptor in that list */
999 FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlPersistentMemory, Flags, Page);
1000 if (FoundDescriptor)
1001 {
1002 /* Got it */
1003 return FoundDescriptor;
1004 }
1005 }
1006
1007 /* Nothing if we got here */
1008 return NULL;
1009 }
1010
1011 BOOLEAN
1012 MmMdFindSatisfyingRegion (
1013 _In_ PBL_MEMORY_DESCRIPTOR Descriptor,
1014 _Out_ PBL_MEMORY_DESCRIPTOR NewDescriptor,
1015 _In_ ULONGLONG Pages,
1016 _In_ PBL_ADDRESS_RANGE BaseRange,
1017 _In_ PBL_ADDRESS_RANGE VirtualRange,
1018 _In_ BOOLEAN TopDown,
1019 _In_ BL_MEMORY_TYPE MemoryType,
1020 _In_ ULONG Flags,
1021 _In_ ULONG Alignment
1022 )
1023 {
1024 ULONGLONG BaseMin, BaseMax;
1025 ULONGLONG VirtualPage, BasePage;
1026
1027 /* Extract the minimum and maximum range */
1028 BaseMin = BaseRange->Minimum;
1029 BaseMax = BaseRange->Maximum;
1030
1031 /* Don't go below where the descriptor starts */
1032 if (BaseMin < Descriptor->BasePage)
1033 {
1034 BaseMin = Descriptor->BasePage;
1035 }
1036
1037 /* Don't go beyond where the descriptor ends */
1038 if (BaseMax > (Descriptor->BasePage + Descriptor->PageCount - 1))
1039 {
1040 BaseMax = (Descriptor->BasePage + Descriptor->PageCount - 1);
1041 }
1042
1043 /* Check for start overflow */
1044 if (BaseMin > BaseMax)
1045 {
1046 EfiPrintf(L"Descriptor overflow\r\n");
1047 return FALSE;
1048 }
1049
1050 /* Align the base as required */
1051 if (Alignment != 1)
1052 {
1053 BaseMin = ALIGN_UP_BY(BaseMin, Alignment);
1054 }
1055
1056 /* Check for range overflow */
1057 if (((BaseMin + Pages - 1) < BaseMin) || ((BaseMin + Pages - 1) > BaseMax))
1058 {
1059 return FALSE;
1060 }
1061
1062 /* Check if this was a top-down request */
1063 if (TopDown)
1064 {
1065 /* Then get the highest page possible */
1066 BasePage = BaseMax - Pages + 1;
1067 if (Alignment != 1)
1068 {
1069 /* Align it as needed */
1070 BasePage = ALIGN_DOWN_BY(BasePage, Alignment);
1071 }
1072 }
1073 else
1074 {
1075 /* Otherwise, get the lowest page possible */
1076 BasePage = BaseMin;
1077 }
1078
1079 /* If a virtual address range was passed in, this must be a virtual descriptor */
1080 if (((VirtualRange->Minimum) || (VirtualRange->Maximum)) &&
1081 !(Descriptor->VirtualPage))
1082 {
1083 return FALSE;
1084 }
1085
1086 /* Any mapped page already? */
1087 if (Descriptor->VirtualPage)
1088 {
1089 EfiPrintf(L"Virtual memory not yet supported\r\n");
1090 return FALSE;
1091 }
1092 else
1093 {
1094 /* Nothing to worry about */
1095 VirtualPage = 0;
1096 }
1097
1098 /* Bail out if the memory type attributes don't match */
1099 if ((((Flags & 0xFF) & (Descriptor->Flags & 0xFF)) != (Flags & 0xFF)) ||
1100 (((Flags & 0xFF00) & (Descriptor->Flags & 0xFF00)) != (Flags & 0xFF00)))
1101 {
1102 EfiPrintf(L"Incorrect memory attributes\r\n");
1103 return FALSE;
1104 }
1105
1106 /* Bail out if the allocation flags don't match */
1107 if (((Flags ^ Descriptor->Flags) & (BlMemoryRuntime | BlMemoryBelow1MB | BlMemoryLargePages)))
1108 {
1109 //EfiPrintf(L"Incorrect memory allocation flags\r\n");
1110 return FALSE;
1111 }
1112
1113 /* Bail out if the type doesn't match */
1114 if (Descriptor->Type != MemoryType)
1115 {
1116 //EfiPrintf(L"Incorrect descriptor type: %lx %lx\r\n", Descriptor->Type, MemoryType);
1117 return FALSE;
1118 }
1119
1120 /* We have a matching region, fill out the descriptor for it */
1121 NewDescriptor->BasePage = BasePage;
1122 NewDescriptor->PageCount = Pages;
1123 NewDescriptor->Type = Descriptor->Type;
1124 NewDescriptor->VirtualPage = VirtualPage;
1125 NewDescriptor->Flags = Descriptor->Flags;
1126 //EfiPrintf(L"Found a matching descriptor: %08I64X with %08I64X pages\r\n", BasePage, Pages);
1127 return TRUE;
1128 }
1129
1130 VOID
1131 MmMdFreeGlobalDescriptors (
1132 VOID
1133 )
1134 {
1135 PBL_MEMORY_DESCRIPTOR Descriptor, OldDescriptor;
1136 ULONG Index = 0;
1137 PLIST_ENTRY OldFlink, OldBlink;
1138
1139 /* Make sure we're not int middle of a call using a descriptor */
1140 if (MmDescriptorCallTreeCount != 1)
1141 {
1142 return;
1143 }
1144
1145 /* Loop every current global descriptor */
1146 while (Index < MmGlobalMemoryDescriptorsUsed)
1147 {
1148 /* Does it have any valid pageS? */
1149 OldDescriptor = &MmGlobalMemoryDescriptors[Index];
1150 if (OldDescriptor->PageCount)
1151 {
1152 /* Allocate a copy of it */
1153 Descriptor = BlMmAllocateHeap(sizeof(*Descriptor));
1154 if (!Descriptor)
1155 {
1156 return;
1157 }
1158
1159 /* Save the links */
1160 OldBlink = OldDescriptor->ListEntry.Blink;
1161 OldFlink = OldDescriptor->ListEntry.Flink;
1162
1163 /* Make the copy */
1164 *Descriptor = *OldDescriptor;
1165
1166 /* Fix the links */
1167 OldBlink->Flink = &Descriptor->ListEntry;
1168 OldFlink->Blink = &Descriptor->ListEntry;
1169
1170 /* Zero the descriptor */
1171 RtlZeroMemory(OldDescriptor, sizeof(*OldDescriptor));
1172 }
1173
1174 /* Keep going */
1175 Index++;
1176 }
1177
1178 /* All global descriptors freed */
1179 MmGlobalMemoryDescriptorsUsed = 0;
1180 }
1181
1182 VOID
1183 MmMdInitialize (
1184 _In_ ULONG Phase,
1185 _In_ PBL_LIBRARY_PARAMETERS LibraryParameters
1186 )
1187 {
1188 /* Are we in phase 1? */
1189 if (Phase != 0)
1190 {
1191 /* Switch to dynamic descriptors if we have too many */
1192 if (LibraryParameters->DescriptorCount > RTL_NUMBER_OF(MmStaticMemoryDescriptors))
1193 {
1194 MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
1195 }
1196 }
1197 else
1198 {
1199 /* In phase 0, start with a pool of 512 static descriptors */
1200 MmGlobalMemoryDescriptorCount = RTL_NUMBER_OF(MmStaticMemoryDescriptors);
1201 MmGlobalMemoryDescriptors = MmStaticMemoryDescriptors;
1202 RtlZeroMemory(MmStaticMemoryDescriptors, sizeof(MmStaticMemoryDescriptors));
1203 MmGlobalMemoryDescriptorsUsed = 0;
1204 }
1205 }