3 # Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>
4 # SPDX-License-Identifier: BSD-2-Clause-Patent
15 from functools
import reduce
18 This utility supports some operations for Intel FSP 1.x/2.x image.
20 - Display FSP 1.x/2.x information header
21 - Split FSP 2.x image into individual FSP-T/M/S/O component
22 - Rebase FSP 1.x/2.x components to a different base address
23 - Generate FSP 1.x/2.x mapping C header file
26 CopyRightHeaderFile
= """/*
28 * Automatically generated file; DO NOT EDIT.
34 class c_uint24(Structure
):
35 """Little-Endian 24-bit Unsigned Integer"""
37 _fields_
= [('Data', (c_uint8
* 3))]
39 def __init__(self
, val
=0):
42 def __str__(self
, indent
=0):
43 return '0x%.6x' % self
.value
46 return self
.get_value()
48 def set_value(self
, val
):
49 self
.Data
[0:3] = Val2Bytes(val
, 3)
52 return Bytes2Val(self
.Data
[0:3])
54 value
= property(get_value
, set_value
)
56 class EFI_FIRMWARE_VOLUME_HEADER(Structure
):
58 ('ZeroVector', ARRAY(c_uint8
, 16)),
59 ('FileSystemGuid', ARRAY(c_uint8
, 16)),
60 ('FvLength', c_uint64
),
61 ('Signature', ARRAY(c_char
, 4)),
62 ('Attributes', c_uint32
),
63 ('HeaderLength', c_uint16
),
64 ('Checksum', c_uint16
),
65 ('ExtHeaderOffset', c_uint16
),
66 ('Reserved', c_uint8
),
70 class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure
):
72 ('FvName', ARRAY(c_uint8
, 16)),
73 ('ExtHeaderSize', c_uint32
)
76 class EFI_FFS_INTEGRITY_CHECK(Structure
):
82 class EFI_FFS_FILE_HEADER(Structure
):
84 ('Name', ARRAY(c_uint8
, 16)),
85 ('IntegrityCheck', EFI_FFS_INTEGRITY_CHECK
),
87 ('Attributes', c_uint8
),
92 class EFI_COMMON_SECTION_HEADER(Structure
):
98 class FSP_COMMON_HEADER(Structure
):
100 ('Signature', ARRAY(c_char
, 4)),
101 ('HeaderLength', c_uint32
)
104 class FSP_INFORMATION_HEADER(Structure
):
106 ('Signature', ARRAY(c_char
, 4)),
107 ('HeaderLength', c_uint32
),
108 ('Reserved1', c_uint16
),
109 ('SpecVersion', c_uint8
),
110 ('HeaderRevision', c_uint8
),
111 ('ImageRevision', c_uint32
),
112 ('ImageId', ARRAY(c_char
, 8)),
113 ('ImageSize', c_uint32
),
114 ('ImageBase', c_uint32
),
115 ('ImageAttribute', c_uint16
),
116 ('ComponentAttribute', c_uint16
),
117 ('CfgRegionOffset', c_uint32
),
118 ('CfgRegionSize', c_uint32
),
119 ('Reserved2', c_uint32
),
120 ('TempRamInitEntryOffset', c_uint32
),
121 ('Reserved3', c_uint32
),
122 ('NotifyPhaseEntryOffset', c_uint32
),
123 ('FspMemoryInitEntryOffset', c_uint32
),
124 ('TempRamExitEntryOffset', c_uint32
),
125 ('FspSiliconInitEntryOffset', c_uint32
)
128 class FSP_PATCH_TABLE(Structure
):
130 ('Signature', ARRAY(c_char
, 4)),
131 ('HeaderLength', c_uint16
),
132 ('HeaderRevision', c_uint8
),
133 ('Reserved', c_uint8
),
134 ('PatchEntryNum', c_uint32
)
137 class EFI_IMAGE_DATA_DIRECTORY(Structure
):
139 ('VirtualAddress', c_uint32
),
143 class EFI_TE_IMAGE_HEADER(Structure
):
145 ('Signature', ARRAY(c_char
, 2)),
146 ('Machine', c_uint16
),
147 ('NumberOfSections', c_uint8
),
148 ('Subsystem', c_uint8
),
149 ('StrippedSize', c_uint16
),
150 ('AddressOfEntryPoint', c_uint32
),
151 ('BaseOfCode', c_uint32
),
152 ('ImageBase', c_uint64
),
153 ('DataDirectoryBaseReloc', EFI_IMAGE_DATA_DIRECTORY
),
154 ('DataDirectoryDebug', EFI_IMAGE_DATA_DIRECTORY
)
157 class EFI_IMAGE_DOS_HEADER(Structure
):
159 ('e_magic', c_uint16
),
160 ('e_cblp', c_uint16
),
162 ('e_crlc', c_uint16
),
163 ('e_cparhdr', c_uint16
),
164 ('e_minalloc', c_uint16
),
165 ('e_maxalloc', c_uint16
),
168 ('e_csum', c_uint16
),
171 ('e_lfarlc', c_uint16
),
172 ('e_ovno', c_uint16
),
173 ('e_res', ARRAY(c_uint16
, 4)),
174 ('e_oemid', c_uint16
),
175 ('e_oeminfo', c_uint16
),
176 ('e_res2', ARRAY(c_uint16
, 10)),
177 ('e_lfanew', c_uint16
)
180 class EFI_IMAGE_FILE_HEADER(Structure
):
182 ('Machine', c_uint16
),
183 ('NumberOfSections', c_uint16
),
184 ('TimeDateStamp', c_uint32
),
185 ('PointerToSymbolTable', c_uint32
),
186 ('NumberOfSymbols', c_uint32
),
187 ('SizeOfOptionalHeader', c_uint16
),
188 ('Characteristics', c_uint16
)
191 class PE_RELOC_BLOCK_HEADER(Structure
):
193 ('PageRVA', c_uint32
),
194 ('BlockSize', c_uint32
)
197 class EFI_IMAGE_OPTIONAL_HEADER32(Structure
):
200 ('MajorLinkerVersion', c_uint8
),
201 ('MinorLinkerVersion', c_uint8
),
202 ('SizeOfCode', c_uint32
),
203 ('SizeOfInitializedData', c_uint32
),
204 ('SizeOfUninitializedData', c_uint32
),
205 ('AddressOfEntryPoint', c_uint32
),
206 ('BaseOfCode', c_uint32
),
207 ('BaseOfData', c_uint32
),
208 ('ImageBase', c_uint32
),
209 ('SectionAlignment', c_uint32
),
210 ('FileAlignment', c_uint32
),
211 ('MajorOperatingSystemVersion', c_uint16
),
212 ('MinorOperatingSystemVersion', c_uint16
),
213 ('MajorImageVersion', c_uint16
),
214 ('MinorImageVersion', c_uint16
),
215 ('MajorSubsystemVersion', c_uint16
),
216 ('MinorSubsystemVersion', c_uint16
),
217 ('Win32VersionValue', c_uint32
),
218 ('SizeOfImage', c_uint32
),
219 ('SizeOfHeaders', c_uint32
),
220 ('CheckSum' , c_uint32
),
221 ('Subsystem', c_uint16
),
222 ('DllCharacteristics', c_uint16
),
223 ('SizeOfStackReserve', c_uint32
),
224 ('SizeOfStackCommit' , c_uint32
),
225 ('SizeOfHeapReserve', c_uint32
),
226 ('SizeOfHeapCommit' , c_uint32
),
227 ('LoaderFlags' , c_uint32
),
228 ('NumberOfRvaAndSizes', c_uint32
),
229 ('DataDirectory', ARRAY(EFI_IMAGE_DATA_DIRECTORY
, 16))
232 class EFI_IMAGE_OPTIONAL_HEADER32_PLUS(Structure
):
235 ('MajorLinkerVersion', c_uint8
),
236 ('MinorLinkerVersion', c_uint8
),
237 ('SizeOfCode', c_uint32
),
238 ('SizeOfInitializedData', c_uint32
),
239 ('SizeOfUninitializedData', c_uint32
),
240 ('AddressOfEntryPoint', c_uint32
),
241 ('BaseOfCode', c_uint32
),
242 ('ImageBase', c_uint64
),
243 ('SectionAlignment', c_uint32
),
244 ('FileAlignment', c_uint32
),
245 ('MajorOperatingSystemVersion', c_uint16
),
246 ('MinorOperatingSystemVersion', c_uint16
),
247 ('MajorImageVersion', c_uint16
),
248 ('MinorImageVersion', c_uint16
),
249 ('MajorSubsystemVersion', c_uint16
),
250 ('MinorSubsystemVersion', c_uint16
),
251 ('Win32VersionValue', c_uint32
),
252 ('SizeOfImage', c_uint32
),
253 ('SizeOfHeaders', c_uint32
),
254 ('CheckSum' , c_uint32
),
255 ('Subsystem', c_uint16
),
256 ('DllCharacteristics', c_uint16
),
257 ('SizeOfStackReserve', c_uint64
),
258 ('SizeOfStackCommit' , c_uint64
),
259 ('SizeOfHeapReserve', c_uint64
),
260 ('SizeOfHeapCommit' , c_uint64
),
261 ('LoaderFlags' , c_uint32
),
262 ('NumberOfRvaAndSizes', c_uint32
),
263 ('DataDirectory', ARRAY(EFI_IMAGE_DATA_DIRECTORY
, 16))
266 class EFI_IMAGE_OPTIONAL_HEADER(Union
):
268 ('PeOptHdr', EFI_IMAGE_OPTIONAL_HEADER32
),
269 ('PePlusOptHdr', EFI_IMAGE_OPTIONAL_HEADER32_PLUS
)
272 class EFI_IMAGE_NT_HEADERS32(Structure
):
274 ('Signature', c_uint32
),
275 ('FileHeader', EFI_IMAGE_FILE_HEADER
),
276 ('OptionalHeader', EFI_IMAGE_OPTIONAL_HEADER
)
280 class EFI_IMAGE_DIRECTORY_ENTRY
:
293 class EFI_FV_FILETYPE
:
302 COMBINED_PEIM_DRIVER
= 0x08
305 FIRMWARE_VOLUME_IMAGE
= 0x0b
306 COMBINED_SMM_DXE
= 0x0c
316 class EFI_SECTION_TYPE
:
317 """Enumeration of all valid firmware file section types."""
327 USER_INTERFACE
= 0x15
328 COMPATIBILITY16
= 0x16
329 FIRMWARE_VOLUME_IMAGE
= 0x17
330 FREEFORM_SUBTYPE_GUID
= 0x18
335 def AlignPtr (offset
, alignment
= 8):
336 return (offset
+ alignment
- 1) & ~
(alignment
- 1)
338 def Bytes2Val (bytes
):
339 return reduce(lambda x
,y
: (x
<<8)|y
, bytes
[::-1] )
341 def Val2Bytes (value
, blen
):
342 return [(value
>>(i
*8) & 0xff) for i
in range(blen
)]
344 def IsIntegerType (val
):
345 if sys
.version_info
[0] < 3:
346 if type(val
) in (int, long):
354 if sys
.version_info
[0] < 3:
358 if type(val
) is bytes
:
362 def HandleNameStr (val
):
363 if sys
.version_info
[0] < 3:
364 rep
= "0x%X ('%s')" % (Bytes2Val (bytearray (val
)), val
)
366 rep
= "0x%X ('%s')" % (Bytes2Val (bytearray (val
)), str (val
, 'utf-8'))
369 def OutputStruct (obj
, indent
= 0, plen
= 0):
373 body
= (' ' * indent
+ '<%s>:\n') % obj
.__class
__.__name
__
379 pstr
= (' ' * (indent
+ 1) + '{0:<%d} = {1}\n') % max_key_len
381 for field
in obj
._fields
_:
383 val
= getattr(obj
, key
)
385 if not isinstance(val
, c_uint24
) and isinstance(val
, Structure
):
386 body
+= pstr
.format(key
, val
.__class
__.__name
__)
387 body
+= OutputStruct (val
, indent
+ 1)
391 rep
= HandleNameStr (val
)
392 elif IsIntegerType (val
):
394 elif isinstance(val
, c_uint24
):
395 rep
= '0x%X' % val
.get_value()
396 elif 'c_ubyte_Array' in str(type(val
)):
397 if sizeof(val
) == 16:
398 if sys
.version_info
[0] < 3:
399 rep
= str(bytearray(val
))
402 rep
= str(uuid
.UUID(bytes_le
= rep
)).upper()
404 res
= ['0x%02X'%i for i
in bytearray(val
)]
405 rep
= '[%s]' % (','.join(res
))
408 plen
-= sizeof(field
[1])
409 body
+= pstr
.format(key
, rep
)
415 def __init__(self
, offset
, secdata
):
416 self
.SecHdr
= EFI_COMMON_SECTION_HEADER
.from_buffer (secdata
, 0)
417 self
.SecData
= secdata
[0:int(self
.SecHdr
.Size
)]
421 def __init__(self
, offset
, filedata
):
422 self
.FfsHdr
= EFI_FFS_FILE_HEADER
.from_buffer (filedata
, 0)
423 self
.FfsData
= filedata
[0:int(self
.FfsHdr
.Size
)]
428 ffssize
= len(self
.FfsData
)
429 offset
= sizeof(self
.FfsHdr
)
430 if self
.FfsHdr
.Name
!= '\xff' * 16:
431 while offset
< (ffssize
- sizeof (EFI_COMMON_SECTION_HEADER
)):
432 sechdr
= EFI_COMMON_SECTION_HEADER
.from_buffer (self
.FfsData
, offset
)
433 sec
= Section (offset
, self
.FfsData
[offset
:offset
+ int(sechdr
.Size
)])
434 self
.SecList
.append(sec
)
435 offset
+= int(sechdr
.Size
)
436 offset
= AlignPtr(offset
, 4)
438 class FirmwareVolume
:
439 def __init__(self
, offset
, fvdata
):
440 self
.FvHdr
= EFI_FIRMWARE_VOLUME_HEADER
.from_buffer (fvdata
, 0)
441 self
.FvData
= fvdata
[0 : self
.FvHdr
.FvLength
]
443 if self
.FvHdr
.ExtHeaderOffset
> 0:
444 self
.FvExtHdr
= EFI_FIRMWARE_VOLUME_EXT_HEADER
.from_buffer (self
.FvData
, self
.FvHdr
.ExtHeaderOffset
)
450 fvsize
= len(self
.FvData
)
452 offset
= self
.FvHdr
.ExtHeaderOffset
+ self
.FvExtHdr
.ExtHeaderSize
454 offset
= self
.FvHdr
.HeaderLength
455 offset
= AlignPtr(offset
)
456 while offset
< (fvsize
- sizeof (EFI_FFS_FILE_HEADER
)):
457 ffshdr
= EFI_FFS_FILE_HEADER
.from_buffer (self
.FvData
, offset
)
458 if (ffshdr
.Name
== '\xff' * 16) and (int(ffshdr
.Size
) == 0xFFFFFF):
461 ffs
= FirmwareFile (offset
, self
.FvData
[offset
:offset
+ int(ffshdr
.Size
)])
463 self
.FfsList
.append(ffs
)
464 offset
+= int(ffshdr
.Size
)
465 offset
= AlignPtr(offset
)
468 def __init__(self
, offset
, fih
, fihoff
, patch
):
470 self
.FihOffset
= fihoff
473 self
.Type
= "XTMSXXXXOXXXXXXX"[(fih
.ComponentAttribute
>> 12) & 0x0F]
474 self
.PatchList
= patch
475 self
.PatchList
.append(fihoff
+ 0x1C)
477 def AppendFv(self
, FvIdx
):
478 self
.FvIdxList
.append(FvIdx
)
480 def Patch(self
, delta
, fdbin
):
483 for idx
, patch
in enumerate(self
.PatchList
):
484 ptype
= (patch
>>24) & 0x0F
485 if ptype
not in [0x00, 0x0F]:
486 raise Exception('ERROR: Invalid patch type %d !' % ptype
)
487 if patch
& 0x80000000:
488 patch
= self
.Fih
.ImageSize
- (0x1000000 - (patch
& 0xFFFFFF))
490 patch
= patch
& 0xFFFFFF
491 if (patch
< self
.Fih
.ImageSize
) and (patch
+ sizeof(c_uint32
) <= self
.Fih
.ImageSize
):
492 offset
= patch
+ self
.Offset
493 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint32
)])
495 fdbin
[offset
:offset
+sizeof(c_uint32
)] = Val2Bytes(value
, sizeof(c_uint32
))
498 # Don't count the FSP base address patch entry appended at the end
502 return (count
, applied
)
504 class FirmwareDevice
:
505 def __init__(self
, offset
, fdfile
):
510 hfsp
= open (self
.FdFile
, 'rb')
511 self
.FdData
= bytearray(hfsp
.read())
516 fdsize
= len(self
.FdData
)
518 while offset
< (fdsize
- sizeof (EFI_FIRMWARE_VOLUME_HEADER
)):
519 fvh
= EFI_FIRMWARE_VOLUME_HEADER
.from_buffer (self
.FdData
, offset
)
520 if b
'_FVH' != fvh
.Signature
:
521 raise Exception("ERROR: Invalid FV header !")
522 fv
= FirmwareVolume (offset
, self
.FdData
[offset
:offset
+ fvh
.FvLength
])
524 self
.FvList
.append(fv
)
525 offset
+= fv
.FvHdr
.FvLength
528 if len(self
.FspList
) == 0:
532 for fsp
in self
.FspList
:
537 if (newfih
.ImageId
!= fih
.ImageId
) or (newfih
.ImageRevision
!= fih
.ImageRevision
):
538 raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
542 for idx
, fv
in enumerate(self
.FvList
):
543 # Check if this FV contains FSP header
545 if len(fv
.FfsList
) == 0:
548 if len(ffs
.SecList
) == 0:
551 if sec
.SecHdr
.Type
!= EFI_SECTION_TYPE
.RAW
:
553 fihoffset
= ffs
.Offset
+ sec
.Offset
+ sizeof(sec
.SecHdr
)
554 fspoffset
= fv
.Offset
555 offset
= fspoffset
+ fihoffset
556 fih
= FSP_INFORMATION_HEADER
.from_buffer (self
.FdData
, offset
)
557 if b
'FSPH' != fih
.Signature
:
560 offset
+= fih
.HeaderLength
561 offset
= AlignPtr(offset
, 4)
564 fch
= FSP_COMMON_HEADER
.from_buffer (self
.FdData
, offset
)
565 if b
'FSPP' != fch
.Signature
:
566 offset
+= fch
.HeaderLength
567 offset
= AlignPtr(offset
, 4)
569 fspp
= FSP_PATCH_TABLE
.from_buffer (self
.FdData
, offset
)
570 offset
+= sizeof(fspp
)
571 pdata
= (c_uint32
* fspp
.PatchEntryNum
).from_buffer(self
.FdData
, offset
)
575 fsp
= FspImage (fspoffset
, fih
, fihoffset
, plist
)
577 self
.FspList
.append(fsp
)
578 flen
= fsp
.Fih
.ImageSize
- fv
.FvHdr
.FvLength
581 flen
-= fv
.FvHdr
.FvLength
583 raise Exception("ERROR: Incorrect FV size in image !")
587 def __init__(self
, offset
, data
):
589 tehdr
= EFI_TE_IMAGE_HEADER
.from_buffer (data
, 0)
590 if tehdr
.Signature
== b
'VZ': # TE image
592 elif tehdr
.Signature
== b
'MZ': # PE image
594 self
.DosHdr
= EFI_IMAGE_DOS_HEADER
.from_buffer (data
, 0)
595 self
.PeHdr
= EFI_IMAGE_NT_HEADERS32
.from_buffer (data
, self
.DosHdr
.e_lfanew
)
596 if self
.PeHdr
.Signature
!= 0x4550:
597 raise Exception("ERROR: Invalid PE32 header !")
598 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x10b: # PE32 image
599 if self
.PeHdr
.FileHeader
.SizeOfOptionalHeader
< EFI_IMAGE_OPTIONAL_HEADER32
.DataDirectory
.offset
:
600 raise Exception("ERROR: Unsupported PE32 image !")
601 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
:
602 raise Exception("ERROR: No relocation information available !")
603 elif self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x20b: # PE32+ image
604 if self
.PeHdr
.FileHeader
.SizeOfOptionalHeader
< EFI_IMAGE_OPTIONAL_HEADER32_PLUS
.DataDirectory
.offset
:
605 raise Exception("ERROR: Unsupported PE32+ image !")
606 if self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
:
607 raise Exception("ERROR: No relocation information available !")
609 raise Exception("ERROR: Invalid PE32 optional header !")
615 return self
.TeHdr
is not None
617 def ParseReloc(self
):
619 rsize
= self
.TeHdr
.DataDirectoryBaseReloc
.Size
620 roffset
= sizeof(self
.TeHdr
) - self
.TeHdr
.StrippedSize
+ self
.TeHdr
.DataDirectoryBaseReloc
.VirtualAddress
622 # Assuming PE32 image type (self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b)
623 rsize
= self
.PeHdr
.OptionalHeader
.PeOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].Size
624 roffset
= self
.PeHdr
.OptionalHeader
.PeOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].VirtualAddress
625 if self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.Magic
== 0x20b: # PE32+ image
626 rsize
= self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].Size
627 roffset
= self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].VirtualAddress
631 while offset
< roffset
+ rsize
:
632 offset
= AlignPtr(offset
, 4)
633 blkhdr
= PE_RELOC_BLOCK_HEADER
.from_buffer(self
.Data
, offset
)
634 offset
+= sizeof(blkhdr
)
635 # Read relocation type,offset pairs
636 rlen
= blkhdr
.BlockSize
- sizeof(PE_RELOC_BLOCK_HEADER
)
637 rnum
= int (rlen
/sizeof(c_uint16
))
638 rdata
= (c_uint16
* rnum
).from_buffer(self
.Data
, offset
)
642 if rtype
== 0: # IMAGE_REL_BASED_ABSOLUTE:
644 if ((rtype
!= 3) and (rtype
!= 10)): # IMAGE_REL_BASED_HIGHLOW and IMAGE_REL_BASED_DIR64
645 raise Exception("ERROR: Unsupported relocation type %d!" % rtype
)
646 # Calculate the offset of the relocation
647 aoff
= blkhdr
.PageRVA
+ roff
649 aoff
+= sizeof(self
.TeHdr
) - self
.TeHdr
.StrippedSize
650 self
.RelocList
.append((rtype
, aoff
))
651 offset
+= sizeof(rdata
)
653 def Rebase(self
, delta
, fdbin
):
658 for (rtype
, roff
) in self
.RelocList
:
659 if rtype
== 3: # IMAGE_REL_BASED_HIGHLOW
660 offset
= roff
+ self
.Offset
661 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint32
)])
663 fdbin
[offset
:offset
+sizeof(c_uint32
)] = Val2Bytes(value
, sizeof(c_uint32
))
665 elif rtype
== 10: # IMAGE_REL_BASED_DIR64
666 offset
= roff
+ self
.Offset
667 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint64
)])
669 fdbin
[offset
:offset
+sizeof(c_uint64
)] = Val2Bytes(value
, sizeof(c_uint64
))
672 raise Exception('ERROR: Unknown relocation type %d !' % rtype
)
675 offset
= self
.Offset
+ EFI_TE_IMAGE_HEADER
.ImageBase
.offset
676 size
= EFI_TE_IMAGE_HEADER
.ImageBase
.size
678 offset
= self
.Offset
+ self
.DosHdr
.e_lfanew
679 offset
+= EFI_IMAGE_NT_HEADERS32
.OptionalHeader
.offset
680 offset
+= EFI_IMAGE_OPTIONAL_HEADER32
.ImageBase
.offset
681 size
= EFI_IMAGE_OPTIONAL_HEADER32
.ImageBase
.size
683 value
= Bytes2Val(fdbin
[offset
:offset
+size
]) + delta
684 fdbin
[offset
:offset
+size
] = Val2Bytes(value
, size
)
688 def ShowFspInfo (fspfile
):
689 fd
= FirmwareDevice(0, fspfile
)
693 print ("\nFound the following %d Firmware Volumes in FSP binary:" % (len(fd
.FvList
)))
694 for idx
, fv
in enumerate(fd
.FvList
):
695 name
= fv
.FvExtHdr
.FvName
699 if sys
.version_info
[0] < 3:
700 name
= str(bytearray(name
))
703 guid
= uuid
.UUID(bytes_le
= name
)
704 print ("FV%d:" % idx
)
705 print (" GUID : %s" % str(guid
).upper())
706 print (" Offset : 0x%08X" % fv
.Offset
)
707 print (" Length : 0x%08X" % fv
.FvHdr
.FvLength
)
710 for fsp
in fd
.FspList
:
711 fvlist
= map(lambda x
: 'FV%d' % x
, fsp
.FvIdxList
)
712 print ("FSP_%s contains %s" % (fsp
.Type
, ','.join(fvlist
)))
713 print ("%s" % (OutputStruct(fsp
.Fih
, 0, fsp
.Fih
.HeaderLength
)))
715 def GenFspHdr (fspfile
, outdir
, hfile
):
716 fd
= FirmwareDevice(0, fspfile
)
721 hfile
= os
.path
.splitext(os
.path
.basename(fspfile
))[0] + '.h'
722 fspname
, ext
= os
.path
.splitext(os
.path
.basename(hfile
))
723 filename
= os
.path
.join(outdir
, fspname
+ ext
)
724 hfsp
= open(filename
, 'w')
725 hfsp
.write ('%s\n\n' % CopyRightHeaderFile
)
728 for fsp
in fd
.FspList
:
731 if sys
.version_info
[0] < 3:
732 hfsp
.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih
.ImageId
)), fih
.ImageId
))
734 hfsp
.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih
.ImageId
)), str (fih
.ImageId
, 'utf-8')))
735 hfsp
.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih
.ImageRevision
)
737 fv
= fd
.FvList
[fsp
.FvIdxList
[0]]
738 hfsp
.write ('#define FSP%s_BASE 0x%08X\n' % (fsp
.Type
, fih
.ImageBase
))
739 hfsp
.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp
.Type
, fv
.Offset
))
740 hfsp
.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp
.Type
, fih
.ImageSize
))
744 def SplitFspBin (fspfile
, outdir
, nametemplate
):
745 fd
= FirmwareDevice(0, fspfile
)
749 for fsp
in fd
.FspList
:
750 if fsp
.Fih
.HeaderRevision
< 3:
751 raise Exception("ERROR: FSP 1.x is not supported by the split command !")
754 nametemplate
= fspfile
755 fspname
, ext
= os
.path
.splitext(os
.path
.basename(nametemplate
))
756 filename
= os
.path
.join(outdir
, fspname
+ '_' + fsp
.Type
+ ext
)
757 hfsp
= open(filename
, 'wb')
758 print ("Create FSP component file '%s'" % filename
)
759 for fvidx
in fsp
.FvIdxList
:
760 fv
= fd
.FvList
[fvidx
]
761 hfsp
.write(fv
.FvData
)
764 def RebaseFspBin (FspBinary
, FspComponent
, FspBase
, OutputDir
, OutputFile
):
765 fd
= FirmwareDevice(0, FspBinary
)
769 numcomp
= len(FspComponent
)
771 if numcomp
!= len(baselist
):
772 print ("ERROR: Required number of base does not match number of FSP component !")
775 newfspbin
= fd
.FdData
[:]
777 for idx
, fspcomp
in enumerate(FspComponent
):
780 for fsp
in fd
.FspList
:
781 # Is this FSP 1.x single binary?
782 if fsp
.Fih
.HeaderRevision
< 3:
786 ftype
= fsp
.Type
.lower()
792 print ("ERROR: Could not find FSP_%c component to rebase !" % fspcomp
.upper())
795 fspbase
= baselist
[idx
]
796 if fspbase
.startswith('0x'):
797 newbase
= int(fspbase
, 16)
799 newbase
= int(fspbase
)
800 oldbase
= fsp
.Fih
.ImageBase
801 delta
= newbase
- oldbase
802 print ("Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype
.upper(),oldbase
,newbase
))
805 for fvidx
in fsp
.FvIdxList
:
806 fv
= fd
.FvList
[fvidx
]
807 for ffs
in fv
.FfsList
:
808 for sec
in ffs
.SecList
:
809 if sec
.SecHdr
.Type
in [EFI_SECTION_TYPE
.TE
, EFI_SECTION_TYPE
.PE32
]: # TE or PE32
810 offset
= fd
.Offset
+ fv
.Offset
+ ffs
.Offset
+ sec
.Offset
+ sizeof(sec
.SecHdr
)
811 imglist
.append ((offset
, len(sec
.SecData
) - sizeof(sec
.SecHdr
)))
815 for (offset
, length
) in imglist
:
816 img
= PeTeImage(offset
, fd
.FdData
[offset
:offset
+ length
])
818 pcount
+= img
.Rebase(delta
, newfspbin
)
821 print (" Patched %d entries in %d TE/PE32 images." % (pcount
, fcount
))
823 (count
, applied
) = fsp
.Patch(delta
, newfspbin
)
824 print (" Patched %d entries using FSP patch table." % applied
)
826 print (" %d invalid entries are ignored !" % (count
- applied
))
829 filename
= os
.path
.basename(FspBinary
)
830 base
, ext
= os
.path
.splitext(filename
)
831 OutputFile
= base
+ "_%08X" % newbase
+ ext
833 fspname
, ext
= os
.path
.splitext(os
.path
.basename(OutputFile
))
834 filename
= os
.path
.join(OutputDir
, fspname
+ ext
)
835 fd
= open(filename
, "wb")
840 parser
= argparse
.ArgumentParser()
841 subparsers
= parser
.add_subparsers(title
='commands', dest
="which")
843 parser_rebase
= subparsers
.add_parser('rebase', help='rebase a FSP into a new base address')
844 parser_rebase
.set_defaults(which
='rebase')
845 parser_rebase
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
846 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)
847 parser_rebase
.add_argument('-b', '--newbase', dest
='FspBase', nargs
='+', type=str, help='Rebased FSP binary file name', default
= '', required
= True)
848 parser_rebase
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
849 parser_rebase
.add_argument('-n', '--outfile', dest
='OutputFile', type=str, help='Rebased FSP binary file name', default
= '')
851 parser_split
= subparsers
.add_parser('split', help='split a FSP into multiple components')
852 parser_split
.set_defaults(which
='split')
853 parser_split
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
854 parser_split
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
855 parser_split
.add_argument('-n', '--nametpl', dest
='NameTemplate', type=str, help='Output name template', default
= '')
857 parser_genhdr
= subparsers
.add_parser('genhdr', help='generate a header file for FSP binary')
858 parser_genhdr
.set_defaults(which
='genhdr')
859 parser_genhdr
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
860 parser_genhdr
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
861 parser_genhdr
.add_argument('-n', '--hfile', dest
='HFileName', type=str, help='Output header file name', default
= '')
863 parser_info
= subparsers
.add_parser('info', help='display FSP information')
864 parser_info
.set_defaults(which
='info')
865 parser_info
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
867 args
= parser
.parse_args()
868 if args
.which
in ['rebase', 'split', 'genhdr', 'info']:
869 if not os
.path
.exists(args
.FspBinary
):
870 raise Exception ("ERROR: Could not locate FSP binary file '%s' !" % args
.FspBinary
)
871 if hasattr(args
, 'OutputDir') and not os
.path
.exists(args
.OutputDir
):
872 raise Exception ("ERROR: Invalid output directory '%s' !" % args
.OutputDir
)
874 if args
.which
== 'rebase':
875 RebaseFspBin (args
.FspBinary
, args
.FspComponent
, args
.FspBase
, args
.OutputDir
, args
.OutputFile
)
876 elif args
.which
== 'split':
877 SplitFspBin (args
.FspBinary
, args
.OutputDir
, args
.NameTemplate
)
878 elif args
.which
== 'genhdr':
879 GenFspHdr (args
.FspBinary
, args
.OutputDir
, args
.HFileName
)
880 elif args
.which
== 'info':
881 ShowFspInfo (args
.FspBinary
)
887 if __name__
== '__main__':