From 2ce311322c72857f73138c45358e722607a1e80c Mon Sep 17 00:00:00 2001 From: ajfish Date: Wed, 26 Jul 2006 15:23:35 +0000 Subject: Removed cross references from PciCf8Lib and PciExpressLib class to PciLib class. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added PeCoffLoaderGetMachineType to the PeCoffGetEntryPointLibrary Class. Document to be updated. Added the PeCoffLoaderImageReadFromMemory() and PeCoffLoaderRelocateImageForRuntime () to the PcCoffLib. Updated EfiImage.h and removed EFI_IMAGE_OPTIONAL_HEADER and EFI_IMAGE_NT_HEADERS as they were replaced with checking the MachineType. PeCoffLib – Added checks for MachineType so the PeCoff lib can load any PE32 or PE32+ image. The relocations are still limited to IA32, X64, IPF, and EBC. I also added a re-relocator function to remove PeLoader Code from Runtime Lib. Even though there is only one instance of the re-relocator I wanted to get all the PeCoff loader code together. Replaced DEBUG_CODE() macro with DEBUG_CODE_START() and DEBUG_CODE_END() so you can debug through the DEBUG_CODE() macros. Also removed PE/COFF code and replaced with library usage. I also updated the IO Instrinsic lib to use _ReadWriteBarrior() to help with sync problems git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1103 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Library/BaseIoLibIntrinsic/IoLib.c | 189 ------ MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 192 ++++++ MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 220 ++++++- MdePkg/Library/BasePciCf8Lib/PciLib.c | 10 +- MdePkg/Library/BasePciExpressLib/PciLib.c | 12 +- .../PeCoffGetEntryPoint.c | 49 +- MdePkg/Library/BasePeCoffLib/BasePeCoff.c | 718 +++++++++++++++------ MdePkg/Library/BasePeCoffLib/BasePeCoffLib.msa | 25 +- MdePkg/Library/BasePeCoffLib/Ebc/PeCoffLoaderEx.c | 53 ++ MdePkg/Library/BasePeCoffLib/Ia32/PeCoffLoaderEx.c | 53 ++ MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c | 240 ++++++- MdePkg/Library/BasePeCoffLib/x64/PeCoffLoaderEx.c | 69 +- 12 files changed, 1370 insertions(+), 460 deletions(-) (limited to 'MdePkg/Library') diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c index 126457a7e5..02c03b7aab 100644 --- a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c +++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c @@ -64,192 +64,3 @@ IoWrite64 ( return 0; } -/** - Reads an 8-bit MMIO register. - - Reads the 8-bit MMIO register specified by Address. The 8-bit read value is - returned. This function must guarantee that all MMIO read and write - operations are serialized. - - If 8-bit MMIO register operations are not supported, then ASSERT(). - - @param Address The MMIO register to read. - - @return The value read. - -**/ -UINT8 -EFIAPI -MmioRead8 ( - IN UINTN Address - ) -{ - return *(volatile UINT8*)Address; -} - -/** - Writes an 8-bit MMIO register. - - Writes the 8-bit MMIO register specified by Address with the value specified - by Value and returns Value. This function must guarantee that all MMIO read - and write operations are serialized. - - If 8-bit MMIO register operations are not supported, then ASSERT(). - - @param Address The MMIO register to write. - @param Value The value to write to the MMIO register. - -**/ -UINT8 -EFIAPI -MmioWrite8 ( - IN UINTN Address, - IN UINT8 Value - ) -{ - return *(volatile UINT8*)Address = Value; -} - -/** - Reads a 16-bit MMIO register. - - Reads the 16-bit MMIO register specified by Address. The 16-bit read value is - returned. This function must guarantee that all MMIO read and write - operations are serialized. - - If 16-bit MMIO register operations are not supported, then ASSERT(). - - @param Address The MMIO register to read. - - @return The value read. - -**/ -UINT16 -EFIAPI -MmioRead16 ( - IN UINTN Address - ) -{ - ASSERT ((Address & 1) == 0); - return *(volatile UINT16*)Address; -} - -/** - Writes a 16-bit MMIO register. - - Writes the 16-bit MMIO register specified by Address with the value specified - by Value and returns Value. This function must guarantee that all MMIO read - and write operations are serialized. - - If 16-bit MMIO register operations are not supported, then ASSERT(). - - @param Address The MMIO register to write. - @param Value The value to write to the MMIO register. - -**/ -UINT16 -EFIAPI -MmioWrite16 ( - IN UINTN Address, - IN UINT16 Value - ) -{ - ASSERT ((Address & 1) == 0); - return *(volatile UINT16*)Address = Value; -} - -/** - Reads a 32-bit MMIO register. - - Reads the 32-bit MMIO register specified by Address. The 32-bit read value is - returned. This function must guarantee that all MMIO read and write - operations are serialized. - - If 32-bit MMIO register operations are not supported, then ASSERT(). - - @param Address The MMIO register to read. - - @return The value read. - -**/ -UINT32 -EFIAPI -MmioRead32 ( - IN UINTN Address - ) -{ - ASSERT ((Address & 3) == 0); - return *(volatile UINT32*)Address; -} - -/** - Writes a 32-bit MMIO register. - - Writes the 32-bit MMIO register specified by Address with the value specified - by Value and returns Value. This function must guarantee that all MMIO read - and write operations are serialized. - - If 32-bit MMIO register operations are not supported, then ASSERT(). - - @param Address The MMIO register to write. - @param Value The value to write to the MMIO register. - -**/ -UINT32 -EFIAPI -MmioWrite32 ( - IN UINTN Address, - IN UINT32 Value - ) -{ - ASSERT ((Address & 3) == 0); - return *(volatile UINT32*)Address = Value; -} - -/** - Reads a 64-bit MMIO register. - - Reads the 64-bit MMIO register specified by Address. The 64-bit read value is - returned. This function must guarantee that all MMIO read and write - operations are serialized. - - If 64-bit MMIO register operations are not supported, then ASSERT(). - - @param Address The MMIO register to read. - - @return The value read. - -**/ -UINT64 -EFIAPI -MmioRead64 ( - IN UINTN Address - ) -{ - ASSERT ((Address & 7) == 0); - return *(volatile UINT64*)Address; -} - -/** - Writes a 64-bit MMIO register. - - Writes the 64-bit MMIO register specified by Address with the value specified - by Value and returns Value. This function must guarantee that all MMIO read - and write operations are serialized. - - If 64-bit MMIO register operations are not supported, then ASSERT(). - - @param Address The MMIO register to write. - @param Value The value to write to the MMIO register. - -**/ -UINT64 -EFIAPI -MmioWrite64 ( - IN UINTN Address, - IN UINT64 Value - ) -{ - ASSERT ((Address & 7) == 0); - return *(volatile UINT64*)Address = Value; -} diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c index a065c14299..69fb878888 100644 --- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c +++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c @@ -25,6 +25,198 @@ #ifdef __GNUC__ +/** + Reads an 8-bit MMIO register. + + Reads the 8-bit MMIO register specified by Address. The 8-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 8-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT8 +EFIAPI +MmioRead8 ( + IN UINTN Address + ) +{ + return *(volatile UINT8*)Address; +} + +/** + Writes an 8-bit MMIO register. + + Writes the 8-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 8-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + +**/ +UINT8 +EFIAPI +MmioWrite8 ( + IN UINTN Address, + IN UINT8 Value + ) +{ + return *(volatile UINT8*)Address = Value; +} + +/** + Reads a 16-bit MMIO register. + + Reads the 16-bit MMIO register specified by Address. The 16-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT16 +EFIAPI +MmioRead16 ( + IN UINTN Address + ) +{ + ASSERT ((Address & 1) == 0); + return *(volatile UINT16*)Address; +} + +/** + Writes a 16-bit MMIO register. + + Writes the 16-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + +**/ +UINT16 +EFIAPI +MmioWrite16 ( + IN UINTN Address, + IN UINT16 Value + ) +{ + ASSERT ((Address & 1) == 0); + return *(volatile UINT16*)Address = Value; +} + +/** + Reads a 32-bit MMIO register. + + Reads the 32-bit MMIO register specified by Address. The 32-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT32 +EFIAPI +MmioRead32 ( + IN UINTN Address + ) +{ + ASSERT ((Address & 3) == 0); + return *(volatile UINT32*)Address; +} + +/** + Writes a 32-bit MMIO register. + + Writes the 32-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + +**/ +UINT32 +EFIAPI +MmioWrite32 ( + IN UINTN Address, + IN UINT32 Value + ) +{ + ASSERT ((Address & 3) == 0); + return *(volatile UINT32*)Address = Value; +} + +/** + Reads a 64-bit MMIO register. + + Reads the 64-bit MMIO register specified by Address. The 64-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 64-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT64 +EFIAPI +MmioRead64 ( + IN UINTN Address + ) +{ + ASSERT ((Address & 7) == 0); + return *(volatile UINT64*)Address; +} + +/** + Writes a 64-bit MMIO register. + + Writes the 64-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 64-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + +**/ +UINT64 +EFIAPI +MmioWrite64 ( + IN UINTN Address, + IN UINT64 Value + ) +{ + ASSERT ((Address & 7) == 0); + return *(volatile UINT64*)Address = Value; +} + + + /** Reads an 8-bit I/O port. diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c index 8bce7a5eb9..cfe5ddff43 100644 --- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c +++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c @@ -27,12 +27,13 @@ // // Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics // -int _inp (unsigned short port); +int _inp (unsigned short port); unsigned short _inpw (unsigned short port); unsigned long _inpd (unsigned short port); int _outp (unsigned short port, int databyte ); -unsigned short _outpw(unsigned short port, unsigned short dataword ); -unsigned long _outpd(unsigned short port, unsigned long dataword ); +unsigned short _outpw (unsigned short port, unsigned short dataword ); +unsigned long _outpd (unsigned short port, unsigned long dataword ); +void _ReadWriteBarrier (void); #pragma intrinsic(_inp) #pragma intrinsic(_inpw) @@ -40,7 +41,15 @@ unsigned long _outpd(unsigned short port, unsigned long dataword ); #pragma intrinsic(_outp) #pragma intrinsic(_outpw) #pragma intrinsic(_outpd) +#pragma intrinsic(_ReadWriteBarrier) +// +// _ReadWriteBarrier() forces memory reads and writes to complete at the point +// in the call. This is only a hint to the compiler and does emit code. +// In past versions of the compiler, _ReadWriteBarrier was enforced only +// locally and did not affect functions up the call tree. In Visual C++ +// 2005, _ReadWriteBarrier is enforced all the way up the call tree. +// /** Reads an 8-bit I/O port. @@ -62,6 +71,7 @@ IoRead8 ( IN UINTN Port ) { + _ReadWriteBarrier (); return (UINT8)_inp ((UINT16)Port); } @@ -87,6 +97,7 @@ IoWrite8 ( IN UINT8 Value ) { + _ReadWriteBarrier (); return (UINT8)_outp ((UINT16)Port, Value); } @@ -111,6 +122,7 @@ IoRead16 ( ) { ASSERT ((Port & 1) == 0); + _ReadWriteBarrier (); return _inpw((UINT16)Port); } @@ -137,6 +149,7 @@ IoWrite16 ( ) { ASSERT ((Port & 1) == 0); + _ReadWriteBarrier (); return _outpw ((UINT16)Port, Value); } @@ -161,6 +174,7 @@ IoRead32 ( ) { ASSERT ((Port & 3) == 0); + _ReadWriteBarrier (); return _inpd((UINT16)Port); } @@ -187,7 +201,207 @@ IoWrite32 ( ) { ASSERT ((Port & 3) == 0); + _ReadWriteBarrier (); return _outpd ((UINT16)Port, Value); } + +/** + Reads an 8-bit MMIO register. + + Reads the 8-bit MMIO register specified by Address. The 8-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 8-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT8 +EFIAPI +MmioRead8 ( + IN UINTN Address + ) +{ + _ReadWriteBarrier (); + return *(volatile UINT8 *)Address; +} + +/** + Writes an 8-bit MMIO register. + + Writes the 8-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 8-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + +**/ +UINT8 +EFIAPI +MmioWrite8 ( + IN UINTN Address, + IN UINT8 Value + ) +{ + _ReadWriteBarrier (); + return *(volatile UINT8 *)Address = Value; +} + +/** + Reads a 16-bit MMIO register. + + Reads the 16-bit MMIO register specified by Address. The 16-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT16 +EFIAPI +MmioRead16 ( + IN UINTN Address + ) +{ + ASSERT ((Address & 1) == 0); + _ReadWriteBarrier (); + return *(volatile UINT16 *)Address; +} + +/** + Writes a 16-bit MMIO register. + + Writes the 16-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 16-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + +**/ +UINT16 +EFIAPI +MmioWrite16 ( + IN UINTN Address, + IN UINT16 Value + ) +{ + ASSERT ((Address & 1) == 0); + _ReadWriteBarrier (); + return *(volatile UINT16 *)Address = Value; +} + +/** + Reads a 32-bit MMIO register. + + Reads the 32-bit MMIO register specified by Address. The 32-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT32 +EFIAPI +MmioRead32 ( + IN UINTN Address + ) +{ + ASSERT ((Address & 3) == 0); + _ReadWriteBarrier (); + return *(volatile UINT32 *)Address; +} + +/** + Writes a 32-bit MMIO register. + + Writes the 32-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 32-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + +**/ +UINT32 +EFIAPI +MmioWrite32 ( + IN UINTN Address, + IN UINT32 Value + ) +{ + ASSERT ((Address & 3) == 0); + _ReadWriteBarrier (); + return *(volatile UINT32 *)Address = Value; +} + +/** + Reads a 64-bit MMIO register. + + Reads the 64-bit MMIO register specified by Address. The 64-bit read value is + returned. This function must guarantee that all MMIO read and write + operations are serialized. + + If 64-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to read. + + @return The value read. + +**/ +UINT64 +EFIAPI +MmioRead64 ( + IN UINTN Address + ) +{ + ASSERT ((Address & 7) == 0); + _ReadWriteBarrier (); + return *(volatile UINT64 *)Address; +} + +/** + Writes a 64-bit MMIO register. + + Writes the 64-bit MMIO register specified by Address with the value specified + by Value and returns Value. This function must guarantee that all MMIO read + and write operations are serialized. + + If 64-bit MMIO register operations are not supported, then ASSERT(). + + @param Address The MMIO register to write. + @param Value The value to write to the MMIO register. + +**/ +UINT64 +EFIAPI +MmioWrite64 ( + IN UINTN Address, + IN UINT64 Value + ) +{ + ASSERT ((Address & 7) == 0); + _ReadWriteBarrier (); + return *(volatile UINT64 *)Address = Value; +} + #endif diff --git a/MdePkg/Library/BasePciCf8Lib/PciLib.c b/MdePkg/Library/BasePciCf8Lib/PciLib.c index cbbd407ead..272d641ff3 100644 --- a/MdePkg/Library/BasePciCf8Lib/PciLib.c +++ b/MdePkg/Library/BasePciCf8Lib/PciLib.c @@ -1315,7 +1315,7 @@ PciCf8ReadBuffer ( // // Read a byte if StartAddress is byte aligned // - *(UINT8*)Buffer = PciCf8Read8 (StartAddress); + *(volatile UINT8 *)Buffer = PciCf8Read8 (StartAddress); StartAddress += sizeof (UINT8); Size -= sizeof (UINT8); Buffer = (UINT8*)Buffer + 1; @@ -1325,7 +1325,7 @@ PciCf8ReadBuffer ( // // Read a word if StartAddress is word aligned // - *(UINT16*)Buffer = PciCf8Read16 (StartAddress); + *(volatile UINT16 *)Buffer = PciCf8Read16 (StartAddress); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; @@ -1335,7 +1335,7 @@ PciCf8ReadBuffer ( // // Read as many double words as possible // - *(UINT32*)Buffer = PciCf8Read32 (StartAddress); + *(volatile UINT32 *)Buffer = PciCf8Read32 (StartAddress); StartAddress += sizeof (UINT32); Size -= sizeof (UINT32); Buffer = (UINT32*)Buffer + 1; @@ -1345,7 +1345,7 @@ PciCf8ReadBuffer ( // // Read the last remaining word if exist // - *(UINT16*)Buffer = PciCf8Read16 (StartAddress); + *(volatile UINT16 *)Buffer = PciCf8Read16 (StartAddress); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; @@ -1355,7 +1355,7 @@ PciCf8ReadBuffer ( // // Read the last remaining byte if exist // - *(UINT8*)Buffer = PciCf8Read8 (StartAddress); + *(volatile UINT8 *)Buffer = PciCf8Read8 (StartAddress); } return ReturnValue; diff --git a/MdePkg/Library/BasePciExpressLib/PciLib.c b/MdePkg/Library/BasePciExpressLib/PciLib.c index 509a5e423f..6bb0893887 100644 --- a/MdePkg/Library/BasePciExpressLib/PciLib.c +++ b/MdePkg/Library/BasePciExpressLib/PciLib.c @@ -40,7 +40,7 @@ @return The base address of PCI Express. **/ -UINTN +volatile UINTN GetPciExpressBaseAddress ( VOID ) @@ -1220,7 +1220,7 @@ PciExpressReadBuffer ( // // Read a byte if StartAddress is byte aligned // - *(UINT8*)Buffer = PciExpressRead8 (StartAddress); + *(volatile UINT8 *)Buffer = PciExpressRead8 (StartAddress); StartAddress += sizeof (UINT8); Size -= sizeof (UINT8); Buffer = (UINT8*)Buffer + 1; @@ -1230,7 +1230,7 @@ PciExpressReadBuffer ( // // Read a word if StartAddress is word aligned // - *(UINT16*)Buffer = PciExpressRead16 (StartAddress); + *(volatile UINT16 *)Buffer = PciExpressRead16 (StartAddress); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; @@ -1240,7 +1240,7 @@ PciExpressReadBuffer ( // // Read as many double words as possible // - *(UINT32*)Buffer = PciExpressRead32 (StartAddress); + *(volatile UINT32 *)Buffer = PciExpressRead32 (StartAddress); StartAddress += sizeof (UINT32); Size -= sizeof (UINT32); Buffer = (UINT32*)Buffer + 1; @@ -1250,7 +1250,7 @@ PciExpressReadBuffer ( // // Read the last remaining word if exist // - *(UINT16*)Buffer = PciExpressRead16 (StartAddress); + *(volatile UINT16 *)Buffer = PciExpressRead16 (StartAddress); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; @@ -1260,7 +1260,7 @@ PciExpressReadBuffer ( // // Read the last remaining byte if exist // - *(UINT8*)Buffer = PciExpressRead8 (StartAddress); + *(volatile UINT8 *)Buffer = PciExpressRead8 (StartAddress); } return ReturnValue; diff --git a/MdePkg/Library/BasePeCoffGetEntryPointLib/PeCoffGetEntryPoint.c b/MdePkg/Library/BasePeCoffGetEntryPointLib/PeCoffGetEntryPoint.c index b740bd6e7c..001e043d3f 100644 --- a/MdePkg/Library/BasePeCoffGetEntryPointLib/PeCoffGetEntryPoint.c +++ b/MdePkg/Library/BasePeCoffGetEntryPointLib/PeCoffGetEntryPoint.c @@ -40,26 +40,63 @@ PeCoffLoaderGetEntryPoint ( OUT VOID **EntryPoint ) { - EFI_IMAGE_DOS_HEADER *DosHeader; - EFI_IMAGE_NT_HEADERS *PeHeader; + EFI_IMAGE_DOS_HEADER *DosHeader; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Header; ASSERT (Pe32Data != NULL); ASSERT (EntryPoint != NULL); DosHeader = (EFI_IMAGE_DOS_HEADER *)Pe32Data; - if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) { // // DOS image header is present, so read the PE header after the DOS image header. // - PeHeader = (EFI_IMAGE_NT_HEADERS *) ((UINTN) Pe32Data + (UINTN) ((DosHeader->e_lfanew) & 0x0ffff)); + Header.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHeader->e_lfanew) & 0x0ffff)); } else { // // DOS image header is not present, so PE header is at the image base. // - PeHeader = (EFI_IMAGE_NT_HEADERS *) Pe32Data; + Header.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; } - *EntryPoint = (VOID *) ((UINTN) Pe32Data + (UINTN) (PeHeader->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff)); + // + // Calculate the entry point relative to the start of the image. + // AddressOfEntryPoint is common for PE32 & PE32+ + // + *EntryPoint = (VOID *)((UINTN)Pe32Data + (UINTN)(Header.Pe32->OptionalHeader.AddressOfEntryPoint & 0x0ffffffff)); return RETURN_SUCCESS; } + + +/** + Returns the machine type of PE/COFF image. + + @param Image Pointer to a PE/COFF header + + @return Machine type or zero if not a valid iamge + +**/ +UINT16 +EFIAPI +PeCoffLoaderGetMachineType ( + IN VOID *Pe32Data + ) +{ + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DOS_HEADER *DosHdr; + + DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + DosHdr->e_lfanew); + } else { + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data); + } + + if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + return Hdr.Pe32->FileHeader.Machine; + } + + return 0x0000; +} + + diff --git a/MdePkg/Library/BasePeCoffLib/BasePeCoff.c b/MdePkg/Library/BasePeCoffLib/BasePeCoff.c index 6b8adc1fd6..1e8f573009 100644 --- a/MdePkg/Library/BasePeCoffLib/BasePeCoff.c +++ b/MdePkg/Library/BasePeCoffLib/BasePeCoff.c @@ -1,6 +1,9 @@ /** @file Tiano PE/COFF loader. + This PE/COFF loader supports loading any PE32 or PE32+ image type, but + only supports relocating IA32, X64, IPF, and EBC images. + Copyright (c) 2006, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -14,8 +17,10 @@ **/ + /** - Performs an Itanium-based specific relocation fixup. + Performs an Itanium-based specific relocation fixup and is a no-op on other + instruction sets. @param Reloc Pointer to the relocation record. @param Fixup Pointer to the address to fix up. @@ -34,33 +39,68 @@ PeCoffLoaderRelocateImageEx ( ); +/** + 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 Pointer to the relocation record. + @param Fixup Pointer to the address to fix up. + @param FixupData Pointer to a buffer to log the fixups. + @param Adjust The offset to adjust the fixup. + + @return Status code. + +**/ +RETURN_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + + +/** + Returns TRUE if the machine type of PE/COFF image is supported. Supported + does not mean the image can be executed it means the PE/COFF loader supports + loading and relocating of the image type. It's up to the caller to support + the entry point. + + @param Machine Machine type from the PE Header. + + @return TRUE if this PE/COFF loader can load the image + +**/ +BOOLEAN +PeCoffLoaderImageFormatSupported ( + IN UINT16 Machine + ); + + /** Retrieves the PE or TE Header from a PE/COFF or TE image. @param ImageContext The context of the image being loaded. - @param PeHdr The buffer in which to return the PE header. - @param TeHdr The buffer in which to return the TE header. + @param Hdr The buffer in which to return the PE32, PE32+, or TE header. @retval RETURN_SUCCESS The PE or TE Header is read. @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function. **/ -STATIC RETURN_STATUS PeCoffLoaderGetPeHeader ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - OUT EFI_IMAGE_NT_HEADERS *PeHdr, - OUT EFI_TE_IMAGE_HEADER *TeHdr + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr ) { RETURN_STATUS Status; EFI_IMAGE_DOS_HEADER DosHdr; UINTN Size; - ImageContext->IsTeImage = FALSE; // - // Read the DOS image headers + // Read the DOS image header to check for it's existance // Size = sizeof (EFI_IMAGE_DOS_HEADER); Status = ImageContext->ImageRead ( @@ -77,93 +117,85 @@ PeCoffLoaderGetPeHeader ( ImageContext->PeCoffHeaderOffset = 0; if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) { // - // DOS image header is present, so read the PE header after the DOS image header + // DOS image header is present, so read the PE header after the DOS image + // header // ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew; } + // - // Read the PE/COFF Header + // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much + // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic + // determins if this is a PE32 or PE32+ image. The magic is in the same + // location in both images. // - Size = sizeof (EFI_IMAGE_NT_HEADERS); + Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); Status = ImageContext->ImageRead ( ImageContext->Handle, ImageContext->PeCoffHeaderOffset, &Size, - PeHdr + Hdr.Pe32 ); if (RETURN_ERROR (Status)) { ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; return Status; } + // - // Check the PE/COFF Header Signature. If not, then try to read a TE header + // Use Signature to figure out if we understand the image format // - if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) { - Size = sizeof (EFI_TE_IMAGE_HEADER); - Status = ImageContext->ImageRead ( - ImageContext->Handle, - 0, - &Size, - TeHdr - ); - if (TeHdr->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) { - return RETURN_UNSUPPORTED; - } - - ImageContext->IsTeImage = TRUE; - } - - return RETURN_SUCCESS; -} - -/** - Checks the PE or TE header of a PE/COFF or TE image to determine if it supported. - - @param ImageContext The context of the image being loaded. - @param PeHdr The buffer in which to return the PE header. - @param TeHdr The buffer in which to return the TE header. + if (Hdr.Pe32->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + ImageContext->IsTeImage = TRUE; + ImageContext->Machine = Hdr.Te->Machine; + ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem); + ImageContext->ImageSize = 0; + ImageContext->SectionAlignment = 4096; + ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize; - @retval RETURN_SUCCESS The PE/COFF or TE image is supported. - @retval RETURN_UNSUPPORTED The PE/COFF or TE image is not supported. + } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + ImageContext->IsTeImage = FALSE; + ImageContext->Machine = Hdr.Pe32->FileHeader.Machine; + + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem; + ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage; + ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment; + ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders; -**/ -STATIC -RETURN_STATUS -PeCoffLoaderCheckImageType ( - IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, - IN EFI_IMAGE_NT_HEADERS *PeHdr, - IN EFI_TE_IMAGE_HEADER *TeHdr - ) -{ - // - // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based) - // and the machine type for the Virtual Machine. - // - if (ImageContext->IsTeImage == FALSE) { - ImageContext->Machine = PeHdr->FileHeader.Machine; + } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // + // Use PE32+ offset + // + ImageContext->ImageType = Hdr.Pe32Plus->OptionalHeader.Subsystem; + ImageContext->ImageSize = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage; + ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment; + ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; + } else { + ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE; + return RETURN_UNSUPPORTED; + } } else { - ImageContext->Machine = TeHdr->Machine; - } - - if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) { ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE; return RETURN_UNSUPPORTED; } - // - // See if the image type is supported. We support EFI Applications, - // EFI Boot Service Drivers, and EFI Runtime Drivers. - // - if (ImageContext->IsTeImage == FALSE) { - ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem; - } else { - ImageContext->ImageType = (UINT16) (TeHdr->Subsystem); + if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) { + // + // If the PE/COFF loader does not support the image type return + // unsupported. This library can suport lots of types of images + // this does not mean the user of this library can call the entry + // point of the image. + // + return RETURN_UNSUPPORTED; } - return RETURN_SUCCESS; } + /** Retrieves information about a PE/COFF image. @@ -189,17 +221,18 @@ PeCoffLoaderGetImageInfo ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { - RETURN_STATUS Status; - EFI_IMAGE_NT_HEADERS PeHdr; - EFI_TE_IMAGE_HEADER TeHdr; - EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry; - UINTN Size; - UINTN Index; - UINTN DebugDirectoryEntryRva; - UINTN DebugDirectoryEntryFileOffset; - UINTN SectionHeaderOffset; - EFI_IMAGE_SECTION_HEADER SectionHeader; - EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry; + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry; + UINTN Size; + UINTN Index; + UINTN DebugDirectoryEntryRva; + UINTN DebugDirectoryEntryFileOffset; + UINTN SectionHeaderOffset; + EFI_IMAGE_SECTION_HEADER SectionHeader; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry; + UINT32 NumberOfRvaAndSizes; if (NULL == ImageContext) { return RETURN_INVALID_PARAMETER; @@ -209,25 +242,31 @@ PeCoffLoaderGetImageInfo ( // ImageContext->ImageError = IMAGE_ERROR_SUCCESS; - Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr); - if (RETURN_ERROR (Status)) { - return Status; - } - // - // Verify machine type - // - Status = PeCoffLoaderCheckImageType (ImageContext, &PeHdr, &TeHdr); + Hdr.Union = &HdrData; + Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr); if (RETURN_ERROR (Status)) { return Status; } + // // Retrieve the base address of the image // if (!(ImageContext->IsTeImage)) { - ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase; + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase; + } else { + // + // Use PE32+ offset + // + ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase; + } } else { - ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr.ImageBase); + ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase); } + // // Initialize the alternate destination address to 0 indicating that it // should not be used. @@ -251,23 +290,28 @@ PeCoffLoaderGetImageInfo ( // Look at the file header to determine if relocations have been stripped, and // save this info in the image context for later use. // - if ((!(ImageContext->IsTeImage)) && ((PeHdr.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) { + if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) { ImageContext->RelocationsStripped = TRUE; } else { ImageContext->RelocationsStripped = FALSE; } if (!(ImageContext->IsTeImage)) { - ImageContext->ImageSize = (UINT64) PeHdr.OptionalHeader.SizeOfImage; - ImageContext->SectionAlignment = PeHdr.OptionalHeader.SectionAlignment; - ImageContext->SizeOfHeaders = PeHdr.OptionalHeader.SizeOfHeaders; - - // - // Modify ImageSize to contain .PDB file name if required and initialize - // PdbRVA field... - // - if (PeHdr.OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { - DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } else { + // + // Use PE32+ offset + // + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } + + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; @@ -282,10 +326,10 @@ PeCoffLoaderGetImageInfo ( ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + - PeHdr.FileHeader.SizeOfOptionalHeader + Hdr.Pe32->FileHeader.SizeOfOptionalHeader ); - for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index++) { + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { // // Read section header from file // @@ -303,8 +347,8 @@ PeCoffLoaderGetImageInfo ( if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress && DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) { - DebugDirectoryEntryFileOffset = - DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData; + + DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData; break; } @@ -340,17 +384,14 @@ PeCoffLoaderGetImageInfo ( } } } else { - ImageContext->ImageSize = 0; - ImageContext->SectionAlignment = 4096; - ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr.BaseOfCode - (UINTN) TeHdr.StrippedSize; - DebugDirectoryEntry = &TeHdr.DataDirectory[1]; + DebugDirectoryEntry = &Hdr.Te->DataDirectory[1]; DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; - SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER)); + SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER)); DebugDirectoryEntryFileOffset = 0; - for (Index = 0; Index < TeHdr.NumberOfSections;) { + for (Index = 0; Index < Hdr.Te->NumberOfSections;) { // // Read section header from file // @@ -372,15 +413,15 @@ PeCoffLoaderGetImageInfo ( SectionHeader.VirtualAddress + SectionHeader.PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - - TeHdr.StrippedSize; + Hdr.Te->StrippedSize; // // File offset of the debug directory was found, if this is not the last // section, then skip to the last section for calculating the image size. // - if (Index < (UINTN) TeHdr.NumberOfSections - 1) { - SectionHeaderOffset += (TeHdr.NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER); - Index = TeHdr.NumberOfSections - 1; + if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) { + SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER); + Index = Hdr.Te->NumberOfSections - 1; continue; } } @@ -395,7 +436,7 @@ PeCoffLoaderGetImageInfo ( // by the RVA and the VirtualSize of the last section header in the // Section Table. // - if ((++Index) == (UINTN) TeHdr.NumberOfSections) { + if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) { ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize + ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1); } @@ -431,6 +472,7 @@ PeCoffLoaderGetImageInfo ( return RETURN_SUCCESS; } + /** Converts an image address to the loaded address. @@ -440,19 +482,13 @@ PeCoffLoaderGetImageInfo ( @return The converted address or NULL if the address can not be converted. **/ -STATIC VOID * PeCoffLoaderImageAddress ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, IN UINTN Address ) { - if (Address >= ImageContext->ImageSize) { - ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS; - return NULL; - } - - return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address); + return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address); } /** @@ -481,26 +517,25 @@ PeCoffLoaderRelocateImage ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext ) { - RETURN_STATUS Status; - EFI_IMAGE_NT_HEADERS *PeHdr; - EFI_TE_IMAGE_HEADER *TeHdr; - EFI_IMAGE_DATA_DIRECTORY *RelocDir; - UINT64 Adjust; - EFI_IMAGE_BASE_RELOCATION *RelocBase; - EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; - UINT16 *Reloc; - UINT16 *RelocEnd; - CHAR8 *Fixup; - CHAR8 *FixupBase; - UINT16 *F16; - UINT32 *F32; - CHAR8 *FixupData; - PHYSICAL_ADDRESS BaseAddress; + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DATA_DIRECTORY *RelocDir; + UINT64 Adjust; + EFI_IMAGE_BASE_RELOCATION *RelocBase; + EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; + UINT16 *Reloc; + UINT16 *RelocEnd; + CHAR8 *Fixup; + CHAR8 *FixupBase; + UINT16 *F16; + UINT32 *F32; + UINT64 *F64; + CHAR8 *FixupData; + PHYSICAL_ADDRESS BaseAddress; + UINT32 NumberOfRvaAndSizes; ASSERT (ImageContext != NULL); - PeHdr = NULL; - TeHdr = NULL; // // Assume success // @@ -524,21 +559,35 @@ PeCoffLoaderRelocateImage ( } if (!(ImageContext->IsTeImage)) { - PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext->ImageAddress + - ImageContext->PeCoffHeaderOffset); - - Adjust = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase; - PeHdr->OptionalHeader.ImageBase = (UINTN)BaseAddress; + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset); + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase; + Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress; + + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + } else { + // + // Use PE32+ offset + // + Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase; + Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress; + + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + } // // 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 (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { - RelocDir = &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress); RelocBaseEnd = PeCoffLoaderImageAddress ( ImageContext, @@ -551,19 +600,19 @@ PeCoffLoaderRelocateImage ( RelocBase = RelocBaseEnd = 0; } } else { - TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress); - Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase); - TeHdr->ImageBase = (UINT64) (BaseAddress); + Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress); + Adjust = (UINT64) (BaseAddress - Hdr.Te->ImageBase); + Hdr.Te->ImageBase = (UINT64) (BaseAddress); // // Find the relocation block // - RelocDir = &TeHdr->DataDirectory[0]; + RelocDir = &Hdr.Te->DataDirectory[0]; RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)( ImageContext->ImageAddress + RelocDir->VirtualAddress + sizeof(EFI_TE_IMAGE_HEADER) - - TeHdr->StrippedSize + Hdr.Te->StrippedSize ); RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1); } @@ -582,7 +631,7 @@ PeCoffLoaderRelocateImage ( FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress + RelocBase->VirtualAddress + sizeof(EFI_TE_IMAGE_HEADER) - - TeHdr->StrippedSize + Hdr.Te->StrippedSize ); } @@ -626,21 +675,27 @@ PeCoffLoaderRelocateImage ( *F32 = *F32 + (UINT32) Adjust; if (FixupData != NULL) { FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32)); - *(UINT32 *) FixupData = *F32; + *(UINT32 *)FixupData = *F32; FixupData = FixupData + sizeof (UINT32); } break; - case EFI_IMAGE_REL_BASED_HIGHADJ: - // - // Return the same EFI_UNSUPPORTED return code as - // PeCoffLoaderRelocateImageEx() returns if it does not recognize - // the relocation type. - // - ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; - return RETURN_UNSUPPORTED; + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *) Fixup; + *F64 = *F64 + (UINT64) Adjust; + if (FixupData != NULL) { + FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64)); + *(UINT64 *)(FixupData) = *F64; + FixupData = FixupData + sizeof(UINT64); + } + break; default: + // + // The common code does not handle some of the stranger IPF relocations + // PeCoffLoaderRelocateImageEx () addes support for these complex fixups + // on IPF and is a No-Op on other archtiectures. + // Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust); if (RETURN_ERROR (Status)) { ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; @@ -693,8 +748,7 @@ PeCoffLoaderLoadImage ( ) { RETURN_STATUS Status; - EFI_IMAGE_NT_HEADERS *PeHdr; - EFI_TE_IMAGE_HEADER *TeHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; PE_COFF_LOADER_IMAGE_CONTEXT CheckContext; EFI_IMAGE_SECTION_HEADER *FirstSection; EFI_IMAGE_SECTION_HEADER *Section; @@ -707,12 +761,10 @@ PeCoffLoaderLoadImage ( EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; UINTN Size; UINT32 TempDebugEntryRva; + UINT32 NumberOfRvaAndSizes; ASSERT (ImageContext != NULL); - PeHdr = NULL; - TeHdr = NULL; - // // Assume success // @@ -786,32 +838,31 @@ PeCoffLoaderLoadImage ( (VOID *) (UINTN) ImageContext->ImageAddress ); - PeHdr = (EFI_IMAGE_NT_HEADERS *) - ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset); + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset); FirstSection = (EFI_IMAGE_SECTION_HEADER *) ( (UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset + sizeof(UINT32) + sizeof(EFI_IMAGE_FILE_HEADER) + - PeHdr->FileHeader.SizeOfOptionalHeader + Hdr.Pe32->FileHeader.SizeOfOptionalHeader ); - NumberOfSections = (UINTN) (PeHdr->FileHeader.NumberOfSections); + NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections); } else { Status = ImageContext->ImageRead ( ImageContext->Handle, 0, &ImageContext->SizeOfHeaders, - (void *) (UINTN) ImageContext->ImageAddress + (void *)(UINTN)ImageContext->ImageAddress ); - TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress); + Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress); FirstSection = (EFI_IMAGE_SECTION_HEADER *) ( - (UINTN)ImageContext->ImageAddress + - sizeof(EFI_TE_IMAGE_HEADER) - ); - NumberOfSections = (UINTN) (TeHdr->NumberOfSections); + (UINTN)ImageContext->ImageAddress + + sizeof(EFI_TE_IMAGE_HEADER) + ); + NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections); } @@ -835,8 +886,8 @@ PeCoffLoaderLoadImage ( Section->VirtualAddress + Section->Misc.VirtualSize - 1 ); if (ImageContext->IsTeImage) { - Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize); - End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize); + Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize); + End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize); } if (End > MaxEnd) { @@ -869,7 +920,7 @@ PeCoffLoaderLoadImage ( } else { Status = ImageContext->ImageRead ( ImageContext->Handle, - Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize, + Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize, &Size, Base ); @@ -899,17 +950,33 @@ PeCoffLoaderLoadImage ( // Get image's entry point // if (!(ImageContext->IsTeImage)) { - ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress ( - ImageContext, - PeHdr->OptionalHeader.AddressOfEntryPoint - ); + // + // Sizes of AddressOfEntryPoint are different so we need to do this safely + // + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress ( + ImageContext, + (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint + ); + } else { + // + // Use PE32+ offset + // + ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress ( + ImageContext, + (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint + ); + } } else { ImageContext->EntryPoint = (PHYSICAL_ADDRESS) ( - (UINTN)ImageContext->ImageAddress + - (UINTN)TeHdr->AddressOfEntryPoint + - (UINTN)sizeof(EFI_TE_IMAGE_HEADER) - - (UINTN) TeHdr->StrippedSize - ); + (UINTN)ImageContext->ImageAddress + + (UINTN)Hdr.Te->AddressOfEntryPoint + + (UINTN)sizeof(EFI_TE_IMAGE_HEADER) - + (UINTN)Hdr.Te->StrippedSize + ); } // @@ -920,15 +987,27 @@ PeCoffLoaderLoadImage ( // the optional header to verify a desired directory entry is there. // if (!(ImageContext->IsTeImage)) { - if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { - DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) - &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + } else { + // + // Use PE32+ offset + // + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + } + + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN); } else { ImageContext->FixupDataSize = 0; } } else { - DirectoryEntry = &TeHdr->DataDirectory[0]; + DirectoryEntry = &Hdr.Te->DataDirectory[0]; ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN); } // @@ -948,18 +1027,18 @@ PeCoffLoaderLoadImage ( ); } else { DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)( - ImageContext->ImageAddress + - ImageContext->DebugDirectoryEntryRva + - sizeof(EFI_TE_IMAGE_HEADER) - - TeHdr->StrippedSize - ); + ImageContext->ImageAddress + + ImageContext->DebugDirectoryEntryRva + + sizeof(EFI_TE_IMAGE_HEADER) - + Hdr.Te->StrippedSize + ); } if (DebugEntry != NULL) { TempDebugEntryRva = DebugEntry->RVA; if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) { Section--; - if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) { + if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) { TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize; } else { TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData; @@ -971,11 +1050,11 @@ PeCoffLoaderLoadImage ( ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva); } else { ImageContext->CodeView = (VOID *)( - (UINTN)ImageContext->ImageAddress + - (UINTN)TempDebugEntryRva + - (UINTN)sizeof(EFI_TE_IMAGE_HEADER) - - (UINTN) TeHdr->StrippedSize - ); + (UINTN)ImageContext->ImageAddress + + (UINTN)TempDebugEntryRva + + (UINTN)sizeof (EFI_TE_IMAGE_HEADER) - + (UINTN) Hdr.Te->StrippedSize + ); } if (ImageContext->CodeView == NULL) { @@ -995,7 +1074,7 @@ PeCoffLoaderLoadImage ( } else { Status = ImageContext->ImageRead ( ImageContext->Handle, - DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize, + DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize, &Size, ImageContext->CodeView ); @@ -1016,11 +1095,11 @@ PeCoffLoaderLoadImage ( switch (*(UINT32 *) ImageContext->CodeView) { case CODEVIEW_SIGNATURE_NB10: - ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); + ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); break; case CODEVIEW_SIGNATURE_RSDS: - ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); + ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); break; default: @@ -1032,3 +1111,228 @@ PeCoffLoaderLoadImage ( return Status; } + + +/** + Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI + runtime. + + PE_COFF_LOADER_IMAGE_CONTEXT.FixupData stores information needed to reapply + the fixups with a virtual mapping. + + + @param ImageBase Base address of relocated image + @param VirtImageBase Virtual mapping for ImageBase + @param ImageSize Size of the image to relocate + @param RelocationData Location to place results of read + +**/ +VOID +EFIAPI +PeCoffLoaderRelocateImageForRuntime ( + IN PHYSICAL_ADDRESS ImageBase, + IN PHYSICAL_ADDRESS VirtImageBase, + IN UINTN ImageSize, + IN VOID *RelocationData + ) +{ + CHAR8 *OldBase; + CHAR8 *NewBase; + 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 *F16; + UINT32 *F32; + UINT64 *F64; + CHAR8 *FixupData; + UINTN Adjust; + RETURN_STATUS Status; + + OldBase = (CHAR8 *)((UINTN)ImageBase); + NewBase = (CHAR8 *)((UINTN)VirtImageBase); + Adjust = (UINTN) NewBase - (UINTN) OldBase; + + // + // 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 ; + } + + // + // Get some data from the PE type dependent data + // + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } else { + // + // Use PE32+ offset + // + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } + + // + // 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 + // + ASSERT (FALSE); + return ; + } + + 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) { + + 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: + F16 = (UINT16 *) Fixup; + if (*(UINT16 *) FixupData == *F16) { + *F16 = (UINT16) ((*F16 << 16) + ((UINT16) Adjust & 0xffff)); + } + + FixupData = FixupData + sizeof (UINT16); + break; + + case EFI_IMAGE_REL_BASED_LOW: + F16 = (UINT16 *) Fixup; + if (*(UINT16 *) FixupData == *F16) { + *F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff)); + } + + FixupData = FixupData + sizeof (UINT16); + break; + + case EFI_IMAGE_REL_BASED_HIGHLOW: + F32 = (UINT32 *) Fixup; + FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32)); + if (*(UINT32 *) FixupData == *F32) { + *F32 = *F32 + (UINT32) Adjust; + } + + FixupData = FixupData + sizeof (UINT32); + break; + + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *)Fixup; + FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64)); + if (*(UINT32 *) FixupData == *F64) { + *F64 = *F64 + (UINT64)Adjust; + } + break; + + case EFI_IMAGE_REL_BASED_HIGHADJ: + // + // Not implemented, but not used in EFI 1.0 + // + ASSERT (FALSE); + break; + + default: + // + // Only Itanium requires ConvertPeImage_Ex + // + Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust); + if (RETURN_ERROR (Status)) { + return ; + } + } + // + // Next relocation record + // + Reloc += 1; + } + // + // next reloc block + // + RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd; + } +} + + +/** + ImageRead function that operates on a memory buffer whos base is passed into + FileHandle. + + @param FileHandle Ponter to baes of the input stream + @param FileOffset Offset to the start of the buffer + @param ReadSize Number of bytes to copy into the buffer + @param Buffer Location to place results of read + + @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into + the buffer. +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderImageReadFromMemory ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize); + return RETURN_SUCCESS; +} + diff --git a/MdePkg/Library/BasePeCoffLib/BasePeCoffLib.msa b/MdePkg/Library/BasePeCoffLib/BasePeCoffLib.msa index 69094ad1b8..6e4f9e0e36 100644 --- a/MdePkg/Library/BasePeCoffLib/BasePeCoffLib.msa +++ b/MdePkg/Library/BasePeCoffLib/BasePeCoffLib.msa @@ -1,15 +1,5 @@ - - + BasePeCoffLib BASE @@ -18,11 +8,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Component description file for Base PE/COFF Library PE/COFF Loader Library implementation. Copyright (c) 2006, Intel Corporation. - All rights reserved. This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052 @@ -41,6 +31,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. DebugLib + + PcdLib + BasePeCoff.c diff --git a/MdePkg/Library/BasePeCoffLib/Ebc/PeCoffLoaderEx.c b/MdePkg/Library/BasePeCoffLib/Ebc/PeCoffLoaderEx.c index fe41ac03bd..4289d0bb95 100644 --- a/MdePkg/Library/BasePeCoffLib/Ebc/PeCoffLoaderEx.c +++ b/MdePkg/Library/BasePeCoffLib/Ebc/PeCoffLoaderEx.c @@ -38,3 +38,56 @@ PeCoffLoaderRelocateImageEx ( { return RETURN_UNSUPPORTED; } + +/** + Returns TRUE if the machine type of PE/COFF image is supported. Supported + does not mean the image can be executed it means the PE/COFF loader supports + loading and relocating of the image type. It's up to the caller to support + the entry point. + + This function implies the basic PE/COFF loader/relocator supports IA32, EBC, + & X64 images. Calling the entry point in a correct mannor is up to the + consumer of this library. + + @param Machine Machine type from the PE Header. + + @return TRUE if this PE/COFF loader can load the image + +**/ +BOOLEAN +PeCoffLoaderImageFormatSupported ( + IN UINT16 Machine + ) +{ + if ((Machine == EFI_IMAGE_MACHINE_IA32) || (Machine == EFI_IMAGE_MACHINE_X64) || + (Machine == EFI_IMAGE_MACHINE_EBC)) { + return TRUE; + } + + return FALSE; +} + + +/** + 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 Pointer to the relocation record. + @param Fixup Pointer to the address to fix up. + @param FixupData Pointer to a buffer to log the fixups. + @param Adjust The offset to adjust the fixup. + + @return Status code. + +**/ +RETURN_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + return RETURN_UNSUPPORTED; +} diff --git a/MdePkg/Library/BasePeCoffLib/Ia32/PeCoffLoaderEx.c b/MdePkg/Library/BasePeCoffLib/Ia32/PeCoffLoaderEx.c index 9a2b2a04dd..9515a09f4d 100644 --- a/MdePkg/Library/BasePeCoffLib/Ia32/PeCoffLoaderEx.c +++ b/MdePkg/Library/BasePeCoffLib/Ia32/PeCoffLoaderEx.c @@ -39,3 +39,56 @@ PeCoffLoaderRelocateImageEx ( { return RETURN_UNSUPPORTED; } + +/** + Returns TRUE if the machine type of PE/COFF image is supported. Supported + does not mean the image can be executed it means the PE/COFF loader supports + loading and relocating of the image type. It's up to the caller to support + the entry point. + + This function implies the basic PE/COFF loader/relocator supports IA32, EBC, + & X64 images. Calling the entry point in a correct mannor is up to the + consumer of this library. + + @param Machine Machine type from the PE Header. + + @return TRUE if this PE/COFF loader can load the image + +**/ +BOOLEAN +PeCoffLoaderImageFormatSupported ( + IN UINT16 Machine + ) +{ + if ((Machine == EFI_IMAGE_MACHINE_IA32) || (Machine == EFI_IMAGE_MACHINE_X64) || + (Machine == EFI_IMAGE_MACHINE_EBC)) { + return TRUE; + } + + return FALSE; +} + +/** + 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 Pointer to the relocation record. + @param Fixup Pointer to the address to fix up. + @param FixupData Pointer to a buffer to log the fixups. + @param Adjust The offset to adjust the fixup. + + @return Status code. + +**/ +RETURN_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + return RETURN_UNSUPPORTED; +} + diff --git a/MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c b/MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c index 57c6555408..adbd3fca81 100644 --- a/MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c +++ b/MdePkg/Library/BasePeCoffLib/Ipf/PeCoffLoaderEx.c @@ -88,17 +88,6 @@ PeCoffLoaderRelocateImageEx ( UINT64 FixupVal; switch ((*Reloc) >> 12) { - - case EFI_IMAGE_REL_BASED_DIR64: - F64 = (UINT64 *) Fixup; - *F64 = *F64 + (UINT64) Adjust; - if (*FixupData != NULL) { - *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64)); - *(UINT64 *)(*FixupData) = *F64; - *FixupData = *FixupData + sizeof(UINT64); - } - break; - case EFI_IMAGE_REL_BASED_IA64_IMM64: // @@ -225,3 +214,232 @@ PeCoffLoaderRelocateImageEx ( return RETURN_SUCCESS; } + +/** + Returns TRUE if the machine type of PE/COFF image is supported. Supported + does not mean the image can be executed it means the PE/COFF loader supports + loading and relocating of the image type. It's up to the caller to support + the entry point. + + This function implies the basic PE/COFF loader/relocator supports IA32, EBC, + & X64 images. Calling the entry point in a correct mannor is up to the + consumer of this library. This version also supports the special relocations + for Itanium. + + @param Machine Machine type from the PE Header. + + @return TRUE if this PE/COFF loader can load the image + +**/ +BOOLEAN +PeCoffLoaderImageFormatSupported ( + IN UINT16 Machine + ) +{ + if ((Machine == EFI_IMAGE_MACHINE_IPF) || (Machine == EFI_IMAGE_MACHINE_IA32) || + (Machine == EFI_IMAGE_MACHINE_EBC) || (Machine == EFI_IMAGE_MACHINE_X64)) { + return TRUE; + } + + return FALSE; +} + + +/** + 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 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. +**/ +RETURN_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +/*++ + +Routine Description: + + Performs an IPF specific relocation fixup + +Arguments: + + Reloc - Pointer to the relocation record + + Fixup - Pointer to the address to fix up + + FixupData - Pointer to a buffer to log the fixups + + Adjust - The offset to adjust the fixup + +Returns: + + None + +--*/ +{ + UINT64 *F64; + UINT64 FixupVal; + + switch ((*Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *) Fixup; + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT64)); + if (*(UINT64 *) (*FixupData) == *F64) { + *F64 = *F64 + (UINT64) Adjust; + } + + *FixupData = *FixupData + sizeof (UINT64); + break; + + case EFI_IMAGE_REL_BASED_IA64_IMM64: + F64 = (UINT64 *) Fixup; + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT64)); + if (*(UINT64 *) (*FixupData) == *F64) { + // + // Align it to bundle address before fixing up the + // 64-bit immediate value of the movl instruction. + // + // + Fixup = (CHAR8 *) ((UINT64) Fixup & (UINT64)~(15)); + FixupVal = (UINT64) 0; + + // + // Extract the lower 32 bits of IMM64 from bundle + // + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IMM7B_INST_WORD_X, + IMM64_IMM7B_SIZE_X, + IMM64_IMM7B_INST_WORD_POS_X, + IMM64_IMM7B_VAL_POS_X + ); + + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IMM9D_INST_WORD_X, + IMM64_IMM9D_SIZE_X, + IMM64_IMM9D_INST_WORD_POS_X, + IMM64_IMM9D_VAL_POS_X + ); + + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IMM5C_INST_WORD_X, + IMM64_IMM5C_SIZE_X, + IMM64_IMM5C_INST_WORD_POS_X, + IMM64_IMM5C_VAL_POS_X + ); + + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IC_INST_WORD_X, + IMM64_IC_SIZE_X, + IMM64_IC_INST_WORD_POS_X, + IMM64_IC_VAL_POS_X + ); + + EXT_IMM64 ( + FixupVal, + (UINT32 *) Fixup + IMM64_IMM41a_INST_WORD_X, + IMM64_IMM41a_SIZE_X, + IMM64_IMM41a_INST_WORD_POS_X, + IMM64_IMM41a_VAL_POS_X + ); + + // + // Update 64-bit address + // + FixupVal += Adjust; + + // + // Insert IMM64 into bundle + // + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM7B_INST_WORD_X), + IMM64_IMM7B_SIZE_X, + IMM64_IMM7B_INST_WORD_POS_X, + IMM64_IMM7B_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM9D_INST_WORD_X), + IMM64_IMM9D_SIZE_X, + IMM64_IMM9D_INST_WORD_POS_X, + IMM64_IMM9D_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM5C_INST_WORD_X), + IMM64_IMM5C_SIZE_X, + IMM64_IMM5C_INST_WORD_POS_X, + IMM64_IMM5C_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IC_INST_WORD_X), + IMM64_IC_SIZE_X, + IMM64_IC_INST_WORD_POS_X, + IMM64_IC_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM41a_INST_WORD_X), + IMM64_IMM41a_SIZE_X, + IMM64_IMM41a_INST_WORD_POS_X, + IMM64_IMM41a_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM41b_INST_WORD_X), + IMM64_IMM41b_SIZE_X, + IMM64_IMM41b_INST_WORD_POS_X, + IMM64_IMM41b_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_IMM41c_INST_WORD_X), + IMM64_IMM41c_SIZE_X, + IMM64_IMM41c_INST_WORD_POS_X, + IMM64_IMM41c_VAL_POS_X + ); + + INS_IMM64 ( + FixupVal, + ((UINT32 *) Fixup + IMM64_SIGN_INST_WORD_X), + IMM64_SIGN_SIZE_X, + IMM64_SIGN_INST_WORD_POS_X, + IMM64_SIGN_VAL_POS_X + ); + + *(UINT64 *) (*FixupData) = *F64; + } + + *FixupData = *FixupData + sizeof (UINT64); + break; + + default: + DEBUG ((EFI_D_ERROR, "PeHotRelocateEx:unknown fixed type\n")); + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + + + diff --git a/MdePkg/Library/BasePeCoffLib/x64/PeCoffLoaderEx.c b/MdePkg/Library/BasePeCoffLib/x64/PeCoffLoaderEx.c index db7eead97d..7141adc2ad 100644 --- a/MdePkg/Library/BasePeCoffLib/x64/PeCoffLoaderEx.c +++ b/MdePkg/Library/BasePeCoffLib/x64/PeCoffLoaderEx.c @@ -31,23 +31,58 @@ PeCoffLoaderRelocateImageEx ( IN UINT64 Adjust ) { - UINT64 *F64; - - switch ((*Reloc) >> 12) { - - case EFI_IMAGE_REL_BASED_DIR64: - F64 = (UINT64 *) Fixup; - *F64 = *F64 + (UINT64) Adjust; - if (*FixupData != NULL) { - *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64)); - *(UINT64 *)(*FixupData) = *F64; - *FixupData = *FixupData + sizeof(UINT64); - } - break; - - default: - return RETURN_UNSUPPORTED; + return RETURN_UNSUPPORTED; +} + +/** + Returns TRUE if the machine type of PE/COFF image is supported. Supported + does not mean the image can be executed it means the PE/COFF loader supports + loading and relocating of the image type. It's up to the caller to support + the entry point. + + This function implies the basic PE/COFF loader/relocator supports IA32, EBC, + & X64 images. Calling the entry point in a correct mannor is up to the + consumer of this library. + + @param Machine Machine type from the PE Header. + + @return TRUE if this PE/COFF loader can load the image + +**/ +BOOLEAN +PeCoffLoaderImageFormatSupported ( + IN UINT16 Machine + ) +{ + if ((Machine == EFI_IMAGE_MACHINE_IA32) || (Machine == EFI_IMAGE_MACHINE_X64) || + (Machine == EFI_IMAGE_MACHINE_EBC)) { + return TRUE; } - return RETURN_SUCCESS; + return FALSE; +} + + +/** + 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 Pointer to the relocation record. + @param Fixup Pointer to the address to fix up. + @param FixupData Pointer to a buffer to log the fixups. + @param Adjust The offset to adjust the fixup. + + @return Status code. + +**/ +RETURN_STATUS +PeHotRelocateImageEx ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + return RETURN_UNSUPPORTED; } -- cgit v1.2.3