]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py
Check In tool source code based on Build tool project revision r1655.
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / GenFdsGlobalVariable.py
1 ## @file
2 # Global variables for GenFds
3 #
4 # Copyright (c) 2007, Intel Corporation
5 #
6 # All rights reserved. This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the BSD License
8 # which accompanies this distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
10 #
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 #
14
15 ##
16 # Import Modules
17 #
18 import os
19 import sys
20 import subprocess
21 import struct
22 import array
23
24 from Common.BuildToolError import *
25 from Common import EdkLogger
26 from Common.Misc import SaveFileOnChange
27
28 ## Global variables
29 #
30 #
31 class GenFdsGlobalVariable:
32 FvDir = ''
33 OutputDirDict = {}
34 BinDir = ''
35 # will be FvDir + os.sep + 'Ffs'
36 FfsDir = ''
37 FdfParser = None
38 LibDir = ''
39 WorkSpace = None
40 WorkSpaceDir = ''
41 EdkSourceDir = ''
42 OutputDirFromDscDict = {}
43 TargetName = ''
44 ToolChainTag = ''
45 RuleDict = {}
46 ArchList = None
47 VtfDict = {}
48 ActivePlatform = None
49 FvAddressFileName = ''
50 VerboseMode = False
51 DebugLevel = -1
52 SharpCounter = 0
53 SharpNumberPerLine = 40
54 FdfFile = ''
55 FdfFileTimeStamp = 0
56 FixedLoadAddress = False
57
58 SectionHeader = struct.Struct("3B 1B")
59
60 ## SetDir()
61 #
62 # @param OutputDir Output directory
63 # @param FdfParser FDF contents parser
64 # @param Workspace The directory of workspace
65 # @param ArchList The Arch list of platform
66 #
67 def SetDir (OutputDir, FdfParser, WorkSpace, ArchList):
68 GenFdsGlobalVariable.VerboseLogger( "GenFdsGlobalVariable.OutputDir :%s" %OutputDir)
69 # GenFdsGlobalVariable.OutputDirDict = OutputDir
70 GenFdsGlobalVariable.FdfParser = FdfParser
71 GenFdsGlobalVariable.WorkSpace = WorkSpace
72 GenFdsGlobalVariable.FvDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[ArchList[0]], 'FV')
73 if not os.path.exists(GenFdsGlobalVariable.FvDir) :
74 os.makedirs(GenFdsGlobalVariable.FvDir)
75 GenFdsGlobalVariable.FfsDir = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs')
76 if not os.path.exists(GenFdsGlobalVariable.FfsDir) :
77 os.makedirs(GenFdsGlobalVariable.FfsDir)
78 if ArchList != None:
79 GenFdsGlobalVariable.ArchList = ArchList
80
81 T_CHAR_LF = '\n'
82 #
83 # Create FV Address inf file
84 #
85 GenFdsGlobalVariable.FvAddressFileName = os.path.join(GenFdsGlobalVariable.FfsDir, 'FvAddress.inf')
86 FvAddressFile = open (GenFdsGlobalVariable.FvAddressFileName, 'w')
87 #
88 # Add [Options]
89 #
90 FvAddressFile.writelines("[options]" + T_CHAR_LF)
91 BsAddress = '0'
92 for Arch in ArchList:
93 if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].BsBaseAddress:
94 BsAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].BsBaseAddress
95 break
96
97 FvAddressFile.writelines("EFI_BOOT_DRIVER_BASE_ADDRESS = " + \
98 BsAddress + \
99 T_CHAR_LF)
100
101 RtAddress = '0'
102 for Arch in ArchList:
103 if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].RtBaseAddress:
104 RtAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].RtBaseAddress
105
106 FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \
107 RtAddress + \
108 T_CHAR_LF)
109
110 FvAddressFile.close()
111
112 ## ReplaceWorkspaceMacro()
113 #
114 # @param String String that may contain macro
115 #
116 def ReplaceWorkspaceMacro(String):
117 Str = String.replace('$(WORKSPACE)', GenFdsGlobalVariable.WorkSpaceDir)
118 if os.path.exists(Str):
119 if not os.path.isabs(Str):
120 Str = os.path.abspath(Str)
121 else:
122 Str = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, String)
123 return os.path.normpath(Str)
124
125 ## Check if the input files are newer than output files
126 #
127 # @param Output Path of output file
128 # @param Input Path list of input files
129 #
130 # @retval True if Output doesn't exist, or any Input is newer
131 # @retval False if all Input is older than Output
132 #
133 @staticmethod
134 def NeedsUpdate(Output, Input):
135 if not os.path.exists(Output):
136 return True
137 # always update "Output" if no "Input" given
138 if Input == None or len(Input) == 0:
139 return True
140
141 # if fdf file is changed after the 'Output" is generated, update the 'Output'
142 OutputTime = os.path.getmtime(Output)
143 if GenFdsGlobalVariable.FdfFileTimeStamp > OutputTime:
144 return True
145
146 for F in Input:
147 # always update "Output" if any "Input" doesn't exist
148 if not os.path.exists(F):
149 return True
150 # always update "Output" if any "Input" is newer than "Output"
151 if os.path.getmtime(F) > OutputTime:
152 return True
153 return False
154
155 @staticmethod
156 def GenerateSection(Output, Input, Type=None, CompressionType=None, Guid=None,
157 GuidHdrLen=None, GuidAttr=None, Ui=None, Ver=None):
158 if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
159 return
160 GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
161
162 Cmd = ["GenSec"]
163 if Type not in [None, '']:
164 Cmd += ["-s", Type]
165 if CompressionType not in [None, '']:
166 Cmd += ["-c", CompressionType]
167 if Guid != None:
168 Cmd += ["-g", Guid]
169 if GuidHdrLen not in [None, '']:
170 Cmd += ["-l", GuidHdrLen]
171 if GuidAttr not in [None, '']:
172 Cmd += ["-r", GuidAttr]
173
174 if Ui not in [None, '']:
175 #Cmd += ["-n", '"' + Ui + '"']
176 SectionData = array.array('B', [0,0,0,0])
177 SectionData.fromstring(Ui.encode("utf_16_le"))
178 SectionData.append(0)
179 SectionData.append(0)
180 Len = len(SectionData)
181 GenFdsGlobalVariable.SectionHeader.pack_into(SectionData, 0, Len & 0xff, (Len >> 8) & 0xff, (Len >> 16) & 0xff, 0x15)
182 SaveFileOnChange(Output, SectionData.tostring())
183 elif Ver not in [None, '']:
184 #Cmd += ["-j", Ver]
185 SectionData = array.array('B', [0,0,0,0])
186 SectionData.fromstring(Ver.encode("utf_16_le"))
187 SectionData.append(0)
188 SectionData.append(0)
189 Len = len(SectionData)
190 GenFdsGlobalVariable.SectionHeader.pack_into(SectionData, 0, Len & 0xff, (Len >> 8) & 0xff, (Len >> 16) & 0xff, 0x14)
191 SaveFileOnChange(Output, SectionData.tostring())
192 else:
193 Cmd += ["-o", Output]
194 Cmd += Input
195 GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section")
196
197 @staticmethod
198 def GenerateFfs(Output, Input, Type, Guid, Fixed=False, CheckSum=False, Align=None,
199 SectionAlign=None):
200 if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
201 return
202 GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
203
204 Cmd = ["GenFfs", "-t", Type, "-g", Guid]
205 if Fixed == True:
206 Cmd += ["-x"]
207 if CheckSum:
208 Cmd += ["-s"]
209 if Align not in [None, '']:
210 Cmd += ["-a", Align]
211
212 Cmd += ["-o", Output]
213 for I in range(0, len(Input)):
214 Cmd += ("-i", Input[I])
215 if SectionAlign not in [None, '', []] and SectionAlign[I] not in [None, '']:
216 Cmd += ("-n", SectionAlign[I])
217 GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FFS")
218
219 @staticmethod
220 def GenerateFirmwareVolume(Output, Input, BaseAddress=None, Capsule=False, Dump=False,
221 AddressFile=None, MapFile=None, FfsList=[]):
222 if not GenFdsGlobalVariable.NeedsUpdate(Output, Input+FfsList):
223 return
224 GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
225
226 Cmd = ["GenFv"]
227 if BaseAddress not in [None, '']:
228 Cmd += ["-r", BaseAddress]
229 if Capsule:
230 Cmd += ["-c"]
231 if Dump:
232 Cmd += ["-p"]
233 if AddressFile not in [None, '']:
234 Cmd += ["-a", AddressFile]
235 if MapFile not in [None, '']:
236 Cmd += ["-m", MapFile]
237 Cmd += ["-o", Output]
238 for I in Input:
239 Cmd += ["-i", I]
240
241 GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FV")
242
243 @staticmethod
244 def GenerateVtf(Output, Input, BaseAddress=None, FvSize=None):
245 if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
246 return
247 GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
248
249 Cmd = ["GenVtf"]
250 if BaseAddress not in [None, ''] and FvSize not in [None, ''] \
251 and len(BaseAddress) == len(FvSize):
252 for I in range(0, len(BaseAddress)):
253 Cmd += ["-r", BaseAddress[I], "-s", FvSize[I]]
254 Cmd += ["-o", Output]
255 for F in Input:
256 Cmd += ["-f", F]
257
258 GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate VTF")
259
260 @staticmethod
261 def GenerateFirmwareImage(Output, Input, Type="efi", SubType=None, Zero=False,
262 Strip=False, Replace=False, TimeStamp=None, Join=False,
263 Align=None, Padding=None, Convert=False):
264 if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
265 return
266 GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
267
268 Cmd = ["GenFw"]
269 if Type.lower() == "te":
270 Cmd += ["-t"]
271 if SubType not in [None, '']:
272 Cmd += ["-e", SubType]
273 if TimeStamp not in [None, '']:
274 Cmd += ["-s", TimeStamp]
275 if Align not in [None, '']:
276 Cmd += ["-a", Align]
277 if Padding not in [None, '']:
278 Cmd += ["-p", Padding]
279 if Zero:
280 Cmd += ["-z"]
281 if Strip:
282 Cmd += ["-l"]
283 if Replace:
284 Cmd += ["-r"]
285 if Join:
286 Cmd += ["-j"]
287 if Convert:
288 Cmd += ["-m"]
289 Cmd += ["-o", Output]
290 Cmd += Input
291
292 GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate firmware image")
293
294 @staticmethod
295 def GenerateOptionRom(Output, EfiInput, BinaryInput, Compress=False, ClassCode=None,
296 Revision=None, DeviceId=None, VendorId=None):
297 # if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
298 # return
299 # GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
300
301 Cmd = ["EfiRom"]
302 if len(EfiInput) > 0:
303
304 if Compress:
305 Cmd += ["-ec"]
306 else:
307 Cmd += ["-e"]
308
309 for EfiFile in EfiInput:
310 Cmd += [EfiFile]
311
312 if len(BinaryInput) > 0:
313 Cmd += ["-b"]
314 for BinFile in BinaryInput:
315 Cmd += [BinFile]
316
317 if ClassCode != None:
318 Cmd += ["-l", ClassCode]
319 if Revision != None:
320 Cmd += ["-r", Revision]
321 if DeviceId != None:
322 Cmd += ["-i", DeviceId]
323 if VendorId != None:
324 Cmd += ["-f", VendorId]
325
326 Cmd += ["-o", Output]
327 GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate option rom")
328
329 @staticmethod
330 def GuidTool(Output, Input, ToolPath, Options=''):
331 if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
332 return
333 GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
334
335 Cmd = [ToolPath, Options]
336 Cmd += ["-o", Output]
337 Cmd += Input
338
339 GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to call " + ToolPath)
340
341 def CallExternalTool (cmd, errorMess):
342
343 if type(cmd) not in (tuple, list):
344 GenFdsGlobalVariable.ErrorLogger("ToolError! Invalid parameter type in call to CallExternalTool")
345
346 if GenFdsGlobalVariable.DebugLevel != -1:
347 cmd += ('--debug', str(GenFdsGlobalVariable.DebugLevel))
348 GenFdsGlobalVariable.InfLogger (cmd)
349
350 if GenFdsGlobalVariable.VerboseMode:
351 cmd += ('-v',)
352 GenFdsGlobalVariable.InfLogger (cmd)
353 else:
354 sys.stdout.write ('#')
355 sys.stdout.flush()
356 GenFdsGlobalVariable.SharpCounter = GenFdsGlobalVariable.SharpCounter + 1
357 if GenFdsGlobalVariable.SharpCounter % GenFdsGlobalVariable.SharpNumberPerLine == 0:
358 sys.stdout.write('\n')
359
360 try:
361 PopenObject = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr= subprocess.PIPE)
362 except Exception, X:
363 EdkLogger.error("GenFds", BuildToolError.COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))
364 (out, error) = PopenObject.communicate()
365
366 while PopenObject.returncode == None :
367 PopenObject.wait()
368 if PopenObject.returncode != 0 or GenFdsGlobalVariable.VerboseMode or GenFdsGlobalVariable.DebugLevel != -1:
369 GenFdsGlobalVariable.InfLogger ("Return Value = %d" %PopenObject.returncode)
370 GenFdsGlobalVariable.InfLogger (out)
371 GenFdsGlobalVariable.InfLogger (error)
372 if PopenObject.returncode != 0:
373 print "###", cmd
374 EdkLogger.error("GenFds", BuildToolError.COMMAND_FAILURE, errorMess)
375
376 def VerboseLogger (msg):
377 EdkLogger.verbose(msg)
378
379 def InfLogger (msg):
380 EdkLogger.info(msg)
381
382 def ErrorLogger (msg, File = None, Line = None, ExtraData = None):
383 EdkLogger.error('GenFds', BuildToolError.GENFDS_ERROR, msg, File, Line, ExtraData)
384
385 def DebugLogger (Level, msg):
386 EdkLogger.debug(Level, msg)
387
388 ## ReplaceWorkspaceMacro()
389 #
390 # @param Str String that may contain macro
391 # @param MacroDict Dictionary that contains macro value pair
392 #
393 def MacroExtend (Str, MacroDict = {}, Arch = 'COMMON'):
394 if Str == None :
395 return None
396
397 Dict = {'$(WORKSPACE)' : GenFdsGlobalVariable.WorkSpaceDir,
398 '$(EDK_SOURCE)' : GenFdsGlobalVariable.EdkSourceDir,
399 # '$(OUTPUT_DIRECTORY)': GenFdsGlobalVariable.OutputDirFromDsc,
400 '$(TARGET)' : GenFdsGlobalVariable.TargetName,
401 '$(TOOL_CHAIN_TAG)' : GenFdsGlobalVariable.ToolChainTag
402 }
403 OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[GenFdsGlobalVariable.ArchList[0]]
404 if Arch != 'COMMON' and Arch in GenFdsGlobalVariable.ArchList:
405 OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[Arch]
406
407 Dict['$(OUTPUT_DIRECTORY)'] = OutputDir
408
409 if MacroDict != None and len (MacroDict) != 0:
410 Dict.update(MacroDict)
411
412 for key in Dict.keys():
413 if Str.find(key) >= 0 :
414 Str = Str.replace (key, Dict[key])
415
416 if Str.find('$(ARCH)') >= 0:
417 if len(GenFdsGlobalVariable.ArchList) == 1:
418 Str = Str.replace('$(ARCH)', GenFdsGlobalVariable.ArchList[0])
419 else:
420 EdkLogger.error("GenFds", GENFDS_ERROR, "No way to determine $(ARCH) for %s" % Str)
421
422 return Str
423
424 ## GetPcdValue()
425 #
426 # @param PcdPattern pattern that labels a PCD.
427 #
428 def GetPcdValue (PcdPattern):
429 if PcdPattern == None :
430 return None
431 PcdPair = PcdPattern.lstrip('PCD(').rstrip(')').strip().split('.')
432 TokenSpace = PcdPair[0]
433 TokenCName = PcdPair[1]
434
435 PcdValue = ''
436 for Platform in GenFdsGlobalVariable.WorkSpace.PlatformList:
437 PcdDict = Platform.Pcds
438 for Key in PcdDict:
439 PcdObj = PcdDict[Key]
440 if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace):
441 if PcdObj.Type != 'FixedAtBuild':
442 EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern)
443 if PcdObj.DatumType != 'VOID*':
444 EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern)
445
446 PcdValue = PcdObj.DefaultValue
447 return PcdValue
448
449 for Package in GenFdsGlobalVariable.WorkSpace.PackageList:
450 PcdDict = Package.Pcds
451 for Key in PcdDict:
452 PcdObj = PcdDict[Key]
453 if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace):
454 if PcdObj.Type != 'FixedAtBuild':
455 EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern)
456 if PcdObj.DatumType != 'VOID*':
457 EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern)
458
459 PcdValue = PcdObj.DefaultValue
460 return PcdValue
461
462 return PcdValue
463
464 SetDir = staticmethod(SetDir)
465 ReplaceWorkspaceMacro = staticmethod(ReplaceWorkspaceMacro)
466 CallExternalTool = staticmethod(CallExternalTool)
467 VerboseLogger = staticmethod(VerboseLogger)
468 InfLogger = staticmethod(InfLogger)
469 ErrorLogger = staticmethod(ErrorLogger)
470 DebugLogger = staticmethod(DebugLogger)
471 MacroExtend = staticmethod (MacroExtend)
472 GetPcdValue = staticmethod(GetPcdValue)