+\r
+\r
+/**\r
+ Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI\r
+ runtime. \r
+ \r
+ PE_COFF_LOADER_IMAGE_CONTEXT.FixupData stores information needed to reapply\r
+ the fixups with a virtual mapping.\r
+\r
+\r
+ @param ImageBase Base address of relocated image\r
+ @param VirtImageBase Virtual mapping for ImageBase\r
+ @param ImageSize Size of the image to relocate\r
+ @param RelocationData Location to place results of read\r
+ \r
+**/\r
+VOID\r
+EFIAPI\r
+PeCoffLoaderRelocateImageForRuntime (\r
+ IN PHYSICAL_ADDRESS ImageBase,\r
+ IN PHYSICAL_ADDRESS VirtImageBase,\r
+ IN UINTN ImageSize,\r
+ IN VOID *RelocationData\r
+ )\r
+{\r
+ CHAR8 *OldBase;\r
+ CHAR8 *NewBase;\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ UINT32 NumberOfRvaAndSizes;\r
+ EFI_IMAGE_DATA_DIRECTORY *DataDirectory;\r
+ EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
+ EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
+ EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
+ UINT16 *Reloc;\r
+ UINT16 *RelocEnd;\r
+ CHAR8 *Fixup;\r
+ CHAR8 *FixupBase;\r
+ UINT16 *F16;\r
+ UINT32 *F32;\r
+ UINT64 *F64;\r
+ CHAR8 *FixupData;\r
+ UINTN Adjust;\r
+ RETURN_STATUS Status;\r
+\r
+ OldBase = (CHAR8 *)((UINTN)ImageBase);\r
+ NewBase = (CHAR8 *)((UINTN)VirtImageBase);\r
+ Adjust = (UINTN) NewBase - (UINTN) OldBase;\r
+\r
+ //\r
+ // Find the image's relocate dir info\r
+ //\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;\r
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+ //\r
+ // Valid DOS header so get address of PE header\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);\r
+ } else {\r
+ //\r
+ // No Dos header so assume image starts with PE header.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;\r
+ }\r
+\r
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+ //\r
+ // Not a valid PE image so Exit\r
+ //\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Get some data from the PE type dependent data\r
+ //\r
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ // \r
+ // Use PE32 offset\r
+ //\r
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+ DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+ } else {\r
+ // \r
+ // Use PE32+ offset\r
+ //\r
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+ DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+ } \r
+\r
+ //\r
+ // Find the relocation block\r
+ //\r
+ // Per the PE/COFF spec, you can't assume that a given data directory\r
+ // is present in the image. You have to check the NumberOfRvaAndSizes in\r
+ // the optional header to verify a desired directory entry is there.\r
+ // \r
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
+ RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;\r
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);\r
+ RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);\r
+ } else {\r
+ //\r
+ // Cannot find relocations, cannot continue\r
+ //\r
+ ASSERT (FALSE);\r
+ return ;\r
+ }\r
+\r
+ ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);\r
+\r
+ //\r
+ // Run the whole relocation block. And re-fixup data that has not been\r
+ // modified. The FixupData is used to see if the image has been modified\r
+ // since it was relocated. This is so data sections that have been updated\r
+ // by code will not be fixed up, since that would set them back to\r
+ // defaults.\r
+ //\r
+ FixupData = RelocationData;\r
+ while (RelocBase < RelocBaseEnd) {\r
+\r
+ Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
+ RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);\r
+ FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;\r
+\r
+ //\r
+ // Run this relocation record\r
+ //\r
+ while (Reloc < RelocEnd) {\r
+\r
+ Fixup = FixupBase + (*Reloc & 0xFFF);\r
+ switch ((*Reloc) >> 12) {\r
+\r
+ case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_HIGH:\r
+ F16 = (UINT16 *) Fixup;\r
+ if (*(UINT16 *) FixupData == *F16) {\r
+ *F16 = (UINT16) ((*F16 << 16) + ((UINT16) Adjust & 0xffff));\r
+ }\r
+\r
+ FixupData = FixupData + sizeof (UINT16);\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_LOW:\r
+ F16 = (UINT16 *) Fixup;\r
+ if (*(UINT16 *) FixupData == *F16) {\r
+ *F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff));\r
+ }\r
+\r
+ FixupData = FixupData + sizeof (UINT16);\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_HIGHLOW:\r
+ F32 = (UINT32 *) Fixup;\r
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
+ if (*(UINT32 *) FixupData == *F32) {\r
+ *F32 = *F32 + (UINT32) Adjust;\r
+ }\r
+\r
+ FixupData = FixupData + sizeof (UINT32);\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_DIR64:\r
+ F64 = (UINT64 *)Fixup;\r
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));\r
+ if (*(UINT32 *) FixupData == *F64) {\r
+ *F64 = *F64 + (UINT64)Adjust;\r
+ }\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_HIGHADJ:\r
+ //\r
+ // Not implemented, but not used in EFI 1.0\r
+ //\r
+ ASSERT (FALSE);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Only Itanium requires ConvertPeImage_Ex\r
+ //\r
+ Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
+ if (RETURN_ERROR (Status)) {\r
+ return ;\r
+ }\r
+ }\r
+ //\r
+ // Next relocation record\r
+ //\r
+ Reloc += 1;\r
+ }\r
+ //\r
+ // next reloc block\r
+ //\r
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ ImageRead function that operates on a memory buffer whos base is passed into\r
+ FileHandle. \r
+\r
+ @param FileHandle Ponter to baes of the input stream\r
+ @param FileOffset Offset to the start of the buffer\r
+ @param ReadSize Number of bytes to copy into the buffer\r
+ @param Buffer Location to place results of read\r
+\r
+ @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into \r
+ the buffer.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PeCoffLoaderImageReadFromMemory (\r
+ IN VOID *FileHandle,\r
+ IN UINTN FileOffset,\r
+ IN OUT UINTN *ReadSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);\r
+ return RETURN_SUCCESS;\r
+}\r
+\r