Use the memory mapped FV protocol to obtain the existing location in
memory and the size of an image being loaded from a firmware volume.
This removes the need to do a memcopy of the file data.

Signed-off-by: Ard Biesheuvel <a...@kernel.org>
---
 MdeModulePkg/Core/Dxe/DxeMain.h                |   1 +
 MdeModulePkg/Core/Dxe/DxeMain.inf              |   3 +
 MdeModulePkg/Core/Dxe/Image/Image.c            | 111 +++++++++++++++++---
 MdeModulePkg/Include/Protocol/MemoryMappedFv.h |  59 +++++++++++
 MdeModulePkg/MdeModulePkg.dec                  |   3 +
 5 files changed, 163 insertions(+), 14 deletions(-)

diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h
index 43daa037be441150..a695b457c79b65bb 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.h
+++ b/MdeModulePkg/Core/Dxe/DxeMain.h
@@ -45,6 +45,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Protocol/HiiPackageList.h>
 #include <Protocol/SmmBase2.h>
 #include <Protocol/PeCoffImageEmulator.h>
+#include <Protocol/MemoryMappedFv.h>
 #include <Guid/MemoryTypeInformation.h>
 #include <Guid/FirmwareFileSystem2.h>
 #include <Guid/FirmwareFileSystem3.h>
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf 
b/MdeModulePkg/Core/Dxe/DxeMain.inf
index 35d5bf0dee6f7f3f..a7175cb364b9b5de 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.inf
+++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -153,6 +153,9 @@ [Protocols]
   gEfiLoadedImageDevicePathProtocolGuid         ## PRODUCES
   gEfiHiiPackageListProtocolGuid                ## SOMETIMES_PRODUCES
   gEfiSmmBase2ProtocolGuid                      ## SOMETIMES_CONSUMES
+  ## PRODUCES
+  ## CONSUMES
+  gEdkiiMemoryMappedFvProtocolGuid
   gEdkiiPeCoffImageEmulatorProtocolGuid         ## SOMETIMES_CONSUMES
 
   # Arch Protocols
diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c 
b/MdeModulePkg/Core/Dxe/Image/Image.c
index f30e369370a09609..3dfab4829b3ca17f 100644
--- a/MdeModulePkg/Core/Dxe/Image/Image.c
+++ b/MdeModulePkg/Core/Dxe/Image/Image.c
@@ -1043,6 +1043,76 @@ CoreUnloadAndCloseImage (
   CoreFreePool (Image);
 }
 
+/**
+  Get the image file data and size directly from a memory mapped FV
+
+  If FilePath is NULL, then NULL is returned.
+  If FileSize is NULL, then NULL is returned.
+  If AuthenticationStatus is NULL, then NULL is returned.
+
+  @param[in]       FvHandle             The firmware volume handle
+  @param[in]       FilePath             The pointer to the device path of the 
file
+                                        that is abstracted to the file buffer.
+  @param[out]      FileSize             The pointer to the size of the 
abstracted
+                                        file buffer.
+  @param[out]      AuthenticationStatus Pointer to the authentication status.
+
+  @retval NULL   FilePath is NULL, or FileSize is NULL, or AuthenticationStatus
+                 is NULL, or the file is not memory mapped
+  @retval other  The abstracted file buffer.
+**/
+STATIC
+VOID *
+GetFileFromMemoryMappedFv (
+  IN  EFI_HANDLE                      FvHandle,
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL  *FilePath,
+  OUT UINTN                           *FileSize,
+  OUT UINT32                          *AuthenticationStatus
+  )
+{
+  EDKII_MEMORY_MAPPED_FV_PROTOCOL  *MemMappedFv;
+  CONST EFI_GUID                   *NameGuid;
+  EFI_PHYSICAL_ADDRESS             Address;
+  EFI_STATUS                       Status;
+
+  if ((FilePath == NULL) ||
+      (FileSize == NULL) ||
+      (AuthenticationStatus == NULL))
+  {
+    return NULL;
+  }
+
+  NameGuid = EfiGetNameGuidFromFwVolDevicePathNode (
+               (CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePath);
+  if (NameGuid == NULL) {
+    return NULL;
+  }
+
+  Status = gBS->HandleProtocol (
+                  FvHandle,
+                  &gEdkiiMemoryMappedFvProtocolGuid,
+                  (VOID **)&MemMappedFv
+                  );
+  if (EFI_ERROR (Status)) {
+    ASSERT (Status == EFI_UNSUPPORTED);
+    return NULL;
+  }
+
+  Status = MemMappedFv->GetLocationAndSize (
+                          MemMappedFv,
+                          NameGuid,
+                          EFI_SECTION_PE32,
+                          &Address,
+                          FileSize,
+                          AuthenticationStatus
+                          );
+  if (EFI_ERROR (Status) || (Address > (MAX_ADDRESS - *FileSize))) {
+    return NULL;
+  }
+
+  return (VOID *)(UINTN)Address;
+}
+
 /**
   Loads an EFI image into memory and returns a handle to the image.
 
@@ -1164,6 +1234,16 @@ CoreLoadImageCommon (
     Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, 
&HandleFilePath, &DeviceHandle);
     if (!EFI_ERROR (Status)) {
       ImageIsFromFv = TRUE;
+
+      //
+      // If possible, use the memory mapped file image directly, rather than 
copying it into a buffer
+      //
+      FHand.Source = GetFileFromMemoryMappedFv (
+                       DeviceHandle,
+                       HandleFilePath,
+                       &FHand.SourceSize,
+                       &AuthenticationStatus
+                       );
     } else {
       HandleFilePath = FilePath;
       Status         = CoreLocateDevicePath 
(&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);
@@ -1187,21 +1267,24 @@ CoreLoadImageCommon (
     //
     // Get the source file buffer by its device path.
     //
-    FHand.Source = GetFileBufferByFilePath (
-                     BootPolicy,
-                     FilePath,
-                     &FHand.SourceSize,
-                     &AuthenticationStatus
-                     );
     if (FHand.Source == NULL) {
-      Status = EFI_NOT_FOUND;
-    } else {
-      FHand.FreeBuffer = TRUE;
-      if (ImageIsFromLoadFile) {
-        //
-        // LoadFile () may cause the device path of the Handle be updated.
-        //
-        OriginalFilePath = AppendDevicePath (DevicePathFromHandle 
(DeviceHandle), Node);
+      FHand.Source = GetFileBufferByFilePath (
+                       BootPolicy,
+                       FilePath,
+                       &FHand.SourceSize,
+                       &AuthenticationStatus
+                       );
+
+      if (FHand.Source == NULL) {
+        Status = EFI_NOT_FOUND;
+      } else {
+        FHand.FreeBuffer = TRUE;
+        if (ImageIsFromLoadFile) {
+          //
+          // LoadFile () may cause the device path of the Handle be updated.
+          //
+          OriginalFilePath = AppendDevicePath (DevicePathFromHandle 
(DeviceHandle), Node);
+        }
       }
     }
   }
diff --git a/MdeModulePkg/Include/Protocol/MemoryMappedFv.h 
b/MdeModulePkg/Include/Protocol/MemoryMappedFv.h
new file mode 100644
index 0000000000000000..821009122113a658
--- /dev/null
+++ b/MdeModulePkg/Include/Protocol/MemoryMappedFv.h
@@ -0,0 +1,59 @@
+/** @file
+  Protocol to obtain information about files in memory mapped firmware volumes
+
+  Copyright (c) 2023, Google LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef EDKII_MEMORY_MAPPED_FV_H_
+#define EDKII_MEMORY_MAPPED_FV_H_
+
+#define EDKII_MEMORY_MAPPED_FV_PROTOCOL_GUID \
+  { 0xb9bfa973, 0x5384, 0x441e, { 0xa4, 0xe7, 0x20, 0xe6, 0x5d, 0xaf, 0x2e, 
0x0f } }
+
+typedef struct _EDKII_MEMORY_MAPPED_FV_PROTOCOL 
EDKII_MEMORY_MAPPED_FV_PROTOCOL;
+
+//
+// Function Prototypes
+//
+
+/**
+  Get the physical address and size of a file's section in a memory mapped FV
+
+  @param[in]  This          The protocol pointer
+  @param[in]  NameGuid      The name GUID of the file
+  @param[in]  SectionType   The file section from which to retrieve address 
and size
+  @param[out] FileAddress   The physical address of the file
+  @param[out] FileSize      The size of the file
+  @param[out] AuthStatus    The authentication status associated with the file
+
+  @retval EFI_SUCCESS            Information about the file was retrieved 
successfully.
+  @retval EFI_INVALID_PARAMETER  FileAddress was NULL, FileSize was NULL, 
AuthStatus
+                                 was NULL.
+  @retval EFI_NOT_FOUND          No section of the specified type could be 
located in
+                                 the specified file.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *GET_LOCATION_AND_SIZE)(
+  IN  EDKII_MEMORY_MAPPED_FV_PROTOCOL  *This,
+  IN  CONST EFI_GUID                   *NameGuid,
+  IN  EFI_SECTION_TYPE                 SectionType,
+  OUT EFI_PHYSICAL_ADDRESS             *FileAddress,
+  OUT UINTN                            *FileSize,
+  OUT UINT32                           *AuthStatus
+  );
+
+//
+// Protocol interface structure
+//
+struct _EDKII_MEMORY_MAPPED_FV_PROTOCOL {
+  GET_LOCATION_AND_SIZE   GetLocationAndSize;
+};
+
+extern EFI_GUID  gEdkiiMemoryMappedFvProtocolGuid;
+
+#endif
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index d65dae18aa81e569..2d72ac733d82195e 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -679,6 +679,9 @@ [Protocols]
   ## Include/Protocol/PlatformBootManager.h
   gEdkiiPlatformBootManagerProtocolGuid = { 0xaa17add4, 0x756c, 0x460d, { 
0x94, 0xb8, 0x43, 0x88, 0xd7, 0xfb, 0x3e, 0x59 } }
 
+  ## Include/Protocol/MemoryMappedFv.h
+  gEdkiiMemoryMappedFvProtocolGuid = { 0xb9bfa973, 0x5384, 0x441e, { 0xa4, 
0xe7, 0x20, 0xe6, 0x5d, 0xaf, 0x2e, 0x0f } }
+
 #
 # [Error.gEfiMdeModulePkgTokenSpaceGuid]
 #   0x80000001 | Invalid value provided.
-- 
2.39.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#105367): https://edk2.groups.io/g/devel/message/105367
Mute This Topic: https://groups.io/mt/99197138/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to