Cc: Maurice Ma <maurice.ma@intel.com> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com> Cc: Chasel Chiu <chasel.chiu@intel.com> Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Chasel Chiu <chasel.chiu@intel.com> Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
		
			
				
	
	
		
			915 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			915 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| ## @ SplitFspBin.py
 | |
| #
 | |
| # Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
 | |
| # SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| #
 | |
| ##
 | |
| 
 | |
| import os
 | |
| import sys
 | |
| import uuid
 | |
| import copy
 | |
| import struct
 | |
| import argparse
 | |
| from   ctypes import *
 | |
| from functools import reduce
 | |
| 
 | |
| """
 | |
| This utility supports some operations for Intel FSP 1.x/2.x image.
 | |
| It supports:
 | |
|     - Display FSP 1.x/2.x information header
 | |
|     - Split FSP 2.x image into individual FSP-T/M/S/O component
 | |
|     - Rebase FSP 1.x/2.x components to a different base address
 | |
|     - Generate FSP 1.x/2.x 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))]
 | |
| 
 | |
|     def __init__(self, val=0):
 | |
|         self.set_value(val)
 | |
| 
 | |
|     def __str__(self, indent=0):
 | |
|         return '0x%.6x' % self.value
 | |
| 
 | |
|     def __int__(self):
 | |
|         return self.get_value()
 | |
| 
 | |
|     def set_value(self, val):
 | |
|         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_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_uint8, 16)),
 | |
|         ('ExtHeaderSize',        c_uint32)
 | |
|         ]
 | |
| 
 | |
| class EFI_FFS_INTEGRITY_CHECK(Structure):
 | |
|     _fields_ = [
 | |
|         ('Header',               c_uint8),
 | |
|         ('File',                 c_uint8)
 | |
|         ]
 | |
| 
 | |
| class EFI_FFS_FILE_HEADER(Structure):
 | |
|     _fields_ = [
 | |
|         ('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)
 | |
|         ]
 | |
| 
 | |
| class FSP_COMMON_HEADER(Structure):
 | |
|      _fields_ = [
 | |
|         ('Signature',            ARRAY(c_char, 4)),
 | |
|         ('HeaderLength',         c_uint32)
 | |
|         ]
 | |
| 
 | |
| class FSP_INFORMATION_HEADER(Structure):
 | |
|      _fields_ = [
 | |
|         ('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),
 | |
|         ('FspMultiPhaseSiInitEntryOffset', c_uint32),
 | |
|         ('ExtendedImageRevision',          c_uint16),
 | |
|         ('Reserved4',                      c_uint16)
 | |
|     ]
 | |
| 
 | |
| 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 EFI_IMAGE_DOS_HEADER(Structure):
 | |
|     _fields_ = [
 | |
|         ('e_magic',              c_uint16),
 | |
|         ('e_cblp',               c_uint16),
 | |
|         ('e_cp',                 c_uint16),
 | |
|         ('e_crlc',               c_uint16),
 | |
|         ('e_cparhdr',            c_uint16),
 | |
|         ('e_minalloc',           c_uint16),
 | |
|         ('e_maxalloc',           c_uint16),
 | |
|         ('e_ss',                 c_uint16),
 | |
|         ('e_sp',                 c_uint16),
 | |
|         ('e_csum',               c_uint16),
 | |
|         ('e_ip',                 c_uint16),
 | |
|         ('e_cs',                 c_uint16),
 | |
|         ('e_lfarlc',             c_uint16),
 | |
|         ('e_ovno',               c_uint16),
 | |
|         ('e_res',                ARRAY(c_uint16, 4)),
 | |
|         ('e_oemid',              c_uint16),
 | |
|         ('e_oeminfo',            c_uint16),
 | |
|         ('e_res2',               ARRAY(c_uint16, 10)),
 | |
|         ('e_lfanew',             c_uint16)
 | |
|         ]
 | |
| 
 | |
| class EFI_IMAGE_FILE_HEADER(Structure):
 | |
|     _fields_ = [
 | |
|         ('Machine',               c_uint16),
 | |
|         ('NumberOfSections',      c_uint16),
 | |
|         ('TimeDateStamp',         c_uint32),
 | |
|         ('PointerToSymbolTable',  c_uint32),
 | |
|         ('NumberOfSymbols',       c_uint32),
 | |
|         ('SizeOfOptionalHeader',  c_uint16),
 | |
|         ('Characteristics',       c_uint16)
 | |
|         ]
 | |
| 
 | |
| class PE_RELOC_BLOCK_HEADER(Structure):
 | |
|     _fields_ = [
 | |
|         ('PageRVA',              c_uint32),
 | |
|         ('BlockSize',            c_uint32)
 | |
|         ]
 | |
| 
 | |
| class EFI_IMAGE_OPTIONAL_HEADER32(Structure):
 | |
|     _fields_ = [
 | |
|         ('Magic',                         c_uint16),
 | |
|         ('MajorLinkerVersion',            c_uint8),
 | |
|         ('MinorLinkerVersion',            c_uint8),
 | |
|         ('SizeOfCode',                    c_uint32),
 | |
|         ('SizeOfInitializedData',         c_uint32),
 | |
|         ('SizeOfUninitializedData',       c_uint32),
 | |
|         ('AddressOfEntryPoint',           c_uint32),
 | |
|         ('BaseOfCode',                    c_uint32),
 | |
|         ('BaseOfData',                    c_uint32),
 | |
|         ('ImageBase',                     c_uint32),
 | |
|         ('SectionAlignment',              c_uint32),
 | |
|         ('FileAlignment',                 c_uint32),
 | |
|         ('MajorOperatingSystemVersion',   c_uint16),
 | |
|         ('MinorOperatingSystemVersion',   c_uint16),
 | |
|         ('MajorImageVersion',             c_uint16),
 | |
|         ('MinorImageVersion',             c_uint16),
 | |
|         ('MajorSubsystemVersion',         c_uint16),
 | |
|         ('MinorSubsystemVersion',         c_uint16),
 | |
|         ('Win32VersionValue',             c_uint32),
 | |
|         ('SizeOfImage',                   c_uint32),
 | |
|         ('SizeOfHeaders',                 c_uint32),
 | |
|         ('CheckSum'     ,                 c_uint32),
 | |
|         ('Subsystem',                     c_uint16),
 | |
|         ('DllCharacteristics',            c_uint16),
 | |
|         ('SizeOfStackReserve',            c_uint32),
 | |
|         ('SizeOfStackCommit' ,            c_uint32),
 | |
|         ('SizeOfHeapReserve',             c_uint32),
 | |
|         ('SizeOfHeapCommit' ,             c_uint32),
 | |
|         ('LoaderFlags'     ,              c_uint32),
 | |
|         ('NumberOfRvaAndSizes',           c_uint32),
 | |
|         ('DataDirectory',                 ARRAY(EFI_IMAGE_DATA_DIRECTORY, 16))
 | |
|         ]
 | |
| 
 | |
| class EFI_IMAGE_OPTIONAL_HEADER32_PLUS(Structure):
 | |
|     _fields_ = [
 | |
|         ('Magic',                         c_uint16),
 | |
|         ('MajorLinkerVersion',            c_uint8),
 | |
|         ('MinorLinkerVersion',            c_uint8),
 | |
|         ('SizeOfCode',                    c_uint32),
 | |
|         ('SizeOfInitializedData',         c_uint32),
 | |
|         ('SizeOfUninitializedData',       c_uint32),
 | |
|         ('AddressOfEntryPoint',           c_uint32),
 | |
|         ('BaseOfCode',                    c_uint32),
 | |
|         ('ImageBase',                     c_uint64),
 | |
|         ('SectionAlignment',              c_uint32),
 | |
|         ('FileAlignment',                 c_uint32),
 | |
|         ('MajorOperatingSystemVersion',   c_uint16),
 | |
|         ('MinorOperatingSystemVersion',   c_uint16),
 | |
|         ('MajorImageVersion',             c_uint16),
 | |
|         ('MinorImageVersion',             c_uint16),
 | |
|         ('MajorSubsystemVersion',         c_uint16),
 | |
|         ('MinorSubsystemVersion',         c_uint16),
 | |
|         ('Win32VersionValue',             c_uint32),
 | |
|         ('SizeOfImage',                   c_uint32),
 | |
|         ('SizeOfHeaders',                 c_uint32),
 | |
|         ('CheckSum'     ,                 c_uint32),
 | |
|         ('Subsystem',                     c_uint16),
 | |
|         ('DllCharacteristics',            c_uint16),
 | |
|         ('SizeOfStackReserve',            c_uint64),
 | |
|         ('SizeOfStackCommit' ,            c_uint64),
 | |
|         ('SizeOfHeapReserve',             c_uint64),
 | |
|         ('SizeOfHeapCommit' ,             c_uint64),
 | |
|         ('LoaderFlags'     ,              c_uint32),
 | |
|         ('NumberOfRvaAndSizes',           c_uint32),
 | |
|         ('DataDirectory',                 ARRAY(EFI_IMAGE_DATA_DIRECTORY, 16))
 | |
|         ]
 | |
| 
 | |
| class EFI_IMAGE_OPTIONAL_HEADER(Union):
 | |
|     _fields_ = [
 | |
|         ('PeOptHdr',             EFI_IMAGE_OPTIONAL_HEADER32),
 | |
|         ('PePlusOptHdr',         EFI_IMAGE_OPTIONAL_HEADER32_PLUS)
 | |
|         ]
 | |
| 
 | |
| class EFI_IMAGE_NT_HEADERS32(Structure):
 | |
|     _fields_ = [
 | |
|         ('Signature',            c_uint32),
 | |
|         ('FileHeader',           EFI_IMAGE_FILE_HEADER),
 | |
|         ('OptionalHeader',       EFI_IMAGE_OPTIONAL_HEADER)
 | |
|         ]
 | |
| 
 | |
| 
 | |
| class EFI_IMAGE_DIRECTORY_ENTRY:
 | |
|     EXPORT                     = 0
 | |
|     IMPORT                     = 1
 | |
|     RESOURCE                   = 2
 | |
|     EXCEPTION                  = 3
 | |
|     SECURITY                   = 4
 | |
|     BASERELOC                  = 5
 | |
|     DEBUG                      = 6
 | |
|     COPYRIGHT                  = 7
 | |
|     GLOBALPTR                  = 8
 | |
|     TLS                        = 9
 | |
|     LOAD_CONFIG                = 10
 | |
| 
 | |
| 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 IsIntegerType (val):
 | |
|     if sys.version_info[0] < 3:
 | |
|         if type(val) in (int, long):
 | |
|             return True
 | |
|     else:
 | |
|         if type(val) is int:
 | |
|             return True
 | |
|     return False
 | |
| 
 | |
| def IsStrType (val):
 | |
|     if sys.version_info[0] < 3:
 | |
|         if type(val) is str:
 | |
|             return True
 | |
|     else:
 | |
|         if type(val) is bytes:
 | |
|             return True
 | |
|     return False
 | |
| 
 | |
| def HandleNameStr (val):
 | |
|     if sys.version_info[0] < 3:
 | |
|         rep = "0x%X ('%s')" % (Bytes2Val (bytearray (val)), val)
 | |
|     else:
 | |
|         rep = "0x%X ('%s')" % (Bytes2Val (bytearray (val)), str (val, 'utf-8'))
 | |
|     return rep
 | |
| 
 | |
| 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:
 | |
|             if IsStrType (val):
 | |
|                 rep = HandleNameStr (val)
 | |
|             elif IsIntegerType (val):
 | |
|                 if (key == 'ImageRevision'):
 | |
|                     FspImageRevisionMajor       = ((val >> 24) & 0xFF)
 | |
|                     FspImageRevisionMinor       = ((val >> 16) & 0xFF)
 | |
|                     FspImageRevisionRevision    = ((val >> 8) & 0xFF)
 | |
|                     FspImageRevisionBuildNumber = (val & 0xFF)
 | |
|                     rep = '0x%08X' % val
 | |
|                 elif (key == 'ExtendedImageRevision'):
 | |
|                     FspImageRevisionRevision    |= (val & 0xFF00)
 | |
|                     FspImageRevisionBuildNumber |= ((val << 8) & 0xFF00)
 | |
|                     rep = "0x%04X ('%02X.%02X.%04X.%04X')" % (val, FspImageRevisionMajor, FspImageRevisionMinor, FspImageRevisionRevision, FspImageRevisionBuildNumber)
 | |
|                 elif field[1] == c_uint64:
 | |
|                     rep = '0x%016X' % val
 | |
|                 elif field[1] == c_uint32:
 | |
|                     rep = '0x%08X' % val
 | |
|                 elif field[1] == c_uint16:
 | |
|                     rep = '0x%04X' % val
 | |
|                 elif field[1] == c_uint8:
 | |
|                     rep = '0x%02X' % val
 | |
|                 else:
 | |
|                     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:
 | |
|                     if sys.version_info[0] < 3:
 | |
|                         rep = str(bytearray(val))
 | |
|                     else:
 | |
|                         rep = bytes(val)
 | |
|                     rep = str(uuid.UUID(bytes_le = rep)).upper()
 | |
|                 else:
 | |
|                     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 - sizeof (EFI_COMMON_SECTION_HEADER)):
 | |
|                 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:
 | |
|             self.FvExtHdr = None
 | |
|         self.FfsList  = []
 | |
| 
 | |
|     def ParseFv(self):
 | |
|         fvsize = len(self.FvData)
 | |
|         if self.FvExtHdr:
 | |
|             offset = self.FvHdr.ExtHeaderOffset + self.FvExtHdr.ExtHeaderSize
 | |
|         else:
 | |
|             offset = self.FvHdr.HeaderLength
 | |
|         offset = AlignPtr(offset)
 | |
|         while offset < (fvsize - sizeof (EFI_FFS_FILE_HEADER)):
 | |
|             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 ParseFd(self):
 | |
|         offset = 0
 | |
|         fdsize = len(self.FdData)
 | |
|         self.FvList  = []
 | |
|         while offset < (fdsize - sizeof (EFI_FIRMWARE_VOLUME_HEADER)):
 | |
|             fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset)
 | |
|             if b'_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.FspList) == 0:
 | |
|             return
 | |
| 
 | |
|         fih = None
 | |
|         for fsp in self.FspList:
 | |
|             if not fih:
 | |
|                 fih = fsp.Fih
 | |
|             else:
 | |
|                 newfih = fsp.Fih
 | |
|                 if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):
 | |
|                     raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
 | |
| 
 | |
|     def ParseFsp(self):
 | |
|         flen = 0
 | |
|         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 b'FSPH' != fih.Signature:
 | |
|                     continue
 | |
| 
 | |
|                 offset += fih.HeaderLength
 | |
|                 offset = AlignPtr(offset, 4)
 | |
|                 plist  = []
 | |
|                 while True:
 | |
|                     fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset)
 | |
|                     if b'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("ERROR: Incorrect FV size in image !")
 | |
|         self.CheckFsp ()
 | |
| 
 | |
| class PeTeImage:
 | |
|     def __init__(self, offset, data):
 | |
|         self.Offset    = offset
 | |
|         tehdr          = EFI_TE_IMAGE_HEADER.from_buffer (data, 0)
 | |
|         if   tehdr.Signature == b'VZ': # TE image
 | |
|             self.TeHdr   = tehdr
 | |
|         elif tehdr.Signature == b'MZ': # PE image
 | |
|             self.TeHdr   = None
 | |
|             self.DosHdr  = EFI_IMAGE_DOS_HEADER.from_buffer (data, 0)
 | |
|             self.PeHdr   = EFI_IMAGE_NT_HEADERS32.from_buffer (data, self.DosHdr.e_lfanew)
 | |
|             if self.PeHdr.Signature != 0x4550:
 | |
|                 raise Exception("ERROR: Invalid PE32 header !")
 | |
|             if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image
 | |
|                 if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32.DataDirectory.offset:
 | |
|                     raise Exception("ERROR: Unsupported PE32 image !")
 | |
|                 if self.PeHdr.OptionalHeader.PeOptHdr.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:
 | |
|                     raise Exception("ERROR: No relocation information available !")
 | |
|             elif self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x20b: # PE32+ image
 | |
|                 if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32_PLUS.DataDirectory.offset:
 | |
|                     raise Exception("ERROR: Unsupported PE32+ image !")
 | |
|                 if self.PeHdr.OptionalHeader.PePlusOptHdr.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:
 | |
|                     raise Exception("ERROR: No relocation information available !")
 | |
|             else:
 | |
|                 raise Exception("ERROR: Invalid PE32 optional header !")
 | |
|         self.Offset    = offset
 | |
|         self.Data      = data
 | |
|         self.RelocList = []
 | |
| 
 | |
|     def IsTeImage(self):
 | |
|         return  self.TeHdr is not None
 | |
| 
 | |
|     def ParseReloc(self):
 | |
|         if self.IsTeImage():
 | |
|             rsize   = self.TeHdr.DataDirectoryBaseReloc.Size
 | |
|             roffset = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress
 | |
|         else:
 | |
|             # Assuming PE32 image type (self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b)
 | |
|             rsize   = self.PeHdr.OptionalHeader.PeOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size
 | |
|             roffset = self.PeHdr.OptionalHeader.PeOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress
 | |
|             if self.PeHdr.OptionalHeader.PePlusOptHdr.Magic == 0x20b: # PE32+ image
 | |
|                 rsize   = self.PeHdr.OptionalHeader.PePlusOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size
 | |
|                 roffset = self.PeHdr.OptionalHeader.PePlusOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress
 | |
| 
 | |
|         alignment = 4
 | |
|         offset = roffset
 | |
|         while offset < roffset + rsize:
 | |
|             offset = AlignPtr(offset, 4)
 | |
|             blkhdr = PE_RELOC_BLOCK_HEADER.from_buffer(self.Data, offset)
 | |
|             offset += sizeof(blkhdr)
 | |
|             # Read relocation type,offset pairs
 | |
|             rlen  = blkhdr.BlockSize - sizeof(PE_RELOC_BLOCK_HEADER)
 | |
|             rnum  = int (rlen/sizeof(c_uint16))
 | |
|             rdata = (c_uint16 * rnum).from_buffer(self.Data, offset)
 | |
|             for each in rdata:
 | |
|                 roff  = each & 0xfff
 | |
|                 rtype = each >> 12
 | |
|                 if rtype == 0: # IMAGE_REL_BASED_ABSOLUTE:
 | |
|                     continue
 | |
|                 if ((rtype != 3) and (rtype != 10)): # IMAGE_REL_BASED_HIGHLOW and IMAGE_REL_BASED_DIR64
 | |
|                     raise Exception("ERROR: Unsupported relocation type %d!" % rtype)
 | |
|                 # Calculate the offset of the relocation
 | |
|                 aoff  = blkhdr.PageRVA + roff
 | |
|                 if self.IsTeImage():
 | |
|                     aoff += sizeof(self.TeHdr) - self.TeHdr.StrippedSize
 | |
|                 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 == 3: # IMAGE_REL_BASED_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
 | |
|             elif rtype == 10: # IMAGE_REL_BASED_DIR64
 | |
|                 offset = roff + self.Offset
 | |
|                 value  = Bytes2Val(fdbin[offset:offset+sizeof(c_uint64)])
 | |
|                 value += delta
 | |
|                 fdbin[offset:offset+sizeof(c_uint64)] = Val2Bytes(value, sizeof(c_uint64))
 | |
|                 count += 1
 | |
|             else:
 | |
|                 raise Exception('ERROR: Unknown relocation type %d !' % rtype)
 | |
| 
 | |
|         if self.IsTeImage():
 | |
|             offset  = self.Offset + EFI_TE_IMAGE_HEADER.ImageBase.offset
 | |
|             size    = EFI_TE_IMAGE_HEADER.ImageBase.size
 | |
|         else:
 | |
|             offset  = self.Offset + self.DosHdr.e_lfanew
 | |
|             offset += EFI_IMAGE_NT_HEADERS32.OptionalHeader.offset
 | |
|             if self.PeHdr.OptionalHeader.PePlusOptHdr.Magic == 0x20b: # PE32+ image
 | |
|                 offset += EFI_IMAGE_OPTIONAL_HEADER32_PLUS.ImageBase.offset
 | |
|                 size    = EFI_IMAGE_OPTIONAL_HEADER32_PLUS.ImageBase.size
 | |
|             else:
 | |
|                 offset += EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.offset
 | |
|                 size    = EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.size
 | |
| 
 | |
|         value  = Bytes2Val(fdbin[offset:offset+size]) + delta
 | |
|         fdbin[offset:offset+size] = Val2Bytes(value, size)
 | |
| 
 | |
|         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:
 | |
|             if sys.version_info[0] < 3:
 | |
|                 name = str(bytearray(name))
 | |
|             else:
 | |
|                 name = bytes(name)
 | |
|         guid = uuid.UUID(bytes_le = 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:
 | |
|             if sys.version_info[0] < 3:
 | |
|                 hfsp.write("#define  FSP_IMAGE_ID    0x%016X    /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId))
 | |
|             else:
 | |
|                 hfsp.write("#define  FSP_IMAGE_ID    0x%016X    /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), str (fih.ImageId, 'utf-8')))
 | |
|             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:
 | |
|         if fsp.Fih.HeaderRevision < 3:
 | |
|             raise Exception("ERROR: FSP 1.x is not supported by the split command !")
 | |
|         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 ("Create 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:
 | |
|             # Is this FSP 1.x single binary?
 | |
|             if fsp.Fih.HeaderRevision < 3:
 | |
|                 found = True
 | |
|                 ftype = 'X'
 | |
|                 break
 | |
|             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))
 | |
| 
 | |
|         imglist = []
 | |
|         for fvidx in fsp.FvIdxList:
 | |
|             fv = fd.FvList[fvidx]
 | |
|             for ffs in fv.FfsList:
 | |
|                 for sec in ffs.SecList:
 | |
|                     if sec.SecHdr.Type in [EFI_SECTION_TYPE.TE, EFI_SECTION_TYPE.PE32]:   # TE or PE32
 | |
|                         offset = fd.Offset + fv.Offset + ffs.Offset + sec.Offset + sizeof(sec.SecHdr)
 | |
|                         imglist.append ((offset, len(sec.SecData) - sizeof(sec.SecHdr)))
 | |
| 
 | |
|         fcount  = 0
 | |
|         pcount  = 0
 | |
|         for (offset, length) in imglist:
 | |
|             img = PeTeImage(offset, fd.FdData[offset:offset + length])
 | |
|             img.ParseReloc()
 | |
|             pcount += img.Rebase(delta, newfspbin)
 | |
|             fcount += 1
 | |
| 
 | |
|         print ("  Patched %d entries in %d TE/PE32 images." % (pcount, 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', dest="which")
 | |
| 
 | |
|     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_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_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 ['rebase', 'split', 'genhdr', 'info']:
 | |
|         if not os.path.exists(args.FspBinary):
 | |
|             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 == '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)
 | |
|     elif args.which == 'info':
 | |
|         ShowFspInfo (args.FspBinary)
 | |
|     else:
 | |
|         parser.print_help()
 | |
| 
 | |
|     return 0
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     sys.exit(main())
 |