3 # Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
4 # This program and the accompanying materials are licensed and made available under
5 # the terms and conditions of the BSD License that accompanies this distribution.
6 # The full text of the license may be found at
7 # http://opensource.org/licenses/bsd-license.php.
9 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 This utility supports some operations for Intel FSP 2.0 image.
25 - Display FSP 2.0 information header
26 - Split FSP 2.0 image into individual FSP-T/M/S/O component
27 - Rebase FSP 2.0 components to a different base address
28 - Generate FSP mapping C header file
31 CopyRightHeaderFile
= """/*
33 * Automatically generated file; DO NOT EDIT.
39 class c_uint24(Structure
):
40 """Little-Endian 24-bit Unsigned Integer"""
42 _fields_
= [('Data', (c_uint8
* 3))]
44 def __init__(self
, val
=0):
47 def __str__(self
, indent
=0):
48 return '0x%.6x' % self
.value
51 return self
.get_value()
53 def set_value(self
, val
):
54 self
.Data
[0:3] = Val2Bytes(val
, 3)
57 return Bytes2Val(self
.Data
[0:3])
59 value
= property(get_value
, set_value
)
61 class EFI_FIRMWARE_VOLUME_HEADER(Structure
):
63 ('ZeroVector', ARRAY(c_uint8
, 16)),
64 ('FileSystemGuid', ARRAY(c_uint8
, 16)),
65 ('FvLength', c_uint64
),
66 ('Signature', ARRAY(c_char
, 4)),
67 ('Attributes', c_uint32
),
68 ('HeaderLength', c_uint16
),
69 ('Checksum', c_uint16
),
70 ('ExtHeaderOffset', c_uint16
),
71 ('Reserved', c_uint8
),
75 class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure
):
77 ('FvName', ARRAY(c_uint8
, 16)),
78 ('ExtHeaderSize', c_uint32
)
81 class EFI_FFS_INTEGRITY_CHECK(Structure
):
87 class EFI_FFS_FILE_HEADER(Structure
):
89 ('Name', ARRAY(c_uint8
, 16)),
90 ('IntegrityCheck', EFI_FFS_INTEGRITY_CHECK
),
92 ('Attributes', c_uint8
),
97 class EFI_COMMON_SECTION_HEADER(Structure
):
103 class FSP_COMMON_HEADER(Structure
):
105 ('Signature', ARRAY(c_char
, 4)),
106 ('HeaderLength', c_uint32
)
109 class FSP_INFORMATION_HEADER(Structure
):
111 ('Signature', ARRAY(c_char
, 4)),
112 ('HeaderLength', c_uint32
),
113 ('Reserved1', c_uint16
),
114 ('SpecVersion', c_uint8
),
115 ('HeaderRevision', c_uint8
),
116 ('ImageRevision', c_uint32
),
117 ('ImageId', ARRAY(c_char
, 8)),
118 ('ImageSize', c_uint32
),
119 ('ImageBase', c_uint32
),
120 ('ImageAttribute', c_uint16
),
121 ('ComponentAttribute', c_uint16
),
122 ('CfgRegionOffset', c_uint32
),
123 ('CfgRegionSize', c_uint32
),
124 ('Reserved2', c_uint32
),
125 ('TempRamInitEntryOffset', c_uint32
),
126 ('Reserved3', c_uint32
),
127 ('NotifyPhaseEntryOffset', c_uint32
),
128 ('FspMemoryInitEntryOffset', c_uint32
),
129 ('TempRamExitEntryOffset', c_uint32
),
130 ('FspSiliconInitEntryOffset', c_uint32
)
133 class FSP_PATCH_TABLE(Structure
):
135 ('Signature', ARRAY(c_char
, 4)),
136 ('HeaderLength', c_uint16
),
137 ('HeaderRevision', c_uint8
),
138 ('Reserved', c_uint8
),
139 ('PatchEntryNum', c_uint32
)
142 class EFI_IMAGE_DATA_DIRECTORY(Structure
):
144 ('VirtualAddress', c_uint32
),
148 class EFI_TE_IMAGE_HEADER(Structure
):
150 ('Signature', ARRAY(c_char
, 2)),
151 ('Machine', c_uint16
),
152 ('NumberOfSections', c_uint8
),
153 ('Subsystem', c_uint8
),
154 ('StrippedSize', c_uint16
),
155 ('AddressOfEntryPoint', c_uint32
),
156 ('BaseOfCode', c_uint32
),
157 ('ImageBase', c_uint64
),
158 ('DataDirectoryBaseReloc', EFI_IMAGE_DATA_DIRECTORY
),
159 ('DataDirectoryDebug', EFI_IMAGE_DATA_DIRECTORY
)
162 class EFI_IMAGE_DOS_HEADER(Structure
):
164 ('e_magic', c_uint16
),
165 ('e_cblp', c_uint16
),
167 ('e_crlc', c_uint16
),
168 ('e_cparhdr', c_uint16
),
169 ('e_minalloc', c_uint16
),
170 ('e_maxalloc', c_uint16
),
173 ('e_csum', c_uint16
),
176 ('e_lfarlc', c_uint16
),
177 ('e_ovno', c_uint16
),
178 ('e_res', ARRAY(c_uint16
, 4)),
179 ('e_oemid', c_uint16
),
180 ('e_oeminfo', c_uint16
),
181 ('e_res2', ARRAY(c_uint16
, 10)),
182 ('e_lfanew', c_uint16
)
185 class EFI_IMAGE_FILE_HEADER(Structure
):
187 ('Machine', c_uint16
),
188 ('NumberOfSections', c_uint16
),
189 ('TimeDateStamp', c_uint32
),
190 ('PointerToSymbolTable', c_uint32
),
191 ('NumberOfSymbols', c_uint32
),
192 ('SizeOfOptionalHeader', c_uint16
),
193 ('Characteristics', c_uint16
)
196 class PE_RELOC_BLOCK_HEADER(Structure
):
198 ('PageRVA', c_uint32
),
199 ('BlockSize', c_uint32
)
202 class EFI_IMAGE_OPTIONAL_HEADER32(Structure
):
205 ('MajorLinkerVersion', c_uint8
),
206 ('MinorLinkerVersion', c_uint8
),
207 ('SizeOfCode', c_uint32
),
208 ('SizeOfInitializedData', c_uint32
),
209 ('SizeOfUninitializedData', c_uint32
),
210 ('AddressOfEntryPoint', c_uint32
),
211 ('BaseOfCode', c_uint32
),
212 ('BaseOfData', c_uint32
),
213 ('ImageBase', c_uint32
),
214 ('SectionAlignment', c_uint32
),
215 ('FileAlignment', c_uint32
),
216 ('MajorOperatingSystemVersion', c_uint16
),
217 ('MinorOperatingSystemVersion', c_uint16
),
218 ('MajorImageVersion', c_uint16
),
219 ('MinorImageVersion', c_uint16
),
220 ('MajorSubsystemVersion', c_uint16
),
221 ('MinorSubsystemVersion', c_uint16
),
222 ('Win32VersionValue', c_uint32
),
223 ('SizeOfImage', c_uint32
),
224 ('SizeOfHeaders', c_uint32
),
225 ('CheckSum' , c_uint32
),
226 ('Subsystem', c_uint16
),
227 ('DllCharacteristics', c_uint16
),
228 ('SizeOfStackReserve', c_uint32
),
229 ('SizeOfStackCommit' , c_uint32
),
230 ('SizeOfHeapReserve', c_uint32
),
231 ('SizeOfHeapCommit' , c_uint32
),
232 ('LoaderFlags' , c_uint32
),
233 ('NumberOfRvaAndSizes', c_uint32
),
234 ('DataDirectory', ARRAY(EFI_IMAGE_DATA_DIRECTORY
, 16))
237 class EFI_IMAGE_OPTIONAL_HEADER32_PLUS(Structure
):
240 ('MajorLinkerVersion', c_uint8
),
241 ('MinorLinkerVersion', c_uint8
),
242 ('SizeOfCode', c_uint32
),
243 ('SizeOfInitializedData', c_uint32
),
244 ('SizeOfUninitializedData', c_uint32
),
245 ('AddressOfEntryPoint', c_uint32
),
246 ('BaseOfCode', c_uint32
),
247 ('ImageBase', c_uint64
),
248 ('SectionAlignment', c_uint32
),
249 ('FileAlignment', c_uint32
),
250 ('MajorOperatingSystemVersion', c_uint16
),
251 ('MinorOperatingSystemVersion', c_uint16
),
252 ('MajorImageVersion', c_uint16
),
253 ('MinorImageVersion', c_uint16
),
254 ('MajorSubsystemVersion', c_uint16
),
255 ('MinorSubsystemVersion', c_uint16
),
256 ('Win32VersionValue', c_uint32
),
257 ('SizeOfImage', c_uint32
),
258 ('SizeOfHeaders', c_uint32
),
259 ('CheckSum' , c_uint32
),
260 ('Subsystem', c_uint16
),
261 ('DllCharacteristics', c_uint16
),
262 ('SizeOfStackReserve', c_uint64
),
263 ('SizeOfStackCommit' , c_uint64
),
264 ('SizeOfHeapReserve', c_uint64
),
265 ('SizeOfHeapCommit' , c_uint64
),
266 ('LoaderFlags' , c_uint32
),
267 ('NumberOfRvaAndSizes', c_uint32
),
268 ('DataDirectory', ARRAY(EFI_IMAGE_DATA_DIRECTORY
, 16))
271 class EFI_IMAGE_OPTIONAL_HEADER(Union
):
273 ('PeOptHdr', EFI_IMAGE_OPTIONAL_HEADER32
),
274 ('PePlusOptHdr', EFI_IMAGE_OPTIONAL_HEADER32_PLUS
)
277 class EFI_IMAGE_NT_HEADERS32(Structure
):
279 ('Signature', c_uint32
),
280 ('FileHeader', EFI_IMAGE_FILE_HEADER
),
281 ('OptionalHeader', EFI_IMAGE_OPTIONAL_HEADER
)
285 class EFI_IMAGE_DIRECTORY_ENTRY
:
298 class EFI_FV_FILETYPE
:
307 COMBINED_PEIM_DRIVER
= 0x08
310 FIRMWARE_VOLUME_IMAGE
= 0x0b
311 COMBINED_SMM_DXE
= 0x0c
321 class EFI_SECTION_TYPE
:
322 """Enumeration of all valid firmware file section types."""
332 USER_INTERFACE
= 0x15
333 COMPATIBILITY16
= 0x16
334 FIRMWARE_VOLUME_IMAGE
= 0x17
335 FREEFORM_SUBTYPE_GUID
= 0x18
340 def AlignPtr (offset
, alignment
= 8):
341 return (offset
+ alignment
- 1) & ~
(alignment
- 1)
343 def Bytes2Val (bytes
):
344 return reduce(lambda x
,y
: (x
<<8)|y
, bytes
[::-1] )
346 def Val2Bytes (value
, blen
):
347 return [(value
>>(i
*8) & 0xff) for i
in range(blen
)]
349 def OutputStruct (obj
, indent
= 0, plen
= 0):
353 body
= (' ' * indent
+ '<%s>:\n') % obj
.__class
__.__name
__
359 pstr
= (' ' * (indent
+ 1) + '{0:<%d} = {1}\n') % max_key_len
361 for field
in obj
._fields
_:
363 val
= getattr(obj
, key
)
365 if not isinstance(val
, c_uint24
) and isinstance(val
, Structure
):
366 body
+= pstr
.format(key
, val
.__class
__.__name
__)
367 body
+= OutputStruct (val
, indent
+ 1)
371 rep
= "0x%X ('%s')" % (Bytes2Val(bytearray(val
)), val
)
372 elif type(val
) in (int, long):
374 elif isinstance(val
, c_uint24
):
375 rep
= '0x%X' % val
.get_value()
376 elif 'c_ubyte_Array' in str(type(val
)):
377 if sizeof(val
) == 16:
378 rep
= str(uuid
.UUID(bytes
= str(bytearray(val
)))).upper()
380 res
= ['0x%02X'%i for i
in bytearray(val
)]
381 rep
= '[%s]' % (','.join(res
))
384 plen
-= sizeof(field
[1])
385 body
+= pstr
.format(key
, rep
)
391 def __init__(self
, offset
, secdata
):
392 self
.SecHdr
= EFI_COMMON_SECTION_HEADER
.from_buffer (secdata
, 0)
393 self
.SecData
= secdata
[0:int(self
.SecHdr
.Size
)]
397 def __init__(self
, offset
, filedata
):
398 self
.FfsHdr
= EFI_FFS_FILE_HEADER
.from_buffer (filedata
, 0)
399 self
.FfsData
= filedata
[0:int(self
.FfsHdr
.Size
)]
404 ffssize
= len(self
.FfsData
)
405 offset
= sizeof(self
.FfsHdr
)
406 if self
.FfsHdr
.Name
!= '\xff' * 16:
407 while offset
< ffssize
:
408 sechdr
= EFI_COMMON_SECTION_HEADER
.from_buffer (self
.FfsData
, offset
)
409 sec
= Section (offset
, self
.FfsData
[offset
:offset
+ int(sechdr
.Size
)])
410 self
.SecList
.append(sec
)
411 offset
+= int(sechdr
.Size
)
412 offset
= AlignPtr(offset
, 4)
414 class FirmwareVolume
:
415 def __init__(self
, offset
, fvdata
):
416 self
.FvHdr
= EFI_FIRMWARE_VOLUME_HEADER
.from_buffer (fvdata
, 0)
417 self
.FvData
= fvdata
[0 : self
.FvHdr
.FvLength
]
419 if self
.FvHdr
.ExtHeaderOffset
> 0:
420 self
.FvExtHdr
= EFI_FIRMWARE_VOLUME_EXT_HEADER
.from_buffer (self
.FvData
, self
.FvHdr
.ExtHeaderOffset
)
426 fvsize
= len(self
.FvData
)
428 offset
= self
.FvHdr
.ExtHeaderOffset
+ self
.FvExtHdr
.ExtHeaderSize
430 offset
= self
.FvHdr
.HeaderLength
431 offset
= AlignPtr(offset
)
432 while offset
< fvsize
:
433 ffshdr
= EFI_FFS_FILE_HEADER
.from_buffer (self
.FvData
, offset
)
434 if (ffshdr
.Name
== '\xff' * 16) and (int(ffshdr
.Size
) == 0xFFFFFF):
437 ffs
= FirmwareFile (offset
, self
.FvData
[offset
:offset
+ int(ffshdr
.Size
)])
439 self
.FfsList
.append(ffs
)
440 offset
+= int(ffshdr
.Size
)
441 offset
= AlignPtr(offset
)
444 def __init__(self
, offset
, fih
, fihoff
, patch
):
446 self
.FihOffset
= fihoff
449 self
.Type
= "XTMSXXXXOXXXXXXX"[(fih
.ComponentAttribute
>> 12) & 0x0F]
450 self
.PatchList
= patch
451 self
.PatchList
.append(fihoff
+ 0x1C)
453 def AppendFv(self
, FvIdx
):
454 self
.FvIdxList
.append(FvIdx
)
456 def Patch(self
, delta
, fdbin
):
459 for idx
, patch
in enumerate(self
.PatchList
):
460 ptype
= (patch
>>24) & 0x0F
461 if ptype
not in [0x00, 0x0F]:
462 raise Exception('ERROR: Invalid patch type %d !' % ptype
)
463 if patch
& 0x80000000:
464 patch
= self
.Fih
.ImageSize
- (0x1000000 - (patch
& 0xFFFFFF))
466 patch
= patch
& 0xFFFFFF
467 if (patch
< self
.Fih
.ImageSize
) and (patch
+ sizeof(c_uint32
) <= self
.Fih
.ImageSize
):
468 offset
= patch
+ self
.Offset
469 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint32
)])
471 fdbin
[offset
:offset
+sizeof(c_uint32
)] = Val2Bytes(value
, sizeof(c_uint32
))
474 # Don't count the FSP base address patch entry appended at the end
478 return (count
, applied
)
480 class FirmwareDevice
:
481 def __init__(self
, offset
, fdfile
):
486 hfsp
= open (self
.FdFile
, 'rb')
487 self
.FdData
= bytearray(hfsp
.read())
492 fdsize
= len(self
.FdData
)
494 while offset
< fdsize
:
495 fvh
= EFI_FIRMWARE_VOLUME_HEADER
.from_buffer (self
.FdData
, offset
)
496 if '_FVH' != fvh
.Signature
:
497 raise Exception("ERROR: Invalid FV header !")
498 fv
= FirmwareVolume (offset
, self
.FdData
[offset
:offset
+ fvh
.FvLength
])
500 self
.FvList
.append(fv
)
501 offset
+= fv
.FvHdr
.FvLength
504 if len(self
.FspList
) == 0:
508 for fsp
in self
.FspList
:
509 if fsp
.Fih
.HeaderRevision
< 3:
510 raise Exception("ERROR: FSP 1.x is not supported by this tool !")
515 if (newfih
.ImageId
!= fih
.ImageId
) or (newfih
.ImageRevision
!= fih
.ImageRevision
):
516 raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
520 for idx
, fv
in enumerate(self
.FvList
):
521 # Check if this FV contains FSP header
523 if len(fv
.FfsList
) == 0:
526 if len(ffs
.SecList
) == 0:
529 if sec
.SecHdr
.Type
!= EFI_SECTION_TYPE
.RAW
:
531 fihoffset
= ffs
.Offset
+ sec
.Offset
+ sizeof(sec
.SecHdr
)
532 fspoffset
= fv
.Offset
533 offset
= fspoffset
+ fihoffset
534 fih
= FSP_INFORMATION_HEADER
.from_buffer (self
.FdData
, offset
)
535 if 'FSPH' != fih
.Signature
:
538 offset
+= fih
.HeaderLength
539 offset
= AlignPtr(offset
, 4)
542 fch
= FSP_COMMON_HEADER
.from_buffer (self
.FdData
, offset
)
543 if 'FSPP' != fch
.Signature
:
544 offset
+= fch
.HeaderLength
545 offset
= AlignPtr(offset
, 4)
547 fspp
= FSP_PATCH_TABLE
.from_buffer (self
.FdData
, offset
)
548 offset
+= sizeof(fspp
)
549 pdata
= (c_uint32
* fspp
.PatchEntryNum
).from_buffer(self
.FdData
, offset
)
553 fsp
= FspImage (fspoffset
, fih
, fihoffset
, plist
)
555 self
.FspList
.append(fsp
)
556 flen
= fsp
.Fih
.ImageSize
- fv
.FvHdr
.FvLength
559 flen
-= fv
.FvHdr
.FvLength
561 raise Exception("ERROR: Incorrect FV size in image !")
565 def __init__(self
, offset
, data
):
567 tehdr
= EFI_TE_IMAGE_HEADER
.from_buffer (data
, 0)
568 if tehdr
.Signature
== 'VZ': # TE image
570 elif tehdr
.Signature
== 'MZ': # PE image
572 self
.DosHdr
= EFI_IMAGE_DOS_HEADER
.from_buffer (data
, 0)
573 self
.PeHdr
= EFI_IMAGE_NT_HEADERS32
.from_buffer (data
, self
.DosHdr
.e_lfanew
)
574 if self
.PeHdr
.Signature
!= 0x4550:
575 raise Exception("ERROR: Invalid PE32 header !")
576 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x10b: # PE32 image
577 if self
.PeHdr
.FileHeader
.SizeOfOptionalHeader
< EFI_IMAGE_OPTIONAL_HEADER32
.DataDirectory
.offset
:
578 raise Exception("ERROR: Unsupported PE32 image !")
579 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
:
580 raise Exception("ERROR: No relocation information available !")
581 elif self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x20b: # PE32+ image
582 if self
.PeHdr
.FileHeader
.SizeOfOptionalHeader
< EFI_IMAGE_OPTIONAL_HEADER32_PLUS
.DataDirectory
.offset
:
583 raise Exception("ERROR: Unsupported PE32+ image !")
584 if self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
:
585 raise Exception("ERROR: No relocation information available !")
587 raise Exception("ERROR: Invalid PE32 optional header !")
593 return self
.TeHdr
is not None
595 def ParseReloc(self
):
597 rsize
= self
.TeHdr
.DataDirectoryBaseReloc
.Size
598 roffset
= sizeof(self
.TeHdr
) - self
.TeHdr
.StrippedSize
+ self
.TeHdr
.DataDirectoryBaseReloc
.VirtualAddress
600 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x10b: # PE32 image
601 rsize
= self
.PeHdr
.OptionalHeader
.PeOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].Size
602 roffset
= self
.PeHdr
.OptionalHeader
.PeOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].VirtualAddress
603 if self
.PeHdr
.OptionalHeader
.PeOptHdr
.Magic
== 0x20b: # PE32+ image
604 rsize
= self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].Size
605 roffset
= self
.PeHdr
.OptionalHeader
.PePlusOptHdr
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY
.BASERELOC
].VirtualAddress
609 while offset
< roffset
+ rsize
:
610 offset
= AlignPtr(offset
, 4)
611 blkhdr
= PE_RELOC_BLOCK_HEADER
.from_buffer(self
.Data
, offset
)
612 offset
+= sizeof(blkhdr
)
613 # Read relocation type,offset pairs
614 rlen
= blkhdr
.BlockSize
- sizeof(PE_RELOC_BLOCK_HEADER
)
615 rnum
= rlen
/sizeof(c_uint16
)
616 rdata
= (c_uint16
* rnum
).from_buffer(self
.Data
, offset
)
620 if rtype
== 0: # IMAGE_REL_BASED_ABSOLUTE:
622 if ((rtype
!= 3) and (rtype
!= 10)): # IMAGE_REL_BASED_HIGHLOW and IMAGE_REL_BASED_DIR64
623 raise Exception("ERROR: Unsupported relocation type %d!" % rtype
)
624 # Calculate the offset of the relocation
625 aoff
= blkhdr
.PageRVA
+ roff
627 aoff
+= sizeof(self
.TeHdr
) - self
.TeHdr
.StrippedSize
628 self
.RelocList
.append((rtype
, aoff
))
629 offset
+= sizeof(rdata
)
631 def Rebase(self
, delta
, fdbin
):
636 for (rtype
, roff
) in self
.RelocList
:
637 if rtype
== 3: # IMAGE_REL_BASED_HIGHLOW
638 offset
= roff
+ self
.Offset
639 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint32
)])
641 fdbin
[offset
:offset
+sizeof(c_uint32
)] = Val2Bytes(value
, sizeof(c_uint32
))
643 elif rtype
== 10: # IMAGE_REL_BASED_DIR64
644 offset
= roff
+ self
.Offset
645 value
= Bytes2Val(fdbin
[offset
:offset
+sizeof(c_uint64
)])
647 fdbin
[offset
:offset
+sizeof(c_uint64
)] = Val2Bytes(value
, sizeof(c_uint64
))
650 raise Exception('ERROR: Unknown relocation type %d !' % rtype
)
653 offset
= self
.Offset
+ EFI_TE_IMAGE_HEADER
.ImageBase
.offset
654 size
= EFI_TE_IMAGE_HEADER
.ImageBase
.size
656 offset
= self
.Offset
+ self
.DosHdr
.e_lfanew
657 offset
+= EFI_IMAGE_NT_HEADERS32
.OptionalHeader
.offset
658 offset
+= EFI_IMAGE_OPTIONAL_HEADER32
.ImageBase
.offset
659 size
= EFI_IMAGE_OPTIONAL_HEADER32
.ImageBase
.size
661 value
= Bytes2Val(fdbin
[offset
:offset
+size
]) + delta
662 fdbin
[offset
:offset
+size
] = Val2Bytes(value
, size
)
666 def ShowFspInfo (fspfile
):
667 fd
= FirmwareDevice(0, fspfile
)
671 print ("\nFound the following %d Firmware Volumes in FSP binary:" % (len(fd
.FvList
)))
672 for idx
, fv
in enumerate(fd
.FvList
):
673 name
= fv
.FvExtHdr
.FvName
677 name
= str(bytearray(name
))
678 guid
= uuid
.UUID(bytes
= name
)
679 print ("FV%d:" % idx
)
680 print (" GUID : %s" % str(guid
).upper())
681 print (" Offset : 0x%08X" % fv
.Offset
)
682 print (" Length : 0x%08X" % fv
.FvHdr
.FvLength
)
685 for fsp
in fd
.FspList
:
686 fvlist
= map(lambda x
: 'FV%d' % x
, fsp
.FvIdxList
)
687 print ("FSP_%s contains %s" % (fsp
.Type
, ','.join(fvlist
)))
688 print ("%s" % (OutputStruct(fsp
.Fih
, 0, fsp
.Fih
.HeaderLength
)))
690 def GenFspHdr (fspfile
, outdir
, hfile
):
691 fd
= FirmwareDevice(0, fspfile
)
696 hfile
= os
.path
.splitext(os
.path
.basename(fspfile
))[0] + '.h'
697 fspname
, ext
= os
.path
.splitext(os
.path
.basename(hfile
))
698 filename
= os
.path
.join(outdir
, fspname
+ ext
)
699 hfsp
= open(filename
, 'w')
700 hfsp
.write ('%s\n\n' % CopyRightHeaderFile
)
703 for fsp
in fd
.FspList
:
706 hfsp
.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih
.ImageId
)), fih
.ImageId
))
707 hfsp
.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih
.ImageRevision
)
709 fv
= fd
.FvList
[fsp
.FvIdxList
[0]]
710 hfsp
.write ('#define FSP%s_BASE 0x%08X\n' % (fsp
.Type
, fih
.ImageBase
))
711 hfsp
.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp
.Type
, fv
.Offset
))
712 hfsp
.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp
.Type
, fih
.ImageSize
))
716 def SplitFspBin (fspfile
, outdir
, nametemplate
):
717 fd
= FirmwareDevice(0, fspfile
)
721 for fsp
in fd
.FspList
:
724 nametemplate
= fspfile
725 fspname
, ext
= os
.path
.splitext(os
.path
.basename(nametemplate
))
726 filename
= os
.path
.join(outdir
, fspname
+ '_' + fsp
.Type
+ ext
)
727 hfsp
= open(filename
, 'wb')
728 print ("Ceate FSP component file '%s'" % filename
)
729 for fvidx
in fsp
.FvIdxList
:
730 fv
= fd
.FvList
[fvidx
]
731 hfsp
.write(fv
.FvData
)
734 def RebaseFspBin (FspBinary
, FspComponent
, FspBase
, OutputDir
, OutputFile
):
735 fd
= FirmwareDevice(0, FspBinary
)
739 numcomp
= len(FspComponent
)
741 if numcomp
!= len(baselist
):
742 print "ERROR: Required number of base does not match number of FSP component !"
745 newfspbin
= fd
.FdData
[:]
747 for idx
, fspcomp
in enumerate(FspComponent
):
750 for fsp
in fd
.FspList
:
751 ftype
= fsp
.Type
.lower()
757 print "ERROR: Could not find FSP_%c component to rebase !" % fspcomp
.upper()
760 fspbase
= baselist
[idx
]
761 if fspbase
.startswith('0x'):
762 newbase
= int(fspbase
, 16)
764 newbase
= int(fspbase
)
765 oldbase
= fsp
.Fih
.ImageBase
766 delta
= newbase
- oldbase
767 print "Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype
.upper(),oldbase
,newbase
)
770 for fvidx
in fsp
.FvIdxList
:
771 fv
= fd
.FvList
[fvidx
]
772 for ffs
in fv
.FfsList
:
773 for sec
in ffs
.SecList
:
774 if sec
.SecHdr
.Type
in [EFI_SECTION_TYPE
.TE
, EFI_SECTION_TYPE
.PE32
]: # TE or PE32
775 offset
= fd
.Offset
+ fv
.Offset
+ ffs
.Offset
+ sec
.Offset
+ sizeof(sec
.SecHdr
)
776 imglist
.append ((offset
, len(sec
.SecData
) - sizeof(sec
.SecHdr
)))
780 for (offset
, length
) in imglist
:
781 img
= PeTeImage(offset
, fd
.FdData
[offset
:offset
+ length
])
783 pcount
+= img
.Rebase(delta
, newfspbin
)
786 print " Patched %d entries in %d TE/PE32 images." % (pcount
, fcount
)
788 (count
, applied
) = fsp
.Patch(delta
, newfspbin
)
789 print " Patched %d entries using FSP patch table." % applied
791 print " %d invalid entries are ignored !" % (count
- applied
)
794 filename
= os
.path
.basename(FspBinary
)
795 base
, ext
= os
.path
.splitext(filename
)
796 OutputFile
= base
+ "_%08X" % newbase
+ ext
798 fspname
, ext
= os
.path
.splitext(os
.path
.basename(OutputFile
))
799 filename
= os
.path
.join(OutputDir
, fspname
+ ext
)
800 fd
= open(filename
, "wb")
805 parser
= argparse
.ArgumentParser()
806 subparsers
= parser
.add_subparsers(title
='commands')
808 parser_rebase
= subparsers
.add_parser('rebase', help='rebase a FSP into a new base address')
809 parser_rebase
.set_defaults(which
='rebase')
810 parser_rebase
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
811 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)
812 parser_rebase
.add_argument('-b', '--newbase', dest
='FspBase', nargs
='+', type=str, help='Rebased FSP binary file name', default
= '', required
= True)
813 parser_rebase
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
814 parser_rebase
.add_argument('-n', '--outfile', dest
='OutputFile', type=str, help='Rebased FSP binary file name', default
= '')
816 parser_split
= subparsers
.add_parser('split', help='split a FSP into multiple components')
817 parser_split
.set_defaults(which
='split')
818 parser_split
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
819 parser_split
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
820 parser_split
.add_argument('-n', '--nametpl', dest
='NameTemplate', type=str, help='Output name template', default
= '')
822 parser_genhdr
= subparsers
.add_parser('genhdr', help='generate a header file for FSP binary')
823 parser_genhdr
.set_defaults(which
='genhdr')
824 parser_genhdr
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
825 parser_genhdr
.add_argument('-o', '--outdir' , dest
='OutputDir', type=str, help='Output directory path', default
= '.')
826 parser_genhdr
.add_argument('-n', '--hfile', dest
='HFileName', type=str, help='Output header file name', default
= '')
828 parser_info
= subparsers
.add_parser('info', help='display FSP information')
829 parser_info
.set_defaults(which
='info')
830 parser_info
.add_argument('-f', '--fspbin' , dest
='FspBinary', type=str, help='FSP binary file path', required
= True)
832 args
= parser
.parse_args()
833 if args
.which
in ['rebase', 'split', 'genhdr', 'info']:
834 if not os
.path
.exists(args
.FspBinary
):
835 raise Exception ("ERROR: Could not locate FSP binary file '%s' !" % args
.FspBinary
)
836 if hasattr(args
, 'OutputDir') and not os
.path
.exists(args
.OutputDir
):
837 raise Exception ("ERROR: Invalid output directory '%s' !" % args
.OutputDir
)
839 if args
.which
== 'rebase':
840 RebaseFspBin (args
.FspBinary
, args
.FspComponent
, args
.FspBase
, args
.OutputDir
, args
.OutputFile
)
841 elif args
.which
== 'split':
842 SplitFspBin (args
.FspBinary
, args
.OutputDir
, args
.NameTemplate
)
843 elif args
.which
== 'genhdr':
844 GenFspHdr (args
.FspBinary
, args
.OutputDir
, args
.HFileName
)
845 elif args
.which
== 'info':
846 ShowFspInfo (args
.FspBinary
)
852 if __name__
== '__main__':