IntelFsp2Pkg/Tools: Add FSP rebasing function into SplitFspBin tool
authorMaurice Ma <maurice.ma@intel.com>
Fri, 27 May 2016 20:26:28 +0000 (13:26 -0700)
committerMaurice Ma <maurice.ma@intel.com>
Thu, 2 Jun 2016 00:26:11 +0000 (17:26 -0700)
Enhanced the SplitFspBin tool in IntelFsp2Pkg to support:
  - Rebase FSP 2.0 components to a different base address
  - Display FSP 2.0 information header

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: Giri P Mudusuru <giri.p.mudusuru@intel.com>
IntelFsp2Pkg/Tools/SplitFspBin.py

index cc2b87e..ef759f0 100644 (file)
@@ -20,18 +20,26 @@ import argparse
 from   ctypes import *\r
 \r
 """\r
-This utility supports some operations for Intel FSP image.\r
+This utility supports some operations for Intel FSP 2.0 image.\r
 It supports:\r
-    - Split a FSP 2.0 compatibale image into individual FSP-T/M/S/C\r
-        and generate the mapping header file.\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
+"""\r
+\r
+CopyRightHeaderFile = """/*\r
+ *\r
+ * Automatically generated file; DO NOT EDIT.\r
+ * FSP mapping file\r
+ *\r
+ */\r
 """\r
 \r
 class c_uint24(Structure):\r
     """Little-Endian 24-bit Unsigned Integer"""\r
     _pack_   = 1\r
-    _fields_ = [\r
-        ('Data', (c_uint8 * 3))\r
-        ]\r
+    _fields_ = [('Data', (c_uint8 * 3))]\r
 \r
     def __init__(self, val=0):\r
         self.set_value(val)\r
@@ -39,324 +47,632 @@ class c_uint24(Structure):
     def __str__(self, indent=0):\r
         return '0x%.6x' % self.value\r
 \r
-    def get_value(self):\r
-        return (\r
-            (self.Data[0]      ) +\r
-            (self.Data[1] <<  8) +\r
-            (self.Data[2] << 16)\r
-            )\r
+    def __int__(self):\r
+        return self.get_value()\r
 \r
     def set_value(self, val):\r
-        self.Data[0] = (val      ) & 0xff\r
-        self.Data[1] = (val >>  8) & 0xff\r
-        self.Data[2] = (val >> 16) & 0xff\r
+        self.Data[0:3] = Val2Bytes(val, 3)\r
+\r
+    def get_value(self):\r
+        return Bytes2Val(self.Data[0:3])\r
 \r
     value = property(get_value, set_value)\r
 \r
 class EFI_FIRMWARE_VOLUME_HEADER(Structure):\r
     _fields_ = [\r
-        ('ZeroVector',                 ARRAY(c_uint8, 16)),\r
-        ('FileSystemGuid',             ARRAY(c_char, 16)),\r
-        ('FvLength',                   c_uint64),\r
-        ('Signature',                  c_uint32),\r
-        ('Attributes',                 c_uint32),\r
-        ('HeaderLength',               c_uint16),\r
-        ('Checksum',                   c_uint16),\r
-        ('ExtHeaderOffset',            c_uint16),\r
-        ('Reserved',                   c_uint8),\r
-        ('Revision',                   c_uint8)\r
+        ('ZeroVector',           ARRAY(c_uint8, 16)),\r
+        ('FileSystemGuid',       ARRAY(c_uint8, 16)),\r
+        ('FvLength',             c_uint64),\r
+        ('Signature',            ARRAY(c_char, 4)),\r
+        ('Attributes',           c_uint32),\r
+        ('HeaderLength',         c_uint16),\r
+        ('Checksum',             c_uint16),\r
+        ('ExtHeaderOffset',      c_uint16),\r
+        ('Reserved',             c_uint8),\r
+        ('Revision',             c_uint8)\r
         ]\r
 \r
 class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure):\r
     _fields_ = [\r
-        ('FvName',                     ARRAY(c_char, 16)),\r
-        ('ExtHeaderSize',              c_uint32)\r
+        ('FvName',               ARRAY(c_uint8, 16)),\r
+        ('ExtHeaderSize',        c_uint32)\r
         ]\r
 \r
 class EFI_FFS_INTEGRITY_CHECK(Structure):\r
     _fields_ = [\r
-        ('Header',                     c_uint8),\r
-        ('File',                       c_uint8)\r
+        ('Header',               c_uint8),\r
+        ('File',                 c_uint8)\r
         ]\r
 \r
 class EFI_FFS_FILE_HEADER(Structure):\r
     _fields_ = [\r
-        ('Name',                       ARRAY(c_char, 16)),\r
-        ('IntegrityCheck',             EFI_FFS_INTEGRITY_CHECK),\r
-        ('Type',                       c_uint8),\r
-        ('Attributes',                 c_uint8),\r
-        ('Size',                       c_uint24),\r
-        ('State',                      c_uint8)\r
+        ('Name',                 ARRAY(c_uint8, 16)),\r
+        ('IntegrityCheck',       EFI_FFS_INTEGRITY_CHECK),\r
+        ('Type',                 c_uint8),\r
+        ('Attributes',           c_uint8),\r
+        ('Size',                 c_uint24),\r
+        ('State',                c_uint8)\r
         ]\r
 \r
 class EFI_COMMON_SECTION_HEADER(Structure):\r
     _fields_ = [\r
-        ('Size',                       c_uint24),\r
-        ('Type',                       c_uint8)\r
+        ('Size',                 c_uint24),\r
+        ('Type',                 c_uint8)\r
+        ]\r
+\r
+class FSP_COMMON_HEADER(Structure):\r
+     _fields_ = [\r
+        ('Signature',            ARRAY(c_char, 4)),\r
+        ('HeaderLength',         c_uint32)\r
         ]\r
 \r
 class FSP_INFORMATION_HEADER(Structure):\r
      _fields_ = [\r
-        ('Signature',                   c_uint32),\r
-        ('HeaderLength',                c_uint32),\r
-        ('Reserved1',                   ARRAY(c_uint8, 3)),\r
-        ('HeaderRevision',              c_uint8),\r
-        ('ImageRevision',               c_uint32),\r
-        ('ImageId',                     c_uint64),\r
-        ('ImageSize',                   c_uint32),\r
-        ('ImageBase',                   c_uint32),\r
-        ('ImageAttribute',              c_uint32),\r
-        ('CfgRegionOffset',             c_uint32),\r
-        ('CfgRegionSize',               c_uint32),\r
-        ('ApiEntryNum',                 c_uint32),\r
-        ('NemInitEntry',                c_uint32),\r
-        ('FspInitEntry',                c_uint32),\r
-        ('NotifyPhaseEntry',            c_uint32),\r
-        ('FspMemoryInitEntry',          c_uint32),\r
-        ('TempRamExitEntry',            c_uint32),\r
-        ('FspSiliconInitEntry',         c_uint32)\r
+        ('Signature',            ARRAY(c_char, 4)),\r
+        ('HeaderLength',         c_uint32),\r
+        ('Reserved1',            c_uint16),\r
+        ('SpecVersion',          c_uint8),\r
+        ('HeaderRevision',       c_uint8),\r
+        ('ImageRevision',        c_uint32),\r
+        ('ImageId',              ARRAY(c_char, 8)),\r
+        ('ImageSize',            c_uint32),\r
+        ('ImageBase',            c_uint32),\r
+        ('ImageAttribute',       c_uint16),\r
+        ('ComponentAttribute',   c_uint16),\r
+        ('CfgRegionOffset',      c_uint32),\r
+        ('CfgRegionSize',        c_uint32),\r
+        ('Reserved2',            c_uint32),\r
+        ('TempRamInitEntryOffset',     c_uint32),\r
+        ('Reserved3',                  c_uint32),\r
+        ('NotifyPhaseEntryOffset',     c_uint32),\r
+        ('FspMemoryInitEntryOffset',   c_uint32),\r
+        ('TempRamExitEntryOffset',     c_uint32),\r
+        ('FspSiliconInitEntryOffset',  c_uint32)\r
     ]\r
 \r
-class FspFv:\r
-    HeaderFile = """/*\r
- *\r
- * Automatically generated file; DO NOT EDIT.\r
- * FSP mapping file\r
- *\r
- */\r
-"""\r
-    FspNameDict = {\r
-        "0" : "-C.Fv",\r
-        "1" : "-T.Fv",\r
-        "2" : "-M.Fv",\r
-        "3" : "-S.Fv",\r
-    }\r
-\r
-    def __init__(self, FvBin):\r
-        self.FspFv  = {}\r
-        self.FvList = []\r
-        self.FspBin = FvBin\r
-        hfsp = open (self.FspBin, 'r+b')\r
-        self.FspDat = bytearray(hfsp.read())\r
-        hfsp.close()\r
+class FSP_PATCH_TABLE(Structure):\r
+    _fields_ = [\r
+        ('Signature',            ARRAY(c_char, 4)),\r
+        ('HeaderLength',         c_uint16),\r
+        ('HeaderRevision',       c_uint8),\r
+        ('Reserved',             c_uint8),\r
+        ('PatchEntryNum',        c_uint32)\r
+        ]\r
+\r
+class EFI_IMAGE_DATA_DIRECTORY(Structure):\r
+    _fields_ = [\r
+        ('VirtualAddress',       c_uint32),\r
+        ('Size',                 c_uint32)\r
+        ]\r
+\r
+class EFI_TE_IMAGE_HEADER(Structure):\r
+    _fields_ = [\r
+        ('Signature',            ARRAY(c_char, 2)),\r
+        ('Machine',              c_uint16),\r
+        ('NumberOfSections',     c_uint8),\r
+        ('Subsystem',            c_uint8),\r
+        ('StrippedSize',         c_uint16),\r
+        ('AddressOfEntryPoint',  c_uint32),\r
+        ('BaseOfCode',           c_uint32),\r
+        ('ImageBase',            c_uint64),\r
+        ('DataDirectoryBaseReloc',  EFI_IMAGE_DATA_DIRECTORY),\r
+        ('DataDirectoryDebug',      EFI_IMAGE_DATA_DIRECTORY)\r
+        ]\r
+\r
+class PE_RELOC_BLOCK_HEADER(Structure):\r
+    _fields_ = [\r
+        ('PageRVA',              c_uint32),\r
+        ('BlockSize',            c_uint32)\r
+        ]\r
 \r
-    def OutputStruct (self, obj, indent = 0):\r
-        max_key_len = 20\r
-        pstr = ('  ' * indent + '{0:<%d} = {1}\n') % max_key_len\r
-        if indent:\r
-            s = ''\r
+class EFI_FV_FILETYPE:\r
+    ALL                        = 0x00\r
+    RAW                        = 0x01\r
+    FREEFORM                   = 0x02\r
+    SECURITY_CORE              = 0x03\r
+    PEI_CORE                   = 0x04\r
+    DXE_CORE                   = 0x05\r
+    PEIM                       = 0x06\r
+    DRIVER                     = 0x07\r
+    COMBINED_PEIM_DRIVER       = 0x08\r
+    APPLICATION                = 0x09\r
+    SMM                        = 0x0a\r
+    FIRMWARE_VOLUME_IMAGE      = 0x0b\r
+    COMBINED_SMM_DXE           = 0x0c\r
+    SMM_CORE                   = 0x0d\r
+    OEM_MIN                    = 0xc0\r
+    OEM_MAX                    = 0xdf\r
+    DEBUG_MIN                  = 0xe0\r
+    DEBUG_MAX                  = 0xef\r
+    FFS_MIN                    = 0xf0\r
+    FFS_MAX                    = 0xff\r
+    FFS_PAD                    = 0xf0\r
+\r
+class EFI_SECTION_TYPE:\r
+    """Enumeration of all valid firmware file section types."""\r
+    ALL                        = 0x00\r
+    COMPRESSION                = 0x01\r
+    GUID_DEFINED               = 0x02\r
+    DISPOSABLE                 = 0x03\r
+    PE32                       = 0x10\r
+    PIC                        = 0x11\r
+    TE                         = 0x12\r
+    DXE_DEPEX                  = 0x13\r
+    VERSION                    = 0x14\r
+    USER_INTERFACE             = 0x15\r
+    COMPATIBILITY16            = 0x16\r
+    FIRMWARE_VOLUME_IMAGE      = 0x17\r
+    FREEFORM_SUBTYPE_GUID      = 0x18\r
+    RAW                        = 0x19\r
+    PEI_DEPEX                  = 0x1b\r
+    SMM_DEPEX                  = 0x1c\r
+\r
+def AlignPtr (offset, alignment = 8):\r
+    return (offset + alignment - 1) & ~(alignment - 1)\r
+\r
+def Bytes2Val (bytes):\r
+    return reduce(lambda x,y: (x<<8)|y,  bytes[::-1] )\r
+\r
+def Val2Bytes (value, blen):\r
+    return [(value>>(i*8) & 0xff) for i in range(blen)]\r
+\r
+def OutputStruct (obj, indent = 0, plen = 0):\r
+    if indent:\r
+        body = ''\r
+    else:\r
+        body = ('  ' * indent + '<%s>:\n') % obj.__class__.__name__\r
+\r
+    if plen == 0:\r
+        plen = sizeof(obj)\r
+\r
+    max_key_len = 26\r
+    pstr = ('  ' * (indent + 1) + '{0:<%d} = {1}\n') % max_key_len\r
+\r
+    for field in obj._fields_:\r
+        key = field[0]\r
+        val = getattr(obj, key)\r
+        rep = ''\r
+        if not isinstance(val, c_uint24) and isinstance(val, Structure):\r
+            body += pstr.format(key, val.__class__.__name__)\r
+            body += OutputStruct (val, indent + 1)\r
+            plen -= sizeof(val)\r
         else:\r
-            s = ('  ' * indent + '<%s>:\n') % obj.__class__.__name__\r
-        for field in obj._fields_:\r
-            key = field[0]\r
-            val = getattr(obj, key)\r
-            rep = ''\r
-            \r
-            if not isinstance(val, c_uint24) and isinstance(val, Structure):                \r
-                s += pstr.format(key, val.__class__.__name__)\r
-                s += self.OutputStruct (val, indent + 1)                \r
-            else:\r
-                if type(val) in (int, long):\r
-                    rep = hex(val)\r
-                elif isinstance(val, str) and (len(val) == 16):\r
-                    rep = str(uuid.UUID(bytes = val))\r
-                elif isinstance(val, c_uint24):                    \r
-                    rep = hex(val.get_value())\r
-                elif 'c_ubyte_Array' in str(type(val)):                \r
-                    rep = str(list(bytearray(val)))\r
+            if type(val) is str:\r
+                rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val)\r
+            elif type(val) in (int, long):\r
+                rep = '0x%X' % val\r
+            elif isinstance(val, c_uint24):\r
+                rep = '0x%X' % val.get_value()\r
+            elif 'c_ubyte_Array' in str(type(val)):\r
+                if sizeof(val) == 16:\r
+                    rep = str(uuid.UUID(bytes = str(bytearray(val)))).upper()\r
                 else:\r
-                    rep = str(val)\r
-                s += pstr.format(key, rep)\r
-        return s\r
-    \r
-    def PrintFv (self):\r
-        print ("FV LIST:")\r
-        idx = 0\r
-        for (fvh, fvhe, offset) in self.FvList:            \r
-            guid = uuid.UUID(bytes = fvhe.FvName)\r
-            print ("FV%d FV GUID:%s  Offset:0x%08X  Length:0x%08X" % (idx, str(guid), offset, fvh.FvLength))\r
-            idx = idx + 1\r
-        print ("\nFSP LIST:")\r
-        for fsp in self.FspFv:\r
-            print "FSP%s contains FV%s" % (fsp, str(self.FspFv[fsp][1]))\r
-            print "\nFSP%s Info Header:" % fsp\r
-            fih = self.FspFv[fsp][0]            \r
-\r
-    def AlaignPtr (self, offset, alignment = 8):\r
-        return (offset + alignment - 1) & ~(alignment - 1)\r
-\r
-    def GetFspInfoHdr (self, fvh, fvhe, fvoffset):\r
-        if fvhe:\r
-            offset = fvh.ExtHeaderOffset + fvhe.ExtHeaderSize\r
+                    res = ['0x%02X'%i for i in bytearray(val)]\r
+                    rep = '[%s]' % (','.join(res))\r
+            else:\r
+                rep = str(val)\r
+            plen -= sizeof(field[1])\r
+            body += pstr.format(key, rep)\r
+        if plen <= 0:\r
+            break\r
+    return body\r
+\r
+class Section:\r
+    def __init__(self, offset, secdata):\r
+        self.SecHdr   = EFI_COMMON_SECTION_HEADER.from_buffer (secdata, 0)\r
+        self.SecData  = secdata[0:int(self.SecHdr.Size)]\r
+        self.Offset   = offset\r
+\r
+class FirmwareFile:\r
+    def __init__(self, offset, filedata):\r
+        self.FfsHdr   = EFI_FFS_FILE_HEADER.from_buffer (filedata, 0)\r
+        self.FfsData  = filedata[0:int(self.FfsHdr.Size)]\r
+        self.Offset   = offset\r
+        self.SecList  = []\r
+\r
+    def ParseFfs(self):\r
+        ffssize = len(self.FfsData)\r
+        offset  = sizeof(self.FfsHdr)\r
+        if self.FfsHdr.Name != '\xff' * 16:\r
+            while offset < ffssize:\r
+                sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset)\r
+                sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)])\r
+                self.SecList.append(sec)\r
+                offset += int(sechdr.Size)\r
+                offset  = AlignPtr(offset, 4)\r
+\r
+class FirmwareVolume:\r
+    def __init__(self, offset, fvdata):\r
+        self.FvHdr    = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (fvdata, 0)\r
+        self.FvData   = fvdata[0 : self.FvHdr.FvLength]\r
+        self.Offset   = offset\r
+        if self.FvHdr.ExtHeaderOffset > 0:\r
+            self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset)\r
         else:\r
-            offset = fvh.HeaderLength\r
-        offset = self.AlaignPtr(offset)\r
-\r
-        # Now it should be 1st FFS\r
-        ffs = EFI_FFS_FILE_HEADER.from_buffer (self.FspDat, offset)        \r
-        offset += sizeof(ffs)\r
-        offset = self.AlaignPtr(offset)\r
-\r
-        # Now it should be 1st Section\r
-        sec = EFI_COMMON_SECTION_HEADER.from_buffer (self.FspDat, offset)\r
-        offset += sizeof(sec)\r
-\r
-        # Now it should be FSP_INFO_HEADER\r
-        offset += fvoffset\r
-        fih = FSP_INFORMATION_HEADER.from_buffer (self.FspDat, offset)\r
-        if 'FSPH' != bytearray.fromhex('%08X' % fih.Signature)[::-1]:\r
-            return None\r
-\r
-        return fih\r
-\r
-    def GetFvHdr (self, offset):\r
-        fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FspDat, offset)\r
-        if '_FVH' != bytearray.fromhex('%08X' % fvh.Signature)[::-1]:\r
-            return None, None\r
-        if fvh.ExtHeaderOffset > 0:\r
-            offset += fvh.ExtHeaderOffset\r
-            fvhe = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FspDat, offset)\r
+            self.FvExtHdr = None\r
+        self.FfsList  = []\r
+\r
+    def ParseFv(self):\r
+        fvsize = len(self.FvData)\r
+        if self.FvExtHdr:\r
+            offset = self.FvHdr.ExtHeaderOffset + self.FvExtHdr.ExtHeaderSize\r
         else:\r
-            fvhe = None\r
-        return fvh, fvhe\r
+            offset = self.FvHdr.HeaderLength\r
+        offset = AlignPtr(offset)\r
+        while offset < fvsize:\r
+            ffshdr = EFI_FFS_FILE_HEADER.from_buffer (self.FvData, offset)\r
+            if (ffshdr.Name == '\xff' * 16) and (int(ffshdr.Size) == 0xFFFFFF):\r
+                offset = fvsize\r
+            else:\r
+                ffs = FirmwareFile (offset, self.FvData[offset:offset + int(ffshdr.Size)])\r
+                ffs.ParseFfs()\r
+                self.FfsList.append(ffs)\r
+                offset += int(ffshdr.Size)\r
+                offset = AlignPtr(offset)\r
+\r
+class FspImage:\r
+    def __init__(self, offset, fih, fihoff, patch):\r
+        self.Fih       = fih\r
+        self.FihOffset = fihoff\r
+        self.Offset    = offset\r
+        self.FvIdxList = []\r
+        self.Type      = "XTMSXXXXOXXXXXXX"[(fih.ComponentAttribute >> 12) & 0x0F]\r
+        self.PatchList = patch\r
+        self.PatchList.append(fihoff + 0x1C)\r
+\r
+    def AppendFv(self, FvIdx):\r
+        self.FvIdxList.append(FvIdx)\r
+\r
+    def Patch(self, delta, fdbin):\r
+        count   = 0\r
+        applied = 0\r
+        for idx, patch in enumerate(self.PatchList):\r
+            ptype = (patch>>24) & 0x0F\r
+            if ptype not in [0x00, 0x0F]:\r
+                raise Exception('ERROR: Invalid patch type %d !' % ptype)\r
+            if patch & 0x80000000:\r
+                patch = self.Fih.ImageSize - (0x1000000 - (patch & 0xFFFFFF))\r
+            else:\r
+                patch = patch & 0xFFFFFF\r
+            if (patch < self.Fih.ImageSize) and (patch + sizeof(c_uint32) <= self.Fih.ImageSize):\r
+                offset = patch + 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
+                applied += 1\r
+            count += 1\r
+        # Don't count the FSP base address patch entry appended at the end\r
+        if count != 0:\r
+            count   -= 1\r
+            applied -= 1\r
+        return (count, applied)\r
+\r
+class FirmwareDevice:\r
+    def __init__(self, offset, fdfile):\r
+        self.FvList  = []\r
+        self.FspList = []\r
+        self.FdFile = fdfile\r
+        self.Offset = 0\r
+        hfsp = open (self.FdFile, 'rb')\r
+        self.FdData = bytearray(hfsp.read())\r
+        hfsp.close()\r
 \r
-    def GetFvData(self, idx):\r
-        (fvh, fvhe, offset) = self.FvList[idx]\r
-        return self.FspDat[offset:offset+fvh.FvLength]\r
+    def ParseFd(self):\r
+        offset = 0\r
+        fdsize = len(self.FdData)\r
+        self.FvList  = []\r
+        while offset < fdsize:\r
+            fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset)\r
+            if '_FVH' != fvh.Signature:\r
+                raise Exception("ERROR: Invalid FV header !")\r
+            fv = FirmwareVolume (offset, self.FdData[offset:offset + fvh.FvLength])\r
+            fv.ParseFv ()\r
+            self.FvList.append(fv)\r
+            offset += fv.FvHdr.FvLength\r
 \r
     def CheckFsp (self):\r
-        if len(self.FspFv) == 0:\r
+        if len(self.FspList) == 0:\r
             return\r
 \r
         fih = None\r
-        for fv in self.FspFv:\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 = self.FspFv[fv][0]\r
+                fih = fsp.Fih\r
             else:\r
-                newfih = self.FspFv[fv][0]\r
+                newfih = fsp.Fih\r
                 if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):\r
-                    raise Exception("Inconsistent FSP ImageId or ImageRevision detected !")\r
-        return\r
+                    raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")\r
+\r
+    def ParseFsp(self):\r
+        flen = 0\r
+        for idx, fv in enumerate(self.FvList):\r
+            # Check if this FV contains FSP header\r
+            if flen == 0:\r
+                if len(fv.FfsList) == 0:\r
+                    continue\r
+                ffs = fv.FfsList[0]\r
+                if len(ffs.SecList) == 0:\r
+                    continue\r
+                sec = ffs.SecList[0]\r
+                if sec.SecHdr.Type != EFI_SECTION_TYPE.RAW:\r
+                    continue\r
+                fihoffset = ffs.Offset + sec.Offset + sizeof(sec.SecHdr)\r
+                fspoffset = fv.Offset\r
+                offset    = fspoffset + fihoffset\r
+                fih = FSP_INFORMATION_HEADER.from_buffer (self.FdData, offset)\r
+                if 'FSPH' != fih.Signature:\r
+                    continue\r
+\r
+                offset += fih.HeaderLength\r
+                offset = AlignPtr(offset, 4)\r
+                plist  = []\r
+                while True:\r
+                    fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset)\r
+                    if 'FSPP' != fch.Signature:\r
+                        offset += fch.HeaderLength\r
+                        offset = AlignPtr(offset, 4)\r
+                    else:\r
+                        fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset)\r
+                        offset += sizeof(fspp)\r
+                        pdata  = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset)\r
+                        plist  = list(pdata)\r
+                        break\r
+\r
+                fsp  = FspImage (fspoffset, fih, fihoffset, plist)\r
+                fsp.AppendFv (idx)\r
+                self.FspList.append(fsp)\r
+                flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength\r
+            else:\r
+                fsp.AppendFv (idx)\r
+                flen -= fv.FvHdr.FvLength\r
+                if flen < 0:\r
+                    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
+        self.RelocList = []\r
+\r
+    def ParseReloc(self):\r
+        rsize   = self.TeHdr.DataDirectoryBaseReloc.Size\r
+        roffset   = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress\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
+            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
+            for each in rdata:\r
+                roff  = each & 0xfff\r
+                rtype = each >> 12\r
+                if rtype == 0: # IMAGE_REL_BASED.ABSOLUTE:\r
+                    continue\r
+                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
+                self.RelocList.append((rtype, aoff))\r
+            offset += sizeof(rdata)\r
+\r
+    def Rebase(self, delta, fdbin):\r
+        count = 0\r
+        if delta == 0:\r
+            return count\r
+\r
+        for (rtype, roff) in self.RelocList:\r
+            if rtype == 0x03: # 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
+            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
+\r
+        return count\r
 \r
-    def WriteFsp(self, dir, name):\r
+def ShowFspInfo (fspfile):\r
+    fd = FirmwareDevice(0, fspfile)\r
+    fd.ParseFd  ()\r
+    fd.ParseFsp ()\r
+\r
+    print ("\nFound the following %d Firmware Volumes in FSP binary:" % (len(fd.FvList)))\r
+    for idx, fv in enumerate(fd.FvList):\r
+        name = fv.FvExtHdr.FvName\r
         if not name:\r
-            name = self.FspBin\r
-        fspname, ext = os.path.splitext(os.path.basename(name))\r
-        for fv in self.FspFv:\r
-            filename = os.path.join(dir, fspname + fv + ext)\r
-            hfsp = open(filename, 'w+b')\r
-            for fvidx in self.FspFv[fv][1]:\r
-                hfsp.write (self.GetFvData(fvidx))\r
-            hfsp.close()\r
-\r
-    def WriteMap(self, dir, hfile):\r
-        if not hfile:\r
-            hfile = os.path.splitext(os.path.basename(self.FspBin))[0] + '.h'\r
-        fspname, ext = os.path.splitext(os.path.basename(hfile))\r
-        filename = os.path.join(dir, fspname + ext)\r
-        hfsp   = open(filename, 'w')\r
-        hfsp.write ('%s\n\n' % self.HeaderFile)\r
-\r
-        firstfv = True\r
-        for fsp in self.FspFv:\r
-            fih = self.FspFv[fsp][0]\r
-            fvs = self.FspFv[fsp][1]\r
-            if firstfv:\r
-                IdStr = str(bytearray.fromhex('%016X' % fih.ImageId)[::-1])\r
-                hfsp.write("#define  FSP_IMAGE_ID    0x%016X        /* '%s' */\n" % (fih.ImageId, IdStr))\r
-                hfsp.write("#define  FSP_IMAGE_REV   0x%08X \n\n" % fih.ImageRevision)\r
-                firstfv = False\r
-            hfsp.write ('#define  FSP%s_BASE      0x%08X\n'   % (fsp, fih.ImageBase))\r
-            hfsp.write ('#define  FSP%s_OFFSET    0x%08X\n'   % (fsp, self.FvList[fvs[0]][-1]))\r
-            hfsp.write ('#define  FSP%s_LENGTH    0x%08X\n\n' % (fsp, fih.ImageSize))\r
+            name = '\xff' * 16\r
+        else:\r
+            name = str(bytearray(name))\r
+        guid = uuid.UUID(bytes = name)\r
+        print ("FV%d:" % idx)\r
+        print ("  GUID   : %s" % str(guid).upper())\r
+        print ("  Offset : 0x%08X" %  fv.Offset)\r
+        print ("  Length : 0x%08X" % fv.FvHdr.FvLength)\r
+    print ("\n")\r
+\r
+    for fsp in fd.FspList:\r
+        fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList)\r
+        print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist)))\r
+        print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength)))\r
+\r
+def GenFspHdr (fspfile, outdir, hfile):\r
+    fd = FirmwareDevice(0, fspfile)\r
+    fd.ParseFd  ()\r
+    fd.ParseFsp ()\r
+\r
+    if not hfile:\r
+        hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h'\r
+    fspname, ext = os.path.splitext(os.path.basename(hfile))\r
+    filename = os.path.join(outdir, fspname + ext)\r
+    hfsp   = open(filename, 'w')\r
+    hfsp.write ('%s\n\n' % CopyRightHeaderFile)\r
+\r
+    firstfv = True\r
+    for fsp in fd.FspList:\r
+        fih = fsp.Fih\r
+        if firstfv:\r
+            hfsp.write("#define  FSP_IMAGE_ID    0x%016X    /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId))\r
+            hfsp.write("#define  FSP_IMAGE_REV   0x%08X \n\n" % fih.ImageRevision)\r
+            firstfv = False\r
+        fv = fd.FvList[fsp.FvIdxList[0]]\r
+        hfsp.write ('#define  FSP%s_BASE       0x%08X\n'   % (fsp.Type, fih.ImageBase))\r
+        hfsp.write ('#define  FSP%s_OFFSET     0x%08X\n'   % (fsp.Type, fv.Offset))\r
+        hfsp.write ('#define  FSP%s_LENGTH     0x%08X\n\n' % (fsp.Type, fih.ImageSize))\r
+\r
+    hfsp.close()\r
+\r
+def SplitFspBin (fspfile, outdir, nametemplate):\r
+    fd = FirmwareDevice(0, fspfile)\r
+    fd.ParseFd  ()\r
+    fd.ParseFsp ()\r
+\r
+    for fsp in fd.FspList:\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
+        for fvidx in fsp.FvIdxList:\r
+            fv = fd.FvList[fvidx]\r
+            hfsp.write(fv.FvData)\r
         hfsp.close()\r
 \r
-    def ParseFsp (self):\r
-        self.FspFv  = {}\r
-        flen = 0\r
-        for (fvh, fvhe, offset) in self.FvList:\r
-            fih = self.GetFspInfoHdr (fvh, fvhe, offset)\r
-            if fih:\r
-                if flen != 0:\r
-                    raise Exception("Incorrect FV size in image !")\r
-                ftype = str((fih.ImageAttribute >> 28) & 0xF)\r
-                if ftype not in self.FspNameDict:\r
-                    raise Exception("Unknown Attribute in image !")\r
-                fname = self.FspNameDict[str(ftype)]\r
-                if fname in self.FspFv:\r
-                    raise Exception("Multiple '%s' in image !" % fname)\r
-                self.FspFv[fname] = (copy.deepcopy(fih), [])\r
-                flen = fih.ImageSize\r
-            if flen > 0:\r
-                flen = flen - fvh.FvLength\r
-                if flen < 0:\r
-                    raise Exception("Incorrect FV size in image !")\r
-                self.FspFv[fname][1].append(self.FvList.index((fvh, fvhe, offset)))\r
+def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile):\r
+    fd = FirmwareDevice(0, FspBinary)\r
+    fd.ParseFd  ()\r
+    fd.ParseFsp ()\r
 \r
-    def AddFv(self, offset):\r
-        fvh, fvhe = self.GetFvHdr (offset)\r
-        if fvh is None:\r
-            raise Exception('FV signature is not valid !')\r
-        fvitem = (copy.deepcopy(fvh), copy.deepcopy(fvhe), offset)\r
-        self.FvList.append(fvitem)\r
-        return fvh.FvLength\r
+    numcomp  = len(FspComponent)\r
+    baselist = FspBase\r
+    if numcomp != len(baselist):\r
+        print "ERROR: Required number of base does not match number of FSP component !"\r
+        return\r
 \r
-    def ParseFv(self):\r
-        offset = 0\r
-        while (offset < len(self.FspDat)):\r
-            fv_len  = self.AddFv (offset)\r
-            offset += fv_len\r
-\r
-def GenFspHdr (fspfile, outdir, hfile, show):\r
-    fsp_fv = FspFv(fspfile)\r
-    fsp_fv.ParseFv()\r
-    fsp_fv.ParseFsp()\r
-    fsp_fv.CheckFsp()\r
-    if show:\r
-        fsp_fv.PrintFv()\r
-    fsp_fv.WriteMap(outdir, hfile)\r
-\r
-def SplitFspBin (fspfile, outdir, nametemplate, show):\r
-    fsp_fv = FspFv(fspfile)\r
-    fsp_fv.ParseFv()\r
-    fsp_fv.ParseFsp()\r
-    if show:\r
-        fsp_fv.PrintFv()\r
-    fsp_fv.WriteFsp(outdir, nametemplate)\r
+    newfspbin = fd.FdData[:]\r
+\r
+    for idx, fspcomp in enumerate(FspComponent):\r
+\r
+        found = False\r
+        for fsp in fd.FspList:\r
+            ftype = fsp.Type.lower()\r
+            if ftype == fspcomp:\r
+                found = True\r
+                break\r
+\r
+        if not found:\r
+            print "ERROR: Could not find FSP_%c component to rebase !" % fspcomp.upper()\r
+            return\r
+\r
+        fspbase = baselist[idx]\r
+        if fspbase.startswith('0x'):\r
+            newbase = int(fspbase, 16)\r
+        else:\r
+            newbase = int(fspbase)\r
+        oldbase = fsp.Fih.ImageBase\r
+        delta = newbase - oldbase\r
+        print "Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype.upper(),oldbase,newbase)\r
+\r
+        telist = []\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
+                        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
+\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
+\r
+        (count, applied) = fsp.Patch(delta, newfspbin)\r
+        print "  Patched %d entries using FSP patch table." % applied\r
+        if count != applied:\r
+            print "  %d invalid entries are ignored !" % (count - applied)\r
+\r
+    if OutputFile == '':\r
+        filename = os.path.basename(FspBinary)\r
+        base, ext  = os.path.splitext(filename)\r
+        OutputFile = base + "_%08X" % newbase + ext\r
+\r
+    fspname, ext = os.path.splitext(os.path.basename(OutputFile))\r
+    filename = os.path.join(OutputDir, fspname + ext)\r
+    fd = open(filename, "wb")\r
+    fd.write(newfspbin)\r
+    fd.close()\r
 \r
 def main ():\r
-    parser = argparse.ArgumentParser()\r
-    subparsers    = parser.add_subparsers(title='commands')\r
+    parser     = argparse.ArgumentParser()\r
+    subparsers = parser.add_subparsers(title='commands')\r
+\r
+    parser_rebase  = subparsers.add_parser('rebase',  help='rebase a FSP into a new base address')\r
+    parser_rebase.set_defaults(which='rebase')\r
+    parser_rebase.add_argument('-f',  '--fspbin' , dest='FspBinary',  type=str, help='FSP binary file path', required = True)\r
+    parser_rebase.add_argument('-c',  '--fspcomp', choices=['t','m','s','o'],  nargs='+', dest='FspComponent', type=str, help='FSP component to rebase', default = "['t']", required = True)\r
+    parser_rebase.add_argument('-b',  '--newbase', dest='FspBase', nargs='+', type=str, help='Rebased FSP binary file name', default = '', required = True)\r
+    parser_rebase.add_argument('-o',  '--outdir' , dest='OutputDir',  type=str, help='Output directory path', default = '.')\r
+    parser_rebase.add_argument('-n',  '--outfile', dest='OutputFile', type=str, help='Rebased FSP binary file name', default = '')\r
 \r
     parser_split  = subparsers.add_parser('split',  help='split a FSP into multiple components')\r
     parser_split.set_defaults(which='split')\r
     parser_split.add_argument('-f',  '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
     parser_split.add_argument('-o',  '--outdir' , dest='OutputDir', type=str, help='Output directory path',   default = '.')\r
     parser_split.add_argument('-n',  '--nametpl', dest='NameTemplate', type=str, help='Output name template', default = '')\r
-    parser_split.add_argument('-p', action='store_true', help='Print FSP FV information', default = False)\r
 \r
     parser_genhdr = subparsers.add_parser('genhdr',  help='generate a header file for FSP binary')\r
     parser_genhdr.set_defaults(which='genhdr')\r
     parser_genhdr.add_argument('-f',  '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
     parser_genhdr.add_argument('-o',  '--outdir' , dest='OutputDir', type=str, help='Output directory path',   default = '.')\r
     parser_genhdr.add_argument('-n',  '--hfile',   dest='HFileName', type=str, help='Output header file name', default = '')\r
-    parser_genhdr.add_argument('-p', action='store_true', help='Print FSP FV information', default = False)\r
+\r
+    parser_info = subparsers.add_parser('info',  help='display FSP information')\r
+    parser_info.set_defaults(which='info')\r
+    parser_info.add_argument('-f',  '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
 \r
     args = parser.parse_args()\r
-    if args.which in ['split', 'genhdr']:\r
+    if args.which in ['rebase', 'split', 'genhdr', 'info']:\r
         if not os.path.exists(args.FspBinary):\r
-            raise Exception ("Could not locate FSP binary file '%s' !" % args.FspBinary)\r
-        if not os.path.exists(args.OutputDir):\r
-            raise Exception ("Invalid output directory '%s' !" % args.OutputDir)\r
-\r
-    if args.which == 'split':\r
-        SplitFspBin (args.FspBinary, args.OutputDir, args.NameTemplate, args.p)\r
+            raise Exception ("ERROR: Could not locate FSP binary file '%s' !" % args.FspBinary)\r
+        if hasattr(args, 'OutputDir') and not os.path.exists(args.OutputDir):\r
+            raise Exception ("ERROR: Invalid output directory '%s' !" % args.OutputDir)\r
+\r
+    if args.which == 'rebase':\r
+        RebaseFspBin (args.FspBinary, args.FspComponent, args.FspBase, args.OutputDir, args.OutputFile)\r
+    elif args.which == 'split':\r
+        SplitFspBin (args.FspBinary, args.OutputDir, args.NameTemplate)\r
     elif args.which == 'genhdr':\r
-        GenFspHdr   (args.FspBinary, args.OutputDir, args.HFileName, args.p)\r
+        GenFspHdr (args.FspBinary, args.OutputDir, args.HFileName)\r
+    elif args.which == 'info':\r
+        ShowFspInfo (args.FspBinary)\r
     else:\r
         pass\r
 \r
-    print 'Done!'\r
     return 0\r
 \r
 if __name__ == '__main__':\r