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