123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- ## @ SplitFspBin.py
- #
- # Copyright (c) 2015 - 2022, 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),
- ('FspMultiPhaseMemInitEntryOffset', c_uint32),
- ('FspSmmInitEntryOffset', c_uint32)
- ]
- 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 = "XTMSIXXXOXXXXXXX"[(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','i'], 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())
|