2fa081e7c31c03b01023c609799c1b7954e5ef42
[people/mcb30/basetools.git] / Source / Python / GenFds / GenFds.py
1 ## @file\r
2 # generate flash image\r
3 #\r
4 #  Copyright (c) 2007, Intel Corporation\r
5 #\r
6 #  All rights reserved. This program and the accompanying materials\r
7 #  are licensed and made available under the terms and conditions of the BSD License\r
8 #  which accompanies this distribution.  The full text of the license may be found at\r
9 #  http://opensource.org/licenses/bsd-license.php\r
10 #\r
11 #  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 #  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 #\r
14 \r
15 ##\r
16 # Import Modules\r
17 #\r
18 from optparse import OptionParser\r
19 import sys\r
20 import os\r
21 import FdfParser\r
22 from Common import BuildToolError\r
23 from GenFdsGlobalVariable import GenFdsGlobalVariable\r
24 import Common.EdkIIWorkspaceBuild\r
25 import RuleComplexFile\r
26 from EfiSection import EfiSection\r
27 import StringIO\r
28 import Common.TargetTxtClassObject as TargetTxtClassObject\r
29 import Common.DataType\r
30 import Common.GlobalData as GlobalData\r
31 from Common import EdkLogger\r
32 from Common.String import *\r
33 \r
34 ## Version and Copyright\r
35 versionNumber = "1.0"\r
36 __version__ = "%prog Version " + versionNumber\r
37 __copyright__ = "Copyright (c) 2007, Intel Corporation  All rights reserved."\r
38 \r
39 ## Tool entrance method\r
40 #\r
41 # This method mainly dispatch specific methods per the command line options.\r
42 # If no error found, return zero value so the caller of this tool can know\r
43 # if it's executed successfully or not.\r
44 #\r
45 #   @retval 0     Tool was successful\r
46 #   @retval 1     Tool failed\r
47 #\r
48 def main():\r
49     global Options\r
50     Options = myOptionParser()\r
51     global Workspace\r
52     Workspace = ""\r
53     ArchList = None\r
54     try:\r
55         EdkLogger.Initialize()\r
56         if Options.verbose != None:\r
57             EdkLogger.SetLevel(EdkLogger.VERBOSE)\r
58             GenFdsGlobalVariable.VerboseMode = True\r
59         if Options.quiet != None:\r
60             EdkLogger.SetLevel(EdkLogger.QUIET)\r
61         if Options.debug != None:\r
62             EdkLogger.SetLevel(Options.debug + 1)\r
63             GenFdsGlobalVariable.DebugLevel = Options.debug\r
64         else:\r
65             EdkLogger.SetLevel(EdkLogger.INFO)\r
66             \r
67         if (Options.Workspace == None):\r
68             GenFdsGlobalVariable.ErrorLogger("WORKSPACE not defined.\n  Please set the WORKSPACE environment variable to the location of the EDK II install directory.")\r
69             sys.exit(1)\r
70         else:\r
71             Workspace = Options.Workspace\r
72             GenFdsGlobalVariable.WorkSpaceDir = Workspace\r
73             if 'EDK_SOURCE' in os.environ.keys():\r
74                 GenFdsGlobalVariable.EdkSourceDir = os.environ['EDK_SOURCE']\r
75             if (Options.debug):\r
76                 GenFdsGlobalVariable.VerboseLogger( "Using Workspace:" + Workspace)\r
77     \r
78         if (Options.filename):\r
79             FdfFilename = Options.filename\r
80             FdfFilename = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdfFilename)\r
81         else:\r
82             GenFdsGlobalVariable.ErrorLogger("You must specify an input filename")\r
83             sys.exit(1)\r
84     \r
85         if (Options.BuildTarget):\r
86             GenFdsGlobalVariable.TargetName = Options.BuildTarget\r
87         else:\r
88             GenFdsGlobalVariable.ErrorLogger("You must specify a build target")\r
89             sys.exit(1)\r
90             \r
91         if (Options.ToolChain):\r
92             GenFdsGlobalVariable.ToolChainTag = Options.ToolChain\r
93         else:\r
94             GenFdsGlobalVariable.ErrorLogger("You must specify a tool chain tag")\r
95             sys.exit(1)\r
96             \r
97         if FdfFilename[0:2] == '..':\r
98             FdfFilename = os.path.realpath(FdfFilename)\r
99         if FdfFilename[1] != ':':\r
100             FdfFilename = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename)\r
101                 \r
102         if not os.path.exists(FdfFilename):\r
103             GenFdsGlobalVariable.ErrorLogger ("File %s not found" % (FdfFilename))\r
104             sys.exit(1)\r
105     \r
106         if (Options.activePlatform):\r
107             ActivePlatform = Options.activePlatform\r
108             ActivePlatform = GenFdsGlobalVariable.ReplaceWorkspaceMacro(ActivePlatform)\r
109     \r
110             if ActivePlatform[0:2] == '..':\r
111                 ActivePlatform = os.path.realpath(ActivePlatform)\r
112     \r
113             if ActivePlatform[1] != ':':\r
114                 ActivePlatform = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform)\r
115     \r
116             if not os.path.exists(ActivePlatform)  :\r
117                 raise Exception ("ActivePlatform doesn't exist!")\r
118             \r
119             if ActivePlatform.find(Workspace) == -1:\r
120                 raise Exception ("ActivePlatform doesn't exist in Workspace!")\r
121             \r
122             ActivePlatform = ActivePlatform.replace(Workspace, '')\r
123             if len(ActivePlatform) > 0 :\r
124                 if ActivePlatform[0] == '\\' or ActivePlatform[0] == '/':\r
125                     ActivePlatform = ActivePlatform[1:]\r
126             else:\r
127                 raise Exception ("ActivePlatform doesn't exist!")\r
128         else :\r
129             GenFdsGlobalVariable.ErrorLogger("You must specify an active platform")\r
130             sys.exit(1)\r
131     \r
132         GenFdsGlobalVariable.ActivePlatform = NormPath(ActivePlatform)\r
133             \r
134         if (Options.archList) :\r
135             ArchList = Options.archList.split(',')\r
136         else:\r
137             GenFdsGlobalVariable.ErrorLogger("You must specify a build ARCH")\r
138             sys.exit(1)\r
139         \r
140         BuildConfigurationFile = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, "Conf/target.txt"))\r
141         if os.path.isfile(BuildConfigurationFile) == True:\r
142             TargetTxtClassObject.TargetTxtClassObject(BuildConfigurationFile)\r
143         else:\r
144             GenFdsGlobalVariable.ErrorLogger("File NOT found: %s", BuildConfigrationFile)\r
145             sys.exit(1)\r
146         \r
147         if Options.Macros:\r
148             for Pair in Options.Macros:\r
149                 Pair.strip('"')\r
150                 List = Pair.split('=')\r
151                 if len(List) == 2:\r
152                     FdfParser.InputMacroDict[List[0].strip()] = List[1].strip()\r
153                     GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip()\r
154                 else:\r
155                     FdfParser.InputMacroDict[List[0].strip()] = None\r
156             \r
157         """call Workspace build create database"""\r
158         os.environ["WORKSPACE"] = Workspace\r
159         BuildWorkSpace = Common.EdkIIWorkspaceBuild.WorkspaceBuild(GenFdsGlobalVariable.ActivePlatform, GenFdsGlobalVariable.WorkSpaceDir)\r
160             \r
161 #        OutputDirFromDsc = BuildWorkSpace.DscDatabase[GenFdsGlobalVariable.ActivePlatform].Defines.DefinesDictionary['OUTPUT_DIRECTORY'][0]\r
162         for Arch in ArchList:\r
163             GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.DscDatabase[GenFdsGlobalVariable.ActivePlatform].Platform.Header[Arch].OutputDirectory)\r
164         \r
165         if (Options.outputDir):\r
166             OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(Options.outputDir)\r
167             for Arch in ArchList:\r
168                 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine\r
169         else:\r
170             for Arch in ArchList:\r
171                 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)        \r
172     \r
173         for Key in GenFdsGlobalVariable.OutputDirDict:\r
174             OutputDir = GenFdsGlobalVariable.OutputDirDict[Key]\r
175             if OutputDir[0:2] == '..':\r
176                 OutputDir = os.path.realpath(OutputDir)\r
177                 \r
178             if OutputDir[1] != ':':\r
179                 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)\r
180         \r
181             if not os.path.exists(OutputDir):\r
182                 GenFdsGlobalVariable.ErrorLogger ("Directory %s not found" % (OutputDir))\r
183                 sys.exit(1)\r
184             GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir\r
185                     \r
186         """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """\r
187         try:\r
188             FdfParserObj = FdfParser.FdfParser(FdfFilename)\r
189             FdfParserObj.ParseFile()\r
190         except FdfParser.Warning, X:\r
191             EdkLogger.error(X.ToolName, BuildToolError.GENFDS_ERROR, X.message, X.FileName, X.LineNumber, RaiseError = False)    \r
192             sys.exit(1)\r
193             \r
194         if FdfParserObj.CycleReferenceCheck():\r
195             GenFdsGlobalVariable.InfLogger ("ERROR: Cycle Reference Detected in FDF file")\r
196             sys.exit(1)\r
197         \r
198         if (Options.uiFdName) :\r
199             if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict.keys():\r
200                 GenFds.currentFd = Options.uiFdName\r
201             else:\r
202                 GenFdsGlobalVariable.ErrorLogger("No such an FD in FDF file.")\r
203                 sys.exit(1)\r
204     \r
205         if (Options.uiFvName) :\r
206             if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict.keys():\r
207                 GenFds.currentFv = Options.uiFvName\r
208             else:\r
209                 GenFdsGlobalVariable.ErrorLogger("No such an FV in FDF file.")\r
210                 sys.exit(1)\r
211        \r
212         # Disable output of parsing DSC/INF/DEC temporarily\r
213         OldLevel = EdkLogger.GetLevel()\r
214         EdkLogger.SetLevel(EdkLogger.QUIET)\r
215         BuildWorkSpace.GenBuildDatabase({}, FdfParserObj.Profile.InfList)\r
216         EdkLogger.SetLevel(OldLevel)\r
217         \r
218         """Call GenFds"""\r
219         GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)\r
220         print "\nDone!\n"\r
221     except Exception, X:\r
222         EdkLogger.error("GenFds", BuildToolError.GENFDS_ERROR, X, RaiseError = False)\r
223         sys.exit(1)\r
224 \r
225 ## Parse command line options\r
226 #\r
227 # Using standard Python module optparse to parse command line option of this tool.\r
228 #\r
229 #   @retval Opt   A optparse.Values object containing the parsed options\r
230 #   @retval Args  Target of build command\r
231 #    \r
232 def myOptionParser():\r
233     usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -y \"MacroName [= MacroValue]\""\r
234     Parser = OptionParser(usage=usage,description=__copyright__,version="%prog " + str(versionNumber))\r
235     Parser.add_option("-f", "--file", dest="filename", help="Name of FDF file to convert")\r
236     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")\r
237     Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
238     Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")\r
239     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
240     Parser.add_option("-p", "--platform", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.")\r
241     Parser.add_option("-w", "--workspace", dest="Workspace", default=str(os.environ.get('WORKSPACE')), help="Set the WORKSPACE")\r
242     Parser.add_option("-o", "--outputDir", dest="outputDir", help="Name of Build Output directory")\r
243     Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")\r
244     Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Buld the FV image using the [FV] section named by UiFvName")\r
245     Parser.add_option("-b", "--buildtarget", action="store", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget", help="Build TARGET is one of list: DEBUG, RELEASE.")\r
246     Parser.add_option("-t", "--tagname", action="store", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.")\r
247     Parser.add_option("-y", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
248     (Options, args) = Parser.parse_args()\r
249     return Options\r
250 \r
251 ## The class implementing the EDK2 flash image generation process\r
252 #\r
253 #   This process includes:\r
254 #       1. Collect workspace information, includes platform and module information\r
255 #       2. Call methods of Fd class to generate FD\r
256 #       3. Call methods of Fv class to generate FV that not belong to FD\r
257 #\r
258 class GenFds :\r
259     FdfParsef = None\r
260     # FvName in FDF, FvBinFile name\r
261     FvBinDict = {}\r
262     OnlyGenerateThisFd = None\r
263     OnlyGenerateThisFv = None\r
264     \r
265     ## GenFd()\r
266     #\r
267     #   @param  OutputDir           Output directory\r
268     #   @param  FdfParser           FDF contents parser\r
269     #   @param  Workspace           The directory of workspace\r
270     #   @param  ArchList            The Arch list of platform\r
271     #\r
272     def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):\r
273         GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)\r
274 \r
275         GenFdsGlobalVariable.VerboseLogger("   Gen Fd  !")\r
276         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
277             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(GenFds.OnlyGenerateThisFd.upper())\r
278             if FdObj != None:\r
279                 FdObj.GenFd(GenFds.FvBinDict)\r
280         elif GenFds.OnlyGenerateThisFv == None:\r
281             for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
282                 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]\r
283                 FdObj.GenFd(GenFds.FvBinDict)\r
284             \r
285         GenFdsGlobalVariable.VerboseLogger(" Gen FV ! ")\r
286         if GenFds.OnlyGenerateThisFv != None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():\r
287             FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(GenFds.OnlyGenerateThisFv.upper())\r
288             if FvObj != None:\r
289                 Buffer = StringIO.StringIO()\r
290                 # Get FV base Address\r
291                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))\r
292                 Buffer.close()\r
293                 return\r
294         elif GenFds.OnlyGenerateThisFd == None:\r
295             for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():          \r
296                 Buffer = StringIO.StringIO('')\r
297                 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]\r
298                 # Get FV base Address\r
299                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))\r
300                 Buffer.close()\r
301     \r
302         if GenFds.OnlyGenerateThisFv == None and GenFds.OnlyGenerateThisFd == None:\r
303             GenFdsGlobalVariable.VerboseLogger(" Gen Capsule !")\r
304             for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleList:\r
305                 CapsuleObj.GenCapsule()\r
306 \r
307     ## GetFvBlockSize()\r
308     #\r
309     #   @param  FvObj           Whose block size to get\r
310     #   @retval int             Block size value\r
311     #\r
312     def GetFvBlockSize(FvObj):\r
313         FdObj = None\r
314         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
315             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]\r
316         if FdObj == None:\r
317             for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
318                 for ElementRegion in ElementFd.RegionList:\r
319                     if ElementRegion.RegionType == 'FV':\r
320                         for ElementRegionData in ElementRegion.RegionDataList:\r
321                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:\r
322                                 if FvObj.BlockSizeList != []:\r
323                                     return FvObj.BlockSizeList[0][0]\r
324                                 else:\r
325                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
326             return 0x10000\r
327         else:\r
328             for ElementRegion in FdObj.RegionList:\r
329                     if ElementRegion.RegionType == 'FV':\r
330                         for ElementRegionData in ElementRegion.RegionDataList:\r
331                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:\r
332                                 if FvObj.BlockSizeList != []:\r
333                                     return FvObj.BlockSizeList[0][0]\r
334                                 else:\r
335                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
336             return 0x10000\r
337         \r
338     ##Define GenFd as static function\r
339     GenFd = staticmethod(GenFd)\r
340     GetFvBlockSize = staticmethod(GetFvBlockSize)\r
341 \r
342 if __name__ == '__main__':\r
343     \r
344     main()\r