diff --git a/MdeModulePkg/Core/RuntimeDxe/Runtime.c b/MdeModulePkg/Core/RuntimeDxe/Runtime.c
index c61301cf80d8..c8dbfdd5a3ef 100644
--- a/MdeModulePkg/Core/RuntimeDxe/Runtime.c
+++ b/MdeModulePkg/Core/RuntimeDxe/Runtime.c
@@ -213,6 +213,232 @@ RuntimeDriverConvertInternalPointer (
 }
 
 /**
+  Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
+  runtime.
+
+  This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
+  and ImageSize so the image will execute correctly when the PE/COFF image is mapped
+  to the address specified by VirtualImageBase.  RelocationData must be identical
+  to the FixupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
+  after this PE/COFF image was relocated with BasePecoffLib::PeCoffLoaderRelocateImage().
+
+  Note that if the platform does not maintain coherency between the instruction cache(s) and the data
+  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
+  prior to transferring control to a PE/COFF image that is loaded using this funation.
+
+  @param  ImageBase          The base address of a PE/COFF image that has been loaded
+                             and relocated into system memory.
+  @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().
+
+  @return EFI_SUCCESS        The fixups have been reapplied successfully.
+
+  @return EFI_UNSUPPORTED    ImageBase does not point to a valid PE image
+  @return EFI_UNSUPPORTED    No reloc directory found or contents invalid
+  @return EFI_UNSUPPORTED    Image uses high/low relocations and section alignment < 64 KB
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+RuntimeDriverRelocateImageForRuntime (
+  IN  PHYSICAL_ADDRESS        ImageBase,
+  IN  UINTN                   ImageSize,
+  IN  VOID                    *RelocationData
+  )
+{
+  CHAR8                               *OldBase;
+  EFI_IMAGE_DOS_HEADER                *DosHdr;
+  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+  UINT32                              NumberOfRvaAndSizes;
+  EFI_IMAGE_DATA_DIRECTORY            *DataDirectory;
+  EFI_IMAGE_DATA_DIRECTORY            *RelocDir;
+  EFI_IMAGE_BASE_RELOCATION           *RelocBase;
+  EFI_IMAGE_BASE_RELOCATION           *RelocBaseEnd;
+  UINT16                              *Reloc;
+  UINT16                              *RelocEnd;
+  CHAR8                               *Fixup;
+  CHAR8                               *FixupBase;
+  UINT16                              *Fixup16;
+  UINT32                              *Fixup32;
+  UINT64                              *Fixup64;
+  CHAR8                               *FixupData;
+  UINT16                              Magic;
+  UINTN                               ConvertAddress;
+
+  OldBase = (CHAR8 *)((UINTN)ImageBase);
+
+  //
+  // Find the image's relocate dir info
+  //
+  DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;
+  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+    //
+    // Valid DOS header so get address of PE header
+    //
+    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
+  } else {
+    //
+    // No Dos header so assume image starts with PE header.
+    //
+    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
+  }
+
+  if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+    //
+    // Not a valid PE image so Exit
+    //
+    return EFI_UNSUPPORTED;
+  }
+
+  Magic = Hdr.Pe32->OptionalHeader.Magic;
+
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+    //
+    // Use PE32 offset
+    //
+    NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+    DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);
+  } else {
+    //
+    // Use PE32+ offset
+    //
+    NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+    DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);
+  }
+
+  //
+  // Find the relocation block
+  //
+  // Per the PE/COFF spec, you can't assume that a given data directory
+  // is present in the image. You have to check the NumberOfRvaAndSizes in
+  // the optional header to verify a desired directory entry is there.
+  //
+  if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
+    RelocDir      = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
+    RelocBase     = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);
+    RelocBaseEnd  = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);
+  } else {
+    //
+    // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
+    //
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
+  //
+  ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
+
+  //
+  // Run the whole relocation block. And re-fixup data that has not been
+  // modified. The FixupData is used to see if the image has been modified
+  // since it was relocated. This is so data sections that have been updated
+  // by code will not be fixed up, since that would set them back to
+  // defaults.
+  //
+  FixupData = RelocationData;
+  while (RelocBase < RelocBaseEnd) {
+    //
+    // Add check for RelocBase->SizeOfBlock field.
+    //
+    if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {
+      //
+      // Data invalid, cannot continue to relocate the image, just return.
+      //
+      return EFI_UNSUPPORTED;
+    }
+
+    Reloc     = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
+    RelocEnd  = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
+    FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;
+
+    //
+    // Run this relocation record
+    //
+    while (Reloc < RelocEnd) {
+
+      Fixup = FixupBase + (*Reloc & 0xFFF);
+      switch ((*Reloc) >> 12) {
+
+      case EFI_IMAGE_REL_BASED_ABSOLUTE:
+        break;
+
+      case EFI_IMAGE_REL_BASED_HIGH:
+        //
+        // In order to be able to apply relocations to code and data regions
+        // that may be disjoint in the virtual mapping, we disallow relocations
+        // of type EFI_IMAGE_REL_BASED_HIGH or EFI_IMAGE_REL_BASED_LOW, unless
+        // the section alignment is at least 64 KB.
+        //
+        if (Hdr.Pe32->OptionalHeader.SectionAlignment < SIZE_64KB) {
+          return EFI_UNSUPPORTED;
+        }
+        Fixup16 = (UINT16 *) Fixup;
+        if (*(UINT16 *) FixupData == *Fixup16) {
+          ConvertAddress = (UINTN) *Fixup16 << 16;
+          RuntimeDriverConvertInternalPointer ((VOID **) &ConvertAddress);
+          *Fixup16 = (UINT16) (ConvertAddress >> 16);
+        }
+
+        FixupData = FixupData + sizeof (UINT16);
+        break;
+
+      case EFI_IMAGE_REL_BASED_LOW:
+        if (Hdr.Pe32->OptionalHeader.SectionAlignment < SIZE_64KB) {
+          return EFI_UNSUPPORTED;
+        }
+        //
+        // Since the adjustment is guaranteed to be a multiple of 64 KB,
+        // there is nothing to do here.
+        //
+        break;
+
+      case EFI_IMAGE_REL_BASED_HIGHLOW:
+        Fixup32       = (UINT32 *) Fixup;
+        FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
+        if (*(UINT32 *) FixupData == *Fixup32) {
+          ConvertAddress = (UINTN) *Fixup32;
+          RuntimeDriverConvertInternalPointer ((VOID **) &ConvertAddress);
+          *Fixup32 = (UINT32) ConvertAddress;
+        }
+
+        FixupData = FixupData + sizeof (UINT32);
+        break;
+
+      case EFI_IMAGE_REL_BASED_DIR64:
+        Fixup64       = (UINT64 *)Fixup;
+        FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
+        if (*(UINT64 *) FixupData == *Fixup64) {
+          ConvertAddress = (UINTN) *Fixup64;
+          RuntimeDriverConvertInternalPointer ((VOID **) &ConvertAddress);
+          *Fixup64 = (UINT64) ConvertAddress;
+        }
+
+        FixupData = FixupData + sizeof (UINT64);
+        break;
+
+      default:
+        ASSERT (FALSE);
+      }
+      //
+      // Next relocation record
+      //
+      Reloc += 1;
+    }
+    //
+    // next reloc block
+    //
+    RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
 
   Changes the runtime addressing mode of EFI firmware from physical to virtual.
 
@@ -312,9 +538,8 @@ RuntimeDriverSetVirtualAddressMap (
       Status  = RuntimeDriverConvertPointer (0, (VOID **) &VirtImageBase);
       ASSERT_EFI_ERROR (Status);
 
-      PeCoffLoaderRelocateImageForRuntime (
+      RuntimeDriverRelocateImageForRuntime (
         (EFI_PHYSICAL_ADDRESS) (UINTN) RuntimeImage->ImageBase,
-        VirtImageBase,
         (UINTN) RuntimeImage->ImageSize,
         RuntimeImage->RelocationData
         );
