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 | 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:
|
---|
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:
|
---|
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:
|
---|
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 | if self.PeHdr.OptionalHeader.PeOptHdr.Magic == 0x10b: # PE32 image
|
---|
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.PeOptHdr.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')
|
---|
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 | pass
|
---|
884 |
|
---|
885 | return 0
|
---|
886 |
|
---|
887 | if __name__ == '__main__':
|
---|
888 | sys.exit(main())
|
---|