+EFI_STATUS\r
+RebaseImageRead (\r
+ IN VOID *FileHandle,\r
+ IN UINTN FileOffset,\r
+ IN OUT UINT32 *ReadSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
+\r
+Arguments:\r
+\r
+ FileHandle - The handle to the PE/COFF file\r
+\r
+ FileOffset - The offset, in bytes, into the file to read\r
+\r
+ ReadSize - The number of bytes to read from the file starting at FileOffset\r
+\r
+ Buffer - A pointer to the buffer to read the data into.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
+\r
+--*/\r
+{\r
+ CHAR8 *Destination8;\r
+ CHAR8 *Source8;\r
+ UINT32 Length;\r
+\r
+ Destination8 = Buffer;\r
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
+ Length = *ReadSize;\r
+ while (Length--) {\r
+ *(Destination8++) = *(Source8++);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SetAddressToSectionHeader (\r
+ IN CHAR8 *FileName,\r
+ IN OUT UINT8 *FileBuffer,\r
+ IN UINT64 NewPe32BaseAddress\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set new base address into the section header of PeImage\r
+\r
+Arguments:\r
+\r
+ FileName - Name of file\r
+ FileBuffer - Pointer to PeImage.\r
+ NewPe32BaseAddress - New Base Address for PE image.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Set new base address into this image successfully.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ UINTN Index;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
+\r
+ //\r
+ // Initialize context\r
+ //\r
+ memset (&ImageContext, 0, sizeof (ImageContext));\r
+ ImageContext.Handle = (VOID *) FileBuffer;\r
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead;\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName);\r
+ return Status;\r
+ }\r
+\r
+ if (ImageContext.RelocationsStripped) {\r
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get PeHeader pointer\r
+ //\r
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset);\r
+\r
+ //\r
+ // Get section header list\r
+ //\r
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
+ (UINTN) ImgHdr +\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
+ );\r
+\r
+ //\r
+ // Set base address into the first section header that doesn't point to code section.\r
+ //\r
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
+ if ((SectionHeader->Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
+ *(UINT64 *) &SectionHeader->PointerToRelocations = NewPe32BaseAddress;\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // BaseAddress is set to section header.\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+RebaseImage (\r
+ IN CHAR8 *FileName,\r
+ IN OUT UINT8 *FileBuffer,\r
+ IN UINT64 NewPe32BaseAddress\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set new base address into PeImage, and fix up PeImage based on new address.\r
+\r
+Arguments:\r
+\r
+ FileName - Name of file\r
+ FileBuffer - Pointer to PeImage.\r
+ NewPe32BaseAddress - New Base Address for PE image.\r
+\r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - BaseAddress is not valid.\r
+ EFI_SUCCESS - Update PeImage is correctly.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ UINTN Index;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
+ UINT8 *MemoryImagePointer;\r
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
+\r
+ //\r
+ // Initialize context\r
+ //\r
+ memset (&ImageContext, 0, sizeof (ImageContext));\r
+ ImageContext.Handle = (VOID *) FileBuffer;\r
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead;\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName);\r
+ return Status;\r
+ }\r
+\r
+ if (ImageContext.RelocationsStripped) {\r
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get PeHeader pointer\r
+ //\r
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset);\r
+\r
+ //\r
+ // Load and Relocate Image Data\r
+ //\r
+ MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+ if (MemoryImagePointer == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+ ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((INT64)ImageContext.SectionAlignment - 1));\r
+\r
+ Status = PeCoffLoaderLoadImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
+ free ((VOID *) MemoryImagePointer);\r
+ return Status;\r
+ }\r
+\r
+ ImageContext.DestinationAddress = NewPe32BaseAddress;\r
+ Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
+ free ((VOID *) MemoryImagePointer);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Copy Relocated data to raw image file.\r
+ //\r
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
+ (UINTN) ImgHdr +\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
+ );\r
+\r
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
+ CopyMem (\r
+ FileBuffer + SectionHeader->PointerToRawData,\r
+ (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),\r
+ SectionHeader->SizeOfRawData\r
+ );\r
+ }\r
+\r
+ free ((VOID *) MemoryImagePointer);\r
+\r
+ //\r
+ // Update Image Base Address\r
+ //\r
+ if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;\r
+ } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+ ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;\r
+ } else {\r
+ Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",\r
+ ImgHdr->Pe32.OptionalHeader.Magic,\r
+ FileName\r
+ );\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ //\r
+ // Set new base address into section header\r
+ //\r
+ Status = SetAddressToSectionHeader (FileName, FileBuffer, NewPe32BaseAddress);\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CombinePath (\r
+ IN CHAR8* DefaultPath,\r
+ IN CHAR8* AppendPath,\r
+ OUT CHAR8* NewPath\r
+)\r
+{\r
+ UINT32 DefaultPathLen;\r
+ UINT64 Index;\r
+ CHAR8 QuotesStr[] = "\"";\r
+ strcpy(NewPath, QuotesStr);\r
+ DefaultPathLen = strlen(DefaultPath);\r
+ strcat(NewPath, DefaultPath);\r
+ Index = 0;\r
+ for (; Index < DefaultPathLen + 1; Index ++) {\r
+ if (NewPath[Index] == '\\' || NewPath[Index] == '/') {\r
+ if (NewPath[Index + 1] != '\0') {\r
+ NewPath[Index] = '/';\r
+ }\r
+ }\r
+ }\r
+ if (NewPath[Index -1] != '/') {\r
+ NewPath[Index] = '/';\r
+ NewPath[Index + 1] = '\0';\r
+ }\r
+ strcat(NewPath, AppendPath);\r
+ strcat(NewPath, QuotesStr);\r
+ return EFI_SUCCESS;\r
+}\r
+\r