GenFds output message clarification for build ARCH.
[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         BuildConfigurationFile = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, "Conf/target.txt"))
136         if os.path.isfile(BuildConfigurationFile) == True:
137             TargetTxtClassObject.TargetTxtClassObject(BuildConfigurationFile)
138         else:
139             EdkLogger.error("GenFds", BuildToolError.FILE_NOT_FOUND, ExtraData=BuildConfigrationFile)
140
141         if Options.Macros:
142             for Pair in Options.Macros:
143                 Pair.strip('"')
144                 List = Pair.split('=')
145                 if len(List) == 2:
146                     FdfParser.InputMacroDict[List[0].strip()] = List[1].strip()
147                     GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip()
148                 else:
149                     FdfParser.InputMacroDict[List[0].strip()] = None
150
151         """call Workspace build create database"""
152         os.environ["WORKSPACE"] = Workspace
153         BuildWorkSpace = WorkspaceDatabase(':memory:', GlobalData.gGlobalDefines)
154         BuildWorkSpace.InitDatabase()
155
156         if (Options.archList) :
157             ArchList = Options.archList.split(',')
158         else:
159 #            EdkLogger.error("GenFds", BuildToolError.OPTION_MISSING, "Missing build ARCH")
160             ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON'].SupArchList
161
162         TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON'].SupArchList) & set(ArchList)
163         if len(TargetArchList) == 0:
164             EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 'COMMON'].SupArchList)))
165         
166         for Arch in ArchList:
167             GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[ActivePlatform, Arch].OutputDirectory)
168
169         if (Options.outputDir):
170             OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(Options.outputDir)
171             for Arch in ArchList:
172                 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine
173         else:
174             for Arch in ArchList:
175                 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)
176
177         for Key in GenFdsGlobalVariable.OutputDirDict:
178             OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]
179             if OutputDir[0:2] == '..':
180                 OutputDir = os.path.realpath(OutputDir)
181
182             if OutputDir[1] != ':':
183                 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)
184
185             if not os.path.exists(OutputDir):
186                 EdkLogger.error("GenFds", BuildToolError.FILE_NOT_FOUND, ExtraData=OutputDir)
187             GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir
188
189         """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """
190         FdfParserObj = FdfParser.FdfParser(FdfFilename)
191         FdfParserObj.ParseFile()
192
193         if FdfParserObj.CycleReferenceCheck():
194             EdkLogger.error("GenFds", BuildToolError.FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file")
195
196         if (Options.uiFdName) :
197             if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict.keys():
198                 GenFds.currentFd = Options.uiFdName
199             else:
200                 EdkLogger.error("GenFds", BuildToolError.OPTION_VALUE_INVALID,
201                                 "No such an FD in FDF file: %s" % Options.uiFdName)
202
203         if (Options.uiFvName) :
204             if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict.keys():
205                 GenFds.currentFv = Options.uiFvName
206             else:
207                 EdkLogger.error("GenFds", BuildToolError.OPTION_VALUE_INVALID,
208                                 "No such an FV in FDF file: %s" % Options.uiFvName)
209
210         """Call GenFds"""
211         GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)
212         
213         """Display FV space info."""
214         GenFds.DisplayFvSpaceInfo(FdfParserObj)
215         
216     except FdfParser.Warning, X:
217         EdkLogger.error(X.ToolName, BuildToolError.FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError = False)
218         ReturnCode = BuildToolError.FORMAT_INVALID
219     except FatalError, X:
220         if Options.debug != None:
221             import traceback
222             EdkLogger.quiet(traceback.format_exc())
223         ReturnCode = X.args[0]
224     except:
225         import traceback
226         EdkLogger.error(
227                     "\nPython",
228                     CODE_ERROR,
229                     "Tools code failure",
230                     ExtraData="Please submit bug report in www.TianoCore.org, attaching following call stack trace!\n",
231                     RaiseError=False
232                     )
233         EdkLogger.quiet(traceback.format_exc())
234         ReturnCode = CODE_ERROR
235     return ReturnCode
236
237 ## Parse command line options
238 #
239 # Using standard Python module optparse to parse command line option of this tool.
240 #
241 #   @retval Opt   A optparse.Values object containing the parsed options
242 #   @retval Args  Target of build command
243 #
244 def myOptionParser():
245     usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -y \"MacroName [= MacroValue]\""
246     Parser = OptionParser(usage=usage,description=__copyright__,version="%prog " + str(versionNumber))
247     Parser.add_option("-f", "--file", dest="filename", help="Name of FDF file to convert")
248     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")
249     Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")
250     Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")
251     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")
252     Parser.add_option("-p", "--platform", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.")
253     Parser.add_option("-w", "--workspace", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE")
254     Parser.add_option("-o", "--outputDir", dest="outputDir", help="Name of Build Output directory")
255     Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")
256     Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Buld the FV image using the [FV] section named by UiFvName")
257     Parser.add_option("-b", "--buildtarget", action="store", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget", help="Build TARGET is one of list: DEBUG, RELEASE.")
258     Parser.add_option("-t", "--tagname", action="store", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.")
259     Parser.add_option("-y", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")
260     (Options, args) = Parser.parse_args()
261     return Options
262
263 ## The class implementing the EDK2 flash image generation process
264 #
265 #   This process includes:
266 #       1. Collect workspace information, includes platform and module information
267 #       2. Call methods of Fd class to generate FD
268 #       3. Call methods of Fv class to generate FV that not belong to FD
269 #
270 class GenFds :
271     FdfParsef = None
272     # FvName in FDF, FvBinFile name
273     FvBinDict = {}
274     OnlyGenerateThisFd = None
275     OnlyGenerateThisFv = None
276
277     ## GenFd()
278     #
279     #   @param  OutputDir           Output directory
280     #   @param  FdfParser           FDF contents parser
281     #   @param  Workspace           The directory of workspace
282     #   @param  ArchList            The Arch list of platform
283     #
284     def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):
285         GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)
286
287         GenFdsGlobalVariable.VerboseLogger("   Gen Fd  !")
288         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
289             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(GenFds.OnlyGenerateThisFd.upper())
290             if FdObj != None:
291                 FdObj.GenFd(GenFds.FvBinDict)
292         elif GenFds.OnlyGenerateThisFv == None:
293             for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
294                 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
295                 FdObj.GenFd(GenFds.FvBinDict)
296
297         GenFdsGlobalVariable.VerboseLogger(" Gen FV ! ")
298         if GenFds.OnlyGenerateThisFv != None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
299             FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(GenFds.OnlyGenerateThisFv.upper())
300             if FvObj != None:
301                 Buffer = StringIO.StringIO()
302                 # Get FV base Address
303                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))
304                 Buffer.close()
305                 return
306         elif GenFds.OnlyGenerateThisFd == None:
307             for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():
308                 Buffer = StringIO.StringIO('')
309                 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]
310                 # Get FV base Address
311                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))
312                 Buffer.close()
313
314         if GenFds.OnlyGenerateThisFv == None and GenFds.OnlyGenerateThisFd == None:
315             GenFdsGlobalVariable.VerboseLogger(" Gen Capsule !")
316             for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleList:
317                 CapsuleObj.GenCapsule()
318
319     ## GetFvBlockSize()
320     #
321     #   @param  FvObj           Whose block size to get
322     #   @retval int             Block size value
323     #
324     def GetFvBlockSize(FvObj):
325         FdObj = None
326         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
327             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]
328         if FdObj == None:
329             for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():
330                 for ElementRegion in ElementFd.RegionList:
331                     if ElementRegion.RegionType == 'FV':
332                         for ElementRegionData in ElementRegion.RegionDataList:
333                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:
334                                 if FvObj.BlockSizeList != []:
335                                     return FvObj.BlockSizeList[0][0]
336                                 else:
337                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
338             return 0x10000
339         else:
340             for ElementRegion in FdObj.RegionList:
341                     if ElementRegion.RegionType == 'FV':
342                         for ElementRegionData in ElementRegion.RegionDataList:
343                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:
344                                 if FvObj.BlockSizeList != []:
345                                     return FvObj.BlockSizeList[0][0]
346                                 else:
347                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)
348             return 0x10000
349
350     
351     def DisplayFvSpaceInfo(FdfParser):
352         
353         FvSpaceInfoList = []
354         MaxFvNameLength = 0
355         for FvName in FdfParser.Profile.FvDict:
356             if len(FvName) > MaxFvNameLength:
357                 MaxFvNameLength = len(FvName)
358             FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FfsDir, FvName.upper() + '.inf')
359             if os.path.exists(FvSpaceInfoFileName):
360                 FileLinesList = linecache.getlines(FvSpaceInfoFileName)
361                 TotalFound = False
362                 Total = ''
363                 UsedFound = False
364                 Used = ''
365                 FreeFound = False
366                 Free = ''
367                 for Line in FileLinesList:
368                     NameValue = Line.split('=')
369                     if len(NameValue) == 2:
370                         if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE':
371                             TotalFound = True
372                             Total = NameValue[1].strip()
373                         if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE':
374                             UsedFound = True
375                             Used = NameValue[1].strip()
376                         if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE':
377                             FreeFound = True
378                             Free = NameValue[1].strip()
379                 
380                 if TotalFound and UsedFound and FreeFound:
381                     FvSpaceInfoList.append((FvName, Total, Used, Free))
382                 
383         GenFdsGlobalVariable.InfLogger('\nFV Space Information')
384         for FvSpaceInfo in FvSpaceInfoList:
385             Name = FvSpaceInfo[0]
386             TotalSizeValue = long(FvSpaceInfo[1], 0)
387             UsedSizeValue = long(FvSpaceInfo[2], 0)
388             FreeSizeValue = long(FvSpaceInfo[3], 0)
389             GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + str((UsedSizeValue+0.0)/TotalSizeValue)[0:4].lstrip('0.') + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free')
390
391     ##Define GenFd as static function
392     GenFd = staticmethod(GenFd)
393     GetFvBlockSize = staticmethod(GetFvBlockSize)
394     DisplayFvSpaceInfo = staticmethod(DisplayFvSpaceInfo)
395
396 if __name__ == '__main__':
397     sys.exit(main())
398