]>
git.proxmox.com Git - mirror_edk2.git/blob - IntelFspPkg/Tools/PatchFv.py
2143161d2c204184d3ccce16e45cb2aead9df391
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.
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.
18 def readDataFromFile (binfile
, offset
, len=1):
19 fd
= open(binfile
, "r+b")
20 fsize
= os
.path
.getsize(binfile
)
21 offval
= offset
& 0xFFFFFFFF
22 if (offval
& 0x80000000):
23 offval
= fsize
- (0xFFFFFFFF - offval
+ 1)
25 bytearray
= [ord(b
) for b
in fd
.read(len)]
29 value
= value
<< 8 | bytearray
[idx
]
34 def IsFspHeaderValid (binfile
):
35 fd
= open (binfile
, "rb")
36 bindat
= fd
.read(0x200)
38 HeaderList
= ['FSPH' , 'FSPP' , 'FSPE']
40 for each
in HeaderList
:
42 idx
= bindat
.index(each
)
45 OffsetList
.append(idx
)
46 if not OffsetList
[0] or not OffsetList
[1]:
48 Revision
= ord(bindat
[OffsetList
[0] + 0x0B])
49 if Revision
> 1 and not OffsetList
[2]:
53 def patchDataInFile (binfile
, offset
, value
, len=1):
54 fd
= open(binfile
, "r+b")
55 fsize
= os
.path
.getsize(binfile
)
56 offval
= offset
& 0xFFFFFFFF
57 if (offval
& 0x80000000):
58 offval
= fsize
- (0xFFFFFFFF - offval
+ 1)
62 bytearray
.append(value
& 0xFF)
66 fd
.write("".join(chr(b
) for b
in bytearray
))
73 self
.dictSymbolAddress
= {}
74 self
.dictGuidNameXref
= {}
75 self
.dictFfsOffset
= {}
76 self
.dictVariable
= {}
80 self
.fdBase
= 0xFFFFFFFF
83 self
.parenthesisOpenSet
= '([{<'
84 self
.parenthesisCloseSet
= ')]}>'
92 def createDicts (self
, fvDir
, fvNames
):
93 if not os
.path
.isdir(fvDir
):
94 raise Exception ("'%s' is not a valid directory!" % FvDir
)
96 xrefFile
= os
.path
.join(fvDir
, "Guid.xref")
97 if not os
.path
.exists(xrefFile
):
98 raise Exception("Cannot open GUID Xref file '%s'!" % xrefFile
)
100 self
.dictGuidNameXref
= {}
101 self
.parseGuidXrefFile(xrefFile
)
103 fvList
= fvNames
.split(":")
104 fdBase
= fvList
.pop()
106 fvList
.append(fdBase
)
108 fdFile
= os
.path
.join(fvDir
, fdBase
.strip() + ".fd")
109 if not os
.path
.exists(fdFile
):
110 raise Exception("Cannot open FD file '%s'!" % fdFile
)
113 self
.fdSize
= os
.path
.getsize(fdFile
)
115 infFile
= os
.path
.join(fvDir
, fvList
[0].strip()) + ".inf"
116 if not os
.path
.exists(infFile
):
117 raise Exception("Cannot open INF file '%s'!" % infFile
)
119 self
.parseInfFile(infFile
)
121 self
.dictVariable
= {}
122 self
.dictVariable
["FDSIZE"] = self
.fdSize
123 self
.dictVariable
["FDBASE"] = self
.fdBase
125 self
.dictSymbolAddress
= {}
126 self
.dictFfsOffset
= {}
129 fvFile
= os
.path
.join(fvDir
, file.strip()) + ".Fv"
130 mapFile
= fvFile
+ ".map"
131 if not os
.path
.exists(mapFile
):
132 raise Exception("Cannot open MAP file '%s'!" % mapFile
)
134 self
.parseFvMapFile(mapFile
)
136 fvTxtFile
= fvFile
+ ".txt"
137 if not os
.path
.exists(fvTxtFile
):
138 raise Exception("Cannot open FV TXT file '%s'!" % fvTxtFile
)
140 self
.parseFvTxtFile(fvTxtFile
)
142 ffsDir
= os
.path
.join(fvDir
, "Ffs")
143 if (os
.path
.isdir(ffsDir
)):
144 for item
in os
.listdir(ffsDir
):
145 if len(item
) <= 0x24:
147 mapFile
=os
.path
.join(ffsDir
, item
, "%s.map" % item
[0:0x24])
148 if not os
.path
.exists(mapFile
):
150 self
.parseModMapFile(item
[0x24:], mapFile
)
154 def getFvOffsetInFd(self
, fvFile
):
155 fvHandle
= open(fvFile
, "r+b")
156 fdHandle
= open(self
.fdFile
, "r+b")
157 offset
= fdHandle
.read().find(fvHandle
.read(0x70))
161 raise Exception("Could not locate FV file %s in FD!" % fvFile
)
164 def parseInfFile(self
, infFile
):
165 fvOffset
= self
.getFvOffsetInFd(infFile
[0:-4] + ".Fv")
166 fdIn
= open(infFile
, "r")
167 rptLine
= fdIn
.readline()
168 self
.fdBase
= 0xFFFFFFFF
169 while (rptLine
!= "" ):
170 #EFI_BASE_ADDRESS = 0xFFFDF400
171 match
= re
.match("^EFI_BASE_ADDRESS\s*=\s*(0x[a-fA-F0-9]+)", rptLine
)
172 if match
is not None:
173 self
.fdBase
= int(match
.group(1), 16) - fvOffset
174 rptLine
= fdIn
.readline()
176 if self
.fdBase
== 0xFFFFFFFF:
177 raise Exception("Could not find EFI_BASE_ADDRESS in INF file!" % fvFile
)
180 def parseFvTxtFile(self
, fvTxtFile
):
181 fvOffset
= self
.getFvOffsetInFd(fvTxtFile
[0:-4])
182 fdIn
= open(fvTxtFile
, "r")
183 rptLine
= fdIn
.readline()
184 while (rptLine
!= "" ):
185 match
= re
.match("(0x[a-fA-F0-9]+)\s([0-9a-fA-F\-]+)", rptLine
)
186 if match
is not None:
187 self
.dictFfsOffset
[match
.group(2)] = "0x%08X" % (int(match
.group(1), 16) + fvOffset
)
188 rptLine
= fdIn
.readline()
192 def parseFvMapFile(self
, mapFile
):
193 fdIn
= open(mapFile
, "r")
194 rptLine
= fdIn
.readline()
196 while (rptLine
!= "" ):
197 if rptLine
[0] != ' ':
198 #DxeIpl (Fixed Flash Address, BaseAddress=0x00fffb4310, EntryPoint=0x00fffb4958)
199 #(GUID=86D70125-BAA3-4296-A62F-602BEBBB9081 .textbaseaddress=0x00fffb4398 .databaseaddress=0x00fffb4178)
200 match
= re
.match("([_a-zA-Z0-9\-]+)\s\(.+BaseAddress=(0x[0-9a-fA-F]+),\s+EntryPoint=(0x[0-9a-fA-F]+)\)", rptLine
)
201 if match
is not None:
202 modName
= match
.group(1)
203 if len(modName
) == 36:
204 modName
= self
.dictGuidNameXref
[modName
.upper()]
205 self
.dictModBase
['%s:BASE' % modName
] = int (match
.group(2), 16)
206 self
.dictModBase
['%s:ENTRY' % modName
] = int (match
.group(3), 16)
207 match
= re
.match("\(GUID=([A-Z0-9\-]+)\s+\.textbaseaddress=(0x[0-9a-fA-F]+)\s+\.databaseaddress=(0x[0-9a-fA-F]+)\)", rptLine
)
208 if match
is not None:
209 modName
= match
.group(1)
210 if len(modName
) == 36:
211 modName
= self
.dictGuidNameXref
[modName
.upper()]
212 self
.dictModBase
['%s:TEXT' % modName
] = int (match
.group(2), 16)
213 self
.dictModBase
['%s:DATA' % modName
] = int (match
.group(3), 16)
215 # 0x00fff8016c __ModuleEntryPoint
216 match
= re
.match("^\s+(0x[a-z0-9]+)\s+([_a-zA-Z0-9]+)", rptLine
)
217 if match
is not None:
218 self
.dictSymbolAddress
["%s:%s"%(modName
, match
.group(2))] = match
.group(1)
219 rptLine
= fdIn
.readline()
223 def parseModMapFile(self
, moduleName
, mapFile
):
225 fdIn
= open(mapFile
, "r")
226 reportLine
= fdIn
.readline()
227 if reportLine
.strip().find("Archive member included because of file (symbol)") != -1:
229 # 0x0000000000001d55 IoRead8
230 patchMapFileMatchString
= "\s+(0x[0-9a-fA-F]{16})\s+([^\s][^0x][_a-zA-Z0-9\-]+)\s"
231 matchKeyGroupIndex
= 2
232 matchSymbolGroupIndex
= 1
233 moduleEntryPoint
= "_ModuleEntryPoint"
236 #0003:00000190 _gComBase 00007a50 SerialPo
237 patchMapFileMatchString
= "^\s[0-9a-fA-F]{4}:[0-9a-fA-F]{8}\s+(\w+)\s+([0-9a-fA-F]{8}\s+)"
238 matchKeyGroupIndex
= 1
239 matchSymbolGroupIndex
= 2
240 moduleEntryPoint
= "__ModuleEntryPoint"
241 while (reportLine
!= "" ):
242 match
= re
.match(patchMapFileMatchString
, reportLine
)
243 if match
is not None:
244 modSymbols
[match
.group(matchKeyGroupIndex
)] = match
.group(matchSymbolGroupIndex
)
245 reportLine
= fdIn
.readline()
248 if not moduleEntryPoint
in modSymbols
:
251 modEntry
= '%s:%s' % (moduleName
,moduleEntryPoint
)
252 if not modEntry
in self
.dictSymbolAddress
:
253 modKey
= '%s:ENTRY' % moduleName
254 if modKey
in self
.dictModBase
:
255 baseOffset
= self
.dictModBase
['%s:ENTRY' % moduleName
] - int(modSymbols
[moduleEntryPoint
], 16)
259 baseOffset
= int(self
.dictSymbolAddress
[modEntry
], 16) - int(modSymbols
[moduleEntryPoint
], 16)
260 for symbol
in modSymbols
:
261 fullSym
= "%s:%s" % (moduleName
, symbol
)
262 if not fullSym
in self
.dictSymbolAddress
:
263 self
.dictSymbolAddress
[fullSym
] = "0x00%08x" % (baseOffset
+ int(modSymbols
[symbol
], 16))
266 def parseGuidXrefFile(self
, xrefFile
):
267 fdIn
= open(xrefFile
, "r")
268 rptLine
= fdIn
.readline()
269 while (rptLine
!= "" ):
270 match
= re
.match("([0-9a-fA-F\-]+)\s([_a-zA-Z0-9]+)", rptLine
)
271 if match
is not None:
272 self
.dictGuidNameXref
[match
.group(1).upper()] = match
.group(2)
273 rptLine
= fdIn
.readline()
279 return self
.string
[self
.index
]
284 return self
.index
== len(self
.string
)
290 while not self
.isLast():
291 if self
.getCurr() in ' \t':
296 def parseValue(self
):
299 while not self
.isLast():
300 char
= self
.getCurr()
301 if char
.lower() in '_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:-':
308 partList
= var
.split(':')
309 if len(partList
) != 2:
310 raise Exception("Unrecognized expression %s" % var
)
311 modName
= partList
[0]
313 if ('-' not in modName
) and (modOff
[0] in '0123456789'):
315 var
= self
.getModGuid(modName
) + ":" + modOff
316 if '-' in var
: # GUID:OFFSET
317 value
= self
.getGuidOff(var
)
319 value
= self
.getSymbols(var
)
322 if var
[0] in '0123456789':
323 value
= self
.getNumber(var
)
325 value
= self
.getVariable(var
)
328 def parseSingleOp(self
):
330 char
= self
.getCurr()
333 return ~self
.parseBrace()
335 return self
.parseValue()
337 def parseBrace(self
):
339 char
= self
.getCurr()
340 parenthesisType
= self
.parenthesisOpenSet
.find(char
)
341 if parenthesisType
>= 0:
343 value
= self
.parseExpr()
345 if self
.getCurr() != self
.parenthesisCloseSet
[parenthesisType
]:
346 raise Exception("No closing brace")
348 if parenthesisType
== 1: # [ : Get content
349 value
= self
.getContent(value
)
350 elif parenthesisType
== 2: # { : To address
351 value
= self
.toAddress(value
)
352 elif parenthesisType
== 3: # < : To offset
353 value
= self
.toOffset(value
)
356 return self
.parseSingleOp()
359 values
= [self
.parseBrace()]
362 char
= self
.getCurr()
365 values
.append(self
.parseBrace())
373 def parseAndOr(self
):
374 values
= [self
.parseMul()]
379 char
= self
.getCurr()
382 values
.append(self
.parseMul())
385 div_index
= self
.index
387 values
.append(self
.parseMul())
401 def parseAddMinus(self
):
402 values
= [self
.parseAndOr()]
405 char
= self
.getCurr()
408 values
.append(self
.parseAndOr())
411 values
.append(-1 * self
.parseAndOr())
417 return self
.parseAddMinus()
420 value
= self
.parseExpr()
422 if not self
.isLast():
423 raise Exception("Unexpected character found '%s'" % self
.getCurr())
426 def getModGuid(self
, var
):
427 guid
= (guid
for guid
,name
in self
.dictGuidNameXref
.items() if name
==var
)
431 raise Exception("Unknown module name %s !" % var
)
434 def getVariable(self
, var
):
435 value
= self
.dictVariable
.get(var
, None)
437 raise Exception("Unrecognized variable '%s'" % var
)
440 def getNumber(self
, var
):
442 if var
.startswith('0x'): # HEX
448 def getContent(self
, value
):
449 if (value
>= self
.fdBase
) and (value
< self
.fdBase
+ self
.fdSize
):
450 value
= value
- self
.fdBase
451 if value
>= self
.fdSize
:
452 raise Exception("Invalid file offset 0x%08x !" % value
)
453 return readDataFromFile (self
.fdFile
, value
, 4)
455 def toAddress(self
, value
):
456 if value
< self
.fdSize
:
457 value
= value
+ self
.fdBase
460 def toOffset(self
, value
):
461 if value
> self
.fdBase
:
462 value
= value
- self
.fdBase
465 def getGuidOff(self
, value
):
467 symbolName
= value
.split(':')
468 if len(symbolName
) == 2 and self
.dictFfsOffset
.has_key(symbolName
[0]):
469 value
= (int(self
.dictFfsOffset
[symbolName
[0]], 16) + int(symbolName
[1], 16)) & 0xFFFFFFFF
471 raise Exception("Unknown GUID %s !" % value
)
474 def getSymbols(self
, value
):
475 if self
.dictSymbolAddress
.has_key(value
):
477 ret
= int (self
.dictSymbolAddress
[value
], 16)
479 raise Exception("Unknown symbol %s !" % value
)
482 def evaluate(self
, expression
, isOffset
):
485 self
.string
= expression
486 value
= self
.getResult()
489 # Consider it as an address first
490 if (value
>= self
.fdBase
) and (value
< self
.fdBase
+ self
.fdSize
):
491 value
= value
- self
.fdBase
492 if value
& 0x80000000:
493 # Consider it as a negative offset next
494 offset
= (~value
& 0xFFFFFFFF) + 1
495 if offset
< self
.fdSize
:
496 value
= self
.fdSize
- offset
497 if value
>= self
.fdSize
:
498 raise Exception("Invalid offset expression !")
499 return value
& 0xFFFFFFFF
502 print "Usage: \n\tPatchFv FvBuildDir [FvFileBaseNames:]FdFileBaseNameToPatch \"Offset, Value\""
506 # Parse the options and args
508 symTables
= Symbols()
510 if len(sys
.argv
) < 4:
514 if symTables
.createDicts(sys
.argv
[1], sys
.argv
[2]) != 0:
515 print "ERROR: Failed to create symbol dictionary!!"
518 fdFile
= symTables
.getFdFile()
519 fdSize
= symTables
.getFdSize()
522 ret
= IsFspHeaderValid(fdFile
)
524 raise Exception ("The FSP header is not valid. Stop patching FD.")
526 for fvFile
in sys
.argv
[3:]:
527 items
= fvFile
.split(",")
529 raise Exception("Expect more arguments for '%s'!" % fvFile
)
536 if item
.startswith("@"):
538 elif item
.startswith("$"):
545 params
.append (symTables
.evaluate(item
, isOffset
))
549 if len (params
) == 2:
552 oldvalue
= readDataFromFile(fdFile
, offset
, 4)
553 ret
= patchDataInFile (fdFile
, offset
, value
, 4) - 4
555 raise Exception ("Patch command needs 2 parameters !")
558 raise Exception ("Patch failed for offset 0x%08X" % offset
)
560 print "Patched offset 0x%08X:[%08X] with value 0x%08X # %s" % (offset
, oldvalue
, value
, comment
)
562 elif command
== "COPY":
563 # Copy binary block from source to destination
564 if len (params
) == 3:
565 src
= symTables
.toOffset(params
[0])
566 dest
= symTables
.toOffset(params
[1])
567 clen
= symTables
.toOffset(params
[2])
568 if (dest
+ clen
<= fdSize
) and (src
+ clen
<= fdSize
):
569 oldvalue
= readDataFromFile(fdFile
, src
, clen
)
570 ret
= patchDataInFile (fdFile
, dest
, oldvalue
, clen
) - clen
572 raise Exception ("Copy command OFFSET or LENGTH parameter is invalid !")
574 raise Exception ("Copy command needs 3 parameters !")
577 raise Exception ("Copy failed from offset 0x%08X to offset 0x%08X!" % (src
, dest
))
579 print "Copied %d bytes from offset 0x%08X ~ offset 0x%08X # %s" % (clen
, src
, dest
, comment
)
581 raise Exception ("Unknown command %s!" % command
)
584 except Exception as (ex
):
585 print "ERROR: %s" % ex
588 if __name__
== '__main__':