]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFsp2Pkg/Tools/SplitFspBin.py
IntelFsp2Pkg/SplitFspBin.py: Support rebasing 1.x binary.
[mirror_edk2.git] / IntelFsp2Pkg / Tools / SplitFspBin.py
index ef759f0dc46a708e15d30d0c22eb06373bf311d1..15c8bebee27839731b73daaaadd20d99cd12fd9b 100644 (file)
@@ -1,13 +1,7 @@
 ## @ FspTool.py\r
 #\r
-# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
-# This program and the accompanying materials are licensed and made available under\r
-# the terms and conditions of the BSD License that accompanies this distribution.\r
-# The full text of the license may be found at\r
-# http://opensource.org/licenses/bsd-license.php.\r
-#\r
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+# Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
 #\r
 ##\r
 \r
@@ -20,12 +14,12 @@ import argparse
 from   ctypes import *\r
 \r
 """\r
-This utility supports some operations for Intel FSP 2.0 image.\r
+This utility supports some operations for Intel FSP 1.x/2.x image.\r
 It supports:\r
-    - Display FSP 2.0 information header\r
-    - Split FSP 2.0 image into individual FSP-T/M/S/O component\r
-    - Rebase FSP 2.0 components to a different base address\r
-    - Generate FSP mapping C header file\r
+    - Display FSP 1.x/2.x information header\r
+    - Split FSP 2.x image into individual FSP-T/M/S/O component\r
+    - Rebase FSP 1.x/2.x components to a different base address\r
+    - Generate FSP 1.x/2.x mapping C header file\r
 """\r
 \r
 CopyRightHeaderFile = """/*\r
@@ -159,12 +153,142 @@ 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_OPTIONAL_HEADER32_PLUS(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
+        ('ImageBase',                     c_uint64),\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_uint64),\r
+        ('SizeOfStackCommit' ,            c_uint64),\r
+        ('SizeOfHeapReserve',             c_uint64),\r
+        ('SizeOfHeapCommit' ,             c_uint64),\r
+        ('LoaderFlags'     ,              c_uint32),\r
+        ('NumberOfRvaAndSizes',           c_uint32),\r
+        ('DataDirectory',                 ARRAY(EFI_IMAGE_DATA_DIRECTORY, 16))\r
+        ]\r
+\r
+class EFI_IMAGE_OPTIONAL_HEADER(Union):\r
+    _fields_ = [\r
+        ('PeOptHdr',             EFI_IMAGE_OPTIONAL_HEADER32),\r
+        ('PePlusOptHdr',         EFI_IMAGE_OPTIONAL_HEADER32_PLUS)\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_HEADER)\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
@@ -376,8 +500,6 @@ class FirmwareDevice:
 \r
         fih = None\r
         for fsp in self.FspList:\r
-            if fsp.Fih.HeaderRevision < 3:\r
-                raise Exception("ERROR: FSP 1.x is not supported by this tool !")\r
             if not fih:\r
                 fih = fsp.Fih\r
             else:\r
@@ -431,35 +553,70 @@ 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': # PE 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.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image\r
+                if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32.DataDirectory.offset:\r
+                    raise Exception("ERROR: Unsupported PE32 image !")\r
+                if self.PeHdr.OptionalHeader.PeOptHdr.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:\r
+                    raise Exception("ERROR: No relocation information available !")\r
+            elif self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x20b: # PE32+ image\r
+                if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32_PLUS.DataDirectory.offset:\r
+                    raise Exception("ERROR: Unsupported PE32+ image !")\r
+                if self.PeHdr.OptionalHeader.PePlusOptHdr.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:\r
+                    raise Exception("ERROR: No relocation information available !")\r
+            else:\r
+                raise Exception("ERROR: Invalid PE32 optional header !")\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
+            if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image\r
+                rsize   = self.PeHdr.OptionalHeader.PeOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size\r
+                roffset = self.PeHdr.OptionalHeader.PeOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress\r
+            if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x20b: # PE32+ image\r
+                rsize   = self.PeHdr.OptionalHeader.PePlusOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size\r
+                roffset = self.PeHdr.OptionalHeader.PePlusOptHdr.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
-                if rtype == 0: # IMAGE_REL_BASED.ABSOLUTE:\r
+                if rtype == 0: # IMAGE_REL_BASED_ABSOLUTE:\r
                     continue\r
-                if rtype != 3: # IMAGE_REL_BASED_HIGHLOW\r
+                if ((rtype != 3) and (rtype != 10)): # IMAGE_REL_BASED_HIGHLOW and IMAGE_REL_BASED_DIR64\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
@@ -469,19 +626,32 @@ class TeImage:
             return count\r
 \r
         for (rtype, roff) in self.RelocList:\r
-            if rtype == 0x03: # HIGHLOW\r
+            if rtype == 3: # IMAGE_REL_BASED_HIGHLOW\r
                 offset = roff + self.Offset\r
                 value  = Bytes2Val(fdbin[offset:offset+sizeof(c_uint32)])\r
                 value += delta\r
                 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))\r
                 count += 1\r
+            elif rtype == 10: # IMAGE_REL_BASED_DIR64\r
+                offset = roff + self.Offset\r
+                value  = Bytes2Val(fdbin[offset:offset+sizeof(c_uint64)])\r
+                value += delta\r
+                fdbin[offset:offset+sizeof(c_uint64)] = Val2Bytes(value, sizeof(c_uint64))\r
+                count += 1\r
             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
@@ -541,13 +711,15 @@ def SplitFspBin (fspfile, outdir, nametemplate):
     fd.ParseFsp ()\r
 \r
     for fsp in fd.FspList:\r
+        if fsp.Fih.HeaderRevision < 3:\r
+            raise Exception("ERROR: FSP 1.x is not supported by the split command !")\r
         ftype = fsp.Type\r
         if not nametemplate:\r
             nametemplate = fspfile\r
         fspname, ext = os.path.splitext(os.path.basename(nametemplate))\r
         filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext)\r
         hfsp = open(filename, 'wb')\r
-        print ("Ceate FSP component file '%s'" % filename)\r
+        print ("Create FSP component file '%s'" % filename)\r
         for fvidx in fsp.FvIdxList:\r
             fv = fd.FvList[fvidx]\r
             hfsp.write(fv.FvData)\r
@@ -570,6 +742,11 @@ def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile):
 \r
         found = False\r
         for fsp in fd.FspList:\r
+            # Is this FSP 1.x single binary?\r
+            if fsp.Fih.HeaderRevision < 3:\r
+                found = True\r
+                ftype = 'X'\r
+                break\r
             ftype = fsp.Type.lower()\r
             if ftype == fspcomp:\r
                 found = True\r
@@ -588,28 +765,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