https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ccef43f3b0dcc2ee472d497ae09cf8ead9c0bf06

commit ccef43f3b0dcc2ee472d497ae09cf8ead9c0bf06
Author:     Justin Miller <[email protected]>
AuthorDate: Mon Apr 3 08:33:20 2023 -0700
Commit:     GitHub <[email protected]>
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 <[email protected]>
  */
 
@@ -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 <[email protected]>
  */
 
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 <[email protected]>
  */
 
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 <[email protected]>
+ */
+
+/* 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 <[email protected]>
  */
 
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 <[email protected]>
  */
 
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 <[email protected]>
  */
 
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")

Reply via email to