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