]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFsp2Pkg/Tools/SplitFspBin.py
IntelFsp2Pkg SplitFspBin.py: Correct file name in file header
[mirror_edk2.git] / IntelFsp2Pkg / Tools / SplitFspBin.py
CommitLineData
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
8import os\r
9import sys\r
10import uuid\r
11import copy\r
12import struct\r
13import argparse\r
14from ctypes import *\r
c3f0829b 15from functools import reduce\r
cf1d4549
JY
16\r
17"""\r
8349b868 18This utility supports some operations for Intel FSP 1.x/2.x image.\r
cf1d4549 19It 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
26CopyRightHeaderFile = """/*\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
34class 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
56class 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
70class 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
76class 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
82class 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
92class 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
98class 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
104class 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
131class 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
140class EFI_IMAGE_DATA_DIRECTORY(Structure):\r
141 _fields_ = [\r
142 ('VirtualAddress', c_uint32),\r
143 ('Size', c_uint32)\r
144 ]\r
145\r
146class 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
160class 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
183class 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
194class 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
200class 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
235class 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
269class 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
275class 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
283class 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
296class 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
319class 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
338def AlignPtr (offset, alignment = 8):\r
339 return (offset + alignment - 1) & ~(alignment - 1)\r
340\r
341def Bytes2Val (bytes):\r
342 return reduce(lambda x,y: (x<<8)|y, bytes[::-1] )\r
343\r
344def Val2Bytes (value, blen):\r
345 return [(value>>(i*8) & 0xff) for i in range(blen)]\r
346\r
c3f0829b
CC
347def 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
356def 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
365def 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
372def 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
436class 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
442class 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
460class 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
489class 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
526class 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
608class 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
714def 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
741def 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
770def 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
790def 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
865def 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
913if __name__ == '__main__':\r
914 sys.exit(main())\r