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