reactos/boot/environ/lib/mm/mm.c
Hermès Bélusca-Maïto 9393fc320e
[FORMATTING] Remove trailing whitespace. Addendum to 34593d93.
Excluded: 3rd-party code (incl. wine) and most of the win32ss.
2021-09-13 03:52:22 +02:00

658 lines
21 KiB
C

/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/mm/mm.c
* PURPOSE: Boot Library Memory Manager Core
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
#include "bcd.h"
/* DATA VARIABLES ************************************************************/
/* This is a bug in Windows, but is required for MmTrInitialize to load */
BL_TRANSLATION_TYPE MmTranslationType = BlMax;
BL_TRANSLATION_TYPE MmOriginalTranslationType;
ULONG MmDescriptorCallTreeCount;
/* FUNCTIONS *****************************************************************/
NTSTATUS
TrpGenerateMappingTracker (
_In_ PVOID VirtualAddress,
_In_ ULONG Flags,
_In_ LARGE_INTEGER PhysicalAddress,
_In_ ULONGLONG Size
)
{
PBL_MEMORY_DESCRIPTOR Descriptor, NextDescriptor;
PLIST_ENTRY ListHead, NextEntry;
/* Increment descriptor call count */
MmDescriptorCallTreeCount++;
/* Initialize a descriptor for this allocation */
Descriptor = MmMdInitByteGranularDescriptor(Flags,
0,
PhysicalAddress.QuadPart,
(ULONG_PTR)VirtualAddress,
Size);
/* Loop the current tracker list */
ListHead = MmMdlMappingTrackers.First;
NextEntry = ListHead->Flink;
if (IsListEmpty(ListHead))
{
/* If it's empty, just add the descriptor at the end */
InsertTailList(ListHead, &Descriptor->ListEntry);
goto Quickie;
}
/* Otherwise, go to the last descriptor */
NextDescriptor = CONTAINING_RECORD(NextEntry,
BL_MEMORY_DESCRIPTOR,
ListEntry);
while (NextDescriptor->VirtualPage < Descriptor->VirtualPage)
{
/* Keep going... */
NextEntry = NextEntry->Flink;
NextDescriptor = CONTAINING_RECORD(NextEntry,
BL_MEMORY_DESCRIPTOR,
ListEntry);
/* If we hit the end of the list, just add it at the end */
if (NextEntry == ListHead)
{
goto Quickie;
}
/* Otherwise, add it right after this descriptor */
InsertTailList(&NextDescriptor->ListEntry, &Descriptor->ListEntry);
}
Quickie:
/* Release any global descriptors allocated */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return STATUS_SUCCESS;
}
NTSTATUS
MmTrInitialize (
VOID
)
{
PBL_MEMORY_DESCRIPTOR Descriptor;
NTSTATUS Status;
PLIST_ENTRY NextEntry;
/* Nothing to track if we're using physical memory */
if (MmTranslationType == BlNone)
{
return STATUS_SUCCESS;
}
/* Initialize all the virtual lists */
MmMdInitializeListHead(&MmMdlMappingTrackers);
MmMdlMappingTrackers.Type = BlMdTracker;
MmMdInitializeListHead(&MmMdlFreeVirtual);
MmMdlFreeVirtual.Type = BlMdVirtual;
/* Initialize a 4GB free descriptor */
Descriptor = MmMdInitByteGranularDescriptor(0,
BlConventionalMemory,
0,
0,
((ULONGLONG)4 * 1024 * 1024 * 1024) >>
PAGE_SHIFT);
if (!Descriptor)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Add this 4GB region to the free virtual address space list */
Status = MmMdAddDescriptorToList(&MmMdlFreeVirtual,
Descriptor,
BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG);
if (!NT_SUCCESS(Status))
{
RtlZeroMemory(Descriptor, sizeof(*Descriptor));
goto Quickie;
}
/* Remove any reserved regions of virtual address space */
NextEntry = MmMdlReservedAllocated.First->Flink;
while (NextEntry != MmMdlReservedAllocated.First)
{
/* Grab the descriptor and see if it's mapped */
Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
if (Descriptor->VirtualPage)
{
EfiPrintf(L"Need to handle reserved allocation: %llx %llx\r\n",
Descriptor->VirtualPage, Descriptor->PageCount);
EfiStall(100000);
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
}
/* Next entry */
NextEntry = NextEntry->Flink;
}
/* Set success if we made it */
Status = STATUS_SUCCESS;
Quickie:
/* Return back to caller */
return Status;
}
NTSTATUS
BlMmRemoveBadMemory (
VOID
)
{
BOOLEAN AllowBad;
NTSTATUS Status;
PULONGLONG BadPages;
ULONGLONG BadPageCount;
/* First check if bad memory access is allowed */
AllowBad = FALSE;
Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_AllowBadMemoryAccess,
&AllowBad);
if ((NT_SUCCESS(Status)) && (AllowBad))
{
/* No point checking the list if it is */
return STATUS_SUCCESS;
}
/* Otherwise, check if there's a persisted bad page list */
Status = BlpGetBootOptionIntegerList(BlpApplicationEntry.BcdData,
BcdLibraryIntegerList_BadMemoryList,
&BadPages,
&BadPageCount,
TRUE);
if (NT_SUCCESS(Status))
{
EfiPrintf(L"Persistent bad page list not supported\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/* All done here */
return STATUS_SUCCESS;
}
NTSTATUS
BlMmMapPhysicalAddressEx (
_In_ PVOID* VirtualAddress,
_In_ ULONG Flags,
_In_ ULONGLONG Size,
_In_ PHYSICAL_ADDRESS PhysicalAddress
)
{
NTSTATUS Status;
PVOID MappingAddress;
PHYSICAL_ADDRESS MappedAddress;
PVOID MappedBase;
ULONGLONG MapSize;
UCHAR CacheAttributes;
ULONGLONG BasePage, EndPage, MappedPage, FoundBasePage;
ULONGLONG PageOffset, FoundPageCount;
PBL_MEMORY_DESCRIPTOR Descriptor, NewDescriptor;
PBL_MEMORY_DESCRIPTOR_LIST List;
ULONG AddPages;
/* Increase call depth */
++MmDescriptorCallTreeCount;
/* Check if any parameters are missing */
if (!(VirtualAddress) || !(Size))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check for fixed allocation without an actual address */
if ((Flags & BlMemoryFixed) &&
(PhysicalAddress.QuadPart == -1) &&
!(*VirtualAddress))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check for invalid requirement flag, if one is present */
if (((Flags & BlMemoryValidAllocationAttributes) != BlMemoryFixed) &&
((Flags & BlMemoryValidAllocationAttributes) != BlMemoryKernelRange) &&
(Flags & BlMemoryValidAllocationAttributes))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Check for invalid cache attribute flags */
if (((Flags & BlMemoryValidCacheAttributeMask) - 1) &
(Flags & BlMemoryValidCacheAttributeMask))
{
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Select an address to map this at */
Status = MmSelectMappingAddress(&MappingAddress,
*VirtualAddress,
Size,
Flags & BlMemoryValidAllocationAttributes,
Flags,
PhysicalAddress);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Map the selected address, using the appropriate caching attributes */
MappedAddress = PhysicalAddress;
MapSize = Size;
CacheAttributes = ((Flags & BlMemoryValidCacheAttributeMask) != 0x20) ?
(Flags & BlMemoryValidCacheAttributeMask) : 0;
Status = MmMapPhysicalAddress(&MappedAddress,
&MappingAddress,
&MapSize,
CacheAttributes);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Compute the final address where the mapping was made */
MappedBase = (PVOID)(ULONG_PTR)((ULONG_PTR)MappingAddress +
PhysicalAddress.QuadPart -
MappedAddress.QuadPart);
MappedAddress.QuadPart = (ULONG_PTR)MappedBase;
/* Check if we're in physical or virtual mode */
if (MmTranslationType == BlNone)
{
/* We are in physical mode -- just return this address directly */
Status = STATUS_SUCCESS;
*VirtualAddress = MappedBase;
goto Quickie;
}
/* Remove the mapping address from the list of free virtual memory */
Status = MmMdRemoveRegionFromMdlEx(&MmMdlFreeVirtual,
BL_MM_REMOVE_VIRTUAL_REGION_FLAG,
(ULONG_PTR)MappingAddress >> PAGE_SHIFT,
MapSize >> PAGE_SHIFT,
NULL);
if (NT_SUCCESS(Status))
{
/* And then add an entry for the fact we mapped it */
Status = TrpGenerateMappingTracker(MappedBase,
CacheAttributes,
PhysicalAddress,
MapSize);
}
/* Abandon if we didn't update the memory map successfully */
if (!NT_SUCCESS(Status))
{
/* Unmap the virtual address so it can be used later */
MmUnmapVirtualAddress(MappingAddress, &MapSize);
goto Quickie;
}
/* Check if no real mapping into RAM was made */
if (PhysicalAddress.QuadPart == -1)
{
/* Then we're done here */
Status = STATUS_SUCCESS;
*VirtualAddress = MappedBase;
goto Quickie;
}
/* Loop over the entire allocation */
BasePage = MappedAddress.QuadPart >> PAGE_SHIFT;
EndPage = (MappedAddress.QuadPart + MapSize) >> PAGE_SHIFT;
MappedPage = (ULONG_PTR)MappingAddress >> PAGE_SHIFT;
do
{
/* Start with the unmapped allocated list */
List = &MmMdlUnmappedAllocated;
Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_ALLOCATED,
BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
BasePage);
if (!Descriptor)
{
/* Try persistent next */
List = &MmMdlPersistentMemory;
Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_PERSISTENT_MEMORY,
BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
BasePage);
}
if (!Descriptor)
{
/* Try unmapped, unallocated, next */
List = &MmMdlUnmappedUnallocated;
Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_UNMAPPED_UNALLOCATED,
BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
BasePage);
}
if (!Descriptor)
{
/* Try reserved next */
List = &MmMdlReservedAllocated;
Descriptor = MmMdFindDescriptor(BL_MM_INCLUDE_RESERVED_ALLOCATED,
BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
BasePage);
}
/* Check if we have a descriptor */
if (Descriptor)
{
/* Remove it from its list */
MmMdRemoveDescriptorFromList(List, Descriptor);
/* Check if it starts before our allocation */
FoundBasePage = Descriptor->BasePage;
if (FoundBasePage < BasePage)
{
/* Create a new descriptor to cover the gap before our allocation */
PageOffset = BasePage - FoundBasePage;
NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
Descriptor->Type,
FoundBasePage,
0,
PageOffset);
/* Insert it */
MmMdAddDescriptorToList(List, NewDescriptor, 0);
/* Adjust ours to ignore that piece */
Descriptor->PageCount -= PageOffset;
Descriptor->BasePage = BasePage;
}
/* Check if it goes beyond our allocation */
FoundPageCount = Descriptor->PageCount;
if (EndPage < (FoundPageCount + Descriptor->BasePage))
{
/* Create a new descriptor to cover the range after our allocation */
PageOffset = EndPage - BasePage;
NewDescriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
Descriptor->Type,
EndPage,
0,
FoundPageCount -
PageOffset);
/* Insert it */
MmMdAddDescriptorToList(List, NewDescriptor, 0);
/* Adjust ours to ignore that piece */
Descriptor->PageCount = PageOffset;
}
/* Update the descriptor to be mapepd at this virtual page */
Descriptor->VirtualPage = MappedPage;
/* Check if this was one of the regular lists */
if ((List != &MmMdlReservedAllocated) &&
(List != &MmMdlPersistentMemory))
{
/* Was it allocated, or unallocated? */
if (List != &MmMdlUnmappedAllocated)
{
/* In which case use the unallocated mapped list */
List = &MmMdlMappedUnallocated;
}
else
{
/* Insert it into the mapped list */
List = &MmMdlMappedAllocated;
}
}
/* Add the descriptor that was removed, into the right list */
MmMdAddDescriptorToList(List, Descriptor, 0);
/* Add the pages this descriptor had */
AddPages = Descriptor->PageCount;
}
else
{
/* Nope, so just add one page */
AddPages = 1;
}
/* Increment the number of pages the descriptor had */
MappedPage += AddPages;
BasePage += AddPages;
}
while (BasePage < EndPage);
/* We're done -- returned the address */
Status = STATUS_SUCCESS;
*VirtualAddress = MappedBase;
Quickie:
/* Cleanup descriptors and reduce depth */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}
NTSTATUS
MmUnmapVirtualAddress (
_Inout_ PVOID* VirtualAddress,
_Inout_ PULONGLONG Size
)
{
NTSTATUS Status;
/* Make sure parameters were passed in and are valid */
if ((VirtualAddress) && (Size) && (*Size <= 0xFFFFFFFF))
{
/* Nothing to do if translation isn't active */
if (MmTranslationType == BlNone)
{
Status = STATUS_SUCCESS;
}
else
{
/* We don't support virtual memory yet @TODO */
EfiPrintf(L"unmap not yet implemented in %S\r\n", __FUNCTION__);
EfiStall(1000000);
Status = STATUS_NOT_IMPLEMENTED;
}
}
else
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
/* All done */
return Status;
}
NTSTATUS
BlMmUnmapVirtualAddressEx (
_In_ PVOID VirtualAddress,
_In_ ULONGLONG Size
)
{
NTSTATUS Status;
/* Increment call depth */
++MmDescriptorCallTreeCount;
/* Make sure all parameters are there */
if ((VirtualAddress) && (Size))
{
/* Unmap the virtual address */
Status = MmUnmapVirtualAddress(&VirtualAddress, &Size);
/* Check if we actually had a virtual mapping active */
if ((NT_SUCCESS(Status)) && (MmTranslationType != BlNone))
{
/* We don't support virtual memory yet @TODO */
EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
EfiStall(1000000);
Status = STATUS_NOT_IMPLEMENTED;
}
}
else
{
/* Fail */
Status = STATUS_INVALID_PARAMETER;
}
/* Cleanup descriptors and reduce depth */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}
BOOLEAN
BlMmTranslateVirtualAddress (
_In_ PVOID VirtualAddress,
_Out_ PPHYSICAL_ADDRESS PhysicalAddress
)
{
/* Make sure arguments are present */
if (!(VirtualAddress) || !(PhysicalAddress))
{
return FALSE;
}
/* Do the architecture-specific translation */
return MmArchTranslateVirtualAddress(VirtualAddress, PhysicalAddress, NULL);
}
NTSTATUS
BlpMmInitialize (
_In_ PBL_MEMORY_DATA MemoryData,
_In_ BL_TRANSLATION_TYPE TranslationType,
_In_ PBL_LIBRARY_PARAMETERS LibraryParameters
)
{
NTSTATUS Status;
/* Take a reference */
MmDescriptorCallTreeCount = 1;
/* Only support valid translation types */
if ((TranslationType > BlPae) || (LibraryParameters->TranslationType > BlPae))
{
/* Bail out */
EfiPrintf(L"Invalid translation types present\r\n");
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Initialize memory descriptors */
MmMdInitialize(0, LibraryParameters);
/* Remember the page type we came in with */
MmOriginalTranslationType = TranslationType;
/* Initialize the physical page allocator */
Status = MmPaInitialize(MemoryData,
LibraryParameters->MinimumAllocationCount);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Initialize the memory tracker */
Status = MmTrInitialize();
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"TR Mm init failed: %lx\r\n", Status);
//MmArchDestroy();
//MmPaDestroy(1);
goto Quickie;
}
/* Initialize paging, large pages, self-mapping, PAE, if needed */
Status = MmArchInitialize(1,
MemoryData,
TranslationType,
LibraryParameters->TranslationType);
if (NT_SUCCESS(Status))
{
/* Save the newly active transation type */
MmTranslationType = LibraryParameters->TranslationType;
/* Initialize the heap allocator now */
Status = MmHaInitialize(LibraryParameters->MinimumHeapSize,
LibraryParameters->HeapAllocationAttributes);
}
/* If Phase 1 init failed, bail out */
if (!NT_SUCCESS(Status))
{
/* Kill everything set setup so far */
EfiPrintf(L"Phase 1 Mm init failed: %lx\r\n", Status);
//MmPaDestroy(0);
//MmTrDestroy();
//MmArchDestroy();
//MmPaDestroy(1);
goto Quickie;
}
/* Do we have too many descriptors? */
if (LibraryParameters->DescriptorCount > 512)
{
/* Switch to using a dynamic buffer instead */
EfiPrintf(L"Warning: too many descriptors\r\n");
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
//MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
}
/* Remove memory that the BCD says is bad */
BlMmRemoveBadMemory();
/* Now map all the memory regions as needed */
Status = MmArchInitialize(2,
MemoryData,
TranslationType,
LibraryParameters->TranslationType);
if (NT_SUCCESS(Status))
{
/* Initialize the block allocator */
Status = MmBaInitialize();
}
/* Check if anything in phase 2 failed */
if (!NT_SUCCESS(Status))
{
/* Go back to static descriptors and kill the heap */
EfiPrintf(L"Phase 2 Mm init failed: %lx\r\n", Status);
//MmMdpSwitchToStaticDescriptors();
//HapInitializationStatus = 0;
//++MmDescriptorCallTreeCount;
/* Destroy the Phase 1 initialization */
//MmPaDestroy(0);
//MmTrDestroy();
//MmArchDestroy();
//MmPaDestroy(1);
}
Quickie:
/* Free the memory descriptors and return the initialization state */
MmMdFreeGlobalDescriptors();
--MmDescriptorCallTreeCount;
return Status;
}