mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 21:13:52 +00:00
1406 lines
42 KiB
C
1406 lines
42 KiB
C
/*
|
|
* 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;
|
|
}
|
|
}
|