1d51ea039b12a3be47384030d3d48fe10b316f59
[people/mcb30/basetools.git] / Source / Python / GenFds / GenFds.py
1 ## @file
2 # generate flash image
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 from optparse import OptionParser
19 import sys
20 import os
21 import linecache
22 import FdfParser
23 from Common import BuildToolError
24 from GenFdsGlobalVariable import GenFdsGlobalVariable
25 from Workspace.WorkspaceDatabase import WorkspaceDatabase
26 import RuleComplexFile
27 from EfiSection import EfiSection
28 import StringIO
29 import Common.TargetTxtClassObject as TargetTxtClassObject
30 import Common.DataType
31 import Common.GlobalData as GlobalData
32 from Common import EdkLogger
33 from Common.String import *
34
35 ## Version and Copyright
36 versionNumber = "1.0"
37 __version__ = "%prog Version " + versionNumber
38 __copyright__ = "Copyright (c) 2007, Intel Corporation  All rights reserved."
39
40 ## Tool entrance method
41 #
42 # This method mainly dispatch specific methods per the command line options.
43 # If no error found, return zero value so the caller of this tool can know
44 # if it's executed successfully or not.
45 #
46 #   @retval 0     Tool was successful
47 #   @retval 1     Tool failed
48 #
49 def main():
50     global Options
51     Options = myOptionParser()
52     global Workspace
53     Workspace = ""
54     ArchList = None
55     ReturnCode = 0
56
57     EdkLogger.Initialize()
58     try:
59         if Options.verbose != None:
60             EdkLogger.SetLevel(EdkLogger.VERBOSE)
61             GenFdsGlobalVariable.VerboseMode = True
62         if Options.quiet != None:
63             EdkLogger.SetLevel(EdkLogger.QUIET)
64         if Options.debug != None:
65             EdkLogger.SetLevel(Options.debug + 1)
66             GenFdsGlobalVariable.DebugLevel = Options.debug
67         else:
68             EdkLogger.SetLevel(EdkLogger.INFO)
69
70         if (Options.Workspace == None):
71             EdkLogger.error("GenFds", BuildToolError.OPTION_MISSING, "WORKSPACE not defined",
72                             ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.")
73         else:
74             Workspace = Options.Workspace
75             GenFdsGlobalVariable.WorkSpaceDir = Workspace
76             if 'EDK_SOURCE' in os.environ.keys():
77                 GenFdsGlobalVariable.EdkSourceDir = os.environ['EDK_SOURCE']
78             if (Options.debug):
79                 GenFdsGlobalVariable.VerboseLogger( "Using Workspace:" + Workspace)
80         os.chdir(GenFdsGlobalVariable.WorkSpaceDir)
81
82         if (Options.filename):
83             FdfFilename = Options.filename
84             FdfFilename = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdfFilename)
85         else:
86             EdkLogger.error("GenFds", BuildToolError.OPTION_MISSING, "Missing FDF filename")
87
88         if (Options.BuildTarget):
89             GenFdsGlobalVariable.TargetName = Options.BuildTarget
90         else:
91             EdkLogger.error("GenFds", BuildToolError.OPTION_MISSING, "Missing build target")
92
93         if (Options.ToolChain):
94             GenFdsGlobalVariable.ToolChainTag = Options.ToolChain
95         else:
96             EdkLogger.error("GenFds", BuildToolError.OPTION_MISSING, "Missing tool chain tag")
97
98         if FdfFilename[0:2] == '..':
99             FdfFilename = os.path.realpath(FdfFilename)
100         if FdfFilename[1] != ':':
101             FdfFilename = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)
102
103         if not os.path.exists(FdfFilename):
104             EdkLogger.error("GenFds", BuildToolError.FILE_NOT_FOUND, ExtraData=FdfFilename)
105         GenFdsGlobalVariable.FdfFile = FdfFilename
106         GenFdsGlobalVariable.FdfFileTimeStamp = os.path.getmtime(FdfFilename)
107
108         if (Options.activePlatform):
109             ActivePlatform = Options.activePlatform
110             ActivePlatform = GenFdsGlobalVariable.ReplaceWorkspaceMacro(ActivePlatform)
111
112             if ActivePlatform[0:2] == '..':
113                 ActivePlatform = os.path.realpath(ActivePlatform)
114
115             if ActivePlatform[1] != ':':
116                 ActivePlatform = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)
117
118             if not os.path.exists(ActivePlatform)  :
119                 EdkLogger.error("GenFds", BuildToolError.FILE_NOT_FOUND, "ActivePlatform doesn't exist!")
120
121             if ActivePlatform.find(Workspace) == -1:
122                 EdkLogger.error("GenFds", BuildToolError.FILE_NOT_FOUND, "ActivePlatform doesn't exist in Workspace!")
123
124             ActivePlatform = ActivePlatform.replace(Workspace, '')
125             if len(ActivePlatform) > 0 :
126                 if ActivePlatform[0] == '\\' or ActivePlatform[0] == '/':
127                     ActivePlatform = ActivePlatform[1:]
128             else:
129                 EdkLogger.error("GenFds", BuildToolError.FILE_NOT_FOUND, "ActivePlatform doesn't exist!")
130         else :
131             EdkLogger.error("GenFds", BuildToolError.OPTION_MISSING, "Missing active platform")
132
133         GenFdsGlobalVariable.ActivePlatform = NormPath(ActivePlatform)
134
135         if (Options.archList) :
136             ArchList = Options.archList.split(',')
137         else:
138             EdkLogger.error("GenFds", BuildToolError.OPTION_MISSING, "Missing build ARCH")
139
140         BuildConfigurationFile = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, "Conf/target.txt"))
141         if os.path.isfile(BuildConfigurationFile) == True:
142             TargetTxtClassObject.TargetTxtClassObject(BuildConfigurationFile)
143         else:
144             EdkLogger.error("GenFds", BuildToolError.FILE_NOT_FOUND, ExtraData=BuildConfigrationFile)
145
146         if Options.Macros:
147             for Pair in Options.Macros:
148                 Pair.strip('"')
149                 List = Pair.split('=')
150                 if len(List) == 2:
151                     FdfParser.InputMacroDict[List[0].strip()] = List[1].strip()
152                     GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip()
153                 else:
154                     FdfParser.InputMacroDict[List[0].strip()] = None
155
156         """call Workspace build create database"""
157         os.environ["WORKSPACE"] = Workspace
158         BuildWorkSpace = WorkspaceDatabase(':memory:', GlobalData.gGlobalDefines)
159         BuildWorkSpace.InitDatabase()
160
161         for Arch in ArchList:
162             GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[ActivePlatform, Arch].OutputDirectory)
163
164         if (Options.outputDir):
165             OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(Options.outputDir)
166             for Arch in ArchList:
167                 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine
168         else:
169             for Arch in ArchList:
170                 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)
171
172         for Key in GenFdsGlobalVariable.OutputDirDict:
173             OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]
174             if OutputDir[0:2] == '..':
175                 OutputDir = os.path.realpath(OutputDir)
176
177             if OutputDir[1] != ':':
178                 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)
179
180             if not os.path.exists(OutputDir):
181                 EdkLogger.error("GenFds", BuildToolError.FILE_NOT_FOUND, ExtraData=OutputDir)
182             GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir
183
184         """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
185         FdfParserObj = FdfParser.FdfParser(FdfFilename)
186         FdfParserObj.ParseFile()
187
188         if FdfParserObj.CycleReferenceCheck():
189             EdkLogger.error("GenFds", BuildToolError.FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")
190
191         if (Options.uiFdName) :
192             if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict.keys():
193                 GenFds.currentFd = Options.uiFdName
194             else:
195                 EdkLogger.error("GenFds", BuildToolError.OPTION_VALUE_INVALID,
196                                 "No such an FD in FDF file: %s" % Options.uiFdName)
197
198         if (Options.uiFvName) :
199             if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict.keys():
200                 GenFds.currentFv = Options.uiFvName
201             else:
202                 EdkLogger.error("GenFds", BuildToolError.OPTION_VALUE_INVALID,
203                                 "No such an FV in FDF file: %s" % Options.uiFvName)
204
205         """Call GenFds"""
206         GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)
207         
208         """Display FV space info."""
209         GenFds.DisplayFvSpaceInfo(FdfParserObj)
210         
211     except FdfParser.Warning, X:
212         EdkLogger.error(X.ToolName, BuildToolError.FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)
213         ReturnCode = BuildToolError.FORMAT_INVALID
214     except FatalError, X:
215         if Options.debug != None:
216             import traceback
217             EdkLogger.quiet(traceback.format_exc())
218         ReturnCode = X.args[0]
219     except:
220         import traceback
221         EdkLogger.error(
222                     "\nPython",
223                     CODE_ERROR,
224                     "Tools code failure",
225                     ExtraData="Please submit bug report in www.TianoCore.org, attaching following call stack trace!\n",
226                     RaiseError=False
227                     )
228         EdkLogger.quiet(traceback.format_exc())
229         ReturnCode = CODE_ERROR
230     return ReturnCode
231
232 ## Parse command line options
233 #
234 # Using standard Python module optparse to parse command line option of this tool.
235 #
236 #   @retval Opt   A optparse.Values object containing the parsed options
237 #   @retval Args  Target of build command
238 #
239 def myOptionParser():
240     usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -y \"MacroName [= MacroValue]\""
241     Parser = OptionParser(usage=usage,description=__copyright__,version="%prog " + str(versionNumber))
242     Parser.add_option("-f", "--file", dest="filename", help="Name of FDF file to convert")
243     Parser.add_option("-a", "--arch", dest="archList", help="comma separated list containing one or more of: IA32, X64, IPF or EBC which should be built, overrides target.txt?s TARGET_ARCH")
244     Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
245     Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
246     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
247     Parser.add_option("-p", "--platform", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.")
248     Parser.add_option("-w", "--workspace", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE")
249     Parser.add_option("-o", "--outputDir", dest="outputDir", help="Name of Build Output directory")
250     Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
251     Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Buld the FV image using the [FV] section named by UiFvName")
252     Parser.add_option("-b", "--buildtarget", action="store", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget", help="Build TARGET is one of list: DEBUG, RELEASE.")
253     Parser.add_option("-t", "--tagname", action="store", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.")
254     Parser.add_option("-y", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
255     (Options, args) = Parser.parse_args()
256     return Options
257
258 ## The class implementing the EDK2 flash image generation process
259 #
260 #   This process includes:
261 #       1. Collect workspace information, includes platform and module information
262 #       2. Call methods of Fd class to generate FD
263 #       3. Call methods of Fv class to generate FV that not belong to FD
264 #
265 class GenFds :
266     FdfParsef = None
267     # FvName in FDF, FvBinFile name
268     FvBinDict = {}
269     OnlyGenerateThisFd = None
270     OnlyGenerateThisFv = None
271
272     ## GenFd()
273     #
274     #   @param  OutputDir           Output directory
275     #   @param  FdfParser           FDF contents parser
276     #   @param  Workspace           The directory of workspace
277     #   @param  ArchList            The Arch list of platform
278     #
279     def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):
280         GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)
281
282         GenFdsGlobalVariable.VerboseLogger("   Gen Fd  !")
283         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
284             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(GenFds.OnlyGenerateThisFd.upper())
285             if FdObj != None:
286                 FdObj.GenFd(GenFds.FvBinDict)
287         elif GenFds.OnlyGenerateThisFv == None:
288             for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
289                 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
290                 FdObj.GenFd(GenFds.FvBinDict)
291
292         GenFdsGlobalVariable.VerboseLogger(" Gen FV ! ")
293         if GenFds.OnlyGenerateThisFv != None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
294             FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(GenFds.OnlyGenerateThisFv.upper())
295             if FvObj != None:
296                 Buffer = StringIO.StringIO()
297                 # Get FV base Address
298                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))
299                 Buffer.close()
300                 return
301         elif GenFds.OnlyGenerateThisFd == None:
302             for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
303                 Buffer = StringIO.StringIO('')
304                 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]
305                 # Get FV base Address
306                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))
307                 Buffer.close()
308
309         if GenFds.OnlyGenerateThisFv == None and GenFds.OnlyGenerateThisFd == None:
310             GenFdsGlobalVariable.VerboseLogger(" Gen Capsule !")
311             for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleList:
312                 CapsuleObj.GenCapsule()
313
314     ## GetFvBlockSize()
315     #
316     #   @param  FvObj           Whose block size to get
317     #   @retval int             Block size value
318     #
319     def GetFvBlockSize(FvObj):
320         FdObj = None
321         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
322             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
323         if FdObj == None:
324             for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
325                 for ElementRegion in ElementFd.RegionList:
326                     if ElementRegion.RegionType == 'FV':
327                         for ElementRegionData in ElementRegion.RegionDataList:
328                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:
329                                 if FvObj.BlockSizeList != []:
330                                     return FvObj.BlockSizeList[0][0]
331                                 else:
332                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
333             return 0x10000
334         else:
335             for ElementRegion in FdObj.RegionList:
336                     if ElementRegion.RegionType == 'FV':
337                         for ElementRegionData in ElementRegion.RegionDataList:
338                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:
339                                 if FvObj.BlockSizeList != []:
340                                     return FvObj.BlockSizeList[0][0]
341                                 else:
342                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
343             return 0x10000
344
345     
346     def DisplayFvSpaceInfo(FdfParser):
347         
348         FvSpaceInfoList = []
349         MaxFvNameLength = 0
350         for FvName in FdfParser.Profile.FvDict:
351             if len(FvName) > MaxFvNameLength:
352                 MaxFvNameLength = len(FvName)
353             FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FfsDir, FvName.upper() + '.inf')
354             if os.path.exists(FvSpaceInfoFileName):
355                 FileLinesList = linecache.getlines(FvSpaceInfoFileName)
356                 TotalFound = False
357                 Total = ''
358                 UsedFound = False
359                 Used = ''
360                 FreeFound = False
361                 Free = ''
362                 for Line in FileLinesList:
363                     NameValue = Line.split('=')
364                     if len(NameValue) == 2:
365                         if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
366                             TotalFound = True
367                             Total = NameValue[1].strip()
368                         if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
369                             UsedFound = True
370                             Used = NameValue[1].strip()
371                         if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
372                             FreeFound = True
373                             Free = NameValue[1].strip()
374                 
375                 if TotalFound and UsedFound and FreeFound:
376                     FvSpaceInfoList.append((FvName, Total, Used, Free))
377                 
378         GenFdsGlobalVariable.InfLogger('\nFV Space Information')
379         for FvSpaceInfo in FvSpaceInfoList:
380             Name = FvSpaceInfo[0]
381             TotalSizeValue = long(FvSpaceInfo[1], 0)
382             UsedSizeValue = long(FvSpaceInfo[2], 0)
383             FreeSizeValue = long(FvSpaceInfo[3], 0)
384             GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + str((UsedSizeValue+0.0)/TotalSizeValue)[0:4].lstrip('0.') + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')
385
386     ##Define GenFd as static function
387     GenFd = staticmethod(GenFd)
388     GetFvBlockSize = staticmethod(GetFvBlockSize)
389     DisplayFvSpaceInfo = staticmethod(DisplayFvSpaceInfo)
390
391 if __name__ == '__main__':
392     sys.exit(main())
393