+\r
+EFI_IMAGE_OPTIONAL_HEADER_UNION *\r
+GetPeCoffHeader (\r
+ void *Data\r
+ )\r
+{\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;\r
+\r
+ //\r
+ // Read the dos & pe hdrs of the image\r
+ //\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)Data;\r
+ if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
+ // NO DOS header, check for PE/COFF header\r
+ PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(Data);\r
+ if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+ return NULL;\r
+ }\r
+ } else {\r
+\r
+ PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(((UINT8 *)Data) + DosHdr->e_lfanew);\r
+ if (PeHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+ return NULL;\r
+ }\r
+ }\r
+ \r
+ return PeHdr;\r
+}\r
+\r
+void\r
+PeCoffConvertImageToXip (\r
+ UINT8 **FileBuffer,\r
+ UINT32 *FileLength\r
+ )\r
+{\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *NewPeHdr;\r
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
+ UINTN TotalNecessaryFileSize;\r
+ UINTN SectionSize;\r
+ UINT8 *XipFile;\r
+ UINT32 XipLength;\r
+ UINTN Index;\r
+ UINTN FirstSectionOffset;\r
+ BOOLEAN ConversionNeeded;\r
+\r
+ PeHdr = GetPeCoffHeader ((void *) *FileBuffer);\r
+ if (PeHdr == NULL) {\r
+ return;\r
+ }\r
+ \r
+ if (PeHdr->Pe32.OptionalHeader.SectionAlignment != PeHdr->Pe32.OptionalHeader.FileAlignment) {\r
+ //\r
+ // The only reason to expand zero fill sections is to make them compatible with XIP images.\r
+ // If SectionAlignment is not equal to FileAlginment then it is not an XIP type image.\r
+ //\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Calculate size of XIP file, and determine if the conversion is needed.\r
+ //\r
+ ConversionNeeded = FALSE;\r
+ XipLength = 0;\r
+ FirstSectionOffset = *FileLength;\r
+ TotalNecessaryFileSize = 0;\r
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->Pe32.OptionalHeader) + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader);\r
+ for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
+ SectionSize = MAX (SectionHeader->Misc.VirtualSize, SectionHeader->SizeOfRawData);\r
+ TotalNecessaryFileSize += SectionSize;\r
+ if (SectionSize > 0) {\r
+ FirstSectionOffset = MIN (FirstSectionOffset, SectionHeader->VirtualAddress);\r
+ XipLength = MAX (XipLength, SectionHeader->VirtualAddress + SectionSize);\r
+ if (SectionHeader->VirtualAddress != SectionHeader->PointerToRawData) {\r
+ ConversionNeeded = TRUE;\r
+ }\r
+ }\r
+ if (SectionHeader->Misc.VirtualSize > SectionHeader->SizeOfRawData) {\r
+ ConversionNeeded = TRUE;\r
+ }\r
+ }\r
+\r
+ if (FirstSectionOffset < PeHdr->Pe32.OptionalHeader.SizeOfHeaders) {\r
+ //\r
+ // If one of the sections should be loaded to an offset overlapping with\r
+ // the executable header, then it cannot be made into an XIP image.\r
+ //\r
+ VerboseMsg ("PE/COFF conversion to XIP is impossible due to overlap");\r
+ VerboseMsg ("of section data with the executable header.");\r
+ return;\r
+ }\r
+\r
+ if (FirstSectionOffset == *FileLength) {\r
+ //\r
+ // If we never found a section with a non-zero size, then we\r
+ // skip the conversion.\r
+ //\r
+ return;\r
+ }\r
+\r
+ TotalNecessaryFileSize += FirstSectionOffset;\r
+\r
+ if (!ConversionNeeded) {\r
+ return;\r
+ }\r
+\r
+ if (XipLength > (2 * TotalNecessaryFileSize)) {\r
+ VerboseMsg ("PE/COFF conversion to XIP appears to be larger than necessary.");\r
+ VerboseMsg ("The image linking process may have left unused memory ranges.");\r
+ }\r
+\r
+ if (PeHdr->Pe32.FileHeader.PointerToSymbolTable != 0) {\r
+ //\r
+ // This field is obsolete and should be zero\r
+ //\r
+ PeHdr->Pe32.FileHeader.PointerToSymbolTable = 0;\r
+ }\r
+\r
+ //\r
+ // Allocate the extra space that we need to grow the image\r
+ //\r
+ XipFile = malloc (XipLength);\r
+ memset (XipFile, 0, XipLength);\r
+\r
+ //\r
+ // Copy the file headers\r
+ //\r
+ memcpy (XipFile, *FileBuffer, PeHdr->Pe32.OptionalHeader.SizeOfHeaders);\r
+\r
+ NewPeHdr = GetPeCoffHeader ((void *)XipFile);\r
+ if (NewPeHdr == NULL) {\r
+ free (XipFile);\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Copy the section data over to the appropriate XIP offsets\r
+ //\r
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(NewPeHdr->Pe32.OptionalHeader) + NewPeHdr->Pe32.FileHeader.SizeOfOptionalHeader);\r
+ for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
+ if (SectionHeader->SizeOfRawData > 0) {\r
+ memcpy (\r
+ XipFile + SectionHeader->VirtualAddress,\r
+ *FileBuffer + SectionHeader->PointerToRawData,\r
+ SectionHeader->SizeOfRawData\r
+ );\r
+ }\r
+ SectionHeader->SizeOfRawData = SectionHeader->Misc.VirtualSize;\r
+ SectionHeader->PointerToRawData = SectionHeader->VirtualAddress;\r
+ }\r
+\r
+ free (*FileBuffer);\r
+ *FileLength = XipLength;\r
+ *FileBuffer = XipFile;\r
+}\r
+\r
+UINT8 *\r
+CreateHiiResouceSectionHeader (\r
+ UINT32 *pSectionHeaderSize, \r
+ UINT32 HiiDataSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Create COFF resource section header\r
+\r
+Arguments:\r
+\r
+ pSectionHeaderSize - Pointer to section header size.\r
+ HiiDataSize - Size of the total HII data in section.\r
+\r
+Returns:\r
+ The created section header buffer.\r
+\r
+--*/\r
+{\r
+ UINT32 HiiSectionHeaderSize;\r
+ UINT32 HiiSectionOffset;\r
+ UINT8 *HiiSectionHeader;\r
+ EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;\r
+ EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *TypeResourceDirectoryEntry;\r
+ EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *NameResourceDirectoryEntry;\r
+ EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *LanguageResourceDirectoryEntry;\r
+ EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;\r
+ EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;\r
+\r
+ //\r
+ // Calculate the total size for the resource header (include Type, Name and Language)\r
+ // then allocate memory for the resource header.\r
+ //\r
+ HiiSectionHeaderSize = 3 * (sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY)) \r
+ + 3 * (sizeof (UINT16) + 3 * sizeof (CHAR16)) \r
+ + sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY);\r
+ HiiSectionHeader = malloc (HiiSectionHeaderSize);\r
+ memset (HiiSectionHeader, 0, HiiSectionHeaderSize);\r
+\r
+ HiiSectionOffset = 0;\r
+ //\r
+ // Create Type entry \r
+ //\r
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset);\r
+ HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY);\r
+ ResourceDirectory->NumberOfNamedEntries = 1;\r
+ TypeResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset);\r
+ HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY);\r
+ TypeResourceDirectoryEntry->u1.s.NameIsString = 1;\r
+ TypeResourceDirectoryEntry->u2.s.DataIsDirectory = 1;\r
+ TypeResourceDirectoryEntry->u2.s.OffsetToDirectory = HiiSectionOffset;\r
+ //\r
+ // Create Name entry\r
+ //\r
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset);\r
+ HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY);\r
+ ResourceDirectory->NumberOfNamedEntries = 1;\r
+ NameResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset);\r
+ HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY);\r
+ NameResourceDirectoryEntry->u1.s.NameIsString = 1;\r
+ NameResourceDirectoryEntry->u2.s.DataIsDirectory = 1;\r
+ NameResourceDirectoryEntry->u2.s.OffsetToDirectory = HiiSectionOffset;\r
+ //\r
+ // Create Language entry\r
+ //\r
+ ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (HiiSectionHeader + HiiSectionOffset);\r
+ HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY);\r
+ ResourceDirectory->NumberOfNamedEntries = 1;\r
+ LanguageResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (HiiSectionHeader + HiiSectionOffset);\r
+ HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY);\r
+ LanguageResourceDirectoryEntry->u1.s.NameIsString = 1;\r
+ //\r
+ // Create string entry for Type\r
+ //\r
+ TypeResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset;\r
+ ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset);\r
+ ResourceDirectoryString->Length = 3;\r
+ ResourceDirectoryString->String[0] = L'H';\r
+ ResourceDirectoryString->String[1] = L'I';\r
+ ResourceDirectoryString->String[2] = L'I';\r
+ HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]);\r
+ //\r
+ // Create string entry for Name\r
+ //\r
+ NameResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset;\r
+ ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset);\r
+ ResourceDirectoryString->Length = 3;\r
+ ResourceDirectoryString->String[0] = L'E';\r
+ ResourceDirectoryString->String[1] = L'F';\r
+ ResourceDirectoryString->String[2] = L'I';\r
+ HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]);\r
+ //\r
+ // Create string entry for Language\r
+ //\r
+ LanguageResourceDirectoryEntry->u1.s.NameOffset = HiiSectionOffset;\r
+ ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (HiiSectionHeader + HiiSectionOffset);\r
+ ResourceDirectoryString->Length = 3;\r
+ ResourceDirectoryString->String[0] = L'B';\r
+ ResourceDirectoryString->String[1] = L'I';\r
+ ResourceDirectoryString->String[2] = L'N';\r
+ HiiSectionOffset = HiiSectionOffset + sizeof (ResourceDirectoryString->Length) + ResourceDirectoryString->Length * sizeof (ResourceDirectoryString->String[0]);\r
+ //\r
+ // Create Leaf data\r
+ //\r
+ LanguageResourceDirectoryEntry->u2.OffsetToData = HiiSectionOffset;\r
+ ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (HiiSectionHeader + HiiSectionOffset);\r
+ HiiSectionOffset += sizeof (EFI_IMAGE_RESOURCE_DATA_ENTRY);\r
+ ResourceDataEntry->OffsetToData = HiiSectionOffset;\r
+ ResourceDataEntry->Size = HiiDataSize;\r
+\r
+ *pSectionHeaderSize = HiiSectionHeaderSize;\r
+ return HiiSectionHeader;\r
+}\r
+\r