]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFsp2Pkg/Tools/SplitFspBin.py
InterFsp2Pkg:Tool: Add user manual for SplitFspBin tool.
[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
162class PE_RELOC_BLOCK_HEADER(Structure):\r
163 _fields_ = [\r
164 ('PageRVA', c_uint32),\r
165 ('BlockSize', c_uint32)\r
166 ]\r
cf1d4549 167\r
c6ca1c01
MM
168class EFI_FV_FILETYPE:\r
169 ALL = 0x00\r
170 RAW = 0x01\r
171 FREEFORM = 0x02\r
172 SECURITY_CORE = 0x03\r
173 PEI_CORE = 0x04\r
174 DXE_CORE = 0x05\r
175 PEIM = 0x06\r
176 DRIVER = 0x07\r
177 COMBINED_PEIM_DRIVER = 0x08\r
178 APPLICATION = 0x09\r
179 SMM = 0x0a\r
180 FIRMWARE_VOLUME_IMAGE = 0x0b\r
181 COMBINED_SMM_DXE = 0x0c\r
182 SMM_CORE = 0x0d\r
183 OEM_MIN = 0xc0\r
184 OEM_MAX = 0xdf\r
185 DEBUG_MIN = 0xe0\r
186 DEBUG_MAX = 0xef\r
187 FFS_MIN = 0xf0\r
188 FFS_MAX = 0xff\r
189 FFS_PAD = 0xf0\r
190\r
191class EFI_SECTION_TYPE:\r
192 """Enumeration of all valid firmware file section types."""\r
193 ALL = 0x00\r
194 COMPRESSION = 0x01\r
195 GUID_DEFINED = 0x02\r
196 DISPOSABLE = 0x03\r
197 PE32 = 0x10\r
198 PIC = 0x11\r
199 TE = 0x12\r
200 DXE_DEPEX = 0x13\r
201 VERSION = 0x14\r
202 USER_INTERFACE = 0x15\r
203 COMPATIBILITY16 = 0x16\r
204 FIRMWARE_VOLUME_IMAGE = 0x17\r
205 FREEFORM_SUBTYPE_GUID = 0x18\r
206 RAW = 0x19\r
207 PEI_DEPEX = 0x1b\r
208 SMM_DEPEX = 0x1c\r
209\r
210def AlignPtr (offset, alignment = 8):\r
211 return (offset + alignment - 1) & ~(alignment - 1)\r
212\r
213def Bytes2Val (bytes):\r
214 return reduce(lambda x,y: (x<<8)|y, bytes[::-1] )\r
215\r
216def Val2Bytes (value, blen):\r
217 return [(value>>(i*8) & 0xff) for i in range(blen)]\r
218\r
219def OutputStruct (obj, indent = 0, plen = 0):\r
220 if indent:\r
221 body = ''\r
222 else:\r
223 body = (' ' * indent + '<%s>:\n') % obj.__class__.__name__\r
224\r
225 if plen == 0:\r
226 plen = sizeof(obj)\r
227\r
228 max_key_len = 26\r
229 pstr = (' ' * (indent + 1) + '{0:<%d} = {1}\n') % max_key_len\r
230\r
231 for field in obj._fields_:\r
232 key = field[0]\r
233 val = getattr(obj, key)\r
234 rep = ''\r
235 if not isinstance(val, c_uint24) and isinstance(val, Structure):\r
236 body += pstr.format(key, val.__class__.__name__)\r
237 body += OutputStruct (val, indent + 1)\r
238 plen -= sizeof(val)\r
cf1d4549 239 else:\r
c6ca1c01
MM
240 if type(val) is str:\r
241 rep = "0x%X ('%s')" % (Bytes2Val(bytearray(val)), val)\r
242 elif type(val) in (int, long):\r
243 rep = '0x%X' % val\r
244 elif isinstance(val, c_uint24):\r
245 rep = '0x%X' % val.get_value()\r
246 elif 'c_ubyte_Array' in str(type(val)):\r
247 if sizeof(val) == 16:\r
248 rep = str(uuid.UUID(bytes = str(bytearray(val)))).upper()\r
cf1d4549 249 else:\r
c6ca1c01
MM
250 res = ['0x%02X'%i for i in bytearray(val)]\r
251 rep = '[%s]' % (','.join(res))\r
252 else:\r
253 rep = str(val)\r
254 plen -= sizeof(field[1])\r
255 body += pstr.format(key, rep)\r
256 if plen <= 0:\r
257 break\r
258 return body\r
259\r
260class Section:\r
261 def __init__(self, offset, secdata):\r
262 self.SecHdr = EFI_COMMON_SECTION_HEADER.from_buffer (secdata, 0)\r
263 self.SecData = secdata[0:int(self.SecHdr.Size)]\r
264 self.Offset = offset\r
265\r
266class FirmwareFile:\r
267 def __init__(self, offset, filedata):\r
268 self.FfsHdr = EFI_FFS_FILE_HEADER.from_buffer (filedata, 0)\r
269 self.FfsData = filedata[0:int(self.FfsHdr.Size)]\r
270 self.Offset = offset\r
271 self.SecList = []\r
272\r
273 def ParseFfs(self):\r
274 ffssize = len(self.FfsData)\r
275 offset = sizeof(self.FfsHdr)\r
276 if self.FfsHdr.Name != '\xff' * 16:\r
277 while offset < ffssize:\r
278 sechdr = EFI_COMMON_SECTION_HEADER.from_buffer (self.FfsData, offset)\r
279 sec = Section (offset, self.FfsData[offset:offset + int(sechdr.Size)])\r
280 self.SecList.append(sec)\r
281 offset += int(sechdr.Size)\r
282 offset = AlignPtr(offset, 4)\r
283\r
284class FirmwareVolume:\r
285 def __init__(self, offset, fvdata):\r
286 self.FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (fvdata, 0)\r
287 self.FvData = fvdata[0 : self.FvHdr.FvLength]\r
288 self.Offset = offset\r
289 if self.FvHdr.ExtHeaderOffset > 0:\r
290 self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer (self.FvData, self.FvHdr.ExtHeaderOffset)\r
cf1d4549 291 else:\r
c6ca1c01
MM
292 self.FvExtHdr = None\r
293 self.FfsList = []\r
294\r
295 def ParseFv(self):\r
296 fvsize = len(self.FvData)\r
297 if self.FvExtHdr:\r
298 offset = self.FvHdr.ExtHeaderOffset + self.FvExtHdr.ExtHeaderSize\r
cf1d4549 299 else:\r
c6ca1c01
MM
300 offset = self.FvHdr.HeaderLength\r
301 offset = AlignPtr(offset)\r
302 while offset < fvsize:\r
303 ffshdr = EFI_FFS_FILE_HEADER.from_buffer (self.FvData, offset)\r
304 if (ffshdr.Name == '\xff' * 16) and (int(ffshdr.Size) == 0xFFFFFF):\r
305 offset = fvsize\r
306 else:\r
307 ffs = FirmwareFile (offset, self.FvData[offset:offset + int(ffshdr.Size)])\r
308 ffs.ParseFfs()\r
309 self.FfsList.append(ffs)\r
310 offset += int(ffshdr.Size)\r
311 offset = AlignPtr(offset)\r
312\r
313class FspImage:\r
314 def __init__(self, offset, fih, fihoff, patch):\r
315 self.Fih = fih\r
316 self.FihOffset = fihoff\r
317 self.Offset = offset\r
318 self.FvIdxList = []\r
319 self.Type = "XTMSXXXXOXXXXXXX"[(fih.ComponentAttribute >> 12) & 0x0F]\r
320 self.PatchList = patch\r
321 self.PatchList.append(fihoff + 0x1C)\r
322\r
323 def AppendFv(self, FvIdx):\r
324 self.FvIdxList.append(FvIdx)\r
325\r
326 def Patch(self, delta, fdbin):\r
327 count = 0\r
328 applied = 0\r
329 for idx, patch in enumerate(self.PatchList):\r
330 ptype = (patch>>24) & 0x0F\r
331 if ptype not in [0x00, 0x0F]:\r
332 raise Exception('ERROR: Invalid patch type %d !' % ptype)\r
333 if patch & 0x80000000:\r
334 patch = self.Fih.ImageSize - (0x1000000 - (patch & 0xFFFFFF))\r
335 else:\r
336 patch = patch & 0xFFFFFF\r
337 if (patch < self.Fih.ImageSize) and (patch + sizeof(c_uint32) <= self.Fih.ImageSize):\r
338 offset = patch + self.Offset\r
339 value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint32)])\r
340 value += delta\r
341 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))\r
342 applied += 1\r
343 count += 1\r
344 # Don't count the FSP base address patch entry appended at the end\r
345 if count != 0:\r
346 count -= 1\r
347 applied -= 1\r
348 return (count, applied)\r
349\r
350class FirmwareDevice:\r
351 def __init__(self, offset, fdfile):\r
352 self.FvList = []\r
353 self.FspList = []\r
354 self.FdFile = fdfile\r
355 self.Offset = 0\r
356 hfsp = open (self.FdFile, 'rb')\r
357 self.FdData = bytearray(hfsp.read())\r
358 hfsp.close()\r
cf1d4549 359\r
c6ca1c01
MM
360 def ParseFd(self):\r
361 offset = 0\r
362 fdsize = len(self.FdData)\r
363 self.FvList = []\r
364 while offset < fdsize:\r
365 fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer (self.FdData, offset)\r
366 if '_FVH' != fvh.Signature:\r
367 raise Exception("ERROR: Invalid FV header !")\r
368 fv = FirmwareVolume (offset, self.FdData[offset:offset + fvh.FvLength])\r
369 fv.ParseFv ()\r
370 self.FvList.append(fv)\r
371 offset += fv.FvHdr.FvLength\r
cf1d4549
JY
372\r
373 def CheckFsp (self):\r
c6ca1c01 374 if len(self.FspList) == 0:\r
cf1d4549
JY
375 return\r
376\r
377 fih = None\r
c6ca1c01
MM
378 for fsp in self.FspList:\r
379 if fsp.Fih.HeaderRevision < 3:\r
380 raise Exception("ERROR: FSP 1.x is not supported by this tool !")\r
cf1d4549 381 if not fih:\r
c6ca1c01 382 fih = fsp.Fih\r
cf1d4549 383 else:\r
c6ca1c01 384 newfih = fsp.Fih\r
cf1d4549 385 if (newfih.ImageId != fih.ImageId) or (newfih.ImageRevision != fih.ImageRevision):\r
c6ca1c01
MM
386 raise Exception("ERROR: Inconsistent FSP ImageId or ImageRevision detected !")\r
387\r
388 def ParseFsp(self):\r
389 flen = 0\r
390 for idx, fv in enumerate(self.FvList):\r
391 # Check if this FV contains FSP header\r
392 if flen == 0:\r
393 if len(fv.FfsList) == 0:\r
394 continue\r
395 ffs = fv.FfsList[0]\r
396 if len(ffs.SecList) == 0:\r
397 continue\r
398 sec = ffs.SecList[0]\r
399 if sec.SecHdr.Type != EFI_SECTION_TYPE.RAW:\r
400 continue\r
401 fihoffset = ffs.Offset + sec.Offset + sizeof(sec.SecHdr)\r
402 fspoffset = fv.Offset\r
403 offset = fspoffset + fihoffset\r
404 fih = FSP_INFORMATION_HEADER.from_buffer (self.FdData, offset)\r
405 if 'FSPH' != fih.Signature:\r
406 continue\r
407\r
408 offset += fih.HeaderLength\r
409 offset = AlignPtr(offset, 4)\r
410 plist = []\r
411 while True:\r
412 fch = FSP_COMMON_HEADER.from_buffer (self.FdData, offset)\r
413 if 'FSPP' != fch.Signature:\r
414 offset += fch.HeaderLength\r
415 offset = AlignPtr(offset, 4)\r
416 else:\r
417 fspp = FSP_PATCH_TABLE.from_buffer (self.FdData, offset)\r
418 offset += sizeof(fspp)\r
419 pdata = (c_uint32 * fspp.PatchEntryNum).from_buffer(self.FdData, offset)\r
420 plist = list(pdata)\r
421 break\r
422\r
423 fsp = FspImage (fspoffset, fih, fihoffset, plist)\r
424 fsp.AppendFv (idx)\r
425 self.FspList.append(fsp)\r
426 flen = fsp.Fih.ImageSize - fv.FvHdr.FvLength\r
427 else:\r
428 fsp.AppendFv (idx)\r
429 flen -= fv.FvHdr.FvLength\r
430 if flen < 0:\r
431 raise Exception("ERROR: Incorrect FV size in image !")\r
432 self.CheckFsp ()\r
433\r
434class TeImage:\r
435 def __init__(self, offset, tedata):\r
436 self.Offset = offset\r
437 self.TeHdr = EFI_TE_IMAGE_HEADER.from_buffer (tedata, 0)\r
438 self.TeData = tedata\r
439 self.RelocList = []\r
440\r
441 def ParseReloc(self):\r
442 rsize = self.TeHdr.DataDirectoryBaseReloc.Size\r
443 roffset = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + self.TeHdr.DataDirectoryBaseReloc.VirtualAddress\r
444 alignment = 4\r
445 offset = roffset\r
446 while offset < roffset + rsize:\r
447 offset = AlignPtr(offset, 4)\r
448 blkhdr = PE_RELOC_BLOCK_HEADER.from_buffer(self.TeData, offset)\r
449 offset += sizeof(blkhdr)\r
450 # Read relocation type,offset pairs\r
451 rlen = blkhdr.BlockSize - sizeof(PE_RELOC_BLOCK_HEADER)\r
452 rnum = rlen/sizeof(c_uint16)\r
453 rdata = (c_uint16 * rnum).from_buffer(self.TeData, offset)\r
454 for each in rdata:\r
455 roff = each & 0xfff\r
456 rtype = each >> 12\r
457 if rtype == 0: # IMAGE_REL_BASED.ABSOLUTE:\r
458 continue\r
459 if rtype != 3: # IMAGE_REL_BASED_HIGHLOW\r
460 raise Exception("ERROR: Unsupported relocation type %d!" % rtype)\r
461 # Calculate the offset of the relocation\r
462 aoff = sizeof(self.TeHdr) - self.TeHdr.StrippedSize + blkhdr.PageRVA + roff\r
463 self.RelocList.append((rtype, aoff))\r
464 offset += sizeof(rdata)\r
465\r
466 def Rebase(self, delta, fdbin):\r
467 count = 0\r
468 if delta == 0:\r
469 return count\r
470\r
471 for (rtype, roff) in self.RelocList:\r
472 if rtype == 0x03: # HIGHLOW\r
473 offset = roff + self.Offset\r
474 value = Bytes2Val(fdbin[offset:offset+sizeof(c_uint32)])\r
475 value += delta\r
476 fdbin[offset:offset+sizeof(c_uint32)] = Val2Bytes(value, sizeof(c_uint32))\r
477 count += 1\r
478 else:\r
479 raise Exception('ERROR: Unknown relocation type %d !' % rtype)\r
480\r
481 tehdr = self.TeHdr\r
482 tehdr.ImageBase += delta\r
483 offset = self.Offset\r
484 fdbin[offset:offset+sizeof(tehdr)] = bytearray(tehdr)\r
485\r
486 return count\r
cf1d4549 487\r
c6ca1c01
MM
488def ShowFspInfo (fspfile):\r
489 fd = FirmwareDevice(0, fspfile)\r
490 fd.ParseFd ()\r
491 fd.ParseFsp ()\r
492\r
493 print ("\nFound the following %d Firmware Volumes in FSP binary:" % (len(fd.FvList)))\r
494 for idx, fv in enumerate(fd.FvList):\r
495 name = fv.FvExtHdr.FvName\r
cf1d4549 496 if not name:\r
c6ca1c01
MM
497 name = '\xff' * 16\r
498 else:\r
499 name = str(bytearray(name))\r
500 guid = uuid.UUID(bytes = name)\r
501 print ("FV%d:" % idx)\r
502 print (" GUID : %s" % str(guid).upper())\r
503 print (" Offset : 0x%08X" % fv.Offset)\r
504 print (" Length : 0x%08X" % fv.FvHdr.FvLength)\r
505 print ("\n")\r
506\r
507 for fsp in fd.FspList:\r
508 fvlist = map(lambda x : 'FV%d' % x, fsp.FvIdxList)\r
509 print ("FSP_%s contains %s" % (fsp.Type, ','.join(fvlist)))\r
510 print ("%s" % (OutputStruct(fsp.Fih, 0, fsp.Fih.HeaderLength)))\r
511\r
512def GenFspHdr (fspfile, outdir, hfile):\r
513 fd = FirmwareDevice(0, fspfile)\r
514 fd.ParseFd ()\r
515 fd.ParseFsp ()\r
516\r
517 if not hfile:\r
518 hfile = os.path.splitext(os.path.basename(fspfile))[0] + '.h'\r
519 fspname, ext = os.path.splitext(os.path.basename(hfile))\r
520 filename = os.path.join(outdir, fspname + ext)\r
521 hfsp = open(filename, 'w')\r
522 hfsp.write ('%s\n\n' % CopyRightHeaderFile)\r
523\r
524 firstfv = True\r
525 for fsp in fd.FspList:\r
526 fih = fsp.Fih\r
527 if firstfv:\r
528 hfsp.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (Bytes2Val(bytearray(fih.ImageId)), fih.ImageId))\r
529 hfsp.write("#define FSP_IMAGE_REV 0x%08X \n\n" % fih.ImageRevision)\r
530 firstfv = False\r
531 fv = fd.FvList[fsp.FvIdxList[0]]\r
532 hfsp.write ('#define FSP%s_BASE 0x%08X\n' % (fsp.Type, fih.ImageBase))\r
533 hfsp.write ('#define FSP%s_OFFSET 0x%08X\n' % (fsp.Type, fv.Offset))\r
534 hfsp.write ('#define FSP%s_LENGTH 0x%08X\n\n' % (fsp.Type, fih.ImageSize))\r
535\r
536 hfsp.close()\r
537\r
538def SplitFspBin (fspfile, outdir, nametemplate):\r
539 fd = FirmwareDevice(0, fspfile)\r
540 fd.ParseFd ()\r
541 fd.ParseFsp ()\r
542\r
543 for fsp in fd.FspList:\r
544 ftype = fsp.Type\r
545 if not nametemplate:\r
546 nametemplate = fspfile\r
547 fspname, ext = os.path.splitext(os.path.basename(nametemplate))\r
548 filename = os.path.join(outdir, fspname + '_' + fsp.Type + ext)\r
549 hfsp = open(filename, 'wb')\r
550 print ("Ceate FSP component file '%s'" % filename)\r
551 for fvidx in fsp.FvIdxList:\r
552 fv = fd.FvList[fvidx]\r
553 hfsp.write(fv.FvData)\r
cf1d4549
JY
554 hfsp.close()\r
555\r
c6ca1c01
MM
556def RebaseFspBin (FspBinary, FspComponent, FspBase, OutputDir, OutputFile):\r
557 fd = FirmwareDevice(0, FspBinary)\r
558 fd.ParseFd ()\r
559 fd.ParseFsp ()\r
cf1d4549 560\r
c6ca1c01
MM
561 numcomp = len(FspComponent)\r
562 baselist = FspBase\r
563 if numcomp != len(baselist):\r
564 print "ERROR: Required number of base does not match number of FSP component !"\r
565 return\r
cf1d4549 566\r
c6ca1c01
MM
567 newfspbin = fd.FdData[:]\r
568\r
569 for idx, fspcomp in enumerate(FspComponent):\r
570\r
571 found = False\r
572 for fsp in fd.FspList:\r
573 ftype = fsp.Type.lower()\r
574 if ftype == fspcomp:\r
575 found = True\r
576 break\r
577\r
578 if not found:\r
579 print "ERROR: Could not find FSP_%c component to rebase !" % fspcomp.upper()\r
580 return\r
581\r
582 fspbase = baselist[idx]\r
583 if fspbase.startswith('0x'):\r
584 newbase = int(fspbase, 16)\r
585 else:\r
586 newbase = int(fspbase)\r
587 oldbase = fsp.Fih.ImageBase\r
588 delta = newbase - oldbase\r
589 print "Rebase FSP-%c from 0x%08X to 0x%08X:" % (ftype.upper(),oldbase,newbase)\r
590\r
591 telist = []\r
592 for fvidx in fsp.FvIdxList:\r
593 fv = fd.FvList[fvidx]\r
594 for ffs in fv.FfsList:\r
595 for sec in ffs.SecList:\r
596 if sec.SecHdr.Type == EFI_SECTION_TYPE.TE: # TE\r
597 offset = fd.Offset + fv.Offset + ffs.Offset + sec.Offset + sizeof(sec.SecHdr)\r
598 telist.append ((offset, len(sec.SecData) - sizeof(sec.SecHdr)))\r
599 elif sec.SecHdr.Type == EFI_SECTION_TYPE.PE32: # PE\r
600 raise Exception("ERROR: PE32 Section is not supported !")\r
601\r
602 fcount = 0\r
603 tecount = 0\r
604 for (teoffset, telen) in telist:\r
605 tehdr = EFI_TE_IMAGE_HEADER.from_buffer (fd.FdData, teoffset)\r
606 if 'VZ' != tehdr.Signature:\r
607 raise Exception("ERROR: Invalid TE header !")\r
608 te = TeImage(teoffset, fd.FdData[teoffset:teoffset + telen])\r
609 te.ParseReloc()\r
610 tecount += te.Rebase(delta, newfspbin)\r
611 fcount += 1\r
612 print " Patched %d entries in %d TE images." % (tecount, fcount)\r
613\r
614 (count, applied) = fsp.Patch(delta, newfspbin)\r
615 print " Patched %d entries using FSP patch table." % applied\r
616 if count != applied:\r
617 print " %d invalid entries are ignored !" % (count - applied)\r
618\r
619 if OutputFile == '':\r
620 filename = os.path.basename(FspBinary)\r
621 base, ext = os.path.splitext(filename)\r
622 OutputFile = base + "_%08X" % newbase + ext\r
623\r
624 fspname, ext = os.path.splitext(os.path.basename(OutputFile))\r
625 filename = os.path.join(OutputDir, fspname + ext)\r
626 fd = open(filename, "wb")\r
627 fd.write(newfspbin)\r
628 fd.close()\r
cf1d4549
JY
629\r
630def main ():\r
c6ca1c01
MM
631 parser = argparse.ArgumentParser()\r
632 subparsers = parser.add_subparsers(title='commands')\r
633\r
634 parser_rebase = subparsers.add_parser('rebase', help='rebase a FSP into a new base address')\r
635 parser_rebase.set_defaults(which='rebase')\r
636 parser_rebase.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
637 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
638 parser_rebase.add_argument('-b', '--newbase', dest='FspBase', nargs='+', type=str, help='Rebased FSP binary file name', default = '', required = True)\r
639 parser_rebase.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')\r
640 parser_rebase.add_argument('-n', '--outfile', dest='OutputFile', type=str, help='Rebased FSP binary file name', default = '')\r
cf1d4549
JY
641\r
642 parser_split = subparsers.add_parser('split', help='split a FSP into multiple components')\r
643 parser_split.set_defaults(which='split')\r
644 parser_split.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
645 parser_split.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')\r
646 parser_split.add_argument('-n', '--nametpl', dest='NameTemplate', type=str, help='Output name template', default = '')\r
cf1d4549
JY
647\r
648 parser_genhdr = subparsers.add_parser('genhdr', help='generate a header file for FSP binary')\r
649 parser_genhdr.set_defaults(which='genhdr')\r
650 parser_genhdr.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
651 parser_genhdr.add_argument('-o', '--outdir' , dest='OutputDir', type=str, help='Output directory path', default = '.')\r
652 parser_genhdr.add_argument('-n', '--hfile', dest='HFileName', type=str, help='Output header file name', default = '')\r
c6ca1c01
MM
653\r
654 parser_info = subparsers.add_parser('info', help='display FSP information')\r
655 parser_info.set_defaults(which='info')\r
656 parser_info.add_argument('-f', '--fspbin' , dest='FspBinary', type=str, help='FSP binary file path', required = True)\r
cf1d4549
JY
657\r
658 args = parser.parse_args()\r
c6ca1c01 659 if args.which in ['rebase', 'split', 'genhdr', 'info']:\r
cf1d4549 660 if not os.path.exists(args.FspBinary):\r
c6ca1c01
MM
661 raise Exception ("ERROR: Could not locate FSP binary file '%s' !" % args.FspBinary)\r
662 if hasattr(args, 'OutputDir') and not os.path.exists(args.OutputDir):\r
663 raise Exception ("ERROR: Invalid output directory '%s' !" % args.OutputDir)\r
664\r
665 if args.which == 'rebase':\r
666 RebaseFspBin (args.FspBinary, args.FspComponent, args.FspBase, args.OutputDir, args.OutputFile)\r
667 elif args.which == 'split':\r
668 SplitFspBin (args.FspBinary, args.OutputDir, args.NameTemplate)\r
cf1d4549 669 elif args.which == 'genhdr':\r
c6ca1c01
MM
670 GenFspHdr (args.FspBinary, args.OutputDir, args.HFileName)\r
671 elif args.which == 'info':\r
672 ShowFspInfo (args.FspBinary)\r
cf1d4549
JY
673 else:\r
674 pass\r
675\r
cf1d4549
JY
676 return 0\r
677\r
678if __name__ == '__main__':\r
679 sys.exit(main())\r