3 # Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
4 # SPDX-License-Identifier: BSD-2-Clause-Patent
17 This utility supports some operations for Intel FSP 1.x/2.x image.
19 - Display FSP 1.x/2.x information header
20 - Split FSP 2.x image into individual FSP-T/M/S/O component
21 - Rebase FSP 1.x/2.x components to a different base address
22 - Generate FSP 1.x/2.x mapping C header file
25 CopyRightHeaderFile
= """/*
27 * Automatically generated file; DO NOT EDIT.
33 class c_uint24(Structure
):
34 """Little-Endian 24-bit Unsigned Integer"""
36 _fields_
= [('Data', (c_uint8
* 3))]
38 def __init__(self
, val
=0):
41 def __str__(self
, indent
=0):
42 return '0x%.6x' % self
.value
45 return self
.get_value()
47 def set_value(self
, val
):
48 self
.Data
[0:3] = Val2Bytes(val
, 3)
51 return Bytes2Val(self
.Data
[0:3])
53 value
= property(get_value
, set_value
)
55 class EFI_FIRMWARE_VOLUME_HEADER(Structure
):
57 ('ZeroVector', ARRAY(c_uint8
, 16)),
58 ('FileSystemGuid', ARRAY(c_uint8
, 16)),
59 ('FvLength', c_uint64
),
60 ('Signature', ARRAY(c_char
, 4)),
61 ('Attributes', c_uint32
),
62 ('HeaderLength', c_uint16
),
63 ('Checksum', c_uint16
),
64 ('ExtHeaderOffset', c_uint16
),
65 ('Reserved', c_uint8
),
69 class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure
):
71 ('FvName', ARRAY(c_uint8
, 16)),
72 ('ExtHeaderSize', c_uint32
)
75 class EFI_FFS_INTEGRITY_CHECK(Structure
):
81 class EFI_FFS_FILE_HEADER(Structure
):
83 ('Name', ARRAY(c_uint8
, 16)),
84 ('IntegrityCheck', EFI_FFS_INTEGRITY_CHECK
),
86 ('Attributes', c_uint8
),
91 class EFI_COMMON_SECTION_HEADER(Structure
):
97 class FSP_COMMON_HEADER(Structure
):
99 ('Signature', ARRAY(c_char
, 4)),
100 ('HeaderLength', c_uint32
)
103 class FSP_INFORMATION_HEADER(Structure
):
105 ('Signature', ARRAY(c_char
, 4)),
106 ('HeaderLength', c_uint32
),
107 ('Reserved1', c_uint16
),
108 ('SpecVersion', c_uint8
),
109 ('HeaderRevision', c_uint8
),
110 ('ImageRevision', c_uint32
),
111 ('ImageId', ARRAY(c_char
, 8)),
112 ('ImageSize', c_uint32
),
113 ('ImageBase', c_uint32
),
114 ('ImageAttribute', c_uint16
),
115 ('ComponentAttribute', c_uint16
),
116 ('CfgRegionOffset', c_uint32
),
117 ('CfgRegionSize', c_uint32
),
118 ('Reserved2', c_uint32
),
119 ('TempRamInitEntryOffset', c_uint32
),
120 ('Reserved3', c_uint32
),
121 ('NotifyPhaseEntryOffset', c_uint32
),
122 ('FspMemoryInitEntryOffset', c_uint32
),
123 ('TempRamExitEntryOffset', c_uint32
),
124 ('FspSiliconInitEntryOffset', c_uint32
)
127 class FSP_PATCH_TABLE(Structure
):
129 ('Signature', ARRAY(c_char
, 4)),
130 ('HeaderLength', c_uint16
),
131 ('HeaderRevision', c_uint8
),
132 ('Reserved', c_uint8
),
133 ('PatchEntryNum', c_uint32
)
136 class EFI_IMAGE_DATA_DIRECTORY(Structure
):
138 ('VirtualAddress', c_uint32
),
142 class EFI_TE_IMAGE_HEADER(Structure
):
144 ('Signature', ARRAY(c_char
, 2)),
145 ('Machine', c_uint16
),
146 ('NumberOfSections', c_uint8
),
147 ('Subsystem', c_uint8
),
148 ('StrippedSize', c_uint16
),
149 ('AddressOfEntryPoint', c_uint32
),
150 ('BaseOfCode', c_uint32
),
151 ('ImageBase', c_uint64
),
152 ('DataDirectoryBaseReloc', EFI_IMAGE_DATA_DIRECTORY
),
153 ('DataDirectoryDebug', EFI_IMAGE_DATA_DIRECTORY
)
156 class EFI_IMAGE_DOS_HEADER(Structure
):
158 ('e_magic', c_uint16
),
159 ('e_cblp', c_uint16
),
161 ('e_crlc', c_uint16
),
162 ('e_cparhdr', c_uint16
),
163 ('e_minalloc', c_uint16
),
164 ('e_maxalloc', c_uint16
),
167 ('e_csum', c_uint16
),
170 ('e_lfarlc', c_uint16
),
171 ('e_ovno', c_uint16
),
172 ('e_res', ARRAY(c_uint16
, 4)),
173 ('e_oemid', c_uint16
),
174 ('e_oeminfo', c_uint16
),
175 ('e_res2', ARRAY(c_uint16
, 10)),
176 ('e_lfanew', c_uint16
)
179 class EFI_IMAGE_FILE_HEADER(Structure
):
181 ('Machine', c_uint16
),
182 ('NumberOfSections', c_uint16
),
183 ('TimeDateStamp', c_uint32
),
184 ('PointerToSymbolTable', c_uint32
),
185 ('NumberOfSymbols', c_uint32
),
186 ('SizeOfOptionalHeader', c_uint16
),
187 ('Characteristics', c_uint16
)
190 class PE_RELOC_BLOCK_HEADER(Structure
):
192 ('PageRVA', c_uint32
),
193 ('BlockSize', c_uint32
)
196 class EFI_IMAGE_OPTIONAL_HEADER32(Structure
):
199 ('MajorLinkerVersion', c_uint8
),
200 ('MinorLinkerVersion', c_uint8
),
201 ('SizeOfCode', c_uint32
),
202 ('SizeOfInitializedData', c_uint32
),
203 ('SizeOfUninitializedData', c_uint32
),
204 ('AddressOfEntryPoint', c_uint32
),
205 ('BaseOfCode', c_uint32
),
206 ('BaseOfData', c_uint32
),
207 ('ImageBase', c_uint32
),
208 ('SectionAlignment', c_uint32
),
209 ('FileAlignment', c_uint32
),
210 ('MajorOperatingSystemVersion', c_uint16
),
211 ('MinorOperatingSystemVersion', c_uint16
),
212 ('MajorImageVersion', c_uint16
),
213 ('MinorImageVersion', c_uint16
),
214 ('MajorSubsystemVersion', c_uint16
),
215 ('MinorSubsystemVersion', c_uint16
),
216 ('Win32VersionValue', c_uint32
),
217 ('SizeOfImage', c_uint32
),
218 ('SizeOfHeaders', c_uint32
),
219 ('CheckSum' , c_uint32
),
220 ('Subsystem', c_uint16
),
221 ('DllCharacteristics', c_uint16
),
222 ('SizeOfStackReserve', c_uint32
),
223 ('SizeOfStackCommit' , c_uint32
),
224 ('SizeOfHeapReserve', c_uint32
),
225 ('SizeOfHeapCommit' , c_uint32
),
226 ('LoaderFlags' , c_uint32
),
227 ('NumberOfRvaAndSizes', c_uint32
),
228 ('DataDirectory', ARRAY(EFI_IMAGE_DATA_DIRECTORY
, 16))
231 class EFI_IMAGE_OPTIONAL_HEADER32_PLUS(Structure
):
234 ('MajorLinkerVersion', c_uint8
),
235 ('MinorLinkerVersion', c_uint8
),
236 ('SizeOfCode', c_uint32
),
237 ('SizeOfInitializedData', c_uint32
),
238 ('SizeOfUninitializedData', c_uint32
),
239 ('AddressOfEntryPoint', c_uint32
),
240 ('BaseOfCode', c_uint32
),
241 ('ImageBase', c_uint64
),
242 ('SectionAlignment', c_uint32
),
243 ('FileAlignment', c_uint32
),
244 ('MajorOperatingSystemVersion', c_uint16
),
245 ('MinorOperatingSystemVersion', c_uint16
),
246 ('MajorImageVersion', c_uint16
),
247 ('MinorImageVersion', c_uint16
),
248 ('MajorSubsystemVersion', c_uint16
),
249 ('MinorSubsystemVersion', c_uint16
),
250 ('Win32VersionValue', c_uint32
),
251 ('SizeOfImage', c_uint32
),
252 ('SizeOfHeaders', c_uint32
),
253 ('CheckSum' , c_uint32
),
254 ('Subsystem', c_uint16
),
255 ('DllCharacteristics', c_uint16
),
256 ('SizeOfStackReserve', c_uint64
),
257 ('SizeOfStackCommit' , c_uint64
),
258 ('SizeOfHeapReserve', c_uint64
),
259 ('SizeOfHeapCommit' , c_uint64
),
260 ('LoaderFlags' , c_uint32
),
261 ('NumberOfRvaAndSizes', c_uint32
),
262 ('DataDirectory', ARRAY(EFI_IMAGE_DATA_DIRECTORY
, 16))
265 class EFI_IMAGE_OPTIONAL_HEADER(Union
):
267 ('PeOptHdr', EFI_IMAGE_OPTIONAL_HEADER32
),
268 ('PePlusOptHdr', EFI_IMAGE_OPTIONAL_HEADER32_PLUS
)
271 class EFI_IMAGE_NT_HEADERS32(Structure
):
273 ('Signature', c_uint32
),
274 ('FileHeader', EFI_IMAGE_FILE_HEADER
),
275 ('OptionalHeader', EFI_IMAGE_OPTIONAL_HEADER
)
279 class EFI_IMAGE_DIRECTORY_ENTRY
:
292 class EFI_FV_FILETYPE
:
301 COMBINED_PEIM_DRIVER
= 0x08
304 FIRMWARE_VOLUME_IMAGE
= 0x0b
305 COMBINED_SMM_DXE
= 0x0c
315 class EFI_SECTION_TYPE
:
316 """Enumeration of all valid firmware file section types."""
326 USER_INTERFACE
= 0x15
327 COMPATIBILITY16
= 0x16
328 FIRMWARE_VOLUME_IMAGE
= 0x17
329 FREEFORM_SUBTYPE_GUID
= 0x18
334 def AlignPtr (offset
, alignment
= 8):
335 return (offset
+ alignment
- 1) & ~
(alignment
- 1)
337 def Bytes2Val (bytes
):
338 return reduce(lambda x
,y
: (x
<<8)|y
, bytes
[::-1] )
340 def Val2Bytes (value
, blen
):
341 return [(value
>>(i
*8) & 0xff) for i
in range(blen
)]
343 def OutputStruct (obj
, indent
= 0, plen
= 0):
347 body
= (' ' * indent
+ '<%s>:\n') % obj
.__class
__.__name
__
353 pstr
= (' ' * (indent
+ 1) + '{0:<%d} = {1}\n') % max_key_len
355 for field
in obj
._fields
_:
357 val
= getattr(obj
, key
)
359 if not isinstance(val
, c_uint24
) and isinstance(val
, Structure
):
360 body
+= pstr
.format(key
, val
.__class
__.__name
__)
361 body
+= OutputStruct (val
, indent
+ 1)
365 rep
= "0x%X ('%s')" % (Bytes2Val(bytearray(val
)), val
)
366 elif type(val
) in (int, long):
368 elif isinstance(val
, c_uint24
):
369 rep
= '0x%X' % val
.get_value()
370 elif 'c_ubyte_Array' in str(type(val
)):
371 if sizeof(val
) == 16:
372 rep
= str(uuid
.UUID(bytes
= str(bytearray(val
)))).upper()
374 res
= ['0x%02X'%i for i
in bytearray(val
)]
375 rep
= '[%s]' % (','.join(res
))
378 plen
-= sizeof(field
[1])
379 body
+= pstr
.format(key
, rep
)
385 def __init__(self
, offset
, secdata
):
386 self
.SecHdr
= EFI_COMMON_SECTION_HEADER
.from_buffer (secdata
, 0)
387 self
.SecData
= secdata
[0:int(self
.SecHdr
.Size
)]
391 def __init__(self
, offset
, filedata
):
392 self
.FfsHdr
= EFI_FFS_FILE_HEADER
.from_buffer (filedata
, 0)
393 self
.FfsData
= filedata
[0:int(self
.FfsHdr
.Size
)]
398 ffssize
= len(self
.FfsData
)
399 offset
= sizeof(self
.FfsHdr
)
400 if self
.FfsHdr
.Name
!= '\xff' * 16:
401 while offset
< ffssize
:
402 sechdr
= EFI_COMMON_SECTION_HEADER
.from_buffer (self
.FfsData
, offset
)
403 sec
= Section (offset
, self
.FfsData
[offset
:offset
+ int(sechdr
.Size
)])
404 self
.SecList
.append(sec
)
405 offset
+= int(sechdr
.Size
)
406 offset
= AlignPtr(offset
, 4)
408 class FirmwareVolume
:
409 def __init__(self
, offset
, fvdata
):
410 self
.FvHdr
= EFI_FIRMWARE_VOLUME_HEADER
.from_buffer (fvdata
, 0)
411 self
.FvData
= fvdata
[0 : self
.FvHdr
.FvLength
]
413 if self
.FvHdr
.ExtHeaderOffset
> 0:
414 self
.FvExtHdr
= EFI_FIRMWARE_VOLUME_EXT_HEADER
.from_buffer (self
.FvData
, self
.FvHdr
.ExtHeaderOffset
)
420 fvsize
= len(self
.FvData
)
422 offset
= self
.FvHdr
.ExtHeaderOffset
+ self
.FvExtHdr
.ExtHeaderSize
424 offset
= self
.FvHdr
.HeaderLength
425 offset
= AlignPtr(offset
)
426 while offset
< fvsize
:
427 ffshdr
= EFI_FFS_FILE_HEADER
.from_buffer (self
.FvData
, offset
)
428 if (ffshdr
.Name
== '\xff' * 16) and (int(ffshdr
.Size
) == 0xFFFFFF):
431 ffs
= FirmwareFile (offset
, self
.FvData
[offset
:offset
+ int(ffshdr
.Size
)])
433 self
.FfsList
.append(ffs
)
434 offset
+= int(ffshdr
.Size
)
435 offset
= AlignPtr(offset
)
438 def __init__(self
, offset
, fih
, fihoff
, patch
):
440 self
.FihOffset
= fihoff
443 self
.Type
= "XTMSXXXXOXXXXXXX"[(fih
.ComponentAttribute
>> 12) & 0x0F]
444 self
.PatchList
= patch
445 self
.PatchList
.append(fihoff
+ 0x1C)
447 def AppendFv(self
, FvIdx
):
448 self
.FvIdxList
.append(FvIdx
)
450 def Patch(self
, delta
, fdbin
):
453 for idx
, patch
in enumerate(self
.PatchList
):
454 ptype
= (patch
>>24) & 0x0F
455 if ptype
not in [0x00, 0x0F]:
456 raise Exception('ERROR: Invalid patch type %d !' % ptype
)
457 if patch
& 0x80000000:
458 patch
= self
.Fih
.ImageSize
- (0x1000000 - (patch
& 0xFFFFFF))
460 patch
= patch
& 0xFFFFFF
461 if (patch
< self
.Fih
.ImageSize
) and (patch
+ sizeof(c_uint32
) <= self
.Fih
.ImageSize
):
462 offset
= patch
+ self
.Offset
463 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint32
)])
465 fdbin
[offset
:offset
+sizeof(c_uint32
)] = Val2Bytes(value
, sizeof(c_uint32
))
468 # Don't count the FSP base address patch entry appended at the end
472 return (count
, applied
)
474 class FirmwareDevice
:
475 def __init__(self
, offset
, fdfile
):
480 hfsp
= open (self
.FdFile
, 'rb')
481 self
.FdData
= bytearray(hfsp
.read())
486 fdsize
= len(self
.FdData
)
488 while offset
< fdsize
:
489 fvh
= EFI_FIRMWARE_VOLUME_HEADER
.from_buffer (self
.FdData
, offset
)
490 if '_FVH' != fvh
.Signature
:
491 raise Exception("ERROR: Invalid FV header !")
492 fv
= FirmwareVolume (offset
, self
.FdData
[offset
:offset
+ fvh
.FvLength
])
494 self
.FvList
.append(fv
)
495 offset
+= fv
.FvHdr
.FvLength
498 if len(self
.FspList
) == 0:
502 for fsp
in self
.FspList
:
507 if (newfih
.ImageId
!= fih
.ImageId
) or (newfih
.ImageRevision
!= fih
.ImageRevision
):
508 raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
512 for idx
, fv
in enumerate(self
.FvList
):
513 # Check if this FV contains FSP header
515 if len(fv
.FfsList
) == 0:
518 if len(ffs
.SecList
) == 0:
521 if sec
.SecHdr
.Type
!= EFI_SECTION_TYPE
.RAW
:
523 fihoffset
= ffs
.Offset
+ sec
.Offset
+ sizeof(sec
.SecHdr
)
524 fspoffset
= fv
.Offset
525 offset
= fspoffset
+ fihoffset
526 fih
= FSP_INFORMATION_HEADER
.from_buffer (self
.FdData
, offset
)
527 if 'FSPH' != fih
.Signature
:
530 offset
+= fih
.HeaderLength
531 offset
= AlignPtr(offset
, 4)
534 fch
= FSP_COMMON_HEADER
.from_buffer (self
.FdData
, offset
)
535 if 'FSPP' != fch
.Signature
:
536 offset
+= fch
.HeaderLength
537 offset
= AlignPtr(offset
, 4)
539 fspp
= FSP_PATCH_TABLE
.from_buffer (self
.FdData
, offset
)
540 offset
+= sizeof(fspp
)
541 pdata
= (c_uint32
* fspp
.PatchEntryNum
).from_buffer(self
.FdData
, offset
)
545 fsp
= FspImage (fspoffset
, fih
, fihoffset
, plist
)
547 self
.FspList
.append(fsp
)
548 flen
= fsp
.Fih
.ImageSize
- fv
.FvHdr
.FvLength
551 flen
-= fv
.FvHdr
.FvLength
553 raise Exception("ERROR: Incorrect FV size in image !")
557 def __init__(self
, offset
, data
):
559 tehdr
= EFI_TE_IMAGE_HEADER
.from_buffer (data
, 0)
560 if tehdr
.Signature
== 'VZ': # TE image
562 elif tehdr
.Signature
== 'MZ': # PE image
564 self
.DosHdr
= EFI_IMAGE_DOS_HEADER
.from_buffer (data
, 0)
565 self
.PeHdr
= EFI_IMAGE_NT_HEADERS32
.from_buffer (data
, self
.DosHdr
.e_lfanew
)
566 if self
.PeHdr
.Signature
!= 0x4550:
567 raise Exception("ERROR: Invalid PE32 header !")
568 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x10b: # PE32 image
569 if self
.PeHdr
.FileHeader
.SizeOfOptionalHeader
< EFI_IMAGE_OPTIONAL_HEADER32
.DataDirectory
.offset
:
570 raise Exception("ERROR: Unsupported PE32 image !")
571 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
:
572 raise Exception("ERROR: No relocation information available !")
573 elif self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x20b: # PE32+ image
574 if self
.PeHdr
.FileHeader
.SizeOfOptionalHeader
< EFI_IMAGE_OPTIONAL_HEADER32_PLUS
.DataDirectory
.offset
:
575 raise Exception("ERROR: Unsupported PE32+ image !")
576 if self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
:
577 raise Exception("ERROR: No relocation information available !")
579 raise Exception("ERROR: Invalid PE32 optional header !")
585 return self
.TeHdr
is not None
587 def ParseReloc(self
):
589 rsize
= self
.TeHdr
.DataDirectoryBaseReloc
.Size
590 roffset
= sizeof(self
.TeHdr
) - self
.TeHdr
.StrippedSize
+ self
.TeHdr
.DataDirectoryBaseReloc
.VirtualAddress
592 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x10b: # PE32 image
593 rsize
= self
.PeHdr
.OptionalHeader
.PeOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].Size
594 roffset
= self
.PeHdr
.OptionalHeader
.PeOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].VirtualAddress
595 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x20b: # PE32+ image
596 rsize
= self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].Size
597 roffset
= self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].VirtualAddress
601 while offset
< roffset
+ rsize
:
602 offset
= AlignPtr(offset
, 4)
603 blkhdr
= PE_RELOC_BLOCK_HEADER
.from_buffer(self
.Data
, offset
)
604 offset
+= sizeof(blkhdr
)
605 # Read relocation type,offset pairs
606 rlen
= blkhdr
.BlockSize
- sizeof(PE_RELOC_BLOCK_HEADER
)
607 rnum
= rlen
/sizeof(c_uint16
)
608 rdata
= (c_uint16
* rnum
).from_buffer(self
.Data
, offset
)
612 if rtype
== 0: # IMAGE_REL_BASED_ABSOLUTE:
614 if ((rtype
!= 3) and (rtype
!= 10)): # IMAGE_REL_BASED_HIGHLOW and IMAGE_REL_BASED_DIR64
615 raise Exception("ERROR: Unsupported relocation type %d!" % rtype
)
616 # Calculate the offset of the relocation
617 aoff
= blkhdr
.PageRVA
+ roff
619 aoff
+= sizeof(self
.TeHdr
) - self
.TeHdr
.StrippedSize
620 self
.RelocList
.append((rtype
, aoff
))
621 offset
+= sizeof(rdata
)
623 def Rebase(self
, delta
, fdbin
):
628 for (rtype
, roff
) in self
.RelocList
:
629 if rtype
== 3: # IMAGE_REL_BASED_HIGHLOW
630 offset
= roff
+ self
.Offset
631 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint32
)])
633 fdbin
[offset
:offset
+sizeof(c_uint32
)] = Val2Bytes(value
, sizeof(c_uint32
))
635 elif rtype
== 10: # IMAGE_REL_BASED_DIR64
636 offset
= roff
+ self
.Offset
637 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint64
)])
639 fdbin
[offset
:offset
+sizeof(c_uint64
)] = Val2Bytes(value
, sizeof(c_uint64
))
642 raise Exception('ERROR: Unknown relocation type %d !' % rtype
)
645 offset
= self
.Offset
+ EFI_TE_IMAGE_HEADER
.ImageBase
.offset
646 size
= EFI_TE_IMAGE_HEADER
.ImageBase
.size
648 offset
= self
.Offset
+ self
.DosHdr
.e_lfanew
649 offset
+= EFI_IMAGE_NT_HEADERS32
.OptionalHeader
.offset
650 offset
+= EFI_IMAGE_OPTIONAL_HEADER32
.ImageBase
.offset
651 size
= EFI_IMAGE_OPTIONAL_HEADER32
.ImageBase
.size
653 value
= Bytes2Val(fdbin
[offset
:offset
+size
]) + delta
654 fdbin
[offset
:offset
+size
] = Val2Bytes(value
, size
)
658 def ShowFspInfo (fspfile
):
659 fd
= FirmwareDevice(0, fspfile
)
663 print ("\nFound the following %d Firmware Volumes in FSP binary:" % (len(fd
.FvList
)))
664 for idx
, fv
in enumerate(fd
.FvList
):
665 name
= fv
.FvExtHdr
.FvName
669 name
= str(bytearray(name
))
670 guid
= uuid
.UUID(bytes
= name
)
671 print ("FV%d:" % idx
)
672 print (" GUID : %s" % str(guid
).upper())
673 print (" Offset : 0x%08X" % fv
.Offset
)
674 print (" Length : 0x%08X" % fv
.FvHdr
.FvLength
)
677 for fsp
in fd
.FspList
:
678 fvlist
= map(lambda x
: 'FV%d' % x
, fsp
.FvIdxList
)
679 print ("FSP_%s contains %s" % (fsp
.Type
, ','.join(fvlist
)))
680 print ("%s" % (OutputStruct(fsp
.Fih
, 0, fsp
.Fih
.HeaderLength
)))
682 def GenFspHdr (fspfile
, outdir
, hfile
):
683 fd
= FirmwareDevice(0, fspfile
)
688 hfile
= os
.path
.splitext(os
.path
.basename(fspfile
))[0] + '.h'
689 fspname
, ext
= os
.path
.splitext(os
.path
.basename(hfile
))
690 filename
= os
.path
.join(outdir
, fspname
+ ext
)
691 hfsp
= open(filename
, 'w')
692 hfsp
.write ('%s\n\n' % CopyRightHeaderFile
)
695 for fsp
in fd
.FspList
:
698 hfsp
.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih
.ImageId
)), fih
.ImageId
))
699 hfsp
.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih
.ImageRevision
)
701 fv
= fd
.FvList
[fsp
.FvIdxList
[0]]
702 hfsp
.write ('#define FSP%s_BASE 0x%08X\n' % (fsp
.Type
, fih
.ImageBase
))
703 hfsp
.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp
.Type
, fv
.Offset
))
704 hfsp
.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp
.Type
, fih
.ImageSize
))
708 def SplitFspBin (fspfile
, outdir
, nametemplate
):
709 fd
= FirmwareDevice(0, fspfile
)
713 for fsp
in fd
.FspList
:
714 if fsp
.Fih
.HeaderRevision
< 3:
715 raise Exception("ERROR: FSP 1.x is not supported by the split command !")
718 nametemplate
= fspfile
719 fspname
, ext
= os
.path
.splitext(os
.path
.basename(nametemplate
))
720 filename
= os
.path
.join(outdir
, fspname
+ '_' + fsp
.Type
+ ext
)
721 hfsp
= open(filename
, 'wb')
722 print ("Create FSP component file '%s'" % filename
)
723 for fvidx
in fsp
.FvIdxList
:
724 fv
= fd
.FvList
[fvidx
]
725 hfsp
.write(fv
.FvData
)
728 def RebaseFspBin (FspBinary
, FspComponent
, FspBase
, OutputDir
, OutputFile
):
729 fd
= FirmwareDevice(0, FspBinary
)
733 numcomp
= len(FspComponent
)
735 if numcomp
!= len(baselist
):
736 print "ERROR: Required number of base does not match number of FSP component !"
739 newfspbin
= fd
.FdData
[:]
741 for idx
, fspcomp
in enumerate(FspComponent
):
744 for fsp
in fd
.FspList
:
745 # Is this FSP 1.x single binary?
746 if fsp
.Fih
.HeaderRevision
< 3:
750 ftype
= fsp
.Type
.lower()
756 print "ERROR: Could not find FSP_%c component to rebase !" % fspcomp
.upper()
759 fspbase
= baselist
[idx
]
760 if fspbase
.startswith('0x'):
761 newbase
= int(fspbase
, 16)
763 newbase
= int(fspbase
)
764 oldbase
= fsp
.Fih
.ImageBase
765 delta
= newbase
- oldbase
766 print "Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype
.upper(),oldbase
,newbase
)
769 for fvidx
in fsp
.FvIdxList
:
770 fv
= fd
.FvList
[fvidx
]
771 for ffs
in fv
.FfsList
:
772 for sec
in ffs
.SecList
:
773 if sec
.SecHdr
.Type
in [EFI_SECTION_TYPE
.TE
, EFI_SECTION_TYPE
.PE32
]: # TE or PE32
774 offset
= fd
.Offset
+ fv
.Offset
+ ffs
.Offset
+ sec
.Offset
+ sizeof(sec
.SecHdr
)
775 imglist
.append ((offset
, len(sec
.SecData
) - sizeof(sec
.SecHdr
)))
779 for (offset
, length
) in imglist
:
780 img
= PeTeImage(offset
, fd
.FdData
[offset
:offset
+ length
])
782 pcount
+= img
.Rebase(delta
, newfspbin
)
785 print " Patched %d entries in %d TE/PE32 images." % (pcount
, fcount
)
787 (count
, applied
) = fsp
.Patch(delta
, newfspbin
)
788 print " Patched %d entries using FSP patch table." % applied
790 print " %d invalid entries are ignored !" % (count
- applied
)
793 filename
= os
.path
.basename(FspBinary
)
794 base
, ext
= os
.path
.splitext(filename
)
795 OutputFile
= base
+ "_%08X" % newbase
+ ext
797 fspname
, ext
= os
.path
.splitext(os
.path
.basename(OutputFile
))
798 filename
= os
.path
.join(OutputDir
, fspname
+ ext
)
799 fd
= open(filename
, "wb")
804 parser
= argparse
.ArgumentParser()
805 subparsers
= parser
.add_subparsers(title
='commands')
807 parser_rebase
= subparsers
.add_parser('rebase', help='rebase a FSP into a new base address')
808 parser_rebase
.set_defaults(which
='rebase')
809 parser_rebase
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
810 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)
811 parser_rebase
.add_argument('-b', '--newbase', dest
='FspBase', nargs
='+', type=str, help='Rebased FSP binary file name', default
= '', required
= True)
812 parser_rebase
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
813 parser_rebase
.add_argument('-n', '--outfile', dest
='OutputFile', type=str, help='Rebased FSP binary file name', default
= '')
815 parser_split
= subparsers
.add_parser('split', help='split a FSP into multiple components')
816 parser_split
.set_defaults(which
='split')
817 parser_split
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
818 parser_split
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
819 parser_split
.add_argument('-n', '--nametpl', dest
='NameTemplate', type=str, help='Output name template', default
= '')
821 parser_genhdr
= subparsers
.add_parser('genhdr', help='generate a header file for FSP binary')
822 parser_genhdr
.set_defaults(which
='genhdr')
823 parser_genhdr
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
824 parser_genhdr
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
825 parser_genhdr
.add_argument('-n', '--hfile', dest
='HFileName', type=str, help='Output header file name', default
= '')
827 parser_info
= subparsers
.add_parser('info', help='display FSP information')
828 parser_info
.set_defaults(which
='info')
829 parser_info
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
831 args
= parser
.parse_args()
832 if args
.which
in ['rebase', 'split', 'genhdr', 'info']:
833 if not os
.path
.exists(args
.FspBinary
):
834 raise Exception ("ERROR: Could not locate FSP binary file '%s' !" % args
.FspBinary
)
835 if hasattr(args
, 'OutputDir') and not os
.path
.exists(args
.OutputDir
):
836 raise Exception ("ERROR: Invalid output directory '%s' !" % args
.OutputDir
)
838 if args
.which
== 'rebase':
839 RebaseFspBin (args
.FspBinary
, args
.FspComponent
, args
.FspBase
, args
.OutputDir
, args
.OutputFile
)
840 elif args
.which
== 'split':
841 SplitFspBin (args
.FspBinary
, args
.OutputDir
, args
.NameTemplate
)
842 elif args
.which
== 'genhdr':
843 GenFspHdr (args
.FspBinary
, args
.OutputDir
, args
.HFileName
)
844 elif args
.which
== 'info':
845 ShowFspInfo (args
.FspBinary
)
851 if __name__
== '__main__':