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
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