]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/SplitFspBin.py
IntelFsp2Pkg/SplitFspBin.py: Support rebasing 1.x binary.
[mirror_edk2.git] / IntelFsp2Pkg / Tools / SplitFspBin.py
1 ## @ FspTool.py
2 #
3 # Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
4 # SPDX-License-Identifier: BSD-2-Clause-Patent
5 #
6 ##
7
8 import os
9 import sys
10 import uuid
11 import copy
12 import struct
13 import argparse
14 from ctypes import *
15
16 """
17 This utility supports some operations for Intel FSP 1.x/2.x image.
18 It supports:
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
23 """
24
25 CopyRightHeaderFile = """/*
26 *
27 * Automatically generated file; DO NOT EDIT.
28 * FSP mapping file
29 *
30 */
31 """
32
33 class c_uint24(Structure):
34 """Little-Endian 24-bit Unsigned Integer"""
35 _pack_ = 1
36 _fields_ = [('Data', (c_uint8 * 3))]
37
38 def __init__(self, val=0):
39 self.set_value(val)
40
41 def __str__(self, indent=0):
42 return '0x%.6x' % self.value
43
44 def __int__(self):
45 return self.get_value()
46
47 def set_value(self, val):
48 self.Data[0:3] = Val2Bytes(val, 3)
49
50 def get_value(self):
51 return Bytes2Val(self.Data[0:3])
52
53 value = property(get_value, set_value)
54
55 class EFI_FIRMWARE_VOLUME_HEADER(Structure):
56 _fields_ = [
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),
66 ('Revision', c_uint8)
67 ]
68
69 class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure):
70 _fields_ = [
71 ('FvName', ARRAY(c_uint8, 16)),
72 ('ExtHeaderSize', c_uint32)
73 ]
74
75 class EFI_FFS_INTEGRITY_CHECK(Structure):
76 _fields_ = [
77 ('Header', c_uint8),
78 ('File', c_uint8)
79 ]
80
81 class EFI_FFS_FILE_HEADER(Structure):
82 _fields_ = [
83 ('Name', ARRAY(c_uint8, 16)),
84 ('IntegrityCheck', EFI_FFS_INTEGRITY_CHECK),
85 ('Type', c_uint8),
86 ('Attributes', c_uint8),
87 ('Size', c_uint24),
88 ('State', c_uint8)
89 ]
90
91 class EFI_COMMON_SECTION_HEADER(Structure):
92 _fields_ = [
93 ('Size', c_uint24),
94 ('Type', c_uint8)
95 ]
96
97 class FSP_COMMON_HEADER(Structure):
98 _fields_ = [
99 ('Signature', ARRAY(c_char, 4)),
100 ('HeaderLength', c_uint32)
101 ]
102
103 class FSP_INFORMATION_HEADER(Structure):
104 _fields_ = [
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)
125 ]
126
127 class FSP_PATCH_TABLE(Structure):
128 _fields_ = [
129 ('Signature', ARRAY(c_char, 4)),
130 ('HeaderLength', c_uint16),
131 ('HeaderRevision', c_uint8),
132 ('Reserved', c_uint8),
133 ('PatchEntryNum', c_uint32)
134 ]
135
136 class EFI_IMAGE_DATA_DIRECTORY(Structure):
137 _fields_ = [
138 ('VirtualAddress', c_uint32),
139 ('Size', c_uint32)
140 ]
141
142 class EFI_TE_IMAGE_HEADER(Structure):
143 _fields_ = [
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)
154 ]
155
156 class EFI_IMAGE_DOS_HEADER(Structure):
157 _fields_ = [
158 ('e_magic', c_uint16),
159 ('e_cblp', c_uint16),
160 ('e_cp', c_uint16),
161 ('e_crlc', c_uint16),
162 ('e_cparhdr', c_uint16),
163 ('e_minalloc', c_uint16),
164 ('e_maxalloc', c_uint16),
165 ('e_ss', c_uint16),
166 ('e_sp', c_uint16),
167 ('e_csum', c_uint16),
168 ('e_ip', c_uint16),
169 ('e_cs', 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)
177 ]
178
179 class EFI_IMAGE_FILE_HEADER(Structure):
180 _fields_ = [
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)
188 ]
189
190 class PE_RELOC_BLOCK_HEADER(Structure):
191 _fields_ = [
192 ('PageRVA', c_uint32),
193 ('BlockSize', c_uint32)
194 ]
195
196 class EFI_IMAGE_OPTIONAL_HEADER32(Structure):
197 _fields_ = [
198 ('Magic', c_uint16),
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))
229 ]
230
231 class EFI_IMAGE_OPTIONAL_HEADER32_PLUS(Structure):
232 _fields_ = [
233 ('Magic', c_uint16),
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))
263 ]
264
265 class EFI_IMAGE_OPTIONAL_HEADER(Union):
266 _fields_ = [
267 ('PeOptHdr', EFI_IMAGE_OPTIONAL_HEADER32),
268 ('PePlusOptHdr', EFI_IMAGE_OPTIONAL_HEADER32_PLUS)
269 ]
270
271 class EFI_IMAGE_NT_HEADERS32(Structure):
272 _fields_ = [
273 ('Signature', c_uint32),
274 ('FileHeader', EFI_IMAGE_FILE_HEADER),
275 ('OptionalHeader', EFI_IMAGE_OPTIONAL_HEADER)
276 ]
277
278
279 class EFI_IMAGE_DIRECTORY_ENTRY:
280 EXPORT = 0
281 IMPORT = 1
282 RESOURCE = 2
283 EXCEPTION = 3
284 SECURITY = 4
285 BASERELOC = 5
286 DEBUG = 6
287 COPYRIGHT = 7
288 GLOBALPTR = 8
289 TLS = 9
290 LOAD_CONFIG = 10
291
292 class EFI_FV_FILETYPE:
293 ALL = 0x00
294 RAW = 0x01
295 FREEFORM = 0x02
296 SECURITY_CORE = 0x03
297 PEI_CORE = 0x04
298 DXE_CORE = 0x05
299 PEIM = 0x06
300 DRIVER = 0x07
301 COMBINED_PEIM_DRIVER = 0x08
302 APPLICATION = 0x09
303 SMM = 0x0a
304 FIRMWARE_VOLUME_IMAGE = 0x0b
305 COMBINED_SMM_DXE = 0x0c
306 SMM_CORE = 0x0d
307 OEM_MIN = 0xc0
308 OEM_MAX = 0xdf
309 DEBUG_MIN = 0xe0
310 DEBUG_MAX = 0xef
311 FFS_MIN = 0xf0
312 FFS_MAX = 0xff
313 FFS_PAD = 0xf0
314
315 class EFI_SECTION_TYPE:
316 """Enumeration of all valid firmware file section types."""
317 ALL = 0x00
318 COMPRESSION = 0x01
319 GUID_DEFINED = 0x02
320 DISPOSABLE = 0x03
321 PE32 = 0x10
322 PIC = 0x11
323 TE = 0x12
324 DXE_DEPEX = 0x13
325 VERSION = 0x14
326 USER_INTERFACE = 0x15
327 COMPATIBILITY16 = 0x16
328 FIRMWARE_VOLUME_IMAGE = 0x17
329 FREEFORM_SUBTYPE_GUID = 0x18
330 RAW = 0x19
331 PEI_DEPEX = 0x1b
332 SMM_DEPEX = 0x1c
333
334 def AlignPtr (offset, alignment = 8):
335 return (offset + alignment - 1) & ~(alignment - 1)
336
337 def Bytes2Val (bytes):
338 return reduce(lambda x,y: (x<<8)|y, bytes[::-1] )
339
340 def Val2Bytes (value, blen):
341 return [(value>>(i*8) & 0xff) for i in range(blen)]
342
343 def OutputStruct (obj, indent = 0, plen = 0):
344 if indent:
345 body = ''
346 else:
347 body = (' ' * indent + '<%s>:\n') % obj.__class__.__name__
348
349 if plen == 0:
350 plen = sizeof(obj)
351
352 max_key_len = 26
353 pstr = (' ' * (indent + 1) + '{0:<%d} = {1}\n') % max_key_len
354
355 for field in obj._fields_:
356 key = field[0]
357 val = getattr(obj, key)
358 rep = ''
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)
362 plen -= sizeof(val)
363 else:
364 if type(val) is str:
365 rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val)
366 elif type(val) in (int, long):
367 rep = '0x%X' % val
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()
373 else:
374 res = ['0x%02X'%i for i in bytearray(val)]
375 rep = '[%s]' % (','.join(res))
376 else:
377 rep = str(val)
378 plen -= sizeof(field[1])
379 body += pstr.format(key, rep)
380 if plen <= 0:
381 break
382 return body
383
384 class Section:
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)]
388 self.Offset = offset
389
390 class FirmwareFile:
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)]
394 self.Offset = offset
395 self.SecList = []
396
397 def ParseFfs(self):
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)
407
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]
412 self.Offset = offset
413 if self.FvHdr.ExtHeaderOffset > 0:
414 self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset)
415 else:
416 self.FvExtHdr = None
417 self.FfsList = []
418
419 def ParseFv(self):
420 fvsize = len(self.FvData)
421 if self.FvExtHdr:
422 offset = self.FvHdr.ExtHeaderOffset + self.FvExtHdr.ExtHeaderSize
423 else:
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):
429 offset = fvsize
430 else:
431 ffs = FirmwareFile (offset, self.FvData[offset:offset + int(ffshdr.Size)])
432 ffs.ParseFfs()
433 self.FfsList.append(ffs)
434 offset += int(ffshdr.Size)
435 offset = AlignPtr(offset)
436
437 class FspImage:
438 def __init__(self, offset, fih, fihoff, patch):
439 self.Fih = fih
440 self.FihOffset = fihoff
441 self.Offset = offset
442 self.FvIdxList = []
443 self.Type = "XTMSXXXXOXXXXXXX"[(fih.ComponentAttribute >> 12) & 0x0F]
444 self.PatchList = patch
445 self.PatchList.append(fihoff + 0x1C)
446
447 def AppendFv(self, FvIdx):
448 self.FvIdxList.append(FvIdx)
449
450 def Patch(self, delta, fdbin):
451 count = 0
452 applied = 0
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))
459 else:
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)])
464 value += delta
465 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
466 applied += 1
467 count += 1
468 # Don't count the FSP base address patch entry appended at the end
469 if count != 0:
470 count -= 1
471 applied -= 1
472 return (count, applied)
473
474 class FirmwareDevice:
475 def __init__(self, offset, fdfile):
476 self.FvList = []
477 self.FspList = []
478 self.FdFile = fdfile
479 self.Offset = 0
480 hfsp = open (self.FdFile, 'rb')
481 self.FdData = bytearray(hfsp.read())
482 hfsp.close()
483
484 def ParseFd(self):
485 offset = 0
486 fdsize = len(self.FdData)
487 self.FvList = []
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])
493 fv.ParseFv ()
494 self.FvList.append(fv)
495 offset += fv.FvHdr.FvLength
496
497 def CheckFsp (self):
498 if len(self.FspList) == 0:
499 return
500
501 fih = None
502 for fsp in self.FspList:
503 if not fih:
504 fih = fsp.Fih
505 else:
506 newfih = fsp.Fih
507 if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):
508 raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
509
510 def ParseFsp(self):
511 flen = 0
512 for idx, fv in enumerate(self.FvList):
513 # Check if this FV contains FSP header
514 if flen == 0:
515 if len(fv.FfsList) == 0:
516 continue
517 ffs = fv.FfsList[0]
518 if len(ffs.SecList) == 0:
519 continue
520 sec = ffs.SecList[0]
521 if sec.SecHdr.Type != EFI_SECTION_TYPE.RAW:
522 continue
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:
528 continue
529
530 offset += fih.HeaderLength
531 offset = AlignPtr(offset, 4)
532 plist = []
533 while True:
534 fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset)
535 if 'FSPP' != fch.Signature:
536 offset += fch.HeaderLength
537 offset = AlignPtr(offset, 4)
538 else:
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)
542 plist = list(pdata)
543 break
544
545 fsp = FspImage (fspoffset, fih, fihoffset, plist)
546 fsp.AppendFv (idx)
547 self.FspList.append(fsp)
548 flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength
549 else:
550 fsp.AppendFv (idx)
551 flen -= fv.FvHdr.FvLength
552 if flen < 0:
553 raise Exception("ERROR: Incorrect FV size in image !")
554 self.CheckFsp ()
555
556 class PeTeImage:
557 def __init__(self, offset, data):
558 self.Offset = offset
559 tehdr = EFI_TE_IMAGE_HEADER.from_buffer (data, 0)
560 if tehdr.Signature == 'VZ': # TE image
561 self.TeHdr = tehdr
562 elif tehdr.Signature == 'MZ': # PE image
563 self.TeHdr = None
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 !")
578 else:
579 raise Exception("ERROR: Invalid PE32 optional header !")
580 self.Offset = offset
581 self.Data = data
582 self.RelocList = []
583
584 def IsTeImage(self):
585 return self.TeHdr is not None
586
587 def ParseReloc(self):
588 if self.IsTeImage():
589 rsize = self.TeHdr.DataDirectoryBaseReloc.Size
590 roffset = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress
591 else:
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
598
599 alignment = 4
600 offset = roffset
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)
609 for each in rdata:
610 roff = each & 0xfff
611 rtype = each >> 12
612 if rtype == 0: # IMAGE_REL_BASED_ABSOLUTE:
613 continue
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
618 if self.IsTeImage():
619 aoff += sizeof(self.TeHdr) - self.TeHdr.StrippedSize
620 self.RelocList.append((rtype, aoff))
621 offset += sizeof(rdata)
622
623 def Rebase(self, delta, fdbin):
624 count = 0
625 if delta == 0:
626 return count
627
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)])
632 value += delta
633 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
634 count += 1
635 elif rtype == 10: # IMAGE_REL_BASED_DIR64
636 offset = roff + self.Offset
637 value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint64)])
638 value += delta
639 fdbin[offset:offset+sizeof(c_uint64)] = Val2Bytes(value, sizeof(c_uint64))
640 count += 1
641 else:
642 raise Exception('ERROR: Unknown relocation type %d !' % rtype)
643
644 if self.IsTeImage():
645 offset = self.Offset + EFI_TE_IMAGE_HEADER.ImageBase.offset
646 size = EFI_TE_IMAGE_HEADER.ImageBase.size
647 else:
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
652
653 value = Bytes2Val(fdbin[offset:offset+size]) + delta
654 fdbin[offset:offset+size] = Val2Bytes(value, size)
655
656 return count
657
658 def ShowFspInfo (fspfile):
659 fd = FirmwareDevice(0, fspfile)
660 fd.ParseFd ()
661 fd.ParseFsp ()
662
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
666 if not name:
667 name = '\xff' * 16
668 else:
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)
675 print ("\n")
676
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)))
681
682 def GenFspHdr (fspfile, outdir, hfile):
683 fd = FirmwareDevice(0, fspfile)
684 fd.ParseFd ()
685 fd.ParseFsp ()
686
687 if not hfile:
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)
693
694 firstfv = True
695 for fsp in fd.FspList:
696 fih = fsp.Fih
697 if firstfv:
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)
700 firstfv = False
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))
705
706 hfsp.close()
707
708 def SplitFspBin (fspfile, outdir, nametemplate):
709 fd = FirmwareDevice(0, fspfile)
710 fd.ParseFd ()
711 fd.ParseFsp ()
712
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 !")
716 ftype = fsp.Type
717 if not nametemplate:
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)
726 hfsp.close()
727
728 def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile):
729 fd = FirmwareDevice(0, FspBinary)
730 fd.ParseFd ()
731 fd.ParseFsp ()
732
733 numcomp = len(FspComponent)
734 baselist = FspBase
735 if numcomp != len(baselist):
736 print "ERROR: Required number of base does not match number of FSP component !"
737 return
738
739 newfspbin = fd.FdData[:]
740
741 for idx, fspcomp in enumerate(FspComponent):
742
743 found = False
744 for fsp in fd.FspList:
745 # Is this FSP 1.x single binary?
746 if fsp.Fih.HeaderRevision < 3:
747 found = True
748 ftype = 'X'
749 break
750 ftype = fsp.Type.lower()
751 if ftype == fspcomp:
752 found = True
753 break
754
755 if not found:
756 print "ERROR: Could not find FSP_%c component to rebase !" % fspcomp.upper()
757 return
758
759 fspbase = baselist[idx]
760 if fspbase.startswith('0x'):
761 newbase = int(fspbase, 16)
762 else:
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)
767
768 imglist = []
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)))
776
777 fcount = 0
778 pcount = 0
779 for (offset, length) in imglist:
780 img = PeTeImage(offset, fd.FdData[offset:offset + length])
781 img.ParseReloc()
782 pcount += img.Rebase(delta, newfspbin)
783 fcount += 1
784
785 print " Patched %d entries in %d TE/PE32 images." % (pcount, fcount)
786
787 (count, applied) = fsp.Patch(delta, newfspbin)
788 print " Patched %d entries using FSP patch table." % applied
789 if count != applied:
790 print " %d invalid entries are ignored !" % (count - applied)
791
792 if OutputFile == '':
793 filename = os.path.basename(FspBinary)
794 base, ext = os.path.splitext(filename)
795 OutputFile = base + "_%08X" % newbase + ext
796
797 fspname, ext = os.path.splitext(os.path.basename(OutputFile))
798 filename = os.path.join(OutputDir, fspname + ext)
799 fd = open(filename, "wb")
800 fd.write(newfspbin)
801 fd.close()
802
803 def main ():
804 parser = argparse.ArgumentParser()
805 subparsers = parser.add_subparsers(title='commands')
806
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 = '')
814
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 = '')
820
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 = '')
826
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)
830
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)
837
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)
846 else:
847 pass
848
849 return 0
850
851 if __name__ == '__main__':
852 sys.exit(main())