| ## @file |
| # Global variables for GenFds |
| # |
| # Copyright (c) 2007, Intel Corporation |
| # |
| # All rights reserved. This program and the accompanying materials |
| # are licensed and made available under the terms and conditions of the BSD License |
| # which accompanies this distribution. The full text of the license may be found at |
| # http://opensource.org/licenses/bsd-license.php |
| # |
| # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
| # |
| |
| ## |
| # Import Modules |
| # |
| import os |
| import sys |
| import subprocess |
| import struct |
| import array |
| |
| from Common.BuildToolError import * |
| from Common import EdkLogger |
| from Common.Misc import SaveFileOnChange |
| |
| ## Global variables |
| # |
| # |
| class GenFdsGlobalVariable: |
| FvDir = '' |
| OutputDirDict = {} |
| BinDir = '' |
| # will be FvDir + os.sep + 'Ffs' |
| FfsDir = '' |
| FdfParser = None |
| LibDir = '' |
| WorkSpace = None |
| WorkSpaceDir = '' |
| EdkSourceDir = '' |
| OutputDirFromDscDict = {} |
| TargetName = '' |
| ToolChainTag = '' |
| RuleDict = {} |
| ArchList = None |
| VtfDict = {} |
| ActivePlatform = None |
| FvAddressFileName = '' |
| VerboseMode = False |
| DebugLevel = -1 |
| SharpCounter = 0 |
| SharpNumberPerLine = 40 |
| FdfFile = '' |
| FdfFileTimeStamp = 0 |
| FixedLoadAddress = False |
| |
| SectionHeader = struct.Struct("3B 1B") |
| |
| ## SetDir() |
| # |
| # @param OutputDir Output directory |
| # @param FdfParser FDF contents parser |
| # @param Workspace The directory of workspace |
| # @param ArchList The Arch list of platform |
| # |
| def SetDir (OutputDir, FdfParser, WorkSpace, ArchList): |
| GenFdsGlobalVariable.VerboseLogger( "GenFdsGlobalVariable.OutputDir :%s" %OutputDir) |
| # GenFdsGlobalVariable.OutputDirDict = OutputDir |
| GenFdsGlobalVariable.FdfParser = FdfParser |
| GenFdsGlobalVariable.WorkSpace = WorkSpace |
| GenFdsGlobalVariable.FvDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[ArchList[0]], 'FV') |
| if not os.path.exists(GenFdsGlobalVariable.FvDir) : |
| os.makedirs(GenFdsGlobalVariable.FvDir) |
| GenFdsGlobalVariable.FfsDir = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs') |
| if not os.path.exists(GenFdsGlobalVariable.FfsDir) : |
| os.makedirs(GenFdsGlobalVariable.FfsDir) |
| if ArchList != None: |
| GenFdsGlobalVariable.ArchList = ArchList |
| |
| T_CHAR_LF = '\n' |
| # |
| # Create FV Address inf file |
| # |
| GenFdsGlobalVariable.FvAddressFileName = os.path.join(GenFdsGlobalVariable.FfsDir, 'FvAddress.inf') |
| FvAddressFile = open (GenFdsGlobalVariable.FvAddressFileName, 'w') |
| # |
| # Add [Options] |
| # |
| FvAddressFile.writelines("[options]" + T_CHAR_LF) |
| BsAddress = '0' |
| for Arch in ArchList: |
| if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].BsBaseAddress: |
| BsAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].BsBaseAddress |
| break |
| |
| FvAddressFile.writelines("EFI_BOOT_DRIVER_BASE_ADDRESS = " + \ |
| BsAddress + \ |
| T_CHAR_LF) |
| |
| RtAddress = '0' |
| for Arch in ArchList: |
| if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].RtBaseAddress: |
| RtAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch].RtBaseAddress |
| |
| FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \ |
| RtAddress + \ |
| T_CHAR_LF) |
| |
| FvAddressFile.close() |
| |
| ## ReplaceWorkspaceMacro() |
| # |
| # @param String String that may contain macro |
| # |
| def ReplaceWorkspaceMacro(String): |
| Str = String.replace('$(WORKSPACE)', GenFdsGlobalVariable.WorkSpaceDir) |
| if os.path.exists(Str): |
| if not os.path.isabs(Str): |
| Str = os.path.abspath(Str) |
| else: |
| Str = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, String) |
| return os.path.normpath(Str) |
| |
| ## Check if the input files are newer than output files |
| # |
| # @param Output Path of output file |
| # @param Input Path list of input files |
| # |
| # @retval True if Output doesn't exist, or any Input is newer |
| # @retval False if all Input is older than Output |
| # |
| @staticmethod |
| def NeedsUpdate(Output, Input): |
| if not os.path.exists(Output): |
| return True |
| # always update "Output" if no "Input" given |
| if Input == None or len(Input) == 0: |
| return True |
| |
| # if fdf file is changed after the 'Output" is generated, update the 'Output' |
| OutputTime = os.path.getmtime(Output) |
| if GenFdsGlobalVariable.FdfFileTimeStamp > OutputTime: |
| return True |
| |
| for F in Input: |
| # always update "Output" if any "Input" doesn't exist |
| if not os.path.exists(F): |
| return True |
| # always update "Output" if any "Input" is newer than "Output" |
| if os.path.getmtime(F) > OutputTime: |
| return True |
| return False |
| |
| @staticmethod |
| def GenerateSection(Output, Input, Type=None, CompressionType=None, Guid=None, |
| GuidHdrLen=None, GuidAttr=None, Ui=None, Ver=None): |
| if not GenFdsGlobalVariable.NeedsUpdate(Output, Input): |
| return |
| GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) |
| |
| Cmd = ["GenSec"] |
| if Type not in [None, '']: |
| Cmd += ["-s", Type] |
| if CompressionType not in [None, '']: |
| Cmd += ["-c", CompressionType] |
| if Guid != None: |
| Cmd += ["-g", Guid] |
| if GuidHdrLen not in [None, '']: |
| Cmd += ["-l", GuidHdrLen] |
| if GuidAttr not in [None, '']: |
| Cmd += ["-r", GuidAttr] |
| |
| if Ui not in [None, '']: |
| #Cmd += ["-n", '"' + Ui + '"'] |
| SectionData = array.array('B', [0,0,0,0]) |
| SectionData.fromstring(Ui.encode("utf_16_le")) |
| SectionData.append(0) |
| SectionData.append(0) |
| Len = len(SectionData) |
| GenFdsGlobalVariable.SectionHeader.pack_into(SectionData, 0, Len & 0xff, (Len >> 8) & 0xff, (Len >> 16) & 0xff, 0x15) |
| SaveFileOnChange(Output, SectionData.tostring()) |
| elif Ver not in [None, '']: |
| #Cmd += ["-j", Ver] |
| SectionData = array.array('B', [0,0,0,0]) |
| SectionData.fromstring(Ver.encode("utf_16_le")) |
| SectionData.append(0) |
| SectionData.append(0) |
| Len = len(SectionData) |
| GenFdsGlobalVariable.SectionHeader.pack_into(SectionData, 0, Len & 0xff, (Len >> 8) & 0xff, (Len >> 16) & 0xff, 0x14) |
| SaveFileOnChange(Output, SectionData.tostring()) |
| else: |
| Cmd += ["-o", Output] |
| Cmd += Input |
| GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section") |
| |
| @staticmethod |
| def GenerateFfs(Output, Input, Type, Guid, Fixed=False, CheckSum=False, Align=None, |
| SectionAlign=None): |
| if not GenFdsGlobalVariable.NeedsUpdate(Output, Input): |
| return |
| GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) |
| |
| Cmd = ["GenFfs", "-t", Type, "-g", Guid] |
| if Fixed == True: |
| Cmd += ["-x"] |
| if CheckSum: |
| Cmd += ["-s"] |
| if Align not in [None, '']: |
| Cmd += ["-a", Align] |
| |
| Cmd += ["-o", Output] |
| for I in range(0, len(Input)): |
| Cmd += ("-i", Input[I]) |
| if SectionAlign not in [None, '', []] and SectionAlign[I] not in [None, '']: |
| Cmd += ("-n", SectionAlign[I]) |
| GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FFS") |
| |
| @staticmethod |
| def GenerateFirmwareVolume(Output, Input, BaseAddress=None, Capsule=False, Dump=False, |
| AddressFile=None, MapFile=None, FfsList=[]): |
| if not GenFdsGlobalVariable.NeedsUpdate(Output, Input+FfsList): |
| return |
| GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) |
| |
| Cmd = ["GenFv"] |
| if BaseAddress not in [None, '']: |
| Cmd += ["-r", BaseAddress] |
| if Capsule: |
| Cmd += ["-c"] |
| if Dump: |
| Cmd += ["-p"] |
| if AddressFile not in [None, '']: |
| Cmd += ["-a", AddressFile] |
| if MapFile not in [None, '']: |
| Cmd += ["-m", MapFile] |
| Cmd += ["-o", Output] |
| for I in Input: |
| Cmd += ["-i", I] |
| |
| GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FV") |
| |
| @staticmethod |
| def GenerateVtf(Output, Input, BaseAddress=None, FvSize=None): |
| if not GenFdsGlobalVariable.NeedsUpdate(Output, Input): |
| return |
| GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) |
| |
| Cmd = ["GenVtf"] |
| if BaseAddress not in [None, ''] and FvSize not in [None, ''] \ |
| and len(BaseAddress) == len(FvSize): |
| for I in range(0, len(BaseAddress)): |
| Cmd += ["-r", BaseAddress[I], "-s", FvSize[I]] |
| Cmd += ["-o", Output] |
| for F in Input: |
| Cmd += ["-f", F] |
| |
| GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate VTF") |
| |
| @staticmethod |
| def GenerateFirmwareImage(Output, Input, Type="efi", SubType=None, Zero=False, |
| Strip=False, Replace=False, TimeStamp=None, Join=False, |
| Align=None, Padding=None, Convert=False): |
| if not GenFdsGlobalVariable.NeedsUpdate(Output, Input): |
| return |
| GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) |
| |
| Cmd = ["GenFw"] |
| if Type.lower() == "te": |
| Cmd += ["-t"] |
| if SubType not in [None, '']: |
| Cmd += ["-e", SubType] |
| if TimeStamp not in [None, '']: |
| Cmd += ["-s", TimeStamp] |
| if Align not in [None, '']: |
| Cmd += ["-a", Align] |
| if Padding not in [None, '']: |
| Cmd += ["-p", Padding] |
| if Zero: |
| Cmd += ["-z"] |
| if Strip: |
| Cmd += ["-l"] |
| if Replace: |
| Cmd += ["-r"] |
| if Join: |
| Cmd += ["-j"] |
| if Convert: |
| Cmd += ["-m"] |
| Cmd += ["-o", Output] |
| Cmd += Input |
| |
| GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate firmware image") |
| |
| @staticmethod |
| def GenerateOptionRom(Output, EfiInput, BinaryInput, Compress=False, ClassCode=None, |
| Revision=None, DeviceId=None, VendorId=None): |
| # if not GenFdsGlobalVariable.NeedsUpdate(Output, Input): |
| # return |
| # GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) |
| |
| Cmd = ["EfiRom"] |
| if len(EfiInput) > 0: |
| |
| if Compress: |
| Cmd += ["-ec"] |
| else: |
| Cmd += ["-e"] |
| |
| for EfiFile in EfiInput: |
| Cmd += [EfiFile] |
| |
| if len(BinaryInput) > 0: |
| Cmd += ["-b"] |
| for BinFile in BinaryInput: |
| Cmd += [BinFile] |
| |
| if ClassCode != None: |
| Cmd += ["-l", ClassCode] |
| if Revision != None: |
| Cmd += ["-r", Revision] |
| if DeviceId != None: |
| Cmd += ["-i", DeviceId] |
| if VendorId != None: |
| Cmd += ["-f", VendorId] |
| |
| Cmd += ["-o", Output] |
| GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate option rom") |
| |
| @staticmethod |
| def GuidTool(Output, Input, ToolPath, Options=''): |
| if not GenFdsGlobalVariable.NeedsUpdate(Output, Input): |
| return |
| GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) |
| |
| Cmd = [ToolPath, Options] |
| Cmd += ["-o", Output] |
| Cmd += Input |
| |
| GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to call " + ToolPath) |
| |
| def CallExternalTool (cmd, errorMess): |
| |
| if type(cmd) not in (tuple, list): |
| GenFdsGlobalVariable.ErrorLogger("ToolError! Invalid parameter type in call to CallExternalTool") |
| |
| if GenFdsGlobalVariable.DebugLevel != -1: |
| cmd += ('--debug', str(GenFdsGlobalVariable.DebugLevel)) |
| GenFdsGlobalVariable.InfLogger (cmd) |
| |
| if GenFdsGlobalVariable.VerboseMode: |
| cmd += ('-v',) |
| GenFdsGlobalVariable.InfLogger (cmd) |
| else: |
| sys.stdout.write ('#') |
| sys.stdout.flush() |
| GenFdsGlobalVariable.SharpCounter = GenFdsGlobalVariable.SharpCounter + 1 |
| if GenFdsGlobalVariable.SharpCounter % GenFdsGlobalVariable.SharpNumberPerLine == 0: |
| sys.stdout.write('\n') |
| |
| try: |
| PopenObject = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr= subprocess.PIPE) |
| except Exception, X: |
| EdkLogger.error("GenFds", BuildToolError.COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0])) |
| (out, error) = PopenObject.communicate() |
| |
| while PopenObject.returncode == None : |
| PopenObject.wait() |
| if PopenObject.returncode != 0 or GenFdsGlobalVariable.VerboseMode or GenFdsGlobalVariable.DebugLevel != -1: |
| GenFdsGlobalVariable.InfLogger ("Return Value = %d" %PopenObject.returncode) |
| GenFdsGlobalVariable.InfLogger (out) |
| GenFdsGlobalVariable.InfLogger (error) |
| if PopenObject.returncode != 0: |
| print "###", cmd |
| EdkLogger.error("GenFds", BuildToolError.COMMAND_FAILURE, errorMess) |
| |
| def VerboseLogger (msg): |
| EdkLogger.verbose(msg) |
| |
| def InfLogger (msg): |
| EdkLogger.info(msg) |
| |
| def ErrorLogger (msg, File = None, Line = None, ExtraData = None): |
| EdkLogger.error('GenFds', BuildToolError.GENFDS_ERROR, msg, File, Line, ExtraData) |
| |
| def DebugLogger (Level, msg): |
| EdkLogger.debug(Level, msg) |
| |
| ## ReplaceWorkspaceMacro() |
| # |
| # @param Str String that may contain macro |
| # @param MacroDict Dictionary that contains macro value pair |
| # |
| def MacroExtend (Str, MacroDict = {}, Arch = 'COMMON'): |
| if Str == None : |
| return None |
| |
| Dict = {'$(WORKSPACE)' : GenFdsGlobalVariable.WorkSpaceDir, |
| '$(EDK_SOURCE)' : GenFdsGlobalVariable.EdkSourceDir, |
| # '$(OUTPUT_DIRECTORY)': GenFdsGlobalVariable.OutputDirFromDsc, |
| '$(TARGET)' : GenFdsGlobalVariable.TargetName, |
| '$(TOOL_CHAIN_TAG)' : GenFdsGlobalVariable.ToolChainTag |
| } |
| OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[GenFdsGlobalVariable.ArchList[0]] |
| if Arch != 'COMMON' and Arch in GenFdsGlobalVariable.ArchList: |
| OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[Arch] |
| |
| Dict['$(OUTPUT_DIRECTORY)'] = OutputDir |
| |
| if MacroDict != None and len (MacroDict) != 0: |
| Dict.update(MacroDict) |
| |
| for key in Dict.keys(): |
| if Str.find(key) >= 0 : |
| Str = Str.replace (key, Dict[key]) |
| |
| if Str.find('$(ARCH)') >= 0: |
| if len(GenFdsGlobalVariable.ArchList) == 1: |
| Str = Str.replace('$(ARCH)', GenFdsGlobalVariable.ArchList[0]) |
| else: |
| EdkLogger.error("GenFds", GENFDS_ERROR, "No way to determine $(ARCH) for %s" % Str) |
| |
| return Str |
| |
| ## GetPcdValue() |
| # |
| # @param PcdPattern pattern that labels a PCD. |
| # |
| def GetPcdValue (PcdPattern): |
| if PcdPattern == None : |
| return None |
| PcdPair = PcdPattern.lstrip('PCD(').rstrip(')').strip().split('.') |
| TokenSpace = PcdPair[0] |
| TokenCName = PcdPair[1] |
| |
| PcdValue = '' |
| for Platform in GenFdsGlobalVariable.WorkSpace.PlatformList: |
| PcdDict = Platform.Pcds |
| for Key in PcdDict: |
| PcdObj = PcdDict[Key] |
| if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace): |
| if PcdObj.Type != 'FixedAtBuild': |
| EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern) |
| if PcdObj.DatumType != 'VOID*': |
| EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern) |
| |
| PcdValue = PcdObj.DefaultValue |
| return PcdValue |
| |
| for Package in GenFdsGlobalVariable.WorkSpace.PackageList: |
| PcdDict = Package.Pcds |
| for Key in PcdDict: |
| PcdObj = PcdDict[Key] |
| if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace): |
| if PcdObj.Type != 'FixedAtBuild': |
| EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern) |
| if PcdObj.DatumType != 'VOID*': |
| EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern) |
| |
| PcdValue = PcdObj.DefaultValue |
| return PcdValue |
| |
| return PcdValue |
| |
| SetDir = staticmethod(SetDir) |
| ReplaceWorkspaceMacro = staticmethod(ReplaceWorkspaceMacro) |
| CallExternalTool = staticmethod(CallExternalTool) |
| VerboseLogger = staticmethod(VerboseLogger) |
| InfLogger = staticmethod(InfLogger) |
| ErrorLogger = staticmethod(ErrorLogger) |
| DebugLogger = staticmethod(DebugLogger) |
| MacroExtend = staticmethod (MacroExtend) |
| GetPcdValue = staticmethod(GetPcdValue) |