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