[BOOTLIB]: Clarify some attributes now that their meaning is clearer.
authorAlex Ionescu <aionescu@gmail.com>
Mon, 13 Feb 2017 23:47:06 +0000 (23:47 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Mon, 13 Feb 2017 23:47:06 +0000 (23:47 +0000)
[BOOTLIB]: Implement MmSelectMappingAddress and fix its prototype.
[BOOTLIB]: Implement MmPapPageAllocatorExtend and fix MmPapAllocatePagesInRange to use it.
We are trying to choose VA 0 for PA 0x8000 and currently fail due to conflicts. TBD.

svn path=/trunk/; revision=73797

reactos/boot/environ/include/bl.h
reactos/boot/environ/lib/mm/descriptor.c
reactos/boot/environ/lib/mm/i386/mmx86.c
reactos/boot/environ/lib/mm/mm.c
reactos/boot/environ/lib/mm/pagealloc.c

index cfdd687..f692e84 100644 (file)
@@ -362,11 +362,11 @@ typedef enum _BL_MEMORY_ATTR
     //
     // Memory Allocation Attributes
     //
-    BlMemoryUnknown =           0x00010000,
-    BlMemoryNonFixed =          0x00020000,
+    BlMemoryLargePages =        0x00010000,
+    BlMemoryKernelRange =       0x00020000,
     BlMemoryFixed =             0x00040000,
     BlMemoryBelow1MB =          0x00080000,
-    BlMemoryValidAllocationAttributes       = BlMemoryNonFixed | BlMemoryFixed | BlMemoryBelow1MB | BlMemoryUnknown,
+    BlMemoryValidAllocationAttributes       = BlMemoryKernelRange | BlMemoryFixed | BlMemoryBelow1MB | BlMemoryLargePages,
     BlMemoryValidAllocationAttributeMask    = 0x00FF0000,
 
     //
@@ -2194,6 +2194,7 @@ BlMmGetMemoryMap (
 NTSTATUS
 MmSelectMappingAddress (
     _Out_ PVOID* MappingAddress,
+    _In_ PVOID PreferredAddress,
     _In_ ULONGLONG Size,
     _In_ ULONG AllocationAttributes,
     _In_ ULONG Flags,
@@ -2721,5 +2722,7 @@ extern BL_MEMORY_DESCRIPTOR_LIST MmMdlFreeVirtual;
 extern BL_MEMORY_DESCRIPTOR_LIST MmMdlMappingTrackers;
 extern ULONGLONG BlpTimePerformanceFrequency;
 extern LIST_ENTRY RegisteredFileSystems;
+extern BL_ADDRESS_RANGE MmArchKsegAddressRange;
+extern ULONG_PTR MmArchTopOfApplicationAddressSpace;
 
 #endif
index d821218..705ba1d 100644 (file)
@@ -1104,7 +1104,7 @@ MmMdFindSatisfyingRegion (
     }
 
     /* Bail out if the allocation flags don't match */
-    if (((Flags ^ Descriptor->Flags) & (BlMemoryRuntime | BlMemoryBelow1MB | BlMemoryUnknown)))
+    if (((Flags ^ Descriptor->Flags) & (BlMemoryRuntime | BlMemoryBelow1MB | BlMemoryLargePages)))
     {
         //EfiPrintf(L"Incorrect memory allocation flags\r\n");
         return FALSE;
index 48632a9..4078177 100644 (file)
@@ -489,29 +489,6 @@ MmDefpTranslateVirtualAddress (
     return TRUE;
 }
 
-NTSTATUS
-MmSelectMappingAddress (
-    _Out_ PVOID* MappingAddress,
-    _In_ ULONGLONG Size,
-    _In_ ULONG AllocationAttributes,
-    _In_ ULONG Flags,
-    _In_ PHYSICAL_ADDRESS PhysicalAddress
-    )
-{
-    /* Are we in physical mode? */
-    if (MmTranslationType == BlNone)
-    {
-        /* Just return the physical address as the mapping address */
-        *MappingAddress = (PVOID)PhysicalAddress.LowPart;
-        return STATUS_SUCCESS;
-    }
-
-    /* We don't support virtual memory yet @TODO */
-    EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
-    EfiStall(1000000);
-    return STATUS_NOT_IMPLEMENTED;
-}
-
 NTSTATUS
 MmMapPhysicalAddress (
     _Inout_ PPHYSICAL_ADDRESS PhysicalAddressPtr,
index 832750b..63814db 100644 (file)
@@ -164,7 +164,7 @@ BlMmMapPhysicalAddressEx (
 
     /* Check for invalid requirement flag, if one is present */
     if (((Flags & BlMemoryValidAllocationAttributes) != BlMemoryFixed) &&
-        ((Flags & BlMemoryValidAllocationAttributes) != BlMemoryNonFixed) &&
+        ((Flags & BlMemoryValidAllocationAttributes) != BlMemoryKernelRange) &&
         (Flags & BlMemoryValidAllocationAttributes))
     {
         Status = STATUS_INVALID_PARAMETER;
@@ -181,6 +181,7 @@ BlMmMapPhysicalAddressEx (
 
     /* Select an address to map this at */
     Status = MmSelectMappingAddress(&MappingAddress,
+                                    *VirtualAddress,
                                     Size,
                                     Flags & BlMemoryValidAllocationAttributes,
                                     Flags,
@@ -195,6 +196,7 @@ BlMmMapPhysicalAddressEx (
     MapSize = Size;
     CacheAttributes = ((Flags & BlMemoryValidCacheAttributeMask) != 0x20) ?
                       (Flags & BlMemoryValidCacheAttributeMask) : 0;
+    EfiPrintf(L"Selected address: %p for %lx\r\n", MappingAddress, MappedAddress.LowPart);
     Status = MmMapPhysicalAddress(&MappedAddress,
                                   &MappingAddress,
                                   &MapSize,
index 5066c0b..ffe2f6e 100644 (file)
@@ -24,6 +24,8 @@ typedef struct _BL_PA_REQUEST
 
 /* DATA VARIABLES ************************************************************/
 
+extern ULONG MmArchLargePageSize;
+
 ULONGLONG PapMaximumPhysicalPage, PapMinimumPhysicalPage;
 
 ULONG PapMinimumAllocationCount;
@@ -418,6 +420,168 @@ Quickie:
     return Status;
 }
 
+NTSTATUS
+MmPapPageAllocatorExtend (
+    _In_ ULONG Attributes,
+    _In_ ULONG Alignment,
+    _In_ ULONGLONG PageCount,
+    _In_ ULONGLONG VirtualPage,
+    _In_opt_ PBL_ADDRESS_RANGE Range,
+    _In_opt_ ULONG Type
+    )
+{
+    BL_PA_REQUEST Request;
+    ULONGLONG PageRange;
+    BL_MEMORY_DESCRIPTOR NewDescriptor;
+    ULONG AllocationFlags, CacheAttributes, AddFlags;
+    NTSTATUS Status;
+    PBL_MEMORY_DESCRIPTOR_LIST MdList;
+    PBL_MEMORY_DESCRIPTOR Descriptor;
+    PVOID VirtualAddress;
+    PHYSICAL_ADDRESS PhysicalAddress;
+
+    /* Is the caller requesting less pages than allowed? */
+    if (!(Attributes & BlMemoryFixed) &&
+        !(Range) &&
+        (PageCount < PapMinimumAllocationCount))
+    {
+        /* Unless this is a fixed request, then adjust the original requirements */
+        PageCount = PapMinimumAllocationCount;
+        Alignment = PapMinimumAllocationCount;
+    }
+
+    /* Extract only the allocation attributes */
+    AllocationFlags = Attributes & BlMemoryValidAllocationAttributeMask;
+
+    /* Check if the caller wants large pages */
+    if ((AllocationFlags & BlMemoryLargePages) && (MmArchLargePageSize != 1))
+    {
+        EfiPrintf(L"Large pages not supported!\r\n");
+        EfiStall(10000000);
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    /* Set an emty virtual range */
+    Request.VirtualRange.Minimum = 0;
+    Request.VirtualRange.Maximum = 0;
+
+    /* Check if the caller requested a range */
+    if (Range)
+    {
+        /* Calculate it size in pages, minus a page as this is a 0-based range */
+        PageRange = ((Range->Maximum - Range->Minimum) >> PAGE_SHIFT) - 1;
+
+        /* Set the minimum and maximum, in pages */
+        Request.BaseRange.Minimum = Range->Minimum >> PAGE_SHIFT;
+        Request.BaseRange.Maximum = Request.BaseRange.Minimum + PageRange;
+    }
+    else
+    {
+        /* Initialize a range from the smallest page to the biggest */
+        Request.BaseRange.Minimum = PapMinimumPhysicalPage;
+        Request.BaseRange.Maximum = 0xFFFFFFFF / PAGE_SIZE;
+    }
+
+    /* Get the cache attributes */
+    CacheAttributes = Attributes & BlMemoryValidCacheAttributeMask;
+
+    /* Check if the caller requested a valid allocation type */
+    if ((Type) && !(Type & ~(BL_MM_REQUEST_DEFAULT_TYPE |
+                             BL_MM_REQUEST_TOP_DOWN_TYPE)))
+    {
+        /* Use what the caller wanted */
+        Request.Type = Type;
+    }
+    else
+    {
+        /* Use the default bottom-up type */
+        Request.Type = BL_MM_REQUEST_DEFAULT_TYPE;
+    }
+
+    /* Use the original protection and type, but ignore other attributes */
+    Request.Flags = Attributes & ~(BlMemoryValidAllocationAttributeMask |
+                                   BlMemoryValidCacheAttributeMask);
+    Request.Alignment = Alignment;
+    Request.Pages = PageCount;
+
+    /* Allocate some free pages */
+    Status = MmPaAllocatePages(NULL,
+                               &NewDescriptor,
+                               &MmMdlUnmappedUnallocated,
+                               &Request,
+                               BlConventionalMemory);
+    if (!NT_SUCCESS(Status))
+    {
+        EfiPrintf(L"Failed to get unmapped,unallocated memory!\r\n");
+        EfiStall(10000000);
+        return Status;
+    }
+
+    /* Initialize a descriptor for these pages, adding in the allocation flags */
+    Descriptor = MmMdInitByteGranularDescriptor(AllocationFlags |
+                                                NewDescriptor.Flags,
+                                                BlConventionalMemory,
+                                                NewDescriptor.BasePage,
+                                                NewDescriptor.VirtualPage,
+                                                NewDescriptor.PageCount);
+
+    /* Now map a virtual address for these physical pages */
+    VirtualAddress = (PVOID)((ULONG_PTR)VirtualPage << PAGE_SHIFT);
+    PhysicalAddress.QuadPart = NewDescriptor.BasePage << PAGE_SHIFT;
+    Status = BlMmMapPhysicalAddressEx(&VirtualAddress,
+                                      AllocationFlags | CacheAttributes,
+                                      NewDescriptor.PageCount << PAGE_SHIFT,
+                                      PhysicalAddress);
+    EfiPrintf(L"MAP status: %lx\r\n", Status);
+    if (Status == STATUS_SUCCESS)
+    {
+        /* Add the cache attributes now that the mapping worked */
+        Descriptor->Flags |= CacheAttributes;
+
+        /* Update the virtual page now that we mapped it */
+        Descriptor->VirtualPage = (ULONG_PTR)VirtualAddress >> PAGE_SHIFT;
+
+        /* Add this as a mapped region */
+        Status = MmMdAddDescriptorToList(&MmMdlMappedUnallocated,
+                                         Descriptor,
+                                         BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG);
+
+        /* Make new descriptor that we'll add in firmware allocation tracker */
+        MdList = &MmMdlFwAllocationTracker;
+        Descriptor = MmMdInitByteGranularDescriptor(0,
+                                                    BlConventionalMemory,
+                                                    NewDescriptor.BasePage,
+                                                    0,
+                                                    NewDescriptor.PageCount);
+
+        /* Do not coalesce */
+        AddFlags = 0;
+    }
+    else
+    {
+        /* We failed, free the physical pages */
+        Status = MmFwFreePages(NewDescriptor.BasePage, NewDescriptor.PageCount);
+        if (!NT_SUCCESS(Status))
+        {
+            /* We failed to free the pages, so this is still around */
+            MdList = &MmMdlUnmappedAllocated;
+        }
+        else
+        {
+            /* This is now back to unmapped/unallocated memory */
+            Descriptor->Flags = 0;
+            MdList = &MmMdlUnmappedUnallocated;
+        }
+
+        /* Coalesce the free descriptor */
+        AddFlags = BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG;
+    }
+
+    /* Either add to firmware list, or to unmapped list, then return result */
+    MmMdAddDescriptorToList(MdList, Descriptor, AddFlags);
+    return Status;
+}
+
 NTSTATUS
 MmPapAllocatePagesInRange (
     _Inout_ PVOID* PhysicalAddress,
@@ -470,8 +634,9 @@ MmPapAllocatePagesInRange (
         }
         else
         {
+            /* Use the entire range that's possible */
             Request.BaseRange.Minimum = PapMinimumPhysicalPage;
-            Request.BaseRange.Maximum = (4 * 1024 * 1024) >> PAGE_SHIFT;
+            Request.BaseRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT;
         }
 
         /* Check if a fixed allocation was requested */
@@ -486,7 +651,7 @@ MmPapAllocatePagesInRange (
         else
         {
             /* Check if non-fixed was specifically requested */
-            if (Attributes & BlMemoryNonFixed)
+            if (Attributes & BlMemoryKernelRange)
             {
                 /* We don't support virtual memory yet @TODO */
                 EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
@@ -497,20 +662,15 @@ MmPapAllocatePagesInRange (
 
             /* Set the virtual address range */
             Request.VirtualRange.Minimum = 0;
-            Request.VirtualRange.Maximum = (4 * 1024 * 1024) >> PAGE_SHIFT;
+            Request.VirtualRange.Maximum = 0xFFFFFFFF >> PAGE_SHIFT;
         }
 
         /* Check what type of allocation was requested */
-        if (Type)
+        if ((Type) && !(Type & ~(BL_MM_REQUEST_DEFAULT_TYPE |
+                               BL_MM_REQUEST_TOP_DOWN_TYPE)))
         {
-            /* Save it */
+            /* Save it if it was valid */
             Request.Type = Type;
-
-            /* If it was invalid, set the default */
-            if (Type & ~(BL_MM_REQUEST_DEFAULT_TYPE | BL_MM_REQUEST_TOP_DOWN_TYPE))
-            {
-                Request.Type = BL_MM_REQUEST_DEFAULT_TYPE;
-            }
         }
         else
         {
@@ -531,11 +691,34 @@ MmPapAllocatePagesInRange (
                                    MemoryType);
         if (!NT_SUCCESS(Status))
         {
-            /* We don't support virtual memory yet @TODO */
-            EfiPrintf(L"Need to extend PA allocator\r\n");
-            EfiStall(1000000);
-            Status = STATUS_NOT_IMPLEMENTED;
-            goto Exit;
+            /* Extend the physical allocator */
+            Status = MmPapPageAllocatorExtend(Attributes,
+                                              Alignment,
+                                              Pages,
+                                              ((ULONG_PTR)*PhysicalAddress) >>
+                                              PAGE_SHIFT,
+                                              Range,
+                                              Type);
+            if (!NT_SUCCESS(Status))
+            {
+                /* Fail since we're out of memory */
+                EfiPrintf(L"OUT OF MEMORY: %lx\r\n", Status);
+                Status = STATUS_NO_MEMORY;
+                goto Exit;
+            }
+
+            /* Try the allocation again now */
+            Status = MmPaAllocatePages(&MmMdlMappedAllocated,
+                                       &Descriptor,
+                                       &MmMdlMappedUnallocated,
+                                       &Request,
+                                       MemoryType);
+            if (!NT_SUCCESS(Status))
+            {
+                /* Fail since we're out of memory */
+                EfiPrintf(L"OUT OF MEMORY: %lx\r\n", Status);
+                goto Exit;
+            }
         }
 
         /* Return the allocated address */
@@ -544,7 +727,8 @@ MmPapAllocatePagesInRange (
     else
     {
         /* Check if this is a fixed allocation */
-        BaseAddress.QuadPart = (Attributes & BlMemoryFixed) ? (ULONG_PTR)*PhysicalAddress : 0;
+        BaseAddress.QuadPart = (Attributes & BlMemoryFixed) ?
+                                (ULONG_PTR)*PhysicalAddress : 0;
 
         /* Allocate the pages */
         Status = MmPapAllocatePhysicalPagesInRange(&BaseAddress,
@@ -1316,3 +1500,81 @@ Quickie:
     return Status;
 }
 
+NTSTATUS
+MmSelectMappingAddress (
+    _Out_ PVOID* MappingAddress,
+    _In_ PVOID PreferredAddress, 
+    _In_ ULONGLONG Size,
+    _In_ ULONG AllocationAttributes,
+    _In_ ULONG Flags,
+    _In_ PHYSICAL_ADDRESS PhysicalAddress
+    )
+{
+    BL_PA_REQUEST Request;
+    NTSTATUS Status;
+    BL_MEMORY_DESCRIPTOR NewDescriptor;
+
+    /* Are we in physical mode? */
+    if (MmTranslationType == BlNone)
+    {
+        /* Just return the physical address as the mapping address */
+        PreferredAddress = (PVOID)PhysicalAddress.LowPart;
+    }
+
+    /* If no physical address, or caller wants a fixed address... */
+    if ((PhysicalAddress.QuadPart == -1) || (Flags & BlMemoryFixed))
+    {
+        /* Then just return the preferred address */
+        goto Success;
+    }
+
+    /* Check which range of virtual memory should be used */
+    if (AllocationAttributes & BlMemoryKernelRange)
+    {
+        /* Use kernel range */
+        Request.BaseRange = MmArchKsegAddressRange;
+        Request.Type = BL_MM_REQUEST_DEFAULT_TYPE;
+    }
+    else
+    {
+        /* User user/application range */
+        Request.BaseRange.Minimum = 0;
+        Request.BaseRange.Maximum = MmArchTopOfApplicationAddressSpace;
+        Request.Type = BL_MM_REQUEST_TOP_DOWN_TYPE;
+    }
+
+    /* Build a request */
+    Request.VirtualRange.Minimum = 0;
+    Request.VirtualRange.Maximum = 0;
+    Request.Flags = AllocationAttributes & BlMemoryLargePages;
+    Request.Alignment = 1;
+    Request.Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(PhysicalAddress.LowPart, Size);
+
+    /* Allocate the physical pages */
+    Status = MmPaAllocatePages(NULL,
+                               &NewDescriptor,
+                               &MmMdlFreeVirtual,
+                               &Request,
+                               BlConventionalMemory);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Return the address we got back */
+    PreferredAddress = (PVOID)((ULONG_PTR)NewDescriptor.BasePage << PAGE_SHIFT);
+
+    /* Check if the existing physical address was not aligned */
+    if (PhysicalAddress.QuadPart != -1)
+    {
+        /* Add the offset to the returned virtual address */
+        PreferredAddress = (PVOID)((ULONG_PTR)PreferredAddress +
+                                   PhysicalAddress.LowPart -
+                                   BYTE_OFFSET(PhysicalAddress.LowPart));
+    }
+    
+Success:
+    /* Return the mapping address and success */
+    *MappingAddress = PreferredAddress;
+    return STATUS_SUCCESS;
+}