Author: ion
Date: Sun Sep 6 19:22:37 2015
New Revision: 69067
URL:
http://svn.reactos.org/svn/reactos?rev=69067&view=rev
Log:
[BOOTMGFW]
- Implement most of the physical memory allocator. The heap manager now gets its page
allocation fulfilled.
Modified:
trunk/reactos/boot/environ/include/bl.h
trunk/reactos/boot/environ/lib/mm/descriptor.c
trunk/reactos/boot/environ/lib/mm/pagealloc.c
Modified: trunk/reactos/boot/environ/include/bl.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/include/bl.h?…
==============================================================================
--- trunk/reactos/boot/environ/include/bl.h [iso-8859-1] (original)
+++ trunk/reactos/boot/environ/include/bl.h [iso-8859-1] Sun Sep 6 19:22:37 2015
@@ -61,8 +61,15 @@
#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 @@
_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,11 +569,35 @@
_In_ ULONGLONG PageCount
);
+VOID
+MmMdFreeGlobalDescriptors (
+ VOID
+ );
+
NTSTATUS
MmMdAddDescriptorToList (
_In_ PBL_MEMORY_DESCRIPTOR_LIST MdList,
_In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor,
_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
@@ -567,6 +607,11 @@
__in ULONGLONG BasePage,
__in ULONGLONG PageCount,
__in PBL_MEMORY_DESCRIPTOR_LIST NewMdList
+ );
+
+NTSTATUS
+MmMdFreeDescriptor (
+ _In_ PBL_MEMORY_DESCRIPTOR MemoryDescriptor
);
NTSTATUS
Modified: trunk/reactos/boot/environ/lib/mm/descriptor.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/lib/mm/descri…
==============================================================================
--- trunk/reactos/boot/environ/lib/mm/descriptor.c [iso-8859-1] (original)
+++ trunk/reactos/boot/environ/lib/mm/descriptor.c [iso-8859-1] Sun Sep 6 19:22:37
2015
@@ -646,6 +646,151 @@
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,
Modified: trunk/reactos/boot/environ/lib/mm/pagealloc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/boot/environ/lib/mm/pageal…
==============================================================================
--- trunk/reactos/boot/environ/lib/mm/pagealloc.c [iso-8859-1] (original)
+++ trunk/reactos/boot/environ/lib/mm/pagealloc.c [iso-8859-1] Sun Sep 6 19:22:37
2015
@@ -9,6 +9,18 @@
/* INCLUDES ******************************************************************/
#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 ************************************************************/
@@ -43,6 +55,341 @@
}
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_ BL_MEMORY_TYPE MemoryType,
@@ -53,7 +400,56 @@
_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