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?r... ============================================================================== --- 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/descrip... ============================================================================== --- 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/pageall... ============================================================================== --- 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