1## @ PatchFv.py 2# 3# Copyright (c) 2014 - 2015, 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 re 16import sys 17 18# 19# Read data from file 20# 21# param [in] binfile Binary file 22# param [in] offset Offset 23# param [in] len Length 24# 25# retval value Value 26# 27def readDataFromFile (binfile, offset, len=1): 28 fd = open(binfile, "r+b") 29 fsize = os.path.getsize(binfile) 30 offval = offset & 0xFFFFFFFF 31 if (offval & 0x80000000): 32 offval = fsize - (0xFFFFFFFF - offval + 1) 33 fd.seek(offval) 34 bytearray = [ord(b) for b in fd.read(len)] 35 value = 0 36 idx = len - 1 37 while idx >= 0: 38 value = value << 8 | bytearray[idx] 39 idx = idx - 1 40 fd.close() 41 return value 42 43# 44# Check FSP header is valid or not 45# 46# param [in] binfile Binary file 47# 48# retval boolean True: valid; False: invalid 49# 50def IsFspHeaderValid (binfile): 51 fd = open (binfile, "rb") 52 bindat = fd.read(0x200) # only read first 0x200 bytes 53 fd.close() 54 HeaderList = ['FSPH' , 'FSPP' , 'FSPE'] # Check 'FSPH', 'FSPP', and 'FSPE' in the FSP header 55 OffsetList = [] 56 for each in HeaderList: 57 if each in bindat: 58 idx = bindat.index(each) 59 else: 60 idx = 0 61 OffsetList.append(idx) 62 if not OffsetList[0] or not OffsetList[1]: # If 'FSPH' or 'FSPP' is missing, it will return false 63 return False 64 Revision = ord(bindat[OffsetList[0] + 0x0B]) 65 # 66 # if revision is bigger than 1, it means it is FSP v1.1 or greater revision, which must contain 'FSPE'. 67 # 68 if Revision > 1 and not OffsetList[2]: 69 return False # If FSP v1.1 or greater without 'FSPE', then return false 70 return True 71 72# 73# Patch data in file 74# 75# param [in] binfile Binary file 76# param [in] offset Offset 77# param [in] value Patch value 78# param [in] len Length 79# 80# retval len Length 81# 82def patchDataInFile (binfile, offset, value, len=1): 83 fd = open(binfile, "r+b") 84 fsize = os.path.getsize(binfile) 85 offval = offset & 0xFFFFFFFF 86 if (offval & 0x80000000): 87 offval = fsize - (0xFFFFFFFF - offval + 1) 88 bytearray = [] 89 idx = 0 90 while idx < len: 91 bytearray.append(value & 0xFF) 92 value = value >> 8 93 idx = idx + 1 94 fd.seek(offval) 95 fd.write("".join(chr(b) for b in bytearray)) 96 fd.close() 97 return len 98 99 100class Symbols: 101 def __init__(self): 102 self.dictSymbolAddress = {} 103 self.dictGuidNameXref = {} 104 self.dictFfsOffset = {} 105 self.dictVariable = {} 106 self.dictModBase = {} 107 self.fdFile = None 108 self.string = "" 109 self.fdBase = 0xFFFFFFFF 110 self.fdSize = 0 111 self.index = 0 112 self.parenthesisOpenSet = '([{<' 113 self.parenthesisCloseSet = ')]}>' 114 115 # 116 # Get FD file 117 # 118 # retval self.fdFile Retrieve FD file 119 # 120 def getFdFile (self): 121 return self.fdFile 122 123 # 124 # Get FD size 125 # 126 # retval self.fdSize Retrieve the size of FD file 127 # 128 def getFdSize (self): 129 return self.fdSize 130 131 # 132 # Create dictionaries 133 # 134 # param [in] fvDir FV's directory 135 # param [in] fvNames All FV's names 136 # 137 # retval 0 Created dictionaries successfully 138 # 139 def createDicts (self, fvDir, fvNames): 140 # 141 # If the fvDir is not a dirctory, then raise an exception 142 # 143 if not os.path.isdir(fvDir): 144 raise Exception ("'%s' is not a valid directory!" % FvDir) 145 146 # 147 # If the Guid.xref is not existing in fvDir, then raise an exception 148 # 149 xrefFile = os.path.join(fvDir, "Guid.xref") 150 if not os.path.exists(xrefFile): 151 raise Exception("Cannot open GUID Xref file '%s'!" % xrefFile) 152 153 # 154 # Add GUID reference to dictionary 155 # 156 self.dictGuidNameXref = {} 157 self.parseGuidXrefFile(xrefFile) 158 159 # 160 # Split up each FV from fvNames and get the fdBase 161 # 162 fvList = fvNames.split(":") 163 fdBase = fvList.pop() 164 if len(fvList) == 0: 165 fvList.append(fdBase) 166 167 # 168 # If the FD file is not existing, then raise an exception 169 # 170 fdFile = os.path.join(fvDir, fdBase.strip() + ".fd") 171 if not os.path.exists(fdFile): 172 raise Exception("Cannot open FD file '%s'!" % fdFile) 173 174 # 175 # Get the size of the FD file 176 # 177 self.fdFile = fdFile 178 self.fdSize = os.path.getsize(fdFile) 179 180 # 181 # If the INF file, which is the first element of fvList, is not existing, then raise an exception 182 # 183 infFile = os.path.join(fvDir, fvList[0].strip()) + ".inf" 184 if not os.path.exists(infFile): 185 raise Exception("Cannot open INF file '%s'!" % infFile) 186 187 # 188 # Parse INF file in order to get fdBase and then assign those values to dictVariable 189 # 190 self.parseInfFile(infFile) 191 self.dictVariable = {} 192 self.dictVariable["FDSIZE"] = self.fdSize 193 self.dictVariable["FDBASE"] = self.fdBase 194 195 # 196 # Collect information from FV MAP file and FV TXT file then 197 # put them into dictionaries 198 # 199 self.dictSymbolAddress = {} 200 self.dictFfsOffset = {} 201 for file in fvList: 202 203 # 204 # If the .Fv.map file is not existing, then raise an exception. 205 # Otherwise, parse FV MAP file 206 # 207 fvFile = os.path.join(fvDir, file.strip()) + ".Fv" 208 mapFile = fvFile + ".map" 209 if not os.path.exists(mapFile): 210 raise Exception("Cannot open MAP file '%s'!" % mapFile) 211 212 self.parseFvMapFile(mapFile) 213 214 # 215 # If the .Fv.txt file is not existing, then raise an exception. 216 # Otherwise, parse FV TXT file 217 # 218 fvTxtFile = fvFile + ".txt" 219 if not os.path.exists(fvTxtFile): 220 raise Exception("Cannot open FV TXT file '%s'!" % fvTxtFile) 221 222 self.parseFvTxtFile(fvTxtFile) 223 224 # 225 # Search all MAP files in FFS directory if it exists then parse MOD MAP file 226 # 227 ffsDir = os.path.join(fvDir, "Ffs") 228 if (os.path.isdir(ffsDir)): 229 for item in os.listdir(ffsDir): 230 if len(item) <= 0x24: 231 continue 232 mapFile =os.path.join(ffsDir, item, "%s.map" % item[0:0x24]) 233 if not os.path.exists(mapFile): 234 continue 235 self.parseModMapFile(item[0x24:], mapFile) 236 237 return 0 238 239 # 240 # Get FV offset in FD file 241 # 242 # param [in] fvFile FV file 243 # 244 # retval offset Got FV offset successfully 245 # 246 def getFvOffsetInFd(self, fvFile): 247 # 248 # Check if the first 0x70 bytes of fvFile can be found in fdFile 249 # 250 fvHandle = open(fvFile, "r+b") 251 fdHandle = open(self.fdFile, "r+b") 252 offset = fdHandle.read().find(fvHandle.read(0x70)) 253 fvHandle.close() 254 fdHandle.close() 255 if offset == -1: 256 raise Exception("Could not locate FV file %s in FD!" % fvFile) 257 return offset 258 259 # 260 # Parse INF file 261 # 262 # param [in] infFile INF file 263 # 264 # retval 0 Parsed INF file successfully 265 # 266 def parseInfFile(self, infFile): 267 # 268 # Get FV offset and search EFI_BASE_ADDRESS in the FD file 269 # then assign the value of EFI_BASE_ADDRESS to fdBase 270 # 271 fvOffset = self.getFvOffsetInFd(infFile[0:-4] + ".Fv") 272 fdIn = open(infFile, "r") 273 rptLine = fdIn.readline() 274 self.fdBase = 0xFFFFFFFF 275 while (rptLine != "" ): 276 #EFI_BASE_ADDRESS = 0xFFFDF400 277 match = re.match("^EFI_BASE_ADDRESS\s*=\s*(0x[a-fA-F0-9]+)", rptLine) 278 if match is not None: 279 self.fdBase = int(match.group(1), 16) - fvOffset 280 rptLine = fdIn.readline() 281 fdIn.close() 282 if self.fdBase == 0xFFFFFFFF: 283 raise Exception("Could not find EFI_BASE_ADDRESS in INF file!" % fvFile) 284 return 0 285 286 # 287 # Parse FV TXT file 288 # 289 # param [in] fvTxtFile .Fv.txt file 290 # 291 # retval 0 Parsed FV TXT file successfully 292 # 293 def parseFvTxtFile(self, fvTxtFile): 294 # 295 # Get information from .Fv.txt in order to create a dictionary 296 # For example, 297 # self.dictFfsOffset[912740BE-2284-4734-B971-84B027353F0C] = 0x000D4078 298 # 299 fvOffset = self.getFvOffsetInFd(fvTxtFile[0:-4]) 300 fdIn = open(fvTxtFile, "r") 301 rptLine = fdIn.readline() 302 while (rptLine != "" ): 303 match = re.match("(0x[a-fA-F0-9]+)\s([0-9a-fA-F\-]+)", rptLine) 304 if match is not None: 305 self.dictFfsOffset[match.group(2)] = "0x%08X" % (int(match.group(1), 16) + fvOffset) 306 rptLine = fdIn.readline() 307 fdIn.close() 308 return 0 309 310 # 311 # Parse FV MAP file 312 # 313 # param [in] mapFile .Fv.map file 314 # 315 # retval 0 Parsed FV MAP file successfully 316 # 317 def parseFvMapFile(self, mapFile): 318 # 319 # Get information from .Fv.map in order to create dictionaries 320 # For example, 321 # self.dictModBase[FspSecCore:BASE] = 4294592776 (0xfffa4908) 322 # self.dictModBase[FspSecCore:ENTRY] = 4294606552 (0xfffa7ed8) 323 # self.dictModBase[FspSecCore:TEXT] = 4294593080 (0xfffa4a38) 324 # self.dictModBase[FspSecCore:DATA] = 4294612280 (0xfffa9538) 325 # self.dictSymbolAddress[FspSecCore:_SecStartup] = 0x00fffa4a38 326 # 327 fdIn = open(mapFile, "r") 328 rptLine = fdIn.readline() 329 modName = "" 330 while (rptLine != "" ): 331 if rptLine[0] != ' ': 332 #DxeIpl (Fixed Flash Address, BaseAddress=0x00fffb4310, EntryPoint=0x00fffb4958) 333 #(GUID=86D70125-BAA3-4296-A62F-602BEBBB9081 .textbaseaddress=0x00fffb4398 .databaseaddress=0x00fffb4178) 334 match = re.match("([_a-zA-Z0-9\-]+)\s\(.+BaseAddress=(0x[0-9a-fA-F]+),\s+EntryPoint=(0x[0-9a-fA-F]+)\)", rptLine) 335 if match is not None: 336 modName = match.group(1) 337 if len(modName) == 36: 338 modName = self.dictGuidNameXref[modName.upper()] 339 self.dictModBase['%s:BASE' % modName] = int (match.group(2), 16) 340 self.dictModBase['%s:ENTRY' % modName] = int (match.group(3), 16) 341 match = re.match("\(GUID=([A-Z0-9\-]+)\s+\.textbaseaddress=(0x[0-9a-fA-F]+)\s+\.databaseaddress=(0x[0-9a-fA-F]+)\)", rptLine) 342 if match is not None: 343 modName = match.group(1) 344 if len(modName) == 36: 345 modName = self.dictGuidNameXref[modName.upper()] 346 self.dictModBase['%s:TEXT' % modName] = int (match.group(2), 16) 347 self.dictModBase['%s:DATA' % modName] = int (match.group(3), 16) 348 else: 349 # 0x00fff8016c __ModuleEntryPoint 350 match = re.match("^\s+(0x[a-z0-9]+)\s+([_a-zA-Z0-9]+)", rptLine) 351 if match is not None: 352 self.dictSymbolAddress["%s:%s"%(modName, match.group(2))] = match.group(1) 353 rptLine = fdIn.readline() 354 fdIn.close() 355 return 0 356 357 # 358 # Parse MOD MAP file 359 # 360 # param [in] moduleName Module name 361 # param [in] mapFile .Fv.map file 362 # 363 # retval 0 Parsed MOD MAP file successfully 364 # retval 1 There is no moduleEntryPoint in modSymbols 365 # 366 def parseModMapFile(self, moduleName, mapFile): 367 # 368 # Get information from mapFile by moduleName in order to create a dictionary 369 # For example, 370 # self.dictSymbolAddress[FspSecCore:___guard_fids_count] = 0x00fffa4778 371 # 372 modSymbols = {} 373 fdIn = open(mapFile, "r") 374 reportLines = fdIn.readlines() 375 fdIn.close() 376 377 moduleEntryPoint = "__ModuleEntryPoint" 378 reportLine = reportLines[0] 379 if reportLine.strip().find("Archive member included") != -1: 380 #GCC 381 # 0x0000000000001d55 IoRead8 382 patchMapFileMatchString = "\s+(0x[0-9a-fA-F]{16})\s+([^\s][^0x][_a-zA-Z0-9\-]+)\s" 383 matchKeyGroupIndex = 2 384 matchSymbolGroupIndex = 1 385 prefix = '_' 386 else: 387 #MSFT 388 #0003:00000190 _gComBase 00007a50 SerialPo 389 patchMapFileMatchString = "^\s[0-9a-fA-F]{4}:[0-9a-fA-F]{8}\s+(\w+)\s+([0-9a-fA-F]{8}\s+)" 390 matchKeyGroupIndex = 1 391 matchSymbolGroupIndex = 2 392 prefix = '' 393 394 for reportLine in reportLines: 395 match = re.match(patchMapFileMatchString, reportLine) 396 if match is not None: 397 modSymbols[prefix + match.group(matchKeyGroupIndex)] = match.group(matchSymbolGroupIndex) 398 399 # Handle extra module patchable PCD variable in Linux map since it might have different format 400 # .data._gPcd_BinaryPatch_PcdVpdBaseAddress 401 # 0x0000000000003714 0x4 /tmp/ccmytayk.ltrans1.ltrans.o 402 handleNext = False 403 if matchSymbolGroupIndex == 1: 404 for reportLine in reportLines: 405 if handleNext: 406 handleNext = False 407 pcdName = match.group(1) 408 match = re.match("\s+(0x[0-9a-fA-F]{16})\s+", reportLine) 409 if match is not None: 410 modSymbols[prefix + pcdName] = match.group(1) 411 else: 412 match = re.match("^\s\.data\.(_gPcd_BinaryPatch[_a-zA-Z0-9\-]+)", reportLine) 413 if match is not None: 414 handleNext = True 415 continue 416 417 if not moduleEntryPoint in modSymbols: 418 return 1 419 420 modEntry = '%s:%s' % (moduleName,moduleEntryPoint) 421 if not modEntry in self.dictSymbolAddress: 422 modKey = '%s:ENTRY' % moduleName 423 if modKey in self.dictModBase: 424 baseOffset = self.dictModBase['%s:ENTRY' % moduleName] - int(modSymbols[moduleEntryPoint], 16) 425 else: 426 return 2 427 else: 428 baseOffset = int(self.dictSymbolAddress[modEntry], 16) - int(modSymbols[moduleEntryPoint], 16) 429 for symbol in modSymbols: 430 fullSym = "%s:%s" % (moduleName, symbol) 431 if not fullSym in self.dictSymbolAddress: 432 self.dictSymbolAddress[fullSym] = "0x00%08x" % (baseOffset+ int(modSymbols[symbol], 16)) 433 return 0 434 435 # 436 # Parse Guid.xref file 437 # 438 # param [in] xrefFile the full directory of Guid.xref file 439 # 440 # retval 0 Parsed Guid.xref file successfully 441 # 442 def parseGuidXrefFile(self, xrefFile): 443 # 444 # Get information from Guid.xref in order to create a GuidNameXref dictionary 445 # The dictGuidNameXref, for example, will be like 446 # dictGuidNameXref [1BA0062E-C779-4582-8566-336AE8F78F09] = FspSecCore 447 # 448 fdIn = open(xrefFile, "r") 449 rptLine = fdIn.readline() 450 while (rptLine != "" ): 451 match = re.match("([0-9a-fA-F\-]+)\s([_a-zA-Z0-9]+)", rptLine) 452 if match is not None: 453 self.dictGuidNameXref[match.group(1).upper()] = match.group(2) 454 rptLine = fdIn.readline() 455 fdIn.close() 456 return 0 457 458 # 459 # Get current character 460 # 461 # retval elf.string[self.index] 462 # retval '' Exception 463 # 464 def getCurr(self): 465 try: 466 return self.string[self.index] 467 except Exception: 468 return '' 469 470 # 471 # Check to see if it is last index 472 # 473 # retval self.index 474 # 475 def isLast(self): 476 return self.index == len(self.string) 477 478 # 479 # Move to next index 480 # 481 def moveNext(self): 482 self.index += 1 483 484 # 485 # Skip space 486 # 487 def skipSpace(self): 488 while not self.isLast(): 489 if self.getCurr() in ' \t': 490 self.moveNext() 491 else: 492 return 493 494 # 495 # Parse value 496 # 497 # retval value 498 # 499 def parseValue(self): 500 self.skipSpace() 501 var = '' 502 while not self.isLast(): 503 char = self.getCurr() 504 if char.lower() in '_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:-': 505 var += char 506 self.moveNext() 507 else: 508 break 509 510 if ':' in var: 511 partList = var.split(':') 512 if len(partList) != 2: 513 raise Exception("Unrecognized expression %s" % var) 514 modName = partList[0] 515 modOff = partList[1] 516 if ('-' not in modName) and (modOff[0] in '0123456789'): 517 # MOD: OFFSET 518 var = self.getModGuid(modName) + ":" + modOff 519 if '-' in var: # GUID:OFFSET 520 value = self.getGuidOff(var) 521 else: 522 value = self.getSymbols(var) 523 self.synUsed = True 524 else: 525 if var[0] in '0123456789': 526 value = self.getNumber(var) 527 else: 528 value = self.getVariable(var) 529 return int(value) 530 531 # 532 # Parse single operation 533 # 534 # retval ~self.parseBrace() or self.parseValue() 535 # 536 def parseSingleOp(self): 537 self.skipSpace() 538 char = self.getCurr() 539 if char == '~': 540 self.moveNext() 541 return ~self.parseBrace() 542 else: 543 return self.parseValue() 544 545 # 546 # Parse symbol of Brace([, {, <) 547 # 548 # retval value or self.parseSingleOp() 549 # 550 def parseBrace(self): 551 self.skipSpace() 552 char = self.getCurr() 553 parenthesisType = self.parenthesisOpenSet.find(char) 554 if parenthesisType >= 0: 555 self.moveNext() 556 value = self.parseExpr() 557 self.skipSpace() 558 if self.getCurr() != self.parenthesisCloseSet[parenthesisType]: 559 raise Exception("No closing brace") 560 self.moveNext() 561 if parenthesisType == 1: # [ : Get content 562 value = self.getContent(value) 563 elif parenthesisType == 2: # { : To address 564 value = self.toAddress(value) 565 elif parenthesisType == 3: # < : To offset 566 value = self.toOffset(value) 567 return value 568 else: 569 return self.parseSingleOp() 570 571 # 572 # Parse symbol of Multiplier(*) 573 # 574 # retval value or self.parseSingleOp() 575 # 576 def parseMul(self): 577 values = [self.parseBrace()] 578 while True: 579 self.skipSpace() 580 char = self.getCurr() 581 if char == '*': 582 self.moveNext() 583 values.append(self.parseBrace()) 584 else: 585 break 586 value = 1 587 for each in values: 588 value *= each 589 return value 590 591 # 592 # Parse symbol of And(&) and Or(|) 593 # 594 # retval value 595 # 596 def parseAndOr(self): 597 values = [self.parseMul()] 598 op = None 599 value = 0xFFFFFFFF 600 while True: 601 self.skipSpace() 602 char = self.getCurr() 603 if char == '&': 604 self.moveNext() 605 values.append(self.parseMul()) 606 op = char 607 elif char == '|': 608 div_index = self.index 609 self.moveNext() 610 values.append(self.parseMul()) 611 value = 0 612 op = char 613 else: 614 break 615 616 for each in values: 617 if op == '|': 618 value |= each 619 else: 620 value &= each 621 622 return value 623 624 # 625 # Parse symbol of Add(+) and Minus(-) 626 # 627 # retval sum(values) 628 # 629 def parseAddMinus(self): 630 values = [self.parseAndOr()] 631 while True: 632 self.skipSpace() 633 char = self.getCurr() 634 if char == '+': 635 self.moveNext() 636 values.append(self.parseAndOr()) 637 elif char == '-': 638 self.moveNext() 639 values.append(-1 * self.parseAndOr()) 640 else: 641 break 642 return sum(values) 643 644 # 645 # Parse expression 646 # 647 # retval self.parseAddMinus() 648 # 649 def parseExpr(self): 650 return self.parseAddMinus() 651 652 # 653 # Get result 654 # 655 # retval value 656 # 657 def getResult(self): 658 value = self.parseExpr() 659 self.skipSpace() 660 if not self.isLast(): 661 raise Exception("Unexpected character found '%s'" % self.getCurr()) 662 return value 663 664 # 665 # Get module GUID 666 # 667 # retval value 668 # 669 def getModGuid(self, var): 670 guid = (guid for guid,name in self.dictGuidNameXref.items() if name==var) 671 try: 672 value = guid.next() 673 except Exception: 674 raise Exception("Unknown module name %s !" % var) 675 return value 676 677 # 678 # Get variable 679 # 680 # retval value 681 # 682 def getVariable(self, var): 683 value = self.dictVariable.get(var, None) 684 if value == None: 685 raise Exception("Unrecognized variable '%s'" % var) 686 return value 687 688 # 689 # Get number 690 # 691 # retval value 692 # 693 def getNumber(self, var): 694 var = var.strip() 695 if var.startswith('0x'): # HEX 696 value = int(var, 16) 697 else: 698 value = int(var, 10) 699 return value 700 701 # 702 # Get content 703 # 704 # param [in] value 705 # 706 # retval value 707 # 708 def getContent(self, value): 709 if (value >= self.fdBase) and (value < self.fdBase + self.fdSize): 710 value = value - self.fdBase 711 if value >= self.fdSize: 712 raise Exception("Invalid file offset 0x%08x !" % value) 713 return readDataFromFile (self.fdFile, value, 4) 714 715 # 716 # Change value to address 717 # 718 # param [in] value 719 # 720 # retval value 721 # 722 def toAddress(self, value): 723 if value < self.fdSize: 724 value = value + self.fdBase 725 return value 726 727 # 728 # Change value to offset 729 # 730 # param [in] value 731 # 732 # retval value 733 # 734 def toOffset(self, value): 735 if value > self.fdBase: 736 value = value - self.fdBase 737 return value 738 739 # 740 # Get GUID offset 741 # 742 # param [in] value 743 # 744 # retval value 745 # 746 def getGuidOff(self, value): 747 # GUID:Offset 748 symbolName = value.split(':') 749 if len(symbolName) == 2 and self.dictFfsOffset.has_key(symbolName[0]): 750 value = (int(self.dictFfsOffset[symbolName[0]], 16) + int(symbolName[1], 16)) & 0xFFFFFFFF 751 else: 752 raise Exception("Unknown GUID %s !" % value) 753 return value 754 755 # 756 # Get symbols 757 # 758 # param [in] value 759 # 760 # retval ret 761 # 762 def getSymbols(self, value): 763 if self.dictSymbolAddress.has_key(value): 764 # Module:Function 765 ret = int (self.dictSymbolAddress[value], 16) 766 else: 767 raise Exception("Unknown symbol %s !" % value) 768 return ret 769 770 # 771 # Evaluate symbols 772 # 773 # param [in] expression 774 # param [in] isOffset 775 # 776 # retval value & 0xFFFFFFFF 777 # 778 def evaluate(self, expression, isOffset): 779 self.index = 0 780 self.synUsed = False 781 self.string = expression 782 value = self.getResult() 783 if isOffset: 784 if self.synUsed: 785 # Consider it as an address first 786 if (value >= self.fdBase) and (value < self.fdBase + self.fdSize): 787 value = value - self.fdBase 788 if value & 0x80000000: 789 # Consider it as a negative offset next 790 offset = (~value & 0xFFFFFFFF) + 1 791 if offset < self.fdSize: 792 value = self.fdSize - offset 793 if value >= self.fdSize: 794 raise Exception("Invalid offset expression !") 795 return value & 0xFFFFFFFF 796 797# 798# Print out the usage 799# 800def usage(): 801 print "Usage: \n\tPatchFv FvBuildDir [FvFileBaseNames:]FdFileBaseNameToPatch \"Offset, Value\"" 802 803def main(): 804 # 805 # Parse the options and args 806 # 807 symTables = Symbols() 808 809 # 810 # If the arguments are less than 4, then return an error. 811 # 812 if len(sys.argv) < 4: 813 Usage() 814 return 1 815 816 # 817 # If it fails to create dictionaries, then return an error. 818 # 819 if symTables.createDicts(sys.argv[1], sys.argv[2]) != 0: 820 print "ERROR: Failed to create symbol dictionary!!" 821 return 2 822 823 # 824 # Get FD file and size 825 # 826 fdFile = symTables.getFdFile() 827 fdSize = symTables.getFdSize() 828 829 try: 830 # 831 # Check to see if FSP header is valid 832 # 833 ret = IsFspHeaderValid(fdFile) 834 if ret == False: 835 raise Exception ("The FSP header is not valid. Stop patching FD.") 836 comment = "" 837 for fvFile in sys.argv[3:]: 838 # 839 # Check to see if it has enough arguments 840 # 841 items = fvFile.split(",") 842 if len (items) < 2: 843 raise Exception("Expect more arguments for '%s'!" % fvFile) 844 845 comment = "" 846 command = "" 847 params = [] 848 for item in items: 849 item = item.strip() 850 if item.startswith("@"): 851 comment = item[1:] 852 elif item.startswith("$"): 853 command = item[1:] 854 else: 855 if len(params) == 0: 856 isOffset = True 857 else : 858 isOffset = False 859 # 860 # Parse symbols then append it to params 861 # 862 params.append (symTables.evaluate(item, isOffset)) 863 864 # 865 # Patch a new value into FD file if it is not a command 866 # 867 if command == "": 868 # Patch a DWORD 869 if len (params) == 2: 870 offset = params[0] 871 value = params[1] 872 oldvalue = readDataFromFile(fdFile, offset, 4) 873 ret = patchDataInFile (fdFile, offset, value, 4) - 4 874 else: 875 raise Exception ("Patch command needs 2 parameters !") 876 877 if ret: 878 raise Exception ("Patch failed for offset 0x%08X" % offset) 879 else: 880 print "Patched offset 0x%08X:[%08X] with value 0x%08X # %s" % (offset, oldvalue, value, comment) 881 882 elif command == "COPY": 883 # 884 # Copy binary block from source to destination 885 # 886 if len (params) == 3: 887 src = symTables.toOffset(params[0]) 888 dest = symTables.toOffset(params[1]) 889 clen = symTables.toOffset(params[2]) 890 if (dest + clen <= fdSize) and (src + clen <= fdSize): 891 oldvalue = readDataFromFile(fdFile, src, clen) 892 ret = patchDataInFile (fdFile, dest, oldvalue, clen) - clen 893 else: 894 raise Exception ("Copy command OFFSET or LENGTH parameter is invalid !") 895 else: 896 raise Exception ("Copy command needs 3 parameters !") 897 898 if ret: 899 raise Exception ("Copy failed from offset 0x%08X to offset 0x%08X!" % (src, dest)) 900 else : 901 print "Copied %d bytes from offset 0x%08X ~ offset 0x%08X # %s" % (clen, src, dest, comment) 902 else: 903 raise Exception ("Unknown command %s!" % command) 904 return 0 905 906 except Exception as (ex): 907 print "ERROR: %s" % ex 908 return 1 909 910if __name__ == '__main__': 911 sys.exit(main()) 912