]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/SplitFspBin.py
IntelFsp2Pkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFsp2Pkg / Tools / SplitFspBin.py
1 ## @ FspTool.py
2 #
3 # Copyright (c) 2015 - 2018, 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 2.0 image.
18 It supports:
19 - Display FSP 2.0 information header
20 - Split FSP 2.0 image into individual FSP-T/M/S/O component
21 - Rebase FSP 2.0 components to a different base address
22 - Generate FSP 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 fsp.Fih.HeaderRevision < 3:
504 raise Exception("ERROR: FSP 1.x is not supported by this tool !")
505 if not fih:
506 fih = fsp.Fih
507 else:
508 newfih = fsp.Fih
509 if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):
510 raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
511
512 def ParseFsp(self):
513 flen = 0
514 for idx, fv in enumerate(self.FvList):
515 # Check if this FV contains FSP header
516 if flen == 0:
517 if len(fv.FfsList) == 0:
518 continue
519 ffs = fv.FfsList[0]
520 if len(ffs.SecList) == 0:
521 continue
522 sec = ffs.SecList[0]
523 if sec.SecHdr.Type != EFI_SECTION_TYPE.RAW:
524 continue
525 fihoffset = ffs.Offset + sec.Offset + sizeof(sec.SecHdr)
526 fspoffset = fv.Offset
527 offset = fspoffset + fihoffset
528 fih = FSP_INFORMATION_HEADER.from_buffer (self.FdData, offset)
529 if 'FSPH' != fih.Signature:
530 continue
531
532 offset += fih.HeaderLength
533 offset = AlignPtr(offset, 4)
534 plist = []
535 while True:
536 fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset)
537 if 'FSPP' != fch.Signature:
538 offset += fch.HeaderLength
539 offset = AlignPtr(offset, 4)
540 else:
541 fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset)
542 offset += sizeof(fspp)
543 pdata = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset)
544 plist = list(pdata)
545 break
546
547 fsp = FspImage (fspoffset, fih, fihoffset, plist)
548 fsp.AppendFv (idx)
549 self.FspList.append(fsp)
550 flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength
551 else:
552 fsp.AppendFv (idx)
553 flen -= fv.FvHdr.FvLength
554 if flen < 0:
555 raise Exception("ERROR: Incorrect FV size in image !")
556 self.CheckFsp ()
557
558 class PeTeImage:
559 def __init__(self, offset, data):
560 self.Offset = offset
561 tehdr = EFI_TE_IMAGE_HEADER.from_buffer (data, 0)
562 if tehdr.Signature == 'VZ': # TE image
563 self.TeHdr = tehdr
564 elif tehdr.Signature == 'MZ': # PE image
565 self.TeHdr = None
566 self.DosHdr = EFI_IMAGE_DOS_HEADER.from_buffer (data, 0)
567 self.PeHdr = EFI_IMAGE_NT_HEADERS32.from_buffer (data, self.DosHdr.e_lfanew)
568 if self.PeHdr.Signature != 0x4550:
569 raise Exception("ERROR: Invalid PE32 header !")
570 if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image
571 if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32.DataDirectory.offset:
572 raise Exception("ERROR: Unsupported PE32 image !")
573 if self.PeHdr.OptionalHeader.PeOptHdr.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:
574 raise Exception("ERROR: No relocation information available !")
575 elif self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x20b: # PE32+ image
576 if self.PeHdr.FileHeader.SizeOfOptionalHeader < EFI_IMAGE_OPTIONAL_HEADER32_PLUS.DataDirectory.offset:
577 raise Exception("ERROR: Unsupported PE32+ image !")
578 if self.PeHdr.OptionalHeader.PePlusOptHdr.NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC:
579 raise Exception("ERROR: No relocation information available !")
580 else:
581 raise Exception("ERROR: Invalid PE32 optional header !")
582 self.Offset = offset
583 self.Data = data
584 self.RelocList = []
585
586 def IsTeImage(self):
587 return self.TeHdr is not None
588
589 def ParseReloc(self):
590 if self.IsTeImage():
591 rsize = self.TeHdr.DataDirectoryBaseReloc.Size
592 roffset = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress
593 else:
594 if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image
595 rsize = self.PeHdr.OptionalHeader.PeOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size
596 roffset = self.PeHdr.OptionalHeader.PeOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress
597 if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x20b: # PE32+ image
598 rsize = self.PeHdr.OptionalHeader.PePlusOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].Size
599 roffset = self.PeHdr.OptionalHeader.PePlusOptHdr.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY.BASERELOC].VirtualAddress
600
601 alignment = 4
602 offset = roffset
603 while offset < roffset + rsize:
604 offset = AlignPtr(offset, 4)
605 blkhdr = PE_RELOC_BLOCK_HEADER.from_buffer(self.Data, offset)
606 offset += sizeof(blkhdr)
607 # Read relocation type,offset pairs
608 rlen = blkhdr.BlockSize - sizeof(PE_RELOC_BLOCK_HEADER)
609 rnum = rlen/sizeof(c_uint16)
610 rdata = (c_uint16 * rnum).from_buffer(self.Data, offset)
611 for each in rdata:
612 roff = each & 0xfff
613 rtype = each >> 12
614 if rtype == 0: # IMAGE_REL_BASED_ABSOLUTE:
615 continue
616 if ((rtype != 3) and (rtype != 10)): # IMAGE_REL_BASED_HIGHLOW and IMAGE_REL_BASED_DIR64
617 raise Exception("ERROR: Unsupported relocation type %d!" % rtype)
618 # Calculate the offset of the relocation
619 aoff = blkhdr.PageRVA + roff
620 if self.IsTeImage():
621 aoff += sizeof(self.TeHdr) - self.TeHdr.StrippedSize
622 self.RelocList.append((rtype, aoff))
623 offset += sizeof(rdata)
624
625 def Rebase(self, delta, fdbin):
626 count = 0
627 if delta == 0:
628 return count
629
630 for (rtype, roff) in self.RelocList:
631 if rtype == 3: # IMAGE_REL_BASED_HIGHLOW
632 offset = roff + self.Offset
633 value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint32)])
634 value += delta
635 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
636 count += 1
637 elif rtype == 10: # IMAGE_REL_BASED_DIR64
638 offset = roff + self.Offset
639 value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint64)])
640 value += delta
641 fdbin[offset:offset+sizeof(c_uint64)] = Val2Bytes(value, sizeof(c_uint64))
642 count += 1
643 else:
644 raise Exception('ERROR: Unknown relocation type %d !' % rtype)
645
646 if self.IsTeImage():
647 offset = self.Offset + EFI_TE_IMAGE_HEADER.ImageBase.offset
648 size = EFI_TE_IMAGE_HEADER.ImageBase.size
649 else:
650 offset = self.Offset + self.DosHdr.e_lfanew
651 offset += EFI_IMAGE_NT_HEADERS32.OptionalHeader.offset
652 offset += EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.offset
653 size = EFI_IMAGE_OPTIONAL_HEADER32.ImageBase.size
654
655 value = Bytes2Val(fdbin[offset:offset+size]) + delta
656 fdbin[offset:offset+size] = Val2Bytes(value, size)
657
658 return count
659
660 def ShowFspInfo (fspfile):
661 fd = FirmwareDevice(0, fspfile)
662 fd.ParseFd ()
663 fd.ParseFsp ()
664
665 print ("\nFound the following %d Firmware Volumes in FSP binary:" % (len(fd.FvList)))
666 for idx, fv in enumerate(fd.FvList):
667 name = fv.FvExtHdr.FvName
668 if not name:
669 name = '\xff' * 16
670 else:
671 name = str(bytearray(name))
672 guid = uuid.UUID(bytes = name)
673 print ("FV%d:" % idx)
674 print (" GUID : %s" % str(guid).upper())
675 print (" Offset : 0x%08X" % fv.Offset)
676 print (" Length : 0x%08X" % fv.FvHdr.FvLength)
677 print ("\n")
678
679 for fsp in fd.FspList:
680 fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList)
681 print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist)))
682 print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength)))
683
684 def GenFspHdr (fspfile, outdir, hfile):
685 fd = FirmwareDevice(0, fspfile)
686 fd.ParseFd ()
687 fd.ParseFsp ()
688
689 if not hfile:
690 hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h'
691 fspname, ext = os.path.splitext(os.path.basename(hfile))
692 filename = os.path.join(outdir, fspname + ext)
693 hfsp = open(filename, 'w')
694 hfsp.write ('%s\n\n' % CopyRightHeaderFile)
695
696 firstfv = True
697 for fsp in fd.FspList:
698 fih = fsp.Fih
699 if firstfv:
700 hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId))
701 hfsp.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih.ImageRevision)
702 firstfv = False
703 fv = fd.FvList[fsp.FvIdxList[0]]
704 hfsp.write ('#define FSP%s_BASE 0x%08X\n' % (fsp.Type, fih.ImageBase))
705 hfsp.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp.Type, fv.Offset))
706 hfsp.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp.Type, fih.ImageSize))
707
708 hfsp.close()
709
710 def SplitFspBin (fspfile, outdir, nametemplate):
711 fd = FirmwareDevice(0, fspfile)
712 fd.ParseFd ()
713 fd.ParseFsp ()
714
715 for fsp in fd.FspList:
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 ftype = fsp.Type.lower()
746 if ftype == fspcomp:
747 found = True
748 break
749
750 if not found:
751 print "ERROR: Could not find FSP_%c component to rebase !" % fspcomp.upper()
752 return
753
754 fspbase = baselist[idx]
755 if fspbase.startswith('0x'):
756 newbase = int(fspbase, 16)
757 else:
758 newbase = int(fspbase)
759 oldbase = fsp.Fih.ImageBase
760 delta = newbase - oldbase
761 print "Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype.upper(),oldbase,newbase)
762
763 imglist = []
764 for fvidx in fsp.FvIdxList:
765 fv = fd.FvList[fvidx]
766 for ffs in fv.FfsList:
767 for sec in ffs.SecList:
768 if sec.SecHdr.Type in [EFI_SECTION_TYPE.TE, EFI_SECTION_TYPE.PE32]: # TE or PE32
769 offset = fd.Offset + fv.Offset + ffs.Offset + sec.Offset + sizeof(sec.SecHdr)
770 imglist.append ((offset, len(sec.SecData) - sizeof(sec.SecHdr)))
771
772 fcount = 0
773 pcount = 0
774 for (offset, length) in imglist:
775 img = PeTeImage(offset, fd.FdData[offset:offset + length])
776 img.ParseReloc()
777 pcount += img.Rebase(delta, newfspbin)
778 fcount += 1
779
780 print " Patched %d entries in %d TE/PE32 images." % (pcount, fcount)
781
782 (count, applied) = fsp.Patch(delta, newfspbin)
783 print " Patched %d entries using FSP patch table." % applied
784 if count != applied:
785 print " %d invalid entries are ignored !" % (count - applied)
786
787 if OutputFile == '':
788 filename = os.path.basename(FspBinary)
789 base, ext = os.path.splitext(filename)
790 OutputFile = base + "_%08X" % newbase + ext
791
792 fspname, ext = os.path.splitext(os.path.basename(OutputFile))
793 filename = os.path.join(OutputDir, fspname + ext)
794 fd = open(filename, "wb")
795 fd.write(newfspbin)
796 fd.close()
797
798 def main ():
799 parser = argparse.ArgumentParser()
800 subparsers = parser.add_subparsers(title='commands')
801
802 parser_rebase = subparsers.add_parser('rebase', help='rebase a FSP into a new base address')
803 parser_rebase.set_defaults(which='rebase')
804 parser_rebase.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
805 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)
806 parser_rebase.add_argument('-b', '--newbase', dest='FspBase', nargs='+', type=str, help='Rebased FSP binary file name', default = '', required = True)
807 parser_rebase.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
808 parser_rebase.add_argument('-n', '--outfile', dest='OutputFile', type=str, help='Rebased FSP binary file name', default = '')
809
810 parser_split = subparsers.add_parser('split', help='split a FSP into multiple components')
811 parser_split.set_defaults(which='split')
812 parser_split.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
813 parser_split.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
814 parser_split.add_argument('-n', '--nametpl', dest='NameTemplate', type=str, help='Output name template', default = '')
815
816 parser_genhdr = subparsers.add_parser('genhdr', help='generate a header file for FSP binary')
817 parser_genhdr.set_defaults(which='genhdr')
818 parser_genhdr.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
819 parser_genhdr.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')
820 parser_genhdr.add_argument('-n', '--hfile', dest='HFileName', type=str, help='Output header file name', default = '')
821
822 parser_info = subparsers.add_parser('info', help='display FSP information')
823 parser_info.set_defaults(which='info')
824 parser_info.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)
825
826 args = parser.parse_args()
827 if args.which in ['rebase', 'split', 'genhdr', 'info']:
828 if not os.path.exists(args.FspBinary):
829 raise Exception ("ERROR: Could not locate FSP binary file '%s' !" % args.FspBinary)
830 if hasattr(args, 'OutputDir') and not os.path.exists(args.OutputDir):
831 raise Exception ("ERROR: Invalid output directory '%s' !" % args.OutputDir)
832
833 if args.which == 'rebase':
834 RebaseFspBin (args.FspBinary, args.FspComponent, args.FspBase, args.OutputDir, args.OutputFile)
835 elif args.which == 'split':
836 SplitFspBin (args.FspBinary, args.OutputDir, args.NameTemplate)
837 elif args.which == 'genhdr':
838 GenFspHdr (args.FspBinary, args.OutputDir, args.HFileName)
839 elif args.which == 'info':
840 ShowFspInfo (args.FspBinary)
841 else:
842 pass
843
844 return 0
845
846 if __name__ == '__main__':
847 sys.exit(main())