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