IntelFsp2Pkg/Tools: Add PE32 section rebasing support
authorMaurice Ma <maurice.ma@intel.com>
Wed, 5 Oct 2016 00:02:24 +0000 (17:02 -0700)
committerMaurice Ma <maurice.ma@intel.com>
Thu, 6 Oct 2016 03:07:58 +0000 (20:07 -0700)
The current SplitFspBin.py can only support TE image format
rebasing in an FSP binary. This patch adds PE32 image format
rebasing support.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Maurice Ma <maurice.ma@intel.com>
Reviewed-by: Satya Yarlagadda <Satya.p.yarlagadda@intel.com>
IntelFsp2Pkg/Tools/SplitFspBin.py

index ef759f0..e4c3aa6 100644 (file)
@@ -159,12 +159,102 @@ class EFI_TE_IMAGE_HEADER(Structure):
         ('DataDirectoryDebug',      EFI_IMAGE_DATA_DIRECTORY)\r
         ]\r
 \r
+class EFI_IMAGE_DOS_HEADER(Structure):\r
+    _fields_ = [\r
+        ('e_magic',              c_uint16),\r
+        ('e_cblp',               c_uint16),\r
+        ('e_cp',                 c_uint16),\r
+        ('e_crlc',               c_uint16),\r
+        ('e_cparhdr',            c_uint16),\r
+        ('e_minalloc',           c_uint16),\r
+        ('e_maxalloc',           c_uint16),\r
+        ('e_ss',                 c_uint16),\r
+        ('e_sp',                 c_uint16),\r
+        ('e_csum',               c_uint16),\r
+        ('e_ip',                 c_uint16),\r
+        ('e_cs',                 c_uint16),\r
+        ('e_lfarlc',             c_uint16),\r
+        ('e_ovno',               c_uint16),\r
+        ('e_res',                ARRAY(c_uint16, 4)),\r
+        ('e_oemid',              c_uint16),\r
+        ('e_oeminfo',            c_uint16),\r
+        ('e_res2',               ARRAY(c_uint16, 10)),\r
+        ('e_lfanew',             c_uint16)\r
+        ]\r
+\r
+class EFI_IMAGE_FILE_HEADER(Structure):\r
+    _fields_ = [\r
+        ('Machine',               c_uint16),\r
+        ('NumberOfSections',      c_uint16),\r
+        ('TimeDateStamp',         c_uint32),\r
+        ('PointerToSymbolTable',  c_uint32),\r
+        ('NumberOfSymbols',       c_uint32),\r
+        ('SizeOfOptionalHeader',  c_uint16),\r
+        ('Characteristics',       c_uint16)\r
+        ]\r
+\r
 class PE_RELOC_BLOCK_HEADER(Structure):\r
     _fields_ = [\r
         ('PageRVA',              c_uint32),\r
         ('BlockSize',            c_uint32)\r
         ]\r
 \r
+class EFI_IMAGE_OPTIONAL_HEADER32(Structure):\r
+    _fields_ = [\r
+        ('Magic',                         c_uint16),\r
+        ('MajorLinkerVersion',            c_uint8),\r
+        ('MinorLinkerVersion',            c_uint8),\r
+        ('SizeOfCode',                    c_uint32),\r
+        ('SizeOfInitializedData',         c_uint32),\r
+        ('SizeOfUninitializedData',       c_uint32),\r
+        ('AddressOfEntryPoint',           c_uint32),\r
+        ('BaseOfCode',                    c_uint32),\r
+        ('BaseOfData',                    c_uint32),\r
+        ('ImageBase',                     c_uint32),\r
+        ('SectionAlignment',              c_uint32),\r
+        ('FileAlignment',                 c_uint32),\r
+        ('MajorOperatingSystemVersion',   c_uint16),\r
+        ('MinorOperatingSystemVersion',   c_uint16),\r
+        ('MajorImageVersion',             c_uint16),\r
+        ('MinorImageVersion',             c_uint16),\r
+        ('MajorSubsystemVersion',         c_uint16),\r
+        ('MinorSubsystemVersion',         c_uint16),\r
+        ('Win32VersionValue',             c_uint32),\r
+        ('SizeOfImage',                   c_uint32),\r
+        ('SizeOfHeaders',                 c_uint32),\r
+        ('CheckSum'     ,                 c_uint32),\r
+        ('Subsystem',                     c_uint16),\r
+        ('DllCharacteristics',            c_uint16),\r
+        ('SizeOfStackReserve',            c_uint32),\r
+        ('SizeOfStackCommit' ,            c_uint32),\r
+        ('SizeOfHeapReserve',             c_uint32),\r
+        ('SizeOfHeapCommit' ,             c_uint32),\r
+        ('LoaderFlags'     ,              c_uint32),\r
+        ('NumberOfRvaAndSizes',           c_uint32),\r
+        ('DataDirectory',                 ARRAY(EFI_IMAGE_DATA_DIRECTORY, 16))\r
+        ]\r
+\r
+class EFI_IMAGE_NT_HEADERS32(Structure):\r
+    _fields_ = [\r
+        ('Signature',            c_uint32),\r
+        ('FileHeader',           EFI_IMAGE_FILE_HEADER),\r
+        ('OptionalHeader',       EFI_IMAGE_OPTIONAL_HEADER32)\r
+        ]\r
+\r
+\r
+class EFI_IMAGE_DIRECTORY_ENTRY:\r
+    EXPORT                     = 0\r
+    IMPORT                     = 1\r
+    RESOURCE                   = 2\r
+    EXCEPTION                  = 3\r
+    SECURITY                   = 4\r
+    BASERELOC                  = 5\r
+    DEBUG                      = 6\r
+    COPYRIGHT                  = 7\r
+    GLOBALPTR                  = 8\r
+    TLS                        = 9\r
+    LOAD_CONFIG                = 10\r
+\r
 class EFI_FV_FILETYPE:\r
     ALL                        = 0x00\r
     RAW                        = 0x01\r
@@ -431,26 +521,47 @@ class FirmwareDevice:
                     raise Exception("ERROR: Incorrect FV size in image !")\r
         self.CheckFsp ()\r
 \r
-class TeImage:\r
-    def __init__(self, offset, tedata):\r
-        self.Offset = offset\r
-        self.TeHdr     = EFI_TE_IMAGE_HEADER.from_buffer (tedata, 0)\r
-        self.TeData    = tedata\r
+class PeTeImage:\r
+    def __init__(self, offset, data):\r
+        self.Offset    = offset\r
+        tehdr          = EFI_TE_IMAGE_HEADER.from_buffer (data, 0)\r
+        if   tehdr.Signature == 'VZ': # TE image\r
+            self.TeHdr   = tehdr\r
+        elif tehdr.Signature == 'MZ': # PE32 image\r
+            self.TeHdr   = None\r
+            self.DosHdr  = EFI_IMAGE_DOS_HEADER.from_buffer (data, 0)\r
+            self.PeHdr   = EFI_IMAGE_NT_HEADERS32.from_buffer (data, self.DosHdr.e_lfanew)\r
+            if self.PeHdr.Signature != 0x4550:\r
+                raise Exception("ERROR: Invalid PE32 header !")\r
+            if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32.DataDirectory.offset:\r
+                raise Exception("ERROR: Unsupported PE32 image !")\r
+            if self.PeHdr.OptionalHeader.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:\r
+                raise Exception("ERROR: No relocation information available !")\r
+        self.Offset    = offset\r
+        self.Data      = data\r
         self.RelocList = []\r
 \r
+    def IsTeImage(self):\r
+        return  self.TeHdr is not None\r
+\r
     def ParseReloc(self):\r
-        rsize   = self.TeHdr.DataDirectoryBaseReloc.Size\r
-        roffset   = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress\r
+        if self.IsTeImage():\r
+            rsize   = self.TeHdr.DataDirectoryBaseReloc.Size\r
+            roffset = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress\r
+        else:\r
+            rsize   = self.PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size\r
+            roffset = self.PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress\r
+\r
         alignment = 4\r
         offset = roffset\r
         while offset < roffset + rsize:\r
             offset = AlignPtr(offset, 4)\r
-            blkhdr = PE_RELOC_BLOCK_HEADER.from_buffer(self.TeData, offset)\r
+            blkhdr = PE_RELOC_BLOCK_HEADER.from_buffer(self.Data, offset)\r
             offset += sizeof(blkhdr)\r
             # Read relocation type,offset pairs\r
             rlen  = blkhdr.BlockSize - sizeof(PE_RELOC_BLOCK_HEADER)\r
             rnum  = rlen/sizeof(c_uint16)\r
-            rdata = (c_uint16 * rnum).from_buffer(self.TeData, offset)\r
+            rdata = (c_uint16 * rnum).from_buffer(self.Data, offset)\r
             for each in rdata:\r
                 roff  = each & 0xfff\r
                 rtype = each >> 12\r
@@ -459,7 +570,9 @@ class TeImage:
                 if rtype != 3: # IMAGE_REL_BASED_HIGHLOW\r
                     raise Exception("ERROR: Unsupported relocation type %d!" % rtype)\r
                 # Calculate the offset of the relocation\r
-                aoff = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + blkhdr.PageRVA + roff\r
+                aoff  = blkhdr.PageRVA + roff\r
+                if self.IsTeImage():\r
+                    aoff += sizeof(self.TeHdr) - self.TeHdr.StrippedSize\r
                 self.RelocList.append((rtype, aoff))\r
             offset += sizeof(rdata)\r
 \r
@@ -478,10 +591,17 @@ class TeImage:
             else:\r
                 raise Exception('ERROR: Unknown relocation type %d !' % rtype)\r
 \r
-        tehdr = self.TeHdr\r
-        tehdr.ImageBase += delta\r
-        offset = self.Offset\r
-        fdbin[offset:offset+sizeof(tehdr)] = bytearray(tehdr)\r
+        if self.IsTeImage():\r
+            offset  = self.Offset + EFI_TE_IMAGE_HEADER.ImageBase.offset\r
+            size    = EFI_TE_IMAGE_HEADER.ImageBase.size\r
+        else:\r
+            offset  = self.Offset + self.DosHdr.e_lfanew\r
+            offset += EFI_IMAGE_NT_HEADERS32.OptionalHeader.offset\r
+            offset += EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.offset\r
+            size    = EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.size\r
+\r
+        value  = Bytes2Val(fdbin[offset:offset+size]) + delta\r
+        fdbin[offset:offset+size] = Val2Bytes(value, size)\r
 \r
         return count\r
 \r
@@ -588,28 +708,24 @@ def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile):
         delta = newbase - oldbase\r
         print "Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype.upper(),oldbase,newbase)\r
 \r
-        telist = []\r
+        imglist = []\r
         for fvidx in fsp.FvIdxList:\r
             fv = fd.FvList[fvidx]\r
             for ffs in fv.FfsList:\r
                 for sec in ffs.SecList:\r
-                    if sec.SecHdr.Type == EFI_SECTION_TYPE.TE:   # TE\r
+                    if sec.SecHdr.Type in [EFI_SECTION_TYPE.TE, EFI_SECTION_TYPE.PE32]:   # TE or PE32\r
                         offset = fd.Offset + fv.Offset + ffs.Offset + sec.Offset + sizeof(sec.SecHdr)\r
-                        telist.append ((offset, len(sec.SecData) - sizeof(sec.SecHdr)))\r
-                    elif sec.SecHdr.Type == EFI_SECTION_TYPE.PE32: # PE\r
-                        raise Exception("ERROR: PE32 Section is not supported !")\r
+                        imglist.append ((offset, len(sec.SecData) - sizeof(sec.SecHdr)))\r
 \r
         fcount  = 0\r
-        tecount = 0\r
-        for (teoffset, telen) in telist:\r
-            tehdr = EFI_TE_IMAGE_HEADER.from_buffer (fd.FdData, teoffset)\r
-            if 'VZ' != tehdr.Signature:\r
-                raise Exception("ERROR: Invalid TE header !")\r
-            te = TeImage(teoffset, fd.FdData[teoffset:teoffset + telen])\r
-            te.ParseReloc()\r
-            tecount += te.Rebase(delta, newfspbin)\r
-            fcount  += 1\r
-        print "  Patched %d entries in %d TE images." % (tecount, fcount)\r
+        pcount  = 0\r
+        for (offset, length) in imglist:\r
+            img = PeTeImage(offset, fd.FdData[offset:offset + length])\r
+            img.ParseReloc()\r
+            pcount += img.Rebase(delta, newfspbin)\r
+            fcount += 1\r
+\r
+        print "  Patched %d entries in %d TE/PE32 images." % (pcount, fcount)\r
 \r
         (count, applied) = fsp.Patch(delta, newfspbin)\r
         print "  Patched %d entries using FSP patch table." % applied\r