Handle extra module patchable PCD variable in Linux map.
authorYao, Jiewen <jiewen.yao@intel.com>
Sun, 6 Sep 2015 22:36:43 +0000 (22:36 +0000)
committerjyao1 <jyao1@Edk2>
Sun, 6 Sep 2015 22:36:43 +0000 (22:36 +0000)
Add comment for python function, too.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: "Yao, Jiewen" <jiewen.yao@intel.com>
Reviewed-by: "Mudusuru, Giri P" <giri.p.mudusuru@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18406 6f19259b-4bc3-4df7-8a09-765794883524

IntelFspPkg/Tools/PatchFv.py

index 4421a83..b6dab55 100644 (file)
@@ -15,6 +15,15 @@ import os
 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
@@ -31,11 +40,18 @@ def readDataFromFile (binfile, offset, len=1):
     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
@@ -43,13 +59,26 @@ def IsFspHeaderValid (binfile):
         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
@@ -83,49 +112,98 @@ class Symbols:
         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
@@ -133,12 +211,19 @@ class Symbols:
 \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
@@ -151,7 +236,17 @@ class Symbols:
 \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
@@ -161,7 +256,18 @@ class Symbols:
             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
@@ -177,7 +283,19 @@ class Symbols:
             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
@@ -189,7 +307,23 @@ class Symbols:
         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
@@ -220,30 +354,65 @@ class Symbols:
         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
@@ -263,7 +432,19 @@ class Symbols:
                 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
@@ -274,18 +455,35 @@ class Symbols:
         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
@@ -293,6 +491,11 @@ class Symbols:
             else:\r
                 return\r
 \r
+    #\r
+    #  Parse value\r
+    #\r
+    #  retval      value\r
+    #\r
     def parseValue(self):\r
         self.skipSpace()\r
         var = ''\r
@@ -325,6 +528,11 @@ class Symbols:
                 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
@@ -334,6 +542,11 @@ class Symbols:
         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
@@ -355,6 +568,11 @@ class Symbols:
         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
@@ -370,6 +588,11 @@ class Symbols:
             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
@@ -398,6 +621,11 @@ class Symbols:
 \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
@@ -413,9 +641,19 @@ class Symbols:
                 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
@@ -423,6 +661,11 @@ class Symbols:
             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
@@ -431,12 +674,22 @@ class Symbols:
             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
@@ -445,6 +698,13 @@ class Symbols:
             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
@@ -452,16 +712,37 @@ class Symbols:
             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
@@ -471,6 +752,13 @@ class Symbols:
             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
@@ -479,6 +767,14 @@ class Symbols:
             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
@@ -498,6 +794,9 @@ class Symbols:
                 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
@@ -507,23 +806,38 @@ def main():
     #\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
@@ -542,8 +856,14 @@ def main():
                         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
@@ -560,7 +880,9 @@ def main():
                     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