Thanks Maurice, for extending the capability of the split tool to support 
rebasing.

Reviewed-by: Giri P Mudusuru <giri.p.mudus...@intel.com>


-----Original Message-----
From: Ma, Maurice 
Sent: Friday, May 27, 2016 2:12 PM
To: edk2-devel@lists.01.org
Cc: Ma, Maurice <maurice...@intel.com>; Yao, Jiewen <jiewen....@intel.com>; 
Mudusuru, Giri P <giri.p.mudus...@intel.com>
Subject: [edk2] [PATCH] IntelFsp2Pkg/Tools: Add FSP rebasing function into 
SplitFspBin tool

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....@intel.com>
Cc: Giri P Mudusuru <giri.p.mudus...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Maurice Ma <maurice...@intel.com>
---
 IntelFsp2Pkg/Tools/SplitFspBin.py | 830 ++++++++++++++++++++++++++------------
 1 file changed, 573 insertions(+), 257 deletions(-)

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

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to