audk/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py

498 lines
19 KiB
Python

## @file
# Global variables for GenFds
#
# Copyright (c) 2007 - 2010, 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
PlatformName = ''
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=[], Ui=None, Ver=None, InputAlign=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 len(GuidAttr) != 0:
#Add each guided attribute
for Attr in GuidAttr:
Cmd += ["-r", Attr]
if InputAlign != None:
#Section Align is only for dummy section without section type
for SecAlign in InputAlign:
Cmd += ["--sectionalign", SecAlign]
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 GetAlignment (AlignString):
if AlignString == None:
return 0
if AlignString in ("1K", "2K", "4K", "8K", "16K", "32K", "64K"):
return int (AlignString.rstrip('K')) * 1024
else:
return int (AlignString)
@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):
InputList = []
Cmd = ["EfiRom"]
if len(EfiInput) > 0:
if Compress:
Cmd += ["-ec"]
else:
Cmd += ["-e"]
for EfiFile in EfiInput:
Cmd += [EfiFile]
InputList.append (EfiFile)
if len(BinaryInput) > 0:
Cmd += ["-b"]
for BinFile in BinaryInput:
Cmd += [BinFile]
InputList.append (BinFile)
# Check List
if not GenFdsGlobalVariable.NeedsUpdate(Output, InputList):
return
GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, InputList))
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='', returnValue=[]):
if not GenFdsGlobalVariable.NeedsUpdate(Output, Input):
return
GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input))
Cmd = [ToolPath, ]
Cmd += Options.split(' ')
Cmd += ["-o", Output]
Cmd += Input
GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to call " + ToolPath, returnValue)
def CallExternalTool (cmd, errorMess, returnValue=[]):
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", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0]))
(out, error) = PopenObject.communicate()
while PopenObject.returncode == None :
PopenObject.wait()
if returnValue != [] and returnValue[0] != 0:
#get command return value
returnValue[0] = PopenObject.returncode
return
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", 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', 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)