]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/SplitFspBin.py
IntelFsp2Pkg/GenCfgOpt.py: Support PCD input from command line
[mirror_edk2.git] / IntelFsp2Pkg / Tools / SplitFspBin.py
1 ## @ FspTool.py
2 #
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.
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_OPTIONAL_HEADER32_PLUS(Structure):
238 _fields_ = [
239 ('Magic', c_uint16),
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))
269 ]
270
271 class EFI_IMAGE_OPTIONAL_HEADER(Union):
272 _fields_ = [
273 ('PeOptHdr', EFI_IMAGE_OPTIONAL_HEADER32),
274 ('PePlusOptHdr', EFI_IMAGE_OPTIONAL_HEADER32_PLUS)
275 ]
276
277 class EFI_IMAGE_NT_HEADERS32(Structure):
278 _fields_ = [
279 ('Signature', c_uint32),
280 ('FileHeader', EFI_IMAGE_FILE_HEADER),
281 ('OptionalHeader', EFI_IMAGE_OPTIONAL_HEADER)
282 ]
283
284
285 class EFI_IMAGE_DIRECTORY_ENTRY:
286 EXPORT = 0
287 IMPORT = 1
288 RESOURCE = 2
289 EXCEPTION = 3
290 SECURITY = 4
291 BASERELOC = 5
292 DEBUG = 6
293 COPYRIGHT = 7
294 GLOBALPTR = 8
295 TLS = 9
296 LOAD_CONFIG = 10
297
298 class EFI_FV_FILETYPE:
299 ALL = 0x00
300 RAW = 0x01
301 FREEFORM = 0x02
302 SECURITY_CORE = 0x03
303 PEI_CORE = 0x04
304 DXE_CORE = 0x05
305 PEIM = 0x06
306 DRIVER = 0x07
307 COMBINED_PEIM_DRIVER = 0x08
308 APPLICATION = 0x09
309 SMM = 0x0a
310 FIRMWARE_VOLUME_IMAGE = 0x0b
311 COMBINED_SMM_DXE = 0x0c
312 SMM_CORE = 0x0d
313 OEM_MIN = 0xc0
314 OEM_MAX = 0xdf
315 DEBUG_MIN = 0xe0
316 DEBUG_MAX = 0xef
317 FFS_MIN = 0xf0
318 FFS_MAX = 0xff
319 FFS_PAD = 0xf0
320
321 class EFI_SECTION_TYPE:
322 """Enumeration of all valid firmware file section types."""
323 ALL = 0x00
324 COMPRESSION = 0x01
325 GUID_DEFINED = 0x02
326 DISPOSABLE = 0x03
327 PE32 = 0x10
328 PIC = 0x11
329 TE = 0x12
330 DXE_DEPEX = 0x13
331 VERSION = 0x14
332 USER_INTERFACE = 0x15
333 COMPATIBILITY16 = 0x16
334 FIRMWARE_VOLUME_IMAGE = 0x17
335 FREEFORM_SUBTYPE_GUID = 0x18
336 RAW = 0x19
337 PEI_DEPEX = 0x1b
338 SMM_DEPEX = 0x1c
339
340 def AlignPtr (offset, alignment = 8):
341 return (offset + alignment - 1) & ~(alignment - 1)
342
343 def Bytes2Val (bytes):
344 return reduce(lambda x,y: (x<<8)|y, bytes[::-1] )
345
346 def Val2Bytes (value, blen):
347 return [(value>>(i*8) & 0xff) for i in range(blen)]
348
349 def OutputStruct (obj, indent = 0, plen = 0):
350 if indent:
351 body = ''
352 else:
353 body = (' ' * indent + '<%s>:\n') % obj.__class__.__name__
354
355 if plen == 0:
356 plen = sizeof(obj)
357
358 max_key_len = 26
359 pstr = (' ' * (indent + 1) + '{0:<%d} = {1}\n') % max_key_len
360
361 for field in obj._fields_:
362 key = field[0]
363 val = getattr(obj, key)
364 rep = ''
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)
368 plen -= sizeof(val)
369 else:
370 if type(val) is str:
371 rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val)
372 elif type(val) in (int, long):
373 rep = '0x%X' % val
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()
379 else:
380 res = ['0x%02X'%i for i in bytearray(val)]
381 rep = '[%s]' % (','.join(res))
382 else:
383 rep = str(val)
384 plen -= sizeof(field[1])
385 body += pstr.format(key, rep)
386 if plen <= 0:
387 break
388 return body
389
390 class Section:
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)]
394 self.Offset = offset
395
396 class FirmwareFile:
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)]
400 self.Offset = offset
401 self.SecList = []
402
403 def ParseFfs(self):
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)
413
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]
418 self.Offset = offset
419 if self.FvHdr.ExtHeaderOffset > 0:
420 self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset)
421 else:
422 self.FvExtHdr = None
423 self.FfsList = []
424
425 def ParseFv(self):
426 fvsize = len(self.FvData)
427 if self.FvExtHdr:
428 offset = self.FvHdr.ExtHeaderOffset + self.FvExtHdr.ExtHeaderSize
429 else:
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):
435 offset = fvsize
436 else:
437 ffs = FirmwareFile (offset, self.FvData[offset:offset + int(ffshdr.Size)])
438 ffs.ParseFfs()
439 self.FfsList.append(ffs)
440 offset += int(ffshdr.Size)
441 offset = AlignPtr(offset)
442
443 class FspImage:
444 def __init__(self, offset, fih, fihoff, patch):
445 self.Fih = fih
446 self.FihOffset = fihoff
447 self.Offset = offset
448 self.FvIdxList = []
449 self.Type = "XTMSXXXXOXXXXXXX"[(fih.ComponentAttribute >> 12) & 0x0F]
450 self.PatchList = patch
451 self.PatchList.append(fihoff + 0x1C)
452
453 def AppendFv(self, FvIdx):
454 self.FvIdxList.append(FvIdx)
455
456 def Patch(self, delta, fdbin):
457 count = 0
458 applied = 0
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))
465 else:
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)])
470 value += delta
471 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
472 applied += 1
473 count += 1
474 # Don't count the FSP base address patch entry appended at the end
475 if count != 0:
476 count -= 1
477 applied -= 1
478 return (count, applied)
479
480 class FirmwareDevice:
481 def __init__(self, offset, fdfile):
482 self.FvList = []
483 self.FspList = []
484 self.FdFile = fdfile
485 self.Offset = 0
486 hfsp = open (self.FdFile, 'rb')
487 self.FdData = bytearray(hfsp.read())
488 hfsp.close()
489
490 def ParseFd(self):
491 offset = 0
492 fdsize = len(self.FdData)
493 self.FvList = []
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])
499 fv.ParseFv ()
500 self.FvList.append(fv)
501 offset += fv.FvHdr.FvLength
502
503 def CheckFsp (self):
504 if len(self.FspList) == 0:
505 return
506
507 fih = None
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 !")
511 if not fih:
512 fih = fsp.Fih
513 else:
514 newfih = fsp.Fih
515 if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):
516 raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")
517
518 def ParseFsp(self):
519 flen = 0
520 for idx, fv in enumerate(self.FvList):
521 # Check if this FV contains FSP header
522 if flen == 0:
523 if len(fv.FfsList) == 0:
524 continue
525 ffs = fv.FfsList[0]
526 if len(ffs.SecList) == 0:
527 continue
528 sec = ffs.SecList[0]
529 if sec.SecHdr.Type != EFI_SECTION_TYPE.RAW:
530 continue
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:
536 continue
537
538 offset += fih.HeaderLength
539 offset = AlignPtr(offset, 4)
540 plist = []
541 while True:
542 fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset)
543 if 'FSPP' != fch.Signature:
544 offset += fch.HeaderLength
545 offset = AlignPtr(offset, 4)
546 else:
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)
550 plist = list(pdata)
551 break
552
553 fsp = FspImage (fspoffset, fih, fihoffset, plist)
554 fsp.AppendFv (idx)
555 self.FspList.append(fsp)
556 flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength
557 else:
558 fsp.AppendFv (idx)
559 flen -= fv.FvHdr.FvLength
560 if flen < 0:
561 raise Exception("ERROR: Incorrect FV size in image !")
562 self.CheckFsp ()
563
564 class PeTeImage:
565 def __init__(self, offset, data):
566 self.Offset = offset
567 tehdr = EFI_TE_IMAGE_HEADER.from_buffer (data, 0)
568 if tehdr.Signature == 'VZ': # TE image
569 self.TeHdr = tehdr
570 elif tehdr.Signature == 'MZ': # PE image
571 self.TeHdr = None
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 !")
586 else:
587 raise Exception("ERROR: Invalid PE32 optional header !")
588 self.Offset = offset
589 self.Data = data
590 self.RelocList = []
591
592 def IsTeImage(self):
593 return self.TeHdr is not None
594
595 def ParseReloc(self):
596 if self.IsTeImage():
597 rsize = self.TeHdr.DataDirectoryBaseReloc.Size
598 roffset = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress
599 else:
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
606
607 alignment = 4
608 offset = roffset
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)
617 for each in rdata:
618 roff = each & 0xfff
619 rtype = each >> 12
620 if rtype == 0: # IMAGE_REL_BASED_ABSOLUTE:
621 continue
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
626 if self.IsTeImage():
627 aoff += sizeof(self.TeHdr) - self.TeHdr.StrippedSize
628 self.RelocList.append((rtype, aoff))
629 offset += sizeof(rdata)
630
631 def Rebase(self, delta, fdbin):
632 count = 0
633 if delta == 0:
634 return count
635
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)])
640 value += delta
641 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))
642 count += 1
643 elif rtype == 10: # IMAGE_REL_BASED_DIR64
644 offset = roff + self.Offset
645 value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint64)])
646 value += delta
647 fdbin[offset:offset+sizeof(c_uint64)] = Val2Bytes(value, sizeof(c_uint64))
648 count += 1
649 else:
650 raise Exception('ERROR: Unknown relocation type %d !' % rtype)
651
652 if self.IsTeImage():
653 offset = self.Offset + EFI_TE_IMAGE_HEADER.ImageBase.offset
654 size = EFI_TE_IMAGE_HEADER.ImageBase.size
655 else:
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
660
661 value = Bytes2Val(fdbin[offset:offset+size]) + delta
662 fdbin[offset:offset+size] = Val2Bytes(value, size)
663
664 return count
665
666 def ShowFspInfo (fspfile):
667 fd = FirmwareDevice(0, fspfile)
668 fd.ParseFd ()
669 fd.ParseFsp ()
670
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
674 if not name:
675 name = '\xff' * 16
676 else:
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)
683 print ("\n")
684
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)))
689
690 def GenFspHdr (fspfile, outdir, hfile):
691 fd = FirmwareDevice(0, fspfile)
692 fd.ParseFd ()
693 fd.ParseFsp ()
694
695 if not hfile:
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)
701
702 firstfv = True
703 for fsp in fd.FspList:
704 fih = fsp.Fih
705 if firstfv:
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)
708 firstfv = False
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))
713
714 hfsp.close()
715
716 def SplitFspBin (fspfile, outdir, nametemplate):
717 fd = FirmwareDevice(0, fspfile)
718 fd.ParseFd ()
719 fd.ParseFsp ()
720
721 for fsp in fd.FspList:
722 ftype = fsp.Type
723 if not nametemplate:
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 ("Create FSP component file '%s'" % filename)
729 for fvidx in fsp.FvIdxList:
730 fv = fd.FvList[fvidx]
731 hfsp.write(fv.FvData)
732 hfsp.close()
733
734 def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile):
735 fd = FirmwareDevice(0, FspBinary)
736 fd.ParseFd ()
737 fd.ParseFsp ()
738
739 numcomp = len(FspComponent)
740 baselist = FspBase
741 if numcomp != len(baselist):
742 print "ERROR: Required number of base does not match number of FSP component !"
743 return
744
745 newfspbin = fd.FdData[:]
746
747 for idx, fspcomp in enumerate(FspComponent):
748
749 found = False
750 for fsp in fd.FspList:
751 ftype = fsp.Type.lower()
752 if ftype == fspcomp:
753 found = True
754 break
755
756 if not found:
757 print "ERROR: Could not find FSP_%c component to rebase !" % fspcomp.upper()
758 return
759
760 fspbase = baselist[idx]
761 if fspbase.startswith('0x'):
762 newbase = int(fspbase, 16)
763 else:
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)
768
769 imglist = []
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)))
777
778 fcount = 0
779 pcount = 0
780 for (offset, length) in imglist:
781 img = PeTeImage(offset, fd.FdData[offset:offset + length])
782 img.ParseReloc()
783 pcount += img.Rebase(delta, newfspbin)
784 fcount += 1
785
786 print " Patched %d entries in %d TE/PE32 images." % (pcount, fcount)
787
788 (count, applied) = fsp.Patch(delta, newfspbin)
789 print " Patched %d entries using FSP patch table." % applied
790 if count != applied:
791 print " %d invalid entries are ignored !" % (count - applied)
792
793 if OutputFile == '':
794 filename = os.path.basename(FspBinary)
795 base, ext = os.path.splitext(filename)
796 OutputFile = base + "_%08X" % newbase + ext
797
798 fspname, ext = os.path.splitext(os.path.basename(OutputFile))
799 filename = os.path.join(OutputDir, fspname + ext)
800 fd = open(filename, "wb")
801 fd.write(newfspbin)
802 fd.close()
803
804 def main ():
805 parser = argparse.ArgumentParser()
806 subparsers = parser.add_subparsers(title='commands')
807
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 = '')
815
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 = '')
821
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 = '')
827
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)
831
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)
838
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)
847 else:
848 pass
849
850 return 0
851
852 if __name__ == '__main__':
853 sys.exit(main())