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