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