public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Ard Biesheuvel" <ardb@kernel.org>
To: devel@edk2.groups.io
Cc: Ard Biesheuvel <ardb@kernel.org>, Ray Ni <ray.ni@intel.com>,
	Jiewen Yao <jiewen.yao@intel.com>,
	Gerd Hoffmann <kraxel@redhat.com>,
	Taylor Beebe <t@taylorbeebe.com>,
	Oliver Smith-Denny <osd@smith-denny.com>,
	Dandan Bi <dandan.bi@intel.com>,
	Liming Gao <gaoliming@byosoft.com.cn>,
	"Kinney, Michael D" <michael.d.kinney@intel.com>,
	Leif Lindholm <quic_llindhol@quicinc.com>,
	Michael Kubacki <mikuback@linux.microsoft.com>
Subject: [RFC PATCH 08/11] MdeModulePkg/DxeIpl: Relocate and remap XIP capable DXE drivers
Date: Mon, 29 May 2023 12:17:02 +0200	[thread overview]
Message-ID: <20230529101705.2476949-9-ardb@kernel.org> (raw)
In-Reply-To: <20230529101705.2476949-1-ardb@kernel.org>

Before handing over to the DXE core, iterate over all known FFS files
and find the ones that can execute in place. These files are then
relocated in place and mapped with restricted permissions, allowing the
DXE core to dispatch them without the need to perform any manipulation
of the file contents or the page table permissions.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf |   1 +
 MdeModulePkg/Core/DxeIplPeim/DxeLoad.c  | 196 ++++++++++++++++++++
 2 files changed, 197 insertions(+)

diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
index f1990eac77607854..60112100df78b396 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
@@ -65,6 +65,7 @@ [LibraryClasses]
   PeimEntryPoint
   DebugLib
   DebugAgentLib
+  PeCoffLib
   PeiServicesTablePointerLib
   PerformanceLib
 
diff --git a/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c b/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
index 2c19f1a507baf34a..1f20db1faffbd1d2 100644
--- a/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
+++ b/MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
@@ -10,6 +10,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #include "DxeIpl.h"
 
+#include <Library/PeCoffLib.h>
+#include <Ppi/MemoryAttribute.h>
+
 //
 // Module Globals used in the DXE to PEI hand off
 // These must be module globals, so the stack can be switched
@@ -228,6 +231,197 @@ ValidateMemoryTypeInfoVariable (
   return TRUE;
 }
 
+/**
+  Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.
+  The function is used for XIP code to have optimized memory copy.
+
+  @param FileHandle      The handle to the PE/COFF file
+  @param FileOffset      The offset, in bytes, into the file to read
+  @param ReadSize        The number of bytes to read from the file starting at FileOffset
+  @param Buffer          A pointer to the buffer to read the data into.
+
+  @return EFI_SUCCESS    ReadSize bytes of data were read into Buffer from the
+                         PE/COFF file starting at FileOffset
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+PeiImageRead (
+  IN     VOID   *FileHandle,
+  IN     UINTN  FileOffset,
+  IN     UINTN  *ReadSize,
+  OUT    VOID   *Buffer
+  )
+{
+  CHAR8  *Destination8;
+  CHAR8  *Source8;
+
+  Destination8 = Buffer;
+  Source8      = (CHAR8 *)((UINTN)FileHandle + FileOffset);
+  if (Destination8 != Source8) {
+    CopyMem (Destination8, Source8, *ReadSize);
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+RemapImage (
+  IN  EDKII_MEMORY_ATTRIBUTE_PPI          *MemoryPpi,
+  IN  CONST PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  )
+{
+  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
+  EFI_IMAGE_SECTION_HEADER             *Section;
+  PHYSICAL_ADDRESS                     SectionAddress;
+  EFI_STATUS                           Status;
+  UINT64                               Permissions;
+  UINTN                                Index;
+
+  if (MemoryPpi == NULL) {
+    return;
+  }
+
+  Hdr.Union = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINT8 *)ImageContext->Handle +
+                                                  ImageContext->PeCoffHeaderOffset);
+  ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE);
+
+  Section = (EFI_IMAGE_SECTION_HEADER *)((UINT8 *)Hdr.Union + sizeof (UINT32) +
+                                         sizeof (EFI_IMAGE_FILE_HEADER) +
+                                         Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+                                         );
+
+  for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+    SectionAddress = ImageContext->ImageAddress + Section[Index].VirtualAddress;
+    Permissions    = 0;
+
+    if ((Section[Index].Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0) {
+      Permissions |= EFI_MEMORY_RO;
+    }
+
+    if ((Section[Index].Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) {
+      Permissions |= EFI_MEMORY_XP;
+    }
+
+    Status = MemoryPpi->SetPermissions (
+                          MemoryPpi,
+                          SectionAddress,
+                          Section[Index].Misc.VirtualSize,
+                          Permissions,
+                          Permissions ^ EFI_MEMORY_RO ^ EFI_MEMORY_XP
+                          );
+    ASSERT_EFI_ERROR (Status);
+  }
+}
+
+STATIC
+VOID
+RelocateAndRemapDriversInPlace (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+  UINTN                         Instance;
+  EFI_PEI_FV_HANDLE             VolumeHandle;
+  EFI_PEI_FILE_HANDLE           FileHandle;
+  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
+  UINT32                        AuthenticationState;
+  EDKII_MEMORY_ATTRIBUTE_PPI    *MemoryPpi;
+
+  MemoryPpi = NULL;
+  PeiServicesLocatePpi (&gEdkiiMemoryAttributePpiGuid, 0, NULL, (VOID **)&MemoryPpi);
+
+  Instance = 0;
+  do {
+    //
+    // Traverse all firmware volume instances
+    //
+    Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
+    if (Status == EFI_NOT_FOUND) {
+      return;
+    }
+
+    ASSERT_EFI_ERROR (Status);
+
+    FileHandle = NULL;
+    do {
+      Status = PeiServicesFfsFindNextFile (
+                 EFI_FV_FILETYPE_DRIVER,
+                 VolumeHandle,
+                 &FileHandle);
+      if (Status == EFI_NOT_FOUND) {
+        break;
+      }
+
+      ASSERT_EFI_ERROR (Status);
+
+      ZeroMem (&ImageContext, sizeof (ImageContext));
+
+      Status = PeiServicesFfsFindSectionData3 (
+                 EFI_SECTION_PE32,
+                 0,
+                 FileHandle,
+                 &ImageContext.Handle,
+                 &AuthenticationState
+                 );
+      if (Status == EFI_NOT_FOUND) {
+        continue;
+      }
+
+      ASSERT_EFI_ERROR (Status);
+
+      ImageContext.ImageRead = PeiImageRead;
+      Status                 = PeCoffLoaderGetImageInfo (&ImageContext);
+      if (EFI_ERROR (Status)) {
+        ASSERT_EFI_ERROR (Status);
+        continue;
+      }
+
+      ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)ImageContext.Handle;
+      if ((ImageContext.ImageAddress & (ImageContext.SectionAlignment - 1)) != 0) {
+        DEBUG ((DEBUG_VERBOSE, "%a: skip PE image at %p\n", __func__, ImageContext.Handle));
+        continue;
+      }
+
+      DEBUG ((
+        DEBUG_INFO,
+        "%a: relocate PE image at %p for execution in place\n",
+        __func__,
+        ImageContext.Handle
+        ));
+
+      //
+      // 'Load' the image in-place - this just performs a sanity check on
+      // the PE metadata but does not actually move any data
+      //
+      Status = PeCoffLoaderLoadImage (&ImageContext);
+      if (EFI_ERROR (Status)) {
+        ASSERT_EFI_ERROR (Status);
+        continue;
+      }
+
+      //
+      // Relocate this driver in place
+      //
+      Status = PeCoffLoaderRelocateImage (&ImageContext);
+      if (EFI_ERROR (Status)) {
+        ASSERT_EFI_ERROR (Status);
+        continue;
+      }
+
+      //
+      // Apply section permissions to the page tables
+      //
+      RemapImage (MemoryPpi, &ImageContext);
+
+    } while (TRUE);
+
+    Instance++;
+  } while (TRUE);
+}
+
 /**
    Main entry point to last PEIM.
 
@@ -436,6 +630,8 @@ DxeLoadCore (
     DxeCoreEntryPoint
     );
 
+  RelocateAndRemapDriversInPlace ();
+
   //
   // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
   //
-- 
2.39.2


  parent reply	other threads:[~2023-05-29 10:17 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-29 10:16 [RFC PATCH 00/11] Permit DXE drivers to execute in place Ard Biesheuvel
2023-05-29 10:16 ` [RFC PATCH 01/11] MdeModulePkg/DxeCore: Remove unused 'EntryPoint' argument to LoadImage Ard Biesheuvel
2023-05-30  5:54   ` Ni, Ray
2023-05-30  7:36     ` Ard Biesheuvel
2023-05-29 10:16 ` [RFC PATCH 02/11] MdeModulePkg/DxeCore: Remove unused DstBuffer arg from LoadImage Ard Biesheuvel
2023-05-30  5:58   ` Ni, Ray
2023-05-29 10:16 ` [RFC PATCH 03/11] MdeModulePkg/DxeCore: Remove FreePage argument from CoreUnloadImage Ard Biesheuvel
2023-05-30  5:59   ` Ni, Ray
2023-05-29 10:16 ` [RFC PATCH 04/11] MdeModulePkg/DxeCore: Avoid caching memory mapped FFS files Ard Biesheuvel
2023-05-30  6:03   ` Ni, Ray
2023-05-30  7:47     ` Ard Biesheuvel
2023-05-29 10:16 ` [RFC PATCH 05/11] MdeModulePkg/DxeCore: Use memory mapped FV protocol to avoid image copy Ard Biesheuvel
2023-05-30  6:21   ` Ni, Ray
2023-05-30  7:51     ` [edk2-devel] " Ard Biesheuvel
2023-05-30  8:40       ` Ni, Ray
2023-05-30  8:51         ` Ard Biesheuvel
2023-05-29 10:17 ` [RFC PATCH 06/11] MdeModulePkg/DxeCore: Expose memory mapped FV protocol when possible Ard Biesheuvel
2023-05-30  6:22   ` Ni, Ray
2023-05-29 10:17 ` [RFC PATCH 07/11] MdeModulePkg/DxeCore: Execute loaded images in place if possible Ard Biesheuvel
2023-05-30  6:32   ` Ni, Ray
2023-05-30  7:54     ` Ard Biesheuvel
2023-05-29 10:17 ` Ard Biesheuvel [this message]
2023-05-30  6:45   ` [edk2-devel] [RFC PATCH 08/11] MdeModulePkg/DxeIpl: Relocate and remap XIP capable DXE drivers Ni, Ray
2023-05-30  7:58     ` Ard Biesheuvel
2023-05-30  8:02       ` Ni, Ray
2023-05-30  8:29         ` Ard Biesheuvel
2023-05-30  9:06       ` Marvin Häuser
2023-05-30  9:18         ` Marvin Häuser
2023-05-30  9:38         ` Ard Biesheuvel
2023-05-30  9:41           ` Marvin Häuser
2023-05-30  9:47             ` Ard Biesheuvel
2023-05-30  9:48               ` Ard Biesheuvel
2023-05-30  9:52                 ` Marvin Häuser
2023-05-30 10:02                   ` Ard Biesheuvel
2023-05-30 10:25                     ` Marvin Häuser
2023-05-31  7:13                       ` Ni, Ray
2023-05-31  8:05                         ` Marvin Häuser
2023-05-29 10:17 ` [RFC PATCH 09/11] MdeModulePkg/DxeCore: Add PCD NX policy bit for default NX state Ard Biesheuvel
2023-05-30  6:54   ` Ni, Ray
2023-05-30  8:33     ` Ard Biesheuvel
2023-05-29 10:17 ` [RFC PATCH 10/11] ArmVirtPkg/ArmVirtQemu: Allow CPU arch protocol DXE to execute in place Ard Biesheuvel
2023-05-29 10:17 ` [RFC PATCH 11/11] ArmVirtPkg/ArmVirtQemu: Map all DRAM non-execute by default Ard Biesheuvel
2023-06-01 14:53 ` [edk2-devel] [RFC PATCH 00/11] Permit DXE drivers to execute in place Oliver Smith-Denny
2023-06-01 18:11   ` Ard Biesheuvel
2023-06-01 18:30     ` Oliver Smith-Denny

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230529101705.2476949-9-ardb@kernel.org \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox