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