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