[BOOTMGFW]

- Implement most of the physical memory allocator. The heap manager now gets its page allocation fulfilled.

svn path=/trunk/; revision=69067
This commit is contained in:
Alex Ionescu 2015-09-06 19:22:37 +00:00
parent c8df1bac22
commit e21146906a
3 changed files with 587 additions and 1 deletions

View file

@ -61,8 +61,15 @@ EarlyPrint(_In_ PWCHAR Format, ...);
#define BL_MM_ADD_DESCRIPTOR_NEVER_TRUNCATE_FLAG 0x20
#define BL_MM_ADD_DESCRIPTOR_UPDATE_LIST_POINTER_FLAG 0x2000
#define BL_MM_DESCRIPTOR_REQUIRES_FIXED_FLAG 0x40000
#define BL_MM_DESCRIPTOR_REQUIRES_COALESCING_FLAG 0x2000000
#define BL_MM_DESCRIPTOR_REQUIRES_UPDATING_FLAG 0x4000000
#define BL_MM_DESCRIPTOR_NEVER_USE_FIRMWARE_FLAG 0x8000000
#define BL_MM_DESCRIPTOR_SPECIAL_PAGES_FLAG 0x20000000
#define BL_MM_DESCRIPTOR_CAME_FROM_FIRMWARE_FLAG 0x80000000
#define BL_MM_REQUEST_DEFAULT_TYPE 1
#define BL_MM_REQUEST_TOP_DOWN_TYPE 2
#define BL_MM_REMOVE_VIRTUAL_REGION_FLAG 0x80000000
@ -474,6 +481,15 @@ BlpMmInitialize (
_In_ PBL_LIBRARY_PARAMETERS LibraryParameters
);
/* FIRMWARE ROUTINES *********************************************************/
NTSTATUS
EfiAllocatePages (
_In_ ULONG Type,
_In_ ULONG Pages,
_Inout_ EFI_PHYSICAL_ADDRESS* Memory
);
/* UTILITY ROUTINES **********************************************************/
EFI_STATUS
@ -553,6 +569,11 @@ MmMdInitByteGranularDescriptor (
_In_ ULONGLONG PageCount
);
VOID
MmMdFreeGlobalDescriptors (
VOID
);
NTSTATUS
MmMdAddDescriptorToList (
_In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
@ -560,6 +581,25 @@ MmMdAddDescriptorToList (
_In_ ULONG Flags
);
VOID
MmMdRemoveDescriptorFromList (
_In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
_In_ PBL_MEMORY_DESCRIPTOR Entry
);
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
);
NTSTATUS
MmMdRemoveRegionFromMdlEx (
__in PBL_MEMORY_DESCRIPTOR_LIST MdList,
@ -569,6 +609,11 @@ MmMdRemoveRegionFromMdlEx (
__in PBL_MEMORY_DESCRIPTOR_LIST NewMdList
);
NTSTATUS
MmMdFreeDescriptor (
_In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor
);
NTSTATUS
MmPapAllocatePagesInRange (
_Inout_ PULONG PhysicalAddress,

View file

@ -646,6 +646,151 @@ Quickie:
return Status;
}
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;
ULONGLONG VirtualPage, BasePage;
/* 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)
{
EarlyPrint(L"Descriptor overflow\n");
return FALSE;
}
/* Align the base as required */
if (Alignment != 1)
{
BaseMin = ALIGN_UP_BY(BaseMin, Alignment);
}
/* Check for range overflow */
if (((BaseMin + Pages - 1) < BaseMin) || ((BaseMin + 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 */
BasePage = ALIGN_DOWN_BY(BasePage, Alignment);
}
}
else
{
/* Otherwise, get the lowest page possible */
BasePage = BaseMin;
}
/* 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)
{
EarlyPrint(L"Virtual memory not yet supported\n");
return FALSE;
}
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)))
{
EarlyPrint(L"Incorrect memory attributes\n");
return FALSE;
}
/* Bail out if the allocation flags don't match */
if (((Flags ^ Descriptor->Flags) & 0x190000))
{
EarlyPrint(L"Incorrect memory allocation flags\n");
return FALSE;
}
/* Bail out if the type doesn't match */
if (Descriptor->Type != MemoryType)
{
//EarlyPrint(L"Incorrect descriptor type\n");
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;
//EarlyPrint(L"Found a matching descriptor: %08I64X with %08I64X pages\n", BasePage, Pages);
return TRUE;
}
VOID
MmMdFreeGlobalDescriptors (
VOID
)
{
ULONG Index = 0;
/* 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)
{
EarlyPrint(L"Global descriptors not yet supported\n");
/* Keep going */
Index++;
}
/* All global descriptors freed */
MmGlobalMemoryDescriptorsUsed = 0;
}
VOID
MmMdInitialize (
_In_ ULONG Phase,

View file

@ -10,6 +10,18 @@
#include "bl.h"
typedef struct _BL_PA_REQUEST
{
BL_ADDRESS_RANGE BaseRange;
BL_ADDRESS_RANGE VirtualRange;
ULONG Type;
ULONGLONG Pages;
ULONG MemoryType;
ULONG Alignment;
ULONG Flags;
} BL_PA_REQUEST, *PBL_PA_REQUEST;
/* DATA VARIABLES ************************************************************/
ULONGLONG PapMaximumPhysicalPage, PapMinimumPhysicalPage;
@ -42,6 +54,341 @@ BlpMmInitializeConstraints (
return STATUS_SUCCESS;
}
NTSTATUS
MmPapAllocateRegionFromMdl (
_In_ PBL_MEMORY_DESCRIPTOR_LIST NewList,
_Out_opt_ PBL_MEMORY_DESCRIPTOR Descriptor,
_In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList,
_In_ PBL_PA_REQUEST Request,
_In_ BL_MEMORY_TYPE Type
)
{
NTSTATUS Status;
BL_MEMORY_DESCRIPTOR LocalDescriptor = {{0}};
PBL_MEMORY_DESCRIPTOR FoundDescriptor, TempDescriptor;
PLIST_ENTRY ListHead, NextEntry;
BOOLEAN TopDown, GotFwPages;
EFI_PHYSICAL_ADDRESS EfiAddress;
ULONGLONG LocalEndPage, FoundEndPage, LocalVirtualEndPage;
/* Check if any parameters were not passed in correctly */
if ( !(CurrentList) || !(Request) || (!(NewList) && !(Descriptor)))
{
return STATUS_INVALID_PARAMETER;
}
/* Set failure by default */
Status = STATUS_NO_MEMORY;
/* Take the head and next entry in the list, as appropriate */
ListHead = CurrentList->First;
if (Request->Type & BL_MM_REQUEST_TOP_DOWN_TYPE)
{
NextEntry = ListHead->Flink;
TopDown = FALSE;
}
else
{
NextEntry = ListHead->Blink;
TopDown = TRUE;
}
/* Loop through the list */
GotFwPages = FALSE;
while (NextEntry != ListHead)
{
/* Grab a descriptor */
FoundDescriptor = CONTAINING_RECORD(NextEntry,
BL_MEMORY_DESCRIPTOR,
ListEntry);
/* See if it matches the request */
if (MmMdFindSatisfyingRegion(FoundDescriptor,
&LocalDescriptor,
Request->Pages,
&Request->BaseRange,
&Request->VirtualRange,
TopDown,
Request->MemoryType,
Request->Flags,
Request->Alignment))
{
/* It does, get out */
break;
}
/* It doesn't, move to the next appropriate entry */
if (TopDown)
{
NextEntry = NextEntry->Blink;
}
else
{
NextEntry = NextEntry->Flink;
}
}
/* Check if we exhausted the list */
if (NextEntry == ListHead)
{
EarlyPrint(L"No matching memory found\n");
return Status;
}
/* Copy all the flags that are not request flag */
LocalDescriptor.Flags = (Request->Flags & 0xFFFF0000) |
(LocalDescriptor.Flags & 0x0000FFFF);
/* Are we using the physical memory list, and are we OK with using firmware? */
if ((CurrentList == &MmMdlUnmappedUnallocated) &&
!((Request->Flags & BL_MM_DESCRIPTOR_NEVER_USE_FIRMWARE_FLAG) ||
(LocalDescriptor.Flags & BL_MM_DESCRIPTOR_NEVER_USE_FIRMWARE_FLAG)))
{
/* Allocate the requested address from EFI */
EfiAddress = LocalDescriptor.BasePage << PAGE_SHIFT;
Status = EfiAllocatePages(AllocateAddress,
(ULONG)LocalDescriptor.PageCount,
&EfiAddress);
if (!NT_SUCCESS(Status))
{
EarlyPrint(L"EFI memory allocation failure\n");
return Status;
}
/* Remember we got memory from EFI */
GotFwPages = TRUE;
}
/* Remove the descriptor from the original list it was on */
MmMdRemoveDescriptorFromList(CurrentList, FoundDescriptor);
/* Are we allocating from the virtual memory list? */
if (CurrentList == &MmMdlMappedUnallocated)
{
EarlyPrint(L"Virtual memory not yet supported\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Does the memory we received not exactly fall onto the beginning of its descriptor? */
if (LocalDescriptor.BasePage != FoundDescriptor->BasePage)
{
EarlyPrint(L"Local Page: %08I64X Found Page: %08I64X\n", LocalDescriptor.BasePage, FoundDescriptor->BasePage);
TempDescriptor = MmMdInitByteGranularDescriptor(FoundDescriptor->Flags,
FoundDescriptor->Type,
FoundDescriptor->BasePage,
FoundDescriptor->VirtualPage,
LocalDescriptor.BasePage -
FoundDescriptor->BasePage);
Status = MmMdAddDescriptorToList(CurrentList, TempDescriptor, 0);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
/* Does the memory we received not exactly fall onto the end of its descriptor? */
LocalEndPage = LocalDescriptor.PageCount + LocalDescriptor.BasePage;
FoundEndPage = FoundDescriptor->PageCount + FoundDescriptor->BasePage;
LocalVirtualEndPage = LocalDescriptor.VirtualPage ?
LocalDescriptor.VirtualPage + LocalDescriptor.PageCount : 0;
if (LocalEndPage != FoundEndPage)
{
EarlyPrint(L"Local Page: %08I64X Found Page: %08I64X\n", LocalEndPage, FoundEndPage);
TempDescriptor = MmMdInitByteGranularDescriptor(FoundDescriptor->Flags,
FoundDescriptor->Type,
LocalEndPage,
LocalVirtualEndPage,
FoundEndPage - LocalEndPage);
Status = MmMdAddDescriptorToList(CurrentList, TempDescriptor, 0);
if (!NT_SUCCESS(Status))
{
return Status;
}
}
/* We got the memory we needed */
Status = STATUS_SUCCESS;
/* Are we supposed to insert it into a new list? */
if (NewList)
{
/* Copy the allocated region descriptor into the one we found */
FoundDescriptor->BaseAddress = LocalDescriptor.BaseAddress;
FoundDescriptor->VirtualPage = LocalDescriptor.VirtualPage;
FoundDescriptor->PageCount = LocalDescriptor.PageCount;
FoundDescriptor->Type = Type;
FoundDescriptor->Flags = LocalDescriptor.Flags;
/* Remember if it came from EFI */
if (GotFwPages)
{
FoundDescriptor->Flags |= BL_MM_DESCRIPTOR_CAME_FROM_FIRMWARE_FLAG;
}
/* Add the descriptor to the requested list */
Status = MmMdAddDescriptorToList(NewList, FoundDescriptor, 0);
}
else
{
/* Free the descriptor, nobody wants to know about it anymore */
MmMdFreeDescriptor(FoundDescriptor);
}
/* Return the allocation region back */
RtlCopyMemory(Descriptor, &LocalDescriptor, sizeof(LocalDescriptor));
return Status;
}
NTSTATUS
MmPaAllocatePages (
_In_ PBL_MEMORY_DESCRIPTOR_LIST NewList,
_In_ PBL_MEMORY_DESCRIPTOR Descriptor,
_In_ PBL_MEMORY_DESCRIPTOR_LIST CurrentList,
_In_ PBL_PA_REQUEST Request,
_In_ BL_MEMORY_TYPE MemoryType
)
{
NTSTATUS Status;
/* Heap and page directory/table pages have a special flag */
if ((MemoryType >= BlLoaderHeap) && (MemoryType <= BlLoaderReferencePage))
{
Request->Flags |= BL_MM_DESCRIPTOR_SPECIAL_PAGES_FLAG;
}
/* Try to find a free region of RAM matching this range and request */
Request->MemoryType = BlConventionalMemory;
Status = MmPapAllocateRegionFromMdl(NewList,
Descriptor,
CurrentList,
Request,
MemoryType);
if (Status == STATUS_NOT_FOUND)
{
/* Need to re-synchronize the memory map and check other lists */
EarlyPrint(L"No RAM found -- backup plan not yet implemented\n");
}
/* Did we get the region we wanted? */
if (NT_SUCCESS(Status))
{
/* All good, return back */
return Status;
}
/* Nope, we have to hunt for it elsewhere */
EarlyPrint(L"TODO\n");
return Status;
}
NTSTATUS
MmPapAllocatePhysicalPagesInRange (
_Inout_ PPHYSICAL_ADDRESS BaseAddress,
_In_ BL_MEMORY_TYPE MemoryType,
_In_ ULONGLONG Pages,
_In_ ULONG Attributes,
_In_ ULONG Alignment,
_In_ PBL_MEMORY_DESCRIPTOR_LIST NewList,
_In_opt_ PBL_ADDRESS_RANGE Range,
_In_ ULONG RangeType
)
{
NTSTATUS Status;
BL_PA_REQUEST Request;
BL_MEMORY_DESCRIPTOR Descriptor;
/* Increase nesting depth */
++MmDescriptorCallTreeCount;
/* Bail out if no address was specified */
if (!BaseAddress)
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Bail out if no page count was passed in, or a bad list was specified */
if (!(Pages) ||
((NewList != &MmMdlUnmappedAllocated) &&
(NewList != &MmMdlPersistentMemory)))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Bail out if the passed in range is invalid */
if ((Range) && (Range->Minimum >= Range->Maximum))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Adjust alignment as needed */
if (!Alignment)
{
Alignment = 1;
}
/* Clear the virtual range */
Request.VirtualRange.Minimum = 0;
Request.VirtualRange.Maximum = 0;
/* Check if a fixed allocation was requested*/
if (Attributes & BL_MM_DESCRIPTOR_REQUIRES_FIXED_FLAG)
{
/* Force the only available range to be the passed in address */
Request.BaseRange.Minimum = BaseAddress->QuadPart >> PAGE_SHIFT;
Request.BaseRange.Maximum = Request.BaseRange.Minimum + Pages - 1;
}
else if (Range)
{
/* Otherwise, a manual range was specified, use it */
Request.BaseRange.Minimum = Range->Minimum >> PAGE_SHIFT;
Request.BaseRange.Maximum = Request.BaseRange.Minimum +
(Range->Maximum >> PAGE_SHIFT) - 1;
}
else
{
/* Otherwise, use any possible range of pages */
Request.BaseRange.Minimum = PapMinimumPhysicalPage;
Request.BaseRange.Maximum = MAXULONG >> PAGE_SHIFT;
}
/* Check if no type was specified, or if it was invalid */
if (!(RangeType) ||
(RangeType & ~(BL_MM_REQUEST_TOP_DOWN_TYPE | BL_MM_REQUEST_DEFAULT_TYPE)))
{
/* Use default type */
Request.Type = BL_MM_REQUEST_DEFAULT_TYPE;
}
else
{
/* Use the requested type */
Request.Type = RangeType;
}
/* Capture the other request parameters */
Request.Alignment = Alignment;
Request.Pages = Pages;
Request.Flags = Attributes;
Status = MmPaAllocatePages(NewList,
&Descriptor,
&MmMdlUnmappedUnallocated,
&Request,
MemoryType);
if (NT_SUCCESS(Status))
{
/* We got a descriptor back, return its address */
BaseAddress->QuadPart = Descriptor.BasePage << PAGE_SHIFT;
}
Quickie:
/* Restore the nesting depth */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}
NTSTATUS
MmPapAllocatePagesInRange (
_Inout_ PULONG PhysicalAddress,
@ -53,7 +400,56 @@ MmPapAllocatePagesInRange (
_In_ ULONG Type
)
{
return STATUS_NOT_IMPLEMENTED;
NTSTATUS Status;
PHYSICAL_ADDRESS BaseAddress;
/* Increment nesting depth */
++MmDescriptorCallTreeCount;
/* Check for missing parameters or invalid range */
if (!(PhysicalAddress) ||
!(Pages) ||
((Range) && (Range->Minimum >= Range->Maximum)))
{
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
/* What translation mode are we using? */
if (MmTranslationType != BlNone)
{
/* We don't support virtual memory yet */
Status = STATUS_NOT_IMPLEMENTED;
goto Exit;
}
else
{
/* Check if this is a fixed allocation */
BaseAddress.QuadPart = (Attributes & BL_MM_DESCRIPTOR_REQUIRES_FIXED_FLAG) ?
*PhysicalAddress : 0;
/* Allocate the pages */
Status = MmPapAllocatePhysicalPagesInRange(&BaseAddress,
MemoryType,
Pages,
Attributes,
Alignment,
(&MmMdlMappedAllocated !=
&MmMdlPersistentMemory) ?
&MmMdlUnmappedAllocated :
&MmMdlMappedAllocated,
Range,
Type);
/* Return the allocated address */
*PhysicalAddress = BaseAddress.LowPart;
}
Exit:
/* Restore the nesting depth */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}
NTSTATUS