]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/SplitFspBin.py
Make [-D Macros] as optional argument for GenCfgOpt
[mirror_edk2.git] / IntelFsp2Pkg / Tools / SplitFspBin.py
1 ## @ FspTool.py
2 #
3 # Copyright (c) 2015 - 2016, 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.
8 #
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.
11 #
12 ##
13
14 import os
15 import sys
16 import uuid
17 import copy
18 import struct
19 import argparse
20 from ctypes import *
21
22 """
23 This utility supports some operations for Intel FSP 2.0 image.
24 It supports:
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
29 """
30
31 CopyRightHeaderFile = """/*
32 *
33 * Automatically generated file; DO NOT EDIT.
34 * FSP mapping file
35 *
36 */
37 """
38
39 class c_uint24(Structure):
40 """Little-Endian 24-bit Unsigned Integer"""
41 _pack_ = 1
42 _fields_ = [('Data', (c_uint8 * 3))]
43
44 def __init__(self, val=0):
45 self.set_value(val)
46
47 def __str__(self, indent=0):
48 return '0x%.6x' % self.value
49
50 def __int__(self):
51 return self.get_value()
52
53 def set_value(self, val):
54 self.Data[0:3] = Val2Bytes(val, 3)
55
56 def get_value(self):
57 return Bytes2Val(self.Data[0:3])
58
59 value = property(get_value, set_value)
60
61 class EFI_FIRMWARE_VOLUME_HEADER(Structure):
62 _fields_ = [
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),
72 ('Revision', c_uint8)
73 ]
74
75 class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure):
76 _fields_ = [
77 ('FvName', ARRAY(c_uint8, 16)),
78 ('ExtHeaderSize', c_uint32)
79 ]
80
81 class EFI_FFS_INTEGRITY_CHECK(Structure):
82 _fields_ = [
83 ('Header', c_uint8),
84 ('File', c_uint8)
85 ]
86
87 class EFI_FFS_FILE_HEADER(Structure):
88 _fields_ = [
89 ('Name', ARRAY(c_uint8, 16)),
90 ('IntegrityCheck', EFI_FFS_INTEGRITY_CHECK),
91 ('Type', c_uint8),
92 ('Attributes', c_uint8),
93 ('Size', c_uint24),
94 ('State', c_uint8)
95 ]
96
97 class EFI_COMMON_SECTION_HEADER(Structure):
98 _fields_ = [
99 ('Size', c_uint24),
100 ('Type', c_uint8)
101 ]
102
103 class FSP_COMMON_HEADER(Structure):
104 _fields_ = [
105 ('Signature', ARRAY(c_char, 4)),
106 ('HeaderLength', c_uint32)
107 ]
108
109 class FSP_INFORMATION_HEADER(Structure):
110 _fields_ = [
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)
131 ]
132
133 class FSP_PATCH_TABLE(Structure):
134 _fields_ = [
135 ('Signature', ARRAY(c_char, 4)),
136 ('HeaderLength', c_uint16),
137 ('HeaderRevision', c_uint8),
138 ('Reserved', c_uint8),
139 ('PatchEntryNum', c_uint32)
140 ]
141
142 class EFI_IMAGE_DATA_DIRECTORY(Structure):
143 _fields_ = [
144 ('VirtualAddress', c_uint32),
145 ('Size', c_uint32)
146 ]
147
148 class EFI_TE_IMAGE_HEADER(Structure):
149 _fields_ = [
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)
160 ]
161
162 class EFI_IMAGE_DOS_HEADER(Structure):
163 _fields_ = [
164 ('e_magic', c_uint16),
165 ('e_cblp', c_uint16),
166 ('e_cp', c_uint16),
167 ('e_crlc', c_uint16),
168 ('e_cparhdr', c_uint16),
169 ('e_minalloc', c_uint16),
170 ('e_maxalloc', c_uint16),
171 ('e_ss', c_uint16),
172 ('e_sp', c_uint16),
173 ('e_csum', c_uint16),
174 ('e_ip', c_uint16),
175 ('e_cs', 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)
183 ]
184
185 class EFI_IMAGE_FILE_HEADER(Structure):
186 _fields_ = [
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)
194 ]
195
196 class PE_RELOC_BLOCK_HEADER(Structure):
197 _fields_ = [
198 ('PageRVA', c_uint32),
199 ('BlockSize', c_uint32)
200 ]
201
202 class EFI_IMAGE_OPTIONAL_HEADER32(Structure):
203 _fields_ = [
204 ('Magic', c_uint16),
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))
235 ]
236
237 class EFI_IMAGE_NT_HEADERS32(Structure):
238 _fields_ = [
239 ('Signature', c_uint32),
240 ('FileHeader', EFI_IMAGE_FILE_HEADER),
241 ('OptionalHeader', EFI_IMAGE_OPTIONAL_HEADER32)
242 ]
243
244
245 class EFI_IMAGE_DIRECTORY_ENTRY:
246 EXPORT = 0
247 IMPORT = 1
248 RESOURCE = 2
249 EXCEPTION = 3
250 SECURITY = 4
251 BASERELOC = 5
252 DEBUG = 6
253 COPYRIGHT = 7
254 GLOBALPTR = 8
255 TLS = 9
256 LOAD_CONFIG = 10
257
258 class EFI_FV_FILETYPE:
259 ALL = 0x00
260 RAW = 0x01
261 FREEFORM = 0x02
262 SECURITY_CORE = 0x03
263 PEI_CORE = 0x04
264 DXE_CORE = 0x05
265 PEIM = 0x06
266 DRIVER = 0x07
267 COMBINED_PEIM_DRIVER = 0x08
268 APPLICATION = 0x09
269 SMM = 0x0a
270 FIRMWARE_VOLUME_IMAGE = 0x0b
271 COMBINED_SMM_DXE = 0x0c
272 SMM_CORE = 0x0d
273 OEM_MIN = 0xc0
274 OEM_MAX = 0xdf
275 DEBUG_MIN = 0xe0
276 DEBUG_MAX = 0xef
277 FFS_MIN = 0xf0
278 FFS_MAX = 0xff
279 FFS_PAD = 0xf0
280
281 class EFI_SECTION_TYPE:
282 """Enumeration of all valid firmware file section types."""
283 ALL = 0x00
284 COMPRESSION = 0x01
285 GUID_DEFINED = 0x02
286 DISPOSABLE = 0x03
287 PE32 = 0x10
288 PIC = 0x11
289 TE = 0x12
290 DXE_DEPEX = 0x13
291 VERSION = 0x14
292 USER_INTERFACE = 0x15
293 COMPATIBILITY16 = 0x16
294 FIRMWARE_VOLUME_IMAGE = 0x17
295 FREEFORM_SUBTYPE_GUID = 0x18
296 RAW = 0x19
297 PEI_DEPEX = 0x1b
298 SMM_DEPEX = 0x1c
299
300 def AlignPtr (offset, alignment = 8):
301 return (offset + alignment - 1) & ~(alignment - 1)
302
303 def Bytes2Val (bytes):
304 return reduce(lambda x,y: (x<<8)|y, bytes[::-1] )
305
306 def Val2Bytes (value, blen):
307 return [(value>>(i*8) & 0xff) for i in range(blen)]
308
309 def OutputStruct (obj, indent = 0, plen = 0):
310 if indent:
311 body = ''
312 else:
313 body = (' ' * indent + '<%s>:\n') % obj.__class__.__name__
314
315 if plen == 0:
316 plen = sizeof(obj)
317
318 max_key_len = 26
319 pstr = (' ' * (indent + 1) + '{0:<%d} = {1}\n') % max_key_len
320
321 for field in obj._fields_:
322 key = field[0]
323 val = getattr(obj, key)
324 rep = ''
325 if not isinstance(val, c_uint24) and isinstance(val, Structure):
326 body += pstr.format(key, val.__class__.__name__)
327 body += OutputStruct (val, indent + 1)
328 plen -= sizeof(val)
329 else:
330 if type(val) is str:
331 rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val)
332 elif type(val) in (int, long):
333 rep = '0x%X' % val
334 elif isinstance(val, c_uint24):
335 rep = '0x%X' % val.get_value()
336 elif 'c_ubyte_Array' in str(type(val)):
337 if sizeof(val) == 16:
338 rep = str(uuid.UUID(bytes = str(bytearray(val)))).upper()
339 else:
340 res = ['0x%02X'%i for i in bytearray(val)]
341 rep = '[%s]' % (','.join(res))
342 else:
343 rep = str(val)
344 plen -= sizeof(field[1])
345 body += pstr.format(key, rep)
346 if plen <= 0:
347 break
348 return body
349
350 class Section:
351 def __init__(self, offset, secdata):
352 self.SecHdr = EFI_COMMON_SECTION_HEADER.from_buffer (secdata, 0)
353 self.SecData = secdata[0:int(self.SecHdr.Size)]
354 self.Offset = offset
355
356 class FirmwareFile:
357 def __init__(self, offset, filedata):
358 self.FfsHdr = EFI_FFS_FILE_HEADER.from_buffer (filedata, 0)
359 self.FfsData = filedata[0:int(self.FfsHdr.Size)]
360 self.Offset = offset
361 self.SecList = []
362
363 def ParseFfs(self):
364 ffssize = len(self.FfsData)
365 offset = sizeof(self.FfsHdr)
366 if self.FfsHdr.Name != '\xff' * 16:
367 while offset < ffssize:
368 sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset)
369 sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)])
370 self.SecList.append(sec)
371 offset += int(sechdr.Size)
372 offset = AlignPtr(offset, 4)
373
374 class FirmwareVolume:
375 def __init__(self, offset, fvdata):
376 self.FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (fvdata, 0)
377 self.FvData = fvdata[0 : self.FvHdr.FvLength]
378 self.Offset = offset
379 if self.FvHdr.ExtHeaderOffset > 0:
380 self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset)
381 else:
382 self.FvExtHdr = None
383 self.FfsList = []
384
385 def ParseFv(self):
386 fvsize = len(self.FvData)
387 if self.FvExtHdr:
388 offset = self.FvHdr.ExtHeaderOffset + self.FvExtHdr.ExtHeaderSize
389 else:
390 offset = self.FvHdr.HeaderLength
391 offset = AlignPtr(offset)
392 while offset < fvsize:
393 ffshdr = EFI_FFS_FILE_HEADER.from_buffer (self.FvData, offset)
394 if (ffshdr.Name == '\xff' * 16) and (int(ffshdr.Size) == 0xFFFFFF):
395 offset = fvsize
396 else:
397 ffs = FirmwareFile (offset, self.FvData[offset:offset + int(ffshdr.Size)])
398 ffs.ParseFfs()
399 self.FfsList.append(ffs)
400 offset += int(ffshdr.Size)
401 offset = AlignPtr(offset)
402
403 class FspImage:
404 def __init__(self, offset, fih, fihoff, patch):
405 self.Fih = fih
406 self.FihOffset = fihoff
407 self.Offset = offset
408 self.FvIdxList = []
409 self.Type = "XTMSXXXXOXXXXXXX"[(fih.ComponentAttribute >> 12) & 0x0F]
410 self.PatchList = patch
411 self.PatchList.append(fihoff + 0x1C)
412
413 def AppendFv(self, FvIdx):
414 self.FvIdxList.append(FvIdx)
415
416 def Patch(self, delta, fdbin):
417 count = 0
418 applied = 0
419 for idx, patch in enumerate(self.PatchList):
420 ptype = (patch>>24) & 0x0F
421 if ptype not in [0x00, 0x0F]:
422 raise Exception('ERROR: Invalid patch type %d !' % ptype)
423 if patch & 0x80000000:
424 patch = self.Fih.ImageSize - (0x1000000 - (patch & 0xFFFFFF))
425 else:
426 patch = patch & 0xFFFFFF
427 if (patch < self.Fih.ImageSize) and (patch + sizeof(c_uint32) <= self.Fih.ImageSize):
428 offset = patch + self.Offset
429 value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint32)])
430 value += delta
431 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
432 applied += 1
433 count += 1
434 # Don't count the FSP base address patch entry appended at the end
435 if count != 0:
436 count -= 1
437 applied -= 1
438 return (count, applied)
439
440 class FirmwareDevice:
441 def __init__(self, offset, fdfile):
442 self.FvList = []
443 self.FspList = []
444 self.FdFile = fdfile
445 self.Offset = 0
446 hfsp = open (self.FdFile, 'rb')
447 self.FdData = bytearray(hfsp.read())
448 hfsp.close()
449
450 def ParseFd(self):
451 offset = 0
452 fdsize = len(self.FdData)
453 self.FvList = []
454 while offset < fdsize:
455 fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset)
456 if '_FVH' != fvh.Signature:
457 raise Exception("ERROR: Invalid FV header !")
458 fv = FirmwareVolume (offset, self.FdData[offset:offset + fvh.FvLength])
459 fv.ParseFv ()
460 self.FvList.append(fv)
461 offset += fv.FvHdr.FvLength
462
463 def CheckFsp (self):
464 if len(self.FspList) == 0:
465 return
466
467 fih = None
468 for fsp in self.FspList:
469 if fsp.Fih.HeaderRevision < 3:
470 raise Exception("ERROR: FSP 1.x is not supported by this tool !")
471 if not fih:
472 fih = fsp.Fih
473 else:
474 newfih = fsp.Fih
475 if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):
476 raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
477
478 def ParseFsp(self):
479 flen = 0
480 for idx, fv in enumerate(self.FvList):
481 # Check if this FV contains FSP header
482 if flen == 0:
483 if len(fv.FfsList) == 0:
484 continue
485 ffs = fv.FfsList[0]
486 if len(ffs.SecList) == 0:
487 continue
488 sec = ffs.SecList[0]
489 if sec.SecHdr.Type != EFI_SECTION_TYPE.RAW:
490 continue
491 fihoffset = ffs.Offset + sec.Offset + sizeof(sec.SecHdr)
492 fspoffset = fv.Offset
493 offset = fspoffset + fihoffset
494 fih = FSP_INFORMATION_HEADER.from_buffer (self.FdData, offset)
495 if 'FSPH' != fih.Signature:
496 continue
497
498 offset += fih.HeaderLength
499 offset = AlignPtr(offset, 4)
500 plist = []
501 while True:
502 fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset)
503 if 'FSPP' != fch.Signature:
504 offset += fch.HeaderLength
505 offset = AlignPtr(offset, 4)
506 else:
507 fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset)
508 offset += sizeof(fspp)
509 pdata = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset)
510 plist = list(pdata)
511 break
512
513 fsp = FspImage (fspoffset, fih, fihoffset, plist)
514 fsp.AppendFv (idx)
515 self.FspList.append(fsp)
516 flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength
517 else:
518 fsp.AppendFv (idx)
519 flen -= fv.FvHdr.FvLength
520 if flen < 0:
521 raise Exception("ERROR: Incorrect FV size in image !")
522 self.CheckFsp ()
523
524 class PeTeImage:
525 def __init__(self, offset, data):
526 self.Offset = offset
527 tehdr = EFI_TE_IMAGE_HEADER.from_buffer (data, 0)
528 if tehdr.Signature == 'VZ': # TE image
529 self.TeHdr = tehdr
530 elif tehdr.Signature == 'MZ': # PE32 image
531 self.TeHdr = None
532 self.DosHdr = EFI_IMAGE_DOS_HEADER.from_buffer (data, 0)
533 self.PeHdr = EFI_IMAGE_NT_HEADERS32.from_buffer (data, self.DosHdr.e_lfanew)
534 if self.PeHdr.Signature != 0x4550:
535 raise Exception("ERROR: Invalid PE32 header !")
536 if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32.DataDirectory.offset:
537 raise Exception("ERROR: Unsupported PE32 image !")
538 if self.PeHdr.OptionalHeader.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:
539 raise Exception("ERROR: No relocation information available !")
540 self.Offset = offset
541 self.Data = data
542 self.RelocList = []
543
544 def IsTeImage(self):
545 return self.TeHdr is not None
546
547 def ParseReloc(self):
548 if self.IsTeImage():
549 rsize = self.TeHdr.DataDirectoryBaseReloc.Size
550 roffset = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress
551 else:
552 rsize = self.PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size
553 roffset = self.PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress
554
555 alignment = 4
556 offset = roffset
557 while offset < roffset + rsize:
558 offset = AlignPtr(offset, 4)
559 blkhdr = PE_RELOC_BLOCK_HEADER.from_buffer(self.Data, offset)
560 offset += sizeof(blkhdr)
561 # Read relocation type,offset pairs
562 rlen = blkhdr.BlockSize - sizeof(PE_RELOC_BLOCK_HEADER)
563 rnum = rlen/sizeof(c_uint16)
564 rdata = (c_uint16 * rnum).from_buffer(self.Data, offset)
565 for each in rdata:
566 roff = each & 0xfff
567 rtype = each >> 12
568 if rtype == 0: # IMAGE_REL_BASED.ABSOLUTE:
569 continue
570 if rtype != 3: # IMAGE_REL_BASED_HIGHLOW
571 raise Exception("ERROR: Unsupported relocation type %d!" % rtype)
572 # Calculate the offset of the relocation
573 aoff = blkhdr.PageRVA + roff
574 if self.IsTeImage():
575 aoff += sizeof(self.TeHdr) - self.TeHdr.StrippedSize
576 self.RelocList.append((rtype, aoff))
577 offset += sizeof(rdata)
578
579 def Rebase(self, delta, fdbin):
580 count = 0
581 if delta == 0:
582 return count
583
584 for (rtype, roff) in self.RelocList:
585 if rtype == 0x03: # HIGHLOW
586 offset = roff + self.Offset
587 value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint32)])
588 value += delta
589 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
590 count += 1
591 else:
592 raise Exception('ERROR: Unknown relocation type %d !' % rtype)
593
594 if self.IsTeImage():
595 offset = self.Offset + EFI_TE_IMAGE_HEADER.ImageBase.offset
596 size = EFI_TE_IMAGE_HEADER.ImageBase.size
597 else:
598 offset = self.Offset + self.DosHdr.e_lfanew
599 offset += EFI_IMAGE_NT_HEADERS32.OptionalHeader.offset
600 offset += EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.offset
601 size = EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.size
602
603 value = Bytes2Val(fdbin[offset:offset+size]) + delta
604 fdbin[offset:offset+size] = Val2Bytes(value, size)
605
606 return count
607
608 def ShowFspInfo (fspfile):
609 fd = FirmwareDevice(0, fspfile)
610 fd.ParseFd ()
611 fd.ParseFsp ()
612
613 print ("\nFound the following %d Firmware Volumes in FSP binary:" % (len(fd.FvList)))
614 for idx, fv in enumerate(fd.FvList):
615 name = fv.FvExtHdr.FvName
616 if not name:
617 name = '\xff' * 16
618 else:
619 name = str(bytearray(name))
620 guid = uuid.UUID(bytes = name)
621 print ("FV%d:" % idx)
622 print (" GUID : %s" % str(guid).upper())
623 print (" Offset : 0x%08X" % fv.Offset)
624 print (" Length : 0x%08X" % fv.FvHdr.FvLength)
625 print ("\n")
626
627 for fsp in fd.FspList:
628 fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList)
629 print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist)))
630 print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength)))
631
632 def GenFspHdr (fspfile, outdir, hfile):
633 fd = FirmwareDevice(0, fspfile)
634 fd.ParseFd ()
635 fd.ParseFsp ()
636
637 if not hfile:
638 hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h'
639 fspname, ext = os.path.splitext(os.path.basename(hfile))
640 filename = os.path.join(outdir, fspname + ext)
641 hfsp = open(filename, 'w')
642 hfsp.write ('%s\n\n' % CopyRightHeaderFile)
643
644 firstfv = True
645 for fsp in fd.FspList:
646 fih = fsp.Fih
647 if firstfv:
648 hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId))
649 hfsp.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih.ImageRevision)
650 firstfv = False
651 fv = fd.FvList[fsp.FvIdxList[0]]
652 hfsp.write ('#define FSP%s_BASE 0x%08X\n' % (fsp.Type, fih.ImageBase))
653 hfsp.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp.Type, fv.Offset))
654 hfsp.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp.Type, fih.ImageSize))
655
656 hfsp.close()
657
658 def SplitFspBin (fspfile, outdir, nametemplate):
659 fd = FirmwareDevice(0, fspfile)
660 fd.ParseFd ()
661 fd.ParseFsp ()
662
663 for fsp in fd.FspList:
664 ftype = fsp.Type
665 if not nametemplate:
666 nametemplate = fspfile
667 fspname, ext = os.path.splitext(os.path.basename(nametemplate))
668 filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext)
669 hfsp = open(filename, 'wb')
670 print ("Ceate FSP component file '%s'" % filename)
671 for fvidx in fsp.FvIdxList:
672 fv = fd.FvList[fvidx]
673 hfsp.write(fv.FvData)
674 hfsp.close()
675
676 def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile):
677 fd = FirmwareDevice(0, FspBinary)
678 fd.ParseFd ()
679 fd.ParseFsp ()
680
681 numcomp = len(FspComponent)
682 baselist = FspBase
683 if numcomp != len(baselist):
684 print "ERROR: Required number of base does not match number of FSP component !"
685 return
686
687 newfspbin = fd.FdData[:]
688
689 for idx, fspcomp in enumerate(FspComponent):
690
691 found = False
692 for fsp in fd.FspList:
693 ftype = fsp.Type.lower()
694 if ftype == fspcomp:
695 found = True
696 break
697
698 if not found:
699 print "ERROR: Could not find FSP_%c component to rebase !" % fspcomp.upper()
700 return
701
702 fspbase = baselist[idx]
703 if fspbase.startswith('0x'):
704 newbase = int(fspbase, 16)
705 else:
706 newbase = int(fspbase)
707 oldbase = fsp.Fih.ImageBase
708 delta = newbase - oldbase
709 print "Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype.upper(),oldbase,newbase)
710
711 imglist = []
712 for fvidx in fsp.FvIdxList:
713 fv = fd.FvList[fvidx]
714 for ffs in fv.FfsList:
715 for sec in ffs.SecList:
716 if sec.SecHdr.Type in [EFI_SECTION_TYPE.TE, EFI_SECTION_TYPE.PE32]: # TE or PE32
717 offset = fd.Offset + fv.Offset + ffs.Offset + sec.Offset + sizeof(sec.SecHdr)
718 imglist.append ((offset, len(sec.SecData) - sizeof(sec.SecHdr)))
719
720 fcount = 0
721 pcount = 0
722 for (offset, length) in imglist:
723 img = PeTeImage(offset, fd.FdData[offset:offset + length])
724 img.ParseReloc()
725 pcount += img.Rebase(delta, newfspbin)
726 fcount += 1
727
728 print " Patched %d entries in %d TE/PE32 images." % (pcount, fcount)
729
730 (count, applied) = fsp.Patch(delta, newfspbin)
731 print " Patched %d entries using FSP patch table." % applied
732 if count != applied:
733 print " %d invalid entries are ignored !" % (count - applied)
734
735 if OutputFile == '':
736 filename = os.path.basename(FspBinary)
737 base, ext = os.path.splitext(filename)
738 OutputFile = base + "_%08X" % newbase + ext
739
740 fspname, ext = os.path.splitext(os.path.basename(OutputFile))
741 filename = os.path.join(OutputDir, fspname + ext)
742 fd = open(filename, "wb")
743 fd.write(newfspbin)
744 fd.close()
745
746 def main ():
747 parser = argparse.ArgumentParser()
748 subparsers = parser.add_subparsers(title='commands')
749
750 parser_rebase = subparsers.add_parser('rebase', help='rebase a FSP into a new base address')
751 parser_rebase.set_defaults(which='rebase')
752 parser_rebase.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
753 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)
754 parser_rebase.add_argument('-b', '--newbase', dest='FspBase', nargs='+', type=str, help='Rebased FSP binary file name', default = '', required = True)
755 parser_rebase.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
756 parser_rebase.add_argument('-n', '--outfile', dest='OutputFile', type=str, help='Rebased FSP binary file name', default = '')
757
758 parser_split = subparsers.add_parser('split', help='split a FSP into multiple components')
759 parser_split.set_defaults(which='split')
760 parser_split.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
761 parser_split.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
762 parser_split.add_argument('-n', '--nametpl', dest='NameTemplate', type=str, help='Output name template', default = '')
763
764 parser_genhdr = subparsers.add_parser('genhdr', help='generate a header file for FSP binary')
765 parser_genhdr.set_defaults(which='genhdr')
766 parser_genhdr.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
767 parser_genhdr.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
768 parser_genhdr.add_argument('-n', '--hfile', dest='HFileName', type=str, help='Output header file name', default = '')
769
770 parser_info = subparsers.add_parser('info', help='display FSP information')
771 parser_info.set_defaults(which='info')
772 parser_info.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
773
774 args = parser.parse_args()
775 if args.which in ['rebase', 'split', 'genhdr', 'info']:
776 if not os.path.exists(args.FspBinary):
777 raise Exception ("ERROR: Could not locate FSP binary file '%s' !" % args.FspBinary)
778 if hasattr(args, 'OutputDir') and not os.path.exists(args.OutputDir):
779 raise Exception ("ERROR: Invalid output directory '%s' !" % args.OutputDir)
780
781 if args.which == 'rebase':
782 RebaseFspBin (args.FspBinary, args.FspComponent, args.FspBase, args.OutputDir, args.OutputFile)
783 elif args.which == 'split':
784 SplitFspBin (args.FspBinary, args.OutputDir, args.NameTemplate)
785 elif args.which == 'genhdr':
786 GenFspHdr (args.FspBinary, args.OutputDir, args.HFileName)
787 elif args.which == 'info':
788 ShowFspInfo (args.FspBinary)
789 else:
790 pass
791
792 return 0
793
794 if __name__ == '__main__':
795 sys.exit(main())