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