[edk2,5/6] MdePkg/BasePeCoffLib: relocate for runtime using ConvertPointer callback

Message ID 1435916407-29683-6-git-send-email-ard.biesheuvel@linaro.org
State New
Headers show

Commit Message

Ard Biesheuvel July 3, 2015, 9:40 a.m.
The OS is not required to preserve the relative offsets between
RuntimeServicesCode and RuntimeServicesData memory regions when
switching to virtual mode. This does not present any problems as
long as PE/COFF images in memory are covered by only a single region.

However, with the introduction of the MemoryProtectionAttribute feature
in UEFI v2.5, the firmware may decide to split those regions into
separate code and data regions. So rather than reapplying the relocations
for the entire image based on a single adjustment value (which is derived
from the physical to virtual shift of ImageBase), we need to invoke
ConvertPointer () on each relocation target.

So modify PeCoffLoaderRelocateImageForRuntime () to take a callback
function pointer instead of a fixed adjustment value, and invoke the
callback for each re-relocated value.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 MdePkg/Include/Library/PeCoffLib.h                    | 28 ++++++++++++----
 MdePkg/Library/BasePeCoffLib/Arm/PeCoffLoaderEx.c     | 19 ++++++-----
 MdePkg/Library/BasePeCoffLib/BasePeCoff.c             | 35 +++++++++++---------
 MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h | 16 ++++-----
 MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c     | 32 +++++++++---------
 MdePkg/Library/BasePeCoffLib/PeCoffLoaderEx.c         | 16 ++++-----
 6 files changed, 83 insertions(+), 63 deletions(-)

Patch hide | download patch | download mbox

diff --git a/MdePkg/Include/Library/PeCoffLib.h b/MdePkg/Include/Library/PeCoffLib.h
index 9ed6d61be01c..ed75f3613306 100644
--- a/MdePkg/Include/Library/PeCoffLib.h
+++ b/MdePkg/Include/Library/PeCoffLib.h
@@ -335,6 +335,22 @@  PeCoffLoaderImageReadFromMemory (
   OUT    VOID    *Buffer
   );
 
+/**
+  Translates a physical to virtual address for PE/COFF runtime re-relocation
+
+  @param[in, out]  Address      A pointer to a pointer that is to be fixed to be the value needed
+                                for the new virtual address mappings being applied.
+
+  @retval EFI_SUCCESS           The pointer pointed to by Address was modified.
+  @retval EFI_INVALID_PARAMETER Address is NULL.
+  @retval EFI_NOT_FOUND         The value pointed to by Address could not be converted.
+
+**/
+typedef
+RETURN_STATUS
+(EFIAPI *PE_COFF_LOADER_CONVERT_POINTER) (
+  IN OUT VOID                       **Address
+  );
 
 /**
   Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
@@ -352,8 +368,8 @@  PeCoffLoaderImageReadFromMemory (
 
   @param  ImageBase          The base address of a PE/COFF image that has been loaded 
                              and relocated into system memory.
-  @param  VirtImageBase      The request virtual address that the PE/COFF image is to
-                             be fixed up for.
+  @param  ConvertPointer     Address of a PE_COFF_LOADER_CONVERT_POINTER callback function
+                             that performs physical to virtual conversions
   @param  ImageSize          The size, in bytes, of the PE/COFF image.
   @param  RelocationData     A pointer to the relocation data that was collected when the PE/COFF 
                              image was relocated using PeCoffLoaderRelocateImage().
@@ -362,10 +378,10 @@  PeCoffLoaderImageReadFromMemory (
 VOID
 EFIAPI
 PeCoffLoaderRelocateImageForRuntime (
-  IN  PHYSICAL_ADDRESS        ImageBase,
-  IN  PHYSICAL_ADDRESS        VirtImageBase,
-  IN  UINTN                   ImageSize,
-  IN  VOID                    *RelocationData
+  IN  PHYSICAL_ADDRESS                 ImageBase,
+  IN  PE_COFF_LOADER_CONVERT_POINTER   ConvertPointer,
+  IN  UINTN                            ImageSize,
+  IN  VOID                             *RelocationData
   );
 
 /**
diff --git a/MdePkg/Library/BasePeCoffLib/Arm/PeCoffLoaderEx.c b/MdePkg/Library/BasePeCoffLib/Arm/PeCoffLoaderEx.c
index d6bf42738d2b..ba09e1f16018 100644
--- a/MdePkg/Library/BasePeCoffLib/Arm/PeCoffLoaderEx.c
+++ b/MdePkg/Library/BasePeCoffLib/Arm/PeCoffLoaderEx.c
@@ -205,20 +205,20 @@  PeCoffLoaderImageFormatSupported (
   instruction sets. This is used to re-relocated the image into the EFI virtual
   space for runtime calls.
 
-  @param  Reloc       The pointer to the relocation record.
-  @param  Fixup       The pointer to the address to fix up.
-  @param  FixupData   The pointer to a buffer to log the fixups.
-  @param  Adjust      The offset to adjust the fixup.
+  @param  Reloc           The pointer to the relocation record.
+  @param  Fixup           The pointer to the address to fix up.
+  @param  FixupData       The pointer to a buffer to log the fixups.
+  @param  ConvertPointer  Pointer to a physical to virtual conversion function
 
   @return Status code.
 
 **/
 RETURN_STATUS
 PeHotRelocateImageEx (
-  IN UINT16      *Reloc,
-  IN OUT CHAR8   *Fixup,
-  IN OUT CHAR8   **FixupData,
-  IN UINT64      Adjust
+  IN UINT16                           *Reloc,
+  IN OUT CHAR8                        *Fixup,
+  IN OUT CHAR8                        **FixupData,
+  IN PE_COFF_LOADER_CONVERT_POINTER   ConvertPointer
   )
 {
   UINT16  *Fixup16;
@@ -231,7 +231,8 @@  PeHotRelocateImageEx (
   case EFI_IMAGE_REL_BASED_ARM_MOV32T:
     *FixupData  = ALIGN_POINTER (*FixupData, sizeof (UINT64));
     if (*(UINT64 *) (*FixupData) == ReadUnaligned64 ((UINT64 *)Fixup16)) {
-      FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust;
+      FixupVal = ThumbMovwMovtImmediateAddress (Fixup16);
+      ConvertPointer ((VOID **) &FixupVal);
       ThumbMovwMovtImmediatePatch (Fixup16, FixupVal);
     }
     break;
diff --git a/MdePkg/Library/BasePeCoffLib/BasePeCoff.c b/MdePkg/Library/BasePeCoffLib/BasePeCoff.c
index 23cb691ad729..e4de6fae7ce9 100644
--- a/MdePkg/Library/BasePeCoffLib/BasePeCoff.c
+++ b/MdePkg/Library/BasePeCoffLib/BasePeCoff.c
@@ -1692,8 +1692,8 @@  PeCoffLoaderLoadImage (
 
   @param  ImageBase          The base address of a PE/COFF image that has been loaded 
                              and relocated into system memory.
-  @param  VirtImageBase      The request virtual address that the PE/COFF image is to
-                             be fixed up for.
+  @param  ConvertPointer     Address of a PE_COFF_LOADER_CONVERT_POINTER callback function
+                             that performs physical to virtual conversions
   @param  ImageSize          The size, in bytes, of the PE/COFF image.
   @param  RelocationData     A pointer to the relocation data that was collected when the PE/COFF 
                              image was relocated using PeCoffLoaderRelocateImage().
@@ -1702,14 +1702,13 @@  PeCoffLoaderLoadImage (
 VOID
 EFIAPI
 PeCoffLoaderRelocateImageForRuntime (
-  IN  PHYSICAL_ADDRESS        ImageBase,
-  IN  PHYSICAL_ADDRESS        VirtImageBase,
-  IN  UINTN                   ImageSize,
-  IN  VOID                    *RelocationData
+  IN  PHYSICAL_ADDRESS                 ImageBase,
+  IN  PE_COFF_LOADER_CONVERT_POINTER   ConvertPointer,
+  IN  UINTN                            ImageSize,
+  IN  VOID                             *RelocationData
   )
 {
   CHAR8                               *OldBase;
-  CHAR8                               *NewBase;
   EFI_IMAGE_DOS_HEADER                *DosHdr;
   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
   UINT32                              NumberOfRvaAndSizes;
@@ -1725,15 +1724,13 @@  PeCoffLoaderRelocateImageForRuntime (
   UINT32                              *Fixup32;
   UINT64                              *Fixup64;
   CHAR8                               *FixupData;
-  UINTN                               Adjust;
   RETURN_STATUS                       Status;
   UINT16                              Magic;
   UINT8                               HighLowMask [SIZE_4KB / (8 * sizeof(UINT32))];
   UINTN                               HighLowMaskIndex;
+  UINTN                               ConvertAddress;
 
   OldBase = (CHAR8 *)((UINTN)ImageBase);
-  NewBase = (CHAR8 *)((UINTN)VirtImageBase);
-  Adjust = (UINTN) NewBase - (UINTN) OldBase;
 
   //
   // Find the image's relocate dir info
@@ -1842,7 +1839,9 @@  PeCoffLoaderRelocateImageForRuntime (
         if (*(UINT32 *) FixupData == *Fixup32 ||
             (HighLowMask [HighLowMaskIndex >> 3] & (1 << (HighLowMaskIndex & 7))) != 0) {
 
-          *Fixup16 = (UINT16) ((*Fixup32 + (UINT32) Adjust) >> 16);
+          ConvertAddress = *(UINT32 *) FixupData;
+          ConvertPointer ((VOID **) &ConvertAddress);
+          *Fixup16 = (UINT16) (ConvertAddress >> 16);
 
           //
           // Mark this location in the page as requiring the low relocation to
@@ -1862,7 +1861,9 @@  PeCoffLoaderRelocateImageForRuntime (
         if (*(UINT32 *) FixupData == *(UINT32 *)Fixup ||
             (HighLowMask [HighLowMaskIndex >> 3] & (1 << (HighLowMaskIndex & 7))) != 0) {
 
-          *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) Adjust & 0xffff));
+          ConvertAddress = *(UINT32 *) FixupData;
+          ConvertPointer ((VOID **) &ConvertAddress);
+          *Fixup16 = (UINT16) (ConvertAddress & 0xffff);
 
           //
           // Mark this location in the page as requiring the high relocation to
@@ -1879,7 +1880,9 @@  PeCoffLoaderRelocateImageForRuntime (
         Fixup32       = (UINT32 *) Fixup;
         FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
         if (*(UINT32 *) FixupData == *Fixup32) {
-          *Fixup32 = *Fixup32 + (UINT32) Adjust;
+          ConvertAddress = *Fixup32;
+          ConvertPointer ((VOID **) &ConvertAddress);
+          *Fixup32 = (UINT32) ConvertAddress;
         }
 
         FixupData = FixupData + sizeof (UINT32);
@@ -1889,7 +1892,9 @@  PeCoffLoaderRelocateImageForRuntime (
         Fixup64       = (UINT64 *)Fixup;
         FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
         if (*(UINT64 *) FixupData == *Fixup64) {
-          *Fixup64 = *Fixup64 + (UINT64)Adjust;
+          ConvertAddress = (UINTN) *Fixup64;
+          ConvertPointer ((VOID **) &ConvertAddress);
+          *Fixup64 = ConvertAddress;
         }
 
         FixupData = FixupData + sizeof (UINT64);
@@ -1899,7 +1904,7 @@  PeCoffLoaderRelocateImageForRuntime (
         //
         // Only Itanium requires ConvertPeImage_Ex
         //
-        Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
+        Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, ConvertPointer);
         if (RETURN_ERROR (Status)) {
           return ;
         }
diff --git a/MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h b/MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h
index 0851acc18c19..9ffc59318f9b 100644
--- a/MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h
+++ b/MdePkg/Library/BasePeCoffLib/BasePeCoffLibInternals.h
@@ -50,20 +50,20 @@  PeCoffLoaderRelocateImageEx (
   instruction sets. This is used to re-relocated the image into the EFI virtual
   space for runtime calls.
 
-  @param  Reloc       The pointer to the relocation record.
-  @param  Fixup       The pointer to the address to fix up.
-  @param  FixupData   The pointer to a buffer to log the fixups.
-  @param  Adjust      The offset to adjust the fixup.
+  @param  Reloc           The pointer to the relocation record.
+  @param  Fixup           The pointer to the address to fix up.
+  @param  FixupData       The pointer to a buffer to log the fixups.
+  @param  ConvertPointer  Pointer to a physical to virtual conversion function
 
   @return Status code.
 
 **/
 RETURN_STATUS
 PeHotRelocateImageEx (
-  IN UINT16      *Reloc,
-  IN OUT CHAR8   *Fixup,
-  IN OUT CHAR8   **FixupData,
-  IN UINT64      Adjust
+  IN UINT16                           *Reloc,
+  IN OUT CHAR8                        *Fixup,
+  IN OUT CHAR8                        **FixupData,
+  IN PE_COFF_LOADER_CONVERT_POINTER   ConvertPointer
   );
 
 
diff --git a/MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c b/MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c
index a590f3906fab..bd371a33a445 100644
--- a/MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c
+++ b/MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c
@@ -242,25 +242,23 @@  PeCoffLoaderImageFormatSupported (
 
 
 /**
-  ImageRead function that operates on a memory buffer whos base is passed into
-  FileHandle.
-
-  @param  Reloc             Ponter to baes of the input stream
-  @param  Fixup             Offset to the start of the buffer
-  @param  FixupData         The number of bytes to copy into the buffer
-  @param  Adjust            Location to place results of read
-
-  @retval RETURN_SUCCESS    Data is read from FileOffset from the Handle into
-                            the buffer.
-  @retval RETURN_UNSUPPORTED Un-recoganized relocation entry
-                             type.
+  Performs an Itanium-based specific re-relocation fixup and is a no-op on other
+  instruction sets. This is used to re-relocated the image into the EFI virtual
+  space for runtime calls.
+
+  @param  Reloc           The pointer to the relocation record.
+  @param  Fixup           The pointer to the address to fix up.
+  @param  FixupData       The pointer to a buffer to log the fixups.
+  @param  ConvertPointer  Pointer to a physical to virtual conversion function
+
+  @return Status code.
 **/
 RETURN_STATUS
 PeHotRelocateImageEx (
-  IN UINT16      *Reloc,
-  IN OUT CHAR8   *Fixup,
-  IN OUT CHAR8   **FixupData,
-  IN UINT64      Adjust
+  IN UINT16                           *Reloc,
+  IN OUT CHAR8                        *Fixup,
+  IN OUT CHAR8                        **FixupData,
+  IN PE_COFF_LOADER_CONVERT_POINTER   ConvertPointer
   )
 {
   UINT64  *Fixup64;
@@ -325,7 +323,7 @@  PeHotRelocateImageEx (
       //
       // Update 64-bit address
       //
-      FixupVal += Adjust;
+      ConvertPointer ((VOID **) &FixupVal);
 
       //
       // Insert IMM64 into bundle
diff --git a/MdePkg/Library/BasePeCoffLib/PeCoffLoaderEx.c b/MdePkg/Library/BasePeCoffLib/PeCoffLoaderEx.c
index 01825c85392b..8ddf6fe722f8 100644
--- a/MdePkg/Library/BasePeCoffLib/PeCoffLoaderEx.c
+++ b/MdePkg/Library/BasePeCoffLib/PeCoffLoaderEx.c
@@ -69,20 +69,20 @@  PeCoffLoaderImageFormatSupported (
   instruction sets. This is used to re-relocated the image into the EFI virtual
   space for runtime calls.
 
-  @param  Reloc       The pointer to the relocation record.
-  @param  Fixup       The pointer to the address to fix up.
-  @param  FixupData   The pointer to a buffer to log the fixups.
-  @param  Adjust      The offset to adjust the fixup.
+  @param  Reloc           The pointer to the relocation record.
+  @param  Fixup           The pointer to the address to fix up.
+  @param  FixupData       The pointer to a buffer to log the fixups.
+  @param  ConvertPointer  Pointer to a physical to virtual conversion function
 
   @return Status code.
 
 **/
 RETURN_STATUS
 PeHotRelocateImageEx (
-  IN UINT16      *Reloc,
-  IN OUT CHAR8   *Fixup,
-  IN OUT CHAR8   **FixupData,
-  IN UINT64      Adjust
+  IN UINT16                           *Reloc,
+  IN OUT CHAR8                        *Fixup,
+  IN OUT CHAR8                        **FixupData,
+  IN PE_COFF_LOADER_CONVERT_POINTER   ConvertPointer
   )
 {
   return RETURN_UNSUPPORTED;