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,
#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;
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,
_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