git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@151 6f19259b...
authorlgao4 <lgao4@6f19259b-4bc3-4df7-8a09-765794883524>
Sun, 14 May 2006 09:16:06 +0000 (09:16 +0000)
committerlgao4 <lgao4@6f19259b-4bc3-4df7-8a09-765794883524>
Sun, 14 May 2006 09:16:06 +0000 (09:16 +0000)
EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.c [new file with mode: 0644]
EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.mbd [new file with mode: 0644]
EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.msa [new file with mode: 0644]
EdkModulePkg/Library/EdkPeCoffLoaderLibX64/build.xml [new file with mode: 0644]

diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.c b/EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.c
new file mode 100644 (file)
index 0000000..5ed74f5
--- /dev/null
@@ -0,0 +1,940 @@
+/*++
+
+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,                     
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+
+Module Name:
+
+  EdkPeCoffLoaderX64.c
+
+Abstract:
+
+  Wrap the Base PE/COFF loader with the PE COFF Protocol
+
+
+--*/
+
+#define IMAGE_64_MACHINE_TYPE_SUPPORTED(Machine) \
+  ((Machine) == EFI_IMAGE_MACHINE_IA32 || \
+   (Machine) == EFI_IMAGE_MACHINE_X64 || \
+   (Machine) == EFI_IMAGE_MACHINE_EBC)
+
+STATIC
+EFI_STATUS
+PeCoffLoader64GetPeHeader (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,
+  OUT    EFI_IMAGE_NT_HEADERS64                  *PeHdr
+  );
+
+STATIC
+EFI_STATUS
+PeCoffLoader64CheckImageType (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,
+  IN     EFI_IMAGE_NT_HEADERS64                  *PeHdr
+  );
+
+STATIC
+VOID *
+PeCoffLoader64ImageAddress (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,
+  IN     UINTN                                 Address
+  );
+
+EFI_STATUS
+EFIAPI
+PeCoffLoader64GetImageInfo (
+  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL       *This,
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  );
+
+EFI_STATUS
+EFIAPI
+PeCoffLoader64RelocateImage (
+  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL       *This,
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  );
+
+EFI_STATUS
+EFIAPI
+PeCoffLoader64LoadImage (
+  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL       *This,
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
+  );
+
+EFI_STATUS
+EFIAPI
+PeCoffLoader64UnloadImage (
+  IN EFI_PEI_PE_COFF_LOADER_PROTOCOL      *This,
+  IN PE_COFF_LOADER_IMAGE_CONTEXT   *ImageContext
+  );
+
+EFI_STATUS
+PeCoffLoader64RelocateImageEx (
+  IN UINT16      *Reloc,
+  IN OUT CHAR8   *Fixup, 
+  IN OUT CHAR8   **FixupData,
+  IN UINT64      Adjust
+  );
+
+EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoaderX64 = {
+  PeCoffLoader64GetImageInfo,
+  PeCoffLoader64LoadImage,
+  PeCoffLoader64RelocateImage,
+  PeCoffLoader64UnloadImage
+};
+
+STATIC
+EFI_STATUS
+PeCoffLoader64GetPeHeader (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,
+  OUT    EFI_IMAGE_NT_HEADERS64                *PeHdr
+  )
+/*++
+
+Routine Description:
+  Retrieves the PE Header from a PE/COFF image
+
+Arguments:
+  ImageContext  - The context of the image being loaded
+  PeHdr         - The buffer in which to return the PE header
+
+Returns:
+  EFI_SUCCESS if the PE Header is read, 
+  Otherwise, the error status from reading the PE/COFF image using the ImageRead function.
+
+--*/
+{
+  EFI_STATUS            Status;
+  EFI_IMAGE_DOS_HEADER  DosHdr;
+  UINTN                 Size;
+  
+  //
+  // Read the DOS image headers
+  //
+  Size = sizeof (EFI_IMAGE_DOS_HEADER);
+  Status = ImageContext->ImageRead (
+                           ImageContext->Handle, 
+                           0,
+                           &Size, 
+                           &DosHdr
+                           );
+  if (EFI_ERROR (Status)) {
+    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+    return Status;
+  }
+
+  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
+    //
+    ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
+  } 
+
+  //
+  // Read the PE/COFF Header
+  //
+  Size = sizeof (EFI_IMAGE_NT_HEADERS64);
+  Status = ImageContext->ImageRead (
+                           ImageContext->Handle, 
+                           ImageContext->PeCoffHeaderOffset, 
+                           &Size, 
+                           PeHdr
+                           );
+  if (EFI_ERROR (Status)) {
+      ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+      return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+static
+EFI_STATUS
+PeCoffLoader64CheckImageType (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT      *ImageContext,
+  IN     EFI_IMAGE_NT_HEADERS64                    *PeHdr
+  )
+/*++
+
+Routine Description:
+  Checks the PE header of a PE/COFF image to determine if it supported
+
+Arguments:
+  ImageContext  - The context of the image being loaded
+  PeHdr         - The buffer in which to return the PE header
+
+Returns:
+  EFI_SUCCESS if the PE/COFF image is supported
+  EFI_UNSUPPORTED of the PE/COFF image is not supported.
+
+--*/
+{
+  //
+  // Check the PE/COFF Header SIgnature
+  //
+  if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
+    ImageContext->ImageError = IMAGE_ERROR_INVALID_PE_HEADER_SIGNATURE;
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // 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.
+  //
+  ImageContext->Machine = PeHdr->FileHeader.Machine;
+  if (!(IMAGE_64_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) {
+    ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // See if the image type is supported.  We support EFI Applications, 
+  // EFI Boot Service Drivers, and EFI Runtime Drivers.
+  //
+  ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem;
+  switch (ImageContext->ImageType) {
+
+  case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+    ImageContext->ImageCodeMemoryType = EfiLoaderCode;
+    ImageContext->ImageDataMemoryType = EfiLoaderData;
+    break;
+  
+  case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+    ImageContext->ImageCodeMemoryType = EfiBootServicesCode;
+    ImageContext->ImageDataMemoryType = EfiBootServicesData;
+    break;
+  
+  case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+  case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
+    ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;
+    ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;
+    break;
+  
+  default:
+    ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
+    return EFI_UNSUPPORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+PeCoffLoader64GetImageInfo (
+  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL           *This,
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT      *ImageContext
+  )
+/*++
+
+Routine Description:
+  Retrieves information on a PE/COFF image
+
+Arguments:
+  ImageContext  - The context of the image being loaded
+  PeHdr         - The buffer in which to return the PE header
+
+Returns:
+  EFI_SUCCESS if the information on the PE/COFF image was collected.
+  EFI_UNSUPPORTED of the PE/COFF image is not supported.
+  Otherwise, the error status from reading the PE/COFF image using the 
+    ImageContext->ImageRead() function
+
+--*/
+{
+  EFI_STATUS                      Status;
+  EFI_IMAGE_NT_HEADERS64          PeHdr;
+  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;
+
+  if (NULL == ImageContext) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Assume success
+  //
+  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
+  
+  Status = PeCoffLoader64GetPeHeader (ImageContext, &PeHdr);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Verify machine type
+  //
+  Status = PeCoffLoader64CheckImageType (ImageContext, &PeHdr);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  //
+  // Retrieve the base address of the image
+  //
+  ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase;
+  
+  //
+  // Initialize the alternate destination address to 0 indicating that it 
+  // should not be used.
+  //
+  ImageContext->DestinationAddress = 0;
+
+  //
+  // Initialize the codeview pointer.
+  //
+  ImageContext->CodeView   = NULL;
+  ImageContext->PdbPointer = NULL;
+  
+  //
+  // Three cases with regards to relocations:
+  // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable
+  // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
+  // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
+  //   has no base relocs to apply
+  // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
+  //
+  // Look at the file header to determine if relocations have been stripped, and
+  // save this info in the image context for later use.
+  //
+  if (PeHdr.FileHeader.Characteristics &  EFI_IMAGE_FILE_RELOCS_STRIPPED) {
+    ImageContext->RelocationsStripped = TRUE;
+  } else {
+    ImageContext->RelocationsStripped = FALSE;
+  }
+
+  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]);
+
+    DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
+
+    //
+    // Determine the file offset of the debug directory...  This means we walk
+    // the sections to find which section contains the RVA of the debug
+    // directory
+    //
+    
+    DebugDirectoryEntryFileOffset = 0;
+    
+    SectionHeaderOffset = (UINTN) (
+                      ImageContext->PeCoffHeaderOffset +
+                      sizeof (UINT32) + 
+                      sizeof (EFI_IMAGE_FILE_HEADER) + 
+                      PeHdr.FileHeader.SizeOfOptionalHeader
+                      );
+    
+    for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index += 1) {
+      //
+      // Read section header from file
+      //
+      Size = sizeof (EFI_IMAGE_SECTION_HEADER);
+      Status = ImageContext->ImageRead (
+                               ImageContext->Handle, 
+                               SectionHeaderOffset, 
+                               &Size, 
+                               &SectionHeader
+                               );
+      if (EFI_ERROR (Status)) {
+        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+        return Status;
+      }
+      
+      if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
+          DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
+        DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
+        break;
+      }
+      
+      SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
+    }
+    
+    if (DebugDirectoryEntryFileOffset != 0) {
+      for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {
+        //
+        // Read next debug directory entry
+        //
+        Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
+        Status = ImageContext->ImageRead (
+                                 ImageContext->Handle, 
+                                 DebugDirectoryEntryFileOffset, 
+                                 &Size, 
+                                 &DebugEntry
+                                 );
+        if (EFI_ERROR (Status)) {
+          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+          return Status;
+        }
+        if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
+          ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
+          if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
+            ImageContext->ImageSize += DebugEntry.SizeOfData;
+          }
+          return EFI_SUCCESS;
+        }
+      }
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+static
+VOID *
+PeCoffLoader64ImageAddress (
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT      *ImageContext,
+  IN     UINTN                                     Address
+  )
+/*++
+
+Routine Description:
+  Converts an image address to the loaded address
+
+Arguments:
+  ImageContext  - The context of the image being loaded
+  Address       - The address to be converted to the loaded address
+
+Returns:
+  NULL if the address can not be converted, otherwise, the converted address
+
+--*/
+{
+  if (Address >= ImageContext->ImageSize) {
+    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
+    return NULL;
+  }
+  return (CHAR8 *)((UINTN)ImageContext->ImageAddress + Address);
+}
+
+EFI_STATUS
+EFIAPI
+PeCoffLoader64RelocateImage (
+  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL           *This,
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT      *ImageContext
+  )
+/*++
+
+Routine Description:
+  Relocates a PE/COFF image in memory
+
+Arguments:
+  ImageContext - Contains information on the loaded image to relocate
+
+Returns:
+  EFI_SUCCESS    if the PE/COFF image was relocated
+  EFI_LOAD_ERROR if the image is not a valid PE/COFF image
+
+--*/
+{
+  EFI_STATUS                 Status;
+  EFI_IMAGE_NT_HEADERS64     *PeHdr;
+  EFI_IMAGE_DATA_DIRECTORY   *RelocDir;
+  IN 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;
+  EFI_PHYSICAL_ADDRESS       BaseAddress;
+
+
+  //
+  // Assume success
+  //
+  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
+
+  //
+  // If there are no relocation entries, then we are done
+  //
+  if (ImageContext->RelocationsStripped) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // If the destination address is not 0, use that rather than the
+  // image address as the relocation target.
+  //
+  if (ImageContext->DestinationAddress) {
+    BaseAddress = ImageContext->DestinationAddress;
+  } else {
+    BaseAddress = ImageContext->ImageAddress;
+  }
+  PeHdr    = (EFI_IMAGE_NT_HEADERS64 *)((UINTN)ImageContext->ImageAddress + 
+                                            ImageContext->PeCoffHeaderOffset);
+  Adjust   = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase;
+
+  PeHdr->OptionalHeader.ImageBase = (UINTN) BaseAddress;
+
+  //
+  // 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];
+    RelocBase = PeCoffLoader64ImageAddress (ImageContext, RelocDir->VirtualAddress);
+    RelocBaseEnd = PeCoffLoader64ImageAddress ( 
+                    ImageContext, 
+                    RelocDir->VirtualAddress + RelocDir->Size - 1
+                    );
+} else {
+    //
+    // Set base and end to bypass processing below.
+    //
+    RelocBase = RelocBaseEnd = 0;
+  }
+  //
+  // Run the relocation information and apply the fixups
+  //
+  FixupData = ImageContext->FixupData;
+  while (RelocBase < RelocBaseEnd) {
+           
+    Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof(EFI_IMAGE_BASE_RELOCATION));
+    RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
+    FixupBase = PeCoffLoader64ImageAddress (ImageContext, RelocBase->VirtualAddress);
+    if ((CHAR8 *) RelocEnd < (CHAR8 *)((UINTN)ImageContext->ImageAddress) || 
+        (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + 
+          (UINTN)ImageContext->ImageSize)) {
+      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
+      return EFI_LOAD_ERROR;
+    }
+
+    //
+    // 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;
+        *F16 = (UINT16)((*F16 << 16) + (UINT16) Adjust);
+        if (FixupData != NULL) {
+          *(UINT16 *) FixupData = *F16;
+          FixupData = FixupData + sizeof(UINT16);
+        }
+        break;
+      case EFI_IMAGE_REL_BASED_LOW:
+        F16 = (UINT16 *) Fixup;
+        *F16 = (UINT16)(*F16 + (UINT16) Adjust);
+        if (FixupData != NULL) {
+          *(UINT16 *) FixupData = *F16;
+          FixupData = FixupData + sizeof(UINT16);
+        }
+        break;
+      case EFI_IMAGE_REL_BASED_HIGHLOW:
+        F32 = (UINT32 *) Fixup;
+        *F32 = *F32 + (UINT32) Adjust;
+        if (FixupData != NULL) {
+          FixupData = ALIGN_POINTER(FixupData, sizeof(UINT32));
+          *(UINT32 *) FixupData = *F32;
+          FixupData = FixupData + sizeof(UINT32);
+        }
+        break;
+      case EFI_IMAGE_REL_BASED_HIGHADJ:
+        // Return the same EFI_UNSUPPORTED return code as 
+        // PeCoffLoader64RelocateImageEx() returns if it does not recognize
+        // the relocation type.
+        //
+        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
+        return EFI_UNSUPPORTED;
+      default:
+        Status = PeCoffLoader64RelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
+        if (EFI_ERROR (Status)) {
+          ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
+          return Status;
+        }
+      }
+
+      //
+      // Next relocation record
+      //
+      Reloc += 1;
+    }
+
+    //
+    // Next reloc block
+    //
+    RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+PeCoffLoader64RelocateImageEx (
+  IN UINT16      *Reloc,
+  IN OUT CHAR8   *Fixup, 
+  IN OUT CHAR8   **FixupData,
+  IN UINT64      Adjust
+  )
+/*++
+
+Routine Description:
+  Performs an IA-32 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;
+
+  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 EFI_UNSUPPORTED;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+PeCoffLoader64LoadImage (
+  IN     EFI_PEI_PE_COFF_LOADER_PROTOCOL           *This,
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT      *ImageContext
+  )
+/*++
+
+Routine Description:
+  Loads a PE/COFF image into memory
+
+Arguments:
+  ImageContext - Contains information on image to load into memory
+
+Returns:
+  EFI_SUCCESS            if the PE/COFF image was loaded
+  EFI_BUFFER_TOO_SMALL   if the caller did not provide a large enough buffer
+  EFI_LOAD_ERROR         if the image is a runtime driver with no relocations
+  EFI_INVALID_PARAMETER  if the image address is invalid
+
+--*/
+{
+  EFI_STATUS                            Status;
+  EFI_IMAGE_NT_HEADERS64                *PeHdr;
+  PE_COFF_LOADER_IMAGE_CONTEXT  CheckContext;
+  EFI_IMAGE_SECTION_HEADER              *FirstSection;
+  EFI_IMAGE_SECTION_HEADER              *Section;
+  UINTN                                 Index;
+  CHAR8                                 *Base;
+  CHAR8                                 *End;
+  CHAR8                                 *MaxEnd;
+  EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
+  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
+  UINTN                                 Size;
+  UINT32                                TempDebugEntryRva;
+
+  //
+  // Assume success
+  //
+  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
+
+  //
+  // Copy the provided context info into our local version, get what we
+  // can from the original image, and then use that to make sure everything
+  // is legit.
+  //
+  CopyMem (
+    &CheckContext, 
+    ImageContext, 
+    sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)
+    );
+            
+  Status = PeCoffLoader64GetImageInfo (
+             This,
+             &CheckContext 
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Make sure there is enough allocated space for the image being loaded
+  //
+  if (ImageContext->ImageSize < CheckContext.ImageSize) {
+    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  //
+  // If there's no relocations, then make sure it's not a runtime driver,
+  // and that it's being loaded at the linked address.
+  //
+  if (CheckContext.RelocationsStripped == TRUE) {
+    //
+    // If the image does not contain relocations and it is a runtime driver 
+    // then return an error.
+    //
+    if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
+      ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
+      return EFI_LOAD_ERROR;
+    }
+    //
+    // If the image does not contain relocations, and the requested load address 
+    // is not the linked address, then return an error.
+    //
+    if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
+      ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Make sure the allocated space has the proper section alignment
+  //
+  if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
+    ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Read the entire PE/COFF header into memory
+  //
+  Status = ImageContext->ImageRead (
+                ImageContext->Handle, 
+                0, 
+                &ImageContext->SizeOfHeaders, 
+                (VOID *)(UINTN)ImageContext->ImageAddress
+                );
+  if (EFI_ERROR(Status)) {
+    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+    return EFI_LOAD_ERROR;
+  }
+
+  PeHdr = (EFI_IMAGE_NT_HEADERS64 *)
+      ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
+
+  //
+  // Load each section of the image
+  //
+  FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
+                      (UINTN)ImageContext->ImageAddress +
+                      ImageContext->PeCoffHeaderOffset +
+                      sizeof(UINT32) + 
+                      sizeof(EFI_IMAGE_FILE_HEADER) + 
+                      PeHdr->FileHeader.SizeOfOptionalHeader
+                      );
+
+  Section = FirstSection;
+  for ( Index=0, MaxEnd = NULL; 
+        Index < PeHdr->FileHeader.NumberOfSections; 
+        Index += 1) {
+
+    //
+    // Compute sections address
+    //
+    Base = PeCoffLoader64ImageAddress (ImageContext, Section->VirtualAddress);
+    End  = PeCoffLoader64ImageAddress (
+                  ImageContext, 
+                  Section->VirtualAddress + Section->Misc.VirtualSize - 1);
+    if (End > MaxEnd) {
+      MaxEnd = End;
+    }
+    //
+    // If the base start or end address resolved to 0, then fail.
+    //
+    if (!Base  ||  !End) {
+      ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
+      return EFI_LOAD_ERROR;
+    }
+
+    //
+    // Read the section, we can resume the length of PE image can't 
+    // exceed the max 32bit integer
+    //
+    Size = (UINTN) Section->Misc.VirtualSize;
+    if ((Size == 0) || (Size > Section->SizeOfRawData)) {
+      Size = (UINTN) Section->SizeOfRawData;
+    }
+    if (Section->SizeOfRawData) {
+      Status = ImageContext->ImageRead (
+                               ImageContext->Handle, 
+                               Section->PointerToRawData, 
+                               &Size, 
+                               Base);
+      if (EFI_ERROR(Status)) {
+        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+        return Status;
+      }
+    }
+
+    //
+    // If raw size is less then virt size, zero fill the remaining
+    //
+
+    if (Size < Section->Misc.VirtualSize) {
+      ZeroMem (Base + Size, Section->Misc.VirtualSize - (UINTN)Size);
+    }
+
+    //
+    // Next Section
+    //
+    Section += 1;
+  }
+
+  //
+  // Get image's entry point
+  //
+  ImageContext->EntryPoint = 
+      (EFI_PHYSICAL_ADDRESS) (UINTN) PeCoffLoader64ImageAddress (
+                                      ImageContext, 
+                                      PeHdr->OptionalHeader.AddressOfEntryPoint
+                                      );
+
+  //
+  // Determine the size of the fixup data
+  //
+  // 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) {
+    DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
+      &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+    ImageContext->FixupDataSize = 
+      DirectoryEntry->Size / sizeof(UINT16) * sizeof(UINTN);
+  } else {
+    ImageContext->FixupDataSize = 0;
+  }
+  //
+  // Consumer must allocate a buffer for the relocation fixup log.
+  // Only used for runtime drivers.
+  //
+  ImageContext->FixupData     = NULL;
+
+  //
+  // Load the Codeview info if present
+  //
+  if (ImageContext->DebugDirectoryEntryRva != 0) {
+    DebugEntry = PeCoffLoader64ImageAddress (
+                  ImageContext, 
+                  ImageContext->DebugDirectoryEntryRva
+                  );
+    if (DebugEntry != NULL) {
+      TempDebugEntryRva = DebugEntry->RVA;
+      if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
+        Section--;
+        if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
+          TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
+        } else {
+          TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
+        }
+      }
+      if (TempDebugEntryRva != 0) {
+        ImageContext->CodeView = PeCoffLoader64ImageAddress (ImageContext, TempDebugEntryRva);
+        if (ImageContext->CodeView == NULL) {
+          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+          return EFI_LOAD_ERROR;
+        }
+
+        if (DebugEntry->RVA == 0) {
+          Size = (UINTN) DebugEntry->SizeOfData;
+          Status = ImageContext->ImageRead (
+                        ImageContext->Handle, 
+                        DebugEntry->FileOffset,
+                        &Size, 
+                        ImageContext->CodeView
+                        );
+          if (EFI_ERROR(Status)) {
+            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
+            return EFI_LOAD_ERROR;
+          }
+          DebugEntry->RVA = TempDebugEntryRva;
+        }
+
+        switch (* (UINT32 *) ImageContext->CodeView) {
+          case CODEVIEW_SIGNATURE_NB10:
+            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);
+            break;
+          default:
+            break;
+        }
+      }
+    }
+  }
+  
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+PeCoffLoader64UnloadImage (
+  IN EFI_PEI_PE_COFF_LOADER_PROTOCOL      *This,
+  IN PE_COFF_LOADER_IMAGE_CONTEXT   *ImageContext
+  )
+/*++
+
+Routine Description:
+  Unload of images is not supported
+
+Arguments:
+  ImageContext - The image to unload
+
+Returns:
+  EFI_SUCCESS
+
+--*/
+{
+  return EFI_SUCCESS;
+}
+
+EFI_PEI_PE_COFF_LOADER_PROTOCOL *
+EFIAPI
+GetPeCoffLoaderProtocol (
+  )
+{
+  return &mPeCoffLoaderX64;
+}
+
+
diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.mbd b/EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.mbd
new file mode 100644 (file)
index 0000000..fd0b050
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<LibraryModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0  http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+  <MbdLibHeader>
+    <BaseName>EdkPeCoffLoaderLibX64</BaseName>
+    <Guid>742597d6-2b50-4120-bfba-2400549a792f</Guid>
+    <Version>EDK_RELEASE_VERSION        0x00090000</Version>
+    <Description>FIX ME!</Description>
+    <Copyright>Copyright (c) 2006, Intel Corporation</Copyright>
+    <License>
+      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.
+    </License>
+    <Created>2006-04-26 13:50</Created>
+  </MbdLibHeader>
+</LibraryModuleBuildDescription>
diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.msa b/EdkModulePkg/Library/EdkPeCoffLoaderLibX64/EdkPeCoffLoaderLibX64.msa
new file mode 100644 (file)
index 0000000..eeb13dd
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<LibraryModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0  http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+  <MsaLibHeader>
+    <BaseName>EdkPeCoffLoaderLibX64</BaseName>
+    <ModuleType>DXE_CORE</ModuleType>
+    <ComponentType>LIBRARY</ComponentType>
+    <Guid>742597d6-2b50-4120-bfba-2400549a792f</Guid>
+    <Version>EDK_RELEASE_VERSION        0x00090000</Version>
+    <Abstract>Component description file for the PEI library.</Abstract>
+    <Description>FIX ME!</Description>
+    <Copyright>Copyright (c) 2006, Intel Corporation</Copyright>
+    <License>
+      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.
+    </License>
+    <Specification>EFI_SPECIFICATION_VERSION    0x00000000</Specification>
+    <Created>2006-04-26 13:50</Created>
+  </MsaLibHeader>
+  <LibraryClassDefinitions>
+    <LibraryClass Usage="ALWAYS_PRODUCED">EdkPeCoffLoaderLib</LibraryClass>
+    <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+    <LibraryClass Usage="ALWAYS_CONSUMED">PeCoffLib</LibraryClass>
+  </LibraryClassDefinitions>
+  <SourceFiles>
+    <Filename>EdkPeCoffLoaderLibX64.c</Filename>
+  </SourceFiles>
+  <Includes>
+    <PackageName>MdePkg</PackageName>
+    <PackageName>EdkModulePkg</PackageName>
+  </Includes>
+</LibraryModuleSurfaceArea>
diff --git a/EdkModulePkg/Library/EdkPeCoffLoaderLibX64/build.xml b/EdkModulePkg/Library/EdkPeCoffLoaderLibX64/build.xml
new file mode 100644 (file)
index 0000000..6a41900
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- 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, 
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.-->
+<project basedir="." default="EdkPeCoffLoaderLibX64"><!--Apply external ANT tasks-->
+   <taskdef resource="GenBuild.tasks"/>
+   <property environment="env"/>
+   <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+   <import file="${WORKSPACE_DIR}/Tools/Conf/BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+   <property name="MODULE_RELATIVE_PATH" value="Library/EdkPeCoffLoaderLibX64"/>
+   <property name="MODULE_DIR" value="${PACKAGE_DIR}/${MODULE_RELATIVE_PATH}"/>
+   <property name="COMMON_FILE" value="${WORKSPACE_DIR}/Tools/Conf/Common.xml"/>
+   <target name="EdkPeCoffLoaderLibX64">
+      <GenBuild baseName="EdkPeCoffLoaderLibX64" mbdFilename="${MODULE_DIR}/EdkPeCoffLoaderLibX64.mbd" msaFilename="${MODULE_DIR}/EdkPeCoffLoaderLibX64.msa"/>
+   </target>
+   <target depends="EdkPeCoffLoaderLibX64_clean" name="clean"/>
+   <target depends="EdkPeCoffLoaderLibX64_cleanAll" name="cleanAll"/>
+   <target name="EdkPeCoffLoaderLibX64_clean">
+      <OutputDirSetup baseName="EdkPeCoffLoaderLibX64" mbdFilename="${MODULE_DIR}/EdkPeCoffLoaderLibX64.mbd" msaFilename="${MODULE_DIR}/EdkPeCoffLoaderLibX64.msa"/>
+      <if>
+         <available file="${DEST_DIR_OUTPUT}/EdkPeCoffLoaderLibX64_build.xml"/>
+         <then>
+            <ant antfile="${DEST_DIR_OUTPUT}/EdkPeCoffLoaderLibX64_build.xml" target="clean"/>
+         </then>
+      </if>
+      <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+   </target>
+   <target name="EdkPeCoffLoaderLibX64_cleanAll">
+      <OutputDirSetup baseName="EdkPeCoffLoaderLibX64" mbdFilename="${MODULE_DIR}/EdkPeCoffLoaderLibX64.mbd" msaFilename="${MODULE_DIR}/EdkPeCoffLoaderLibX64.msa"/>
+      <if>
+         <available file="${DEST_DIR_OUTPUT}/EdkPeCoffLoaderLibX64_build.xml"/>
+         <then>
+            <ant antfile="${DEST_DIR_OUTPUT}/EdkPeCoffLoaderLibX64_build.xml" target="cleanAll"/>
+         </then>
+      </if>
+      <delete dir="${DEST_DIR_OUTPUT}"/>
+      <delete dir="${DEST_DIR_DEBUG}"/>
+      <delete>
+         <fileset dir="${BIN_DIR}" includes="**EdkPeCoffLoaderLibX64*"/>
+      </delete>
+   </target>
+</project>
\ No newline at end of file