https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ccef43f3b0dcc2ee472d4…
commit ccef43f3b0dcc2ee472d497ae09cf8ead9c0bf06
Author: Justin Miller <justinmiller100(a)gmail.com>
AuthorDate: Mon Apr 3 08:33:20 2023 -0700
Commit: GitHub <noreply(a)github.com>
CommitDate: Mon Apr 3 17:33:20 2023 +0200
[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(-)
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 <justinmiller100(a)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)
{
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 <justinmiller100(a)gmail.com>
*/
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 <justinmiller100(a)gmail.com>
*/
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 <justinmiller100(a)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);
+}
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 <justinmiller100(a)gmail.com>
*/
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 <justinmiller100(a)gmail.com>
*/
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 <justinmiller100(a)gmail.com>
*/
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")