import re\r
import sys\r
\r
+#\r
+# Read data from file\r
+#\r
+# param [in] binfile Binary file\r
+# param [in] offset Offset\r
+# param [in] len Length\r
+#\r
+# retval value Value\r
+#\r
def readDataFromFile (binfile, offset, len=1):\r
fd = open(binfile, "r+b")\r
fsize = os.path.getsize(binfile)\r
fd.close()\r
return value\r
\r
+#\r
+# Check FSP header is valid or not\r
+#\r
+# param [in] binfile Binary file\r
+#\r
+# retval boolean True: valid; False: invalid\r
+#\r
def IsFspHeaderValid (binfile):\r
fd = open (binfile, "rb")\r
- bindat = fd.read(0x200)\r
+ bindat = fd.read(0x200) # only read first 0x200 bytes\r
fd.close()\r
- HeaderList = ['FSPH' , 'FSPP' , 'FSPE']\r
+ HeaderList = ['FSPH' , 'FSPP' , 'FSPE'] # Check 'FSPH', 'FSPP', and 'FSPE' in the FSP header\r
OffsetList = []\r
for each in HeaderList:\r
if each in bindat:\r
else:\r
idx = 0\r
OffsetList.append(idx)\r
- if not OffsetList[0] or not OffsetList[1]:\r
+ if not OffsetList[0] or not OffsetList[1]: # If 'FSPH' or 'FSPP' is missing, it will return false\r
return False\r
Revision = ord(bindat[OffsetList[0] + 0x0B])\r
+ #\r
+ # if revision is bigger than 1, it means it is FSP v1.1 or greater revision, which must contain 'FSPE'.\r
+ #\r
if Revision > 1 and not OffsetList[2]:\r
- return False\r
+ return False # If FSP v1.1 or greater without 'FSPE', then return false\r
return True\r
\r
+#\r
+# Patch data in file\r
+#\r
+# param [in] binfile Binary file\r
+# param [in] offset Offset\r
+# param [in] value Patch value\r
+# param [in] len Length\r
+#\r
+# retval len Length\r
+#\r
def patchDataInFile (binfile, offset, value, len=1):\r
fd = open(binfile, "r+b")\r
fsize = os.path.getsize(binfile)\r
self.parenthesisOpenSet = '([{<'\r
self.parenthesisCloseSet = ')]}>'\r
\r
+ #\r
+ # Get FD file\r
+ #\r
+ # retval self.fdFile Retrieve FD file\r
+ #\r
def getFdFile (self):\r
return self.fdFile\r
\r
+ #\r
+ # Get FD size\r
+ #\r
+ # retval self.fdSize Retrieve the size of FD file\r
+ #\r
def getFdSize (self):\r
return self.fdSize\r
\r
+ #\r
+ # Create dictionaries\r
+ #\r
+ # param [in] fvDir FV's directory\r
+ # param [in] fvNames All FV's names\r
+ #\r
+ # retval 0 Created dictionaries successfully\r
+ #\r
def createDicts (self, fvDir, fvNames):\r
+ #\r
+ # If the fvDir is not a dirctory, then raise an exception\r
+ #\r
if not os.path.isdir(fvDir):\r
raise Exception ("'%s' is not a valid directory!" % FvDir)\r
\r
+ #\r
+ # If the Guid.xref is not existing in fvDir, then raise an exception\r
+ #\r
xrefFile = os.path.join(fvDir, "Guid.xref")\r
if not os.path.exists(xrefFile):\r
raise Exception("Cannot open GUID Xref file '%s'!" % xrefFile)\r
\r
+ #\r
+ # Add GUID reference to dictionary\r
+ #\r
self.dictGuidNameXref = {}\r
self.parseGuidXrefFile(xrefFile)\r
\r
+ #\r
+ # Split up each FV from fvNames and get the fdBase\r
+ #\r
fvList = fvNames.split(":")\r
fdBase = fvList.pop()\r
if len(fvList) == 0:\r
fvList.append(fdBase)\r
\r
+ #\r
+ # If the FD file is not existing, then raise an exception\r
+ #\r
fdFile = os.path.join(fvDir, fdBase.strip() + ".fd")\r
if not os.path.exists(fdFile):\r
raise Exception("Cannot open FD file '%s'!" % fdFile)\r
\r
+ #\r
+ # Get the size of the FD file\r
+ #\r
self.fdFile = fdFile\r
self.fdSize = os.path.getsize(fdFile)\r
\r
+ #\r
+ # If the INF file, which is the first element of fvList, is not existing, then raise an exception\r
+ #\r
infFile = os.path.join(fvDir, fvList[0].strip()) + ".inf"\r
if not os.path.exists(infFile):\r
raise Exception("Cannot open INF file '%s'!" % infFile)\r
\r
+ #\r
+ # Parse INF file in order to get fdBase and then assign those values to dictVariable\r
+ #\r
self.parseInfFile(infFile)\r
-\r
self.dictVariable = {}\r
self.dictVariable["FDSIZE"] = self.fdSize\r
self.dictVariable["FDBASE"] = self.fdBase\r
\r
+ #\r
+ # Collect information from FV MAP file and FV TXT file then\r
+ # put them into dictionaries\r
+ #\r
self.dictSymbolAddress = {}\r
self.dictFfsOffset = {}\r
for file in fvList:\r
\r
+ #\r
+ # If the .Fv.map file is not existing, then raise an exception.\r
+ # Otherwise, parse FV MAP file\r
+ #\r
fvFile = os.path.join(fvDir, file.strip()) + ".Fv"\r
mapFile = fvFile + ".map"\r
if not os.path.exists(mapFile):\r
\r
self.parseFvMapFile(mapFile)\r
\r
+ #\r
+ # If the .Fv.txt file is not existing, then raise an exception.\r
+ # Otherwise, parse FV TXT file\r
+ #\r
fvTxtFile = fvFile + ".txt"\r
if not os.path.exists(fvTxtFile):\r
raise Exception("Cannot open FV TXT file '%s'!" % fvTxtFile)\r
\r
self.parseFvTxtFile(fvTxtFile)\r
\r
+ #\r
+ # Search all MAP files in FFS directory if it exists then parse MOD MAP file\r
+ #\r
ffsDir = os.path.join(fvDir, "Ffs")\r
if (os.path.isdir(ffsDir)):\r
for item in os.listdir(ffsDir):\r
\r
return 0\r
\r
+ #\r
+ # Get FV offset in FD file\r
+ #\r
+ # param [in] fvFile FV file\r
+ #\r
+ # retval offset Got FV offset successfully\r
+ #\r
def getFvOffsetInFd(self, fvFile):\r
+ #\r
+ # Check if the first 0x70 bytes of fvFile can be found in fdFile\r
+ #\r
fvHandle = open(fvFile, "r+b")\r
fdHandle = open(self.fdFile, "r+b")\r
offset = fdHandle.read().find(fvHandle.read(0x70))\r
raise Exception("Could not locate FV file %s in FD!" % fvFile)\r
return offset\r
\r
+ #\r
+ # Parse INF file\r
+ #\r
+ # param [in] infFile INF file\r
+ #\r
+ # retval 0 Parsed INF file successfully\r
+ #\r
def parseInfFile(self, infFile):\r
+ #\r
+ # Get FV offset and search EFI_BASE_ADDRESS in the FD file \r
+ # then assign the value of EFI_BASE_ADDRESS to fdBase\r
+ #\r
fvOffset = self.getFvOffsetInFd(infFile[0:-4] + ".Fv")\r
fdIn = open(infFile, "r")\r
rptLine = fdIn.readline()\r
raise Exception("Could not find EFI_BASE_ADDRESS in INF file!" % fvFile)\r
return 0\r
\r
+ #\r
+ # Parse FV TXT file\r
+ #\r
+ # param [in] fvTxtFile .Fv.txt file\r
+ #\r
+ # retval 0 Parsed FV TXT file successfully\r
+ #\r
def parseFvTxtFile(self, fvTxtFile):\r
+ #\r
+ # Get information from .Fv.txt in order to create a dictionary\r
+ # For example,\r
+ # self.dictFfsOffset[912740BE-2284-4734-B971-84B027353F0C] = 0x000D4078\r
+ #\r
fvOffset = self.getFvOffsetInFd(fvTxtFile[0:-4])\r
fdIn = open(fvTxtFile, "r")\r
rptLine = fdIn.readline()\r
fdIn.close()\r
return 0\r
\r
+ #\r
+ # Parse FV MAP file\r
+ #\r
+ # param [in] mapFile .Fv.map file\r
+ #\r
+ # retval 0 Parsed FV MAP file successfully\r
+ #\r
def parseFvMapFile(self, mapFile):\r
+ #\r
+ # Get information from .Fv.map in order to create dictionaries\r
+ # For example,\r
+ # self.dictModBase[FspSecCore:BASE] = 4294592776 (0xfffa4908)\r
+ # self.dictModBase[FspSecCore:ENTRY] = 4294606552 (0xfffa7ed8)\r
+ # self.dictModBase[FspSecCore:TEXT] = 4294593080 (0xfffa4a38)\r
+ # self.dictModBase[FspSecCore:DATA] = 4294612280 (0xfffa9538)\r
+ # self.dictSymbolAddress[FspSecCore:_SecStartup] = 0x00fffa4a38\r
+ #\r
fdIn = open(mapFile, "r")\r
rptLine = fdIn.readline()\r
modName = ""\r
fdIn.close()\r
return 0\r
\r
+ #\r
+ # Parse MOD MAP file\r
+ #\r
+ # param [in] moduleName Module name\r
+ # param [in] mapFile .Fv.map file\r
+ #\r
+ # retval 0 Parsed MOD MAP file successfully\r
+ # retval 1 There is no moduleEntryPoint in modSymbols\r
+ #\r
def parseModMapFile(self, moduleName, mapFile):\r
+ #\r
+ # Get information from mapFile by moduleName in order to create a dictionary\r
+ # For example,\r
+ # self.dictSymbolAddress[FspSecCore:___guard_fids_count] = 0x00fffa4778\r
+ #\r
modSymbols = {}\r
fdIn = open(mapFile, "r")\r
- reportLine = fdIn.readline()\r
+ reportLines = fdIn.readlines()\r
+ fdIn.close()\r
+\r
+ moduleEntryPoint = "__ModuleEntryPoint"\r
+ reportLine = reportLines[0]\r
if reportLine.strip().find("Archive member included") != -1:\r
#GCC\r
# 0x0000000000001d55 IoRead8\r
patchMapFileMatchString = "\s+(0x[0-9a-fA-F]{16})\s+([^\s][^0x][_a-zA-Z0-9\-]+)\s"\r
matchKeyGroupIndex = 2\r
matchSymbolGroupIndex = 1\r
- moduleEntryPoint = "_ModuleEntryPoint"\r
+ prefix = '_'\r
else:\r
#MSFT\r
#0003:00000190 _gComBase 00007a50 SerialPo\r
patchMapFileMatchString = "^\s[0-9a-fA-F]{4}:[0-9a-fA-F]{8}\s+(\w+)\s+([0-9a-fA-F]{8}\s+)"\r
matchKeyGroupIndex = 1\r
matchSymbolGroupIndex = 2\r
- moduleEntryPoint = "__ModuleEntryPoint"\r
- while (reportLine != "" ):\r
+ prefix = ''\r
+\r
+ for reportLine in reportLines:\r
match = re.match(patchMapFileMatchString, reportLine)\r
if match is not None:\r
- modSymbols[match.group(matchKeyGroupIndex)] = match.group(matchSymbolGroupIndex)\r
- reportLine = fdIn.readline()\r
- fdIn.close()\r
+ modSymbols[prefix + match.group(matchKeyGroupIndex)] = match.group(matchSymbolGroupIndex)\r
+\r
+ # Handle extra module patchable PCD variable in Linux map since it might have different format\r
+ # .data._gPcd_BinaryPatch_PcdVpdBaseAddress\r
+ # 0x0000000000003714 0x4 /tmp/ccmytayk.ltrans1.ltrans.o\r
+ handleNext = False\r
+ if matchSymbolGroupIndex == 1:\r
+ for reportLine in reportLines:\r
+ if handleNext:\r
+ handleNext = False\r
+ pcdName = match.group(1)\r
+ match = re.match("\s+(0x[0-9a-fA-F]{16})\s+", reportLine)\r
+ if match is not None:\r
+ modSymbols[prefix + pcdName] = match.group(1)\r
+ else:\r
+ match = re.match("^\s\.data\.(_gPcd_BinaryPatch[_a-zA-Z0-9\-]+)", reportLine)\r
+ if match is not None:\r
+ handleNext = True\r
+ continue\r
\r
if not moduleEntryPoint in modSymbols:\r
return 1\r
self.dictSymbolAddress[fullSym] = "0x00%08x" % (baseOffset+ int(modSymbols[symbol], 16))\r
return 0\r
\r
+ #\r
+ # Parse Guid.xref file\r
+ #\r
+ # param [in] xrefFile the full directory of Guid.xref file\r
+ #\r
+ # retval 0 Parsed Guid.xref file successfully\r
+ #\r
def parseGuidXrefFile(self, xrefFile):\r
+ #\r
+ # Get information from Guid.xref in order to create a GuidNameXref dictionary\r
+ # The dictGuidNameXref, for example, will be like\r
+ # dictGuidNameXref [1BA0062E-C779-4582-8566-336AE8F78F09] = FspSecCore\r
+ #\r
fdIn = open(xrefFile, "r")\r
rptLine = fdIn.readline()\r
while (rptLine != "" ):\r
fdIn.close()\r
return 0\r
\r
+ #\r
+ # Get current character\r
+ #\r
+ # retval elf.string[self.index]\r
+ # retval '' Exception\r
+ #\r
def getCurr(self):\r
try:\r
return self.string[self.index]\r
except Exception:\r
return ''\r
\r
+ #\r
+ # Check to see if it is last index\r
+ #\r
+ # retval self.index\r
+ #\r
def isLast(self):\r
return self.index == len(self.string)\r
\r
+ #\r
+ # Move to next index\r
+ #\r
def moveNext(self):\r
self.index += 1\r
\r
+ #\r
+ # Skip space\r
+ #\r
def skipSpace(self):\r
while not self.isLast():\r
if self.getCurr() in ' \t':\r
else:\r
return\r
\r
+ #\r
+ # Parse value\r
+ #\r
+ # retval value\r
+ #\r
def parseValue(self):\r
self.skipSpace()\r
var = ''\r
value = self.getVariable(var)\r
return int(value)\r
\r
+ #\r
+ # Parse single operation\r
+ #\r
+ # retval ~self.parseBrace() or self.parseValue()\r
+ #\r
def parseSingleOp(self):\r
self.skipSpace()\r
char = self.getCurr()\r
else:\r
return self.parseValue()\r
\r
+ #\r
+ # Parse symbol of Brace([, {, <)\r
+ #\r
+ # retval value or self.parseSingleOp()\r
+ #\r
def parseBrace(self):\r
self.skipSpace()\r
char = self.getCurr()\r
else:\r
return self.parseSingleOp()\r
\r
+ #\r
+ # Parse symbol of Multiplier(*)\r
+ #\r
+ # retval value or self.parseSingleOp()\r
+ #\r
def parseMul(self):\r
values = [self.parseBrace()]\r
while True:\r
value *= each\r
return value\r
\r
+ #\r
+ # Parse symbol of And(&) and Or(|)\r
+ #\r
+ # retval value\r
+ #\r
def parseAndOr(self):\r
values = [self.parseMul()]\r
op = None\r
\r
return value\r
\r
+ #\r
+ # Parse symbol of Add(+) and Minus(-)\r
+ #\r
+ # retval sum(values)\r
+ #\r
def parseAddMinus(self):\r
values = [self.parseAndOr()]\r
while True:\r
break\r
return sum(values)\r
\r
+ #\r
+ # Parse expression\r
+ #\r
+ # retval self.parseAddMinus()\r
+ #\r
def parseExpr(self):\r
return self.parseAddMinus()\r
\r
+ #\r
+ # Get result\r
+ #\r
+ # retval value\r
+ #\r
def getResult(self):\r
value = self.parseExpr()\r
self.skipSpace()\r
raise Exception("Unexpected character found '%s'" % self.getCurr())\r
return value\r
\r
+ #\r
+ # Get module GUID\r
+ #\r
+ # retval value\r
+ #\r
def getModGuid(self, var):\r
guid = (guid for guid,name in self.dictGuidNameXref.items() if name==var)\r
try:\r
raise Exception("Unknown module name %s !" % var)\r
return value\r
\r
+ #\r
+ # Get variable\r
+ #\r
+ # retval value\r
+ #\r
def getVariable(self, var):\r
value = self.dictVariable.get(var, None)\r
if value == None:\r
raise Exception("Unrecognized variable '%s'" % var)\r
return value\r
\r
+ #\r
+ # Get number\r
+ #\r
+ # retval value\r
+ #\r
def getNumber(self, var):\r
var = var.strip()\r
if var.startswith('0x'): # HEX\r
value = int(var, 10)\r
return value\r
\r
+ #\r
+ # Get content\r
+ #\r
+ # param [in] value\r
+ #\r
+ # retval value\r
+ #\r
def getContent(self, value):\r
if (value >= self.fdBase) and (value < self.fdBase + self.fdSize):\r
value = value - self.fdBase\r
raise Exception("Invalid file offset 0x%08x !" % value)\r
return readDataFromFile (self.fdFile, value, 4)\r
\r
+ #\r
+ # Change value to address\r
+ #\r
+ # param [in] value\r
+ #\r
+ # retval value\r
+ #\r
def toAddress(self, value):\r
if value < self.fdSize:\r
value = value + self.fdBase\r
return value\r
\r
+ #\r
+ # Change value to offset\r
+ #\r
+ # param [in] value\r
+ #\r
+ # retval value\r
+ #\r
def toOffset(self, value):\r
if value > self.fdBase:\r
value = value - self.fdBase\r
return value\r
\r
+ #\r
+ # Get GUID offset\r
+ #\r
+ # param [in] value\r
+ #\r
+ # retval value\r
+ #\r
def getGuidOff(self, value):\r
# GUID:Offset\r
symbolName = value.split(':')\r
raise Exception("Unknown GUID %s !" % value)\r
return value\r
\r
+ #\r
+ # Get symbols\r
+ #\r
+ # param [in] value\r
+ #\r
+ # retval ret\r
+ #\r
def getSymbols(self, value):\r
if self.dictSymbolAddress.has_key(value):\r
# Module:Function\r
raise Exception("Unknown symbol %s !" % value)\r
return ret\r
\r
+ #\r
+ # Evaluate symbols\r
+ #\r
+ # param [in] expression\r
+ # param [in] isOffset\r
+ #\r
+ # retval value & 0xFFFFFFFF\r
+ #\r
def evaluate(self, expression, isOffset):\r
self.index = 0\r
self.synUsed = False\r
raise Exception("Invalid offset expression !")\r
return value & 0xFFFFFFFF\r
\r
+#\r
+# Print out the usage\r
+#\r
def usage():\r
print "Usage: \n\tPatchFv FvBuildDir [FvFileBaseNames:]FdFileBaseNameToPatch \"Offset, Value\""\r
\r
#\r
symTables = Symbols()\r
\r
+ #\r
+ # If the arguments are less than 4, then return an error.\r
+ #\r
if len(sys.argv) < 4:\r
Usage()\r
return 1\r
\r
+ #\r
+ # If it fails to create dictionaries, then return an error.\r
+ #\r
if symTables.createDicts(sys.argv[1], sys.argv[2]) != 0:\r
print "ERROR: Failed to create symbol dictionary!!"\r
return 2\r
\r
+ #\r
+ # Get FD file and size\r
+ #\r
fdFile = symTables.getFdFile()\r
fdSize = symTables.getFdSize()\r
\r
try:\r
+ #\r
+ # Check to see if FSP header is valid\r
+ #\r
ret = IsFspHeaderValid(fdFile)\r
if ret == False:\r
raise Exception ("The FSP header is not valid. Stop patching FD.")\r
comment = ""\r
for fvFile in sys.argv[3:]:\r
+ #\r
+ # Check to see if it has enough arguments\r
+ #\r
items = fvFile.split(",")\r
if len (items) < 2:\r
raise Exception("Expect more arguments for '%s'!" % fvFile)\r
isOffset = True\r
else :\r
isOffset = False\r
+ #\r
+ # Parse symbols then append it to params\r
+ #\r
params.append (symTables.evaluate(item, isOffset))\r
\r
+ #\r
+ # Patch a new value into FD file if it is not a command\r
+ #\r
if command == "":\r
# Patch a DWORD\r
if len (params) == 2:\r
print "Patched offset 0x%08X:[%08X] with value 0x%08X # %s" % (offset, oldvalue, value, comment)\r
\r
elif command == "COPY":\r
+ #\r
# Copy binary block from source to destination\r
+ #\r
if len (params) == 3:\r
src = symTables.toOffset(params[0])\r
dest = symTables.toOffset(params[1])\r