From c8ec22a266cdd134ac99c3021003710130613a40 Mon Sep 17 00:00:00 2001 From: jyao1 Date: Tue, 29 Jul 2014 02:21:52 +0000 Subject: Add IntelFspPkg to support create FSP bin based on EDKII. Contributed-under: TianoCore Contribution Agreement 1.0 Signed off by: Ravi Rangarajan Reviewed by: Maurice Ma Reviewed by: Jiewen Yao Reviewed by: Giri Mudusuru Reviewed by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15705 6f19259b-4bc3-4df7-8a09-765794883524 --- IntelFspPkg/Tools/PatchFv.py | 567 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 567 insertions(+) create mode 100644 IntelFspPkg/Tools/PatchFv.py (limited to 'IntelFspPkg/Tools/PatchFv.py') diff --git a/IntelFspPkg/Tools/PatchFv.py b/IntelFspPkg/Tools/PatchFv.py new file mode 100644 index 0000000000..cc22cc201e --- /dev/null +++ b/IntelFspPkg/Tools/PatchFv.py @@ -0,0 +1,567 @@ +## @ PatchFv.py +# +# Copyright (c) 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License that accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +import os +import re +import sys + +def readDataFromFile (binfile, offset, len=1): + fd = open(binfile, "r+b") + fsize = os.path.getsize(binfile) + offval = offset & 0xFFFFFFFF + if (offval & 0x80000000): + offval = fsize - (0xFFFFFFFF - offval + 1) + fd.seek(offval) + bytearray = [ord(b) for b in fd.read(len)] + value = 0; + idx = len - 1; + while idx >= 0: + value = value << 8 | bytearray[idx] + idx = idx - 1 + fd.close() + return value + +def patchDataInFile (binfile, offset, value, len=1): + fd = open(binfile, "r+b") + fsize = os.path.getsize(binfile) + offval = offset & 0xFFFFFFFF + if (offval & 0x80000000): + offval = fsize - (0xFFFFFFFF - offval + 1) + bytearray = [] + idx = 0; + while idx < len: + bytearray.append(value & 0xFF) + value = value >> 8 + idx = idx + 1 + fd.seek(offval) + fd.write("".join(chr(b) for b in bytearray)) + fd.close() + return len; + + +class Symbols: + def __init__(self): + self.dictSymbolAddress = {} + self.dictGuidNameXref = {} + self.dictFfsOffset = {} + self.dictVariable = {} + self.dictModBase = {} + self.fdFile = None + self.string = "" + self.fdBase = 0xFFFFFFFF + self.fdSize = 0 + self.index = 0 + self.parenthesisOpenSet = '([{<' + self.parenthesisCloseSet = ')]}>' + + def getFdFile (self): + return self.fdFile + + def getFdSize (self): + return self.fdSize + + def createDicts (self, fvDir, fvNames): + if not os.path.isdir(fvDir): + raise Exception ("'%s' is not a valid directory!" % FvDir) + + xrefFile = os.path.join(fvDir, "Guid.xref") + if not os.path.exists(xrefFile): + raise Exception("Cannot open GUID Xref file '%s'!" % xrefFile) + + self.dictGuidNameXref = {} + self.parseGuidXrefFile(xrefFile) + + fvList = fvNames.split(":") + fdBase = fvList.pop() + if len(fvList) == 0: + fvList.append(fdBase) + + fdFile = os.path.join(fvDir, fdBase.strip() + ".fd") + if not os.path.exists(fdFile): + raise Exception("Cannot open FD file '%s'!" % fdFile) + + self.fdFile = fdFile + self.fdSize = os.path.getsize(fdFile) + + infFile = os.path.join(fvDir, fvList[0].strip()) + ".inf" + if not os.path.exists(infFile): + raise Exception("Cannot open INF file '%s'!" % infFile) + + self.parseInfFile(infFile) + + self.dictVariable = {} + self.dictVariable["FDSIZE"] = self.fdSize + self.dictVariable["FDBASE"] = self.fdBase + + self.dictSymbolAddress = {} + self.dictFfsOffset = {} + for file in fvList: + + fvFile = os.path.join(fvDir, file.strip()) + ".Fv" + mapFile = fvFile + ".map" + if not os.path.exists(mapFile): + raise Exception("Cannot open MAP file '%s'!" % mapFile) + + self.parseFvMapFile(mapFile) + + fvTxtFile = fvFile + ".txt" + if not os.path.exists(fvTxtFile): + raise Exception("Cannot open FV TXT file '%s'!" % fvTxtFile) + + self.parseFvTxtFile(fvTxtFile) + + ffsDir = os.path.join(fvDir, "Ffs") + if (os.path.isdir(ffsDir)): + for item in os.listdir(ffsDir): + if len(item) <= 0x24: + continue + mapFile =os.path.join(ffsDir, item, "%s.map" % item[0:0x24]) + if not os.path.exists(mapFile): + continue + self.parseModMapFile(item[0x24:], mapFile) + + return 0 + + def getFvOffsetInFd(self, fvFile): + fvHandle = open(fvFile, "r+b") + fdHandle = open(self.fdFile, "r+b") + offset = fdHandle.read().find(fvHandle.read(0x70)) + fvHandle.close() + fdHandle.close() + if offset == -1: + raise Exception("Could not locate FV file %s in FD!" % fvFile) + return offset + + def parseInfFile(self, infFile): + fvOffset = self.getFvOffsetInFd(infFile[0:-4] + ".Fv") + fdIn = open(infFile, "r") + rptLine = fdIn.readline() + self.fdBase = 0xFFFFFFFF + while (rptLine != "" ): + #EFI_BASE_ADDRESS = 0xFFFDF400 + match = re.match("^EFI_BASE_ADDRESS\s*=\s*(0x[a-fA-F0-9]+)", rptLine) + if match is not None: + self.fdBase = int(match.group(1), 16) - fvOffset + rptLine = fdIn.readline() + fdIn.close() + if self.fdBase == 0xFFFFFFFF: + raise Exception("Could not find EFI_BASE_ADDRESS in INF file!" % fvFile) + return 0 + + def parseFvTxtFile(self, fvTxtFile): + fvOffset = self.getFvOffsetInFd(fvTxtFile[0:-4]) + fdIn = open(fvTxtFile, "r") + rptLine = fdIn.readline() + while (rptLine != "" ): + match = re.match("(0x[a-fA-F0-9]+)\s([0-9a-fA-F\-]+)", rptLine) + if match is not None: + self.dictFfsOffset[match.group(2)] = "0x%08X" % (int(match.group(1), 16) + fvOffset) + rptLine = fdIn.readline() + fdIn.close() + return 0 + + def parseFvMapFile(self, mapFile): + fdIn = open(mapFile, "r") + rptLine = fdIn.readline() + modName = "" + while (rptLine != "" ): + if rptLine[0] != ' ': + #DxeIpl (Fixed Flash Address, BaseAddress=0x00fffb4310, EntryPoint=0x00fffb4958) + #(GUID=86D70125-BAA3-4296-A62F-602BEBBB9081 .textbaseaddress=0x00fffb4398 .databaseaddress=0x00fffb4178) + match = re.match("([_a-zA-Z0-9\-]+)\s\(.+BaseAddress=(0x[0-9a-fA-F]+),\s+EntryPoint=(0x[0-9a-fA-F]+)\)", rptLine) + if match is not None: + modName = match.group(1) + if len(modName) == 36: + modName = self.dictGuidNameXref[modName.upper()] + self.dictModBase['%s:BASE' % modName] = int (match.group(2), 16) + self.dictModBase['%s:ENTRY' % modName] = int (match.group(3), 16) + match = re.match("\(GUID=([A-Z0-9\-]+)\s+\.textbaseaddress=(0x[0-9a-fA-F]+)\s+\.databaseaddress=(0x[0-9a-fA-F]+)\)", rptLine) + if match is not None: + modName = match.group(1) + if len(modName) == 36: + modName = self.dictGuidNameXref[modName.upper()] + self.dictModBase['%s:TEXT' % modName] = int (match.group(2), 16) + self.dictModBase['%s:DATA' % modName] = int (match.group(3), 16) + else: + # 0x00fff8016c __ModuleEntryPoint + match = re.match("^\s+(0x[a-z0-9]+)\s+([_a-zA-Z0-9]+)", rptLine) + if match is not None: + self.dictSymbolAddress["%s:%s"%(modName, match.group(2))] = match.group(1) + rptLine = fdIn.readline() + fdIn.close() + return 0 + + def parseModMapFile(self, moduleName, mapFile): + modSymbols = {} + fdIn = open(mapFile, "r") + reportLine = fdIn.readline() + if reportLine.strip().find("Archive member included because of file (symbol)") != -1: + #GCC + # 0x0000000000001d55 IoRead8 + patchMapFileMatchString = "\s+(0x[0-9a-fA-F]{16})\s+([^\s][^0x][_a-zA-Z0-9\-]+)\s" + matchKeyGroupIndex = 2 + matchSymbolGroupIndex = 1 + moduleEntryPoint = "_ModuleEntryPoint" + else: + #MSFT + #0003:00000190 _gComBase 00007a50 SerialPo + patchMapFileMatchString = "^\s[0-9a-fA-F]{4}:[0-9a-fA-F]{8}\s+(\w+)\s+([0-9a-fA-F]{8}\s+)" + matchKeyGroupIndex = 1 + matchSymbolGroupIndex = 2 + moduleEntryPoint = "__ModuleEntryPoint" + while (reportLine != "" ): + match = re.match(patchMapFileMatchString, reportLine) + if match is not None: + modSymbols[match.group(matchKeyGroupIndex)] = match.group(matchSymbolGroupIndex) + reportLine = fdIn.readline() + fdIn.close() + + if not moduleEntryPoint in modSymbols: + return 1 + + modEntry = '%s:%s' % (moduleName,moduleEntryPoint) + if not modEntry in self.dictSymbolAddress: + modKey = '%s:ENTRY' % moduleName + if modKey in self.dictModBase: + baseOffset = self.dictModBase['%s:ENTRY' % moduleName] - int(modSymbols[moduleEntryPoint], 16) + else: + return 2 + else: + baseOffset = int(self.dictSymbolAddress[modEntry], 16) - int(modSymbols[moduleEntryPoint], 16) + for symbol in modSymbols: + fullSym = "%s:%s" % (moduleName, symbol) + if not fullSym in self.dictSymbolAddress: + self.dictSymbolAddress[fullSym] = "0x00%08x" % (baseOffset+ int(modSymbols[symbol], 16)) + return 0 + + def parseGuidXrefFile(self, xrefFile): + fdIn = open(xrefFile, "r") + rptLine = fdIn.readline() + while (rptLine != "" ): + match = re.match("([0-9a-fA-F\-]+)\s([_a-zA-Z0-9]+)", rptLine) + if match is not None: + self.dictGuidNameXref[match.group(1).upper()] = match.group(2) + rptLine = fdIn.readline() + fdIn.close() + return 0 + + def getCurr(self): + try: + return self.string[self.index] + except Exception: + return '' + + def isLast(self): + return self.index == len(self.string) + + def moveNext(self): + self.index += 1 + + def skipSpace(self): + while not self.isLast(): + if self.getCurr() in ' \t': + self.moveNext() + else: + return + + def parseValue(self): + self.skipSpace() + var = '' + while not self.isLast(): + char = self.getCurr() + if char.lower() in '_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:-': + var += char + self.moveNext() + else: + break + + if ':' in var: + partList = var.split(':') + if len(partList) != 2: + raise Exception("Unrecognized expression %s" % var) + modName = partList[0] + modOff = partList[1] + if ('-' not in modName) and (modOff[0] in '0123456789'): + # MOD: OFFSET + var = self.getModGuid(modName) + ":" + modOff + if '-' in var: # GUID:OFFSET + value = self.getGuidOff(var) + else: + value = self.getSymbols(var) + self.synUsed = True + else: + if var[0] in '0123456789': + value = self.getNumber(var) + else: + value = self.getVariable(var) + return int(value) + + def parseSingleOp(self): + self.skipSpace() + char = self.getCurr() + if char == '~': + self.moveNext() + return ~self.parseBrace() + else: + return self.parseValue() + + def parseBrace(self): + self.skipSpace() + char = self.getCurr() + parenthesisType = self.parenthesisOpenSet.find(char) + if parenthesisType >= 0: + self.moveNext() + value = self.parseExpr() + self.skipSpace() + if self.getCurr() != self.parenthesisCloseSet[parenthesisType]: + raise Exception("No closing brace") + self.moveNext() + if parenthesisType == 1: # [ : Get content + value = self.getContent(value) + elif parenthesisType == 2: # { : To address + value = self.toAddress(value) + elif parenthesisType == 3: # < : To offset + value = self.toOffset(value) + return value + else: + return self.parseSingleOp() + + def parseMul(self): + values = [self.parseBrace()] + while True: + self.skipSpace() + char = self.getCurr() + if char == '*': + self.moveNext() + values.append(self.parseBrace()) + else: + break + value = 1; + for each in values: + value *= each + return value + + def parseAndOr(self): + values = [self.parseMul()] + op = None + value = 0xFFFFFFFF; + while True: + self.skipSpace() + char = self.getCurr() + if char == '&': + self.moveNext() + values.append(self.parseMul()) + op = char + elif char == '|': + div_index = self.index + self.moveNext() + values.append(self.parseMul()) + value = 0 + op = char + else: + break + + for each in values: + if op == '|': + value |= each + else: + value &= each + + return value + + def parseAddMinus(self): + values = [self.parseAndOr()] + while True: + self.skipSpace() + char = self.getCurr() + if char == '+': + self.moveNext() + values.append(self.parseAndOr()) + elif char == '-': + self.moveNext() + values.append(-1 * self.parseAndOr()) + else: + break + return sum(values) + + def parseExpr(self): + return self.parseAddMinus() + + def getResult(self): + value = self.parseExpr() + self.skipSpace() + if not self.isLast(): + raise Exception("Unexpected character found '%s'" % self.getCurr()) + return value + + def getModGuid(self, var): + guid = (guid for guid,name in self.dictGuidNameXref.items() if name==var) + try: + value = guid.next() + except Exception: + raise Exception("Unknown module name %s !" % var) + return value + + def getVariable(self, var): + value = self.dictVariable.get(var, None) + if value == None: + raise Exception("Unrecognized variable '%s'" % var) + return value + + def getNumber(self, var): + var = var.strip() + if var.startswith('0x'): # HEX + value = int(var, 16) + else: + value = int(var, 10) + return value + + def getContent(self, value): + if (value >= self.fdBase) and (value < self.fdBase + self.fdSize): + value = value - self.fdBase + if value >= self.fdSize: + raise Exception("Invalid file offset 0x%08x !" % value) + return readDataFromFile (self.fdFile, value, 4) + + def toAddress(self, value): + if value < self.fdSize: + value = value + self.fdBase + return value + + def toOffset(self, value): + if value > self.fdBase: + value = value - self.fdBase + return value + + def getGuidOff(self, value): + # GUID:Offset + symbolName = value.split(':') + if len(symbolName) == 2 and self.dictFfsOffset.has_key(symbolName[0]): + value = (int(self.dictFfsOffset[symbolName[0]], 16) + int(symbolName[1], 16)) & 0xFFFFFFFF + else: + raise Exception("Unknown GUID %s !" % value) + return value + + def getSymbols(self, value): + if self.dictSymbolAddress.has_key(value): + # Module:Function + ret = int (self.dictSymbolAddress[value], 16) + else: + raise Exception("Unknown symbol %s !" % value) + return ret + + def evaluate(self, expression, isOffset): + self.index = 0 + self.synUsed = False + self.string = expression + value = self.getResult() + if isOffset: + if self.synUsed: + # Consider it as an address first + if (value >= self.fdBase) and (value < self.fdBase + self.fdSize): + value = value - self.fdBase + if value & 0x80000000: + # Consider it as a negative offset next + offset = (~value & 0xFFFFFFFF) + 1 + if offset < self.fdSize: + value = self.fdSize - offset + if value >= self.fdSize: + raise Exception("Invalid offset expression !") + return value & 0xFFFFFFFF + +def usage(): + print "Usage: \n\tPatchFv FvBuildDir [FvFileBaseNames:]FdFileBaseNameToPatch \"Offset, Value\"" + +def main(): + # + # Parse the options and args + # + symTables = Symbols() + + if len(sys.argv) < 4: + Usage() + return 1 + + if symTables.createDicts(sys.argv[1], sys.argv[2]) != 0: + print "ERROR: Failed to create symbol dictionary!!" + return 2 + + fdFile = symTables.getFdFile() + fdSize = symTables.getFdSize() + + try: + comment = "" + for fvFile in sys.argv[3:]: + items = fvFile.split(",") + if len (items) < 2: + raise Exception("Expect more arguments for '%s'!" % fvFile) + + comment = "" + command = "" + params = [] + for item in items: + item = item.strip() + if item.startswith("@"): + comment = item[1:] + elif item.startswith("$"): + command = item[1:] + else: + if len(params) == 0: + isOffset = True + else : + isOffset = False + params.append (symTables.evaluate(item, isOffset)) + + if command == "": + # Patch a DWORD + if len (params) == 2: + offset = params[0] + value = params[1] + oldvalue = readDataFromFile(fdFile, offset, 4) + ret = patchDataInFile (fdFile, offset, value, 4) - 4 + else: + raise Exception ("Patch command needs 2 parameters !") + + if ret: + raise Exception ("Patch failed for offset 0x%08X" % offset) + else: + print "Patched offset 0x%08X:[%08X] with value 0x%08X # %s" % (offset, oldvalue, value, comment) + + elif command == "COPY": + # Copy binary block from source to destination + if len (params) == 3: + src = symTables.toOffset(params[0]) + dest = symTables.toOffset(params[1]) + clen = symTables.toOffset(params[2]) + if (dest + clen <= fdSize) and (src + clen <= fdSize): + oldvalue = readDataFromFile(fdFile, src, clen) + ret = patchDataInFile (fdFile, dest, oldvalue, clen) - clen + else: + raise Exception ("Copy command OFFSET or LENGTH parameter is invalid !") + else: + raise Exception ("Copy command needs 3 parameters !") + + if ret: + raise Exception ("Copy failed from offset 0x%08X to offset 0x%08X!" % (src, dest)) + else : + print "Copied %d bytes from offset 0x%08X ~ offset 0x%08X # %s" % (clen, src, dest, comment) + else: + raise Exception ("Unknown command %s!" % command) + return 0 + + except Exception as (ex): + print "ERROR: %s" % ex + return 1 + +if __name__ == '__main__': + sys.exit(main()) -- cgit v1.2.3