* [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly @ 2018-09-18 13:32 Patrick Georgi 2018-09-18 13:32 ` [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin Patrick Georgi ` (2 more replies) 0 siblings, 3 replies; 13+ messages in thread From: Patrick Georgi @ 2018-09-18 13:32 UTC (permalink / raw) To: edk2-devel; +Cc: Patrick Georgi Signed-off-by: Patrick Georgi <pgeorgi@google.com> Contributed-under: TianoCore Contribution Agreement 1.1 --- IntelFsp2Pkg/Tools/SplitFspBin.py | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 IntelFsp2Pkg/Tools/SplitFspBin.py diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py b/IntelFsp2Pkg/Tools/SplitFspBin.py old mode 100644 new mode 100755 index 9b18720307..bd5507c2fa --- a/IntelFsp2Pkg/Tools/SplitFspBin.py +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ## @ FspTool.py # # Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> -- 2.19.0.397.gdd90340f6a-goog ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin 2018-09-18 13:32 [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly Patrick Georgi @ 2018-09-18 13:32 ` Patrick Georgi 2018-09-18 15:04 ` Desimone, Nathaniel L 2018-09-18 13:32 ` [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines Patrick Georgi 2018-09-18 15:03 ` [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly Desimone, Nathaniel L 2 siblings, 1 reply; 13+ messages in thread From: Patrick Georgi @ 2018-09-18 13:32 UTC (permalink / raw) To: edk2-devel; +Cc: Patrick Georgi Signed-off-by: Patrick Georgi <pgeorgi@google.com> Contributed-under: TianoCore Contribution Agreement 1.1 --- IntelFsp2Pkg/Tools/SplitFspBin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py b/IntelFsp2Pkg/Tools/SplitFspBin.py index bd5507c2fa..ac864492e8 100755 --- a/IntelFsp2Pkg/Tools/SplitFspBin.py +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py @@ -726,7 +726,7 @@ def SplitFspBin (fspfile, outdir, nametemplate): fspname, ext = os.path.splitext(os.path.basename(nametemplate)) filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext) hfsp = open(filename, 'wb') - print ("Ceate FSP component file '%s'" % filename) + print ("Create FSP component file '%s'" % filename) for fvidx in fsp.FvIdxList: fv = fd.FvList[fvidx] hfsp.write(fv.FvData) -- 2.19.0.397.gdd90340f6a-goog ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin 2018-09-18 13:32 ` [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin Patrick Georgi @ 2018-09-18 15:04 ` Desimone, Nathaniel L 2018-09-20 23:28 ` Chiu, Chasel 0 siblings, 1 reply; 13+ messages in thread From: Desimone, Nathaniel L @ 2018-09-18 15:04 UTC (permalink / raw) To: Patrick Georgi, edk2-devel@lists.01.org Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com> On 9/18/18, 6:32 AM, "edk2-devel on behalf of Patrick Georgi" <edk2-devel-bounces@lists.01.org on behalf of pgeorgi@google.com> wrote: Signed-off-by: Patrick Georgi <pgeorgi@google.com> Contributed-under: TianoCore Contribution Agreement 1.1 --- IntelFsp2Pkg/Tools/SplitFspBin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py b/IntelFsp2Pkg/Tools/SplitFspBin.py index bd5507c2fa..ac864492e8 100755 --- a/IntelFsp2Pkg/Tools/SplitFspBin.py +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py @@ -726,7 +726,7 @@ def SplitFspBin (fspfile, outdir, nametemplate): fspname, ext = os.path.splitext(os.path.basename(nametemplate)) filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext) hfsp = open(filename, 'wb') - print ("Ceate FSP component file '%s'" % filename) + print ("Create FSP component file '%s'" % filename) for fvidx in fsp.FvIdxList: fv = fd.FvList[fvidx] hfsp.write(fv.FvData) -- 2.19.0.397.gdd90340f6a-goog _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin 2018-09-18 15:04 ` Desimone, Nathaniel L @ 2018-09-20 23:28 ` Chiu, Chasel 2018-09-26 3:11 ` Yao, Jiewen 0 siblings, 1 reply; 13+ messages in thread From: Chiu, Chasel @ 2018-09-20 23:28 UTC (permalink / raw) To: Desimone, Nathaniel L, Patrick Georgi, edk2-devel@lists.01.org Reviewed-by: Chasel Chiu <chasel.chiu@intel.com> -----Original Message----- From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Desimone, Nathaniel L Sent: Tuesday, September 18, 2018 11:04 PM To: Patrick Georgi <pgeorgi@google.com>; edk2-devel@lists.01.org Subject: Re: [edk2] [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com> On 9/18/18, 6:32 AM, "edk2-devel on behalf of Patrick Georgi" <edk2-devel-bounces@lists.01.org on behalf of pgeorgi@google.com> wrote: Signed-off-by: Patrick Georgi <pgeorgi@google.com> Contributed-under: TianoCore Contribution Agreement 1.1 --- IntelFsp2Pkg/Tools/SplitFspBin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py b/IntelFsp2Pkg/Tools/SplitFspBin.py index bd5507c2fa..ac864492e8 100755 --- a/IntelFsp2Pkg/Tools/SplitFspBin.py +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py @@ -726,7 +726,7 @@ def SplitFspBin (fspfile, outdir, nametemplate): fspname, ext = os.path.splitext(os.path.basename(nametemplate)) filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext) hfsp = open(filename, 'wb') - print ("Ceate FSP component file '%s'" % filename) + print ("Create FSP component file '%s'" % filename) for fvidx in fsp.FvIdxList: fv = fd.FvList[fvidx] hfsp.write(fv.FvData) -- 2.19.0.397.gdd90340f6a-goog _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin 2018-09-20 23:28 ` Chiu, Chasel @ 2018-09-26 3:11 ` Yao, Jiewen 0 siblings, 0 replies; 13+ messages in thread From: Yao, Jiewen @ 2018-09-26 3:11 UTC (permalink / raw) To: Chiu, Chasel, Desimone, Nathaniel L, Patrick Georgi, edk2-devel@lists.01.org Reviewed-by: Jiewen.yao@intel.com > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of > Chiu, Chasel > Sent: Friday, September 21, 2018 7:28 AM > To: Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Patrick > Georgi <pgeorgi@google.com>; edk2-devel@lists.01.org > Subject: Re: [edk2] [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin > > > Reviewed-by: Chasel Chiu <chasel.chiu@intel.com> > > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of > Desimone, Nathaniel L > Sent: Tuesday, September 18, 2018 11:04 PM > To: Patrick Georgi <pgeorgi@google.com>; edk2-devel@lists.01.org > Subject: Re: [edk2] [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin > > Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com> > > On 9/18/18, 6:32 AM, "edk2-devel on behalf of Patrick Georgi" > <edk2-devel-bounces@lists.01.org on behalf of pgeorgi@google.com> > wrote: > > Signed-off-by: Patrick Georgi <pgeorgi@google.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > --- > IntelFsp2Pkg/Tools/SplitFspBin.py | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py > b/IntelFsp2Pkg/Tools/SplitFspBin.py > index bd5507c2fa..ac864492e8 100755 > --- a/IntelFsp2Pkg/Tools/SplitFspBin.py > +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py > @@ -726,7 +726,7 @@ def SplitFspBin (fspfile, outdir, nametemplate): > fspname, ext = > os.path.splitext(os.path.basename(nametemplate)) > filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext) > hfsp = open(filename, 'wb') > - print ("Ceate FSP component file '%s'" % filename) > + print ("Create FSP component file '%s'" % filename) > for fvidx in fsp.FvIdxList: > fv = fd.FvList[fvidx] > hfsp.write(fv.FvData) > -- > 2.19.0.397.gdd90340f6a-goog > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel > > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines 2018-09-18 13:32 [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly Patrick Georgi 2018-09-18 13:32 ` [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin Patrick Georgi @ 2018-09-18 13:32 ` Patrick Georgi 2018-09-18 15:10 ` Desimone, Nathaniel L 2018-09-18 15:03 ` [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly Desimone, Nathaniel L 2 siblings, 1 reply; 13+ messages in thread From: Patrick Georgi @ 2018-09-18 13:32 UTC (permalink / raw) To: edk2-devel; +Cc: Patrick Georgi Signed-off-by: Patrick Georgi <pgeorgi@google.com> Contributed-under: TianoCore Contribution Agreement 1.1 --- IntelFsp2Pkg/Tools/.gitattributes | 1 + IntelFsp2Pkg/Tools/SplitFspBin.py | 1708 ++++++++++++++--------------- 2 files changed, 855 insertions(+), 854 deletions(-) create mode 100644 IntelFsp2Pkg/Tools/.gitattributes diff --git a/IntelFsp2Pkg/Tools/.gitattributes b/IntelFsp2Pkg/Tools/.gitattributes new file mode 100644 index 0000000000..0f876007cd --- /dev/null +++ b/IntelFsp2Pkg/Tools/.gitattributes @@ -0,0 +1 @@ +SplitFspBin.py text diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py b/IntelFsp2Pkg/Tools/SplitFspBin.py index ac864492e8..5f1fab071f 100755 --- a/IntelFsp2Pkg/Tools/SplitFspBin.py +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py @@ -1,854 +1,854 @@ -#!/usr/bin/env python -## @ FspTool.py -# -# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> -# This program and the accompanying materials are licensed and made available under -# the terms and conditions of the BSD License that accompanies this distribution. -# The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php. -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -## - -import os -import sys -import uuid -import copy -import struct -import argparse -from ctypes import * - -""" -This utility supports some operations for Intel FSP 2.0 image. -It supports: - - Display FSP 2.0 information header - - Split FSP 2.0 image into individual FSP-T/M/S/O component - - Rebase FSP 2.0 components to a different base address - - Generate FSP mapping C header file -""" - -CopyRightHeaderFile = """/* - * - * Automatically generated file; DO NOT EDIT. - * FSP mapping file - * - */ -""" - -class c_uint24(Structure): - """Little-Endian 24-bit Unsigned Integer""" - _pack_ = 1 - _fields_ = [('Data', (c_uint8 * 3))] - - 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) - ] - -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 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 type(val) is str: - rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val) - elif type(val) in (int, long): - rep = '0x%X' % val - elif isinstance(val, c_uint24): - rep = '0x%X' % val.get_value() - elif 'c_ubyte_Array' in str(type(val)): - if sizeof(val) == 16: - rep = str(uuid.UUID(bytes = str(bytearray(val)))).upper() - else: - res = ['0x%02X'%i for i in bytearray(val)] - rep = '[%s]' % (','.join(res)) - else: - rep = str(val) - plen -= sizeof(field[1]) - body += pstr.format(key, rep) - if plen <= 0: - break - return body - -class Section: - def __init__(self, offset, secdata): - self.SecHdr = EFI_COMMON_SECTION_HEADER.from_buffer (secdata, 0) - self.SecData = secdata[0:int(self.SecHdr.Size)] - self.Offset = offset - -class FirmwareFile: - def __init__(self, offset, filedata): - self.FfsHdr = EFI_FFS_FILE_HEADER.from_buffer (filedata, 0) - self.FfsData = filedata[0:int(self.FfsHdr.Size)] - self.Offset = offset - self.SecList = [] - - def ParseFfs(self): - ffssize = len(self.FfsData) - offset = sizeof(self.FfsHdr) - if self.FfsHdr.Name != '\xff' * 16: - while offset < ffssize: - sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset) - sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)]) - self.SecList.append(sec) - offset += int(sechdr.Size) - offset = AlignPtr(offset, 4) - -class FirmwareVolume: - def __init__(self, offset, fvdata): - self.FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (fvdata, 0) - self.FvData = fvdata[0 : self.FvHdr.FvLength] - self.Offset = offset - if self.FvHdr.ExtHeaderOffset > 0: - self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset) - else: - 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: - 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: - fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset) - if '_FVH' != fvh.Signature: - raise Exception("ERROR: Invalid FV header !") - fv = FirmwareVolume (offset, self.FdData[offset:offset + fvh.FvLength]) - fv.ParseFv () - self.FvList.append(fv) - offset += fv.FvHdr.FvLength - - def CheckFsp (self): - if len(self.FspList) == 0: - return - - fih = None - for fsp in self.FspList: - if fsp.Fih.HeaderRevision < 3: - raise Exception("ERROR: FSP 1.x is not supported by this tool !") - if not fih: - fih = 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 'FSPH' != fih.Signature: - continue - - offset += fih.HeaderLength - offset = AlignPtr(offset, 4) - plist = [] - while True: - fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset) - if 'FSPP' != fch.Signature: - offset += fch.HeaderLength - offset = AlignPtr(offset, 4) - else: - fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset) - offset += sizeof(fspp) - pdata = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset) - plist = list(pdata) - break - - fsp = FspImage (fspoffset, fih, fihoffset, plist) - fsp.AppendFv (idx) - self.FspList.append(fsp) - flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength - else: - fsp.AppendFv (idx) - flen -= fv.FvHdr.FvLength - if flen < 0: - raise Exception("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 == 'VZ': # TE image - self.TeHdr = tehdr - elif tehdr.Signature == '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: - if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image - 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.PeOptHdr.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 = 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 - 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: - name = str(bytearray(name)) - guid = uuid.UUID(bytes = name) - print ("FV%d:" % idx) - print (" GUID : %s" % str(guid).upper()) - print (" Offset : 0x%08X" % fv.Offset) - print (" Length : 0x%08X" % fv.FvHdr.FvLength) - print ("\n") - - for fsp in fd.FspList: - fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList) - print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist))) - print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength))) - -def GenFspHdr (fspfile, outdir, hfile): - fd = FirmwareDevice(0, fspfile) - fd.ParseFd () - fd.ParseFsp () - - if not hfile: - hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h' - fspname, ext = os.path.splitext(os.path.basename(hfile)) - filename = os.path.join(outdir, fspname + ext) - hfsp = open(filename, 'w') - hfsp.write ('%s\n\n' % CopyRightHeaderFile) - - firstfv = True - for fsp in fd.FspList: - fih = fsp.Fih - if firstfv: - hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId)) - hfsp.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih.ImageRevision) - firstfv = False - fv = fd.FvList[fsp.FvIdxList[0]] - hfsp.write ('#define FSP%s_BASE 0x%08X\n' % (fsp.Type, fih.ImageBase)) - hfsp.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp.Type, fv.Offset)) - hfsp.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp.Type, fih.ImageSize)) - - hfsp.close() - -def SplitFspBin (fspfile, outdir, nametemplate): - fd = FirmwareDevice(0, fspfile) - fd.ParseFd () - fd.ParseFsp () - - for fsp in fd.FspList: - ftype = fsp.Type - if not nametemplate: - nametemplate = fspfile - fspname, ext = os.path.splitext(os.path.basename(nametemplate)) - filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext) - hfsp = open(filename, 'wb') - print ("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: - 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') - - 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: - pass - - return 0 - -if __name__ == '__main__': - sys.exit(main()) +#!/usr/bin/env python +## @ FspTool.py +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +import os +import sys +import uuid +import copy +import struct +import argparse +from ctypes import * + +""" +This utility supports some operations for Intel FSP 2.0 image. +It supports: + - Display FSP 2.0 information header + - Split FSP 2.0 image into individual FSP-T/M/S/O component + - Rebase FSP 2.0 components to a different base address + - Generate FSP mapping C header file +""" + +CopyRightHeaderFile = """/* + * + * Automatically generated file; DO NOT EDIT. + * FSP mapping file + * + */ +""" + +class c_uint24(Structure): + """Little-Endian 24-bit Unsigned Integer""" + _pack_ = 1 + _fields_ = [('Data', (c_uint8 * 3))] + + 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) + ] + +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 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 type(val) is str: + rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val) + elif type(val) in (int, long): + rep = '0x%X' % val + elif isinstance(val, c_uint24): + rep = '0x%X' % val.get_value() + elif 'c_ubyte_Array' in str(type(val)): + if sizeof(val) == 16: + rep = str(uuid.UUID(bytes = str(bytearray(val)))).upper() + else: + res = ['0x%02X'%i for i in bytearray(val)] + rep = '[%s]' % (','.join(res)) + else: + rep = str(val) + plen -= sizeof(field[1]) + body += pstr.format(key, rep) + if plen <= 0: + break + return body + +class Section: + def __init__(self, offset, secdata): + self.SecHdr = EFI_COMMON_SECTION_HEADER.from_buffer (secdata, 0) + self.SecData = secdata[0:int(self.SecHdr.Size)] + self.Offset = offset + +class FirmwareFile: + def __init__(self, offset, filedata): + self.FfsHdr = EFI_FFS_FILE_HEADER.from_buffer (filedata, 0) + self.FfsData = filedata[0:int(self.FfsHdr.Size)] + self.Offset = offset + self.SecList = [] + + def ParseFfs(self): + ffssize = len(self.FfsData) + offset = sizeof(self.FfsHdr) + if self.FfsHdr.Name != '\xff' * 16: + while offset < ffssize: + sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset) + sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)]) + self.SecList.append(sec) + offset += int(sechdr.Size) + offset = AlignPtr(offset, 4) + +class FirmwareVolume: + def __init__(self, offset, fvdata): + self.FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (fvdata, 0) + self.FvData = fvdata[0 : self.FvHdr.FvLength] + self.Offset = offset + if self.FvHdr.ExtHeaderOffset > 0: + self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset) + else: + 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: + 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: + fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset) + if '_FVH' != fvh.Signature: + raise Exception("ERROR: Invalid FV header !") + fv = FirmwareVolume (offset, self.FdData[offset:offset + fvh.FvLength]) + fv.ParseFv () + self.FvList.append(fv) + offset += fv.FvHdr.FvLength + + def CheckFsp (self): + if len(self.FspList) == 0: + return + + fih = None + for fsp in self.FspList: + if fsp.Fih.HeaderRevision < 3: + raise Exception("ERROR: FSP 1.x is not supported by this tool !") + if not fih: + fih = 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 'FSPH' != fih.Signature: + continue + + offset += fih.HeaderLength + offset = AlignPtr(offset, 4) + plist = [] + while True: + fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset) + if 'FSPP' != fch.Signature: + offset += fch.HeaderLength + offset = AlignPtr(offset, 4) + else: + fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset) + offset += sizeof(fspp) + pdata = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset) + plist = list(pdata) + break + + fsp = FspImage (fspoffset, fih, fihoffset, plist) + fsp.AppendFv (idx) + self.FspList.append(fsp) + flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength + else: + fsp.AppendFv (idx) + flen -= fv.FvHdr.FvLength + if flen < 0: + raise Exception("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 == 'VZ': # TE image + self.TeHdr = tehdr + elif tehdr.Signature == '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: + if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image + 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.PeOptHdr.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 = 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 + 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: + name = str(bytearray(name)) + guid = uuid.UUID(bytes = name) + print ("FV%d:" % idx) + print (" GUID : %s" % str(guid).upper()) + print (" Offset : 0x%08X" % fv.Offset) + print (" Length : 0x%08X" % fv.FvHdr.FvLength) + print ("\n") + + for fsp in fd.FspList: + fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList) + print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist))) + print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength))) + +def GenFspHdr (fspfile, outdir, hfile): + fd = FirmwareDevice(0, fspfile) + fd.ParseFd () + fd.ParseFsp () + + if not hfile: + hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h' + fspname, ext = os.path.splitext(os.path.basename(hfile)) + filename = os.path.join(outdir, fspname + ext) + hfsp = open(filename, 'w') + hfsp.write ('%s\n\n' % CopyRightHeaderFile) + + firstfv = True + for fsp in fd.FspList: + fih = fsp.Fih + if firstfv: + hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId)) + hfsp.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih.ImageRevision) + firstfv = False + fv = fd.FvList[fsp.FvIdxList[0]] + hfsp.write ('#define FSP%s_BASE 0x%08X\n' % (fsp.Type, fih.ImageBase)) + hfsp.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp.Type, fv.Offset)) + hfsp.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp.Type, fih.ImageSize)) + + hfsp.close() + +def SplitFspBin (fspfile, outdir, nametemplate): + fd = FirmwareDevice(0, fspfile) + fd.ParseFd () + fd.ParseFsp () + + for fsp in fd.FspList: + ftype = fsp.Type + if not nametemplate: + nametemplate = fspfile + fspname, ext = os.path.splitext(os.path.basename(nametemplate)) + filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext) + hfsp = open(filename, 'wb') + print ("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: + 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') + + 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: + pass + + return 0 + +if __name__ == '__main__': + sys.exit(main()) -- 2.19.0.397.gdd90340f6a-goog ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines 2018-09-18 13:32 ` [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines Patrick Georgi @ 2018-09-18 15:10 ` Desimone, Nathaniel L 2018-09-18 15:53 ` Patrick Georgi 0 siblings, 1 reply; 13+ messages in thread From: Desimone, Nathaniel L @ 2018-09-18 15:10 UTC (permalink / raw) To: Patrick Georgi, edk2-devel@lists.01.org Hi Patrick, The EDK2 coding standard specifies that all files should be in CR-LF format. Please see the following: https://edk2-docs.gitbooks.io/edk-ii-c-coding-standards-specification/content/5_source_files/#51-general-rules Is the .gitattributes file alone sufficient? Thanks, Nate On 9/18/18, 6:32 AM, "edk2-devel on behalf of Patrick Georgi" <edk2-devel-bounces@lists.01.org on behalf of pgeorgi@google.com> wrote: Signed-off-by: Patrick Georgi <pgeorgi@google.com> Contributed-under: TianoCore Contribution Agreement 1.1 --- IntelFsp2Pkg/Tools/.gitattributes | 1 + IntelFsp2Pkg/Tools/SplitFspBin.py | 1708 ++++++++++++++--------------- 2 files changed, 855 insertions(+), 854 deletions(-) create mode 100644 IntelFsp2Pkg/Tools/.gitattributes diff --git a/IntelFsp2Pkg/Tools/.gitattributes b/IntelFsp2Pkg/Tools/.gitattributes new file mode 100644 index 0000000000..0f876007cd --- /dev/null +++ b/IntelFsp2Pkg/Tools/.gitattributes @@ -0,0 +1 @@ +SplitFspBin.py text diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py b/IntelFsp2Pkg/Tools/SplitFspBin.py index ac864492e8..5f1fab071f 100755 --- a/IntelFsp2Pkg/Tools/SplitFspBin.py +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py @@ -1,854 +1,854 @@ -#!/usr/bin/env python -## @ FspTool.py -# -# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> -# This program and the accompanying materials are licensed and made available under -# the terms and conditions of the BSD License that accompanies this distribution. -# The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php. -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -## - -import os -import sys -import uuid -import copy -import struct -import argparse -from ctypes import * - -""" -This utility supports some operations for Intel FSP 2.0 image. -It supports: - - Display FSP 2.0 information header - - Split FSP 2.0 image into individual FSP-T/M/S/O component - - Rebase FSP 2.0 components to a different base address - - Generate FSP mapping C header file -""" - -CopyRightHeaderFile = """/* - * - * Automatically generated file; DO NOT EDIT. - * FSP mapping file - * - */ -""" - -class c_uint24(Structure): - """Little-Endian 24-bit Unsigned Integer""" - _pack_ = 1 - _fields_ = [('Data', (c_uint8 * 3))] - - 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) - ] - -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 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 type(val) is str: - rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val) - elif type(val) in (int, long): - rep = '0x%X' % val - elif isinstance(val, c_uint24): - rep = '0x%X' % val.get_value() - elif 'c_ubyte_Array' in str(type(val)): - if sizeof(val) == 16: - rep = str(uuid.UUID(bytes = str(bytearray(val)))).upper() - else: - res = ['0x%02X'%i for i in bytearray(val)] - rep = '[%s]' % (','.join(res)) - else: - rep = str(val) - plen -= sizeof(field[1]) - body += pstr.format(key, rep) - if plen <= 0: - break - return body - -class Section: - def __init__(self, offset, secdata): - self.SecHdr = EFI_COMMON_SECTION_HEADER.from_buffer (secdata, 0) - self.SecData = secdata[0:int(self.SecHdr.Size)] - self.Offset = offset - -class FirmwareFile: - def __init__(self, offset, filedata): - self.FfsHdr = EFI_FFS_FILE_HEADER.from_buffer (filedata, 0) - self.FfsData = filedata[0:int(self.FfsHdr.Size)] - self.Offset = offset - self.SecList = [] - - def ParseFfs(self): - ffssize = len(self.FfsData) - offset = sizeof(self.FfsHdr) - if self.FfsHdr.Name != '\xff' * 16: - while offset < ffssize: - sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset) - sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)]) - self.SecList.append(sec) - offset += int(sechdr.Size) - offset = AlignPtr(offset, 4) - -class FirmwareVolume: - def __init__(self, offset, fvdata): - self.FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (fvdata, 0) - self.FvData = fvdata[0 : self.FvHdr.FvLength] - self.Offset = offset - if self.FvHdr.ExtHeaderOffset > 0: - self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset) - else: - 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: - 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: - fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset) - if '_FVH' != fvh.Signature: - raise Exception("ERROR: Invalid FV header !") - fv = FirmwareVolume (offset, self.FdData[offset:offset + fvh.FvLength]) - fv.ParseFv () - self.FvList.append(fv) - offset += fv.FvHdr.FvLength - - def CheckFsp (self): - if len(self.FspList) == 0: - return - - fih = None - for fsp in self.FspList: - if fsp.Fih.HeaderRevision < 3: - raise Exception("ERROR: FSP 1.x is not supported by this tool !") - if not fih: - fih = 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 'FSPH' != fih.Signature: - continue - - offset += fih.HeaderLength - offset = AlignPtr(offset, 4) - plist = [] - while True: - fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset) - if 'FSPP' != fch.Signature: - offset += fch.HeaderLength - offset = AlignPtr(offset, 4) - else: - fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset) - offset += sizeof(fspp) - pdata = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset) - plist = list(pdata) - break - - fsp = FspImage (fspoffset, fih, fihoffset, plist) - fsp.AppendFv (idx) - self.FspList.append(fsp) - flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength - else: - fsp.AppendFv (idx) - flen -= fv.FvHdr.FvLength - if flen < 0: - raise Exception("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 == 'VZ': # TE image - self.TeHdr = tehdr - elif tehdr.Signature == '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: - if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image - 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.PeOptHdr.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 = 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 - 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: - name = str(bytearray(name)) - guid = uuid.UUID(bytes = name) - print ("FV%d:" % idx) - print (" GUID : %s" % str(guid).upper()) - print (" Offset : 0x%08X" % fv.Offset) - print (" Length : 0x%08X" % fv.FvHdr.FvLength) - print ("\n") - - for fsp in fd.FspList: - fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList) - print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist))) - print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength))) - -def GenFspHdr (fspfile, outdir, hfile): - fd = FirmwareDevice(0, fspfile) - fd.ParseFd () - fd.ParseFsp () - - if not hfile: - hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h' - fspname, ext = os.path.splitext(os.path.basename(hfile)) - filename = os.path.join(outdir, fspname + ext) - hfsp = open(filename, 'w') - hfsp.write ('%s\n\n' % CopyRightHeaderFile) - - firstfv = True - for fsp in fd.FspList: - fih = fsp.Fih - if firstfv: - hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId)) - hfsp.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih.ImageRevision) - firstfv = False - fv = fd.FvList[fsp.FvIdxList[0]] - hfsp.write ('#define FSP%s_BASE 0x%08X\n' % (fsp.Type, fih.ImageBase)) - hfsp.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp.Type, fv.Offset)) - hfsp.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp.Type, fih.ImageSize)) - - hfsp.close() - -def SplitFspBin (fspfile, outdir, nametemplate): - fd = FirmwareDevice(0, fspfile) - fd.ParseFd () - fd.ParseFsp () - - for fsp in fd.FspList: - ftype = fsp.Type - if not nametemplate: - nametemplate = fspfile - fspname, ext = os.path.splitext(os.path.basename(nametemplate)) - filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext) - hfsp = open(filename, 'wb') - print ("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: - 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') - - 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: - pass - - return 0 - -if __name__ == '__main__': - sys.exit(main()) +#!/usr/bin/env python +## @ FspTool.py +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +import os +import sys +import uuid +import copy +import struct +import argparse +from ctypes import * + +""" +This utility supports some operations for Intel FSP 2.0 image. +It supports: + - Display FSP 2.0 information header + - Split FSP 2.0 image into individual FSP-T/M/S/O component + - Rebase FSP 2.0 components to a different base address + - Generate FSP mapping C header file +""" + +CopyRightHeaderFile = """/* + * + * Automatically generated file; DO NOT EDIT. + * FSP mapping file + * + */ +""" + +class c_uint24(Structure): + """Little-Endian 24-bit Unsigned Integer""" + _pack_ = 1 + _fields_ = [('Data', (c_uint8 * 3))] + + 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) + ] + +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 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 type(val) is str: + rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val) + elif type(val) in (int, long): + rep = '0x%X' % val + elif isinstance(val, c_uint24): + rep = '0x%X' % val.get_value() + elif 'c_ubyte_Array' in str(type(val)): + if sizeof(val) == 16: + rep = str(uuid.UUID(bytes = str(bytearray(val)))).upper() + else: + res = ['0x%02X'%i for i in bytearray(val)] + rep = '[%s]' % (','.join(res)) + else: + rep = str(val) + plen -= sizeof(field[1]) + body += pstr.format(key, rep) + if plen <= 0: + break + return body + +class Section: + def __init__(self, offset, secdata): + self.SecHdr = EFI_COMMON_SECTION_HEADER.from_buffer (secdata, 0) + self.SecData = secdata[0:int(self.SecHdr.Size)] + self.Offset = offset + +class FirmwareFile: + def __init__(self, offset, filedata): + self.FfsHdr = EFI_FFS_FILE_HEADER.from_buffer (filedata, 0) + self.FfsData = filedata[0:int(self.FfsHdr.Size)] + self.Offset = offset + self.SecList = [] + + def ParseFfs(self): + ffssize = len(self.FfsData) + offset = sizeof(self.FfsHdr) + if self.FfsHdr.Name != '\xff' * 16: + while offset < ffssize: + sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset) + sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)]) + self.SecList.append(sec) + offset += int(sechdr.Size) + offset = AlignPtr(offset, 4) + +class FirmwareVolume: + def __init__(self, offset, fvdata): + self.FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (fvdata, 0) + self.FvData = fvdata[0 : self.FvHdr.FvLength] + self.Offset = offset + if self.FvHdr.ExtHeaderOffset > 0: + self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset) + else: + 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: + 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: + fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset) + if '_FVH' != fvh.Signature: + raise Exception("ERROR: Invalid FV header !") + fv = FirmwareVolume (offset, self.FdData[offset:offset + fvh.FvLength]) + fv.ParseFv () + self.FvList.append(fv) + offset += fv.FvHdr.FvLength + + def CheckFsp (self): + if len(self.FspList) == 0: + return + + fih = None + for fsp in self.FspList: + if fsp.Fih.HeaderRevision < 3: + raise Exception("ERROR: FSP 1.x is not supported by this tool !") + if not fih: + fih = 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 'FSPH' != fih.Signature: + continue + + offset += fih.HeaderLength + offset = AlignPtr(offset, 4) + plist = [] + while True: + fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset) + if 'FSPP' != fch.Signature: + offset += fch.HeaderLength + offset = AlignPtr(offset, 4) + else: + fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset) + offset += sizeof(fspp) + pdata = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset) + plist = list(pdata) + break + + fsp = FspImage (fspoffset, fih, fihoffset, plist) + fsp.AppendFv (idx) + self.FspList.append(fsp) + flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength + else: + fsp.AppendFv (idx) + flen -= fv.FvHdr.FvLength + if flen < 0: + raise Exception("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 == 'VZ': # TE image + self.TeHdr = tehdr + elif tehdr.Signature == '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: + if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image + 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.PeOptHdr.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 = 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 + 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: + name = str(bytearray(name)) + guid = uuid.UUID(bytes = name) + print ("FV%d:" % idx) + print (" GUID : %s" % str(guid).upper()) + print (" Offset : 0x%08X" % fv.Offset) + print (" Length : 0x%08X" % fv.FvHdr.FvLength) + print ("\n") + + for fsp in fd.FspList: + fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList) + print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist))) + print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength))) + +def GenFspHdr (fspfile, outdir, hfile): + fd = FirmwareDevice(0, fspfile) + fd.ParseFd () + fd.ParseFsp () + + if not hfile: + hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h' + fspname, ext = os.path.splitext(os.path.basename(hfile)) + filename = os.path.join(outdir, fspname + ext) + hfsp = open(filename, 'w') + hfsp.write ('%s\n\n' % CopyRightHeaderFile) + + firstfv = True + for fsp in fd.FspList: + fih = fsp.Fih + if firstfv: + hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId)) + hfsp.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih.ImageRevision) + firstfv = False + fv = fd.FvList[fsp.FvIdxList[0]] + hfsp.write ('#define FSP%s_BASE 0x%08X\n' % (fsp.Type, fih.ImageBase)) + hfsp.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp.Type, fv.Offset)) + hfsp.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp.Type, fih.ImageSize)) + + hfsp.close() + +def SplitFspBin (fspfile, outdir, nametemplate): + fd = FirmwareDevice(0, fspfile) + fd.ParseFd () + fd.ParseFsp () + + for fsp in fd.FspList: + ftype = fsp.Type + if not nametemplate: + nametemplate = fspfile + fspname, ext = os.path.splitext(os.path.basename(nametemplate)) + filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext) + hfsp = open(filename, 'wb') + print ("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: + 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') + + 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: + pass + + return 0 + +if __name__ == '__main__': + sys.exit(main()) -- 2.19.0.397.gdd90340f6a-goog _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines 2018-09-18 15:10 ` Desimone, Nathaniel L @ 2018-09-18 15:53 ` Patrick Georgi 2018-09-20 4:37 ` Desimone, Nathaniel L 0 siblings, 1 reply; 13+ messages in thread From: Patrick Georgi @ 2018-09-18 15:53 UTC (permalink / raw) To: Desimone, Nathaniel L; +Cc: edk2-devel Am Di., 18. Sep. 2018 um 17:10 Uhr schrieb Desimone, Nathaniel L < nathaniel.l.desimone@intel.com>: > The EDK2 coding standard specifies that all files should be in CR-LF > format. Please see the following: > https://edk2-docs.gitbooks.io/edk-ii-c-coding-standards-specification/content/5_source_files/#51-general-rules Thank you for the pointer! Is the .gitattributes file alone sufficient? > The conversion of the file is for the repo-internal representation (which defaults to LF given git's origin on unix-like systems). According to the docs, due to the "text" property it should still checkout with CRLF on CRLF platforms (as long as core.eol is kept at its default "native" value, otherwise core.eol and core.autocrlf will influence that decision). I don't have such a system around, so my ability to test is limited. The problem with having CRLF in the file on unixoids is that it elicits an error like the following when calling it directly: $ IntelFsp2Pkg/Tools/SplitFspBin.py /usr/bin/env: 'python\r': No such file or directory If the autoconversion is not considered good enough, I'd propose keeping out patch 1 of this series that adds the #! line and the executable bit, and instead expect people to always call the script with "python $path/SplitFspBin.py" to keep confusion at a minimum. Regards, Patrick ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines 2018-09-18 15:53 ` Patrick Georgi @ 2018-09-20 4:37 ` Desimone, Nathaniel L 2018-09-26 3:12 ` Yao, Jiewen 0 siblings, 1 reply; 13+ messages in thread From: Desimone, Nathaniel L @ 2018-09-20 4:37 UTC (permalink / raw) To: Patrick Georgi; +Cc: edk2-devel@lists.01.org Hi Patrick, > If the autoconversion is not considered good enough, I'd propose keeping out patch 1 of this series that adds the #! line and the executable bit, and instead expect people to always call the script with "python $path/SplitFspBin.py" to keep confusion at a minimum. There was quite a debate on this a few years ago. Without getting into the details, the decision was made that people on Windows platforms would set core.autocrlf=false and that source code would be stored in CR-LF format. Per your recommendation, it sounds like we should only merge patch 2 then. Thanks, Nate ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines 2018-09-20 4:37 ` Desimone, Nathaniel L @ 2018-09-26 3:12 ` Yao, Jiewen 2018-09-26 15:58 ` Patrick Georgi 0 siblings, 1 reply; 13+ messages in thread From: Yao, Jiewen @ 2018-09-26 3:12 UTC (permalink / raw) To: Desimone, Nathaniel L, Patrick Georgi; +Cc: edk2-devel@lists.01.org Hi Patrick Do you agree that we only need merge 2/3 and discard 1/3 and 3/3? I will push 2/3 after get your confirmation. Thank you Yao Jiewen > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of > Desimone, Nathaniel L > Sent: Thursday, September 20, 2018 12:38 PM > To: Patrick Georgi <pgeorgi@google.com> > Cc: edk2-devel@lists.01.org > Subject: Re: [edk2] [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py > with native newlines > > Hi Patrick, > > > If the autoconversion is not considered good enough, I'd propose keeping > out patch 1 of this series that adds the #! line and the executable bit, and > instead expect people to always call the script with "python > $path/SplitFspBin.py" to keep confusion at a minimum. > > There was quite a debate on this a few years ago. Without getting into the > details, the decision was made that people on Windows platforms would set > core.autocrlf=false and that source code would be stored in CR-LF format. > Per your recommendation, it sounds like we should only merge patch 2 then. > > Thanks, > Nate > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines 2018-09-26 3:12 ` Yao, Jiewen @ 2018-09-26 15:58 ` Patrick Georgi 2018-09-27 0:40 ` Yao, Jiewen 0 siblings, 1 reply; 13+ messages in thread From: Patrick Georgi @ 2018-09-26 15:58 UTC (permalink / raw) To: jiewen.yao; +Cc: Desimone, Nathaniel L, edk2-devel I'm fine with discarding 1/3 and 3/3. 2/3 was already merged by Chasel Chui (commit 9062ab47870ea728307e32cdd939586a4ec67fc6), so from my point of view, that patch set is taken care of. Thanks, Patrick Am Mi., 26. Sep. 2018 um 05:13 Uhr schrieb Yao, Jiewen <jiewen.yao@intel.com >: > Hi Patrick > Do you agree that we only need merge 2/3 and discard 1/3 and 3/3? > > I will push 2/3 after get your confirmation. > > Thank you > Yao Jiewen > > > -----Original Message----- > > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of > > Desimone, Nathaniel L > > Sent: Thursday, September 20, 2018 12:38 PM > > To: Patrick Georgi <pgeorgi@google.com> > > Cc: edk2-devel@lists.01.org > > Subject: Re: [edk2] [PATCH 3/3] IntelFsp2Pkg: Tell git to format > SplitFspBin.py > > with native newlines > > > > Hi Patrick, > > > > > If the autoconversion is not considered good enough, I'd propose > keeping > > out patch 1 of this series that adds the #! line and the executable bit, > and > > instead expect people to always call the script with "python > > $path/SplitFspBin.py" to keep confusion at a minimum. > > > > There was quite a debate on this a few years ago. Without getting into > the > > details, the decision was made that people on Windows platforms would set > > core.autocrlf=false and that source code would be stored in CR-LF format. > > Per your recommendation, it sounds like we should only merge patch 2 > then. > > > > Thanks, > > Nate > > > > _______________________________________________ > > edk2-devel mailing list > > edk2-devel@lists.01.org > > https://lists.01.org/mailman/listinfo/edk2-devel > -- Google Germany GmbH, ABC-Str. 19, 20354 Hamburg Registergericht und -nummer: Hamburg, HRB 86891, Sitz der Gesellschaft: Hamburg Geschäftsführer: Paul Manicle, Halimah DeLaine Prado ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines 2018-09-26 15:58 ` Patrick Georgi @ 2018-09-27 0:40 ` Yao, Jiewen 0 siblings, 0 replies; 13+ messages in thread From: Yao, Jiewen @ 2018-09-27 0:40 UTC (permalink / raw) To: Patrick Georgi; +Cc: edk2-devel@lists.01.org Good to know. Thanks! > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of > Patrick Georgi > Sent: Wednesday, September 26, 2018 11:59 PM > To: Yao, Jiewen <jiewen.yao@intel.com> > Cc: edk2-devel@lists.01.org > Subject: Re: [edk2] [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py > with native newlines > > I'm fine with discarding 1/3 and 3/3. > 2/3 was already merged by Chasel Chui > (commit 9062ab47870ea728307e32cdd939586a4ec67fc6), so from my point > of > view, that patch set is taken care of. > > > Thanks, > Patrick > > Am Mi., 26. Sep. 2018 um 05:13 Uhr schrieb Yao, Jiewen > <jiewen.yao@intel.com > >: > > > Hi Patrick > > Do you agree that we only need merge 2/3 and discard 1/3 and 3/3? > > > > I will push 2/3 after get your confirmation. > > > > Thank you > > Yao Jiewen > > > > > -----Original Message----- > > > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf > Of > > > Desimone, Nathaniel L > > > Sent: Thursday, September 20, 2018 12:38 PM > > > To: Patrick Georgi <pgeorgi@google.com> > > > Cc: edk2-devel@lists.01.org > > > Subject: Re: [edk2] [PATCH 3/3] IntelFsp2Pkg: Tell git to format > > SplitFspBin.py > > > with native newlines > > > > > > Hi Patrick, > > > > > > > If the autoconversion is not considered good enough, I'd propose > > keeping > > > out patch 1 of this series that adds the #! line and the executable bit, > > and > > > instead expect people to always call the script with "python > > > $path/SplitFspBin.py" to keep confusion at a minimum. > > > > > > There was quite a debate on this a few years ago. Without getting into > > the > > > details, the decision was made that people on Windows platforms would > set > > > core.autocrlf=false and that source code would be stored in CR-LF > format. > > > Per your recommendation, it sounds like we should only merge patch 2 > > then. > > > > > > Thanks, > > > Nate > > > > > > _______________________________________________ > > > edk2-devel mailing list > > > edk2-devel@lists.01.org > > > https://lists.01.org/mailman/listinfo/edk2-devel > > > > > -- > Google Germany GmbH, ABC-Str. 19, 20354 Hamburg > Registergericht und -nummer: Hamburg, HRB 86891, Sitz der Gesellschaft: > Hamburg > Geschäftsführer: Paul Manicle, Halimah DeLaine Prado > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly 2018-09-18 13:32 [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly Patrick Georgi 2018-09-18 13:32 ` [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin Patrick Georgi 2018-09-18 13:32 ` [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines Patrick Georgi @ 2018-09-18 15:03 ` Desimone, Nathaniel L 2 siblings, 0 replies; 13+ messages in thread From: Desimone, Nathaniel L @ 2018-09-18 15:03 UTC (permalink / raw) To: Patrick Georgi, edk2-devel@lists.01.org Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com> On 9/18/18, 6:32 AM, "edk2-devel on behalf of Patrick Georgi" <edk2-devel-bounces@lists.01.org on behalf of pgeorgi@google.com> wrote: Signed-off-by: Patrick Georgi <pgeorgi@google.com> Contributed-under: TianoCore Contribution Agreement 1.1 --- IntelFsp2Pkg/Tools/SplitFspBin.py | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 IntelFsp2Pkg/Tools/SplitFspBin.py diff --git a/IntelFsp2Pkg/Tools/SplitFspBin.py b/IntelFsp2Pkg/Tools/SplitFspBin.py old mode 100644 new mode 100755 index 9b18720307..bd5507c2fa --- a/IntelFsp2Pkg/Tools/SplitFspBin.py +++ b/IntelFsp2Pkg/Tools/SplitFspBin.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python ## @ FspTool.py # # Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> -- 2.19.0.397.gdd90340f6a-goog _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2018-09-27 0:40 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-09-18 13:32 [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly Patrick Georgi 2018-09-18 13:32 ` [PATCH 2/3] IntelFsp2Pkg: Fix typo in SplitFspBin Patrick Georgi 2018-09-18 15:04 ` Desimone, Nathaniel L 2018-09-20 23:28 ` Chiu, Chasel 2018-09-26 3:11 ` Yao, Jiewen 2018-09-18 13:32 ` [PATCH 3/3] IntelFsp2Pkg: Tell git to format SplitFspBin.py with native newlines Patrick Georgi 2018-09-18 15:10 ` Desimone, Nathaniel L 2018-09-18 15:53 ` Patrick Georgi 2018-09-20 4:37 ` Desimone, Nathaniel L 2018-09-26 3:12 ` Yao, Jiewen 2018-09-26 15:58 ` Patrick Georgi 2018-09-27 0:40 ` Yao, Jiewen 2018-09-18 15:03 ` [PATCH 1/3] IntelFsp2Pkg: Allow calling SplitFspBin.py directly Desimone, Nathaniel L
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox