]> git.proxmox.com Git - mirror_edk2.git/commitdiff
BaseTools/GenFw: Enhance GenFw to support PRM GCC build
authorHuang, Li-Xia <lisa.huang@intel.com>
Mon, 14 Mar 2022 05:27:21 +0000 (13:27 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 16 Mar 2022 07:48:26 +0000 (07:48 +0000)
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3802

Since PRM module needs to support export table in PE-COFF, we'll
enhance GenFw tool to support this.

Add one export flag in GenFw tool. If export flag is set:
Step1: Scan ELF symbol table based on PRM module descriptor to get
descriptor offset address;
Step2: Find PRM handlers number and name in COFF file based on the
address from step1;
Step3: Write PRM info such as handler name and export RVA into COFF
export table.

PRM option currently only supports DXE RUNTIME driver and X64 arch.

Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Yuwei Chen <yuwei.chen@intel.com>
Signed-off-by: Lixia Huang <lisa.huang@intel.com>
Reviewed-by: Bob Feng <bob.c.feng@intel.com>
BaseTools/Source/C/GenFw/Elf64Convert.c
BaseTools/Source/C/GenFw/ElfConvert.c
BaseTools/Source/C/GenFw/ElfConvert.h
BaseTools/Source/C/GenFw/GenFw.c
BaseTools/Source/C/Include/IndustryStandard/PeImage.h

index 0bb3ead228c9066ec2af015e5b6f391c72c155bf..2aa9bfcc9460c0a68208808e036fc631ae14f90e 100644 (file)
@@ -56,6 +56,12 @@ WriteDebug64 (
   VOID\r
   );\r
 \r
+STATIC\r
+VOID\r
+WriteExport64 (\r
+  VOID\r
+  );\r
+\r
 STATIC\r
 VOID\r
 SetImageSize64 (\r
@@ -106,7 +112,7 @@ STATIC UINT32 mCoffAlignment = 0x20;
 //\r
 // PE section alignment.\r
 //\r
-STATIC const UINT16 mCoffNbrSections = 4;\r
+STATIC UINT16 mCoffNbrSections = 4;\r
 \r
 //\r
 // ELF sections to offset in Coff file.\r
@@ -122,7 +128,7 @@ STATIC UINT32 mDataOffset;
 STATIC UINT32 mHiiRsrcOffset;\r
 STATIC UINT32 mRelocOffset;\r
 STATIC UINT32 mDebugOffset;\r
-\r
+STATIC UINT32 mExportOffset;\r
 //\r
 // Used for RISC-V relocations.\r
 //\r
@@ -132,6 +138,14 @@ STATIC Elf64_Half  mRiscVPass1SymSecIndex = 0;
 STATIC INT32       mRiscVPass1Offset;\r
 STATIC INT32       mRiscVPass1GotFixup;\r
 \r
+//\r
+// Used for Export section.\r
+//\r
+STATIC UINT32      mExportSize;\r
+STATIC UINT32      mExportRVA[PRM_MODULE_EXPORT_SYMBOL_NUM];\r
+STATIC UINT32      mExportSymNum;\r
+STATIC CHAR8       mExportSymName[PRM_MODULE_EXPORT_SYMBOL_NUM][PRM_HANDLER_NAME_MAXIMUM_LENGTH];\r
+\r
 //\r
 // Initialization Function\r
 //\r
@@ -171,6 +185,13 @@ InitializeElf64 (
     return FALSE;\r
   }\r
 \r
+  if (mExportFlag) {\r
+    if (mEhdr->e_machine != EM_X86_64) {\r
+      Error (NULL, 0, 3000, "Unsupported", "--prm option currently only supports X64 arch.");\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
   //\r
   // Update section header pointers\r
   //\r
@@ -200,6 +221,11 @@ InitializeElf64 (
   ElfFunctions->SetImageSize = SetImageSize64;\r
   ElfFunctions->CleanUp = CleanUp64;\r
 \r
+  if (mExportFlag) {\r
+    mCoffNbrSections ++;\r
+    ElfFunctions->WriteExport = WriteExport64;\r
+  }\r
+\r
   return TRUE;\r
 }\r
 \r
@@ -263,6 +289,17 @@ IsHiiRsrcShdr (
   return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
 }\r
 \r
+STATIC\r
+BOOLEAN\r
+IsSymbolShdr (\r
+  Elf_Shdr *Shdr\r
+  )\r
+{\r
+  Elf_Shdr *Namehdr = GetShdrByIndex(mEhdr->e_shstrndx);\r
+\r
+  return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namehdr->sh_offset + Shdr->sh_name, ELF_SYMBOL_SECTION_NAME) == 0);\r
+}\r
+\r
 STATIC\r
 BOOLEAN\r
 IsDataShdr (\r
@@ -335,6 +372,37 @@ GetSymName (
   return StrtabContents + Sym->st_name;\r
 }\r
 \r
+//\r
+// Get Prm Handler number and name\r
+//\r
+STATIC\r
+VOID\r
+FindPrmHandler (\r
+  UINT64 Offset\r
+  )\r
+{\r
+  PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER *PrmExport;\r
+  PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT       *PrmHandler;\r
+  UINT32   HandlerNum;\r
+\r
+  PrmExport = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER*)((UINT8*)mEhdr + Offset);\r
+  PrmHandler = (PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT *)(PrmExport + 1);\r
+\r
+  for (HandlerNum = 0; HandlerNum < PrmExport->NumberPrmHandlers; HandlerNum++) {\r
+    strcpy(mExportSymName[mExportSymNum], PrmHandler->PrmHandlerName);\r
+    mExportSymNum ++;\r
+    PrmHandler += 1;\r
+\r
+    //\r
+    // Check if PRM handler number is larger than (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)\r
+    //\r
+    if (mExportSymNum >= (PRM_MODULE_EXPORT_SYMBOL_NUM - 1)) {\r
+      Error (NULL, 0, 3000, "Invalid", "FindPrmHandler: Number %u is too high.", mExportSymNum);\r
+      exit(EXIT_FAILURE);\r
+    }\r
+  }\r
+}\r
+\r
 //\r
 // Find the ELF section hosting the GOT from an ELF Rva\r
 //   of a single GOT entry.  Normally, GOT is placed in\r
@@ -717,6 +785,7 @@ ScanSections64 (
   UINT32                          CoffEntry;\r
   UINT32                          SectionCount;\r
   BOOLEAN                         FoundSection;\r
+  UINT32                          Offset;\r
 \r
   CoffEntry = 0;\r
   mCoffOffset = 0;\r
@@ -880,6 +949,82 @@ ScanSections64 (
     Warning (NULL, 0, 0, NULL, "Multiple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
   }\r
 \r
+  //\r
+  //  The Symbol sections.\r
+  //\r
+  if (mExportFlag) {\r
+    UINT32      SymIndex;\r
+    Elf_Sym     *Sym;\r
+    UINT64      SymNum;\r
+    const UINT8 *SymName;\r
+\r
+    mExportOffset = mCoffOffset;\r
+    mExportSize = sizeof(EFI_IMAGE_EXPORT_DIRECTORY) + strlen(mInImageName) + 1;\r
+\r
+    for (i = 0; i < mEhdr->e_shnum; i++) {\r
+\r
+      //\r
+      // Determine if this is a symbol section.\r
+      //\r
+      Elf_Shdr *shdr = GetShdrByIndex(i);\r
+      if (!IsSymbolShdr(shdr)) {\r
+        continue;\r
+      }\r
+\r
+      UINT8    *Symtab = (UINT8*)mEhdr + shdr->sh_offset;\r
+      SymNum = (shdr->sh_size) / (shdr->sh_entsize);\r
+\r
+      //\r
+      // First Get PrmModuleExportDescriptor\r
+      //\r
+      for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {\r
+        Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);\r
+        SymName = GetSymName(Sym);\r
+        if (SymName == NULL) {\r
+            continue;\r
+        }\r
+\r
+        if (strcmp((CHAR8*)SymName, PRM_MODULE_EXPORT_DESCRIPTOR_NAME) == 0) {\r
+          //\r
+          // Find PrmHandler Number and Name\r
+          //\r
+          FindPrmHandler(Sym->st_value);\r
+\r
+          strcpy(mExportSymName[mExportSymNum], (CHAR8*)SymName);\r
+          mExportRVA[mExportSymNum] = (UINT32)(Sym->st_value);\r
+          mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;\r
+          mExportSymNum ++;\r
+          break;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Second Get PrmHandler\r
+      //\r
+      for (SymIndex = 0; SymIndex < SymNum; SymIndex++) {\r
+        UINT32   ExpIndex;\r
+        Sym = (Elf_Sym *)(Symtab + SymIndex * shdr->sh_entsize);\r
+        SymName = GetSymName(Sym);\r
+        if (SymName == NULL) {\r
+            continue;\r
+        }\r
+\r
+        for (ExpIndex = 0; ExpIndex < (mExportSymNum -1); ExpIndex++) {\r
+          if (strcmp((CHAR8*)SymName, mExportSymName[ExpIndex]) != 0) {\r
+            continue;\r
+          }\r
+          mExportRVA[ExpIndex] = (UINT32)(Sym->st_value);\r
+          mExportSize += 2 * EFI_IMAGE_EXPORT_ADDR_SIZE + EFI_IMAGE_EXPORT_ORDINAL_SIZE + strlen((CHAR8 *)SymName) + 1;\r
+        }\r
+      }\r
+\r
+      break;\r
+    }\r
+\r
+    mCoffOffset += mExportSize;\r
+    mCoffOffset = CoffAlign(mCoffOffset);\r
+  }\r
+\r
   //\r
   //  The HII resource sections.\r
   //\r
@@ -989,8 +1134,17 @@ ScanSections64 (
     NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
   }\r
 \r
+  //\r
+  // If found symbol, add edata section between data and rsrc section\r
+  //\r
+  if(mExportFlag) {\r
+    Offset = mExportOffset;\r
+  } else {\r
+    Offset = mHiiRsrcOffset;\r
+  }\r
+\r
   if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
-    CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
+    CreateSectionHeader (".data", mDataOffset, Offset - mDataOffset,\r
             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
             | EFI_IMAGE_SCN_MEM_WRITE\r
             | EFI_IMAGE_SCN_MEM_READ);\r
@@ -999,6 +1153,20 @@ ScanSections64 (
     NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
   }\r
 \r
+  if(mExportFlag) {\r
+    if ((mHiiRsrcOffset - mExportOffset) > 0) {\r
+      CreateSectionHeader (".edata", mExportOffset, mHiiRsrcOffset - mExportOffset,\r
+              EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
+              | EFI_IMAGE_SCN_MEM_READ);\r
+      NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].Size = mHiiRsrcOffset - mExportOffset;\r
+      NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = mExportOffset;\r
+\r
+    } else {\r
+      // Don't make a section of size 0.\r
+      NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
+    }\r
+  }\r
+\r
   if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
     CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
@@ -1757,4 +1925,72 @@ CleanUp64 (
   }\r
 }\r
 \r
+STATIC\r
+VOID\r
+WriteExport64 (\r
+  VOID\r
+  )\r
+{\r
+  EFI_IMAGE_OPTIONAL_HEADER_UNION     *NtHdr;\r
+  EFI_IMAGE_EXPORT_DIRECTORY          *ExportDir;\r
+  EFI_IMAGE_DATA_DIRECTORY            *DataDir;\r
+  UINT32                              FileNameOffset;\r
+  UINT32                              NameOffset;\r
+  UINT16                              Index;\r
+  UINT8                               *Tdata = NULL;\r
+\r
+  ExportDir = (EFI_IMAGE_EXPORT_DIRECTORY*)(mCoffFile + mExportOffset);\r
+  ExportDir->Characteristics = 0;\r
+  ExportDir->TimeDateStamp = 0;\r
+  ExportDir->MajorVersion = 0;\r
+  ExportDir->MinorVersion =0;\r
+  ExportDir->Name = 0;\r
+  ExportDir->NumberOfFunctions = mExportSymNum;\r
+  ExportDir->NumberOfNames = mExportSymNum;\r
+  ExportDir->Base = EFI_IMAGE_EXPORT_ORDINAL_BASE;\r
+  ExportDir->AddressOfFunctions = mExportOffset + sizeof(EFI_IMAGE_EXPORT_DIRECTORY);\r
+  ExportDir->AddressOfNames = ExportDir->AddressOfFunctions + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;\r
+  ExportDir->AddressOfNameOrdinals = ExportDir->AddressOfNames + EFI_IMAGE_EXPORT_ADDR_SIZE * mExportSymNum;\r
+\r
+  FileNameOffset = ExportDir->AddressOfNameOrdinals + EFI_IMAGE_EXPORT_ORDINAL_SIZE * mExportSymNum;\r
+  NameOffset = FileNameOffset + strlen(mInImageName) + 1;\r
+\r
+  // Write Input image Name RVA\r
+  ExportDir->Name = FileNameOffset;\r
+\r
+  // Write Input image Name\r
+  strcpy((char *)(mCoffFile + FileNameOffset), mInImageName);\r
+\r
+  for (Index = 0; Index < mExportSymNum; Index++) {\r
+    //\r
+    // Write Export Address Table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfFunctions + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;\r
+    *(UINT32 *)Tdata = mExportRVA[Index];\r
+\r
+    //\r
+    // Write Export Name Pointer Table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfNames + Index * EFI_IMAGE_EXPORT_ADDR_SIZE;\r
+    *(UINT32 *)Tdata = NameOffset;\r
+\r
+    //\r
+    // Write Export Ordinal table\r
+    //\r
+    Tdata = mCoffFile + ExportDir->AddressOfNameOrdinals + Index * EFI_IMAGE_EXPORT_ORDINAL_SIZE;\r
+    *(UINT16 *)Tdata = Index;\r
+\r
+    //\r
+    // Write Export Name Table\r
+    //\r
+    strcpy((char *)(mCoffFile + NameOffset), mExportSymName[Index]);\r
+    NameOffset += strlen(mExportSymName[Index]) + 1;\r
+  }\r
+\r
+  NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
+  DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT];\r
+  DataDir->VirtualAddress = mExportOffset;\r
+  DataDir->Size = mExportSize;\r
+\r
+}\r
 \r
index 7db8721167de0fe2050cb50cc5b39997ee70b7eb..be98544056ec49416c844d21f266c5868f4cea84 100644 (file)
@@ -223,6 +223,14 @@ ConvertElf (
   VerboseMsg ("Write debug info.");\r
   ElfFunctions.WriteDebug ();\r
 \r
+  //\r
+  // For PRM Driver to Write export info.\r
+  //\r
+  if (mExportFlag) {\r
+    VerboseMsg ("Write export info.");\r
+    ElfFunctions.WriteExport ();\r
+  }\r
+\r
   //\r
   // Make sure image size is correct before returning the new image.\r
   //\r
index 801e8de4a2ed2d365ac17bdf8fb112845b655c65..6ab46052271a3d968ce094922256fe6d6176c69e 100644 (file)
@@ -24,6 +24,7 @@ extern UINT8  *mCoffFile;
 extern UINT32 mTableOffset;\r
 extern UINT32 mOutImageType;\r
 extern UINT32 mFileBufferSize;\r
+extern BOOLEAN mExportFlag;\r
 \r
 //\r
 // Common EFI specific data.\r
@@ -31,6 +32,44 @@ extern UINT32 mFileBufferSize;
 #define ELF_HII_SECTION_NAME ".hii"\r
 #define ELF_STRTAB_SECTION_NAME ".strtab"\r
 #define MAX_COFF_ALIGNMENT 0x10000\r
+#define ELF_SYMBOL_SECTION_NAME ".symtab"\r
+\r
+//\r
+// Platform Runtime Mechanism (PRM) specific data.\r
+//\r
+#define PRM_MODULE_EXPORT_SYMBOL_NUM 256\r
+\r
+// <to-do> to include PRM header directly once PrmPkg is in main repo\r
+#define PRM_HANDLER_NAME_MAXIMUM_LENGTH 128\r
+\r
+#define PRM_MODULE_EXPORT_DESCRIPTOR_NAME         "PrmModuleExportDescriptor"\r
+#define PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE    SIGNATURE_64 ('P', 'R', 'M', '_', 'M', 'E', 'D', 'T')\r
+#define PRM_MODULE_EXPORT_REVISION                0x0\r
+\r
+//\r
+// Platform Runtime Mechanism (PRM) Export Descriptor Structures\r
+//\r
+#pragma pack(push, 1)\r
+\r
+typedef struct {\r
+  EFI_GUID                              PrmHandlerGuid;\r
+  CHAR8                                 PrmHandlerName[PRM_HANDLER_NAME_MAXIMUM_LENGTH];\r
+} PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT;\r
+\r
+typedef struct {\r
+  UINT64                                Signature;\r
+  UINT16                                Revision;\r
+  UINT16                                NumberPrmHandlers;\r
+  EFI_GUID                              PlatformGuid;\r
+  EFI_GUID                              ModuleGuid;\r
+} PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER;\r
+\r
+typedef struct {\r
+  PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT_HEADER  Header;\r
+  PRM_HANDLER_EXPORT_DESCRIPTOR_STRUCT        PrmHandlerExportDescriptors[1];\r
+} PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT;\r
+\r
+#pragma pack(pop)\r
 \r
 //\r
 // Filter Types\r
@@ -38,7 +77,8 @@ extern UINT32 mFileBufferSize;
 typedef enum {\r
   SECTION_TEXT,\r
   SECTION_HII,\r
-  SECTION_DATA\r
+  SECTION_DATA,\r
+  SECTION_SYMBOL\r
 \r
 } SECTION_FILTER_TYPES;\r
 \r
@@ -50,6 +90,7 @@ typedef struct {
   BOOLEAN (*WriteSections) (SECTION_FILTER_TYPES  FilterType);\r
   VOID    (*WriteRelocations) ();\r
   VOID    (*WriteDebug) ();\r
+  VOID    (*WriteExport) ();\r
   VOID    (*SetImageSize) ();\r
   VOID    (*CleanUp) ();\r
 \r
index 8cab70ba4d5f649057a068e842a0b810ec76e0e1..6f61f16788cd2a0a5d66d17228431d8f2b06ad20 100644 (file)
@@ -87,7 +87,7 @@ UINT32 mImageTimeStamp = 0;
 UINT32 mImageSize = 0;\r
 UINT32 mOutImageType = FW_DUMMY_IMAGE;\r
 BOOLEAN mIsConvertXip = FALSE;\r
-\r
+BOOLEAN mExportFlag = FALSE;\r
 \r
 STATIC\r
 EFI_STATUS\r
@@ -279,6 +279,10 @@ Returns:
                         except for -o or -r option. It is a action option.\n\\r
                         If it is combined with other action options, the later\n\\r
                         input action option will override the previous one.\n");\r
+  fprintf (stdout, "  --prm                 Scan symbol section from ELF image and \n\\r
+                        write export table into PE-COFF.\n\\r
+                        This option can be used together with -e.\n\\r
+                        It doesn't work for other options.\n");\r
   fprintf (stdout, "  -v, --verbose         Turn on verbose output with informational messages.\n");\r
   fprintf (stdout, "  -q, --quiet           Disable all messages except key message and fatal error\n");\r
   fprintf (stdout, "  -d, --debug level     Enable debug messages, at input debug level.\n");\r
@@ -1436,6 +1440,20 @@ Returns:
       continue;\r
     }\r
 \r
+    if (stricmp (argv[0], "--prm") == 0) {\r
+      if (stricmp (ModuleType, "DXE_RUNTIME_DRIVER") != 0 ){\r
+        Error (NULL, 0, 1001, "Invalid", "--prm option only supports DXE RUNTIME driver.");\r
+        goto Finish;\r
+      }\r
+\r
+      if (!mExportFlag) {\r
+        mExportFlag = TRUE;\r
+      }\r
+      argc --;\r
+      argv ++;\r
+      continue;\r
+    }\r
+\r
     if (argv[0][0] == '-') {\r
       Error (NULL, 0, 1000, "Unknown option", argv[0]);\r
       goto Finish;\r
index f17b8ee19b340bc06bb0c2633eebd7c133b38a05..21c968e650e45ae5cebb7d1a394405ce282dcc50 100644 (file)
@@ -571,6 +571,13 @@ typedef struct {
   UINT32  AddressOfNameOrdinals;\r
 } EFI_IMAGE_EXPORT_DIRECTORY;\r
 \r
+//\r
+// Based export types.\r
+//\r
+#define EFI_IMAGE_EXPORT_ORDINAL_BASE     1\r
+#define EFI_IMAGE_EXPORT_ADDR_SIZE        4\r
+#define EFI_IMAGE_EXPORT_ORDINAL_SIZE     2\r
+\r
 ///\r
 /// DLL support.\r
 /// Import Format\r