ef6a3d1db249d0ab8c60dd36502c8a85031936d3
[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 from Workspace.WorkspaceDatabase import WorkspaceDatabase\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 = WorkspaceDatabase('', GlobalData.gGlobalDefines)\r
160         BuildWorkSpace.InitDatabase()\r
161 \r
162         for Arch in ArchList:\r
163             GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, 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         """Call GenFds"""\r
213         GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList)\r
214         print "\nDone!\n"\r
215     except Exception, X:\r
216         EdkLogger.error("GenFds", BuildToolError.GENFDS_ERROR, X, RaiseError = False)\r
217         if Options.debug != None:\r
218             import traceback\r
219             EdkLogger.quiet(traceback.format_exc())\r
220         sys.exit(1)\r
221 \r
222 ## Parse command line options\r
223 #\r
224 # Using standard Python module optparse to parse command line option of this tool.\r
225 #\r
226 #   @retval Opt   A optparse.Values object containing the parsed options\r
227 #   @retval Args  Target of build command\r
228 #    \r
229 def myOptionParser():\r
230     usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -y \"MacroName [= MacroValue]\""\r
231     Parser = OptionParser(usage=usage,description=__copyright__,version="%prog " + str(versionNumber))\r
232     Parser.add_option("-f", "--file", dest="filename", help="Name of FDF file to convert")\r
233     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
234     Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
235     Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")\r
236     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
237     Parser.add_option("-p", "--platform", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.")\r
238     Parser.add_option("-w", "--workspace", dest="Workspace", default=str(os.environ.get('WORKSPACE')), help="Set the WORKSPACE")\r
239     Parser.add_option("-o", "--outputDir", dest="outputDir", help="Name of Build Output directory")\r
240     Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")\r
241     Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Buld the FV image using the [FV] section named by UiFvName")\r
242     Parser.add_option("-b", "--buildtarget", action="store", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget", help="Build TARGET is one of list: DEBUG, RELEASE.")\r
243     Parser.add_option("-t", "--tagname", action="store", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.")\r
244     Parser.add_option("-y", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
245     (Options, args) = Parser.parse_args()\r
246     return Options\r
247 \r
248 ## The class implementing the EDK2 flash image generation process\r
249 #\r
250 #   This process includes:\r
251 #       1. Collect workspace information, includes platform and module information\r
252 #       2. Call methods of Fd class to generate FD\r
253 #       3. Call methods of Fv class to generate FV that not belong to FD\r
254 #\r
255 class GenFds :\r
256     FdfParsef = None\r
257     # FvName in FDF, FvBinFile name\r
258     FvBinDict = {}\r
259     OnlyGenerateThisFd = None\r
260     OnlyGenerateThisFv = None\r
261     \r
262     ## GenFd()\r
263     #\r
264     #   @param  OutputDir           Output directory\r
265     #   @param  FdfParser           FDF contents parser\r
266     #   @param  Workspace           The directory of workspace\r
267     #   @param  ArchList            The Arch list of platform\r
268     #\r
269     def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):\r
270         GenFdsGlobalVariable.SetDir ('', FdfParser, WorkSpace, ArchList)\r
271 \r
272         GenFdsGlobalVariable.VerboseLogger("   Gen Fd  !")\r
273         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
274             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(GenFds.OnlyGenerateThisFd.upper())\r
275             if FdObj != None:\r
276                 FdObj.GenFd(GenFds.FvBinDict)\r
277         elif GenFds.OnlyGenerateThisFv == None:\r
278             for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
279                 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]\r
280                 FdObj.GenFd(GenFds.FvBinDict)\r
281             \r
282         GenFdsGlobalVariable.VerboseLogger(" Gen FV ! ")\r
283         if GenFds.OnlyGenerateThisFv != None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():\r
284             FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(GenFds.OnlyGenerateThisFv.upper())\r
285             if FvObj != None:\r
286                 Buffer = StringIO.StringIO()\r
287                 # Get FV base Address\r
288                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))\r
289                 Buffer.close()\r
290                 return\r
291         elif GenFds.OnlyGenerateThisFd == None:\r
292             for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():          \r
293                 Buffer = StringIO.StringIO('')\r
294                 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]\r
295                 # Get FV base Address\r
296                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))\r
297                 Buffer.close()\r
298     \r
299         if GenFds.OnlyGenerateThisFv == None and GenFds.OnlyGenerateThisFd == None:\r
300             GenFdsGlobalVariable.VerboseLogger(" Gen Capsule !")\r
301             for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleList:\r
302                 CapsuleObj.GenCapsule()\r
303 \r
304     ## GetFvBlockSize()\r
305     #\r
306     #   @param  FvObj           Whose block size to get\r
307     #   @retval int             Block size value\r
308     #\r
309     def GetFvBlockSize(FvObj):\r
310         FdObj = None\r
311         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
312             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]\r
313         if FdObj == None:\r
314             for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
315                 for ElementRegion in ElementFd.RegionList:\r
316                     if ElementRegion.RegionType == 'FV':\r
317                         for ElementRegionData in ElementRegion.RegionDataList:\r
318                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:\r
319                                 if FvObj.BlockSizeList != []:\r
320                                     return FvObj.BlockSizeList[0][0]\r
321                                 else:\r
322                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
323             return 0x10000\r
324         else:\r
325             for ElementRegion in FdObj.RegionList:\r
326                     if ElementRegion.RegionType == 'FV':\r
327                         for ElementRegionData in ElementRegion.RegionDataList:\r
328                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:\r
329                                 if FvObj.BlockSizeList != []:\r
330                                     return FvObj.BlockSizeList[0][0]\r
331                                 else:\r
332                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
333             return 0x10000\r
334         \r
335     ##Define GenFd as static function\r
336     GenFd = staticmethod(GenFd)\r
337     GetFvBlockSize = staticmethod(GetFvBlockSize)\r
338 \r
339 if __name__ == '__main__':\r
340     \r
341     main()\r