Started BlpMmDestroy(), MmMdDestroy(), MmPaDestroy(), EfiSetWatchdogTimer(), EfiOpenProtocol(), EfiConInExSetState(), and BlDestroyLibrary(). Completed BlpFwInitialize(). Improved InitializeLibrary().
960 lines
23 KiB
C
960 lines
23 KiB
C
/*++
|
|
|
|
Copyright (c) 2024, Quinn Stephens.
|
|
Provided under the BSD 3-Clause license.
|
|
|
|
Module Name:
|
|
|
|
mmmd.c
|
|
|
|
Abstract:
|
|
|
|
Provides memory descriptor routines.
|
|
|
|
--*/
|
|
|
|
#include <ntrtl.h>
|
|
#include "bootlib.h"
|
|
#include "mm.h"
|
|
|
|
#define MAX_STATIC_DESCRIPTOR_COUNT 1024
|
|
|
|
MEMORY_DESCRIPTOR MmStaticMemoryDescriptors[MAX_STATIC_DESCRIPTOR_COUNT];
|
|
|
|
PMEMORY_DESCRIPTOR MmGlobalMemoryDescriptors;
|
|
ULONG MmGlobalMemoryDescriptorCount, MmGlobalMemoryDescriptorsUsed;
|
|
|
|
PMEMORY_DESCRIPTOR MmDynamicMemoryDescriptors;
|
|
ULONG MmDynamicMemoryDescriptorCount, MmDynamicMemoryDescriptorsUsed;
|
|
|
|
#define MAX_PRECEDENCE_INDEX sizeof(MmPlatformMemoryTypePrecedence) / sizeof(MmPlatformMemoryTypePrecedence[0])
|
|
|
|
MEMORY_TYPE MmPlatformMemoryTypePrecedence[] = {
|
|
MEMORY_TYPE_RESERVED,
|
|
MEMORY_TYPE_UNUSABLE,
|
|
MEMORY_TYPE_MMIO,
|
|
MEMORY_TYPE_MMIO_PORT_SPACE,
|
|
MEMORY_TYPE_PAL_CODE,
|
|
MEMORY_TYPE_RUNTIME_SERVICES_CODE,
|
|
MEMORY_TYPE_RUNTIME_SERVICES_DATA,
|
|
MEMORY_TYPE_ACPI_NVS,
|
|
MEMORY_TYPE_ACPI_RECLAIM,
|
|
MEMORY_TYPE_PERSISTENT,
|
|
MEMORY_TYPE_BOOT_APPLICATION_2,
|
|
MEMORY_TYPE_BOOT_SERVICES,
|
|
MEMORY_TYPE_FREE,
|
|
MEMORY_TYPE_FREE_ZEROED
|
|
};
|
|
|
|
ULONG
|
|
GetPrecedenceIndex (
|
|
IN MEMORY_TYPE Type
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds the index into MmPlatformMemoryTypePrecedence for Type.
|
|
|
|
Arguments:
|
|
|
|
Type - The memory type.
|
|
|
|
Return Value:
|
|
|
|
The precedence index if found.
|
|
MAX_PRECEDENCE_INDEX if not found.
|
|
|
|
--*/
|
|
|
|
{
|
|
for (ULONG Index = 0;
|
|
Index < MAX_PRECEDENCE_INDEX;
|
|
Index++) {
|
|
if (MmPlatformMemoryTypePrecedence[Index] == Type) {
|
|
return Index;
|
|
}
|
|
}
|
|
|
|
return MAX_PRECEDENCE_INDEX;
|
|
}
|
|
|
|
BOOLEAN
|
|
MmMdpHasPrecedence (
|
|
IN MEMORY_TYPE TypeA,
|
|
IN MEMORY_TYPE TypeB
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compares two memory types to determine which has precedence.
|
|
|
|
Arguments:
|
|
|
|
TypeA - Memory type A.
|
|
|
|
TypeB - Memory type B.
|
|
|
|
Return Value:
|
|
|
|
TRUE if TypeA has precedence over TypeB, or if neither has precedence.
|
|
FALSE if TypeB has precedence over TypeA.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ClassA, ClassB;
|
|
ULONG PrecedenceIndexA, PrecedenceIndexB;
|
|
|
|
if (TypeB == MEMORY_TYPE_FREE_ZEROED) {
|
|
return TRUE;
|
|
} else if (TypeA == MEMORY_TYPE_FREE_ZEROED) {
|
|
return FALSE;
|
|
} else if (TypeB == MEMORY_TYPE_FREE) {
|
|
return TRUE;
|
|
} else if (TypeA == MEMORY_TYPE_FREE) {
|
|
return FALSE;
|
|
}
|
|
|
|
ClassA = TypeA >> 28;
|
|
ClassB = TypeB >> 28;
|
|
if (ClassA != MEMORY_CLASS_APPLICATION
|
|
&& ClassA != MEMORY_CLASS_LIBRARY
|
|
&& ClassA != MEMORY_CLASS_SYSTEM) {
|
|
return TRUE;
|
|
} else if (ClassB != MEMORY_CLASS_APPLICATION
|
|
&& ClassB != MEMORY_CLASS_LIBRARY
|
|
&& ClassB != MEMORY_CLASS_SYSTEM) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (ClassA != MEMORY_CLASS_SYSTEM) {
|
|
return (ClassB != MEMORY_CLASS_SYSTEM
|
|
&& (ClassA == MEMORY_CLASS_APPLICATION
|
|
|| ClassB != MEMORY_CLASS_APPLICATION)) ? TRUE:FALSE;
|
|
} else if (ClassB != MEMORY_CLASS_SYSTEM) {
|
|
return TRUE;
|
|
}
|
|
|
|
PrecedenceIndexA = GetPrecedenceIndex(TypeA);
|
|
if (PrecedenceIndexA == MAX_PRECEDENCE_INDEX) {
|
|
return TRUE;
|
|
}
|
|
|
|
PrecedenceIndexB = GetPrecedenceIndex(TypeB);
|
|
if (PrecedenceIndexB == MAX_PRECEDENCE_INDEX) {
|
|
return FALSE;
|
|
}
|
|
|
|
return PrecedenceIndexA <= PrecedenceIndexB ? TRUE:FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
MmMdpTruncateDescriptor (
|
|
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
|
IN PMEMORY_DESCRIPTOR Descriptor,
|
|
IN ULONG Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Trunactes a memory descriptor that overlaps
|
|
with adjacent descriptors.
|
|
|
|
Arguments:
|
|
|
|
Mdl - The MDL containing Descriptor.
|
|
|
|
Descriptor - The descriptor to truncate.
|
|
|
|
Return Value:
|
|
|
|
TRUE if Descriptor was deleted from Mdl.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PMEMORY_DESCRIPTOR PrevDescriptor, NextDescriptor, NewDescriptor;
|
|
ULONGLONG DescriptorEnd, PrevDescriptorEnd, NextDescriptorEnd;
|
|
ULONGLONG MappedFirstPage;
|
|
ULONGLONG Change;
|
|
|
|
PrevDescriptor = (PMEMORY_DESCRIPTOR)Descriptor->ListEntry.Blink;
|
|
NextDescriptor = (PMEMORY_DESCRIPTOR)Descriptor->ListEntry.Flink;
|
|
|
|
DescriptorEnd = Descriptor->FirstPage + Descriptor->PageCount;
|
|
PrevDescriptorEnd = PrevDescriptor->FirstPage + PrevDescriptor->PageCount;
|
|
NextDescriptorEnd = NextDescriptor->FirstPage + NextDescriptor->PageCount;
|
|
|
|
//
|
|
// Check if overlapping with previous descriptor.
|
|
//
|
|
if (Descriptor->ListEntry.Blink != Mdl->Head && Descriptor->FirstPage < PrevDescriptorEnd) {
|
|
if (MmMdpHasPrecedence(Descriptor->Type, PrevDescriptor->Type)) {
|
|
PrevDescriptor->PageCount = Descriptor->FirstPage - PrevDescriptor->FirstPage;
|
|
|
|
if (DescriptorEnd < PrevDescriptorEnd) {
|
|
if (PrevDescriptor->MappedFirstPage) {
|
|
MappedFirstPage = PrevDescriptor->MappedFirstPage + DescriptorEnd - PrevDescriptor->FirstPage;
|
|
} else {
|
|
MappedFirstPage = 0;
|
|
}
|
|
|
|
NewDescriptor = MmMdInitDescriptor(
|
|
DescriptorEnd,
|
|
MappedFirstPage,
|
|
PrevDescriptorEnd - DescriptorEnd,
|
|
PrevDescriptor->Attributes,
|
|
PrevDescriptor->Type
|
|
);
|
|
if (NewDescriptor != NULL) {
|
|
Status = MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags);
|
|
if (!NT_SUCCESS(Status)) {
|
|
MmMdFreeDescriptor(NewDescriptor);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete and free the previous
|
|
// descriptor if it is now empty.
|
|
//
|
|
if (PrevDescriptor->PageCount == 0) {
|
|
MmMdRemoveDescriptorFromList(Mdl, PrevDescriptor);
|
|
MmMdFreeDescriptor(PrevDescriptor);
|
|
}
|
|
} else {
|
|
//
|
|
// Remove if completely overlapping.
|
|
//
|
|
if (DescriptorEnd <= PrevDescriptorEnd) {
|
|
MmMdRemoveDescriptorFromList(Mdl, Descriptor);
|
|
MmMdFreeDescriptor(Descriptor);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Otherwise, move the descriptor.
|
|
//
|
|
Change = PrevDescriptorEnd - Descriptor->FirstPage;
|
|
Descriptor->FirstPage += Change;
|
|
Descriptor->PageCount -= Change;
|
|
if (Descriptor->MappedFirstPage) {
|
|
Descriptor->MappedFirstPage += Change;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if overlapping with next descriptor.
|
|
//
|
|
if (Descriptor->ListEntry.Flink != Mdl->Head && NextDescriptor->FirstPage < DescriptorEnd) {
|
|
if (MmMdpHasPrecedence(NextDescriptor->Type, Descriptor->Type)) {
|
|
Descriptor->PageCount = NextDescriptor->FirstPage - Descriptor->FirstPage;
|
|
|
|
if (NextDescriptorEnd < DescriptorEnd) {
|
|
if (Descriptor->MappedFirstPage) {
|
|
MappedFirstPage = Descriptor->MappedFirstPage + NextDescriptorEnd - Descriptor->FirstPage;
|
|
} else {
|
|
MappedFirstPage = 0;
|
|
}
|
|
|
|
NewDescriptor = MmMdInitDescriptor(
|
|
NextDescriptorEnd,
|
|
MappedFirstPage,
|
|
DescriptorEnd - NextDescriptorEnd,
|
|
Descriptor->Attributes,
|
|
Descriptor->Type
|
|
);
|
|
if (NewDescriptor != NULL) {
|
|
Status = MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags);
|
|
if (!NT_SUCCESS(Status)) {
|
|
MmMdFreeDescriptor(NewDescriptor);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete and free the previous
|
|
// descriptor if it is now empty.
|
|
//
|
|
if (Descriptor->PageCount == 0) {
|
|
MmMdRemoveDescriptorFromList(Mdl, Descriptor);
|
|
MmMdFreeDescriptor(Descriptor);
|
|
}
|
|
} else {
|
|
//
|
|
// Remove if completely overlapping.
|
|
//
|
|
if (NextDescriptorEnd <= DescriptorEnd) {
|
|
MmMdRemoveDescriptorFromList(Mdl, NextDescriptor);
|
|
MmMdFreeDescriptor(NextDescriptor);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Otherwise, move the next descriptor.
|
|
//
|
|
Change = DescriptorEnd - NextDescriptor->FirstPage;
|
|
NextDescriptor->FirstPage += Change;
|
|
NextDescriptor->PageCount -= Change;
|
|
if (NextDescriptor->MappedFirstPage) {
|
|
NextDescriptor->MappedFirstPage += Change;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
MmMdAddDescriptorToList (
|
|
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
|
IN PMEMORY_DESCRIPTOR Descriptor,
|
|
IN ULONG Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a descriptor to a MDL.
|
|
|
|
Arguments:
|
|
|
|
Mdl - the MDL to add Descriptor to.
|
|
|
|
Descriptor - the descriptor to add to Mdl.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_INVALID_PARAMETER if Mdl or Descriptor are invalid.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PMEMORY_DESCRIPTOR CurrentDescriptor;
|
|
|
|
if (Mdl == NULL || Descriptor == NULL) {
|
|
DebugPrint(L"MmMdAddDescriptorToList(): Mdl and/or Descriptor are NULL\r\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Mdl->Current) {
|
|
if (Descriptor->FirstPage < ((PMEMORY_DESCRIPTOR)Mdl->Current)->FirstPage) {
|
|
Entry = Mdl->Head->Flink;
|
|
} else {
|
|
Entry = Mdl->Current;
|
|
}
|
|
} else {
|
|
Entry = Mdl->Head->Flink;
|
|
}
|
|
|
|
//
|
|
// Search for an existing descriptor for this region.
|
|
//
|
|
while (Entry != Mdl->Head) {
|
|
CurrentDescriptor = (PMEMORY_DESCRIPTOR)Entry;
|
|
|
|
if (
|
|
Descriptor->FirstPage >= CurrentDescriptor->FirstPage && (Descriptor->FirstPage != CurrentDescriptor->FirstPage
|
|
|| !MmMdpHasPrecedence(Descriptor->Type, CurrentDescriptor->Type))
|
|
) {
|
|
Entry = Entry->Flink;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Insert descriptor into the list
|
|
// right before the current entry.
|
|
//
|
|
Descriptor->ListEntry.Blink = Entry->Blink;
|
|
Descriptor->ListEntry.Flink = Entry;
|
|
Entry->Blink->Flink = &Descriptor->ListEntry;
|
|
Entry->Blink = &Descriptor->ListEntry;
|
|
|
|
//
|
|
// Truncate overlapping descriptors
|
|
// into one larger descriptor.
|
|
//
|
|
if (Flags & MDL_OPERATION_FLAGS_TRUNCATE) {
|
|
MmMdpTruncateDescriptor(Mdl, Descriptor, Flags);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If there are no existing descriptors for this region
|
|
// (or the list is empty), insert and truncate the descriptor.
|
|
//
|
|
InsertTailList(Mdl->Head, &Descriptor->ListEntry);
|
|
if (Flags & MDL_OPERATION_FLAGS_TRUNCATE) {
|
|
MmMdpTruncateDescriptor(Mdl, Descriptor, Flags);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
MmMdRemoveDescriptorFromList (
|
|
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
|
IN PMEMORY_DESCRIPTOR Descriptor
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a descriptor from a MDL.
|
|
|
|
Arguments:
|
|
|
|
Mdl - MDL to remove Descriptor from.
|
|
|
|
Descriptor - Descriptor to remove from Mdl.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY Blink;
|
|
|
|
Blink = Descriptor->ListEntry.Blink;
|
|
RemoveEntryList(&Descriptor->ListEntry);
|
|
|
|
//
|
|
// Check if the removed descriptor was cached.
|
|
//
|
|
if (Mdl->Current != &Descriptor->ListEntry) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Cache the previous descriptor if possible.
|
|
//
|
|
if (
|
|
(
|
|
(ULONG_PTR)Blink < (ULONG_PTR)MmGlobalMemoryDescriptors
|
|
|| (ULONG_PTR)Blink >= (ULONG_PTR)&MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorCount]
|
|
)
|
|
&& Blink != Mdl->Head
|
|
) {
|
|
Mdl->Current = Blink;
|
|
} else {
|
|
Mdl->Current = NULL;
|
|
}
|
|
}
|
|
|
|
PMEMORY_DESCRIPTOR
|
|
MmMdFindDescriptorFromMdl (
|
|
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
|
IN ULONGLONG Page,
|
|
IN ULONG Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches an MDL for the descriptor containing a page.
|
|
|
|
Arguments:
|
|
|
|
Mdl - The MDL to search.
|
|
|
|
Page - The page to search for.
|
|
|
|
Flags - MDL_OPERATION_FLAGS_*
|
|
MDL_OPERATION_FLAGS_PHYSICAL if Page is physical.
|
|
MDL_OPERATION_FLAGS_VIRTUAL if Page is virtual.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the descriptor if successful.
|
|
NULL if an error occurs.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
BOOLEAN Mapped;
|
|
PMEMORY_DESCRIPTOR Descriptor;
|
|
PLIST_ENTRY ListEntry;
|
|
ULONGLONG FirstPage;
|
|
|
|
Mapped = FALSE;
|
|
if (Flags & MDL_OPERATION_FLAGS_VIRTUAL) {
|
|
if (Mdl->Type == MDL_TYPE_PHYSICAL) {
|
|
Mapped = TRUE;
|
|
}
|
|
} else {
|
|
//
|
|
// If the MDL is virtual, the
|
|
// virtual flag must be set.
|
|
//
|
|
if (Mdl->Type == MDL_TYPE_VIRTUAL) {
|
|
DebugPrint(L"MmMdFindDescriptorFromMdl(): Flags is invalid\r\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if the cached descriptor is in range.
|
|
//
|
|
if (!Mapped && Mdl->Current != NULL) {
|
|
Descriptor = (PMEMORY_DESCRIPTOR)Mdl->Current;
|
|
if (Page < Descriptor->FirstPage) {
|
|
ListEntry = Mdl->Head->Flink;
|
|
} else {
|
|
ListEntry = Mdl->Current;
|
|
}
|
|
} else {
|
|
ListEntry = Mdl->Head->Flink;
|
|
}
|
|
|
|
while (ListEntry != Mdl->Head) {
|
|
Descriptor = (PMEMORY_DESCRIPTOR)ListEntry;
|
|
|
|
if (Mapped) {
|
|
FirstPage = Descriptor->MappedFirstPage;
|
|
} else {
|
|
FirstPage = Descriptor->FirstPage;
|
|
}
|
|
|
|
//
|
|
// Check if this descriptor contains Page.
|
|
//
|
|
if ((!Mapped || FirstPage)
|
|
&& Page >= FirstPage
|
|
&& Page < FirstPage + Descriptor->PageCount) {
|
|
return Descriptor;
|
|
}
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NTSTATUS
|
|
MmMdRemoveRegionFromMdlEx (
|
|
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
|
IN ULONGLONG RemoveStart,
|
|
IN ULONGLONG PageCount,
|
|
IN ULONG Flags,
|
|
OUT PMEMORY_DESCRIPTOR_LIST Unused
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a region from a MDL.
|
|
|
|
Arguments:
|
|
|
|
Mdl - MDL to remove the region from.
|
|
|
|
RemoveStart - The first page in the region.
|
|
|
|
PageCount - The number of pages in the region.
|
|
|
|
Flags - MDL_OPERATION_FLAGS_*.
|
|
MDL_OPERATION_FLAGS_PHYSICAL if the region is physical.
|
|
MDL_OPERATION_FLAGS_VIRTUAL if the region is virtual.
|
|
|
|
Unused - Unused.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful,
|
|
STATUS_INVALID_PARAMETER if Flags value is invalid.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG Offset;
|
|
BOOLEAN Mapped;
|
|
ULONGLONG RemoveEnd;
|
|
PLIST_ENTRY ListEntry;
|
|
ULONGLONG DescriptorStart, DescriptorEnd;
|
|
PMEMORY_DESCRIPTOR Descriptor, NewDescriptor;
|
|
|
|
(VOID)Unused;
|
|
|
|
Mapped = FALSE;
|
|
if (Flags & MDL_OPERATION_FLAGS_VIRTUAL) {
|
|
if (Mdl->Type == MDL_TYPE_PHYSICAL) {
|
|
Mapped = TRUE;
|
|
}
|
|
} else {
|
|
//
|
|
// If the MDL is virtual, the
|
|
// virtual flag must be set.
|
|
//
|
|
if (Mdl->Type == MDL_TYPE_VIRTUAL) {
|
|
DebugPrint(L"MmMdRemoveRegionFromMdlEx(): Flags is invalid\r\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
RemoveEnd = RemoveStart + PageCount;
|
|
ListEntry = Mdl->Head->Flink;
|
|
while (ListEntry != Mdl->Head) {
|
|
Descriptor = (PMEMORY_DESCRIPTOR)ListEntry;
|
|
|
|
if (Mapped) {
|
|
DescriptorStart = Descriptor->MappedFirstPage;
|
|
} else {
|
|
DescriptorStart = Descriptor->FirstPage;
|
|
}
|
|
DescriptorEnd = DescriptorStart + Descriptor->PageCount;
|
|
|
|
//
|
|
// Check if the region to be removed
|
|
// is inside the current descriptor.
|
|
//
|
|
if (RemoveStart <= DescriptorStart && RemoveEnd > DescriptorStart) {
|
|
//
|
|
// The region is around the start of the descriptor, or
|
|
// they have identical locations and sizes.
|
|
// | RemoveStart | DescriptorStart | RemoveEnd | DescriptorEnd |
|
|
// | Lower address ............................ Higher address |
|
|
//
|
|
|
|
if (RemoveEnd < DescriptorEnd) {
|
|
Offset = RemoveEnd - DescriptorStart;
|
|
} else {
|
|
Offset = DescriptorEnd - DescriptorStart;
|
|
}
|
|
|
|
//
|
|
// Shrink the descriptor.
|
|
//
|
|
Descriptor->FirstPage += Offset;
|
|
Descriptor->PageCount -= Offset;
|
|
if (Descriptor->MappedFirstPage) {
|
|
Descriptor->MappedFirstPage += Offset;
|
|
}
|
|
|
|
//
|
|
// Remove descriptor if now empty.
|
|
//
|
|
if (Descriptor->PageCount == 0) {
|
|
MmMdRemoveDescriptorFromList(Mdl, Descriptor);
|
|
MmMdFreeDescriptor(Descriptor);
|
|
}
|
|
} else if (RemoveStart < DescriptorEnd && RemoveEnd >= DescriptorEnd) {
|
|
//
|
|
// The region is around the end of the descriptor.
|
|
// | DescriptorStart | RemoveStart | DescriptorEnd | RemoveEnd |
|
|
// | Lower address ............................ Higher address |
|
|
//
|
|
|
|
//
|
|
// Simply shrink the descriptor.
|
|
//
|
|
Descriptor->PageCount -= DescriptorEnd - RemoveStart;
|
|
} else if (RemoveStart > DescriptorStart && RemoveEnd < DescriptorEnd) {
|
|
//
|
|
// The region is completely inside the descriptor.
|
|
// In this case, the descriptor must be split in two.
|
|
// | DescriptorStart | RemoveStart | RemoveEnd | DescriptorEnd |
|
|
// | Lower address ............................ Higher address |
|
|
//
|
|
|
|
//
|
|
// Create a new descriptor before the removed region.
|
|
//
|
|
NewDescriptor = MmMdInitDescriptor(
|
|
Descriptor->FirstPage,
|
|
Descriptor->MappedFirstPage,
|
|
RemoveStart - DescriptorStart,
|
|
Descriptor->Attributes,
|
|
Descriptor->Type
|
|
);
|
|
|
|
//
|
|
// Shrink and move the current descriptor.
|
|
//
|
|
Offset = NewDescriptor->PageCount + PageCount;
|
|
Descriptor->FirstPage += Offset;
|
|
Descriptor->PageCount -= Offset;
|
|
if (Descriptor->MappedFirstPage) {
|
|
Descriptor->MappedFirstPage += Offset;
|
|
}
|
|
|
|
//
|
|
// Now check if MmMdInitDescriptor() actually worked.
|
|
//
|
|
if (NewDescriptor == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
Status = MmMdAddDescriptorToList(Mdl, NewDescriptor, Flags);
|
|
if (!NT_SUCCESS(Status)) {
|
|
MmMdFreeDescriptor(NewDescriptor);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MmMdRemoveRegionFromMdl (
|
|
IN PMEMORY_DESCRIPTOR_LIST Mdl,
|
|
IN ULONGLONG RemoveStart,
|
|
IN ULONGLONG PageCount,
|
|
IN ULONG Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a region from a MDL.
|
|
Wrapper around MmMdRemoveRegionFromMdlEx().
|
|
|
|
Arguments:
|
|
|
|
Same as MmMdRemoveRegionFromMdlEx(), except for Unused.
|
|
|
|
Return Value:
|
|
|
|
Any status code returned by MmMdRemoveRegionFromMdlEx().
|
|
|
|
--*/
|
|
|
|
{
|
|
return MmMdRemoveRegionFromMdlEx(
|
|
Mdl,
|
|
RemoveStart,
|
|
PageCount,
|
|
Flags,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
MmMdFreeDescriptor (
|
|
IN PMEMORY_DESCRIPTOR Descriptor
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees a memory descriptor.
|
|
|
|
Arguments:
|
|
|
|
Descriptor - the descriptor to free.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful,
|
|
other NTSTATUS value if an error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (
|
|
(
|
|
MmDynamicMemoryDescriptors != NULL
|
|
&& (ULONG_PTR)Descriptor >= (ULONG_PTR)MmDynamicMemoryDescriptors
|
|
&& (ULONG_PTR)Descriptor <= (ULONG_PTR)&MmDynamicMemoryDescriptors[MmDynamicMemoryDescriptorCount]
|
|
)
|
|
|| (
|
|
(ULONG_PTR)Descriptor >= (ULONG_PTR)MmStaticMemoryDescriptors
|
|
&& (ULONG_PTR)Descriptor <= (ULONG_PTR)&MmStaticMemoryDescriptors[MAX_STATIC_DESCRIPTOR_COUNT]
|
|
)
|
|
) {
|
|
//
|
|
// Clear the descriptor from static/dynamic MDL.
|
|
//
|
|
RtlZeroMemory(Descriptor, sizeof(MEMORY_DESCRIPTOR));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// TODO: Free the descriptor from the heap.
|
|
// Need BlMmFreeHeap().
|
|
//
|
|
DebugPrint(L"MmMdFreeDescriptor(): Heap not available\r\n");
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
// return BlMmFreeHeap(Descriptor);
|
|
}
|
|
|
|
VOID
|
|
MmMdFreeList (
|
|
IN PMEMORY_DESCRIPTOR_LIST Mdl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees a memory descriptor list (MDL).
|
|
|
|
Arguments:
|
|
|
|
Mdl - the MDL.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
|
|
Entry = Mdl->Head->Flink;
|
|
while (Entry != Mdl->Head) {
|
|
MmMdRemoveDescriptorFromList(Mdl, (PMEMORY_DESCRIPTOR)Entry);
|
|
MmMdFreeDescriptor((PMEMORY_DESCRIPTOR)Entry);
|
|
Entry = Entry->Flink;
|
|
}
|
|
}
|
|
|
|
PMEMORY_DESCRIPTOR
|
|
MmMdInitDescriptor (
|
|
IN ULONGLONG FirstPage,
|
|
IN ULONGLONG MappedFirstPage,
|
|
IN ULONGLONG PageCount,
|
|
IN ULONG Attributes,
|
|
IN MEMORY_TYPE Type
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes a memory descriptor.
|
|
|
|
Arguments:
|
|
|
|
FirstPage - The first page in the region.
|
|
|
|
MappedFirstPage - The first page in the mapping.
|
|
|
|
Attributes - Memory attributes of the region.
|
|
|
|
Type - Memory type of the region.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the memory descriptor,
|
|
NULL if an error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMEMORY_DESCRIPTOR Descriptor;
|
|
|
|
if (MmGlobalMemoryDescriptorsUsed >= MmGlobalMemoryDescriptorCount) {
|
|
DebugPrint(L"MmMdInitDescriptor(): No free descriptors available\r\n");
|
|
return NULL;
|
|
}
|
|
|
|
Descriptor = &MmGlobalMemoryDescriptors[MmGlobalMemoryDescriptorsUsed++];
|
|
Descriptor->FirstPage = FirstPage;
|
|
Descriptor->MappedFirstPage = MappedFirstPage;
|
|
Descriptor->PageCount = PageCount;
|
|
Descriptor->Attributes = Attributes;
|
|
Descriptor->Type = Type;
|
|
InitializeListHead(&Descriptor->ListEntry);
|
|
|
|
return Descriptor;
|
|
}
|
|
|
|
NTSTATUS
|
|
MmMdDestroy (
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleans up after any actions performed by the memory descriptor manager.
|
|
After calling this, the memory descriptor manager can no longer be used.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// TODO: Implement this routine.
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
MmMdInitialize (
|
|
IN ULONG Stage,
|
|
IN PBOOT_LIBRARY_PARAMETERS LibraryParameters
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the memory descriptor manager.
|
|
|
|
Arguments:
|
|
|
|
Stage - Which stage of initialization to perform.
|
|
|
|
Stage 0: Initializes the static memory descriptor pool.
|
|
|
|
LibraryParameters - Pointer to the library parameters structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
(VOID)LibraryParameters;
|
|
|
|
if (Stage == 0) {
|
|
//
|
|
// Initialize static memory descriptor pool.
|
|
//
|
|
MmGlobalMemoryDescriptors = &MmStaticMemoryDescriptors[0];
|
|
MmGlobalMemoryDescriptorCount = MAX_STATIC_DESCRIPTOR_COUNT;
|
|
MmGlobalMemoryDescriptorsUsed = 0;
|
|
RtlZeroMemory(MmGlobalMemoryDescriptors, MAX_STATIC_DESCRIPTOR_COUNT * sizeof(MEMORY_DESCRIPTOR));
|
|
}
|
|
|
|
//
|
|
// TODO: Implement stage 1 initialization.
|
|
//
|
|
}
|