/* * COPYRIGHT: See COPYING.ARM in the top level directory * PROJECT: ReactOS UEFI Boot Library * FILE: boot/environ/lib/mm/descriptor.c * PURPOSE: Boot Library Memory Manager Descriptor Manager * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) */ /* INCLUDES ******************************************************************/ #include "bl.h" /* DATA VARIABLES ************************************************************/ BL_MEMORY_DESCRIPTOR MmStaticMemoryDescriptors[512]; ULONG MmGlobalMemoryDescriptorCount; PBL_MEMORY_DESCRIPTOR MmGlobalMemoryDescriptors; ULONG MmGlobalMemoryDescriptorsUsed; PBL_MEMORY_DESCRIPTOR MmDynamicMemoryDescriptors; ULONG MmDynamicMemoryDescriptorCount; BL_MEMORY_TYPE MmPlatformMemoryTypePrecedence[] = { BlReservedMemory, BlUnusableMemory, BlDeviceIoMemory, BlDevicePortMemory, BlPalMemory, BlEfiRuntimeCodeMemory, BlEfiRuntimeDataMemory, BlAcpiNvsMemory, BlAcpiReclaimMemory, BlEfiBootMemory, BlConventionalMemory, BlConventionalZeroedMemory }; /* FUNCTIONS *****************************************************************/ LONG MmMdpLookupTypePrecedenceIndex ( _In_ BL_MEMORY_TYPE Type ) { ULONG i; /* Check the precedence array */ for (i = 0; i < RTL_NUMBER_OF(MmPlatformMemoryTypePrecedence); i++) { /* Check for a match */ if (MmPlatformMemoryTypePrecedence[i] == Type) { /* Return the index */ return i; } } /* Invalid index type */ return -1; } /* The order is Conventional > Other > System > Loader > Application */ BOOLEAN MmMdpHasPrecedence ( _In_ BL_MEMORY_TYPE Type1, _In_ BL_MEMORY_TYPE Type2 ) { BL_MEMORY_CLASS Class1, Class2; ULONG i, j; /* It isn't free RAM, but the comparator is -- it succeeds it */ if (Type2 == BlConventionalMemory) { return TRUE; } /* Descriptor is free RAM -- it precedes */ if (Type1 == BlConventionalMemory) { return FALSE; } /* Descriptor is not system, application, or loader class -- it precedes */ Class1 = Type1 >> BL_MEMORY_CLASS_SHIFT; if ((Class1 != BlSystemClass) && (Class1 != BlApplicationClass) && (Class1 != BlLoaderClass)) { return TRUE; } /* It isn't one of those classes, but the comparator it -- it succeeds it */ Class2 = Type2 >> BL_MEMORY_CLASS_SHIFT; if ((Class2 != BlSystemClass) && (Class2 != BlApplicationClass) && (Class2 != BlLoaderClass)) { return FALSE; } /* Descriptor is system class */ if (Class1 == BlSystemClass) { /* If the other guy isn't, system wins */ if (Class2 != BlSystemClass) { return TRUE; } /* Scan for the descriptor's system precedence index */ i = MmMdpLookupTypePrecedenceIndex(Type1); j = MmMdpLookupTypePrecedenceIndex(Type2); /* Does the current have a valid index? */ if (i == 0xFFFFFFFF) { return TRUE; } /* Yes, what about the comparator? */ if (j == 0xFFFFFFFF) { return FALSE; } /* Let the indexes fight! */ return i <= j; } /* Descriptor is not system class, but comparator is -- it succeeds it */ if (Class2 == BlSystemClass) { return FALSE; } /* Descriptor is loader class -- it preceedes */ if (Class1 == BlLoaderClass) { return TRUE; } /* It isn't loader class -- if the other guy is, succeed it */ return Class2 != BlLoaderClass; } VOID MmMdpSwitchToDynamicDescriptors ( _In_ ULONG Count ) { EfiPrintf(L"Dynamic switch NOT SUPPORTED!!!\r\n"); EfiStall(10000000); } NTSTATUS MmMdFreeDescriptor ( _In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor ) { NTSTATUS Status; /* Check if this is a valid static descriptor */ if (((MmDynamicMemoryDescriptors) && (MemoryDescriptor >= MmDynamicMemoryDescriptors) && (MemoryDescriptor < &MmDynamicMemoryDescriptors[MmDynamicMemoryDescriptorCount])) || ((MemoryDescriptor >= MmStaticMemoryDescriptors) && (MemoryDescriptor < &MmStaticMemoryDescriptors[RTL_NUMBER_OF(MmStaticMemoryDescriptors)]))) { /* It's a global/static descriptor, so just zero it */ RtlZeroMemory(MemoryDescriptor, sizeof(BL_MEMORY_DESCRIPTOR)); Status = STATUS_SUCCESS; } else { /* It's a dynamic descriptor, so free it */ Status = BlMmFreeHeap(MemoryDescriptor); } /* Done */ return Status; } VOID MmMdpSaveCurrentListPointer ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ PLIST_ENTRY Current ) { PBL_MEMORY_DESCRIPTOR FirstEntry, LastEntry; /* Make sure that this is not a global descriptor and not the first one */ FirstEntry = &MmGlobalMemoryDescriptors[0]; LastEntry = &MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorCount]; if ((((ULONG_PTR)Current < (ULONG_PTR)FirstEntry) || ((ULONG_PTR)Current >= (ULONG_PTR)LastEntry)) && (Current != MdList->First)) { /* Save this as the current pointer */ MdList->This = Current; } } ULONG MmMdCountList ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList ) { PLIST_ENTRY First, NextEntry; ULONG Count; /* Iterate the list */ for (Count = 0, First = MdList->First, NextEntry = First->Flink; NextEntry != First; NextEntry = NextEntry->Flink, Count++); /* Return the count */ return Count; } VOID MmMdInitializeList ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ ULONG Type, _In_ PLIST_ENTRY ListHead ) { /* Check if a list was specified */ if (ListHead) { /* Use it */ MdList->First = ListHead; } else { /* Otherwise, use the internal, built-in list */ InitializeListHead(&MdList->ListHead); MdList->First = &MdList->ListHead; } /* Set the type */ MdList->Type = Type; /* Initialize current iterator to nothing */ MdList->This = NULL; } NTSTATUS MmMdCopyList ( _In_ PBL_MEMORY_DESCRIPTOR_LIST DestinationList, _In_ PBL_MEMORY_DESCRIPTOR_LIST SourceList, _In_opt_ PBL_MEMORY_DESCRIPTOR ListDescriptor, _Out_ PULONG ActualCount, _In_ ULONG Count, _In_ ULONG Flags ) { NTSTATUS Status; PULONG Used; PLIST_ENTRY First, NextEntry; PBL_MEMORY_DESCRIPTOR Descriptor; /* Both parameters must be present */ if (!(DestinationList) || !(SourceList)) { return STATUS_INVALID_PARAMETER; } /* Assume success */ Status = STATUS_SUCCESS; /* Check if a descriptor is being used to store the list */ if (ListDescriptor) { /* See how big it is */ Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG; Used = ActualCount; } else { /* We are using our internal descriptors instead */ Used = &MmGlobalMemoryDescriptorsUsed; ++MmDescriptorCallTreeCount; /* Use as many as are available */ Count = MmGlobalMemoryDescriptorCount; ListDescriptor = MmGlobalMemoryDescriptors; } /* Never truncate descriptors during a list copy */ Flags |= BL_MM_ADD_DESCRIPTOR_NEVER_TRUNCATE_FLAG; /* Iterate through the list */ First = SourceList->First; NextEntry = First->Flink; while ((NextEntry != First) && (NT_SUCCESS(Status))) { /* Make sure there's still space */ if (Count <= *Used) { Status = STATUS_NO_MEMORY; break; } /* Get the current descriptor */ Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Copy it into one of the descriptors we have */ RtlCopyMemory(&ListDescriptor[*Used], Descriptor, sizeof(*Descriptor)); /* Add it to the list we have */ Status = MmMdAddDescriptorToList(DestinationList, &ListDescriptor[*Used], Flags); ++*Used; /* Move to the next entry */ NextEntry = NextEntry->Flink; } /* Check if the global descriptors were used */ if (ListDescriptor == MmGlobalMemoryDescriptors) { /* Unwind our usage */ MmMdFreeGlobalDescriptors(); --MmDescriptorCallTreeCount; } /* Return back to caller */ return Status; } VOID MmMdRemoveDescriptorFromList ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ PBL_MEMORY_DESCRIPTOR Entry ) { /* Remove the entry */ RemoveEntryList(&Entry->ListEntry); /* Check if this was the current link */ if (MdList->This == &Entry->ListEntry) { /* Remove the current link and set the next one */ MdList->This = NULL; MmMdpSaveCurrentListPointer(MdList, Entry->ListEntry.Blink); } } VOID MmMdFreeList( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList ) { PLIST_ENTRY FirstEntry, NextEntry; PBL_MEMORY_DESCRIPTOR Entry; /* Go over every descriptor from the top */ FirstEntry = MdList->First; NextEntry = FirstEntry->Flink; while (NextEntry != FirstEntry) { /* Remove and free each one */ Entry = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); NextEntry = NextEntry->Flink; MmMdRemoveDescriptorFromList(MdList, Entry); MmMdFreeDescriptor(Entry); } } PBL_MEMORY_DESCRIPTOR MmMdInitByteGranularDescriptor ( _In_ ULONG Flags, _In_ BL_MEMORY_TYPE Type, _In_ ULONGLONG BasePage, _In_ ULONGLONG VirtualPage, _In_ ULONGLONG PageCount ) { PBL_MEMORY_DESCRIPTOR MemoryDescriptor; /* If we're out of descriptors, bail out */ if (MmGlobalMemoryDescriptorsUsed >= MmGlobalMemoryDescriptorCount) { EfiPrintf(L"Out of descriptors!\r\n"); EfiStall(1000000); return NULL; } /* Take one of the available descriptors and fill it out */ MemoryDescriptor = &MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorsUsed]; MemoryDescriptor->BasePage = BasePage; MemoryDescriptor->VirtualPage = VirtualPage; MemoryDescriptor->PageCount = PageCount; MemoryDescriptor->Flags = Flags; MemoryDescriptor->Type = Type; InitializeListHead(&MemoryDescriptor->ListEntry); /* Increment the count and return the descriptor */ MmGlobalMemoryDescriptorsUsed++; return MemoryDescriptor; } NTSTATUS MmMdTruncateDescriptors ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ PBL_MEMORY_DESCRIPTOR_LIST NewList, _In_ ULONGLONG BasePage ) { PLIST_ENTRY ListHead, NextEntry; PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor; ULONGLONG FoundEndPage; /* Search the descriptor list */ ListHead = MdList->First; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the current descriptor */ Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Go to the next entry in case we have to remove */ NextEntry = NextEntry->Flink; /* Don't touch anything else but free RAM */ if (((Descriptor->Type >> BL_MEMORY_CLASS_SHIFT) == BlSystemClass) && (Descriptor->Type != BlConventionalMemory)) { continue; } /* Check if this page is within the descriptor's region */ FoundEndPage = Descriptor->BasePage + Descriptor->PageCount; if (BasePage > Descriptor->BasePage) { /* Check if it doesn't go beyond the descriptor */ if (BasePage < FoundEndPage) { /* Create a new descriptor to describe this region */ EfiPrintf(L"Truncating descriptor type %lx base: %llx end: %llx\r\n", Descriptor->Type, Descriptor->BasePage, FoundEndPage); NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags, Descriptor->Type, BasePage, 0, FoundEndPage - BasePage); if (!NewDescriptor) { return STATUS_NO_MEMORY; } /* Cut off this descriptor to make it shorter */ Descriptor->PageCount = BasePage - Descriptor->BasePage; /* Add the region to the new list */ MmMdAddDescriptorToList(NewList, NewDescriptor, BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG); } } else { /* This whole descriptor covers the truncated area */ EfiPrintf(L"Truncating descriptor type %lx base: %llx end: %llx\r\n", Descriptor->Type, Descriptor->BasePage, FoundEndPage); MmMdRemoveDescriptorFromList(MdList, Descriptor); MmMdAddDescriptorToList(NewList, Descriptor, BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG); } } /* All good if we got here */ return STATUS_SUCCESS; } BOOLEAN MmMdpTruncateDescriptor ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor, _In_ ULONG Flags ) { PBL_MEMORY_DESCRIPTOR NextDescriptor, PreviousDescriptor; PLIST_ENTRY NextEntry, PreviousEntry; ULONGLONG EndPage, PreviousEndPage;// , NextEndPage; /* Get the next descriptor */ NextEntry = MemoryDescriptor->ListEntry.Flink; NextDescriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Get the previous descriptor */ PreviousEntry = MemoryDescriptor->ListEntry.Blink; PreviousDescriptor = CONTAINING_RECORD(PreviousEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Calculate end pages */ EndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount; //NextEndPage = NextDescriptor->BasePage + NextDescriptor->PageCount; PreviousEndPage = PreviousDescriptor->BasePage + PreviousDescriptor->PageCount; /* Check for backward overlap */ if ((PreviousEntry != MdList->First) && (MemoryDescriptor->BasePage < PreviousEndPage)) { EfiPrintf(L"Overlap detected -- this is unexpected on x86/x64 platforms\r\n"); EfiStall(1000000); } /* Check for forward overlap */ if ((NextEntry != MdList->First) && (NextDescriptor->BasePage < EndPage)) { EfiPrintf(L"Overlap detected -- this is unexpected on x86/x64 platforms\r\n"); EfiStall(1000000); } /* Nothing to do */ return FALSE; } BOOLEAN MmMdpCoalesceDescriptor ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor, _In_ ULONG Flags ) { PBL_MEMORY_DESCRIPTOR NextDescriptor, PreviousDescriptor; PLIST_ENTRY NextEntry, PreviousEntry; ULONGLONG EndPage, PreviousEndPage, PreviousMappedEndPage, MappedEndPage; /* Get the next descriptor */ NextEntry = MemoryDescriptor->ListEntry.Flink; NextDescriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Get the previous descriptor */ PreviousEntry = MemoryDescriptor->ListEntry.Blink; PreviousDescriptor = CONTAINING_RECORD(PreviousEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Calculate end pages */ EndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount; MappedEndPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount; PreviousMappedEndPage = PreviousDescriptor->VirtualPage + PreviousDescriptor->PageCount; PreviousEndPage = PreviousDescriptor->BasePage + PreviousDescriptor->PageCount; PreviousMappedEndPage = PreviousDescriptor->VirtualPage + PreviousDescriptor->PageCount; /* Check if the previous entry touches the current entry, and is compatible */ if ((PreviousEntry != MdList->First) && (PreviousDescriptor->Type == MemoryDescriptor->Type) && ((PreviousDescriptor->Flags ^ MemoryDescriptor->Flags) & 0x1B19FFFF) && (PreviousEndPage == MemoryDescriptor->BasePage) && ((!(MemoryDescriptor->VirtualPage) && !(PreviousDescriptor->VirtualPage)) || ((MemoryDescriptor->VirtualPage) && (PreviousDescriptor->VirtualPage) && (PreviousMappedEndPage == MemoryDescriptor->VirtualPage)))) { EfiPrintf(L"Previous descriptor coalescable!\r\n"); } /* CHeck if the current entry touches the next entry, and is compatible */ if ((NextEntry != MdList->First) && (NextDescriptor->Type == MemoryDescriptor->Type) && ((NextDescriptor->Flags ^ MemoryDescriptor->Flags) & 0x1B19FFFF) && (EndPage == NextDescriptor->BasePage) && ((!(MemoryDescriptor->VirtualPage) && !(NextDescriptor->VirtualPage)) || ((MemoryDescriptor->VirtualPage) && (NextDescriptor->VirtualPage) && (MappedEndPage == NextDescriptor->VirtualPage)))) { EfiPrintf(L"Next descriptor coalescable!\r\n"); } /* Nothing to do */ return FALSE; } NTSTATUS MmMdAddDescriptorToList ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor, _In_ ULONG Flags ) { PLIST_ENTRY ThisEntry, FirstEntry; PBL_MEMORY_DESCRIPTOR ThisDescriptor; /* Arguments must be present */ if (!(MdList) || !(MemoryDescriptor)) { return STATUS_INVALID_PARAMETER; } /* Check if coalescing is forcefully disabled */ if (Flags & BL_MM_ADD_DESCRIPTOR_NEVER_COALESCE_FLAG) { /* Then we won't be coalescing */ Flags &= ~BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG; } else if (MemoryDescriptor->Flags & BlMemoryCoalesced) { /* Coalesce if the descriptor requires it */ Flags |= BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG; } /* Check if truncation is forcefully disabled */ if (Flags & BL_MM_ADD_DESCRIPTOR_NEVER_TRUNCATE_FLAG) { Flags &= ~BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG; } /* Update the current list pointer if the descriptor requires it */ if (MemoryDescriptor->Flags & BlMemoryUpdate) { Flags |= BL_MM_ADD_DESCRIPTOR_UPDATE_LIST_POINTER_FLAG; } /* Get the current descriptor */ ThisEntry = MdList->This; ThisDescriptor = CONTAINING_RECORD(ThisEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Also get the first descriptor */ FirstEntry = MdList->First; /* Check if there's no current pointer, or if it's higher than the new one */ if (!(ThisEntry) || (MemoryDescriptor->BasePage <= ThisDescriptor->BasePage)) { /* Start at the first descriptor instead, since current is past us */ ThisEntry = FirstEntry->Flink; } /* Loop until we find the right location to insert */ while (ThisEntry != FirstEntry) { /* Get the descriptor part of this entry */ ThisDescriptor = CONTAINING_RECORD(ThisEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Is the address smaller, or equal but more important? */ if ((MemoryDescriptor->BasePage < ThisDescriptor->BasePage) || ((MemoryDescriptor->BasePage == ThisDescriptor->BasePage) && (MmMdpHasPrecedence(MemoryDescriptor->Type, ThisDescriptor->Type)))) { /* Then insert right here */ InsertTailList(ThisEntry, &MemoryDescriptor->ListEntry); goto Quickie; } /* Try the next entry */ ThisEntry = ThisEntry->Flink; } /* Then we didn't find a good match, so insert it right here */ InsertTailList(FirstEntry, &MemoryDescriptor->ListEntry); Quickie: /* Do we have to truncate? */ if (Flags & BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG) { /* Do it and then exit */ if (MmMdpTruncateDescriptor(MdList, MemoryDescriptor, Flags)) { return STATUS_SUCCESS; } } /* Do we have to coalesce? */ if (Flags & BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG) { /* Do it and then exit */ if (MmMdpCoalesceDescriptor(MdList, MemoryDescriptor, Flags)) { return STATUS_SUCCESS; } } /* Do we have to update the current pointer? */ if (Flags & BL_MM_ADD_DESCRIPTOR_UPDATE_LIST_POINTER_FLAG) { /* Do it */ MmMdpSaveCurrentListPointer(MdList, &MemoryDescriptor->ListEntry); } /* We're done */ return STATUS_SUCCESS; } NTSTATUS MmMdRemoveRegionFromMdlEx ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ ULONG Flags, _In_ ULONGLONG BasePage, _In_ ULONGLONG PageCount, _Out_opt_ PBL_MEMORY_DESCRIPTOR_LIST NewMdList ) { BOOLEAN HaveNewList, UseVirtualPage; NTSTATUS Status; PLIST_ENTRY ListHead, NextEntry; PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor, ListDescriptor; BL_MEMORY_DESCRIPTOR OldDescriptor; ULONGLONG RegionSize; ULONGLONG FoundBasePage, FoundEndPage, FoundPageCount, EndPage, VirtualPage; /* Set initial status */ Status = STATUS_SUCCESS; ListDescriptor = NULL; NewDescriptor = NULL; HaveNewList = FALSE; /* Check if removed descriptors should go into a new list */ if (NewMdList != NULL) { /* Initialize it */ MmMdInitializeList(NewMdList, MdList->Type, NULL); /* Remember for later */ HaveNewList = TRUE; } /* Is the region being removed physical? */ UseVirtualPage = FALSE; if (!(Flags & BL_MM_REMOVE_VIRTUAL_REGION_FLAG)) { /* Is this a list of virtual descriptors? */ if (MdList->Type == BlMdVirtual) { /* Request is nonsensical, fail */ Status = STATUS_INVALID_PARAMETER; goto Quickie; } } else { /* Is this a list of physical descriptors? */ if (MdList->Type == BlMdPhysical) { /* We'll have to use the virtual page instead */ UseVirtualPage = TRUE; } } /* Loop the list*/ ListHead = MdList->First; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the descriptor */ Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Extract range details */ FoundBasePage = UseVirtualPage ? Descriptor->VirtualPage : Descriptor->BasePage; FoundPageCount = Descriptor->PageCount; FoundEndPage = FoundBasePage + FoundPageCount; EndPage = PageCount + BasePage; /* Make a copy of the original descriptor */ OldDescriptor = *Descriptor; /* Check if the region to be removed starts after the found region starts */ if ((BasePage > FoundBasePage) || (FoundBasePage >= EndPage)) { /* Check if the region ends after the found region */ if ((BasePage >= FoundEndPage) || (FoundEndPage > EndPage)) { /* Check if the found region starts after the region or ends before the region */ if ((FoundBasePage >= BasePage) || (EndPage >= FoundEndPage)) { /* This is a fully-mapped descriptor -- change nothing */ OldDescriptor.PageCount = 0; } else { /* This descriptor fully covers the entire allocation */ FoundBasePage = Descriptor->BasePage; VirtualPage = Descriptor->VirtualPage; FoundPageCount = BasePage - FoundBasePage; /* This is how many pages we will eat away from the descriptor */ RegionSize = FoundPageCount + PageCount; /* Update the descriptor to account for the consumed pages */ Descriptor->BasePage += RegionSize; Descriptor->PageCount -= RegionSize; if (VirtualPage) { Descriptor->VirtualPage += RegionSize; } /* Initialize a descriptor for the start of the region */ NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags, Descriptor->Type, FoundBasePage, VirtualPage, FoundPageCount); if (!NewDescriptor) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Add it into the list */ Status = MmMdAddDescriptorToList(MdList, NewDescriptor, Flags); if (!NT_SUCCESS(Status)) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Don't free it on exit path */ NewDescriptor = NULL; /* Adjust the leftover descriptor */ OldDescriptor.BasePage += FoundPageCount; OldDescriptor.PageCount = PageCount; if (OldDescriptor.VirtualPage) { OldDescriptor.VirtualPage += FoundPageCount; } } } else { /* This descriptor contains the entire allocation */ RegionSize = FoundEndPage - BasePage; Descriptor->PageCount -= RegionSize; /* Adjust the leftover descriptor */ OldDescriptor.BasePage += Descriptor->PageCount; OldDescriptor.PageCount = RegionSize; if (OldDescriptor.VirtualPage) { OldDescriptor.VirtualPage += FoundPageCount; } } /* Go to the next entry */ NextEntry = NextEntry->Flink; } else { /* * This descriptor contains the end of the allocation. It may: * * - Contain the full allocation (i.e.: the start is aligned) * - Contain parts of the end of the allocation (i.e.: the end is beyond) * - Contain the entire tail end of the allocation (i..e:the end is within) * * So first, figure out if we cover the entire end or not */ if (EndPage < FoundEndPage) { /* The allocation goes past the end of this descriptor */ FoundEndPage = EndPage; } /* This is how many pages we will eat away from the descriptor */ FoundPageCount = FoundEndPage - FoundBasePage; /* Update the descriptor to account for the consumed pages */ Descriptor->BasePage += FoundPageCount; Descriptor->PageCount -= FoundPageCount; if (Descriptor->VirtualPage) { Descriptor->VirtualPage += FoundPageCount; } /* Go to the next entry */ NextEntry = NextEntry->Flink; /* Check if the descriptor is now empty */ if (!Descriptor->PageCount) { /* Remove it */ MmMdRemoveDescriptorFromList(MdList, Descriptor); /* Check if we're supposed to insert it into a new list */ if (HaveNewList) { /* This is the one to add */ ListDescriptor = Descriptor; } else { /* Nope -- just get rid of it */ MmMdFreeDescriptor(Descriptor); } } } /* Is there a remainder descriptor, and do we have a list for it */ if ((OldDescriptor.PageCount) && (HaveNewList)) { /* Did we already chop off the descriptor? */ if (ListDescriptor) { /* Use what we previously chopped */ *ListDescriptor = OldDescriptor; } else { /* First time, so build a descriptor to describe the leftover */ ListDescriptor = MmMdInitByteGranularDescriptor(OldDescriptor.Flags, OldDescriptor.Type, OldDescriptor.BasePage, OldDescriptor.VirtualPage, OldDescriptor.PageCount); if (!ListDescriptor) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Add it into the list */ Status = MmMdAddDescriptorToList(NewMdList, ListDescriptor, 0); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Don't free on exit path */ ListDescriptor = NULL; } } } Quickie: /* Check for failure cleanup */ if (!NT_SUCCESS(Status)) { /* Did we have to build a new list? */ if (HaveNewList) { /* Free and re-initialize it */ MmMdFreeList(NewMdList); MmMdInitializeList(NewMdList, MdList->Type, NULL); } /* Check if we had a list descriptor, and free it */ if (ListDescriptor) { MmMdFreeDescriptor(ListDescriptor); } /* Check if we had a new descriptor, and free it */ if (NewDescriptor) { MmMdFreeDescriptor(NewDescriptor); } } /* All done */ return Status; } PBL_MEMORY_DESCRIPTOR MmMdFindDescriptorFromMdl ( _In_ PBL_MEMORY_DESCRIPTOR_LIST MdList, _In_ ULONG Flags, _In_ ULONGLONG Page ) { BOOLEAN IsVirtual; PLIST_ENTRY NextEntry, ListHead; PBL_MEMORY_DESCRIPTOR Current; ULONGLONG BasePage; /* Assume physical */ IsVirtual = FALSE; /* Check if the caller wants physical memory */ if (!(Flags & BL_MM_REMOVE_VIRTUAL_REGION_FLAG)) { /* Check if this is a virtual memory list */ if (MdList->Type == BlMdVirtual) { /* We won't find anything */ return NULL; } } else if (MdList->Type == BlMdPhysical) { /* Otherwise, caller wants virtual, but this is a physical list */ IsVirtual = TRUE; NextEntry = MdList->First->Flink; } /* Check if this is a physical search */ if (!IsVirtual) { /* Check if we can use the current pointer */ NextEntry = MdList->This; if (!NextEntry) { /* We can't -- start at the beginning */ NextEntry = MdList->First->Flink; } else { /* If the page is below the current pointer, restart */ Current = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); if (Page < Current->BasePage) { NextEntry = MdList->First->Flink; } } } /* Loop the list of descriptors */ ListHead = MdList->First; while (NextEntry != ListHead) { /* Get the current one */ Current = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry); /* Check if we are looking for virtual memory */ if (IsVirtual) { /* Use the base address */ BasePage = Current->VirtualPage; } else { /* Use the page */ BasePage = Current->BasePage; } /* If this is a virtual descriptor, make sure it has a base address */ if ((!(IsVirtual) || (BasePage)) && (BasePage <= Page) && (Page < (BasePage + Current->PageCount))) { /* The descriptor fits the page being requested */ return Current; } /* Try the next one */ NextEntry = NextEntry->Flink; } /* Nothing found if we're here */ return NULL; } PBL_MEMORY_DESCRIPTOR MmMdFindDescriptor ( _In_ ULONG WhichList, _In_ ULONG Flags, _In_ ULONGLONG Page ) { PBL_MEMORY_DESCRIPTOR FoundDescriptor; /* Check if the caller is looking for mapped, allocated memory */ if (WhichList & BL_MM_INCLUDE_MAPPED_ALLOCATED) { /* Find a descriptor in that list */ FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlMappedAllocated, Flags, Page); if (FoundDescriptor) { /* Got it */ return FoundDescriptor; } } /* Check if the caller is looking for mapped, unallocated memory */ if (WhichList & BL_MM_INCLUDE_MAPPED_UNALLOCATED) { /* Find a descriptor in that list */ FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlMappedUnallocated, Flags, Page); if (FoundDescriptor) { /* Got it */ return FoundDescriptor; } } /* Check if the caller is looking for unmapped, allocated memory */ if (WhichList & BL_MM_INCLUDE_UNMAPPED_ALLOCATED) { /* Find a descriptor in that list */ FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlUnmappedAllocated, Flags, Page); if (FoundDescriptor) { /* Got it */ return FoundDescriptor; } } /* Check if the caller is looking for unmapped, unallocated memory */ if (WhichList & BL_MM_INCLUDE_UNMAPPED_UNALLOCATED) { /* Find a descriptor in that list */ FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlUnmappedUnallocated, Flags, Page); if (FoundDescriptor) { /* Got it */ return FoundDescriptor; } } /* Check if the caller is looking for reserved, allocated memory */ if (WhichList & BL_MM_INCLUDE_RESERVED_ALLOCATED) { /* Find a descriptor in that list */ FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlReservedAllocated, Flags, Page); if (FoundDescriptor) { /* Got it */ return FoundDescriptor; } } /* Check if the caller is looking for bad memory */ if (WhichList & BL_MM_INCLUDE_BAD_MEMORY) { /* Find a descriptor in that list */ FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlBadMemory, Flags, Page); if (FoundDescriptor) { /* Got it */ return FoundDescriptor; } } /* Check if the caller is looking for truncated memory */ if (WhichList & BL_MM_INCLUDE_TRUNCATED_MEMORY) { /* Find a descriptor in that list */ FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlTruncatedMemory, Flags, Page); if (FoundDescriptor) { /* Got it */ return FoundDescriptor; } } /* Check if the caller is looking for persistent memory */ if (WhichList & BL_MM_INCLUDE_PERSISTENT_MEMORY) { /* Find a descriptor in that list */ FoundDescriptor = MmMdFindDescriptorFromMdl(&MmMdlPersistentMemory, Flags, Page); if (FoundDescriptor) { /* Got it */ return FoundDescriptor; } } /* Nothing if we got here */ return NULL; } BOOLEAN MmMdFindSatisfyingRegion ( _In_ PBL_MEMORY_DESCRIPTOR Descriptor, _Out_ PBL_MEMORY_DESCRIPTOR NewDescriptor, _In_ ULONGLONG Pages, _In_ PBL_ADDRESS_RANGE BaseRange, _In_ PBL_ADDRESS_RANGE VirtualRange, _In_ BOOLEAN TopDown, _In_ BL_MEMORY_TYPE MemoryType, _In_ ULONG Flags, _In_ ULONG Alignment ) { ULONGLONG BaseMin, BaseMax, AlignedMin; ULONGLONG VirtualPage, BasePage; ULONGLONG BaseDelta, AlignedBase; ULONGLONG VirtualMin, VirtualMax; /* Extract the minimum and maximum range */ BaseMin = BaseRange->Minimum; BaseMax = BaseRange->Maximum; /* Don't go below where the descriptor starts */ if (BaseMin < Descriptor->BasePage) { BaseMin = Descriptor->BasePage; } /* Don't go beyond where the descriptor ends */ if (BaseMax > (Descriptor->BasePage + Descriptor->PageCount - 1)) { BaseMax = (Descriptor->BasePage + Descriptor->PageCount - 1); } /* Check for start overflow */ if (BaseMin > BaseMax) { return FALSE; } /* Align the base as required */ if (Alignment != 1) { AlignedMin = ALIGN_UP_BY(BaseMin, Alignment); } else { AlignedMin = BaseMin; } /* Check for range overflow */ if (((AlignedMin + Pages - 1) < AlignedMin) || ((AlignedMin + Pages - 1) > BaseMax)) { return FALSE; } /* Check if this was a top-down request */ if (TopDown) { /* Then get the highest page possible */ BasePage = BaseMax - Pages + 1; if (Alignment != 1) { /* Align it as needed */ AlignedBase = ALIGN_DOWN_BY(BasePage, Alignment); } else { AlignedBase = BasePage; } /* Calculate the delta between max address and our aligned base */ BaseDelta = BasePage - AlignedBase; BasePage -= BaseDelta; } else { /* Otherwise, get the lowest page possible */ BasePage = AlignedMin; BaseDelta = 0; } /* If a virtual address range was passed in, this must be a virtual descriptor */ if (((VirtualRange->Minimum) || (VirtualRange->Maximum)) && !(Descriptor->VirtualPage)) { return FALSE; } /* Any mapped page already? */ if (Descriptor->VirtualPage) { /* Get virtual min/max */ VirtualMin = VirtualRange->Minimum; VirtualMax = VirtualRange->Maximum; /* Don't go below where the descriptor maps */ if (VirtualMin <= Descriptor->VirtualPage) { VirtualMin = Descriptor->VirtualPage; } /* Don't go above where the descriptor maps */ if (VirtualMax >= (Descriptor->VirtualPage + Descriptor->PageCount - 1)) { VirtualMax = Descriptor->VirtualPage + Descriptor->PageCount - 1; } /* Don't let the base overflow */ if (VirtualMin > VirtualMax) { return FALSE; } /* Adjust the base by the alignment delta */ VirtualMin += AlignedMin - BaseMin; /* Check that the bounds don't overflow or underflow */ if (((VirtualMin + Pages - 1) < VirtualMin) || ((VirtualMin + Pages - 1) > VirtualMax)) { return FALSE; } /* Finally, pick the correct address based on direction */ if (TopDown) { /* Highest possible base address, aligned */ VirtualPage = VirtualMax - Pages + 1 - BaseDelta; } else { /* Lowest possible base address, aligned */ VirtualPage = VirtualMin; } } else { /* Nothing to worry about */ VirtualPage = 0; } /* Bail out if the memory type attributes don't match */ if ((((Flags & 0xFF) & (Descriptor->Flags & 0xFF)) != (Flags & 0xFF)) || (((Flags & 0xFF00) & (Descriptor->Flags & 0xFF00)) != (Flags & 0xFF00))) { //EfiPrintf(L"Incorrect memory attributes\r\n"); return FALSE; } /* Bail out if the allocation flags don't match */ if (((Flags ^ Descriptor->Flags) & (BlMemoryRuntime | BlMemoryBelow1MB | BlMemoryLargePages))) { //EfiPrintf(L"Incorrect memory allocation flags\r\n"); return FALSE; } /* Bail out if the type doesn't match */ if (Descriptor->Type != MemoryType) { //EfiPrintf(L"Incorrect descriptor type: %lx %lx\r\n", Descriptor->Type, MemoryType); return FALSE; } /* We have a matching region, fill out the descriptor for it */ NewDescriptor->BasePage = BasePage; NewDescriptor->PageCount = Pages; NewDescriptor->Type = Descriptor->Type; NewDescriptor->VirtualPage = VirtualPage; NewDescriptor->Flags = Descriptor->Flags; //EfiPrintf(L"Found a matching descriptor: %08I64X with %08I64X pages\r\n", BasePage, Pages); return TRUE; } VOID MmMdFreeGlobalDescriptors ( VOID ) { PBL_MEMORY_DESCRIPTOR Descriptor, OldDescriptor; ULONG Index = 0; PLIST_ENTRY OldFlink, OldBlink; /* Make sure we're not int middle of a call using a descriptor */ if (MmDescriptorCallTreeCount != 1) { return; } /* Loop every current global descriptor */ while (Index < MmGlobalMemoryDescriptorsUsed) { /* Does it have any valid pages? */ OldDescriptor = &MmGlobalMemoryDescriptors[Index]; if (OldDescriptor->PageCount) { /* Allocate a copy of it */ Descriptor = BlMmAllocateHeap(sizeof(*Descriptor)); if (!Descriptor) { return; } /* Save the links */ OldBlink = OldDescriptor->ListEntry.Blink; OldFlink = OldDescriptor->ListEntry.Flink; /* Make the copy */ *Descriptor = *OldDescriptor; /* Fix the links */ OldBlink->Flink = &Descriptor->ListEntry; OldFlink->Blink = &Descriptor->ListEntry; /* Zero the descriptor */ RtlZeroMemory(OldDescriptor, sizeof(*OldDescriptor)); } /* Keep going */ Index++; } /* All global descriptors freed */ MmGlobalMemoryDescriptorsUsed = 0; } VOID MmMdInitialize ( _In_ ULONG Phase, _In_ PBL_LIBRARY_PARAMETERS LibraryParameters ) { /* Are we in phase 1? */ if (Phase != 0) { /* Switch to dynamic descriptors if we have too many */ if (LibraryParameters->DescriptorCount > RTL_NUMBER_OF(MmStaticMemoryDescriptors)) { MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount); } } else { /* In phase 0, start with a pool of 512 static descriptors */ MmGlobalMemoryDescriptorCount = RTL_NUMBER_OF(MmStaticMemoryDescriptors); MmGlobalMemoryDescriptors = MmStaticMemoryDescriptors; RtlZeroMemory(MmStaticMemoryDescriptors, sizeof(MmStaticMemoryDescriptors)); MmGlobalMemoryDescriptorsUsed = 0; } }