1## @file 2# generate flash image 3# 4# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR> 5# 6# SPDX-License-Identifier: BSD-2-Clause-Patent 7# 8 9## 10# Import Modules 11# 12from __future__ import print_function 13from __future__ import absolute_import 14from re import compile 15from optparse import OptionParser 16from sys import exit 17from glob import glob 18from struct import unpack 19from linecache import getlines 20from io import BytesIO 21 22import Common.LongFilePathOs as os 23from Common.TargetTxtClassObject import TargetTxtClassObject 24from Common.DataType import * 25import Common.GlobalData as GlobalData 26from Common import EdkLogger 27from Common.StringUtils import NormPath 28from Common.Misc import DirCache, PathClass, GuidStructureStringToGuidString 29from Common.Misc import SaveFileOnChange, ClearDuplicatedInf 30from Common.BuildVersion import gBUILD_VERSION 31from Common.MultipleWorkspace import MultipleWorkspace as mws 32from Common.BuildToolError import FatalError, GENFDS_ERROR, CODE_ERROR, FORMAT_INVALID, RESOURCE_NOT_AVAILABLE, FILE_NOT_FOUND, OPTION_MISSING, FORMAT_NOT_SUPPORTED, OPTION_VALUE_INVALID, PARAMETER_INVALID 33from Workspace.WorkspaceDatabase import WorkspaceDatabase 34 35from .FdfParser import FdfParser, Warning 36from .GenFdsGlobalVariable import GenFdsGlobalVariable 37from .FfsFileStatement import FileStatement 38import Common.DataType as DataType 39from struct import Struct 40 41## Version and Copyright 42versionNumber = "1.0" + ' ' + gBUILD_VERSION 43__version__ = "%prog Version " + versionNumber 44__copyright__ = "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved." 45 46## Tool entrance method 47# 48# This method mainly dispatch specific methods per the command line options. 49# If no error found, return zero value so the caller of this tool can know 50# if it's executed successfully or not. 51# 52# @retval 0 Tool was successful 53# @retval 1 Tool failed 54# 55def main(): 56 global Options 57 Options = myOptionParser() 58 EdkLogger.Initialize() 59 return GenFdsApi(OptionsToCommandDict(Options)) 60 61def resetFdsGlobalVariable(): 62 GenFdsGlobalVariable.FvDir = '' 63 GenFdsGlobalVariable.OutputDirDict = {} 64 GenFdsGlobalVariable.BinDir = '' 65 # will be FvDir + os.sep + 'Ffs' 66 GenFdsGlobalVariable.FfsDir = '' 67 GenFdsGlobalVariable.FdfParser = None 68 GenFdsGlobalVariable.LibDir = '' 69 GenFdsGlobalVariable.WorkSpace = None 70 GenFdsGlobalVariable.WorkSpaceDir = '' 71 GenFdsGlobalVariable.ConfDir = '' 72 GenFdsGlobalVariable.OutputDirFromDscDict = {} 73 GenFdsGlobalVariable.TargetName = '' 74 GenFdsGlobalVariable.ToolChainTag = '' 75 GenFdsGlobalVariable.RuleDict = {} 76 GenFdsGlobalVariable.ArchList = None 77 GenFdsGlobalVariable.ActivePlatform = None 78 GenFdsGlobalVariable.FvAddressFileName = '' 79 GenFdsGlobalVariable.VerboseMode = False 80 GenFdsGlobalVariable.DebugLevel = -1 81 GenFdsGlobalVariable.SharpCounter = 0 82 GenFdsGlobalVariable.SharpNumberPerLine = 40 83 GenFdsGlobalVariable.FdfFile = '' 84 GenFdsGlobalVariable.FdfFileTimeStamp = 0 85 GenFdsGlobalVariable.FixedLoadAddress = False 86 GenFdsGlobalVariable.PlatformName = '' 87 88 GenFdsGlobalVariable.BuildRuleFamily = DataType.TAB_COMPILER_MSFT 89 GenFdsGlobalVariable.ToolChainFamily = DataType.TAB_COMPILER_MSFT 90 GenFdsGlobalVariable.__BuildRuleDatabase = None 91 GenFdsGlobalVariable.GuidToolDefinition = {} 92 GenFdsGlobalVariable.FfsCmdDict = {} 93 GenFdsGlobalVariable.SecCmdList = [] 94 GenFdsGlobalVariable.CopyList = [] 95 GenFdsGlobalVariable.ModuleFile = '' 96 GenFdsGlobalVariable.EnableGenfdsMultiThread = False 97 98 GenFdsGlobalVariable.LargeFileInFvFlags = [] 99 GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID = '5473C07A-3DCB-4dca-BD6F-1E9689E7349A' 100 GenFdsGlobalVariable.LARGE_FILE_SIZE = 0x1000000 101 102 GenFdsGlobalVariable.SectionHeader = Struct("3B 1B") 103 104 # FvName, FdName, CapName in FDF, Image file name 105 GenFdsGlobalVariable.ImageBinDict = {} 106 107def GenFdsApi(FdsCommandDict, WorkSpaceDataBase=None): 108 global Workspace 109 Workspace = "" 110 ArchList = None 111 ReturnCode = 0 112 resetFdsGlobalVariable() 113 114 try: 115 if FdsCommandDict.get("verbose"): 116 EdkLogger.SetLevel(EdkLogger.VERBOSE) 117 GenFdsGlobalVariable.VerboseMode = True 118 119 if FdsCommandDict.get("FixedAddress"): 120 GenFdsGlobalVariable.FixedLoadAddress = True 121 122 if FdsCommandDict.get("quiet"): 123 EdkLogger.SetLevel(EdkLogger.QUIET) 124 if FdsCommandDict.get("debug"): 125 EdkLogger.SetLevel(FdsCommandDict.get("debug") + 1) 126 GenFdsGlobalVariable.DebugLevel = FdsCommandDict.get("debug") 127 else: 128 EdkLogger.SetLevel(EdkLogger.INFO) 129 130 if not FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE')): 131 EdkLogger.error("GenFds", OPTION_MISSING, "WORKSPACE not defined", 132 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.") 133 elif not os.path.exists(FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE'))): 134 EdkLogger.error("GenFds", PARAMETER_INVALID, "WORKSPACE is invalid", 135 ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.") 136 else: 137 Workspace = os.path.normcase(FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE'))) 138 GenFdsGlobalVariable.WorkSpaceDir = Workspace 139 if FdsCommandDict.get("debug"): 140 GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace) 141 if FdsCommandDict.get("GenfdsMultiThread"): 142 GenFdsGlobalVariable.EnableGenfdsMultiThread = True 143 os.chdir(GenFdsGlobalVariable.WorkSpaceDir) 144 145 # set multiple workspace 146 PackagesPath = os.getenv("PACKAGES_PATH") 147 mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath) 148 149 if FdsCommandDict.get("fdf_file"): 150 FdfFilename = FdsCommandDict.get("fdf_file")[0].Path 151 FdfFilename = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdfFilename) 152 153 if FdfFilename[0:2] == '..': 154 FdfFilename = os.path.realpath(FdfFilename) 155 if not os.path.isabs(FdfFilename): 156 FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename) 157 if not os.path.exists(FdfFilename): 158 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename) 159 160 GenFdsGlobalVariable.FdfFile = FdfFilename 161 GenFdsGlobalVariable.FdfFileTimeStamp = os.path.getmtime(FdfFilename) 162 else: 163 EdkLogger.error("GenFds", OPTION_MISSING, "Missing FDF filename") 164 165 if FdsCommandDict.get("build_target"): 166 GenFdsGlobalVariable.TargetName = FdsCommandDict.get("build_target") 167 168 if FdsCommandDict.get("toolchain_tag"): 169 GenFdsGlobalVariable.ToolChainTag = FdsCommandDict.get("toolchain_tag") 170 171 if FdsCommandDict.get("active_platform"): 172 ActivePlatform = FdsCommandDict.get("active_platform") 173 ActivePlatform = GenFdsGlobalVariable.ReplaceWorkspaceMacro(ActivePlatform) 174 175 if ActivePlatform[0:2] == '..': 176 ActivePlatform = os.path.realpath(ActivePlatform) 177 178 if not os.path.isabs (ActivePlatform): 179 ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform) 180 181 if not os.path.exists(ActivePlatform): 182 EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!") 183 else: 184 EdkLogger.error("GenFds", OPTION_MISSING, "Missing active platform") 185 186 GenFdsGlobalVariable.ActivePlatform = PathClass(NormPath(ActivePlatform)) 187 188 if FdsCommandDict.get("conf_directory"): 189 # Get alternate Conf location, if it is absolute, then just use the absolute directory name 190 ConfDirectoryPath = os.path.normpath(FdsCommandDict.get("conf_directory")) 191 if ConfDirectoryPath.startswith('"'): 192 ConfDirectoryPath = ConfDirectoryPath[1:] 193 if ConfDirectoryPath.endswith('"'): 194 ConfDirectoryPath = ConfDirectoryPath[:-1] 195 if not os.path.isabs(ConfDirectoryPath): 196 # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE 197 # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf 198 ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ConfDirectoryPath) 199 else: 200 if "CONF_PATH" in os.environ: 201 ConfDirectoryPath = os.path.normcase(os.environ["CONF_PATH"]) 202 else: 203 # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf 204 ConfDirectoryPath = mws.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf') 205 GenFdsGlobalVariable.ConfDir = ConfDirectoryPath 206 if not GlobalData.gConfDirectory: 207 GlobalData.gConfDirectory = GenFdsGlobalVariable.ConfDir 208 BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt")) 209 if os.path.isfile(BuildConfigurationFile) == True: 210 TargetTxt = TargetTxtClassObject() 211 TargetTxt.LoadTargetTxtFile(BuildConfigurationFile) 212 # if no build target given in command line, get it from target.txt 213 if not GenFdsGlobalVariable.TargetName: 214 BuildTargetList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET] 215 if len(BuildTargetList) != 1: 216 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for Target.") 217 GenFdsGlobalVariable.TargetName = BuildTargetList[0] 218 219 # if no tool chain given in command line, get it from target.txt 220 if not GenFdsGlobalVariable.ToolChainTag: 221 ToolChainList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG] 222 if ToolChainList is None or len(ToolChainList) == 0: 223 EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.") 224 if len(ToolChainList) != 1: 225 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for ToolChain.") 226 GenFdsGlobalVariable.ToolChainTag = ToolChainList[0] 227 else: 228 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile) 229 230 #Set global flag for build mode 231 GlobalData.gIgnoreSource = FdsCommandDict.get("IgnoreSources") 232 233 if FdsCommandDict.get("macro"): 234 for Pair in FdsCommandDict.get("macro"): 235 if Pair.startswith('"'): 236 Pair = Pair[1:] 237 if Pair.endswith('"'): 238 Pair = Pair[:-1] 239 List = Pair.split('=') 240 if len(List) == 2: 241 if not List[1].strip(): 242 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="No Value given for Macro %s" %List[0]) 243 if List[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]: 244 GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip() 245 else: 246 GlobalData.gCommandLineDefines[List[0].strip()] = List[1].strip() 247 else: 248 GlobalData.gCommandLineDefines[List[0].strip()] = "TRUE" 249 os.environ["WORKSPACE"] = Workspace 250 251 # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined 252 if "TARGET" not in GlobalData.gGlobalDefines: 253 GlobalData.gGlobalDefines["TARGET"] = GenFdsGlobalVariable.TargetName 254 if "TOOLCHAIN" not in GlobalData.gGlobalDefines: 255 GlobalData.gGlobalDefines["TOOLCHAIN"] = GenFdsGlobalVariable.ToolChainTag 256 if "TOOL_CHAIN_TAG" not in GlobalData.gGlobalDefines: 257 GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable.ToolChainTag 258 259 """call Workspace build create database""" 260 GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath)) 261 262 if WorkSpaceDataBase: 263 BuildWorkSpace = WorkSpaceDataBase 264 else: 265 BuildWorkSpace = WorkspaceDatabase() 266 # 267 # Get files real name in workspace dir 268 # 269 GlobalData.gAllFiles = DirCache(Workspace) 270 GlobalData.gWorkspace = Workspace 271 272 if FdsCommandDict.get("build_architecture_list"): 273 ArchList = FdsCommandDict.get("build_architecture_list").split(',') 274 else: 275 ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList 276 277 TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList) & set(ArchList) 278 if len(TargetArchList) == 0: 279 EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON].SupArchList))) 280 281 for Arch in ArchList: 282 GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].OutputDirectory) 283 284 # assign platform name based on last entry in ArchList 285 GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, ArchList[-1], FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].PlatformName 286 287 if FdsCommandDict.get("platform_build_directory"): 288 OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdsCommandDict.get("platform_build_directory")) 289 if not os.path.isabs (OutputDirFromCommandLine): 290 OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine) 291 for Arch in ArchList: 292 GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine 293 else: 294 for Arch in ArchList: 295 GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag) 296 297 for Key in GenFdsGlobalVariable.OutputDirDict: 298 OutputDir = GenFdsGlobalVariable.OutputDirDict[Key] 299 if OutputDir[0:2] == '..': 300 OutputDir = os.path.realpath(OutputDir) 301 302 if OutputDir[1] != ':': 303 OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir) 304 305 if not os.path.exists(OutputDir): 306 EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir) 307 GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir 308 309 """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """ 310 if WorkSpaceDataBase: 311 FdfParserObj = GlobalData.gFdfParser 312 else: 313 FdfParserObj = FdfParser(FdfFilename) 314 FdfParserObj.ParseFile() 315 316 if FdfParserObj.CycleReferenceCheck(): 317 EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file") 318 319 if FdsCommandDict.get("fd"): 320 if FdsCommandDict.get("fd")[0].upper() in FdfParserObj.Profile.FdDict: 321 GenFds.OnlyGenerateThisFd = FdsCommandDict.get("fd")[0] 322 else: 323 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, 324 "No such an FD in FDF file: %s" % FdsCommandDict.get("fd")[0]) 325 326 if FdsCommandDict.get("fv"): 327 if FdsCommandDict.get("fv")[0].upper() in FdfParserObj.Profile.FvDict: 328 GenFds.OnlyGenerateThisFv = FdsCommandDict.get("fv")[0] 329 else: 330 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, 331 "No such an FV in FDF file: %s" % FdsCommandDict.get("fv")[0]) 332 333 if FdsCommandDict.get("cap"): 334 if FdsCommandDict.get("cap")[0].upper() in FdfParserObj.Profile.CapsuleDict: 335 GenFds.OnlyGenerateThisCap = FdsCommandDict.get("cap")[0] 336 else: 337 EdkLogger.error("GenFds", OPTION_VALUE_INVALID, 338 "No such a Capsule in FDF file: %s" % FdsCommandDict.get("cap")[0]) 339 340 GenFdsGlobalVariable.WorkSpace = BuildWorkSpace 341 if ArchList: 342 GenFdsGlobalVariable.ArchList = ArchList 343 344 # Dsc Build Data will handle Pcd Settings from CommandLine. 345 346 """Modify images from build output if the feature of loading driver at fixed address is on.""" 347 if GenFdsGlobalVariable.FixedLoadAddress: 348 GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform) 349 350 # Record the FV Region info that may specific in the FD 351 if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict: 352 for FvObj in FdfParserObj.Profile.FvDict.values(): 353 for FdObj in FdfParserObj.Profile.FdDict.values(): 354 for RegionObj in FdObj.RegionList: 355 if RegionObj.RegionType != BINARY_FILE_TYPE_FV: 356 continue 357 for RegionData in RegionObj.RegionDataList: 358 if FvObj.UiFvName.upper() == RegionData.upper(): 359 if not FvObj.BaseAddress: 360 FvObj.BaseAddress = '0x%x' % (int(FdObj.BaseAddress, 0) + RegionObj.Offset) 361 if FvObj.FvRegionInFD: 362 if FvObj.FvRegionInFD != RegionObj.Size: 363 EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName) 364 else: 365 FvObj.FvRegionInFD = RegionObj.Size 366 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj) 367 368 """Call GenFds""" 369 GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList) 370 371 """Generate GUID cross reference file""" 372 GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj) 373 374 """Display FV space info.""" 375 GenFds.DisplayFvSpaceInfo(FdfParserObj) 376 377 except Warning as X: 378 EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False) 379 ReturnCode = FORMAT_INVALID 380 except FatalError as X: 381 if FdsCommandDict.get("debug") is not None: 382 import traceback 383 EdkLogger.quiet(traceback.format_exc()) 384 ReturnCode = X.args[0] 385 except: 386 import traceback 387 EdkLogger.error( 388 "\nPython", 389 CODE_ERROR, 390 "Tools code failure", 391 ExtraData="Please send email to %s for help, attaching following call stack trace!\n" % MSG_EDKII_MAIL_ADDR, 392 RaiseError=False 393 ) 394 EdkLogger.quiet(traceback.format_exc()) 395 ReturnCode = CODE_ERROR 396 finally: 397 ClearDuplicatedInf() 398 return ReturnCode 399 400def OptionsToCommandDict(Options): 401 FdsCommandDict = {} 402 FdsCommandDict["verbose"] = Options.verbose 403 FdsCommandDict["FixedAddress"] = Options.FixedAddress 404 FdsCommandDict["quiet"] = Options.quiet 405 FdsCommandDict["debug"] = Options.debug 406 FdsCommandDict["Workspace"] = Options.Workspace 407 FdsCommandDict["GenfdsMultiThread"] = Options.GenfdsMultiThread 408 FdsCommandDict["fdf_file"] = [PathClass(Options.filename)] if Options.filename else [] 409 FdsCommandDict["build_target"] = Options.BuildTarget 410 FdsCommandDict["toolchain_tag"] = Options.ToolChain 411 FdsCommandDict["active_platform"] = Options.activePlatform 412 FdsCommandDict["OptionPcd"] = Options.OptionPcd 413 FdsCommandDict["conf_directory"] = Options.ConfDirectory 414 FdsCommandDict["IgnoreSources"] = Options.IgnoreSources 415 FdsCommandDict["macro"] = Options.Macros 416 FdsCommandDict["build_architecture_list"] = Options.archList 417 FdsCommandDict["platform_build_directory"] = Options.outputDir 418 FdsCommandDict["fd"] = [Options.uiFdName] if Options.uiFdName else [] 419 FdsCommandDict["fv"] = [Options.uiFvName] if Options.uiFvName else [] 420 FdsCommandDict["cap"] = [Options.uiCapName] if Options.uiCapName else [] 421 return FdsCommandDict 422 423 424gParamCheck = [] 425def SingleCheckCallback(option, opt_str, value, parser): 426 if option not in gParamCheck: 427 setattr(parser.values, option.dest, value) 428 gParamCheck.append(option) 429 else: 430 parser.error("Option %s only allows one instance in command line!" % option) 431 432## Parse command line options 433# 434# Using standard Python module optparse to parse command line option of this tool. 435# 436# @retval Opt A optparse.Values object containing the parsed options 437# 438def myOptionParser(): 439 usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\"" 440 Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber)) 441 Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback) 442 Parser.add_option("-a", "--arch", dest="archList", help="comma separated list containing one or more of: IA32, X64, IPF, ARM, AARCH64 or EBC which should be built, overrides target.txt?s TARGET_ARCH") 443 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.") 444 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.") 445 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.") 446 Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.", 447 action="callback", callback=SingleCheckCallback) 448 Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE", 449 action="callback", callback=SingleCheckCallback) 450 Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory", 451 action="callback", callback=SingleCheckCallback) 452 Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.") 453 Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName") 454 Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName") 455 Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.", 456 action="callback", callback=SingleCheckCallback) 457 Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.", 458 action="callback", callback=SingleCheckCallback) 459 Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".") 460 Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.") 461 Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.") 462 Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files") 463 Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ") 464 Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=False, help="Enable GenFds multi thread to generate ffs file.") 465 466 Options, _ = Parser.parse_args() 467 return Options 468 469## The class implementing the EDK2 flash image generation process 470# 471# This process includes: 472# 1. Collect workspace information, includes platform and module information 473# 2. Call methods of Fd class to generate FD 474# 3. Call methods of Fv class to generate FV that not belong to FD 475# 476class GenFds(object): 477 FdfParsef = None 478 OnlyGenerateThisFd = None 479 OnlyGenerateThisFv = None 480 OnlyGenerateThisCap = None 481 482 ## GenFd() 483 # 484 # @param OutputDir Output directory 485 # @param FdfParserObject FDF contents parser 486 # @param Workspace The directory of workspace 487 # @param ArchList The Arch list of platform 488 # 489 @staticmethod 490 def GenFd (OutputDir, FdfParserObject, WorkSpace, ArchList): 491 GenFdsGlobalVariable.SetDir ('', FdfParserObject, WorkSpace, ArchList) 492 493 GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!") 494 if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict: 495 CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[GenFds.OnlyGenerateThisCap.upper()] 496 if CapsuleObj is not None: 497 CapsuleObj.GenCapsule() 498 return 499 500 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict: 501 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()] 502 if FdObj is not None: 503 FdObj.GenFd() 504 return 505 elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None: 506 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values(): 507 FdObj.GenFd() 508 509 GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ") 510 if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict: 511 FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[GenFds.OnlyGenerateThisFv.upper()] 512 if FvObj is not None: 513 Buffer = BytesIO() 514 FvObj.AddToBuffer(Buffer) 515 Buffer.close() 516 return 517 elif GenFds.OnlyGenerateThisFv is None: 518 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values(): 519 Buffer = BytesIO() 520 FvObj.AddToBuffer(Buffer) 521 Buffer.close() 522 523 if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None: 524 if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}: 525 GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!") 526 for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values(): 527 CapsuleObj.GenCapsule() 528 529 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}: 530 GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!") 531 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values(): 532 OptRomObj.AddToBuffer(None) 533 534 @staticmethod 535 def GenFfsMakefile(OutputDir, FdfParserObject, WorkSpace, ArchList, GlobalData): 536 GenFdsGlobalVariable.SetEnv(FdfParserObject, WorkSpace, ArchList, GlobalData) 537 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values(): 538 FdObj.GenFd(Flag=True) 539 540 for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values(): 541 FvObj.AddToBuffer(Buffer=None, Flag=True) 542 543 if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}: 544 for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values(): 545 OptRomObj.AddToBuffer(Buffer=None, Flag=True) 546 547 return GenFdsGlobalVariable.FfsCmdDict 548 549 ## GetFvBlockSize() 550 # 551 # @param FvObj Whose block size to get 552 # @retval int Block size value 553 # 554 @staticmethod 555 def GetFvBlockSize(FvObj): 556 DefaultBlockSize = 0x1 557 FdObj = None 558 if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict: 559 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()] 560 if FdObj is None: 561 for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values(): 562 for ElementRegion in ElementFd.RegionList: 563 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV: 564 for ElementRegionData in ElementRegion.RegionDataList: 565 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName: 566 if FvObj.BlockSizeList != []: 567 return FvObj.BlockSizeList[0][0] 568 else: 569 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList) 570 if FvObj.BlockSizeList != []: 571 return FvObj.BlockSizeList[0][0] 572 return DefaultBlockSize 573 else: 574 for ElementRegion in FdObj.RegionList: 575 if ElementRegion.RegionType == BINARY_FILE_TYPE_FV: 576 for ElementRegionData in ElementRegion.RegionDataList: 577 if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName: 578 if FvObj.BlockSizeList != []: 579 return FvObj.BlockSizeList[0][0] 580 else: 581 return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList) 582 return DefaultBlockSize 583 584 ## DisplayFvSpaceInfo() 585 # 586 # @param FvObj Whose block size to get 587 # @retval None 588 # 589 @staticmethod 590 def DisplayFvSpaceInfo(FdfParserObject): 591 592 FvSpaceInfoList = [] 593 MaxFvNameLength = 0 594 for FvName in FdfParserObject.Profile.FvDict: 595 if len(FvName) > MaxFvNameLength: 596 MaxFvNameLength = len(FvName) 597 FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map') 598 if os.path.exists(FvSpaceInfoFileName): 599 FileLinesList = getlines(FvSpaceInfoFileName) 600 TotalFound = False 601 Total = '' 602 UsedFound = False 603 Used = '' 604 FreeFound = False 605 Free = '' 606 for Line in FileLinesList: 607 NameValue = Line.split('=') 608 if len(NameValue) == 2: 609 if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE': 610 TotalFound = True 611 Total = NameValue[1].strip() 612 if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE': 613 UsedFound = True 614 Used = NameValue[1].strip() 615 if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE': 616 FreeFound = True 617 Free = NameValue[1].strip() 618 619 if TotalFound and UsedFound and FreeFound: 620 FvSpaceInfoList.append((FvName, Total, Used, Free)) 621 622 GenFdsGlobalVariable.InfLogger('\nFV Space Information') 623 for FvSpaceInfo in FvSpaceInfoList: 624 Name = FvSpaceInfo[0] 625 TotalSizeValue = int(FvSpaceInfo[1], 0) 626 UsedSizeValue = int(FvSpaceInfo[2], 0) 627 FreeSizeValue = int(FvSpaceInfo[3], 0) 628 if UsedSizeValue == TotalSizeValue: 629 Percentage = '100' 630 else: 631 Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.') 632 633 GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free') 634 635 ## PreprocessImage() 636 # 637 # @param BuildDb Database from build meta data files 638 # @param DscFile modules from dsc file will be preprocessed 639 # @retval None 640 # 641 @staticmethod 642 def PreprocessImage(BuildDb, DscFile): 643 PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds 644 PcdValue = '' 645 for Key in PcdDict: 646 PcdObj = PcdDict[Key] 647 if PcdObj.TokenCName == 'PcdBsBaseAddress': 648 PcdValue = PcdObj.DefaultValue 649 break 650 651 if PcdValue == '': 652 return 653 654 Int64PcdValue = int(PcdValue, 0) 655 if Int64PcdValue == 0 or Int64PcdValue < -1: 656 return 657 658 TopAddress = 0 659 if Int64PcdValue > 0: 660 TopAddress = Int64PcdValue 661 662 ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules 663 for Key in ModuleDict: 664 ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] 665 print(ModuleObj.BaseName + ' ' + ModuleObj.ModuleType) 666 667 @staticmethod 668 def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj): 669 GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref") 670 GuidXRefFile = [] 671 PkgGuidDict = {} 672 GuidDict = {} 673 ModuleList = [] 674 FileGuidList = [] 675 VariableGuidSet = set() 676 for Arch in ArchList: 677 PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] 678 PkgList = GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag) 679 for P in PkgList: 680 PkgGuidDict.update(P.Guids) 681 for Name, Guid in PlatformDataBase.Pcds: 682 Pcd = PlatformDataBase.Pcds[Name, Guid] 683 if Pcd.Type in [TAB_PCDS_DYNAMIC_HII, TAB_PCDS_DYNAMIC_EX_HII]: 684 for SkuId in Pcd.SkuInfoList: 685 Sku = Pcd.SkuInfoList[SkuId] 686 if Sku.VariableGuid in VariableGuidSet:continue 687 VariableGuidSet.add(Sku.VariableGuid) 688 if Sku.VariableGuid and Sku.VariableGuid in PkgGuidDict.keys(): 689 GuidDict[Sku.VariableGuid] = PkgGuidDict[Sku.VariableGuid] 690 for ModuleFile in PlatformDataBase.Modules: 691 Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] 692 if Module in ModuleList: 693 continue 694 else: 695 ModuleList.append(Module) 696 if GlobalData.gGuidPattern.match(ModuleFile.BaseName): 697 GuidXRefFile.append("%s %s\n" % (ModuleFile.BaseName, Module.BaseName)) 698 else: 699 GuidXRefFile.append("%s %s\n" % (Module.Guid, Module.BaseName)) 700 GuidDict.update(Module.Protocols) 701 GuidDict.update(Module.Guids) 702 GuidDict.update(Module.Ppis) 703 for FvName in FdfParserObj.Profile.FvDict: 704 for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList: 705 if not isinstance(FfsObj, FileStatement): 706 InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName))) 707 FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] 708 if FdfModule in ModuleList: 709 continue 710 else: 711 ModuleList.append(FdfModule) 712 GuidXRefFile.append("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName)) 713 GuidDict.update(FdfModule.Protocols) 714 GuidDict.update(FdfModule.Guids) 715 GuidDict.update(FdfModule.Ppis) 716 else: 717 FileStatementGuid = FfsObj.NameGuid 718 if FileStatementGuid in FileGuidList: 719 continue 720 else: 721 FileGuidList.append(FileStatementGuid) 722 Name = [] 723 FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs') 724 FfsPath = glob(os.path.join(FfsPath, FileStatementGuid) + TAB_STAR) 725 if not FfsPath: 726 continue 727 if not os.path.exists(FfsPath[0]): 728 continue 729 MatchDict = {} 730 ReFileEnds = compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$') 731 FileList = os.listdir(FfsPath[0]) 732 for File in FileList: 733 Match = ReFileEnds.search(File) 734 if Match: 735 for Index in range(1, 8): 736 if Match.group(Index) and Match.group(Index) in MatchDict: 737 MatchDict[Match.group(Index)].append(File) 738 elif Match.group(Index): 739 MatchDict[Match.group(Index)] = [File] 740 if not MatchDict: 741 continue 742 if '.ui' in MatchDict: 743 for File in MatchDict['.ui']: 744 with open(os.path.join(FfsPath[0], File), 'rb') as F: 745 F.read() 746 length = F.tell() 747 F.seek(4) 748 TmpStr = unpack('%dh' % ((length - 4) // 2), F.read()) 749 Name = ''.join(chr(c) for c in TmpStr[:-1]) 750 else: 751 FileList = [] 752 if 'fv.sec.txt' in MatchDict: 753 FileList = MatchDict['fv.sec.txt'] 754 elif '.pe32.txt' in MatchDict: 755 FileList = MatchDict['.pe32.txt'] 756 elif '.te.txt' in MatchDict: 757 FileList = MatchDict['.te.txt'] 758 elif '.pic.txt' in MatchDict: 759 FileList = MatchDict['.pic.txt'] 760 elif '.raw.txt' in MatchDict: 761 FileList = MatchDict['.raw.txt'] 762 elif '.ffs.txt' in MatchDict: 763 FileList = MatchDict['.ffs.txt'] 764 else: 765 pass 766 for File in FileList: 767 with open(os.path.join(FfsPath[0], File), 'r') as F: 768 Name.append((F.read().split()[-1])) 769 if not Name: 770 continue 771 772 Name = ' '.join(Name) if isinstance(Name, type([])) else Name 773 GuidXRefFile.append("%s %s\n" %(FileStatementGuid, Name)) 774 775 # Append GUIDs, Protocols, and PPIs to the Xref file 776 GuidXRefFile.append("\n") 777 for key, item in GuidDict.items(): 778 GuidXRefFile.append("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key)) 779 780 if GuidXRefFile: 781 GuidXRefFile = ''.join(GuidXRefFile) 782 SaveFileOnChange(GuidXRefFileName, GuidXRefFile, False) 783 GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName) 784 elif os.path.exists(GuidXRefFileName): 785 os.remove(GuidXRefFileName) 786 787 788if __name__ == '__main__': 789 r = main() 790 ## 0-127 is a safe return range, and 1 is a standard default error 791 if r < 0 or r > 127: 792 r = 1 793 exit(r) 794 795