GenFds tool creates target txt object to add macros in target.txt file to make DB...
[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         GenFdsGlobalVariable.OutputDirFromDsc = NormPath(OutputDirFromDsc)\r
163         \r
164         if (Options.outputDir):\r
165             OutputDir = Options.outputDir\r
166             OutputDir = GenFdsGlobalVariable.ReplaceWorkspaceMacro(OutputDir)\r
167         else:\r
168             OutputDir = os.path.join(GenFdsGlobalVariable.OutputDirFromDsc, GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag)        \r
169     \r
170         if OutputDir[0:2] == '..':\r
171             OutputDir = os.path.realpath(OutputDir)\r
172             \r
173         if OutputDir[1] != ':':\r
174             OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir)\r
175     \r
176         if not os.path.exists(OutputDir):\r
177             GenFdsGlobalVariable.ErrorLogger ("Directory %s not found" % (OutputDir))\r
178             sys.exit(1)\r
179                     \r
180         """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """\r
181         try:\r
182             FdfParserObj = FdfParser.FdfParser(FdfFilename)\r
183             FdfParserObj.ParseFile()\r
184         except FdfParser.Warning, X:\r
185             EdkLogger.error(X.ToolName, BuildToolError.GENFDS_ERROR, X.message, X.FileName, X.LineNumber, RaiseError = False)    \r
186             sys.exit(1)\r
187             \r
188         if FdfParserObj.CycleReferenceCheck():\r
189             GenFdsGlobalVariable.InfLogger ("ERROR: Cycle Reference Detected in FDF file")\r
190             sys.exit(1)\r
191         \r
192         if (Options.uiFdName) :\r
193             if Options.uiFdName.upper() in FdfParserObj.Profile.FdDict.keys():\r
194                 GenFds.currentFd = Options.uiFdName\r
195             else:\r
196                 GenFdsGlobalVariable.ErrorLogger("No such an FD in FDF file.")\r
197                 sys.exit(1)\r
198     \r
199         if (Options.uiFvName) :\r
200             if Options.uiFvName.upper() in FdfParserObj.Profile.FvDict.keys():\r
201                 GenFds.currentFv = Options.uiFvName\r
202             else:\r
203                 GenFdsGlobalVariable.ErrorLogger("No such an FV in FDF file.")\r
204                 sys.exit(1)\r
205        \r
206         BuildWorkSpace.GenBuildDatabase({}, FdfParserObj.Profile.InfList)\r
207         \r
208         """Call GenFds"""\r
209         GenFds.GenFd(OutputDir, FdfParserObj, BuildWorkSpace, ArchList)\r
210         print "\nDone!\n"\r
211     except Exception, X:\r
212         EdkLogger.error("GenFds", BuildToolError.GENFDS_ERROR, X, RaiseError = False)\r
213         sys.exit(1)\r
214 \r
215 ## Parse command line options\r
216 #\r
217 # Using standard Python module optparse to parse command line option of this tool.\r
218 #\r
219 #   @retval Opt   A optparse.Values object containing the parsed options\r
220 #   @retval Args  Target of build command\r
221 #    \r
222 def myOptionParser():\r
223     usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -y \"MacroName [= MacroValue]\""\r
224     Parser = OptionParser(usage=usage,description=__copyright__,version="%prog " + str(versionNumber))\r
225     Parser.add_option("-f", "--file", dest="filename", help="Name of FDF file to convert")\r
226     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
227     Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.")\r
228     Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.")\r
229     Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.")\r
230     Parser.add_option("-p", "--platform", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.")\r
231     Parser.add_option("-w", "--workspace", dest="Workspace", default=str(os.environ.get('WORKSPACE')), help="Set the WORKSPACE")\r
232     Parser.add_option("-o", "--outputDir", dest="outputDir", help="Name of Build Output directory")\r
233     Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.")\r
234     Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Buld the FV image using the [FV] section named by UiFvName")\r
235     Parser.add_option("-b", "--buildtarget", action="store", type="choice", choices=['DEBUG','RELEASE'], dest="BuildTarget", help="Build TARGET is one of list: DEBUG, RELEASE.")\r
236     Parser.add_option("-t", "--tagname", action="store", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.")\r
237     Parser.add_option("-y", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".")\r
238     (Options, args) = Parser.parse_args()\r
239     return Options\r
240 \r
241 ## The class implementing the EDK2 flash image generation process\r
242 #\r
243 #   This process includes:\r
244 #       1. Collect workspace information, includes platform and module information\r
245 #       2. Call methods of Fd class to generate FD\r
246 #       3. Call methods of Fv class to generate FV that not belong to FD\r
247 #\r
248 class GenFds :\r
249     FdfParsef = None\r
250     # FvName in FDF, FvBinFile name\r
251     FvBinDict = {}\r
252     OnlyGenerateThisFd = None\r
253     OnlyGenerateThisFv = None\r
254     \r
255     ## GenFd()\r
256     #\r
257     #   @param  OutputDir           Output directory\r
258     #   @param  FdfParser           FDF contents parser\r
259     #   @param  Workspace           The directory of workspace\r
260     #   @param  ArchList            The Arch list of platform\r
261     #\r
262     def GenFd (OutputDir, FdfParser, WorkSpace, ArchList):\r
263         GenFdsGlobalVariable.SetDir (OutputDir, FdfParser, WorkSpace, ArchList)\r
264         \r
265         #Set Default Rule\r
266         VerSection1 = EfiSection()\r
267         VerSection1.BuildNum = "$(BUILD_NUMBER)"\r
268         VerSection1.SectionType = "VERSION"\r
269         VerSection1.Filename = "$(INF_VERSION)"\r
270         VerSection1.VersionNum = "$(INF_VERSION)"\r
271         \r
272         UiSection1 = EfiSection()\r
273         UiSection1.SectionType = 'UI'\r
274         UiSection1.Filename = "$(INF_VERSION)"\r
275         UiSection1.VersionNum = "$(INF_VERSION)"\r
276 \r
277         DataSection = EfiSection()\r
278         DataSection.SectionType = "PE32"\r
279         DataSection.Filename = "$(INF_OUTPUT)/$(MODULE_NAME).efi"\r
280 \r
281         RuleComplexFile1 = RuleComplexFile.RuleComplexFile()\r
282         RuleComplexFile1.Alignment = 32\r
283         RuleComplexFile1.Arch = 'COMMON'\r
284         RuleComplexFile1.CheckSum = True\r
285         RuleComplexFile1.Fixed = True\r
286         RuleComplexFile1.FvFileType = "APPLICATION"\r
287         RuleComplexFile1.ModuleType = "UEFI_APPLICATION"\r
288         RuleComplexFile1.NameGuid = "$(MODULE_NAME)"\r
289         RuleComplexFile1.TemplateName = ''\r
290         RuleComplexFile1.SectionList = [UiSection1, VerSection1, DataSection]\r
291         GenFdsGlobalVariable.SetDefaultRule(RuleComplexFile1)\r
292 \r
293         GenFdsGlobalVariable.VerboseLogger("   Gen Fd  !")\r
294         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
295             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(GenFds.OnlyGenerateThisFd.upper())\r
296             if FdObj != None:\r
297                 FdObj.GenFd(GenFds.FvBinDict)\r
298         elif GenFds.OnlyGenerateThisFv == None:\r
299             for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
300                 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]\r
301                 FdObj.GenFd(GenFds.FvBinDict)\r
302             \r
303         GenFdsGlobalVariable.VerboseLogger(" Gen FV ! ")\r
304         if GenFds.OnlyGenerateThisFv != None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():\r
305             FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(GenFds.OnlyGenerateThisFv.upper())\r
306             if FvObj != None:\r
307                 Buffer = StringIO.StringIO()\r
308                 # Get FV base Address\r
309                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))\r
310                 Buffer.close()\r
311                 return\r
312         elif GenFds.OnlyGenerateThisFd == None:\r
313             for FvName in GenFdsGlobalVariable.FdfParser.Profile.FvDict.keys():          \r
314                 Buffer = StringIO.StringIO('')\r
315                 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[FvName]\r
316                 # Get FV base Address\r
317                 FvObj.AddToBuffer(Buffer, None, GenFds.GetFvBlockSize(FvObj))\r
318                 Buffer.close()\r
319     \r
320         if GenFds.OnlyGenerateThisFv == None and GenFds.OnlyGenerateThisFd == None:\r
321             GenFdsGlobalVariable.VerboseLogger(" Gen Capsule !")\r
322             for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleList:\r
323                 CapsuleObj.GenCapsule()\r
324 \r
325     ## GetFvBlockSize()\r
326     #\r
327     #   @param  FvObj           Whose block size to get\r
328     #   @retval int             Block size value\r
329     #\r
330     def GetFvBlockSize(FvObj):\r
331         FdObj = None\r
332         if GenFds.OnlyGenerateThisFd != None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():\r
333             FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()]\r
334         if FdObj == None:\r
335             for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
336                 for ElementRegion in ElementFd.RegionList:\r
337                     if ElementRegion.RegionType == 'FV':\r
338                         for ElementRegionData in ElementRegion.RegionDataList:\r
339                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:\r
340                                 if FvObj.BlockSizeList != []:\r
341                                     return FvObj.BlockSizeList[0][0]\r
342                                 else:\r
343                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
344             return 0x10000\r
345         else:\r
346             for ElementRegion in FdObj.RegionList:\r
347                     if ElementRegion.RegionType == 'FV':\r
348                         for ElementRegionData in ElementRegion.RegionDataList:\r
349                             if ElementRegionData != None and ElementRegionData.upper() == FvObj.UiFvName:\r
350                                 if FvObj.BlockSizeList != []:\r
351                                     return FvObj.BlockSizeList[0][0]\r
352                                 else:\r
353                                     return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList)\r
354             return 0x10000\r
355         \r
356     ##Define GenFd as static function\r
357     GenFd = staticmethod(GenFd)\r
358     GetFvBlockSize = staticmethod(GetFvBlockSize)\r
359 \r
360 if __name__ == '__main__':\r
361     \r
362     main()\r