[FREELDR] Implement the memory managment functions for UEFI (#5174)

CORE-11954

- EFI binaries have a different subsystem in the PE header;
- ENVIRON: Make sure INTN and UINTN are 64bit for 64bit platforms;
- Handle UEFI Memory maps and translate it for freeldr;
- Add FAILED_TO_EXIT_BOOTSERVICES Freeldr BSoD code.
This commit is contained in:
Justin Miller 2023-04-03 08:33:20 -07:00 committed by GitHub
parent 83e83bfd2c
commit ccef43f3b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 346 additions and 24 deletions

View file

@ -197,6 +197,7 @@ typedef signed char CHAR8;
typedef signed char INT8;
#endif
#ifndef _WIN64
///
/// Unsigned value of native width. (4 bytes on supported 32-bit processor instructions;
/// 8 bytes on supported 64-bit processor instructions.)
@ -207,6 +208,18 @@ typedef UINT32 UINTN;
/// 8 bytes on supported 64-bit processor instructions.)
///
typedef INT32 INTN;
#else
///
/// Unsigned value of native width. (4 bytes on supported 32-bit processor instructions;
/// 8 bytes on supported 64-bit processor instructions.)
///
typedef UINT64 UINTN;
///
/// Signed value of native width. (4 bytes on supported 32-bit processor instructions;
/// 8 bytes on supported 64-bit processor instructions.)
///
typedef INT64 INTN;
#endif
//
// Processor specific defines

View file

@ -1,7 +1,7 @@
/*
* PROJECT: Freeldr UEFI Extension
* PROJECT: FreeLoader UEFI Support
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: UEFI stubs
* PURPOSE: Function stubs
* COPYRIGHT: Copyright 2022 Justin Miller <justinmiller100@gmail.com>
*/
@ -41,12 +41,6 @@ UefiVideoSync(VOID)
}
PFREELDR_MEMORY_DESCRIPTOR
UefiMemGetMemoryMap(ULONG *MemoryMapSize)
{
return 0;
}
VOID
UefiGetExtendedBIOSData(PULONG ExtendedBIOSDataArea,
PULONG ExtendedBIOSDataSize)
@ -94,12 +88,6 @@ UefiHwDetect(VOID)
return 0;
}
VOID
UefiPrepareForReactOS(VOID)
{
}
VOID
UefiPcBeep(VOID)
{

View file

@ -1,7 +1,7 @@
/*
* PROJECT: Freeldr UEFI Extension
* PROJECT: FreeLoader UEFI Support
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: UEFI Console output
* PURPOSE: Console output
* COPYRIGHT: Copyright 2022 Justin Miller <justinmiller100@gmail.com>
*/

View file

@ -1,7 +1,7 @@
/*
* PROJECT: Freeldr UEFI Extension
* PROJECT: FreeLoader UEFI Support
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: UEFI Entry point and helpers
* PURPOSE: Entry point and helpers
* COPYRIGHT: Copyright 2022 Justin Miller <justinmiller100@gmail.com>
*/

View file

@ -0,0 +1,312 @@
/*
* PROJECT: FreeLoader UEFI Support
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Memory Management Functions
* COPYRIGHT: Copyright 2022 Justin Miller <justinmiller100@gmail.com>
*/
/* INCLUDES ******************************************************************/
#include <uefildr.h>
#include <debug.h>
DBG_DEFAULT_CHANNEL(WARNING);
#define NEXT_MEMORY_DESCRIPTOR(Descriptor, DescriptorSize) \
(EFI_MEMORY_DESCRIPTOR*)((char*)(Descriptor) + (DescriptorSize))
#define EXIT_STACK_SIZE 0x1000
#define UNUSED_MAX_DESCRIPTOR_COUNT 10000
ULONG
AddMemoryDescriptor(
_Inout_ PFREELDR_MEMORY_DESCRIPTOR List,
_In_ ULONG MaxCount,
_In_ PFN_NUMBER BasePage,
_In_ PFN_NUMBER PageCount,
_In_ TYPE_OF_MEMORY MemoryType);
/* GLOBALS *******************************************************************/
extern EFI_SYSTEM_TABLE* GlobalSystemTable;
extern EFI_HANDLE GlobalImageHandle;
extern REACTOS_INTERNAL_BGCONTEXT framebufferData;
EFI_MEMORY_DESCRIPTOR* EfiMemoryMap = NULL;
UINT32 FreeldrDescCount;
PVOID OsLoaderBase;
SIZE_T OsLoaderSize;
EFI_HANDLE PublicBootHandle;
PVOID ExitStack;
PVOID EndofExitStack;
/* FUNCTIONS *****************************************************************/
static
VOID
PUEFI_LoadMemoryMap(
_Out_ UINTN* LocMapKey,
_Out_ UINTN* LocMapSize,
_Out_ UINTN* LocDescriptorSize,
_Out_ UINT32* LocDescriptorVersion)
{
EFI_STATUS Status;
UINTN AllocationSize = 0;
ULONG Count = 0;
Status = GlobalSystemTable->BootServices->GetMemoryMap(LocMapSize,
EfiMemoryMap,
LocMapKey,
LocDescriptorSize,
LocDescriptorVersion);
/* Reallocate and retrieve again the needed memory map size (since memory
* allocated by AllocatePool() counts in the map), until it's OK. */
while (Status != EFI_SUCCESS)
{
/* Reallocate the memory map buffer */
if (EfiMemoryMap)
GlobalSystemTable->BootServices->FreePool(EfiMemoryMap);
/* If MapSize never reports the correct size after the first time, increment */
AllocationSize = *LocMapSize + (*LocDescriptorSize * Count);
GlobalSystemTable->BootServices->AllocatePool(EfiLoaderData, AllocationSize,
(VOID**)&EfiMemoryMap);
Status = GlobalSystemTable->BootServices->GetMemoryMap(LocMapSize,
EfiMemoryMap,
LocMapKey,
LocDescriptorSize,
LocDescriptorVersion);
Count++;
}
}
static
VOID
UefiSetMemory(
_Inout_ PFREELDR_MEMORY_DESCRIPTOR MemoryMap,
_In_ ULONG_PTR BaseAddress,
_In_ PFN_COUNT Size,
_In_ TYPE_OF_MEMORY MemoryType)
{
ULONG_PTR BasePage, PageCount;
BasePage = BaseAddress / EFI_PAGE_SIZE;
PageCount = Size;
/* Add the memory descriptor */
FreeldrDescCount = AddMemoryDescriptor(MemoryMap,
UNUSED_MAX_DESCRIPTOR_COUNT,
BasePage,
PageCount,
MemoryType);
}
VOID
ReserveMemory(
_Inout_ PFREELDR_MEMORY_DESCRIPTOR MemoryMap,
_In_ ULONG_PTR BaseAddress,
_In_ PFN_NUMBER Size,
_In_ TYPE_OF_MEMORY MemoryType,
_In_ PCHAR Usage)
{
ULONG_PTR BasePage, PageCount;
ULONG i;
BasePage = BaseAddress / PAGE_SIZE;
PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Size);
for (i = 0; i < FreeldrDescCount; i++)
{
/* Check for conflicting descriptor */
if ((MemoryMap[i].BasePage < BasePage + PageCount) &&
(MemoryMap[i].BasePage + MemoryMap[i].PageCount > BasePage))
{
/* Check if the memory is free */
if (MemoryMap[i].MemoryType != LoaderFree)
{
FrLdrBugCheckWithMessage(
MEMORY_INIT_FAILURE,
__FILE__,
__LINE__,
"Failed to reserve memory in the range 0x%Ix - 0x%Ix for %s",
BaseAddress,
Size,
Usage);
}
}
}
/* Add the memory descriptor */
FreeldrDescCount = AddMemoryDescriptor(MemoryMap,
UNUSED_MAX_DESCRIPTOR_COUNT,
BasePage,
PageCount,
MemoryType);
}
static
TYPE_OF_MEMORY
UefiConvertToFreeldrDesc(EFI_MEMORY_TYPE EfiMemoryType)
{
switch (EfiMemoryType)
{
case EfiReservedMemoryType:
return LoaderReserve;
case EfiLoaderCode:
return LoaderLoadedProgram;
case EfiLoaderData:
return LoaderLoadedProgram;
case EfiBootServicesCode:
return LoaderFirmwareTemporary;
case EfiBootServicesData:
return LoaderFirmwareTemporary;
case EfiRuntimeServicesCode:
return LoaderFirmwarePermanent;
case EfiRuntimeServicesData:
return LoaderFirmwarePermanent;
case EfiConventionalMemory:
return LoaderFree;
case EfiUnusableMemory:
return LoaderBad;
case EfiACPIReclaimMemory:
return LoaderFirmwareTemporary;
case EfiACPIMemoryNVS:
return LoaderReserve;
case EfiMemoryMappedIO:
return LoaderReserve;
case EfiMemoryMappedIOPortSpace:
return LoaderReserve;
default:
break;
}
return LoaderReserve;
}
PFREELDR_MEMORY_DESCRIPTOR
UefiMemGetMemoryMap(ULONG *MemoryMapSize)
{
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
UINT32 DescriptorVersion;
SIZE_T FreeldrMemMapSize;
UINTN DescriptorSize;
EFI_STATUS Status;
UINTN MapSize;
UINTN MapKey;
UINT32 Index;
EFI_GUID EfiLoadedImageProtocol = EFI_LOADED_IMAGE_PROTOCOL_GUID;
PFREELDR_MEMORY_DESCRIPTOR FreeldrMem = NULL;
EFI_MEMORY_DESCRIPTOR* MapEntry = NULL;
UINT32 EntryCount = 0;
FreeldrDescCount = 0;
Status = GlobalSystemTable->BootServices->HandleProtocol(GlobalImageHandle,
&EfiLoadedImageProtocol,
(VOID**)&LoadedImage);
if (Status != EFI_SUCCESS)
{
TRACE("Failed to find LoadedImageHandle with status: %d\n", Status);
UiMessageBoxCritical("Unable to initialize memory manager.");
return NULL;
}
OsLoaderBase = LoadedImage->ImageBase;
OsLoaderSize = LoadedImage->ImageSize;
PublicBootHandle = LoadedImage->DeviceHandle;
EfiMemoryMap = NULL;
TRACE("UefiMemGetMemoryMap: Gather memory map\n");
PUEFI_LoadMemoryMap(&MapKey,
&MapSize,
&DescriptorSize,
&DescriptorVersion);
TRACE("Value of MapKey: %d\n", MapKey);
TRACE("Value of MapSize: %d\n", MapSize);
TRACE("Value of DescriptorSize: %d\n", DescriptorSize);
TRACE("Value of DescriptorVersion: %d\n", DescriptorVersion);
EntryCount = (MapSize / DescriptorSize);
FreeldrMemMapSize = (sizeof(FREELDR_MEMORY_DESCRIPTOR) * EntryCount);
Status = GlobalSystemTable->BootServices->AllocatePool(EfiLoaderData,
FreeldrMemMapSize,
(void**)&FreeldrMem);
if (Status != EFI_SUCCESS)
{
TRACE("Failed to allocate pool with status %d\n", Status);
UiMessageBoxCritical("Unable to initialize memory manager.");
return NULL;
}
RtlZeroMemory(FreeldrMem, FreeldrMemMapSize);
MapEntry = EfiMemoryMap;
for (Index = 0; Index < EntryCount; ++Index)
{
TYPE_OF_MEMORY MemoryType = UefiConvertToFreeldrDesc(MapEntry->Type);
if (MemoryType == LoaderFree)
{
Status = GlobalSystemTable->BootServices->AllocatePages(AllocateAddress,
EfiLoaderData,
MapEntry->NumberOfPages,
&MapEntry->PhysicalStart);
if (Status != EFI_SUCCESS)
{
/* We failed to reserve the page, so change its type */
MemoryType = LoaderFirmwareTemporary;
}
}
UefiSetMemory(FreeldrMem,
MapEntry->PhysicalStart,
MapEntry->NumberOfPages,
MemoryType);
MapEntry = NEXT_MEMORY_DESCRIPTOR(MapEntry, DescriptorSize);
}
*MemoryMapSize = FreeldrDescCount;
return FreeldrMem;
}
static VOID
UefiExitBootServices(VOID)
{
UINTN MapKey;
UINTN MapSize;
EFI_STATUS Status;
UINTN DescriptorSize;
UINT32 DescriptorVersion;
TRACE("Attempting to exit bootsevices\n");
PUEFI_LoadMemoryMap(&MapKey,
&MapSize,
&DescriptorSize,
&DescriptorVersion);
Status = GlobalSystemTable->BootServices->ExitBootServices(GlobalImageHandle, MapKey);
/* UEFI spec demands twice! */
if (Status != EFI_SUCCESS)
Status = GlobalSystemTable->BootServices->ExitBootServices(GlobalImageHandle, MapKey);
if (Status != EFI_SUCCESS)
{
TRACE("Failed to exit boot services with status: %d\n", Status);
FrLdrBugCheckWithMessage(EXIT_BOOTSERVICES_FAILURE,
__FILE__,
__LINE__,
"Failed to exit boot services with status: %d",
Status);
}
else
{
TRACE("Exited bootservices\n");
}
}
VOID
UefiPrepareForReactOS(VOID)
{
UefiExitBootServices();
ExitStack = MmAllocateMemoryWithType(EXIT_STACK_SIZE, LoaderOsloaderStack);
EndofExitStack = (PVOID)((ULONG_PTR)ExitStack + EXIT_STACK_SIZE);
}

View file

@ -1,7 +1,7 @@
/*
* PROJECT: Freeldr UEFI Extension
* PROJECT: FreeLoader UEFI Support
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: UEFI Mach Setup
* PURPOSE: Machine Setup
* COPYRIGHT: Copyright 2022 Justin Miller <justinmiller100@gmail.com>
*/

View file

@ -1,7 +1,7 @@
/*
* PROJECT: Freeldr UEFI Extension
* PROJECT: FreeLoader UEFI Support
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: UEFI Utils source
* PURPOSE: Utils source
* COPYRIGHT: Copyright 2022 Justin Miller <justinmiller100@gmail.com>
*/

View file

@ -1,7 +1,7 @@
/*
* PROJECT: Freeldr UEFI Extension
* PROJECT: FreeLoader UEFI Support
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: UEFI Video output
* PURPOSE: Video output
* COPYRIGHT: Copyright 2022 Justin Miller <justinmiller100@gmail.com>
*/

View file

@ -141,6 +141,9 @@ enum _FRLDR_BUGCHECK_CODES
MISSING_HARDWARE_REQUIREMENTS,
FREELDR_IMAGE_CORRUPTION,
MEMORY_INIT_FAILURE,
#ifdef UEFIBOOT
EXIT_BOOTSERVICES_FAILURE,
#endif
};
extern char *BugCodeStrings[];

View file

@ -518,6 +518,9 @@ char *BugCodeStrings[] =
"MISSING_HARDWARE_REQUIREMENTS",
"FREELDR_IMAGE_CORRUPTION",
"MEMORY_INIT_FAILURE",
#ifdef UEFIBOOT
"EXIT_BOOTSERVICES_FAILURE",
#endif
};
ULONG_PTR BugCheckInfo[5];

View file

@ -238,6 +238,7 @@ static
VOID
MmCheckFreeldrImageFile(VOID)
{
#ifndef UEFIBOOT
PIMAGE_NT_HEADERS NtHeaders;
PIMAGE_FILE_HEADER FileHeader;
PIMAGE_OPTIONAL_HEADER OptionalHeader;
@ -308,6 +309,7 @@ MmCheckFreeldrImageFile(VOID)
/* Calculate the full image size */
FrLdrImageSize = (ULONG_PTR)&__ImageBase + OptionalHeader->SizeOfImage - FREELDR_BASE;
#endif
}
BOOLEAN MmInitializeMemoryManager(VOID)

View file

@ -18,6 +18,7 @@ list(APPEND UEFILDR_ARC_SOURCE
arch/uefi/uefivid.c
arch/uefi/uefiutil.c
arch/uefi/ueficon.c
arch/uefi/uefimem.c
arch/vgafont.c)
if(ARCH STREQUAL "i386")