From ccef43f3b0dcc2ee472d497ae09cf8ead9c0bf06 Mon Sep 17 00:00:00 2001 From: Justin Miller Date: Mon, 3 Apr 2023 08:33:20 -0700 Subject: [PATCH] [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. --- boot/environ/include/efi/ProcessorBind.h | 13 + boot/freeldr/freeldr/arch/uefi/stubs.c | 16 +- boot/freeldr/freeldr/arch/uefi/ueficon.c | 4 +- boot/freeldr/freeldr/arch/uefi/uefildr.c | 4 +- boot/freeldr/freeldr/arch/uefi/uefimem.c | 312 +++++++++++++++++++++ boot/freeldr/freeldr/arch/uefi/uefisetup.c | 4 +- boot/freeldr/freeldr/arch/uefi/uefiutil.c | 4 +- boot/freeldr/freeldr/arch/uefi/uefivid.c | 4 +- boot/freeldr/freeldr/include/debug.h | 3 + boot/freeldr/freeldr/lib/debug.c | 3 + boot/freeldr/freeldr/lib/mm/meminit.c | 2 + boot/freeldr/freeldr/uefi.cmake | 1 + 12 files changed, 346 insertions(+), 24 deletions(-) create mode 100644 boot/freeldr/freeldr/arch/uefi/uefimem.c diff --git a/boot/environ/include/efi/ProcessorBind.h b/boot/environ/include/efi/ProcessorBind.h index 3f73c61d478..bf1dd4c28a3 100644 --- a/boot/environ/include/efi/ProcessorBind.h +++ b/boot/environ/include/efi/ProcessorBind.h @@ -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 diff --git a/boot/freeldr/freeldr/arch/uefi/stubs.c b/boot/freeldr/freeldr/arch/uefi/stubs.c index b3d574fb00f..75f7ee0fc8b 100644 --- a/boot/freeldr/freeldr/arch/uefi/stubs.c +++ b/boot/freeldr/freeldr/arch/uefi/stubs.c @@ -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 */ @@ -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) { diff --git a/boot/freeldr/freeldr/arch/uefi/ueficon.c b/boot/freeldr/freeldr/arch/uefi/ueficon.c index 78c67d9c6e8..944d9707bc7 100644 --- a/boot/freeldr/freeldr/arch/uefi/ueficon.c +++ b/boot/freeldr/freeldr/arch/uefi/ueficon.c @@ -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 */ diff --git a/boot/freeldr/freeldr/arch/uefi/uefildr.c b/boot/freeldr/freeldr/arch/uefi/uefildr.c index e06ff9a1c5b..ded8e405f69 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefildr.c +++ b/boot/freeldr/freeldr/arch/uefi/uefildr.c @@ -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 */ diff --git a/boot/freeldr/freeldr/arch/uefi/uefimem.c b/boot/freeldr/freeldr/arch/uefi/uefimem.c new file mode 100644 index 00000000000..03a62150ef9 --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/uefimem.c @@ -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 + */ + +/* INCLUDES ******************************************************************/ + +#include + +#include +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); +} diff --git a/boot/freeldr/freeldr/arch/uefi/uefisetup.c b/boot/freeldr/freeldr/arch/uefi/uefisetup.c index bd223da465f..01d1be758a1 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefisetup.c +++ b/boot/freeldr/freeldr/arch/uefi/uefisetup.c @@ -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 */ diff --git a/boot/freeldr/freeldr/arch/uefi/uefiutil.c b/boot/freeldr/freeldr/arch/uefi/uefiutil.c index 9dafea22b6c..133adf20c64 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefiutil.c +++ b/boot/freeldr/freeldr/arch/uefi/uefiutil.c @@ -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 */ diff --git a/boot/freeldr/freeldr/arch/uefi/uefivid.c b/boot/freeldr/freeldr/arch/uefi/uefivid.c index 5bd869fcfd4..341798c4d85 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefivid.c +++ b/boot/freeldr/freeldr/arch/uefi/uefivid.c @@ -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 */ diff --git a/boot/freeldr/freeldr/include/debug.h b/boot/freeldr/freeldr/include/debug.h index e85582f8cea..feed051d013 100644 --- a/boot/freeldr/freeldr/include/debug.h +++ b/boot/freeldr/freeldr/include/debug.h @@ -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[]; diff --git a/boot/freeldr/freeldr/lib/debug.c b/boot/freeldr/freeldr/lib/debug.c index e68df9af9cf..b7a37977696 100644 --- a/boot/freeldr/freeldr/lib/debug.c +++ b/boot/freeldr/freeldr/lib/debug.c @@ -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]; diff --git a/boot/freeldr/freeldr/lib/mm/meminit.c b/boot/freeldr/freeldr/lib/mm/meminit.c index 37a705a0c68..aacccda4800 100644 --- a/boot/freeldr/freeldr/lib/mm/meminit.c +++ b/boot/freeldr/freeldr/lib/mm/meminit.c @@ -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) diff --git a/boot/freeldr/freeldr/uefi.cmake b/boot/freeldr/freeldr/uefi.cmake index 21710408dfc..94b5baa7630 100644 --- a/boot/freeldr/freeldr/uefi.cmake +++ b/boot/freeldr/freeldr/uefi.cmake @@ -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")