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