From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Source/Python/GenFds/AprioriSection.py | 121 + .../edk2/BaseTools/Source/Python/GenFds/Capsule.py | 250 ++ .../BaseTools/Source/Python/GenFds/CapsuleData.py | 239 ++ .../Source/Python/GenFds/CompressSection.py | 96 + .../BaseTools/Source/Python/GenFds/DataSection.py | 124 + .../BaseTools/Source/Python/GenFds/DepexSection.py | 111 + .../BaseTools/Source/Python/GenFds/EfiSection.py | 325 ++ roms/edk2/BaseTools/Source/Python/GenFds/Fd.py | 155 + .../BaseTools/Source/Python/GenFds/FdfParser.py | 4528 ++++++++++++++++++++ roms/edk2/BaseTools/Source/Python/GenFds/Ffs.py | 49 + .../Source/Python/GenFds/FfsFileStatement.py | 172 + .../Source/Python/GenFds/FfsInfStatement.py | 1128 +++++ roms/edk2/BaseTools/Source/Python/GenFds/Fv.py | 431 ++ .../Source/Python/GenFds/FvImageSection.py | 158 + roms/edk2/BaseTools/Source/Python/GenFds/GenFds.py | 797 ++++ .../Source/Python/GenFds/GenFdsGlobalVariable.py | 919 ++++ .../BaseTools/Source/Python/GenFds/GuidSection.py | 278 ++ .../Source/Python/GenFds/OptRomFileStatement.py | 48 + .../Source/Python/GenFds/OptRomInfStatement.py | 159 + .../BaseTools/Source/Python/GenFds/OptionRom.py | 131 + roms/edk2/BaseTools/Source/Python/GenFds/Region.py | 348 ++ roms/edk2/BaseTools/Source/Python/GenFds/Rule.py | 23 + .../Source/Python/GenFds/RuleComplexFile.py | 25 + .../Source/Python/GenFds/RuleSimpleFile.py | 25 + .../edk2/BaseTools/Source/Python/GenFds/Section.py | 169 + .../BaseTools/Source/Python/GenFds/UiSection.py | 74 + .../BaseTools/Source/Python/GenFds/VerSection.py | 76 + .../BaseTools/Source/Python/GenFds/__init__.py | 9 + 28 files changed, 10968 insertions(+) create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/AprioriSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/Capsule.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/CapsuleData.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/CompressSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/DataSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/DepexSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/EfiSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/Fd.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/FdfParser.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/Ffs.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/FfsFileStatement.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/FfsInfStatement.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/Fv.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/FvImageSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/GenFds.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/GuidSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/OptRomFileStatement.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/OptRomInfStatement.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/OptionRom.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/Region.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/Rule.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/RuleComplexFile.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/RuleSimpleFile.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/Section.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/UiSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/VerSection.py create mode 100644 roms/edk2/BaseTools/Source/Python/GenFds/__init__.py (limited to 'roms/edk2/BaseTools/Source/Python/GenFds') diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/AprioriSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/AprioriSection.py new file mode 100644 index 000000000..9f64c613e --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/AprioriSection.py @@ -0,0 +1,121 @@ +## @file +# process APRIORI file data and generate PEI/DXE APRIORI file +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from struct import pack +import Common.LongFilePathOs as os +from io import BytesIO +from .FfsFileStatement import FileStatement +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from Common.StringUtils import NormPath +from Common.Misc import SaveFileOnChange, PathClass +from Common.EdkLogger import error as EdkLoggerError +from Common.BuildToolError import RESOURCE_NOT_AVAILABLE +from Common.DataType import TAB_COMMON + +DXE_APRIORI_GUID = "FC510EE7-FFDC-11D4-BD41-0080C73C8881" +PEI_APRIORI_GUID = "1B45CC0A-156A-428A-AF62-49864DA0E6E6" + +## process APRIORI file data and generate PEI/DXE APRIORI file +# +# +class AprioriSection (object): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + self.DefineVarDict = {} + self.FfsList = [] + self.AprioriType = "" + + ## GenFfs() method + # + # Generate FFS for APRIORI file + # + # @param self The object pointer + # @param FvName for whom apriori file generated + # @param Dict dictionary contains macro and its value + # @retval string Generated file name + # + def GenFfs (self, FvName, Dict = None, IsMakefile = False): + if Dict is None: + Dict = {} + Buffer = BytesIO() + if self.AprioriType == "PEI": + AprioriFileGuid = PEI_APRIORI_GUID + else: + AprioriFileGuid = DXE_APRIORI_GUID + + OutputAprFilePath = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, \ + GenFdsGlobalVariable.FfsDir,\ + AprioriFileGuid + FvName) + if not os.path.exists(OutputAprFilePath): + os.makedirs(OutputAprFilePath) + + OutputAprFileName = os.path.join( OutputAprFilePath, \ + AprioriFileGuid + FvName + '.Apri' ) + AprFfsFileName = os.path.join (OutputAprFilePath,\ + AprioriFileGuid + FvName + '.Ffs') + + Dict.update(self.DefineVarDict) + InfFileName = None + for FfsObj in self.FfsList: + Guid = "" + if isinstance(FfsObj, FileStatement): + Guid = FfsObj.NameGuid + else: + InfFileName = NormPath(FfsObj.InfFileName) + Arch = FfsObj.GetCurrentArch() + + if Arch: + Dict['$(ARCH)'] = Arch + InfFileName = GenFdsGlobalVariable.MacroExtend(InfFileName, Dict, Arch) + + if Arch: + Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(InfFileName, GenFdsGlobalVariable.WorkSpaceDir), Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + Guid = Inf.Guid + else: + Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(InfFileName, GenFdsGlobalVariable.WorkSpaceDir), TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + Guid = Inf.Guid + + if not Inf.Module.Binaries: + EdkLoggerError("GenFds", RESOURCE_NOT_AVAILABLE, + "INF %s not found in build ARCH %s!" \ + % (InfFileName, GenFdsGlobalVariable.ArchList)) + + GuidPart = Guid.split('-') + Buffer.write(pack('I', int(GuidPart[0], 16))) + Buffer.write(pack('H', int(GuidPart[1], 16))) + Buffer.write(pack('H', int(GuidPart[2], 16))) + + for Num in range(2): + Char = GuidPart[3][Num*2:Num*2+2] + Buffer.write(pack('B', int(Char, 16))) + + for Num in range(6): + Char = GuidPart[4][Num*2:Num*2+2] + Buffer.write(pack('B', int(Char, 16))) + + SaveFileOnChange(OutputAprFileName, Buffer.getvalue()) + + RawSectionFileName = os.path.join( OutputAprFilePath, \ + AprioriFileGuid + FvName + '.raw' ) + MakefilePath = None + if IsMakefile: + if not InfFileName: + return None + MakefilePath = InfFileName, Arch + GenFdsGlobalVariable.GenerateSection(RawSectionFileName, [OutputAprFileName], 'EFI_SECTION_RAW', IsMakefile=IsMakefile) + GenFdsGlobalVariable.GenerateFfs(AprFfsFileName, [RawSectionFileName], + 'EFI_FV_FILETYPE_FREEFORM', AprioriFileGuid, MakefilePath=MakefilePath) + + return AprFfsFileName diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/Capsule.py b/roms/edk2/BaseTools/Source/Python/GenFds/Capsule.py new file mode 100644 index 000000000..f4bfc74e5 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/Capsule.py @@ -0,0 +1,250 @@ +## @file +# generate capsule +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from .GenFdsGlobalVariable import GenFdsGlobalVariable, FindExtendTool +from CommonDataClass.FdfClass import CapsuleClassObject +import Common.LongFilePathOs as os +from io import BytesIO +from Common.Misc import SaveFileOnChange, PackGUID +import uuid +from struct import pack +from Common import EdkLogger +from Common.BuildToolError import GENFDS_ERROR +from Common.DataType import TAB_LINE_BREAK + +WIN_CERT_REVISION = 0x0200 +WIN_CERT_TYPE_EFI_GUID = 0x0EF1 +EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID('{4aafd29d-68df-49ee-8aa9-347d375665a7}') +EFI_CERT_TYPE_RSA2048_SHA256_GUID = uuid.UUID('{a7717414-c616-4977-9420-844712a735bf}') + +## create inf file describes what goes into capsule and call GenFv to generate capsule +# +# +class Capsule (CapsuleClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + CapsuleClassObject.__init__(self) + # For GenFv + self.BlockSize = None + # For GenFv + self.BlockNum = None + self.CapsuleName = None + + ## Generate FMP capsule + # + # @retval string Generated Capsule file path + # + def GenFmpCapsule(self): + # + # Generate capsule header + # typedef struct { + # EFI_GUID CapsuleGuid; + # UINT32 HeaderSize; + # UINT32 Flags; + # UINT32 CapsuleImageSize; + # } EFI_CAPSULE_HEADER; + # + Header = BytesIO() + # + # Use FMP capsule GUID: 6DCBD5ED-E82D-4C44-BDA1-7194199AD92A + # + Header.write(PackGUID('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A'.split('-'))) + HdrSize = 0 + if 'CAPSULE_HEADER_SIZE' in self.TokensDict: + Header.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16))) + HdrSize = int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16) + else: + Header.write(pack('=I', 0x20)) + HdrSize = 0x20 + Flags = 0 + if 'CAPSULE_FLAGS' in self.TokensDict: + for flag in self.TokensDict['CAPSULE_FLAGS'].split(','): + flag = flag.strip() + if flag == 'PopulateSystemTable': + Flags |= 0x00010000 | 0x00020000 + elif flag == 'PersistAcrossReset': + Flags |= 0x00010000 + elif flag == 'InitiateReset': + Flags |= 0x00040000 + Header.write(pack('=I', Flags)) + # + # typedef struct { + # UINT32 Version; + # UINT16 EmbeddedDriverCount; + # UINT16 PayloadItemCount; + # // UINT64 ItemOffsetList[]; + # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER; + # + FwMgrHdr = BytesIO() + if 'CAPSULE_HEADER_INIT_VERSION' in self.TokensDict: + FwMgrHdr.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_INIT_VERSION'], 16))) + else: + FwMgrHdr.write(pack('=I', 0x00000001)) + FwMgrHdr.write(pack('=HH', len(self.CapsuleDataList), len(self.FmpPayloadList))) + FwMgrHdrSize = 4+2+2+8*(len(self.CapsuleDataList)+len(self.FmpPayloadList)) + + # + # typedef struct _WIN_CERTIFICATE { + # UINT32 dwLength; + # UINT16 wRevision; + # UINT16 wCertificateType; + # //UINT8 bCertificate[ANYSIZE_ARRAY]; + # } WIN_CERTIFICATE; + # + # typedef struct _WIN_CERTIFICATE_UEFI_GUID { + # WIN_CERTIFICATE Hdr; + # EFI_GUID CertType; + # //UINT8 CertData[ANYSIZE_ARRAY]; + # } WIN_CERTIFICATE_UEFI_GUID; + # + # typedef struct { + # UINT64 MonotonicCount; + # WIN_CERTIFICATE_UEFI_GUID AuthInfo; + # } EFI_FIRMWARE_IMAGE_AUTHENTICATION; + # + # typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 { + # EFI_GUID HashType; + # UINT8 PublicKey[256]; + # UINT8 Signature[256]; + # } EFI_CERT_BLOCK_RSA_2048_SHA256; + # + + PreSize = FwMgrHdrSize + Content = BytesIO() + for driver in self.CapsuleDataList: + FileName = driver.GenCapsuleSubItem() + FwMgrHdr.write(pack('=Q', PreSize)) + PreSize += os.path.getsize(FileName) + File = open(FileName, 'rb') + Content.write(File.read()) + File.close() + for fmp in self.FmpPayloadList: + if fmp.Existed: + FwMgrHdr.write(pack('=Q', PreSize)) + PreSize += len(fmp.Buffer) + Content.write(fmp.Buffer) + continue + if fmp.ImageFile: + for Obj in fmp.ImageFile: + fmp.ImageFile = Obj.GenCapsuleSubItem() + if fmp.VendorCodeFile: + for Obj in fmp.VendorCodeFile: + fmp.VendorCodeFile = Obj.GenCapsuleSubItem() + if fmp.Certificate_Guid: + ExternalTool, ExternalOption = FindExtendTool([], GenFdsGlobalVariable.ArchList, fmp.Certificate_Guid) + CmdOption = '' + CapInputFile = fmp.ImageFile + if not os.path.isabs(fmp.ImageFile): + CapInputFile = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, fmp.ImageFile) + CapOutputTmp = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.tmp' + if ExternalTool is None: + EdkLogger.error("GenFds", GENFDS_ERROR, "No tool found with GUID %s" % fmp.Certificate_Guid) + else: + CmdOption += ExternalTool + if ExternalOption: + CmdOption = CmdOption + ' ' + ExternalOption + CmdOption += ' -e ' + ' --monotonic-count ' + str(fmp.MonotonicCount) + ' -o ' + CapOutputTmp + ' ' + CapInputFile + CmdList = CmdOption.split() + GenFdsGlobalVariable.CallExternalTool(CmdList, "Failed to generate FMP auth capsule") + if uuid.UUID(fmp.Certificate_Guid) == EFI_CERT_TYPE_PKCS7_GUID: + dwLength = 4 + 2 + 2 + 16 + os.path.getsize(CapOutputTmp) - os.path.getsize(CapInputFile) + else: + dwLength = 4 + 2 + 2 + 16 + 16 + 256 + 256 + fmp.ImageFile = CapOutputTmp + AuthData = [fmp.MonotonicCount, dwLength, WIN_CERT_REVISION, WIN_CERT_TYPE_EFI_GUID, fmp.Certificate_Guid] + fmp.Buffer = fmp.GenCapsuleSubItem(AuthData) + else: + fmp.Buffer = fmp.GenCapsuleSubItem() + FwMgrHdr.write(pack('=Q', PreSize)) + PreSize += len(fmp.Buffer) + Content.write(fmp.Buffer) + BodySize = len(FwMgrHdr.getvalue()) + len(Content.getvalue()) + Header.write(pack('=I', HdrSize + BodySize)) + # + # The real capsule header structure is 28 bytes + # + Header.write(b'\x00'*(HdrSize-28)) + Header.write(FwMgrHdr.getvalue()) + Header.write(Content.getvalue()) + # + # Generate FMP capsule file + # + CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.Cap' + SaveFileOnChange(CapOutputFile, Header.getvalue(), True) + return CapOutputFile + + ## Generate capsule + # + # @param self The object pointer + # @retval string Generated Capsule file path + # + def GenCapsule(self): + if self.UiCapsuleName.upper() + 'cap' in GenFdsGlobalVariable.ImageBinDict: + return GenFdsGlobalVariable.ImageBinDict[self.UiCapsuleName.upper() + 'cap'] + + GenFdsGlobalVariable.InfLogger( "\nGenerate %s Capsule" %self.UiCapsuleName) + if ('CAPSULE_GUID' in self.TokensDict and + uuid.UUID(self.TokensDict['CAPSULE_GUID']) == uuid.UUID('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')): + return self.GenFmpCapsule() + + CapInfFile = self.GenCapInf() + CapInfFile.append("[files]" + TAB_LINE_BREAK) + CapFileList = [] + for CapsuleDataObj in self.CapsuleDataList: + CapsuleDataObj.CapsuleName = self.CapsuleName + FileName = CapsuleDataObj.GenCapsuleSubItem() + CapsuleDataObj.CapsuleName = None + CapFileList.append(FileName) + CapInfFile.append("EFI_FILE_NAME = " + \ + FileName + \ + TAB_LINE_BREAK) + SaveFileOnChange(self.CapInfFileName, ''.join(CapInfFile), False) + # + # Call GenFv tool to generate capsule + # + CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + CapOutputFile = CapOutputFile + '.Cap' + GenFdsGlobalVariable.GenerateFirmwareVolume( + CapOutputFile, + [self.CapInfFileName], + Capsule=True, + FfsList=CapFileList + ) + + GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s Capsule Successfully" %self.UiCapsuleName) + GenFdsGlobalVariable.SharpCounter = 0 + GenFdsGlobalVariable.ImageBinDict[self.UiCapsuleName.upper() + 'cap'] = CapOutputFile + return CapOutputFile + + ## Generate inf file for capsule + # + # @param self The object pointer + # @retval file inf file object + # + def GenCapInf(self): + self.CapInfFileName = os.path.join(GenFdsGlobalVariable.FvDir, + self.UiCapsuleName + "_Cap" + '.inf') + CapInfFile = [] + + CapInfFile.append("[options]" + TAB_LINE_BREAK) + + for Item in self.TokensDict: + CapInfFile.append("EFI_" + \ + Item + \ + ' = ' + \ + self.TokensDict[Item] + \ + TAB_LINE_BREAK) + + return CapInfFile diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/CapsuleData.py b/roms/edk2/BaseTools/Source/Python/GenFds/CapsuleData.py new file mode 100644 index 000000000..ebbde7f87 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/CapsuleData.py @@ -0,0 +1,239 @@ +## @file +# generate capsule +# +# Copyright (c) 2007-2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from io import BytesIO +from struct import pack +import os +from Common.Misc import SaveFileOnChange +import uuid + +## base class for capsule data +# +# +class CapsuleData: + ## The constructor + # + # @param self The object pointer + def __init__(self): + pass + + ## generate capsule data + # + # @param self The object pointer + def GenCapsuleSubItem(self): + pass + +## FFS class for capsule data +# +# +class CapsuleFfs (CapsuleData): + ## The constructor + # + # @param self The object pointer + # + def __init__(self) : + self.Ffs = None + self.FvName = None + + ## generate FFS capsule data + # + # @param self The object pointer + # @retval string Generated file name + # + def GenCapsuleSubItem(self): + FfsFile = self.Ffs.GenFfs() + return FfsFile + +## FV class for capsule data +# +# +class CapsuleFv (CapsuleData): + ## The constructor + # + # @param self The object pointer + # + def __init__(self) : + self.Ffs = None + self.FvName = None + self.CapsuleName = None + + ## generate FV capsule data + # + # @param self The object pointer + # @retval string Generated file name + # + def GenCapsuleSubItem(self): + if self.FvName.find('.fv') == -1: + if self.FvName.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict: + FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[self.FvName.upper()] + FdBuffer = BytesIO() + FvObj.CapsuleName = self.CapsuleName + FvFile = FvObj.AddToBuffer(FdBuffer) + FvObj.CapsuleName = None + FdBuffer.close() + return FvFile + else: + FvFile = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FvName) + return FvFile + +## FD class for capsule data +# +# +class CapsuleFd (CapsuleData): + ## The constructor + # + # @param self The object pointer + # + def __init__(self) : + self.Ffs = None + self.FdName = None + self.CapsuleName = None + + ## generate FD capsule data + # + # @param self The object pointer + # @retval string Generated file name + # + def GenCapsuleSubItem(self): + if self.FdName.find('.fd') == -1: + if self.FdName.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict: + FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[self.FdName.upper()] + FdFile = FdObj.GenFd() + return FdFile + else: + FdFile = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FdName) + return FdFile + +## AnyFile class for capsule data +# +# +class CapsuleAnyFile (CapsuleData): + ## The constructor + # + # @param self The object pointer + # + def __init__(self) : + self.Ffs = None + self.FileName = None + + ## generate AnyFile capsule data + # + # @param self The object pointer + # @retval string Generated file name + # + def GenCapsuleSubItem(self): + return self.FileName + +## Afile class for capsule data +# +# +class CapsuleAfile (CapsuleData): + ## The constructor + # + # @param self The object pointer + # + def __init__(self) : + self.Ffs = None + self.FileName = None + + ## generate Afile capsule data + # + # @param self The object pointer + # @retval string Generated file name + # + def GenCapsuleSubItem(self): + return self.FileName + +class CapsulePayload(CapsuleData): + '''Generate payload file, the header is defined below: + #pragma pack(1) + typedef struct { + UINT32 Version; + EFI_GUID UpdateImageTypeId; + UINT8 UpdateImageIndex; + UINT8 reserved_bytes[3]; + UINT32 UpdateImageSize; + UINT32 UpdateVendorCodeSize; + UINT64 UpdateHardwareInstance; //Introduced in v2 + } EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER; + ''' + def __init__(self): + self.UiName = None + self.Version = None + self.ImageTypeId = None + self.ImageIndex = None + self.HardwareInstance = None + self.ImageFile = [] + self.VendorCodeFile = [] + self.Certificate_Guid = None + self.MonotonicCount = None + self.Existed = False + self.Buffer = None + + def GenCapsuleSubItem(self, AuthData=[]): + if not self.Version: + self.Version = '0x00000002' + if not self.ImageIndex: + self.ImageIndex = '0x1' + if not self.HardwareInstance: + self.HardwareInstance = '0x0' + ImageFileSize = os.path.getsize(self.ImageFile) + if AuthData: + # the ImageFileSize need include the full authenticated info size. From first bytes of MonotonicCount to last bytes of certificate. + # the 32 bit is the MonotonicCount, dwLength, wRevision, wCertificateType and CertType + ImageFileSize += 32 + VendorFileSize = 0 + if self.VendorCodeFile: + VendorFileSize = os.path.getsize(self.VendorCodeFile) + + # + # Fill structure + # + Guid = self.ImageTypeId.split('-') + Buffer = pack('=ILHHBBBBBBBBBBBBIIQ', + int(self.Version, 16), + int(Guid[0], 16), + int(Guid[1], 16), + int(Guid[2], 16), + int(Guid[3][-4:-2], 16), + int(Guid[3][-2:], 16), + int(Guid[4][-12:-10], 16), + int(Guid[4][-10:-8], 16), + int(Guid[4][-8:-6], 16), + int(Guid[4][-6:-4], 16), + int(Guid[4][-4:-2], 16), + int(Guid[4][-2:], 16), + int(self.ImageIndex, 16), + 0, + 0, + 0, + ImageFileSize, + VendorFileSize, + int(self.HardwareInstance, 16) + ) + if AuthData: + Buffer += pack('QIHH', AuthData[0], AuthData[1], AuthData[2], AuthData[3]) + Buffer += uuid.UUID(AuthData[4]).bytes_le + + # + # Append file content to the structure + # + ImageFile = open(self.ImageFile, 'rb') + Buffer += ImageFile.read() + ImageFile.close() + if self.VendorCodeFile: + VendorFile = open(self.VendorCodeFile, 'rb') + Buffer += VendorFile.read() + VendorFile.close() + self.Existed = True + return Buffer diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/CompressSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/CompressSection.py new file mode 100644 index 000000000..e62280fc1 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/CompressSection.py @@ -0,0 +1,96 @@ +## @file +# process compress section generation +# +# Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from .Ffs import SectionSuffix +from . import Section +import subprocess +import Common.LongFilePathOs as os +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from CommonDataClass.FdfClass import CompressSectionClassObject +from Common.DataType import * + +## generate compress section +# +# +class CompressSection (CompressSectionClassObject) : + + ## compress types: PI standard and non PI standard + CompTypeDict = { + 'PI_STD' : 'PI_STD', + 'PI_NONE' : 'PI_NONE' + } + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + CompressSectionClassObject.__init__(self) + + ## GenSection() method + # + # Generate compressed section + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # @retval tuple (Generated file name, section alignment) + # + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = None, Dict = None, IsMakefile = False): + + if FfsInf is not None: + self.CompType = FfsInf.__ExtendMacro__(self.CompType) + self.Alignment = FfsInf.__ExtendMacro__(self.Alignment) + + SectFiles = tuple() + SectAlign = [] + Index = 0 + MaxAlign = None + if Dict is None: + Dict = {} + for Sect in self.SectionList: + Index = Index + 1 + SecIndex = '%s.%d' %(SecNum, Index) + ReturnSectList, AlignValue = Sect.GenSection(OutputPath, ModuleName, SecIndex, KeyStringList, FfsInf, Dict, IsMakefile=IsMakefile) + if AlignValue is not None: + if MaxAlign is None: + MaxAlign = AlignValue + if GenFdsGlobalVariable.GetAlignment (AlignValue) > GenFdsGlobalVariable.GetAlignment (MaxAlign): + MaxAlign = AlignValue + if ReturnSectList != []: + if AlignValue is None: + AlignValue = "1" + for FileData in ReturnSectList: + SectFiles += (FileData,) + SectAlign.append(AlignValue) + + OutputFile = OutputPath + \ + os.sep + \ + ModuleName + \ + SUP_MODULE_SEC + \ + SecNum + \ + SectionSuffix['COMPRESS'] + OutputFile = os.path.normpath(OutputFile) + DummyFile = OutputFile + '.dummy' + GenFdsGlobalVariable.GenerateSection(DummyFile, SectFiles, InputAlign=SectAlign, IsMakefile=IsMakefile) + + GenFdsGlobalVariable.GenerateSection(OutputFile, [DummyFile], Section.Section.SectionType['COMPRESS'], + CompressionType=self.CompTypeDict[self.CompType], IsMakefile=IsMakefile) + OutputFileList = [] + OutputFileList.append(OutputFile) + return OutputFileList, self.Alignment + + diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/DataSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/DataSection.py new file mode 100644 index 000000000..f20fd7022 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/DataSection.py @@ -0,0 +1,124 @@ +## @file +# process data section generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Section +from .GenFdsGlobalVariable import GenFdsGlobalVariable +import subprocess +from .Ffs import SectionSuffix +import Common.LongFilePathOs as os +from CommonDataClass.FdfClass import DataSectionClassObject +from Common.Misc import PeImageClass +from Common.LongFilePathSupport import CopyLongFilePath +from Common.DataType import * + +## generate data section +# +# +class DataSection (DataSectionClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + DataSectionClassObject.__init__(self) + + ## GenSection() method + # + # Generate compressed section + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # @retval tuple (Generated file name list, section alignment) + # + def GenSection(self, OutputPath, ModuleName, SecNum, keyStringList, FfsFile = None, Dict = None, IsMakefile = False): + # + # Prepare the parameter of GenSection + # + if Dict is None: + Dict = {} + if FfsFile is not None: + self.SectFileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.SectFileName) + self.SectFileName = GenFdsGlobalVariable.MacroExtend(self.SectFileName, Dict, FfsFile.CurrentArch) + else: + self.SectFileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.SectFileName) + self.SectFileName = GenFdsGlobalVariable.MacroExtend(self.SectFileName, Dict) + + """Check Section file exist or not !""" + + if not os.path.exists(self.SectFileName): + self.SectFileName = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, + self.SectFileName) + + """Copy Map file to Ffs output""" + Filename = GenFdsGlobalVariable.MacroExtend(self.SectFileName) + if Filename[(len(Filename)-4):] == '.efi': + MapFile = Filename.replace('.efi', '.map') + CopyMapFile = os.path.join(OutputPath, ModuleName + '.map') + if IsMakefile: + if GenFdsGlobalVariable.CopyList == []: + GenFdsGlobalVariable.CopyList = [(MapFile, CopyMapFile)] + else: + GenFdsGlobalVariable.CopyList.append((MapFile, CopyMapFile)) + else: + if os.path.exists(MapFile): + if not os.path.exists(CopyMapFile) or (os.path.getmtime(MapFile) > os.path.getmtime(CopyMapFile)): + CopyLongFilePath(MapFile, CopyMapFile) + + #Get PE Section alignment when align is set to AUTO + if self.Alignment == 'Auto' and self.SecType in (BINARY_FILE_TYPE_TE, BINARY_FILE_TYPE_PE32): + ImageObj = PeImageClass (Filename) + if ImageObj.SectionAlignment < 0x400: + self.Alignment = str (ImageObj.SectionAlignment) + elif ImageObj.SectionAlignment < 0x100000: + self.Alignment = str (ImageObj.SectionAlignment // 0x400) + 'K' + else: + self.Alignment = str (ImageObj.SectionAlignment // 0x100000) + 'M' + + NoStrip = True + if self.SecType in (BINARY_FILE_TYPE_TE, BINARY_FILE_TYPE_PE32): + if self.KeepReloc is not None: + NoStrip = self.KeepReloc + + if not NoStrip: + FileBeforeStrip = os.path.join(OutputPath, ModuleName + '.efi') + if not os.path.exists(FileBeforeStrip) or \ + (os.path.getmtime(self.SectFileName) > os.path.getmtime(FileBeforeStrip)): + CopyLongFilePath(self.SectFileName, FileBeforeStrip) + StrippedFile = os.path.join(OutputPath, ModuleName + '.stripped') + GenFdsGlobalVariable.GenerateFirmwareImage( + StrippedFile, + [GenFdsGlobalVariable.MacroExtend(self.SectFileName, Dict)], + Strip=True, + IsMakefile = IsMakefile + ) + self.SectFileName = StrippedFile + + if self.SecType == BINARY_FILE_TYPE_TE: + TeFile = os.path.join( OutputPath, ModuleName + 'Te.raw') + GenFdsGlobalVariable.GenerateFirmwareImage( + TeFile, + [GenFdsGlobalVariable.MacroExtend(self.SectFileName, Dict)], + Type='te', + IsMakefile = IsMakefile + ) + self.SectFileName = TeFile + + OutputFile = os.path.join (OutputPath, ModuleName + SUP_MODULE_SEC + SecNum + SectionSuffix.get(self.SecType)) + OutputFile = os.path.normpath(OutputFile) + GenFdsGlobalVariable.GenerateSection(OutputFile, [self.SectFileName], Section.Section.SectionType.get(self.SecType), IsMakefile = IsMakefile) + FileList = [OutputFile] + return FileList, self.Alignment diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/DepexSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/DepexSection.py new file mode 100644 index 000000000..6cabac38c --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/DepexSection.py @@ -0,0 +1,111 @@ +## @file +# process depex section generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Section +from .GenFdsGlobalVariable import GenFdsGlobalVariable +import Common.LongFilePathOs as os +from CommonDataClass.FdfClass import DepexSectionClassObject +from AutoGen.GenDepex import DependencyExpression +from Common import EdkLogger +from Common.BuildToolError import * +from Common.Misc import PathClass +from Common.DataType import * + +## generate data section +# +# +class DepexSection (DepexSectionClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + DepexSectionClassObject.__init__(self) + + def __FindGuidValue(self, CName): + for Arch in GenFdsGlobalVariable.ArchList: + PkgList = GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, + Arch, + GenFdsGlobalVariable.TargetName, + GenFdsGlobalVariable.ToolChainTag) + for Inf in GenFdsGlobalVariable.FdfParser.Profile.InfList: + ModuleData = GenFdsGlobalVariable.WorkSpace.BuildObject[ + PathClass(Inf, GenFdsGlobalVariable.WorkSpaceDir), + Arch, + GenFdsGlobalVariable.TargetName, + GenFdsGlobalVariable.ToolChainTag + ] + for Pkg in ModuleData.Packages: + if Pkg not in PkgList: + PkgList.append(Pkg) + for PkgDb in PkgList: + if CName in PkgDb.Ppis: + return PkgDb.Ppis[CName] + if CName in PkgDb.Protocols: + return PkgDb.Protocols[CName] + if CName in PkgDb.Guids: + return PkgDb.Guids[CName] + return None + + ## GenSection() method + # + # Generate compressed section + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # @retval tuple (Generated file name list, section alignment) + # + def GenSection(self, OutputPath, ModuleName, SecNum, keyStringList, FfsFile = None, Dict = None, IsMakefile = False): + if self.ExpressionProcessed == False: + self.Expression = self.Expression.replace("\n", " ").replace("\r", " ") + ExpList = self.Expression.split() + + for Exp in ExpList: + if Exp.upper() not in ('AND', 'OR', 'NOT', 'TRUE', 'FALSE', 'SOR', 'BEFORE', 'AFTER', 'END'): + GuidStr = self.__FindGuidValue(Exp) + if GuidStr is None: + EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, + "Depex GUID %s could not be found in build DB! (ModuleName: %s)" % (Exp, ModuleName)) + + self.Expression = self.Expression.replace(Exp, GuidStr) + + self.Expression = self.Expression.strip() + self.ExpressionProcessed = True + + if self.DepexType == 'PEI_DEPEX_EXP': + ModuleType = SUP_MODULE_PEIM + SecType = BINARY_FILE_TYPE_PEI_DEPEX + elif self.DepexType == 'DXE_DEPEX_EXP': + ModuleType = SUP_MODULE_DXE_DRIVER + SecType = BINARY_FILE_TYPE_DXE_DEPEX + elif self.DepexType == 'SMM_DEPEX_EXP': + ModuleType = SUP_MODULE_DXE_SMM_DRIVER + SecType = BINARY_FILE_TYPE_SMM_DEPEX + else: + EdkLogger.error("GenFds", FORMAT_INVALID, + "Depex type %s is not valid for module %s" % (self.DepexType, ModuleName)) + + InputFile = os.path.join (OutputPath, ModuleName + SUP_MODULE_SEC + SecNum + '.depex') + InputFile = os.path.normpath(InputFile) + Depex = DependencyExpression(self.Expression, ModuleType) + Depex.Generate(InputFile) + + OutputFile = os.path.join (OutputPath, ModuleName + SUP_MODULE_SEC + SecNum + '.dpx') + OutputFile = os.path.normpath(OutputFile) + + GenFdsGlobalVariable.GenerateSection(OutputFile, [InputFile], Section.Section.SectionType.get (SecType), IsMakefile=IsMakefile) + return [OutputFile], self.Alignment diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/EfiSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/EfiSection.py new file mode 100644 index 000000000..e7d463904 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/EfiSection.py @@ -0,0 +1,325 @@ +## @file +# process rule section generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from struct import * +from . import Section +from .GenFdsGlobalVariable import GenFdsGlobalVariable +import subprocess +from .Ffs import SectionSuffix +import Common.LongFilePathOs as os +from CommonDataClass.FdfClass import EfiSectionClassObject +from Common import EdkLogger +from Common.BuildToolError import * +from Common.Misc import PeImageClass +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.LongFilePathSupport import CopyLongFilePath +from Common.DataType import * + +## generate rule section +# +# +class EfiSection (EfiSectionClassObject): + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + EfiSectionClassObject.__init__(self) + + ## GenSection() method + # + # Generate rule section + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # @retval tuple (Generated file name list, section alignment) + # + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = None, Dict = None, IsMakefile = False) : + + if self.FileName is not None and self.FileName.startswith('PCD('): + self.FileName = GenFdsGlobalVariable.GetPcdValue(self.FileName) + """Prepare the parameter of GenSection""" + if FfsInf is not None : + InfFileName = FfsInf.InfFileName + SectionType = FfsInf.__ExtendMacro__(self.SectionType) + Filename = FfsInf.__ExtendMacro__(self.FileName) + BuildNum = FfsInf.__ExtendMacro__(self.BuildNum) + StringData = FfsInf.__ExtendMacro__(self.StringData) + ModuleNameStr = FfsInf.__ExtendMacro__('$(MODULE_NAME)') + NoStrip = True + if FfsInf.ModuleType in (SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, SUP_MODULE_MM_CORE_STANDALONE) and SectionType in (BINARY_FILE_TYPE_TE, BINARY_FILE_TYPE_PE32): + if FfsInf.KeepReloc is not None: + NoStrip = FfsInf.KeepReloc + elif FfsInf.KeepRelocFromRule is not None: + NoStrip = FfsInf.KeepRelocFromRule + elif self.KeepReloc is not None: + NoStrip = self.KeepReloc + elif FfsInf.ShadowFromInfFile is not None: + NoStrip = FfsInf.ShadowFromInfFile + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "Module %s apply rule for None!" %ModuleName) + + """If the file name was pointed out, add it in FileList""" + FileList = [] + if Dict is None: + Dict = {} + if Filename is not None: + Filename = GenFdsGlobalVariable.MacroExtend(Filename, Dict) + # check if the path is absolute or relative + if os.path.isabs(Filename): + Filename = os.path.normpath(Filename) + else: + Filename = os.path.normpath(os.path.join(FfsInf.EfiOutputPath, Filename)) + + if not self.Optional: + FileList.append(Filename) + elif os.path.exists(Filename): + FileList.append(Filename) + elif IsMakefile: + SuffixMap = FfsInf.GetFinalTargetSuffixMap() + if '.depex' in SuffixMap: + FileList.append(Filename) + else: + FileList, IsSect = Section.Section.GetFileList(FfsInf, self.FileType, self.FileExtension, Dict, IsMakefile=IsMakefile, SectionType=SectionType) + if IsSect : + return FileList, self.Alignment + + Index = 0 + Align = self.Alignment + + """ If Section type is 'VERSION'""" + OutputFileList = [] + if SectionType == 'VERSION': + + InfOverrideVerString = False + if FfsInf.Version is not None: + #StringData = FfsInf.Version + BuildNum = FfsInf.Version + InfOverrideVerString = True + + if InfOverrideVerString: + #VerTuple = ('-n', '"' + StringData + '"') + if BuildNum is not None and BuildNum != '': + BuildNumTuple = ('-j', BuildNum) + else: + BuildNumTuple = tuple() + + Num = SecNum + OutputFile = os.path.join( OutputPath, ModuleName + SUP_MODULE_SEC + str(Num) + SectionSuffix.get(SectionType)) + GenFdsGlobalVariable.GenerateSection(OutputFile, [], 'EFI_SECTION_VERSION', + #Ui=StringData, + Ver=BuildNum, + IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + + elif FileList != []: + for File in FileList: + Index = Index + 1 + Num = '%s.%d' %(SecNum, Index) + OutputFile = os.path.join(OutputPath, ModuleName + SUP_MODULE_SEC + Num + SectionSuffix.get(SectionType)) + f = open(File, 'r') + VerString = f.read() + f.close() + BuildNum = VerString + if BuildNum is not None and BuildNum != '': + BuildNumTuple = ('-j', BuildNum) + GenFdsGlobalVariable.GenerateSection(OutputFile, [], 'EFI_SECTION_VERSION', + #Ui=VerString, + Ver=BuildNum, + IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + + else: + BuildNum = StringData + if BuildNum is not None and BuildNum != '': + BuildNumTuple = ('-j', BuildNum) + else: + BuildNumTuple = tuple() + BuildNumString = ' ' + ' '.join(BuildNumTuple) + + #if VerString == '' and + if BuildNumString == '': + if self.Optional == True : + GenFdsGlobalVariable.VerboseLogger( "Optional Section don't exist!") + return [], None + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "File: %s miss Version Section value" %InfFileName) + Num = SecNum + OutputFile = os.path.join( OutputPath, ModuleName + SUP_MODULE_SEC + str(Num) + SectionSuffix.get(SectionType)) + GenFdsGlobalVariable.GenerateSection(OutputFile, [], 'EFI_SECTION_VERSION', + #Ui=VerString, + Ver=BuildNum, + IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + + # + # If Section Type is BINARY_FILE_TYPE_UI + # + elif SectionType == BINARY_FILE_TYPE_UI: + + InfOverrideUiString = False + if FfsInf.Ui is not None: + StringData = FfsInf.Ui + InfOverrideUiString = True + + if InfOverrideUiString: + Num = SecNum + if IsMakefile and StringData == ModuleNameStr: + StringData = "$(MODULE_NAME)" + OutputFile = os.path.join( OutputPath, ModuleName + SUP_MODULE_SEC + str(Num) + SectionSuffix.get(SectionType)) + GenFdsGlobalVariable.GenerateSection(OutputFile, [], 'EFI_SECTION_USER_INTERFACE', + Ui=StringData, IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + + elif FileList != []: + for File in FileList: + Index = Index + 1 + Num = '%s.%d' %(SecNum, Index) + OutputFile = os.path.join(OutputPath, ModuleName + SUP_MODULE_SEC + Num + SectionSuffix.get(SectionType)) + f = open(File, 'r') + UiString = f.read() + f.close() + if IsMakefile and UiString == ModuleNameStr: + UiString = "$(MODULE_NAME)" + GenFdsGlobalVariable.GenerateSection(OutputFile, [], 'EFI_SECTION_USER_INTERFACE', + Ui=UiString, IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + else: + if StringData is not None and len(StringData) > 0: + UiTuple = ('-n', '"' + StringData + '"') + else: + UiTuple = tuple() + + if self.Optional == True : + GenFdsGlobalVariable.VerboseLogger( "Optional Section don't exist!") + return '', None + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "File: %s miss UI Section value" %InfFileName) + + Num = SecNum + if IsMakefile and StringData == ModuleNameStr: + StringData = "$(MODULE_NAME)" + OutputFile = os.path.join( OutputPath, ModuleName + SUP_MODULE_SEC + str(Num) + SectionSuffix.get(SectionType)) + GenFdsGlobalVariable.GenerateSection(OutputFile, [], 'EFI_SECTION_USER_INTERFACE', + Ui=StringData, IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + + # + # If Section Type is BINARY_FILE_TYPE_RAW + # + elif SectionType == BINARY_FILE_TYPE_RAW: + """If File List is empty""" + if FileList == []: + if self.Optional == True: + GenFdsGlobalVariable.VerboseLogger("Optional Section don't exist!") + return [], None + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "Output file for %s section could not be found for %s" % (SectionType, InfFileName)) + + elif len(FileList) > 1: + EdkLogger.error("GenFds", GENFDS_ERROR, + "Files suffixed with %s are not allowed to have more than one file in %s[Binaries] section" % ( + self.FileExtension, InfFileName)) + else: + for File in FileList: + File = GenFdsGlobalVariable.MacroExtend(File, Dict) + OutputFileList.append(File) + + else: + """If File List is empty""" + if FileList == [] : + if self.Optional == True: + GenFdsGlobalVariable.VerboseLogger("Optional Section don't exist!") + return [], None + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "Output file for %s section could not be found for %s" % (SectionType, InfFileName)) + + else: + """Convert the File to Section file one by one """ + for File in FileList: + """ Copy Map file to FFS output path """ + Index = Index + 1 + Num = '%s.%d' %(SecNum, Index) + OutputFile = os.path.join( OutputPath, ModuleName + SUP_MODULE_SEC + Num + SectionSuffix.get(SectionType)) + File = GenFdsGlobalVariable.MacroExtend(File, Dict) + + #Get PE Section alignment when align is set to AUTO + if self.Alignment == 'Auto' and (SectionType == BINARY_FILE_TYPE_PE32 or SectionType == BINARY_FILE_TYPE_TE): + ImageObj = PeImageClass (File) + if ImageObj.SectionAlignment < 0x400: + Align = str (ImageObj.SectionAlignment) + elif ImageObj.SectionAlignment < 0x100000: + Align = str (ImageObj.SectionAlignment // 0x400) + 'K' + else: + Align = str (ImageObj.SectionAlignment // 0x100000) + 'M' + + if File[(len(File)-4):] == '.efi' and FfsInf.InfModule.BaseName == os.path.basename(File)[:-4]: + MapFile = File.replace('.efi', '.map') + CopyMapFile = os.path.join(OutputPath, ModuleName + '.map') + if IsMakefile: + if GenFdsGlobalVariable.CopyList == []: + GenFdsGlobalVariable.CopyList = [(MapFile, CopyMapFile)] + else: + GenFdsGlobalVariable.CopyList.append((MapFile, CopyMapFile)) + else: + if os.path.exists(MapFile): + if not os.path.exists(CopyMapFile) or \ + (os.path.getmtime(MapFile) > os.path.getmtime(CopyMapFile)): + CopyLongFilePath(MapFile, CopyMapFile) + + if not NoStrip: + FileBeforeStrip = os.path.join(OutputPath, ModuleName + '.efi') + if IsMakefile: + if GenFdsGlobalVariable.CopyList == []: + GenFdsGlobalVariable.CopyList = [(File, FileBeforeStrip)] + else: + GenFdsGlobalVariable.CopyList.append((File, FileBeforeStrip)) + else: + if not os.path.exists(FileBeforeStrip) or \ + (os.path.getmtime(File) > os.path.getmtime(FileBeforeStrip)): + CopyLongFilePath(File, FileBeforeStrip) + StrippedFile = os.path.join(OutputPath, ModuleName + '.stripped') + GenFdsGlobalVariable.GenerateFirmwareImage( + StrippedFile, + [File], + Strip=True, + IsMakefile = IsMakefile + ) + File = StrippedFile + + """For TE Section call GenFw to generate TE image""" + + if SectionType == BINARY_FILE_TYPE_TE: + TeFile = os.path.join( OutputPath, ModuleName + 'Te.raw') + GenFdsGlobalVariable.GenerateFirmwareImage( + TeFile, + [File], + Type='te', + IsMakefile = IsMakefile + ) + File = TeFile + + """Call GenSection""" + GenFdsGlobalVariable.GenerateSection(OutputFile, + [File], + Section.Section.SectionType.get (SectionType), + IsMakefile=IsMakefile + ) + OutputFileList.append(OutputFile) + + return OutputFileList, Align diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/Fd.py b/roms/edk2/BaseTools/Source/Python/GenFds/Fd.py new file mode 100644 index 000000000..973936b6f --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/Fd.py @@ -0,0 +1,155 @@ +## @file +# process FD generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Region +from . import Fv +import Common.LongFilePathOs as os +from io import BytesIO +import sys +from struct import * +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from CommonDataClass.FdfClass import FDClassObject +from Common import EdkLogger +from Common.BuildToolError import * +from Common.Misc import SaveFileOnChange +from Common.DataType import BINARY_FILE_TYPE_FV + +## generate FD +# +# +class FD(FDClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + FDClassObject.__init__(self) + + ## GenFd() method + # + # Generate FD + # + # @retval string Generated FD file name + # + def GenFd (self, Flag = False): + if self.FdUiName.upper() + 'fd' in GenFdsGlobalVariable.ImageBinDict: + return GenFdsGlobalVariable.ImageBinDict[self.FdUiName.upper() + 'fd'] + + # + # Print Information + # + FdFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.FdUiName + '.fd') + if not Flag: + GenFdsGlobalVariable.InfLogger("\nFd File Name:%s (%s)" %(self.FdUiName, FdFileName)) + + Offset = 0x00 + for item in self.BlockSizeList: + Offset = Offset + item[0] * item[1] + if Offset != self.Size: + EdkLogger.error("GenFds", GENFDS_ERROR, 'FD %s Size not consistent with block array' % self.FdUiName) + GenFdsGlobalVariable.VerboseLogger('Following Fv will be add to Fd !!!') + for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict: + GenFdsGlobalVariable.VerboseLogger(FvObj) + + HasCapsuleRegion = False + for RegionObj in self.RegionList: + if RegionObj.RegionType == 'CAPSULE': + HasCapsuleRegion = True + break + if HasCapsuleRegion: + TempFdBuffer = BytesIO() + PreviousRegionStart = -1 + PreviousRegionSize = 1 + + for RegionObj in self.RegionList : + if RegionObj.RegionType == 'CAPSULE': + continue + if RegionObj.Offset + RegionObj.Size <= PreviousRegionStart: + pass + elif RegionObj.Offset <= PreviousRegionStart or (RegionObj.Offset >=PreviousRegionStart and RegionObj.Offset < PreviousRegionStart + PreviousRegionSize): + pass + elif RegionObj.Offset > PreviousRegionStart + PreviousRegionSize: + if not Flag: + GenFdsGlobalVariable.InfLogger('Padding region starting from offset 0x%X, with size 0x%X' %(PreviousRegionStart + PreviousRegionSize, RegionObj.Offset - (PreviousRegionStart + PreviousRegionSize))) + PadRegion = Region.Region() + PadRegion.Offset = PreviousRegionStart + PreviousRegionSize + PadRegion.Size = RegionObj.Offset - PadRegion.Offset + if not Flag: + PadRegion.AddToBuffer(TempFdBuffer, self.BaseAddress, self.BlockSizeList, self.ErasePolarity, GenFdsGlobalVariable.ImageBinDict, self.DefineVarDict) + PreviousRegionStart = RegionObj.Offset + PreviousRegionSize = RegionObj.Size + # + # Call each region's AddToBuffer function + # + if PreviousRegionSize > self.Size: + pass + GenFdsGlobalVariable.VerboseLogger('Call each region\'s AddToBuffer function') + RegionObj.AddToBuffer (TempFdBuffer, self.BaseAddress, self.BlockSizeList, self.ErasePolarity, GenFdsGlobalVariable.ImageBinDict, self.DefineVarDict) + + FdBuffer = BytesIO() + PreviousRegionStart = -1 + PreviousRegionSize = 1 + for RegionObj in self.RegionList : + if RegionObj.Offset + RegionObj.Size <= PreviousRegionStart: + EdkLogger.error("GenFds", GENFDS_ERROR, + 'Region offset 0x%X in wrong order with Region starting from 0x%X, size 0x%X\nRegions in FDF must have offsets appear in ascending order.'\ + % (RegionObj.Offset, PreviousRegionStart, PreviousRegionSize)) + elif RegionObj.Offset <= PreviousRegionStart or (RegionObj.Offset >=PreviousRegionStart and RegionObj.Offset < PreviousRegionStart + PreviousRegionSize): + EdkLogger.error("GenFds", GENFDS_ERROR, + 'Region offset 0x%X overlaps with Region starting from 0x%X, size 0x%X' \ + % (RegionObj.Offset, PreviousRegionStart, PreviousRegionSize)) + elif RegionObj.Offset > PreviousRegionStart + PreviousRegionSize: + if not Flag: + GenFdsGlobalVariable.InfLogger('Padding region starting from offset 0x%X, with size 0x%X' %(PreviousRegionStart + PreviousRegionSize, RegionObj.Offset - (PreviousRegionStart + PreviousRegionSize))) + PadRegion = Region.Region() + PadRegion.Offset = PreviousRegionStart + PreviousRegionSize + PadRegion.Size = RegionObj.Offset - PadRegion.Offset + if not Flag: + PadRegion.AddToBuffer(FdBuffer, self.BaseAddress, self.BlockSizeList, self.ErasePolarity, GenFdsGlobalVariable.ImageBinDict, self.DefineVarDict) + PreviousRegionStart = RegionObj.Offset + PreviousRegionSize = RegionObj.Size + # + # Verify current region fits within allocated FD section Size + # + if PreviousRegionStart + PreviousRegionSize > self.Size: + EdkLogger.error("GenFds", GENFDS_ERROR, + 'FD %s size too small to fit region with offset 0x%X and size 0x%X' + % (self.FdUiName, PreviousRegionStart, PreviousRegionSize)) + # + # Call each region's AddToBuffer function + # + GenFdsGlobalVariable.VerboseLogger('Call each region\'s AddToBuffer function') + RegionObj.AddToBuffer (FdBuffer, self.BaseAddress, self.BlockSizeList, self.ErasePolarity, GenFdsGlobalVariable.ImageBinDict, self.DefineVarDict, Flag=Flag) + # + # Write the buffer contents to Fd file + # + GenFdsGlobalVariable.VerboseLogger('Write the buffer contents to Fd file') + if not Flag: + SaveFileOnChange(FdFileName, FdBuffer.getvalue()) + FdBuffer.close() + GenFdsGlobalVariable.ImageBinDict[self.FdUiName.upper() + 'fd'] = FdFileName + return FdFileName + + ## generate flash map file + # + # @param self The object pointer + # + def GenFlashMap (self): + pass + + + + + + + + diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/FdfParser.py b/roms/edk2/BaseTools/Source/Python/GenFds/FdfParser.py new file mode 100644 index 000000000..ea2401b0e --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/FdfParser.py @@ -0,0 +1,4528 @@ +## @file +# parse FDF file +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2015, Hewlett Packard Enterprise Development, L.P.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import print_function +from __future__ import absolute_import +from re import compile, DOTALL +from string import hexdigits +from uuid import UUID + +from Common.BuildToolError import * +from Common import EdkLogger +from Common.Misc import PathClass, tdict, ProcessDuplicatedInf, GuidStructureStringToGuidString +from Common.StringUtils import NormPath, ReplaceMacro +from Common import GlobalData +from Common.Expression import * +from Common.DataType import * +from Common.MultipleWorkspace import MultipleWorkspace as mws +import Common.LongFilePathOs as os +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.RangeExpression import RangeExpression +from collections import OrderedDict + +from .Fd import FD +from .Region import Region +from .Fv import FV +from .AprioriSection import AprioriSection +from .FfsInfStatement import FfsInfStatement +from .FfsFileStatement import FileStatement +from .VerSection import VerSection +from .UiSection import UiSection +from .FvImageSection import FvImageSection +from .DataSection import DataSection +from .DepexSection import DepexSection +from .CompressSection import CompressSection +from .GuidSection import GuidSection +from .Capsule import EFI_CERT_TYPE_PKCS7_GUID, EFI_CERT_TYPE_RSA2048_SHA256_GUID, Capsule +from .CapsuleData import CapsuleFfs, CapsulePayload, CapsuleFv, CapsuleFd, CapsuleAnyFile, CapsuleAfile +from .RuleComplexFile import RuleComplexFile +from .RuleSimpleFile import RuleSimpleFile +from .EfiSection import EfiSection +from .OptionRom import OPTIONROM +from .OptRomInfStatement import OptRomInfStatement, OverrideAttribs +from .OptRomFileStatement import OptRomFileStatement +from .GenFdsGlobalVariable import GenFdsGlobalVariable + +T_CHAR_CR = '\r' +T_CHAR_TAB = '\t' +T_CHAR_DOUBLE_QUOTE = '\"' +T_CHAR_SINGLE_QUOTE = '\'' +T_CHAR_BRACE_R = '}' + +SEPARATORS = {TAB_EQUAL_SPLIT, TAB_VALUE_SPLIT, TAB_COMMA_SPLIT, '{', T_CHAR_BRACE_R} +ALIGNMENTS = {"Auto", "8", "16", "32", "64", "128", "512", "1K", "4K", "32K", "64K", "128K", + "256K", "512K", "1M", "2M", "4M", "8M", "16M"} +ALIGNMENT_NOAUTO = ALIGNMENTS - {"Auto"} +CR_LB_SET = {T_CHAR_CR, TAB_LINE_BREAK} + +RegionSizePattern = compile("\s*(?P(?:0x|0X)?[a-fA-F0-9]+)\s*\|\s*(?P(?:0x|0X)?[a-fA-F0-9]+)\s*") +RegionSizeGuidPattern = compile("\s*(?P\w+\.\w+[\.\w\[\]]*)\s*\|\s*(?P\w+\.\w+[\.\w\[\]]*)\s*") +RegionOffsetPcdPattern = compile("\s*(?P\w+\.\w+[\.\w\[\]]*)\s*$") +ShortcutPcdPattern = compile("\s*\w+\s*=\s*(?P(?:0x|0X)?[a-fA-F0-9]+)\s*\|\s*(?P\w+\.\w+)\s*") +BaseAddrValuePattern = compile('^0[xX][0-9a-fA-F]+') +FileExtensionPattern = compile(r'([a-zA-Z][a-zA-Z0-9]*)') +TokenFindPattern = compile(r'([a-zA-Z0-9\-]+|\$\(TARGET\)|\*)_([a-zA-Z0-9\-]+|\$\(TOOL_CHAIN_TAG\)|\*)_([a-zA-Z0-9\-]+|\$\(ARCH\)|\*)') +AllIncludeFileList = [] + +# Get the closest parent +def GetParentAtLine (Line): + for Profile in AllIncludeFileList: + if Profile.IsLineInFile(Line): + return Profile + return None + +# Check include loop +def IsValidInclude (File, Line): + for Profile in AllIncludeFileList: + if Profile.IsLineInFile(Line) and Profile.FileName == File: + return False + + return True + +def GetRealFileLine (File, Line): + InsertedLines = 0 + for Profile in AllIncludeFileList: + if Profile.IsLineInFile(Line): + return Profile.GetLineInFile(Line) + elif Line >= Profile.InsertStartLineNumber and Profile.Level == 1: + InsertedLines += Profile.GetTotalLines() + + return (File, Line - InsertedLines) + +## The exception class that used to report error messages when parsing FDF +# +# Currently the "ToolName" is set to be "FdfParser". +# +class Warning (Exception): + ## The constructor + # + # @param self The object pointer + # @param Str The message to record + # @param File The FDF name + # @param Line The Line number that error occurs + # + def __init__(self, Str, File = None, Line = None): + FileLineTuple = GetRealFileLine(File, Line) + self.FileName = FileLineTuple[0] + self.LineNumber = FileLineTuple[1] + self.OriginalLineNumber = Line + self.Message = Str + self.ToolName = 'FdfParser' + + def __str__(self): + return self.Message + + # helper functions to facilitate consistency in warnings + # each function is for a different common warning + @staticmethod + def Expected(Str, File, Line): + return Warning("expected {}".format(Str), File, Line) + @staticmethod + def ExpectedEquals(File, Line): + return Warning.Expected("'='", File, Line) + @staticmethod + def ExpectedCurlyOpen(File, Line): + return Warning.Expected("'{'", File, Line) + @staticmethod + def ExpectedCurlyClose(File, Line): + return Warning.Expected("'}'", File, Line) + @staticmethod + def ExpectedBracketClose(File, Line): + return Warning.Expected("']'", File, Line) + +## The Include file content class that used to record file data when parsing include file +# +# May raise Exception when opening file. +# +class IncludeFileProfile: + ## The constructor + # + # @param self The object pointer + # @param FileName The file that to be parsed + # + def __init__(self, FileName): + self.FileName = FileName + self.FileLinesList = [] + try: + with open(FileName, "r") as fsock: + self.FileLinesList = fsock.readlines() + for index, line in enumerate(self.FileLinesList): + if not line.endswith(TAB_LINE_BREAK): + self.FileLinesList[index] += TAB_LINE_BREAK + except: + EdkLogger.error("FdfParser", FILE_OPEN_FAILURE, ExtraData=FileName) + + self.InsertStartLineNumber = None + self.InsertAdjust = 0 + self.IncludeFileList = [] + self.Level = 1 # first level include file + + def GetTotalLines(self): + TotalLines = self.InsertAdjust + len(self.FileLinesList) + + for Profile in self.IncludeFileList: + TotalLines += Profile.GetTotalLines() + + return TotalLines + + def IsLineInFile(self, Line): + if Line >= self.InsertStartLineNumber and Line < self.InsertStartLineNumber + self.GetTotalLines(): + return True + + return False + + def GetLineInFile(self, Line): + if not self.IsLineInFile (Line): + return (self.FileName, -1) + + InsertedLines = self.InsertStartLineNumber + + for Profile in self.IncludeFileList: + if Profile.IsLineInFile(Line): + return Profile.GetLineInFile(Line) + elif Line >= Profile.InsertStartLineNumber: + InsertedLines += Profile.GetTotalLines() + + return (self.FileName, Line - InsertedLines + 1) + +## The FDF content class that used to record file data when parsing FDF +# +# May raise Exception when opening file. +# +class FileProfile: + ## The constructor + # + # @param self The object pointer + # @param FileName The file that to be parsed + # + def __init__(self, FileName): + self.FileLinesList = [] + try: + with open(FileName, "r") as fsock: + self.FileLinesList = fsock.readlines() + + except: + EdkLogger.error("FdfParser", FILE_OPEN_FAILURE, ExtraData=FileName) + + self.FileName = FileName + self.PcdDict = OrderedDict() + self.PcdLocalDict = OrderedDict() + self.InfList = [] + self.InfDict = {'ArchTBD':[]} + # ECC will use this Dict and List information + self.PcdFileLineDict = {} + self.InfFileLineList = [] + + self.FdDict = {} + self.FdNameNotSet = False + self.FvDict = {} + self.CapsuleDict = {} + self.RuleDict = {} + self.OptRomDict = {} + self.FmpPayloadDict = {} + +## The syntax parser for FDF +# +# PreprocessFile method should be called prior to ParseFile +# CycleReferenceCheck method can detect cycles in FDF contents +# +# GetNext*** procedures mean these procedures will get next token first, then make judgement. +# Get*** procedures mean these procedures will make judgement on current token only. +# +class FdfParser: + ## The constructor + # + # @param self The object pointer + # @param FileName The file that to be parsed + # + def __init__(self, FileName): + self.Profile = FileProfile(FileName) + self.FileName = FileName + self.CurrentLineNumber = 1 + self.CurrentOffsetWithinLine = 0 + self.CurrentFdName = None + self.CurrentFvName = None + self._Token = "" + self._SkippedChars = "" + GlobalData.gFdfParser = self + + # Used to section info + self._CurSection = [] + # Key: [section name, UI name, arch] + # Value: {MACRO_NAME: MACRO_VALUE} + self._MacroDict = tdict(True, 3) + self._PcdDict = OrderedDict() + + self._WipeOffArea = [] + if GenFdsGlobalVariable.WorkSpaceDir == '': + GenFdsGlobalVariable.WorkSpaceDir = os.getenv("WORKSPACE") + + ## _SkipWhiteSpace() method + # + # Skip white spaces from current char. + # + # @param self The object pointer + # + def _SkipWhiteSpace(self): + while not self._EndOfFile(): + if self._CurrentChar() in {TAB_PRINTCHAR_NUL, T_CHAR_CR, TAB_LINE_BREAK, TAB_SPACE_SPLIT, T_CHAR_TAB}: + self._SkippedChars += str(self._CurrentChar()) + self._GetOneChar() + else: + return + return + + ## _EndOfFile() method + # + # Judge current buffer pos is at file end + # + # @param self The object pointer + # @retval True Current File buffer position is at file end + # @retval False Current File buffer position is NOT at file end + # + def _EndOfFile(self): + NumberOfLines = len(self.Profile.FileLinesList) + SizeOfLastLine = len(self.Profile.FileLinesList[-1]) + if self.CurrentLineNumber == NumberOfLines and self.CurrentOffsetWithinLine >= SizeOfLastLine - 1: + return True + if self.CurrentLineNumber > NumberOfLines: + return True + return False + + ## _EndOfLine() method + # + # Judge current buffer pos is at line end + # + # @param self The object pointer + # @retval True Current File buffer position is at line end + # @retval False Current File buffer position is NOT at line end + # + def _EndOfLine(self): + if self.CurrentLineNumber > len(self.Profile.FileLinesList): + return True + SizeOfCurrentLine = len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) + if self.CurrentOffsetWithinLine >= SizeOfCurrentLine: + return True + return False + + ## Rewind() method + # + # Reset file data buffer to the initial state + # + # @param self The object pointer + # @param DestLine Optional new destination line number. + # @param DestOffset Optional new destination offset. + # + def Rewind(self, DestLine = 1, DestOffset = 0): + self.CurrentLineNumber = DestLine + self.CurrentOffsetWithinLine = DestOffset + + ## _UndoOneChar() method + # + # Go back one char in the file buffer + # + # @param self The object pointer + # @retval True Successfully go back one char + # @retval False Not able to go back one char as file beginning reached + # + def _UndoOneChar(self): + if self.CurrentLineNumber == 1 and self.CurrentOffsetWithinLine == 0: + return False + elif self.CurrentOffsetWithinLine == 0: + self.CurrentLineNumber -= 1 + self.CurrentOffsetWithinLine = len(self._CurrentLine()) - 1 + else: + self.CurrentOffsetWithinLine -= 1 + return True + + ## _GetOneChar() method + # + # Move forward one char in the file buffer + # + # @param self The object pointer + # + def _GetOneChar(self): + if self.CurrentOffsetWithinLine == len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) - 1: + self.CurrentLineNumber += 1 + self.CurrentOffsetWithinLine = 0 + else: + self.CurrentOffsetWithinLine += 1 + + ## _CurrentChar() method + # + # Get the char pointed to by the file buffer pointer + # + # @param self The object pointer + # @retval Char Current char + # + def _CurrentChar(self): + return self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine] + + ## _NextChar() method + # + # Get the one char pass the char pointed to by the file buffer pointer + # + # @param self The object pointer + # @retval Char Next char + # + def _NextChar(self): + if self.CurrentOffsetWithinLine == len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) - 1: + return self.Profile.FileLinesList[self.CurrentLineNumber][0] + return self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine + 1] + + ## _SetCurrentCharValue() method + # + # Modify the value of current char + # + # @param self The object pointer + # @param Value The new value of current char + # + def _SetCurrentCharValue(self, Value): + self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine] = Value + + ## _CurrentLine() method + # + # Get the list that contains current line contents + # + # @param self The object pointer + # @retval List current line contents + # + def _CurrentLine(self): + return self.Profile.FileLinesList[self.CurrentLineNumber - 1] + + def _StringToList(self): + self.Profile.FileLinesList = [list(s) for s in self.Profile.FileLinesList] + if not self.Profile.FileLinesList: + EdkLogger.error('FdfParser', FILE_READ_FAILURE, 'The file is empty!', File=self.FileName) + self.Profile.FileLinesList[-1].append(' ') + + def _ReplaceFragment(self, StartPos, EndPos, Value = ' '): + if StartPos[0] == EndPos[0]: + Offset = StartPos[1] + while Offset <= EndPos[1]: + self.Profile.FileLinesList[StartPos[0]][Offset] = Value + Offset += 1 + return + + Offset = StartPos[1] + while self.Profile.FileLinesList[StartPos[0]][Offset] not in CR_LB_SET: + self.Profile.FileLinesList[StartPos[0]][Offset] = Value + Offset += 1 + + Line = StartPos[0] + while Line < EndPos[0]: + Offset = 0 + while self.Profile.FileLinesList[Line][Offset] not in CR_LB_SET: + self.Profile.FileLinesList[Line][Offset] = Value + Offset += 1 + Line += 1 + + Offset = 0 + while Offset <= EndPos[1]: + self.Profile.FileLinesList[EndPos[0]][Offset] = Value + Offset += 1 + + def _SetMacroValue(self, Macro, Value): + if not self._CurSection: + return + + MacroDict = {} + if not self._MacroDict[self._CurSection[0], self._CurSection[1], self._CurSection[2]]: + self._MacroDict[self._CurSection[0], self._CurSection[1], self._CurSection[2]] = MacroDict + else: + MacroDict = self._MacroDict[self._CurSection[0], self._CurSection[1], self._CurSection[2]] + MacroDict[Macro] = Value + + def _GetMacroValue(self, Macro): + # Highest priority + if Macro in GlobalData.gCommandLineDefines: + return GlobalData.gCommandLineDefines[Macro] + if Macro in GlobalData.gGlobalDefines: + return GlobalData.gGlobalDefines[Macro] + + if self._CurSection: + MacroDict = self._MacroDict[ + self._CurSection[0], + self._CurSection[1], + self._CurSection[2] + ] + if MacroDict and Macro in MacroDict: + return MacroDict[Macro] + + # Lowest priority + if Macro in GlobalData.gPlatformDefines: + return GlobalData.gPlatformDefines[Macro] + return None + + def _SectionHeaderParser(self, Section): + # [Defines] + # [FD.UiName]: use dummy instead if UI name is optional + # [FV.UiName] + # [Capsule.UiName] + # [Rule]: don't take rule section into account, macro is not allowed in this section + # [OptionRom.DriverName] + self._CurSection = [] + Section = Section.strip()[1:-1].upper().replace(' ', '').strip(TAB_SPLIT) + ItemList = Section.split(TAB_SPLIT) + Item = ItemList[0] + if Item == '' or Item == 'RULE': + return + + if Item == TAB_COMMON_DEFINES.upper(): + self._CurSection = [TAB_COMMON, TAB_COMMON, TAB_COMMON] + elif len(ItemList) > 1: + self._CurSection = [ItemList[0], ItemList[1], TAB_COMMON] + elif len(ItemList) > 0: + self._CurSection = [ItemList[0], 'DUMMY', TAB_COMMON] + + ## PreprocessFile() method + # + # Preprocess file contents, replace comments with spaces. + # In the end, rewind the file buffer pointer to the beginning + # BUGBUG: No !include statement processing contained in this procedure + # !include statement should be expanded at the same FileLinesList[CurrentLineNumber - 1] + # + # @param self The object pointer + # + def PreprocessFile(self): + self.Rewind() + InComment = False + DoubleSlashComment = False + HashComment = False + # HashComment in quoted string " " is ignored. + InString = False + + while not self._EndOfFile(): + + if self._CurrentChar() == T_CHAR_DOUBLE_QUOTE and not InComment: + InString = not InString + # meet new line, then no longer in a comment for // and '#' + if self._CurrentChar() == TAB_LINE_BREAK: + self.CurrentLineNumber += 1 + self.CurrentOffsetWithinLine = 0 + if InComment and DoubleSlashComment: + InComment = False + DoubleSlashComment = False + if InComment and HashComment: + InComment = False + HashComment = False + # check for */ comment end + elif InComment and not DoubleSlashComment and not HashComment and self._CurrentChar() == TAB_STAR and self._NextChar() == TAB_BACK_SLASH: + self._SetCurrentCharValue(TAB_SPACE_SPLIT) + self._GetOneChar() + self._SetCurrentCharValue(TAB_SPACE_SPLIT) + self._GetOneChar() + InComment = False + # set comments to spaces + elif InComment: + self._SetCurrentCharValue(TAB_SPACE_SPLIT) + self._GetOneChar() + # check for // comment + elif self._CurrentChar() == TAB_BACK_SLASH and self._NextChar() == TAB_BACK_SLASH and not self._EndOfLine(): + InComment = True + DoubleSlashComment = True + # check for '#' comment + elif self._CurrentChar() == TAB_COMMENT_SPLIT and not self._EndOfLine() and not InString: + InComment = True + HashComment = True + # check for /* comment start + elif self._CurrentChar() == TAB_BACK_SLASH and self._NextChar() == TAB_STAR: + self._SetCurrentCharValue(TAB_SPACE_SPLIT) + self._GetOneChar() + self._SetCurrentCharValue(TAB_SPACE_SPLIT) + self._GetOneChar() + InComment = True + else: + self._GetOneChar() + + # restore from ListOfList to ListOfString + self.Profile.FileLinesList = ["".join(list) for list in self.Profile.FileLinesList] + self.Rewind() + + ## PreprocessIncludeFile() method + # + # Preprocess file contents, replace !include statements with file contents. + # In the end, rewind the file buffer pointer to the beginning + # + # @param self The object pointer + # + def PreprocessIncludeFile(self): + # nested include support + Processed = False + MacroDict = {} + while self._GetNextToken(): + + if self._Token == TAB_DEFINE: + if not self._GetNextToken(): + raise Warning.Expected("Macro name", self.FileName, self.CurrentLineNumber) + Macro = self._Token + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + Value = self._GetExpression() + MacroDict[Macro] = Value + + elif self._Token == TAB_INCLUDE: + Processed = True + IncludeLine = self.CurrentLineNumber + IncludeOffset = self.CurrentOffsetWithinLine - len(TAB_INCLUDE) + if not self._GetNextToken(): + raise Warning.Expected("include file name", self.FileName, self.CurrentLineNumber) + IncFileName = self._Token + PreIndex = 0 + StartPos = IncFileName.find('$(', PreIndex) + EndPos = IncFileName.find(')', StartPos+2) + while StartPos != -1 and EndPos != -1: + Macro = IncFileName[StartPos+2: EndPos] + MacroVal = self._GetMacroValue(Macro) + if not MacroVal: + if Macro in MacroDict: + MacroVal = MacroDict[Macro] + if MacroVal is not None: + IncFileName = IncFileName.replace('$(' + Macro + ')', MacroVal, 1) + if MacroVal.find('$(') != -1: + PreIndex = StartPos + else: + PreIndex = StartPos + len(MacroVal) + else: + raise Warning("The Macro %s is not defined" %Macro, self.FileName, self.CurrentLineNumber) + StartPos = IncFileName.find('$(', PreIndex) + EndPos = IncFileName.find(')', StartPos+2) + + IncludedFile = NormPath(IncFileName) + # + # First search the include file under the same directory as FDF file + # + IncludedFile1 = PathClass(IncludedFile, os.path.dirname(self.FileName)) + ErrorCode = IncludedFile1.Validate()[0] + if ErrorCode != 0: + # + # Then search the include file under the same directory as DSC file + # + PlatformDir = '' + if GenFdsGlobalVariable.ActivePlatform: + PlatformDir = GenFdsGlobalVariable.ActivePlatform.Dir + elif GlobalData.gActivePlatform: + PlatformDir = GlobalData.gActivePlatform.MetaFile.Dir + IncludedFile1 = PathClass(IncludedFile, PlatformDir) + ErrorCode = IncludedFile1.Validate()[0] + if ErrorCode != 0: + # + # Also search file under the WORKSPACE directory + # + IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace) + ErrorCode = IncludedFile1.Validate()[0] + if ErrorCode != 0: + raise Warning("The include file does not exist under below directories: \n%s\n%s\n%s\n"%(os.path.dirname(self.FileName), PlatformDir, GlobalData.gWorkspace), + self.FileName, self.CurrentLineNumber) + + if not IsValidInclude (IncludedFile1.Path, self.CurrentLineNumber): + raise Warning("The include file {0} is causing a include loop.\n".format (IncludedFile1.Path), self.FileName, self.CurrentLineNumber) + + IncFileProfile = IncludeFileProfile(IncludedFile1.Path) + + CurrentLine = self.CurrentLineNumber + CurrentOffset = self.CurrentOffsetWithinLine + # list index of the insertion, note that line number is 'CurrentLine + 1' + InsertAtLine = CurrentLine + ParentProfile = GetParentAtLine (CurrentLine) + if ParentProfile is not None: + ParentProfile.IncludeFileList.insert(0, IncFileProfile) + IncFileProfile.Level = ParentProfile.Level + 1 + IncFileProfile.InsertStartLineNumber = InsertAtLine + 1 + # deal with remaining portions after "!include filename", if exists. + if self._GetNextToken(): + if self.CurrentLineNumber == CurrentLine: + RemainingLine = self._CurrentLine()[CurrentOffset:] + self.Profile.FileLinesList.insert(self.CurrentLineNumber, RemainingLine) + IncFileProfile.InsertAdjust += 1 + self.CurrentLineNumber += 1 + self.CurrentOffsetWithinLine = 0 + + for Line in IncFileProfile.FileLinesList: + self.Profile.FileLinesList.insert(InsertAtLine, Line) + self.CurrentLineNumber += 1 + InsertAtLine += 1 + + # reversely sorted to better determine error in file + AllIncludeFileList.insert(0, IncFileProfile) + + # comment out the processed include file statement + TempList = list(self.Profile.FileLinesList[IncludeLine - 1]) + TempList.insert(IncludeOffset, TAB_COMMENT_SPLIT) + self.Profile.FileLinesList[IncludeLine - 1] = ''.join(TempList) + if Processed: # Nested and back-to-back support + self.Rewind(DestLine = IncFileProfile.InsertStartLineNumber - 1) + Processed = False + # Preprocess done. + self.Rewind() + + @staticmethod + def _GetIfListCurrentItemStat(IfList): + if len(IfList) == 0: + return True + + for Item in IfList: + if Item[1] == False: + return False + + return True + + ## PreprocessConditionalStatement() method + # + # Preprocess conditional statement. + # In the end, rewind the file buffer pointer to the beginning + # + # @param self The object pointer + # + def PreprocessConditionalStatement(self): + # IfList is a stack of if branches with elements of list [Pos, CondSatisfied, BranchDetermined] + IfList = [] + RegionLayoutLine = 0 + ReplacedLine = -1 + while self._GetNextToken(): + # Determine section name and the location dependent macro + if self._GetIfListCurrentItemStat(IfList): + if self._Token.startswith(TAB_SECTION_START): + Header = self._Token + if not self._Token.endswith(TAB_SECTION_END): + self._SkipToToken(TAB_SECTION_END) + Header += self._SkippedChars + if Header.find('$(') != -1: + raise Warning("macro cannot be used in section header", self.FileName, self.CurrentLineNumber) + self._SectionHeaderParser(Header) + continue + # Replace macros except in RULE section or out of section + elif self._CurSection and ReplacedLine != self.CurrentLineNumber: + ReplacedLine = self.CurrentLineNumber + self._UndoToken() + CurLine = self.Profile.FileLinesList[ReplacedLine - 1] + PreIndex = 0 + StartPos = CurLine.find('$(', PreIndex) + EndPos = CurLine.find(')', StartPos+2) + while StartPos != -1 and EndPos != -1 and self._Token not in {TAB_IF_DEF, TAB_IF_N_DEF, TAB_IF, TAB_ELSE_IF}: + MacroName = CurLine[StartPos+2: EndPos] + MacroValue = self._GetMacroValue(MacroName) + if MacroValue is not None: + CurLine = CurLine.replace('$(' + MacroName + ')', MacroValue, 1) + if MacroValue.find('$(') != -1: + PreIndex = StartPos + else: + PreIndex = StartPos + len(MacroValue) + else: + PreIndex = EndPos + 1 + StartPos = CurLine.find('$(', PreIndex) + EndPos = CurLine.find(')', StartPos+2) + self.Profile.FileLinesList[ReplacedLine - 1] = CurLine + continue + + if self._Token == TAB_DEFINE: + if self._GetIfListCurrentItemStat(IfList): + if not self._CurSection: + raise Warning("macro cannot be defined in Rule section or out of section", self.FileName, self.CurrentLineNumber) + DefineLine = self.CurrentLineNumber - 1 + DefineOffset = self.CurrentOffsetWithinLine - len(TAB_DEFINE) + if not self._GetNextToken(): + raise Warning.Expected("Macro name", self.FileName, self.CurrentLineNumber) + Macro = self._Token + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + Value = self._GetExpression() + self._SetMacroValue(Macro, Value) + self._WipeOffArea.append(((DefineLine, DefineOffset), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + elif self._Token == 'SET': + if not self._GetIfListCurrentItemStat(IfList): + continue + SetLine = self.CurrentLineNumber - 1 + SetOffset = self.CurrentOffsetWithinLine - len('SET') + PcdPair = self._GetNextPcdSettings() + PcdName = "%s.%s" % (PcdPair[1], PcdPair[0]) + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + Value = self._GetExpression() + Value = self._EvaluateConditional(Value, self.CurrentLineNumber, 'eval', True) + + self._PcdDict[PcdName] = Value + + self.Profile.PcdDict[PcdPair] = Value + self.SetPcdLocalation(PcdPair) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[PcdPair] = FileLineTuple + + self._WipeOffArea.append(((SetLine, SetOffset), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + elif self._Token in {TAB_IF_DEF, TAB_IF_N_DEF, TAB_IF}: + IfStartPos = (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len(self._Token)) + IfList.append([IfStartPos, None, None]) + + CondLabel = self._Token + Expression = self._GetExpression() + + if CondLabel == TAB_IF: + ConditionSatisfied = self._EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'eval') + else: + ConditionSatisfied = self._EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'in') + if CondLabel == TAB_IF_N_DEF: + ConditionSatisfied = not ConditionSatisfied + + BranchDetermined = ConditionSatisfied + IfList[-1] = [IfList[-1][0], ConditionSatisfied, BranchDetermined] + if ConditionSatisfied: + self._WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + elif self._Token in {TAB_ELSE_IF, TAB_ELSE}: + ElseStartPos = (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len(self._Token)) + if len(IfList) <= 0: + raise Warning("Missing !if statement", self.FileName, self.CurrentLineNumber) + + if IfList[-1][1]: + IfList[-1] = [ElseStartPos, False, True] + self._WipeOffArea.append((ElseStartPos, (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + else: + self._WipeOffArea.append((IfList[-1][0], ElseStartPos)) + IfList[-1] = [ElseStartPos, True, IfList[-1][2]] + if self._Token == TAB_ELSE_IF: + Expression = self._GetExpression() + ConditionSatisfied = self._EvaluateConditional(Expression, IfList[-1][0][0] + 1, 'eval') + IfList[-1] = [IfList[-1][0], ConditionSatisfied, IfList[-1][2]] + + if IfList[-1][1]: + if IfList[-1][2]: + IfList[-1][1] = False + else: + IfList[-1][2] = True + self._WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + elif self._Token == '!endif': + if len(IfList) <= 0: + raise Warning("Missing !if statement", self.FileName, self.CurrentLineNumber) + if IfList[-1][1]: + self._WipeOffArea.append(((self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - len('!endif')), (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + else: + self._WipeOffArea.append((IfList[-1][0], (self.CurrentLineNumber - 1, self.CurrentOffsetWithinLine - 1))) + + IfList.pop() + elif not IfList: # Don't use PCDs inside conditional directive + if self.CurrentLineNumber <= RegionLayoutLine: + # Don't try the same line twice + continue + SetPcd = ShortcutPcdPattern.match(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) + if SetPcd: + self._PcdDict[SetPcd.group('name')] = SetPcd.group('value') + RegionLayoutLine = self.CurrentLineNumber + continue + RegionSize = RegionSizePattern.match(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) + if not RegionSize: + RegionLayoutLine = self.CurrentLineNumber + continue + RegionSizeGuid = RegionSizeGuidPattern.match(self.Profile.FileLinesList[self.CurrentLineNumber]) + if not RegionSizeGuid: + RegionLayoutLine = self.CurrentLineNumber + 1 + continue + self._PcdDict[RegionSizeGuid.group('base')] = RegionSize.group('base') + self._PcdDict[RegionSizeGuid.group('size')] = RegionSize.group('size') + RegionLayoutLine = self.CurrentLineNumber + 1 + + if IfList: + raise Warning("Missing !endif", self.FileName, self.CurrentLineNumber) + self.Rewind() + + def _CollectMacroPcd(self): + MacroDict = {} + + # PCD macro + MacroDict.update(GlobalData.gPlatformPcds) + MacroDict.update(self._PcdDict) + + # Lowest priority + MacroDict.update(GlobalData.gPlatformDefines) + + if self._CurSection: + # Defines macro + ScopeMacro = self._MacroDict[TAB_COMMON, TAB_COMMON, TAB_COMMON] + if ScopeMacro: + MacroDict.update(ScopeMacro) + + # Section macro + ScopeMacro = self._MacroDict[ + self._CurSection[0], + self._CurSection[1], + self._CurSection[2] + ] + if ScopeMacro: + MacroDict.update(ScopeMacro) + + MacroDict.update(GlobalData.gGlobalDefines) + MacroDict.update(GlobalData.gCommandLineDefines) + for Item in GlobalData.BuildOptionPcd: + if isinstance(Item, tuple): + continue + PcdName, TmpValue = Item.split(TAB_EQUAL_SPLIT) + TmpValue = BuildOptionValue(TmpValue, {}) + MacroDict[PcdName.strip()] = TmpValue + # Highest priority + + return MacroDict + + def _EvaluateConditional(self, Expression, Line, Op = None, Value = None): + MacroPcdDict = self._CollectMacroPcd() + if Op == 'eval': + try: + if Value: + return ValueExpression(Expression, MacroPcdDict)(True) + else: + return ValueExpression(Expression, MacroPcdDict)() + except WrnExpression as Excpt: + # + # Catch expression evaluation warning here. We need to report + # the precise number of line and return the evaluation result + # + EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt), + File=self.FileName, ExtraData=self._CurrentLine(), + Line=Line) + return Excpt.result + except Exception as Excpt: + if hasattr(Excpt, 'Pcd'): + if Excpt.Pcd in GlobalData.gPlatformOtherPcds: + Info = GlobalData.gPlatformOtherPcds[Excpt.Pcd] + raise Warning("Cannot use this PCD (%s) in an expression as" + " it must be defined in a [PcdsFixedAtBuild] or [PcdsFeatureFlag] section" + " of the DSC file (%s), and it is currently defined in this section:" + " %s, line #: %d." % (Excpt.Pcd, GlobalData.gPlatformOtherPcds['DSCFILE'], Info[0], Info[1]), + self.FileName, Line) + else: + raise Warning("PCD (%s) is not defined in DSC file (%s)" % (Excpt.Pcd, GlobalData.gPlatformOtherPcds['DSCFILE']), + self.FileName, Line) + else: + raise Warning(str(Excpt), self.FileName, Line) + else: + if Expression.startswith('$(') and Expression[-1] == ')': + Expression = Expression[2:-1] + return Expression in MacroPcdDict + + ## _IsToken() method + # + # Check whether input string is found from current char position along + # If found, the string value is put into self._Token + # + # @param self The object pointer + # @param String The string to search + # @param IgnoreCase Indicate case sensitive/non-sensitive search, default is case sensitive + # @retval True Successfully find string, file buffer pointer moved forward + # @retval False Not able to find string, file buffer pointer not changed + # + def _IsToken(self, String, IgnoreCase = False): + self._SkipWhiteSpace() + + # Only consider the same line, no multi-line token allowed + StartPos = self.CurrentOffsetWithinLine + index = -1 + if IgnoreCase: + index = self._CurrentLine()[self.CurrentOffsetWithinLine: ].upper().find(String.upper()) + else: + index = self._CurrentLine()[self.CurrentOffsetWithinLine: ].find(String) + if index == 0: + self.CurrentOffsetWithinLine += len(String) + self._Token = self._CurrentLine()[StartPos: self.CurrentOffsetWithinLine] + return True + return False + + ## _IsKeyword() method + # + # Check whether input keyword is found from current char position along, whole word only! + # If found, the string value is put into self._Token + # + # @param self The object pointer + # @param Keyword The string to search + # @param IgnoreCase Indicate case sensitive/non-sensitive search, default is case sensitive + # @retval True Successfully find string, file buffer pointer moved forward + # @retval False Not able to find string, file buffer pointer not changed + # + def _IsKeyword(self, KeyWord, IgnoreCase = False): + self._SkipWhiteSpace() + + # Only consider the same line, no multi-line token allowed + StartPos = self.CurrentOffsetWithinLine + index = -1 + if IgnoreCase: + index = self._CurrentLine()[self.CurrentOffsetWithinLine: ].upper().find(KeyWord.upper()) + else: + index = self._CurrentLine()[self.CurrentOffsetWithinLine: ].find(KeyWord) + if index == 0: + followingChar = self._CurrentLine()[self.CurrentOffsetWithinLine + len(KeyWord)] + if not str(followingChar).isspace() and followingChar not in SEPARATORS: + return False + self.CurrentOffsetWithinLine += len(KeyWord) + self._Token = self._CurrentLine()[StartPos: self.CurrentOffsetWithinLine] + return True + return False + + def _GetExpression(self): + Line = self.Profile.FileLinesList[self.CurrentLineNumber - 1] + Index = len(Line) - 1 + while Line[Index] in CR_LB_SET: + Index -= 1 + ExpressionString = self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:Index+1] + self.CurrentOffsetWithinLine += len(ExpressionString) + ExpressionString = ExpressionString.strip() + return ExpressionString + + ## _GetNextWord() method + # + # Get next C name from file lines + # If found, the string value is put into self._Token + # + # @param self The object pointer + # @retval True Successfully find a C name string, file buffer pointer moved forward + # @retval False Not able to find a C name string, file buffer pointer not changed + # + def _GetNextWord(self): + self._SkipWhiteSpace() + if self._EndOfFile(): + return False + + TempChar = self._CurrentChar() + StartPos = self.CurrentOffsetWithinLine + if (TempChar >= 'a' and TempChar <= 'z') or (TempChar >= 'A' and TempChar <= 'Z') or TempChar == '_': + self._GetOneChar() + while not self._EndOfLine(): + TempChar = self._CurrentChar() + if (TempChar >= 'a' and TempChar <= 'z') or (TempChar >= 'A' and TempChar <= 'Z') \ + or (TempChar >= '0' and TempChar <= '9') or TempChar == '_' or TempChar == '-': + self._GetOneChar() + + else: + break + + self._Token = self._CurrentLine()[StartPos: self.CurrentOffsetWithinLine] + return True + + return False + + def _GetNextPcdWord(self): + self._SkipWhiteSpace() + if self._EndOfFile(): + return False + + TempChar = self._CurrentChar() + StartPos = self.CurrentOffsetWithinLine + if (TempChar >= 'a' and TempChar <= 'z') or (TempChar >= 'A' and TempChar <= 'Z') or TempChar == '_' or TempChar == TAB_SECTION_START or TempChar == TAB_SECTION_END: + self._GetOneChar() + while not self._EndOfLine(): + TempChar = self._CurrentChar() + if (TempChar >= 'a' and TempChar <= 'z') or (TempChar >= 'A' and TempChar <= 'Z') \ + or (TempChar >= '0' and TempChar <= '9') or TempChar == '_' or TempChar == '-' or TempChar == TAB_SECTION_START or TempChar == TAB_SECTION_END: + self._GetOneChar() + + else: + break + + self._Token = self._CurrentLine()[StartPos: self.CurrentOffsetWithinLine] + return True + + return False + + ## _GetNextToken() method + # + # Get next token unit before a separator + # If found, the string value is put into self._Token + # + # @param self The object pointer + # @retval True Successfully find a token unit, file buffer pointer moved forward + # @retval False Not able to find a token unit, file buffer pointer not changed + # + def _GetNextToken(self): + # Skip leading spaces, if exist. + self._SkipWhiteSpace() + if self._EndOfFile(): + return False + # Record the token start position, the position of the first non-space char. + StartPos = self.CurrentOffsetWithinLine + StartLine = self.CurrentLineNumber + while StartLine == self.CurrentLineNumber: + TempChar = self._CurrentChar() + # Try to find the end char that is not a space and not in separator tuple. + # That is, when we got a space or any char in the tuple, we got the end of token. + if not str(TempChar).isspace() and TempChar not in SEPARATORS: + self._GetOneChar() + # if we happen to meet a separator as the first char, we must proceed to get it. + # That is, we get a token that is a separator char. normally it is the boundary of other tokens. + elif StartPos == self.CurrentOffsetWithinLine and TempChar in SEPARATORS: + self._GetOneChar() + break + else: + break +# else: +# return False + + EndPos = self.CurrentOffsetWithinLine + if self.CurrentLineNumber != StartLine: + EndPos = len(self.Profile.FileLinesList[StartLine-1]) + self._Token = self.Profile.FileLinesList[StartLine-1][StartPos: EndPos] + if self._Token.lower() in {TAB_IF, TAB_END_IF, TAB_ELSE_IF, TAB_ELSE, TAB_IF_DEF, TAB_IF_N_DEF, TAB_ERROR, TAB_INCLUDE}: + self._Token = self._Token.lower() + if StartPos != self.CurrentOffsetWithinLine: + return True + else: + return False + + ## _GetNextGuid() method + # + # Get next token unit before a separator + # If found, the GUID string is put into self._Token + # + # @param self The object pointer + # @retval True Successfully find a registry format GUID, file buffer pointer moved forward + # @retval False Not able to find a registry format GUID, file buffer pointer not changed + # + def _GetNextGuid(self): + if not self._GetNextToken(): + return False + if GlobalData.gGuidPattern.match(self._Token) is not None: + return True + elif self._Token in GlobalData.gGuidDict: + return True + else: + self._UndoToken() + return False + + @staticmethod + def _Verify(Name, Value, Scope): + # value verification only applies to numeric values. + if Scope not in TAB_PCD_NUMERIC_TYPES: + return + + ValueNumber = 0 + try: + ValueNumber = int(Value, 0) + except: + EdkLogger.error("FdfParser", FORMAT_INVALID, "The value is not valid dec or hex number for %s." % Name) + if ValueNumber < 0: + EdkLogger.error("FdfParser", FORMAT_INVALID, "The value can't be set to negative value for %s." % Name) + if ValueNumber > MAX_VAL_TYPE[Scope]: + EdkLogger.error("FdfParser", FORMAT_INVALID, "Too large value for %s." % Name) + return True + + ## _UndoToken() method + # + # Go back one token unit in file buffer + # + # @param self The object pointer + # + def _UndoToken(self): + self._UndoOneChar() + while self._CurrentChar().isspace(): + if not self._UndoOneChar(): + self._GetOneChar() + return + + + StartPos = self.CurrentOffsetWithinLine + CurrentLine = self.CurrentLineNumber + while CurrentLine == self.CurrentLineNumber: + + TempChar = self._CurrentChar() + # Try to find the end char that is not a space and not in separator tuple. + # That is, when we got a space or any char in the tuple, we got the end of token. + if not str(TempChar).isspace() and not TempChar in SEPARATORS: + if not self._UndoOneChar(): + return + # if we happen to meet a separator as the first char, we must proceed to get it. + # That is, we get a token that is a separator char. normally it is the boundary of other tokens. + elif StartPos == self.CurrentOffsetWithinLine and TempChar in SEPARATORS: + return + else: + break + + self._GetOneChar() + + ## _GetNextHexNumber() method + # + # Get next HEX data before a separator + # If found, the HEX data is put into self._Token + # + # @param self The object pointer + # @retval True Successfully find a HEX data, file buffer pointer moved forward + # @retval False Not able to find a HEX data, file buffer pointer not changed + # + def _GetNextHexNumber(self): + if not self._GetNextToken(): + return False + if GlobalData.gHexPatternAll.match(self._Token): + return True + else: + self._UndoToken() + return False + + ## _GetNextDecimalNumber() method + # + # Get next decimal data before a separator + # If found, the decimal data is put into self._Token + # + # @param self The object pointer + # @retval True Successfully find a decimal data, file buffer pointer moved forward + # @retval False Not able to find a decimal data, file buffer pointer not changed + # + def _GetNextDecimalNumber(self): + if not self._GetNextToken(): + return False + if self._Token.isdigit(): + return True + else: + self._UndoToken() + return False + + def _GetNextPcdSettings(self): + if not self._GetNextWord(): + raise Warning.Expected("", self.FileName, self.CurrentLineNumber) + pcdTokenSpaceCName = self._Token + + if not self._IsToken(TAB_SPLIT): + raise Warning.Expected(".", self.FileName, self.CurrentLineNumber) + + if not self._GetNextWord(): + raise Warning.Expected("", self.FileName, self.CurrentLineNumber) + pcdCName = self._Token + + Fields = [] + while self._IsToken(TAB_SPLIT): + if not self._GetNextPcdWord(): + raise Warning.Expected("Pcd Fields", self.FileName, self.CurrentLineNumber) + Fields.append(self._Token) + + return (pcdCName, pcdTokenSpaceCName,TAB_SPLIT.join(Fields)) + + ## _GetStringData() method + # + # Get string contents quoted in "" + # If found, the decimal data is put into self._Token + # + # @param self The object pointer + # @retval True Successfully find a string data, file buffer pointer moved forward + # @retval False Not able to find a string data, file buffer pointer not changed + # + def _GetStringData(self): + QuoteToUse = None + if self._Token.startswith(T_CHAR_DOUBLE_QUOTE) or self._Token.startswith("L\""): + QuoteToUse = T_CHAR_DOUBLE_QUOTE + elif self._Token.startswith(T_CHAR_SINGLE_QUOTE) or self._Token.startswith("L\'"): + QuoteToUse = T_CHAR_SINGLE_QUOTE + else: + return False + + self._UndoToken() + self._SkipToToken(QuoteToUse) + currentLineNumber = self.CurrentLineNumber + + if not self._SkipToToken(QuoteToUse): + raise Warning(QuoteToUse, self.FileName, self.CurrentLineNumber) + if currentLineNumber != self.CurrentLineNumber: + raise Warning(QuoteToUse, self.FileName, self.CurrentLineNumber) + self._Token = self._SkippedChars.rstrip(QuoteToUse) + return True + + ## _SkipToToken() method + # + # Search forward in file buffer for the string + # The skipped chars are put into self._SkippedChars + # + # @param self The object pointer + # @param String The string to search + # @param IgnoreCase Indicate case sensitive/non-sensitive search, default is case sensitive + # @retval True Successfully find the string, file buffer pointer moved forward + # @retval False Not able to find the string, file buffer pointer not changed + # + def _SkipToToken(self, String, IgnoreCase = False): + StartPos = self.GetFileBufferPos() + + self._SkippedChars = "" + while not self._EndOfFile(): + index = -1 + if IgnoreCase: + index = self._CurrentLine()[self.CurrentOffsetWithinLine: ].upper().find(String.upper()) + else: + index = self._CurrentLine()[self.CurrentOffsetWithinLine: ].find(String) + if index == 0: + self.CurrentOffsetWithinLine += len(String) + self._SkippedChars += String + return True + self._SkippedChars += str(self._CurrentChar()) + self._GetOneChar() + + self.SetFileBufferPos(StartPos) + self._SkippedChars = "" + return False + + ## GetFileBufferPos() method + # + # Return the tuple of current line and offset within the line + # + # @param self The object pointer + # @retval Tuple Line number and offset pair + # + def GetFileBufferPos(self): + return (self.CurrentLineNumber, self.CurrentOffsetWithinLine) + + ## SetFileBufferPos() method + # + # Restore the file buffer position + # + # @param self The object pointer + # @param Pos The new file buffer position + # + def SetFileBufferPos(self, Pos): + (self.CurrentLineNumber, self.CurrentOffsetWithinLine) = Pos + + ## Preprocess() method + # + # Preprocess comment, conditional directive, include directive, replace macro. + # Exception will be raised if syntax error found + # + # @param self The object pointer + # + def Preprocess(self): + self._StringToList() + self.PreprocessFile() + self.PreprocessIncludeFile() + self._StringToList() + self.PreprocessFile() + self.PreprocessConditionalStatement() + self._StringToList() + for Pos in self._WipeOffArea: + self._ReplaceFragment(Pos[0], Pos[1]) + self.Profile.FileLinesList = ["".join(list) for list in self.Profile.FileLinesList] + + while self._GetDefines(): + pass + + ## ParseFile() method + # + # Parse the file profile buffer to extract fd, fv ... information + # Exception will be raised if syntax error found + # + # @param self The object pointer + # + def ParseFile(self): + try: + self.Preprocess() + self._GetError() + # + # Keep processing sections of the FDF until no new sections or a syntax error is found + # + while self._GetFd() or self._GetFv() or self._GetFmp() or self._GetCapsule() or self._GetRule() or self._GetOptionRom(): + pass + + except Warning as X: + self._UndoToken() + #'\n\tGot Token: \"%s\" from File %s\n' % (self._Token, FileLineTuple[0]) + \ + # At this point, the closest parent would be the included file itself + Profile = GetParentAtLine(X.OriginalLineNumber) + if Profile is not None: + X.Message += ' near line %d, column %d: %s' \ + % (X.LineNumber, 0, Profile.FileLinesList[X.LineNumber-1]) + else: + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + X.Message += ' near line %d, column %d: %s' \ + % (FileLineTuple[1], self.CurrentOffsetWithinLine + 1, self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:].rstrip(TAB_LINE_BREAK).rstrip(T_CHAR_CR)) + raise + + ## SectionParser() method + # + # Parse the file section info + # Exception will be raised if syntax error found + # + # @param self The object pointer + # @param section The section string + + def SectionParser(self, section): + S = section.upper() + if not S.startswith("[DEFINES") and not S.startswith("[FD.") and not S.startswith("[FV.") and not S.startswith("[CAPSULE.") \ + and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM.") and not S.startswith('[FMPPAYLOAD.'): + raise Warning("Unknown section or section appear sequence error (The correct sequence should be [DEFINES], [FD.], [FV.], [Capsule.], [Rule.], [OptionRom.], [FMPPAYLOAD.])", self.FileName, self.CurrentLineNumber) + + ## _GetDefines() method + # + # Get Defines section contents and store its data into AllMacrosList + # + # @param self The object pointer + # @retval True Successfully find a Defines + # @retval False Not able to find a Defines + # + def _GetDefines(self): + if not self._GetNextToken(): + return False + + S = self._Token.upper() + if S.startswith(TAB_SECTION_START) and not S.startswith("[DEFINES"): + self.SectionParser(S) + self._UndoToken() + return False + + self._UndoToken() + if not self._IsToken("[DEFINES", True): + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + #print 'Parsing String: %s in File %s, At line: %d, Offset Within Line: %d' \ + # % (self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:], FileLineTuple[0], FileLineTuple[1], self.CurrentOffsetWithinLine) + raise Warning.Expected("[DEFINES", self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_SECTION_END): + raise Warning.ExpectedBracketClose(self.FileName, self.CurrentLineNumber) + + while self._GetNextWord(): + # handle the SET statement + if self._Token == 'SET': + self._UndoToken() + self._GetSetStatement(None) + continue + + Macro = self._Token + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken() or self._Token.startswith(TAB_SECTION_START): + raise Warning.Expected("MACRO value", self.FileName, self.CurrentLineNumber) + Value = self._Token + + return False + + ##_GetError() method + def _GetError(self): + #save the Current information + CurrentLine = self.CurrentLineNumber + CurrentOffset = self.CurrentOffsetWithinLine + while self._GetNextToken(): + if self._Token == TAB_ERROR: + EdkLogger.error('FdfParser', ERROR_STATEMENT, self._CurrentLine().replace(TAB_ERROR, '', 1), File=self.FileName, Line=self.CurrentLineNumber) + self.CurrentLineNumber = CurrentLine + self.CurrentOffsetWithinLine = CurrentOffset + + ## _GetFd() method + # + # Get FD section contents and store its data into FD dictionary of self.Profile + # + # @param self The object pointer + # @retval True Successfully find a FD + # @retval False Not able to find a FD + # + def _GetFd(self): + if not self._GetNextToken(): + return False + + S = self._Token.upper() + if S.startswith(TAB_SECTION_START) and not S.startswith("[FD."): + if not S.startswith("[FV.") and not S.startswith('[FMPPAYLOAD.') and not S.startswith("[CAPSULE.") \ + and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."): + raise Warning("Unknown section", self.FileName, self.CurrentLineNumber) + self._UndoToken() + return False + + self._UndoToken() + if not self._IsToken("[FD.", True): + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + #print 'Parsing String: %s in File %s, At line: %d, Offset Within Line: %d' \ + # % (self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:], FileLineTuple[0], FileLineTuple[1], self.CurrentOffsetWithinLine) + raise Warning.Expected("[FD.]", self.FileName, self.CurrentLineNumber) + + FdName = self._GetUiName() + if FdName == "": + if len (self.Profile.FdDict) == 0: + FdName = GenFdsGlobalVariable.PlatformName + if FdName == "" and GlobalData.gActivePlatform: + FdName = GlobalData.gActivePlatform.PlatformName + self.Profile.FdNameNotSet = True + else: + raise Warning.Expected("FdName in [FD.] section", self.FileName, self.CurrentLineNumber) + self.CurrentFdName = FdName.upper() + + if self.CurrentFdName in self.Profile.FdDict: + raise Warning("Unexpected the same FD name", self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_SECTION_END): + raise Warning.ExpectedBracketClose(self.FileName, self.CurrentLineNumber) + + FdObj = FD() + FdObj.FdUiName = self.CurrentFdName + self.Profile.FdDict[self.CurrentFdName] = FdObj + + if len (self.Profile.FdDict) > 1 and self.Profile.FdNameNotSet: + raise Warning.Expected("all FDs have their name", self.FileName, self.CurrentLineNumber) + + Status = self._GetCreateFile(FdObj) + if not Status: + raise Warning("FD name error", self.FileName, self.CurrentLineNumber) + + while self._GetTokenStatements(FdObj): + pass + for Attr in ("BaseAddress", "Size", "ErasePolarity"): + if getattr(FdObj, Attr) is None: + self._GetNextToken() + raise Warning("Keyword %s missing" % Attr, self.FileName, self.CurrentLineNumber) + + if not FdObj.BlockSizeList: + FdObj.BlockSizeList.append((1, FdObj.Size, None)) + + self._GetDefineStatements(FdObj) + + self._GetSetStatements(FdObj) + + if not self._GetRegionLayout(FdObj): + raise Warning.Expected("region layout", self.FileName, self.CurrentLineNumber) + + while self._GetRegionLayout(FdObj): + pass + return True + + ## _GetUiName() method + # + # Return the UI name of a section + # + # @param self The object pointer + # @retval FdName UI name + # + def _GetUiName(self): + Name = "" + if self._GetNextWord(): + Name = self._Token + + return Name + + ## _GetCreateFile() method + # + # Return the output file name of object + # + # @param self The object pointer + # @param Obj object whose data will be stored in file + # @retval FdName UI name + # + def _GetCreateFile(self, Obj): + if self._IsKeyword("CREATE_FILE"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("file name", self.FileName, self.CurrentLineNumber) + + FileName = self._Token + Obj.CreateFileName = FileName + + return True + + def SetPcdLocalation(self,pcdpair): + self.Profile.PcdLocalDict[pcdpair] = (self.Profile.FileName,self.CurrentLineNumber) + + ## _GetTokenStatements() method + # + # Get token statements + # + # @param self The object pointer + # @param Obj for whom token statement is got + # + def _GetTokenStatements(self, Obj): + if self._IsKeyword("BaseAddress"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextHexNumber(): + raise Warning.Expected("Hex base address", self.FileName, self.CurrentLineNumber) + + Obj.BaseAddress = self._Token + + if self._IsToken(TAB_VALUE_SPLIT): + pcdPair = self._GetNextPcdSettings() + Obj.BaseAddressPcd = pcdPair + self.Profile.PcdDict[pcdPair] = Obj.BaseAddress + self.SetPcdLocalation(pcdPair) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[pcdPair] = FileLineTuple + return True + + if self._IsKeyword("Size"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextHexNumber(): + raise Warning.Expected("Hex size", self.FileName, self.CurrentLineNumber) + + Size = self._Token + if self._IsToken(TAB_VALUE_SPLIT): + pcdPair = self._GetNextPcdSettings() + Obj.SizePcd = pcdPair + self.Profile.PcdDict[pcdPair] = Size + self.SetPcdLocalation(pcdPair) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[pcdPair] = FileLineTuple + Obj.Size = int(Size, 0) + return True + + if self._IsKeyword("ErasePolarity"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("Erase Polarity", self.FileName, self.CurrentLineNumber) + + if not self._Token in {"1", "0"}: + raise Warning.Expected("1 or 0 Erase Polarity", self.FileName, self.CurrentLineNumber) + + Obj.ErasePolarity = self._Token + return True + + return self._GetBlockStatements(Obj) + + ## _GetAddressStatements() method + # + # Get address statements + # + # @param self The object pointer + # @param Obj for whom address statement is got + # @retval True Successfully find + # @retval False Not able to find + # + def _GetAddressStatements(self, Obj): + if self._IsKeyword("BsBaseAddress"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextDecimalNumber() and not self._GetNextHexNumber(): + raise Warning.Expected("address", self.FileName, self.CurrentLineNumber) + + BsAddress = int(self._Token, 0) + Obj.BsBaseAddress = BsAddress + + if self._IsKeyword("RtBaseAddress"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextDecimalNumber() and not self._GetNextHexNumber(): + raise Warning.Expected("address", self.FileName, self.CurrentLineNumber) + + RtAddress = int(self._Token, 0) + Obj.RtBaseAddress = RtAddress + + ## _GetBlockStatements() method + # + # Get block statements + # + # @param self The object pointer + # @param Obj for whom block statement is got + # + def _GetBlockStatements(self, Obj): + IsBlock = False + while self._GetBlockStatement(Obj): + IsBlock = True + + Item = Obj.BlockSizeList[-1] + if Item[0] is None or Item[1] is None: + raise Warning.Expected("block statement", self.FileName, self.CurrentLineNumber) + return IsBlock + + ## _GetBlockStatement() method + # + # Get block statement + # + # @param self The object pointer + # @param Obj for whom block statement is got + # @retval True Successfully find + # @retval False Not able to find + # + def _GetBlockStatement(self, Obj): + if not self._IsKeyword("BlockSize"): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextHexNumber() and not self._GetNextDecimalNumber(): + raise Warning.Expected("Hex or Integer block size", self.FileName, self.CurrentLineNumber) + + BlockSize = self._Token + BlockSizePcd = None + if self._IsToken(TAB_VALUE_SPLIT): + PcdPair = self._GetNextPcdSettings() + BlockSizePcd = PcdPair + self.Profile.PcdDict[PcdPair] = BlockSize + self.SetPcdLocalation(PcdPair) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[PcdPair] = FileLineTuple + BlockSize = int(BlockSize, 0) + + BlockNumber = None + if self._IsKeyword("NumBlocks"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextDecimalNumber() and not self._GetNextHexNumber(): + raise Warning.Expected("block numbers", self.FileName, self.CurrentLineNumber) + + BlockNumber = int(self._Token, 0) + + Obj.BlockSizeList.append((BlockSize, BlockNumber, BlockSizePcd)) + return True + + ## _GetDefineStatements() method + # + # Get define statements + # + # @param self The object pointer + # @param Obj for whom define statement is got + # @retval True Successfully find + # @retval False Not able to find + # + def _GetDefineStatements(self, Obj): + while self._GetDefineStatement(Obj): + pass + + ## _GetDefineStatement() method + # + # Get define statement + # + # @param self The object pointer + # @param Obj for whom define statement is got + # @retval True Successfully find + # @retval False Not able to find + # + def _GetDefineStatement(self, Obj): + if self._IsKeyword(TAB_DEFINE): + self._GetNextToken() + Macro = self._Token + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("value", self.FileName, self.CurrentLineNumber) + + Value = self._Token + Macro = '$(' + Macro + ')' + Obj.DefineVarDict[Macro] = Value + return True + + return False + + ## _GetSetStatements() method + # + # Get set statements + # + # @param self The object pointer + # @param Obj for whom set statement is got + # @retval True Successfully find + # @retval False Not able to find + # + def _GetSetStatements(self, Obj): + while self._GetSetStatement(Obj): + pass + + ## _GetSetStatement() method + # + # Get set statement + # + # @param self The object pointer + # @param Obj for whom set statement is got + # @retval True Successfully find + # @retval False Not able to find + # + def _GetSetStatement(self, Obj): + if self._IsKeyword("SET"): + PcdPair = self._GetNextPcdSettings() + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + Value = self._GetExpression() + Value = self._EvaluateConditional(Value, self.CurrentLineNumber, 'eval', True) + + if Obj: + Obj.SetVarDict[PcdPair] = Value + self.Profile.PcdDict[PcdPair] = Value + self.SetPcdLocalation(PcdPair) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[PcdPair] = FileLineTuple + return True + + return False + + ## _CalcRegionExpr(self) + # + # Calculate expression for offset or size of a region + # + # @return: None if invalid expression + # Calculated number if successfully + # + def _CalcRegionExpr(self): + StartPos = self.GetFileBufferPos() + Expr = '' + PairCount = 0 + while not self._EndOfFile(): + CurCh = self._CurrentChar() + if CurCh == '(': + PairCount += 1 + elif CurCh == ')': + PairCount -= 1 + + if CurCh in '|\r\n' and PairCount == 0: + break + Expr += CurCh + self._GetOneChar() + try: + return int( + ValueExpression(Expr, + self._CollectMacroPcd() + )(True), 0) + except Exception: + self.SetFileBufferPos(StartPos) + return None + + ## _GetRegionLayout() method + # + # Get region layout for FD + # + # @param self The object pointer + # @param theFd for whom region is got + # @retval True Successfully find + # @retval False Not able to find + # + def _GetRegionLayout(self, theFd): + Offset = self._CalcRegionExpr() + if Offset is None: + return False + + RegionObj = Region() + RegionObj.Offset = Offset + theFd.RegionList.append(RegionObj) + + if not self._IsToken(TAB_VALUE_SPLIT): + raise Warning.Expected("'|'", self.FileName, self.CurrentLineNumber) + + Size = self._CalcRegionExpr() + if Size is None: + raise Warning.Expected("Region Size", self.FileName, self.CurrentLineNumber) + RegionObj.Size = Size + + if not self._GetNextWord(): + return True + + if not self._Token in {"SET", BINARY_FILE_TYPE_FV, "FILE", "DATA", "CAPSULE", "INF"}: + # + # If next token is a word which is not a valid FV type, it might be part of [PcdOffset[|PcdSize]] + # Or it might be next region's offset described by an expression which starts with a PCD. + # PcdOffset[|PcdSize] or OffsetPcdExpression|Size + # + self._UndoToken() + IsRegionPcd = (RegionSizeGuidPattern.match(self._CurrentLine()[self.CurrentOffsetWithinLine:]) or + RegionOffsetPcdPattern.match(self._CurrentLine()[self.CurrentOffsetWithinLine:])) + if IsRegionPcd: + RegionObj.PcdOffset = self._GetNextPcdSettings() + self.Profile.PcdDict[RegionObj.PcdOffset] = "0x%08X" % (RegionObj.Offset + int(theFd.BaseAddress, 0)) + self.SetPcdLocalation(RegionObj.PcdOffset) + self._PcdDict['%s.%s' % (RegionObj.PcdOffset[1], RegionObj.PcdOffset[0])] = "0x%x" % RegionObj.Offset + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[RegionObj.PcdOffset] = FileLineTuple + if self._IsToken(TAB_VALUE_SPLIT): + RegionObj.PcdSize = self._GetNextPcdSettings() + self.Profile.PcdDict[RegionObj.PcdSize] = "0x%08X" % RegionObj.Size + self.SetPcdLocalation(RegionObj.PcdSize) + self._PcdDict['%s.%s' % (RegionObj.PcdSize[1], RegionObj.PcdSize[0])] = "0x%x" % RegionObj.Size + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.PcdFileLineDict[RegionObj.PcdSize] = FileLineTuple + + if not self._GetNextWord(): + return True + + if self._Token == "SET": + self._UndoToken() + self._GetSetStatements(RegionObj) + if not self._GetNextWord(): + return True + + elif self._Token == BINARY_FILE_TYPE_FV: + self._UndoToken() + self._GetRegionFvType(RegionObj) + + elif self._Token == "CAPSULE": + self._UndoToken() + self._GetRegionCapType(RegionObj) + + elif self._Token == "FILE": + self._UndoToken() + self._GetRegionFileType(RegionObj) + + elif self._Token == "INF": + self._UndoToken() + RegionObj.RegionType = "INF" + while self._IsKeyword("INF"): + self._UndoToken() + ffsInf = self._ParseInfStatement() + if not ffsInf: + break + RegionObj.RegionDataList.append(ffsInf) + + elif self._Token == "DATA": + self._UndoToken() + self._GetRegionDataType(RegionObj) + else: + self._UndoToken() + if self._GetRegionLayout(theFd): + return True + raise Warning("A valid region type was not found. " + "Valid types are [SET, FV, CAPSULE, FILE, DATA, INF]. This error occurred", + self.FileName, self.CurrentLineNumber) + + return True + + ## _GetRegionFvType() method + # + # Get region fv data for region + # + # @param self The object pointer + # @param RegionObj for whom region data is got + # + def _GetRegionFvType(self, RegionObj): + if not self._IsKeyword(BINARY_FILE_TYPE_FV): + raise Warning.Expected("'FV'", self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("FV name", self.FileName, self.CurrentLineNumber) + + RegionObj.RegionType = BINARY_FILE_TYPE_FV + RegionObj.RegionDataList.append((self._Token).upper()) + + while self._IsKeyword(BINARY_FILE_TYPE_FV): + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("FV name", self.FileName, self.CurrentLineNumber) + + RegionObj.RegionDataList.append((self._Token).upper()) + + ## _GetRegionCapType() method + # + # Get region capsule data for region + # + # @param self The object pointer + # @param RegionObj for whom region data is got + # + def _GetRegionCapType(self, RegionObj): + if not self._IsKeyword("CAPSULE"): + raise Warning.Expected("'CAPSULE'", self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("CAPSULE name", self.FileName, self.CurrentLineNumber) + + RegionObj.RegionType = "CAPSULE" + RegionObj.RegionDataList.append(self._Token) + + while self._IsKeyword("CAPSULE"): + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("CAPSULE name", self.FileName, self.CurrentLineNumber) + + RegionObj.RegionDataList.append(self._Token) + + ## _GetRegionFileType() method + # + # Get region file data for region + # + # @param self The object pointer + # @param RegionObj for whom region data is got + # + def _GetRegionFileType(self, RegionObj): + if not self._IsKeyword("FILE"): + raise Warning.Expected("'FILE'", self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("File name", self.FileName, self.CurrentLineNumber) + + RegionObj.RegionType = "FILE" + RegionObj.RegionDataList.append(self._Token) + + while self._IsKeyword("FILE"): + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("FILE name", self.FileName, self.CurrentLineNumber) + + RegionObj.RegionDataList.append(self._Token) + + ## _GetRegionDataType() method + # + # Get region array data for region + # + # @param self The object pointer + # @param RegionObj for whom region data is got + # + def _GetRegionDataType(self, RegionObj): + if not self._IsKeyword("DATA"): + raise Warning.Expected("Region Data type", self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + + if not self._GetNextHexNumber(): + raise Warning.Expected("Hex byte", self.FileName, self.CurrentLineNumber) + + if len(self._Token) > 18: + raise Warning("Hex string can't be converted to a valid UINT64 value", self.FileName, self.CurrentLineNumber) + + # convert hex string value to byte hex string array + AllString = self._Token + AllStrLen = len (AllString) + DataString = "" + while AllStrLen > 4: + DataString = DataString + "0x" + AllString[AllStrLen - 2: AllStrLen] + TAB_COMMA_SPLIT + AllStrLen = AllStrLen - 2 + DataString = DataString + AllString[:AllStrLen] + TAB_COMMA_SPLIT + + # byte value array + if len (self._Token) <= 4: + while self._IsToken(TAB_COMMA_SPLIT): + if not self._GetNextHexNumber(): + raise Warning("Invalid Hex number", self.FileName, self.CurrentLineNumber) + if len(self._Token) > 4: + raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + DataString += self._Token + DataString += TAB_COMMA_SPLIT + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + DataString = DataString.rstrip(TAB_COMMA_SPLIT) + RegionObj.RegionType = "DATA" + RegionObj.RegionDataList.append(DataString) + + while self._IsKeyword("DATA"): + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + + if not self._GetNextHexNumber(): + raise Warning.Expected("Hex byte", self.FileName, self.CurrentLineNumber) + + if len(self._Token) > 18: + raise Warning("Hex string can't be converted to a valid UINT64 value", self.FileName, self.CurrentLineNumber) + + # convert hex string value to byte hex string array + AllString = self._Token + AllStrLen = len (AllString) + DataString = "" + while AllStrLen > 4: + DataString = DataString + "0x" + AllString[AllStrLen - 2: AllStrLen] + TAB_COMMA_SPLIT + AllStrLen = AllStrLen - 2 + DataString = DataString + AllString[:AllStrLen] + TAB_COMMA_SPLIT + + # byte value array + if len (self._Token) <= 4: + while self._IsToken(TAB_COMMA_SPLIT): + if not self._GetNextHexNumber(): + raise Warning("Invalid Hex number", self.FileName, self.CurrentLineNumber) + if len(self._Token) > 4: + raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + DataString += self._Token + DataString += TAB_COMMA_SPLIT + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + DataString = DataString.rstrip(TAB_COMMA_SPLIT) + RegionObj.RegionDataList.append(DataString) + + ## _GetFv() method + # + # Get FV section contents and store its data into FV dictionary of self.Profile + # + # @param self The object pointer + # @retval True Successfully find a FV + # @retval False Not able to find a FV + # + def _GetFv(self): + if not self._GetNextToken(): + return False + + S = self._Token.upper() + if S.startswith(TAB_SECTION_START) and not S.startswith("[FV."): + self.SectionParser(S) + self._UndoToken() + return False + + self._UndoToken() + if not self._IsToken("[FV.", True): + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + #print 'Parsing String: %s in File %s, At line: %d, Offset Within Line: %d' \ + # % (self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:], FileLineTuple[0], FileLineTuple[1], self.CurrentOffsetWithinLine) + raise Warning("Unknown Keyword '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + + FvName = self._GetUiName() + self.CurrentFvName = FvName.upper() + + if not self._IsToken(TAB_SECTION_END): + raise Warning.ExpectedBracketClose(self.FileName, self.CurrentLineNumber) + + FvObj = FV(Name=self.CurrentFvName) + self.Profile.FvDict[self.CurrentFvName] = FvObj + + Status = self._GetCreateFile(FvObj) + if not Status: + raise Warning("FV name error", self.FileName, self.CurrentLineNumber) + + self._GetDefineStatements(FvObj) + + self._GetAddressStatements(FvObj) + + while True: + self._GetSetStatements(FvObj) + + if not (self._GetBlockStatement(FvObj) or self._GetFvBaseAddress(FvObj) or + self._GetFvForceRebase(FvObj) or self._GetFvAlignment(FvObj) or + self._GetFvAttributes(FvObj) or self._GetFvNameGuid(FvObj) or + self._GetFvExtEntryStatement(FvObj) or self._GetFvNameString(FvObj)): + break + + if FvObj.FvNameString == 'TRUE' and not FvObj.FvNameGuid: + raise Warning("FvNameString found but FvNameGuid was not found", self.FileName, self.CurrentLineNumber) + + self._GetAprioriSection(FvObj) + self._GetAprioriSection(FvObj) + + while True: + isInf = self._GetInfStatement(FvObj) + isFile = self._GetFileStatement(FvObj) + if not isInf and not isFile: + break + + return True + + ## _GetFvAlignment() method + # + # Get alignment for FV + # + # @param self The object pointer + # @param Obj for whom alignment is got + # @retval True Successfully find a alignment statement + # @retval False Not able to find a alignment statement + # + def _GetFvAlignment(self, Obj): + if not self._IsKeyword("FvAlignment"): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("alignment value", self.FileName, self.CurrentLineNumber) + + if self._Token.upper() not in {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", \ + "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K", \ + "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M", \ + "1G", "2G"}: + raise Warning("Unknown alignment value '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + Obj.FvAlignment = self._Token + return True + + ## _GetFvBaseAddress() method + # + # Get BaseAddress for FV + # + # @param self The object pointer + # @param Obj for whom FvBaseAddress is got + # @retval True Successfully find a FvBaseAddress statement + # @retval False Not able to find a FvBaseAddress statement + # + def _GetFvBaseAddress(self, Obj): + if not self._IsKeyword("FvBaseAddress"): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("FV base address value", self.FileName, self.CurrentLineNumber) + + if not BaseAddrValuePattern.match(self._Token.upper()): + raise Warning("Unknown FV base address value '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + Obj.FvBaseAddress = self._Token + return True + + ## _GetFvForceRebase() method + # + # Get FvForceRebase for FV + # + # @param self The object pointer + # @param Obj for whom FvForceRebase is got + # @retval True Successfully find a FvForceRebase statement + # @retval False Not able to find a FvForceRebase statement + # + def _GetFvForceRebase(self, Obj): + if not self._IsKeyword("FvForceRebase"): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("FvForceRebase value", self.FileName, self.CurrentLineNumber) + + if self._Token.upper() not in {"TRUE", "FALSE", "0", "0X0", "0X00", "1", "0X1", "0X01"}: + raise Warning("Unknown FvForceRebase value '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + + if self._Token.upper() in {"TRUE", "1", "0X1", "0X01"}: + Obj.FvForceRebase = True + elif self._Token.upper() in {"FALSE", "0", "0X0", "0X00"}: + Obj.FvForceRebase = False + else: + Obj.FvForceRebase = None + + return True + + + ## _GetFvAttributes() method + # + # Get attributes for FV + # + # @param self The object pointer + # @param Obj for whom attribute is got + # @retval None + # + def _GetFvAttributes(self, FvObj): + IsWordToken = False + while self._GetNextWord(): + IsWordToken = True + name = self._Token + if name not in {"ERASE_POLARITY", "MEMORY_MAPPED", \ + "STICKY_WRITE", "LOCK_CAP", "LOCK_STATUS", "WRITE_ENABLED_CAP", \ + "WRITE_DISABLED_CAP", "WRITE_STATUS", "READ_ENABLED_CAP", \ + "READ_DISABLED_CAP", "READ_STATUS", "READ_LOCK_CAP", \ + "READ_LOCK_STATUS", "WRITE_LOCK_CAP", "WRITE_LOCK_STATUS", \ + "WRITE_POLICY_RELIABLE", "WEAK_ALIGNMENT", "FvUsedSizeEnable"}: + self._UndoToken() + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken() or self._Token.upper() not in {"TRUE", "FALSE", "1", "0"}: + raise Warning.Expected("TRUE/FALSE (1/0)", self.FileName, self.CurrentLineNumber) + + FvObj.FvAttributeDict[name] = self._Token + + return IsWordToken + + ## _GetFvNameGuid() method + # + # Get FV GUID for FV + # + # @param self The object pointer + # @param Obj for whom GUID is got + # @retval None + # + def _GetFvNameGuid(self, FvObj): + if not self._IsKeyword("FvNameGuid"): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextGuid(): + raise Warning.Expected("GUID value", self.FileName, self.CurrentLineNumber) + if self._Token in GlobalData.gGuidDict: + self._Token = GuidStructureStringToGuidString(GlobalData.gGuidDict[self._Token]).upper() + + FvObj.FvNameGuid = self._Token + + return True + + def _GetFvNameString(self, FvObj): + if not self._IsKeyword("FvNameString"): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken() or self._Token.upper() not in {'TRUE', 'FALSE'}: + raise Warning.Expected("TRUE or FALSE for FvNameString", self.FileName, self.CurrentLineNumber) + + FvObj.FvNameString = self._Token + + return True + + def _GetFvExtEntryStatement(self, FvObj): + if not (self._IsKeyword("FV_EXT_ENTRY") or self._IsKeyword("FV_EXT_ENTRY_TYPE")): + return False + + if not self._IsKeyword ("TYPE"): + raise Warning.Expected("'TYPE'", self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextHexNumber() and not self._GetNextDecimalNumber(): + raise Warning.Expected("Hex FV extension entry type value At Line ", self.FileName, self.CurrentLineNumber) + + FvObj.FvExtEntryTypeValue.append(self._Token) + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + + if not self._IsKeyword("FILE") and not self._IsKeyword("DATA"): + raise Warning.Expected("'FILE' or 'DATA'", self.FileName, self.CurrentLineNumber) + + FvObj.FvExtEntryType.append(self._Token) + + if self._Token == 'DATA': + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + + if not self._GetNextHexNumber(): + raise Warning.Expected("Hex byte", self.FileName, self.CurrentLineNumber) + + if len(self._Token) > 4: + raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + + DataString = self._Token + DataString += TAB_COMMA_SPLIT + + while self._IsToken(TAB_COMMA_SPLIT): + if not self._GetNextHexNumber(): + raise Warning("Invalid Hex number", self.FileName, self.CurrentLineNumber) + if len(self._Token) > 4: + raise Warning("Hex byte(must be 2 digits) too long", self.FileName, self.CurrentLineNumber) + DataString += self._Token + DataString += TAB_COMMA_SPLIT + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + DataString = DataString.rstrip(TAB_COMMA_SPLIT) + FvObj.FvExtEntryData.append(DataString) + + if self._Token == 'FILE': + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("FV Extension Entry file path At Line ", self.FileName, self.CurrentLineNumber) + + FvObj.FvExtEntryData.append(self._Token) + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + return True + + ## _GetAprioriSection() method + # + # Get token statements + # + # @param self The object pointer + # @param FvObj for whom apriori is got + # @retval True Successfully find apriori statement + # @retval False Not able to find apriori statement + # + def _GetAprioriSection(self, FvObj): + if not self._IsKeyword("APRIORI"): + return False + + if not self._IsKeyword("PEI") and not self._IsKeyword("DXE"): + raise Warning.Expected("Apriori file type", self.FileName, self.CurrentLineNumber) + AprType = self._Token + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + + AprSectionObj = AprioriSection() + AprSectionObj.AprioriType = AprType + + self._GetDefineStatements(AprSectionObj) + + while True: + IsInf = self._GetInfStatement(AprSectionObj) + IsFile = self._GetFileStatement(AprSectionObj) + if not IsInf and not IsFile: + break + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + FvObj.AprioriSectionList.append(AprSectionObj) + return True + + def _ParseInfStatement(self): + if not self._IsKeyword("INF"): + return None + + ffsInf = FfsInfStatement() + self._GetInfOptions(ffsInf) + + if not self._GetNextToken(): + raise Warning.Expected("INF file path", self.FileName, self.CurrentLineNumber) + ffsInf.InfFileName = self._Token + if not ffsInf.InfFileName.endswith('.inf'): + raise Warning.Expected(".inf file path", self.FileName, self.CurrentLineNumber) + + ffsInf.CurrentLineNum = self.CurrentLineNumber + ffsInf.CurrentLineContent = self._CurrentLine() + + #Replace $(SAPCE) with real space + ffsInf.InfFileName = ffsInf.InfFileName.replace('$(SPACE)', ' ') + + if ffsInf.InfFileName.replace(TAB_WORKSPACE, '').find('$') == -1: + #do case sensitive check for file path + ErrorCode, ErrorInfo = PathClass(NormPath(ffsInf.InfFileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + + NewFileName = ffsInf.InfFileName + if ffsInf.OverrideGuid: + NewFileName = ProcessDuplicatedInf(PathClass(ffsInf.InfFileName,GenFdsGlobalVariable.WorkSpaceDir), ffsInf.OverrideGuid, GenFdsGlobalVariable.WorkSpaceDir).Path + + if not NewFileName in self.Profile.InfList: + self.Profile.InfList.append(NewFileName) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.InfFileLineList.append(FileLineTuple) + if ffsInf.UseArch: + if ffsInf.UseArch not in self.Profile.InfDict: + self.Profile.InfDict[ffsInf.UseArch] = [ffsInf.InfFileName] + else: + self.Profile.InfDict[ffsInf.UseArch].append(ffsInf.InfFileName) + else: + self.Profile.InfDict['ArchTBD'].append(ffsInf.InfFileName) + + if self._IsToken(TAB_VALUE_SPLIT): + if self._IsKeyword('RELOCS_STRIPPED'): + ffsInf.KeepReloc = False + elif self._IsKeyword('RELOCS_RETAINED'): + ffsInf.KeepReloc = True + else: + raise Warning("Unknown reloc strip flag '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + return ffsInf + + ## _GetInfStatement() method + # + # Get INF statements + # + # @param self The object pointer + # @param Obj for whom inf statement is got + # @retval True Successfully find inf statement + # @retval False Not able to find inf statement + # + def _GetInfStatement(self, Obj, ForCapsule=False): + ffsInf = self._ParseInfStatement() + if not ffsInf: + return False + + if ForCapsule: + myCapsuleFfs = CapsuleFfs() + myCapsuleFfs.Ffs = ffsInf + Obj.CapsuleDataList.append(myCapsuleFfs) + else: + Obj.FfsList.append(ffsInf) + return True + + ## _GetInfOptions() method + # + # Get options for INF + # + # @param self The object pointer + # @param FfsInfObj for whom option is got + # + def _GetInfOptions(self, FfsInfObj): + if self._IsKeyword("FILE_GUID"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextGuid(): + raise Warning.Expected("GUID value", self.FileName, self.CurrentLineNumber) + if self._Token in GlobalData.gGuidDict: + self._Token = GuidStructureStringToGuidString(GlobalData.gGuidDict[self._Token]).upper() + FfsInfObj.OverrideGuid = self._Token + + if self._IsKeyword("RuleOverride"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("Rule name", self.FileName, self.CurrentLineNumber) + FfsInfObj.Rule = self._Token + + if self._IsKeyword("VERSION"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("Version", self.FileName, self.CurrentLineNumber) + + if self._GetStringData(): + FfsInfObj.Version = self._Token + + if self._IsKeyword(BINARY_FILE_TYPE_UI): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("UI name", self.FileName, self.CurrentLineNumber) + + if self._GetStringData(): + FfsInfObj.Ui = self._Token + + if self._IsKeyword("USE"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("ARCH name", self.FileName, self.CurrentLineNumber) + FfsInfObj.UseArch = self._Token + + + if self._GetNextToken(): + p = compile(r'([a-zA-Z0-9\-]+|\$\(TARGET\)|\*)_([a-zA-Z0-9\-]+|\$\(TOOL_CHAIN_TAG\)|\*)_([a-zA-Z0-9\-]+|\$\(ARCH\))') + if p.match(self._Token) and p.match(self._Token).span()[1] == len(self._Token): + FfsInfObj.KeyStringList.append(self._Token) + if not self._IsToken(TAB_COMMA_SPLIT): + return + else: + self._UndoToken() + return + + while self._GetNextToken(): + if not p.match(self._Token): + raise Warning.Expected("KeyString \"Target_Tag_Arch\"", self.FileName, self.CurrentLineNumber) + FfsInfObj.KeyStringList.append(self._Token) + + if not self._IsToken(TAB_COMMA_SPLIT): + break + + ## _GetFileStatement() method + # + # Get FILE statements + # + # @param self The object pointer + # @param Obj for whom FILE statement is got + # @retval True Successfully find FILE statement + # @retval False Not able to find FILE statement + # + def _GetFileStatement(self, Obj, ForCapsule = False): + if not self._IsKeyword("FILE"): + return False + + if not self._GetNextWord(): + raise Warning.Expected("FFS type", self.FileName, self.CurrentLineNumber) + + if ForCapsule and self._Token == 'DATA': + self._UndoToken() + self._UndoToken() + return False + + FfsFileObj = FileStatement() + FfsFileObj.FvFileType = self._Token + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextGuid(): + if not self._GetNextWord(): + raise Warning.Expected("File GUID", self.FileName, self.CurrentLineNumber) + if self._Token == 'PCD': + if not self._IsToken("("): + raise Warning.Expected("'('", self.FileName, self.CurrentLineNumber) + PcdPair = self._GetNextPcdSettings() + if not self._IsToken(")"): + raise Warning.Expected("')'", self.FileName, self.CurrentLineNumber) + self._Token = 'PCD('+PcdPair[1]+TAB_SPLIT+PcdPair[0]+')' + + if self._Token in GlobalData.gGuidDict: + self._Token = GuidStructureStringToGuidString(GlobalData.gGuidDict[self._Token]).upper() + FfsFileObj.NameGuid = self._Token + + self._GetFilePart(FfsFileObj) + + if ForCapsule: + capsuleFfs = CapsuleFfs() + capsuleFfs.Ffs = FfsFileObj + Obj.CapsuleDataList.append(capsuleFfs) + else: + Obj.FfsList.append(FfsFileObj) + + return True + + ## _FileCouldHaveRelocFlag() method + # + # Check whether reloc strip flag can be set for a file type. + # + # @param FileType The file type to check with + # @retval True This type could have relocation strip flag + # @retval False No way to have it + # + @staticmethod + def _FileCouldHaveRelocFlag (FileType): + if FileType in {SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, SUP_MODULE_MM_CORE_STANDALONE, 'PEI_DXE_COMBO'}: + return True + else: + return False + + ## _SectionCouldHaveRelocFlag() method + # + # Check whether reloc strip flag can be set for a section type. + # + # @param SectionType The section type to check with + # @retval True This type could have relocation strip flag + # @retval False No way to have it + # + @staticmethod + def _SectionCouldHaveRelocFlag (SectionType): + if SectionType in {BINARY_FILE_TYPE_TE, BINARY_FILE_TYPE_PE32}: + return True + else: + return False + + ## _GetFilePart() method + # + # Get components for FILE statement + # + # @param self The object pointer + # @param FfsFileObj for whom component is got + # + def _GetFilePart(self, FfsFileObj): + self._GetFileOpts(FfsFileObj) + + if not self._IsToken("{"): + if self._IsKeyword('RELOCS_STRIPPED') or self._IsKeyword('RELOCS_RETAINED'): + if self._FileCouldHaveRelocFlag(FfsFileObj.FvFileType): + if self._Token == 'RELOCS_STRIPPED': + FfsFileObj.KeepReloc = False + else: + FfsFileObj.KeepReloc = True + else: + raise Warning("File type %s could not have reloc strip flag%d" % (FfsFileObj.FvFileType, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("File name or section data", self.FileName, self.CurrentLineNumber) + + if self._Token == BINARY_FILE_TYPE_FV: + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("FV name", self.FileName, self.CurrentLineNumber) + FfsFileObj.FvName = self._Token + + elif self._Token == "FD": + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("FD name", self.FileName, self.CurrentLineNumber) + FfsFileObj.FdName = self._Token + + elif self._Token in {TAB_DEFINE, "APRIORI", "SECTION"}: + self._UndoToken() + self._GetSectionData(FfsFileObj) + + elif hasattr(FfsFileObj, 'FvFileType') and FfsFileObj.FvFileType == 'RAW': + self._UndoToken() + self._GetRAWData(FfsFileObj) + + else: + FfsFileObj.CurrentLineNum = self.CurrentLineNumber + FfsFileObj.CurrentLineContent = self._CurrentLine() + FfsFileObj.FileName = self._Token.replace('$(SPACE)', ' ') + self._VerifyFile(FfsFileObj.FileName) + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + ## _GetRAWData() method + # + # Get RAW data for FILE statement + # + # @param self The object pointer + # @param FfsFileObj for whom section is got + # + def _GetRAWData(self, FfsFileObj): + FfsFileObj.FileName = [] + FfsFileObj.SubAlignment = [] + while True: + AlignValue = None + if self._GetAlignment(): + if self._Token not in ALIGNMENTS: + raise Warning("Incorrect alignment '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + #For FFS, Auto is default option same to "" + if not self._Token == "Auto": + AlignValue = self._Token + if not self._GetNextToken(): + raise Warning.Expected("Filename value", self.FileName, self.CurrentLineNumber) + + FileName = self._Token.replace('$(SPACE)', ' ') + if FileName == T_CHAR_BRACE_R: + self._UndoToken() + raise Warning.Expected("Filename value", self.FileName, self.CurrentLineNumber) + + self._VerifyFile(FileName) + File = PathClass(NormPath(FileName), GenFdsGlobalVariable.WorkSpaceDir) + FfsFileObj.FileName.append(File.Path) + FfsFileObj.SubAlignment.append(AlignValue) + + if self._IsToken(T_CHAR_BRACE_R): + self._UndoToken() + break + + if len(FfsFileObj.SubAlignment) == 1: + FfsFileObj.SubAlignment = FfsFileObj.SubAlignment[0] + if len(FfsFileObj.FileName) == 1: + FfsFileObj.FileName = FfsFileObj.FileName[0] + + ## _GetFileOpts() method + # + # Get options for FILE statement + # + # @param self The object pointer + # @param FfsFileObj for whom options is got + # + def _GetFileOpts(self, FfsFileObj): + if self._GetNextToken(): + if TokenFindPattern.match(self._Token): + FfsFileObj.KeyStringList.append(self._Token) + if self._IsToken(TAB_COMMA_SPLIT): + while self._GetNextToken(): + if not TokenFindPattern.match(self._Token): + raise Warning.Expected("KeyString \"Target_Tag_Arch\"", self.FileName, self.CurrentLineNumber) + FfsFileObj.KeyStringList.append(self._Token) + + if not self._IsToken(TAB_COMMA_SPLIT): + break + + else: + self._UndoToken() + + if self._IsKeyword("FIXED", True): + FfsFileObj.Fixed = True + + if self._IsKeyword("CHECKSUM", True): + FfsFileObj.CheckSum = True + + if self._GetAlignment(): + if self._Token not in ALIGNMENTS: + raise Warning("Incorrect alignment '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + #For FFS, Auto is default option same to "" + if not self._Token == "Auto": + FfsFileObj.Alignment = self._Token + + ## _GetAlignment() method + # + # Return the alignment value + # + # @param self The object pointer + # @retval True Successfully find alignment + # @retval False Not able to find alignment + # + def _GetAlignment(self): + if self._IsKeyword("Align", True): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("alignment value", self.FileName, self.CurrentLineNumber) + return True + + return False + + ## _GetSectionData() method + # + # Get section data for FILE statement + # + # @param self The object pointer + # @param FfsFileObj for whom section is got + # + def _GetSectionData(self, FfsFileObj): + self._GetDefineStatements(FfsFileObj) + + while True: + IsLeafSection = self._GetLeafSection(FfsFileObj) + IsEncapSection = self._GetEncapsulationSec(FfsFileObj) + if not IsLeafSection and not IsEncapSection: + break + + ## _GetLeafSection() method + # + # Get leaf section for Obj + # + # @param self The object pointer + # @param Obj for whom leaf section is got + # @retval True Successfully find section statement + # @retval False Not able to find section statement + # + def _GetLeafSection(self, Obj): + OldPos = self.GetFileBufferPos() + + if not self._IsKeyword("SECTION"): + if len(Obj.SectionList) == 0: + raise Warning.Expected("SECTION", self.FileName, self.CurrentLineNumber) + else: + return False + + AlignValue = None + if self._GetAlignment(): + if self._Token not in ALIGNMENTS: + raise Warning("Incorrect alignment '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + AlignValue = self._Token + + BuildNum = None + if self._IsKeyword("BUILD_NUM"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("Build number value", self.FileName, self.CurrentLineNumber) + + BuildNum = self._Token + + if self._IsKeyword("VERSION"): + if AlignValue == 'Auto': + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("version", self.FileName, self.CurrentLineNumber) + VerSectionObj = VerSection() + VerSectionObj.Alignment = AlignValue + VerSectionObj.BuildNum = BuildNum + if self._GetStringData(): + VerSectionObj.StringData = self._Token + else: + VerSectionObj.FileName = self._Token + Obj.SectionList.append(VerSectionObj) + + elif self._IsKeyword(BINARY_FILE_TYPE_UI): + if AlignValue == 'Auto': + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("UI", self.FileName, self.CurrentLineNumber) + UiSectionObj = UiSection() + UiSectionObj.Alignment = AlignValue + if self._GetStringData(): + UiSectionObj.StringData = self._Token + else: + UiSectionObj.FileName = self._Token + Obj.SectionList.append(UiSectionObj) + + elif self._IsKeyword("FV_IMAGE"): + if AlignValue == 'Auto': + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("FV name or FV file path", self.FileName, self.CurrentLineNumber) + + FvName = self._Token + FvObj = None + + if self._IsToken("{"): + FvObj = FV() + FvObj.UiFvName = FvName.upper() + self._GetDefineStatements(FvObj) + + self._GetBlockStatement(FvObj) + self._GetSetStatements(FvObj) + self._GetFvAlignment(FvObj) + self._GetFvAttributes(FvObj) + + while True: + IsInf = self._GetInfStatement(FvObj) + IsFile = self._GetFileStatement(FvObj) + if not IsInf and not IsFile: + break + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + FvImageSectionObj = FvImageSection() + FvImageSectionObj.Alignment = AlignValue + if FvObj is not None: + FvImageSectionObj.Fv = FvObj + FvImageSectionObj.FvName = None + else: + FvImageSectionObj.FvName = FvName.upper() + FvImageSectionObj.FvFileName = FvName + + Obj.SectionList.append(FvImageSectionObj) + + elif self._IsKeyword("PEI_DEPEX_EXP") or self._IsKeyword("DXE_DEPEX_EXP") or self._IsKeyword("SMM_DEPEX_EXP"): + if AlignValue == 'Auto': + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + DepexSectionObj = DepexSection() + DepexSectionObj.Alignment = AlignValue + DepexSectionObj.DepexType = self._Token + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + if not self._SkipToToken(T_CHAR_BRACE_R): + raise Warning.Expected("Depex expression ending '}'", self.FileName, self.CurrentLineNumber) + + DepexSectionObj.Expression = self._SkippedChars.rstrip(T_CHAR_BRACE_R) + Obj.SectionList.append(DepexSectionObj) + + else: + if not self._GetNextWord(): + raise Warning.Expected("section type", self.FileName, self.CurrentLineNumber) + + # Encapsulation section appear, UndoToken and return + if self._Token == "COMPRESS" or self._Token == "GUIDED": + self.SetFileBufferPos(OldPos) + return False + + if self._Token not in {"COMPAT16", BINARY_FILE_TYPE_PE32, BINARY_FILE_TYPE_PIC, BINARY_FILE_TYPE_TE, "FV_IMAGE", "RAW", BINARY_FILE_TYPE_DXE_DEPEX,\ + BINARY_FILE_TYPE_UI, "VERSION", BINARY_FILE_TYPE_PEI_DEPEX, "SUBTYPE_GUID", BINARY_FILE_TYPE_SMM_DEPEX}: + raise Warning("Unknown section type '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + if AlignValue == 'Auto'and (not self._Token == BINARY_FILE_TYPE_PE32) and (not self._Token == BINARY_FILE_TYPE_TE): + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + + # DataSection + DataSectionObj = DataSection() + DataSectionObj.Alignment = AlignValue + DataSectionObj.SecType = self._Token + + if self._IsKeyword('RELOCS_STRIPPED') or self._IsKeyword('RELOCS_RETAINED'): + if self._FileCouldHaveRelocFlag(Obj.FvFileType) and self._SectionCouldHaveRelocFlag(DataSectionObj.SecType): + if self._Token == 'RELOCS_STRIPPED': + DataSectionObj.KeepReloc = False + else: + DataSectionObj.KeepReloc = True + else: + raise Warning("File type %s, section type %s, could not have reloc strip flag%d" % (Obj.FvFileType, DataSectionObj.SecType, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) + + if self._IsToken(TAB_EQUAL_SPLIT): + if not self._GetNextToken(): + raise Warning.Expected("section file path", self.FileName, self.CurrentLineNumber) + DataSectionObj.SectFileName = self._Token + self._VerifyFile(DataSectionObj.SectFileName) + else: + if not self._GetCglSection(DataSectionObj): + return False + + Obj.SectionList.append(DataSectionObj) + + return True + + ## _VerifyFile + # + # Check if file exists or not: + # If current phase if GenFds, the file must exist; + # If current phase is AutoGen and the file is not in $(OUTPUT_DIRECTORY), the file must exist + # @param FileName: File path to be verified. + # + def _VerifyFile(self, FileName): + if FileName.replace(TAB_WORKSPACE, '').find('$') != -1: + return + if not GlobalData.gAutoGenPhase or not self._GetMacroValue(TAB_DSC_DEFINES_OUTPUT_DIRECTORY) in FileName: + ErrorCode, ErrorInfo = PathClass(NormPath(FileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + + ## _GetCglSection() method + # + # Get compressed or GUIDed section for Obj + # + # @param self The object pointer + # @param Obj for whom leaf section is got + # @param AlignValue alignment value for complex section + # @retval True Successfully find section statement + # @retval False Not able to find section statement + # + def _GetCglSection(self, Obj, AlignValue = None): + + if self._IsKeyword("COMPRESS"): + type = "PI_STD" + if self._IsKeyword("PI_STD") or self._IsKeyword("PI_NONE"): + type = self._Token + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + + CompressSectionObj = CompressSection() + CompressSectionObj.Alignment = AlignValue + CompressSectionObj.CompType = type + # Recursive sections... + while True: + IsLeafSection = self._GetLeafSection(CompressSectionObj) + IsEncapSection = self._GetEncapsulationSec(CompressSectionObj) + if not IsLeafSection and not IsEncapSection: + break + + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + Obj.SectionList.append(CompressSectionObj) + return True + + elif self._IsKeyword("GUIDED"): + GuidValue = None + if self._GetNextGuid(): + if self._Token in GlobalData.gGuidDict: + self._Token = GuidStructureStringToGuidString(GlobalData.gGuidDict[self._Token]).upper() + GuidValue = self._Token + + AttribDict = self._GetGuidAttrib() + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + GuidSectionObj = GuidSection() + GuidSectionObj.Alignment = AlignValue + GuidSectionObj.NameGuid = GuidValue + GuidSectionObj.SectionType = "GUIDED" + GuidSectionObj.ProcessRequired = AttribDict["PROCESSING_REQUIRED"] + GuidSectionObj.AuthStatusValid = AttribDict["AUTH_STATUS_VALID"] + GuidSectionObj.ExtraHeaderSize = AttribDict["EXTRA_HEADER_SIZE"] + # Recursive sections... + while True: + IsLeafSection = self._GetLeafSection(GuidSectionObj) + IsEncapSection = self._GetEncapsulationSec(GuidSectionObj) + if not IsLeafSection and not IsEncapSection: + break + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + Obj.SectionList.append(GuidSectionObj) + + return True + + return False + + ## _GetGuidAttri() method + # + # Get attributes for GUID section + # + # @param self The object pointer + # @retval AttribDict Dictionary of key-value pair of section attributes + # + def _GetGuidAttrib(self): + AttribDict = {} + AttribDict["PROCESSING_REQUIRED"] = "NONE" + AttribDict["AUTH_STATUS_VALID"] = "NONE" + AttribDict["EXTRA_HEADER_SIZE"] = -1 + while self._IsKeyword("PROCESSING_REQUIRED") or self._IsKeyword("AUTH_STATUS_VALID") \ + or self._IsKeyword("EXTRA_HEADER_SIZE"): + AttribKey = self._Token + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("TRUE(1)/FALSE(0)/Number", self.FileName, self.CurrentLineNumber) + elif AttribKey == "EXTRA_HEADER_SIZE": + Base = 10 + if self._Token[0:2].upper() == "0X": + Base = 16 + try: + AttribDict[AttribKey] = int(self._Token, Base) + continue + except ValueError: + raise Warning.Expected("Number", self.FileName, self.CurrentLineNumber) + elif self._Token.upper() not in {"TRUE", "FALSE", "1", "0"}: + raise Warning.Expected("TRUE/FALSE (1/0)", self.FileName, self.CurrentLineNumber) + AttribDict[AttribKey] = self._Token + + return AttribDict + + ## _GetEncapsulationSec() method + # + # Get encapsulation section for FILE + # + # @param self The object pointer + # @param FfsFile for whom section is got + # @retval True Successfully find section statement + # @retval False Not able to find section statement + # + def _GetEncapsulationSec(self, FfsFileObj): + OldPos = self.GetFileBufferPos() + if not self._IsKeyword("SECTION"): + if len(FfsFileObj.SectionList) == 0: + raise Warning.Expected("SECTION", self.FileName, self.CurrentLineNumber) + else: + return False + + AlignValue = None + if self._GetAlignment(): + if self._Token not in ALIGNMENT_NOAUTO: + raise Warning("Incorrect alignment '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + AlignValue = self._Token + + if not self._GetCglSection(FfsFileObj, AlignValue): + self.SetFileBufferPos(OldPos) + return False + else: + return True + + def _GetFmp(self): + if not self._GetNextToken(): + return False + S = self._Token.upper() + if S.startswith(TAB_SECTION_START) and not S.startswith("[FMPPAYLOAD."): + self.SectionParser(S) + self._UndoToken() + return False + + self._UndoToken() + self._SkipToToken("[FMPPAYLOAD.", True) + FmpUiName = self._GetUiName().upper() + if FmpUiName in self.Profile.FmpPayloadDict: + raise Warning("Duplicated FMP UI name found: %s" % FmpUiName, self.FileName, self.CurrentLineNumber) + + FmpData = CapsulePayload() + FmpData.UiName = FmpUiName + + if not self._IsToken(TAB_SECTION_END): + raise Warning.ExpectedBracketClose(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning("The FMP payload section is empty!", self.FileName, self.CurrentLineNumber) + FmpKeyList = ['IMAGE_HEADER_INIT_VERSION', 'IMAGE_TYPE_ID', 'IMAGE_INDEX', 'HARDWARE_INSTANCE', 'CERTIFICATE_GUID', 'MONOTONIC_COUNT'] + while self._Token in FmpKeyList: + Name = self._Token + FmpKeyList.remove(Name) + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if Name == 'IMAGE_TYPE_ID': + if not self._GetNextGuid(): + raise Warning.Expected("GUID value for IMAGE_TYPE_ID.", self.FileName, self.CurrentLineNumber) + FmpData.ImageTypeId = self._Token + elif Name == 'CERTIFICATE_GUID': + if not self._GetNextGuid(): + raise Warning.Expected("GUID value for CERTIFICATE_GUID.", self.FileName, self.CurrentLineNumber) + FmpData.Certificate_Guid = self._Token + if UUID(FmpData.Certificate_Guid) != EFI_CERT_TYPE_RSA2048_SHA256_GUID and UUID(FmpData.Certificate_Guid) != EFI_CERT_TYPE_PKCS7_GUID: + raise Warning("Only support EFI_CERT_TYPE_RSA2048_SHA256_GUID or EFI_CERT_TYPE_PKCS7_GUID for CERTIFICATE_GUID.", self.FileName, self.CurrentLineNumber) + else: + if not self._GetNextToken(): + raise Warning.Expected("value of %s" % Name, self.FileName, self.CurrentLineNumber) + Value = self._Token + if Name == 'IMAGE_HEADER_INIT_VERSION': + if FdfParser._Verify(Name, Value, 'UINT8'): + FmpData.Version = Value + elif Name == 'IMAGE_INDEX': + if FdfParser._Verify(Name, Value, 'UINT8'): + FmpData.ImageIndex = Value + elif Name == 'HARDWARE_INSTANCE': + if FdfParser._Verify(Name, Value, 'UINT8'): + FmpData.HardwareInstance = Value + elif Name == 'MONOTONIC_COUNT': + if FdfParser._Verify(Name, Value, 'UINT64'): + FmpData.MonotonicCount = Value + if FmpData.MonotonicCount.upper().startswith('0X'): + FmpData.MonotonicCount = int(FmpData.MonotonicCount, 16) + else: + FmpData.MonotonicCount = int(FmpData.MonotonicCount) + if not self._GetNextToken(): + break + else: + self._UndoToken() + + if (FmpData.MonotonicCount and not FmpData.Certificate_Guid) or (not FmpData.MonotonicCount and FmpData.Certificate_Guid): + EdkLogger.error("FdfParser", FORMAT_INVALID, "CERTIFICATE_GUID and MONOTONIC_COUNT must be work as a pair.") + + # Only the IMAGE_TYPE_ID is required item + if FmpKeyList and 'IMAGE_TYPE_ID' in FmpKeyList: + raise Warning("'IMAGE_TYPE_ID' in FMP payload section.", self.FileName, self.CurrentLineNumber) + # get the Image file and Vendor code file + self._GetFMPCapsuleData(FmpData) + if not FmpData.ImageFile: + raise Warning("Missing image file in FMP payload section.", self.FileName, self.CurrentLineNumber) + # check whether more than one Vendor code file + if len(FmpData.VendorCodeFile) > 1: + raise Warning("Vendor code file max of 1 per FMP payload section.", self.FileName, self.CurrentLineNumber) + self.Profile.FmpPayloadDict[FmpUiName] = FmpData + return True + + ## _GetCapsule() method + # + # Get capsule section contents and store its data into capsule list of self.Profile + # + # @param self The object pointer + # @retval True Successfully find a capsule + # @retval False Not able to find a capsule + # + def _GetCapsule(self): + if not self._GetNextToken(): + return False + + S = self._Token.upper() + if S.startswith(TAB_SECTION_START) and not S.startswith("[CAPSULE."): + self.SectionParser(S) + self._UndoToken() + return False + + self._UndoToken() + if not self._IsToken("[CAPSULE.", True): + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + #print 'Parsing String: %s in File %s, At line: %d, Offset Within Line: %d' \ + # % (self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:], FileLineTuple[0], FileLineTuple[1], self.CurrentOffsetWithinLine) + raise Warning.Expected("[Capsule.]", self.FileName, self.CurrentLineNumber) + + CapsuleObj = Capsule() + + CapsuleName = self._GetUiName() + if not CapsuleName: + raise Warning.Expected("capsule name", self.FileName, self.CurrentLineNumber) + + CapsuleObj.UiCapsuleName = CapsuleName.upper() + + if not self._IsToken(TAB_SECTION_END): + raise Warning.ExpectedBracketClose(self.FileName, self.CurrentLineNumber) + + if self._IsKeyword("CREATE_FILE"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("file name", self.FileName, self.CurrentLineNumber) + + CapsuleObj.CreateFile = self._Token + + self._GetCapsuleStatements(CapsuleObj) + self.Profile.CapsuleDict[CapsuleObj.UiCapsuleName] = CapsuleObj + return True + + ## _GetCapsuleStatements() method + # + # Get statements for capsule + # + # @param self The object pointer + # @param Obj for whom statements are got + # + def _GetCapsuleStatements(self, Obj): + self._GetCapsuleTokens(Obj) + self._GetDefineStatements(Obj) + self._GetSetStatements(Obj) + self._GetCapsuleData(Obj) + + ## _GetCapsuleTokens() method + # + # Get token statements for capsule + # + # @param self The object pointer + # @param Obj for whom token statements are got + # + def _GetCapsuleTokens(self, Obj): + if not self._GetNextToken(): + return False + while self._Token in {"CAPSULE_GUID", "CAPSULE_HEADER_SIZE", "CAPSULE_FLAGS", "OEM_CAPSULE_FLAGS", "CAPSULE_HEADER_INIT_VERSION"}: + Name = self._Token.strip() + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("value", self.FileName, self.CurrentLineNumber) + if Name == 'CAPSULE_FLAGS': + if not self._Token in {"PersistAcrossReset", "PopulateSystemTable", "InitiateReset"}: + raise Warning.Expected("PersistAcrossReset, PopulateSystemTable, or InitiateReset", self.FileName, self.CurrentLineNumber) + Value = self._Token.strip() + while self._IsToken(TAB_COMMA_SPLIT): + Value += TAB_COMMA_SPLIT + if not self._GetNextToken(): + raise Warning.Expected("value", self.FileName, self.CurrentLineNumber) + if not self._Token in {"PersistAcrossReset", "PopulateSystemTable", "InitiateReset"}: + raise Warning.Expected("PersistAcrossReset, PopulateSystemTable, or InitiateReset", self.FileName, self.CurrentLineNumber) + Value += self._Token.strip() + elif Name == 'OEM_CAPSULE_FLAGS': + Value = self._Token.strip() + if not Value.upper().startswith('0X'): + raise Warning.Expected("hex value starting with 0x", self.FileName, self.CurrentLineNumber) + try: + Value = int(Value, 0) + except ValueError: + raise Warning.Expected("hex string failed to convert to value", self.FileName, self.CurrentLineNumber) + if not 0x0000 <= Value <= 0xFFFF: + raise Warning.Expected("hex value between 0x0000 and 0xFFFF", self.FileName, self.CurrentLineNumber) + Value = self._Token.strip() + else: + Value = self._Token.strip() + Obj.TokensDict[Name] = Value + if not self._GetNextToken(): + return False + self._UndoToken() + + ## _GetCapsuleData() method + # + # Get capsule data for capsule + # + # @param self The object pointer + # @param Obj for whom capsule data are got + # + def _GetCapsuleData(self, Obj): + while True: + IsInf = self._GetInfStatement(Obj, True) + IsFile = self._GetFileStatement(Obj, True) + IsFv = self._GetFvStatement(Obj) + IsFd = self._GetFdStatement(Obj) + IsAnyFile = self._GetAnyFileStatement(Obj) + IsAfile = self._GetAfileStatement(Obj) + IsFmp = self._GetFmpStatement(Obj) + if not (IsInf or IsFile or IsFv or IsFd or IsAnyFile or IsAfile or IsFmp): + break + + ## _GetFMPCapsuleData() method + # + # Get capsule data for FMP capsule + # + # @param self The object pointer + # @param Obj for whom capsule data are got + # + def _GetFMPCapsuleData(self, Obj): + while True: + IsFv = self._GetFvStatement(Obj, True) + IsFd = self._GetFdStatement(Obj, True) + IsAnyFile = self._GetAnyFileStatement(Obj, True) + if not (IsFv or IsFd or IsAnyFile): + break + + ## _GetFvStatement() method + # + # Get FV for capsule + # + # @param self The object pointer + # @param CapsuleObj for whom FV is got + # @retval True Successfully find a FV statement + # @retval False Not able to find a FV statement + # + def _GetFvStatement(self, CapsuleObj, FMPCapsule = False): + if not self._IsKeyword(BINARY_FILE_TYPE_FV): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("FV name", self.FileName, self.CurrentLineNumber) + + if self._Token.upper() not in self.Profile.FvDict: + raise Warning("FV name does not exist", self.FileName, self.CurrentLineNumber) + + myCapsuleFv = CapsuleFv() + myCapsuleFv.FvName = self._Token + if FMPCapsule: + if not CapsuleObj.ImageFile: + CapsuleObj.ImageFile.append(myCapsuleFv) + else: + CapsuleObj.VendorCodeFile.append(myCapsuleFv) + else: + CapsuleObj.CapsuleDataList.append(myCapsuleFv) + return True + + ## _GetFdStatement() method + # + # Get FD for capsule + # + # @param self The object pointer + # @param CapsuleObj for whom FD is got + # @retval True Successfully find a FD statement + # @retval False Not able to find a FD statement + # + def _GetFdStatement(self, CapsuleObj, FMPCapsule = False): + if not self._IsKeyword("FD"): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("FD name", self.FileName, self.CurrentLineNumber) + + if self._Token.upper() not in self.Profile.FdDict: + raise Warning("FD name does not exist", self.FileName, self.CurrentLineNumber) + + myCapsuleFd = CapsuleFd() + myCapsuleFd.FdName = self._Token + if FMPCapsule: + if not CapsuleObj.ImageFile: + CapsuleObj.ImageFile.append(myCapsuleFd) + else: + CapsuleObj.VendorCodeFile.append(myCapsuleFd) + else: + CapsuleObj.CapsuleDataList.append(myCapsuleFd) + return True + + def _GetFmpStatement(self, CapsuleObj): + if not self._IsKeyword("FMP_PAYLOAD"): + if not self._IsKeyword("FMP"): + return False + + if not self._IsKeyword("PAYLOAD"): + self._UndoToken() + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("payload name after FMP_PAYLOAD =", self.FileName, self.CurrentLineNumber) + Payload = self._Token.upper() + if Payload not in self.Profile.FmpPayloadDict: + raise Warning("This FMP Payload does not exist: %s" % self._Token, self.FileName, self.CurrentLineNumber) + CapsuleObj.FmpPayloadList.append(self.Profile.FmpPayloadDict[Payload]) + return True + + def _ParseRawFileStatement(self): + if not self._IsKeyword("FILE"): + return None + + if not self._IsKeyword("DATA"): + self._UndoToken() + return None + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("File name", self.FileName, self.CurrentLineNumber) + + AnyFileName = self._Token + self._VerifyFile(AnyFileName) + + if not os.path.isabs(AnyFileName): + AnyFileName = mws.join(GenFdsGlobalVariable.WorkSpaceDir, AnyFileName) + + return AnyFileName + + ## _GetAnyFileStatement() method + # + # Get AnyFile for capsule + # + # @param self The object pointer + # @param CapsuleObj for whom AnyFile is got + # @retval True Successfully find a Anyfile statement + # @retval False Not able to find a AnyFile statement + # + def _GetAnyFileStatement(self, CapsuleObj, FMPCapsule = False): + AnyFileName = self._ParseRawFileStatement() + if not AnyFileName: + return False + + myCapsuleAnyFile = CapsuleAnyFile() + myCapsuleAnyFile.FileName = AnyFileName + if FMPCapsule: + if not CapsuleObj.ImageFile: + CapsuleObj.ImageFile.append(myCapsuleAnyFile) + else: + CapsuleObj.VendorCodeFile.append(myCapsuleAnyFile) + else: + CapsuleObj.CapsuleDataList.append(myCapsuleAnyFile) + return True + + ## _GetAfileStatement() method + # + # Get Afile for capsule + # + # @param self The object pointer + # @param CapsuleObj for whom Afile is got + # @retval True Successfully find a Afile statement + # @retval False Not able to find a Afile statement + # + def _GetAfileStatement(self, CapsuleObj): + if not self._IsKeyword("APPEND"): + return False + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("Afile name", self.FileName, self.CurrentLineNumber) + + AfileName = self._Token + AfileBaseName = os.path.basename(AfileName) + + if os.path.splitext(AfileBaseName)[1] not in {".bin", ".BIN", ".Bin", ".dat", ".DAT", ".Dat", ".data", ".DATA", ".Data"}: + raise Warning('invalid binary file type, should be one of "bin",BINARY_FILE_TYPE_BIN,"Bin","dat","DAT","Dat","data","DATA","Data"', \ + self.FileName, self.CurrentLineNumber) + + if not os.path.isabs(AfileName): + AfileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(AfileName) + self._VerifyFile(AfileName) + else: + if not os.path.exists(AfileName): + raise Warning('%s does not exist' % AfileName, self.FileName, self.CurrentLineNumber) + else: + pass + + myCapsuleAfile = CapsuleAfile() + myCapsuleAfile.FileName = AfileName + CapsuleObj.CapsuleDataList.append(myCapsuleAfile) + return True + + ## _GetRule() method + # + # Get Rule section contents and store its data into rule list of self.Profile + # + # @param self The object pointer + # @retval True Successfully find a Rule + # @retval False Not able to find a Rule + # + def _GetRule(self): + if not self._GetNextToken(): + return False + + S = self._Token.upper() + if S.startswith(TAB_SECTION_START) and not S.startswith("[RULE."): + self.SectionParser(S) + self._UndoToken() + return False + self._UndoToken() + if not self._IsToken("[Rule.", True): + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + #print 'Parsing String: %s in File %s, At line: %d, Offset Within Line: %d' \ + # % (self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine:], FileLineTuple[0], FileLineTuple[1], self.CurrentOffsetWithinLine) + raise Warning.Expected("[Rule.]", self.FileName, self.CurrentLineNumber) + + if not self._SkipToToken(TAB_SPLIT): + raise Warning.Expected("'.'", self.FileName, self.CurrentLineNumber) + + Arch = self._SkippedChars.rstrip(TAB_SPLIT) + if Arch.upper() not in ARCH_SET_FULL: + raise Warning("Unknown Arch '%s'" % Arch, self.FileName, self.CurrentLineNumber) + + ModuleType = self._GetModuleType() + + TemplateName = "" + if self._IsToken(TAB_SPLIT): + if not self._GetNextWord(): + raise Warning.Expected("template name", self.FileName, self.CurrentLineNumber) + TemplateName = self._Token + + if not self._IsToken(TAB_SECTION_END): + raise Warning.ExpectedBracketClose(self.FileName, self.CurrentLineNumber) + + RuleObj = self._GetRuleFileStatements() + RuleObj.Arch = Arch.upper() + RuleObj.ModuleType = ModuleType + RuleObj.TemplateName = TemplateName + if TemplateName == '': + self.Profile.RuleDict['RULE' + \ + TAB_SPLIT + \ + Arch.upper() + \ + TAB_SPLIT + \ + ModuleType.upper() ] = RuleObj + else: + self.Profile.RuleDict['RULE' + \ + TAB_SPLIT + \ + Arch.upper() + \ + TAB_SPLIT + \ + ModuleType.upper() + \ + TAB_SPLIT + \ + TemplateName.upper() ] = RuleObj + return True + + ## _GetModuleType() method + # + # Return the module type + # + # @param self The object pointer + # @retval string module type + # + def _GetModuleType(self): + if not self._GetNextWord(): + raise Warning.Expected("Module type", self.FileName, self.CurrentLineNumber) + if self._Token.upper() not in { + SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, + SUP_MODULE_DXE_CORE, SUP_MODULE_DXE_DRIVER, + SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_DXE_SMM_DRIVER, + SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_UEFI_DRIVER, + SUP_MODULE_UEFI_APPLICATION, SUP_MODULE_USER_DEFINED, SUP_MODULE_HOST_APPLICATION, + TAB_DEFAULT, SUP_MODULE_BASE, + EDK_COMPONENT_TYPE_SECURITY_CORE, + EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER, + EDK_COMPONENT_TYPE_PIC_PEIM, + EDK_COMPONENT_TYPE_RELOCATABLE_PEIM, "PE32_PEIM", + EDK_COMPONENT_TYPE_BS_DRIVER, EDK_COMPONENT_TYPE_RT_DRIVER, + EDK_COMPONENT_TYPE_SAL_RT_DRIVER, + EDK_COMPONENT_TYPE_APPLICATION, "ACPITABLE", + SUP_MODULE_SMM_CORE, SUP_MODULE_MM_STANDALONE, + SUP_MODULE_MM_CORE_STANDALONE}: + raise Warning("Unknown Module type '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + return self._Token + + ## _GetFileExtension() method + # + # Return the file extension + # + # @param self The object pointer + # @retval string file name extension + # + def _GetFileExtension(self): + if not self._IsToken(TAB_SPLIT): + raise Warning.Expected("'.'", self.FileName, self.CurrentLineNumber) + + Ext = "" + if self._GetNextToken(): + if FileExtensionPattern.match(self._Token): + Ext = self._Token + return TAB_SPLIT + Ext + else: + raise Warning("Unknown file extension '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + + else: + raise Warning.Expected("file extension", self.FileName, self.CurrentLineNumber) + + ## _GetRuleFileStatement() method + # + # Get rule contents + # + # @param self The object pointer + # @retval Rule Rule object + # + def _GetRuleFileStatements(self): + if not self._IsKeyword("FILE"): + raise Warning.Expected("FILE", self.FileName, self.CurrentLineNumber) + + if not self._GetNextWord(): + raise Warning.Expected("FFS type", self.FileName, self.CurrentLineNumber) + + Type = self._Token.strip().upper() + if Type not in {"RAW", "FREEFORM", SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, + "PEI_DXE_COMBO", "DRIVER", SUP_MODULE_DXE_CORE, EDK_COMPONENT_TYPE_APPLICATION, + "FV_IMAGE", "SMM", SUP_MODULE_SMM_CORE, SUP_MODULE_MM_STANDALONE, + SUP_MODULE_MM_CORE_STANDALONE}: + raise Warning("Unknown FV type '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._IsKeyword("$(NAMED_GUID)"): + if not self._GetNextWord(): + NamedGuid = self._CurrentLine()[self.CurrentOffsetWithinLine:].split()[0].strip() + if GlobalData.gGuidPatternEnd.match(NamedGuid): + self.CurrentOffsetWithinLine += len(NamedGuid) + self._Token = NamedGuid + else: + raise Warning.Expected("$(NAMED_GUID)", self.FileName, self.CurrentLineNumber) + if self._Token == 'PCD': + if not self._IsToken("("): + raise Warning.Expected("'('", self.FileName, self.CurrentLineNumber) + PcdPair = self._GetNextPcdSettings() + if not self._IsToken(")"): + raise Warning.Expected("')'", self.FileName, self.CurrentLineNumber) + self._Token = 'PCD('+PcdPair[1]+TAB_SPLIT+PcdPair[0]+')' + + NameGuid = self._Token + + KeepReloc = None + if self._IsKeyword('RELOCS_STRIPPED') or self._IsKeyword('RELOCS_RETAINED'): + if self._FileCouldHaveRelocFlag(Type): + if self._Token == 'RELOCS_STRIPPED': + KeepReloc = False + else: + KeepReloc = True + else: + raise Warning("File type %s could not have reloc strip flag%d" % (Type, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) + + KeyStringList = [] + if self._GetNextToken(): + if TokenFindPattern.match(self._Token): + KeyStringList.append(self._Token) + if self._IsToken(TAB_COMMA_SPLIT): + while self._GetNextToken(): + if not TokenFindPattern.match(self._Token): + raise Warning.Expected("KeyString \"Target_Tag_Arch\"", self.FileName, self.CurrentLineNumber) + KeyStringList.append(self._Token) + + if not self._IsToken(TAB_COMMA_SPLIT): + break + + else: + self._UndoToken() + + + Fixed = False + if self._IsKeyword("Fixed", True): + Fixed = True + + CheckSum = False + if self._IsKeyword("CheckSum", True): + CheckSum = True + + AlignValue = "" + if self._GetAlignment(): + if self._Token not in ALIGNMENTS: + raise Warning("Incorrect alignment '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + #For FFS, Auto is default option same to "" + if not self._Token == "Auto": + AlignValue = self._Token + + if self._IsToken("{"): + # Complex file rule expected + NewRule = RuleComplexFile() + NewRule.FvFileType = Type + NewRule.NameGuid = NameGuid + NewRule.Alignment = AlignValue + NewRule.CheckSum = CheckSum + NewRule.Fixed = Fixed + NewRule.KeyStringList = KeyStringList + if KeepReloc is not None: + NewRule.KeepReloc = KeepReloc + + while True: + IsEncapsulate = self._GetRuleEncapsulationSection(NewRule) + IsLeaf = self._GetEfiSection(NewRule) + if not IsEncapsulate and not IsLeaf: + break + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + + return NewRule + + else: + # Simple file rule expected + if not self._GetNextWord(): + raise Warning.Expected("leaf section type", self.FileName, self.CurrentLineNumber) + + SectionName = self._Token + + if SectionName not in { + "COMPAT16", BINARY_FILE_TYPE_PE32, + BINARY_FILE_TYPE_PIC, BINARY_FILE_TYPE_TE, "FV_IMAGE", + "RAW",BINARY_FILE_TYPE_DXE_DEPEX, BINARY_FILE_TYPE_UI, + BINARY_FILE_TYPE_PEI_DEPEX, "VERSION", "SUBTYPE_GUID", + BINARY_FILE_TYPE_SMM_DEPEX}: + raise Warning("Unknown leaf section name '%s'" % SectionName, self.FileName, self.CurrentLineNumber) + + + if self._IsKeyword("Fixed", True): + Fixed = True + + if self._IsKeyword("CheckSum", True): + CheckSum = True + + SectAlignment = "" + if self._GetAlignment(): + if self._Token not in ALIGNMENTS: + raise Warning("Incorrect alignment '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + if self._Token == 'Auto' and (not SectionName == BINARY_FILE_TYPE_PE32) and (not SectionName == BINARY_FILE_TYPE_TE): + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + SectAlignment = self._Token + + Ext = None + if self._IsToken(TAB_VALUE_SPLIT): + Ext = self._GetFileExtension() + elif not self._GetNextToken(): + raise Warning.Expected("File name", self.FileName, self.CurrentLineNumber) + + NewRule = RuleSimpleFile() + NewRule.SectionType = SectionName + NewRule.FvFileType = Type + NewRule.NameGuid = NameGuid + NewRule.Alignment = AlignValue + NewRule.SectAlignment = SectAlignment + NewRule.CheckSum = CheckSum + NewRule.Fixed = Fixed + NewRule.KeyStringList = KeyStringList + if KeepReloc is not None: + NewRule.KeepReloc = KeepReloc + NewRule.FileExtension = Ext + NewRule.FileName = self._Token + return NewRule + + ## _GetEfiSection() method + # + # Get section list for Rule + # + # @param self The object pointer + # @param Obj for whom section is got + # @retval True Successfully find section statement + # @retval False Not able to find section statement + # + def _GetEfiSection(self, Obj): + OldPos = self.GetFileBufferPos() + EfiSectionObj = EfiSection() + if not self._GetNextWord(): + CurrentLine = self._CurrentLine()[self.CurrentOffsetWithinLine:].split()[0].strip() + if self._Token == '{' and Obj.FvFileType == "RAW" and TAB_SPLIT in CurrentLine: + if self._IsToken(TAB_VALUE_SPLIT): + EfiSectionObj.FileExtension = self._GetFileExtension() + elif self._GetNextToken(): + EfiSectionObj.FileName = self._Token + EfiSectionObj.SectionType = BINARY_FILE_TYPE_RAW + Obj.SectionList.append(EfiSectionObj) + return True + else: + return False + SectionName = self._Token + + if SectionName not in { + "COMPAT16", BINARY_FILE_TYPE_PE32, + BINARY_FILE_TYPE_PIC, BINARY_FILE_TYPE_TE, "FV_IMAGE", + "RAW",BINARY_FILE_TYPE_DXE_DEPEX, BINARY_FILE_TYPE_UI, + BINARY_FILE_TYPE_PEI_DEPEX, "VERSION", "SUBTYPE_GUID", + BINARY_FILE_TYPE_SMM_DEPEX, BINARY_FILE_TYPE_GUID}: + self._UndoToken() + return False + + if SectionName == "FV_IMAGE": + FvImageSectionObj = FvImageSection() + if self._IsKeyword("FV_IMAGE"): + pass + if self._IsToken("{"): + FvObj = FV() + self._GetDefineStatements(FvObj) + self._GetBlockStatement(FvObj) + self._GetSetStatements(FvObj) + self._GetFvAlignment(FvObj) + self._GetFvAttributes(FvObj) + self._GetAprioriSection(FvObj) + self._GetAprioriSection(FvObj) + + while True: + IsInf = self._GetInfStatement(FvObj) + IsFile = self._GetFileStatement(FvObj) + if not IsInf and not IsFile: + break + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + FvImageSectionObj.Fv = FvObj + FvImageSectionObj.FvName = None + + else: + if not self._IsKeyword(BINARY_FILE_TYPE_FV): + raise Warning.Expected("'FV'", self.FileName, self.CurrentLineNumber) + FvImageSectionObj.FvFileType = self._Token + + if self._GetAlignment(): + if self._Token not in ALIGNMENT_NOAUTO: + raise Warning("Incorrect alignment '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + FvImageSectionObj.Alignment = self._Token + + if self._IsToken(TAB_VALUE_SPLIT): + FvImageSectionObj.FvFileExtension = self._GetFileExtension() + elif self._GetNextToken(): + if self._Token not in { + T_CHAR_BRACE_R, "COMPAT16", BINARY_FILE_TYPE_PE32, + BINARY_FILE_TYPE_PIC, BINARY_FILE_TYPE_TE, + "FV_IMAGE", "RAW", BINARY_FILE_TYPE_DXE_DEPEX, + BINARY_FILE_TYPE_UI, "VERSION", + BINARY_FILE_TYPE_PEI_DEPEX, BINARY_FILE_TYPE_GUID, + BINARY_FILE_TYPE_SMM_DEPEX}: + FvImageSectionObj.FvFileName = self._Token + else: + self._UndoToken() + else: + raise Warning.Expected("FV file name", self.FileName, self.CurrentLineNumber) + + Obj.SectionList.append(FvImageSectionObj) + return True + + EfiSectionObj.SectionType = SectionName + + if not self._GetNextToken(): + raise Warning.Expected("file type", self.FileName, self.CurrentLineNumber) + + if self._Token == "STRING": + if not self._RuleSectionCouldHaveString(EfiSectionObj.SectionType): + raise Warning("%s section could NOT have string data%d" % (EfiSectionObj.SectionType, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + + if not self._GetNextToken(): + raise Warning.Expected("Quoted String", self.FileName, self.CurrentLineNumber) + + if self._GetStringData(): + EfiSectionObj.StringData = self._Token + + if self._IsKeyword("BUILD_NUM"): + if not self._RuleSectionCouldHaveBuildNum(EfiSectionObj.SectionType): + raise Warning("%s section could NOT have BUILD_NUM%d" % (EfiSectionObj.SectionType, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("Build number", self.FileName, self.CurrentLineNumber) + EfiSectionObj.BuildNum = self._Token + + else: + EfiSectionObj.FileType = self._Token + self._CheckRuleSectionFileType(EfiSectionObj.SectionType, EfiSectionObj.FileType) + + if self._IsKeyword("Optional"): + if not self._RuleSectionCouldBeOptional(EfiSectionObj.SectionType): + raise Warning("%s section could NOT be optional%d" % (EfiSectionObj.SectionType, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) + EfiSectionObj.Optional = True + + if self._IsKeyword("BUILD_NUM"): + if not self._RuleSectionCouldHaveBuildNum(EfiSectionObj.SectionType): + raise Warning("%s section could NOT have BUILD_NUM%d" % (EfiSectionObj.SectionType, self.CurrentLineNumber), self.FileName, self.CurrentLineNumber) + + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("Build number", self.FileName, self.CurrentLineNumber) + EfiSectionObj.BuildNum = self._Token + + if self._GetAlignment(): + if self._Token not in ALIGNMENTS: + raise Warning("Incorrect alignment '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + if self._Token == 'Auto' and (not SectionName == BINARY_FILE_TYPE_PE32) and (not SectionName == BINARY_FILE_TYPE_TE): + raise Warning("Auto alignment can only be used in PE32 or TE section ", self.FileName, self.CurrentLineNumber) + EfiSectionObj.Alignment = self._Token + + if self._IsKeyword('RELOCS_STRIPPED') or self._IsKeyword('RELOCS_RETAINED'): + if self._SectionCouldHaveRelocFlag(EfiSectionObj.SectionType): + if self._Token == 'RELOCS_STRIPPED': + EfiSectionObj.KeepReloc = False + else: + EfiSectionObj.KeepReloc = True + if Obj.KeepReloc is not None and Obj.KeepReloc != EfiSectionObj.KeepReloc: + raise Warning("Section type %s has reloc strip flag conflict with Rule" % EfiSectionObj.SectionType, self.FileName, self.CurrentLineNumber) + else: + raise Warning("Section type %s could not have reloc strip flag" % EfiSectionObj.SectionType, self.FileName, self.CurrentLineNumber) + + + if self._IsToken(TAB_VALUE_SPLIT): + EfiSectionObj.FileExtension = self._GetFileExtension() + elif self._GetNextToken(): + if self._Token not in { + T_CHAR_BRACE_R, "COMPAT16", BINARY_FILE_TYPE_PE32, + BINARY_FILE_TYPE_PIC, BINARY_FILE_TYPE_TE, + "FV_IMAGE", "RAW", BINARY_FILE_TYPE_DXE_DEPEX, + BINARY_FILE_TYPE_UI, "VERSION", + BINARY_FILE_TYPE_PEI_DEPEX, BINARY_FILE_TYPE_GUID, + BINARY_FILE_TYPE_SMM_DEPEX}: + + if self._Token.startswith('PCD'): + self._UndoToken() + self._GetNextWord() + + if self._Token == 'PCD': + if not self._IsToken("("): + raise Warning.Expected("'('", self.FileName, self.CurrentLineNumber) + PcdPair = self._GetNextPcdSettings() + if not self._IsToken(")"): + raise Warning.Expected("')'", self.FileName, self.CurrentLineNumber) + self._Token = 'PCD('+PcdPair[1]+TAB_SPLIT+PcdPair[0]+')' + + EfiSectionObj.FileName = self._Token + + else: + self._UndoToken() + else: + raise Warning.Expected("section file name", self.FileName, self.CurrentLineNumber) + + Obj.SectionList.append(EfiSectionObj) + return True + + ## _RuleSectionCouldBeOptional() method + # + # Get whether a section could be optional + # + # @param SectionType The section type to check + # @retval True section could be optional + # @retval False section never optional + # + @staticmethod + def _RuleSectionCouldBeOptional(SectionType): + if SectionType in {BINARY_FILE_TYPE_DXE_DEPEX, BINARY_FILE_TYPE_UI, "VERSION", BINARY_FILE_TYPE_PEI_DEPEX, "RAW", BINARY_FILE_TYPE_SMM_DEPEX}: + return True + else: + return False + + ## _RuleSectionCouldHaveBuildNum() method + # + # Get whether a section could have build number information + # + # @param SectionType The section type to check + # @retval True section could have build number information + # @retval False section never have build number information + # + @staticmethod + def _RuleSectionCouldHaveBuildNum(SectionType): + if SectionType == "VERSION": + return True + else: + return False + + ## _RuleSectionCouldHaveString() method + # + # Get whether a section could have string + # + # @param SectionType The section type to check + # @retval True section could have string + # @retval False section never have string + # + @staticmethod + def _RuleSectionCouldHaveString(SectionType): + if SectionType in {BINARY_FILE_TYPE_UI, "VERSION"}: + return True + else: + return False + + ## _CheckRuleSectionFileType() method + # + # Get whether a section matches a file type + # + # @param self The object pointer + # @param SectionType The section type to check + # @param FileType The file type to check + # + def _CheckRuleSectionFileType(self, SectionType, FileType): + WarningString = "Incorrect section file type '%s'" + if SectionType == "COMPAT16": + if FileType not in {"COMPAT16", "SEC_COMPAT16"}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == BINARY_FILE_TYPE_PE32: + if FileType not in {BINARY_FILE_TYPE_PE32, "SEC_PE32"}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == BINARY_FILE_TYPE_PIC: + if FileType not in {BINARY_FILE_TYPE_PIC, BINARY_FILE_TYPE_PIC}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == BINARY_FILE_TYPE_TE: + if FileType not in {BINARY_FILE_TYPE_TE, "SEC_TE"}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == "RAW": + if FileType not in {BINARY_FILE_TYPE_BIN, "SEC_BIN", "RAW", "ASL", "ACPI"}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == BINARY_FILE_TYPE_DXE_DEPEX or SectionType == BINARY_FILE_TYPE_SMM_DEPEX: + if FileType not in {BINARY_FILE_TYPE_DXE_DEPEX, "SEC_DXE_DEPEX", BINARY_FILE_TYPE_SMM_DEPEX}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == BINARY_FILE_TYPE_UI: + if FileType not in {BINARY_FILE_TYPE_UI, "SEC_UI"}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == "VERSION": + if FileType not in {"VERSION", "SEC_VERSION"}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == BINARY_FILE_TYPE_PEI_DEPEX: + if FileType not in {BINARY_FILE_TYPE_PEI_DEPEX, "SEC_PEI_DEPEX"}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + elif SectionType == BINARY_FILE_TYPE_GUID: + if FileType not in {BINARY_FILE_TYPE_PE32, "SEC_GUID"}: + raise Warning(WarningString % FileType, self.FileName, self.CurrentLineNumber) + + ## _GetRuleEncapsulationSection() method + # + # Get encapsulation section for Rule + # + # @param self The object pointer + # @param theRule for whom section is got + # @retval True Successfully find section statement + # @retval False Not able to find section statement + # + def _GetRuleEncapsulationSection(self, theRule): + if self._IsKeyword("COMPRESS"): + Type = "PI_STD" + if self._IsKeyword("PI_STD") or self._IsKeyword("PI_NONE"): + Type = self._Token + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + + CompressSectionObj = CompressSection() + + CompressSectionObj.CompType = Type + # Recursive sections... + while True: + IsEncapsulate = self._GetRuleEncapsulationSection(CompressSectionObj) + IsLeaf = self._GetEfiSection(CompressSectionObj) + if not IsEncapsulate and not IsLeaf: + break + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + theRule.SectionList.append(CompressSectionObj) + + return True + + elif self._IsKeyword("GUIDED"): + GuidValue = None + if self._GetNextGuid(): + if self._Token in GlobalData.gGuidDict: + self._Token = GuidStructureStringToGuidString(GlobalData.gGuidDict[self._Token]).upper() + GuidValue = self._Token + + if self._IsKeyword("$(NAMED_GUID)"): + GuidValue = self._Token + + AttribDict = self._GetGuidAttrib() + + if not self._IsToken("{"): + raise Warning.ExpectedCurlyOpen(self.FileName, self.CurrentLineNumber) + GuidSectionObj = GuidSection() + GuidSectionObj.NameGuid = GuidValue + GuidSectionObj.SectionType = "GUIDED" + GuidSectionObj.ProcessRequired = AttribDict["PROCESSING_REQUIRED"] + GuidSectionObj.AuthStatusValid = AttribDict["AUTH_STATUS_VALID"] + GuidSectionObj.ExtraHeaderSize = AttribDict["EXTRA_HEADER_SIZE"] + + # Efi sections... + while True: + IsEncapsulate = self._GetRuleEncapsulationSection(GuidSectionObj) + IsLeaf = self._GetEfiSection(GuidSectionObj) + if not IsEncapsulate and not IsLeaf: + break + + if not self._IsToken(T_CHAR_BRACE_R): + raise Warning.ExpectedCurlyClose(self.FileName, self.CurrentLineNumber) + theRule.SectionList.append(GuidSectionObj) + + return True + + return False + + ## _GetOptionRom() method + # + # Get OptionROM section contents and store its data into OptionROM list of self.Profile + # + # @param self The object pointer + # @retval True Successfully find a OptionROM + # @retval False Not able to find a OptionROM + # + def _GetOptionRom(self): + if not self._GetNextToken(): + return False + + S = self._Token.upper() + if S.startswith(TAB_SECTION_START) and not S.startswith("[OPTIONROM."): + self.SectionParser(S) + self._UndoToken() + return False + + self._UndoToken() + if not self._IsToken("[OptionRom.", True): + raise Warning("Unknown Keyword '%s'" % self._Token, self.FileName, self.CurrentLineNumber) + + OptRomName = self._GetUiName() + + if not self._IsToken(TAB_SECTION_END): + raise Warning.ExpectedBracketClose(self.FileName, self.CurrentLineNumber) + + OptRomObj = OPTIONROM(OptRomName) + self.Profile.OptRomDict[OptRomName] = OptRomObj + + while True: + isInf = self._GetOptRomInfStatement(OptRomObj) + isFile = self._GetOptRomFileStatement(OptRomObj) + if not isInf and not isFile: + break + + return True + + ## _GetOptRomInfStatement() method + # + # Get INF statements + # + # @param self The object pointer + # @param Obj for whom inf statement is got + # @retval True Successfully find inf statement + # @retval False Not able to find inf statement + # + def _GetOptRomInfStatement(self, Obj): + if not self._IsKeyword("INF"): + return False + + ffsInf = OptRomInfStatement() + self._GetInfOptions(ffsInf) + + if not self._GetNextToken(): + raise Warning.Expected("INF file path", self.FileName, self.CurrentLineNumber) + ffsInf.InfFileName = self._Token + if ffsInf.InfFileName.replace(TAB_WORKSPACE, '').find('$') == -1: + #check for file path + ErrorCode, ErrorInfo = PathClass(NormPath(ffsInf.InfFileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + + NewFileName = ffsInf.InfFileName + if ffsInf.OverrideGuid: + NewFileName = ProcessDuplicatedInf(PathClass(ffsInf.InfFileName,GenFdsGlobalVariable.WorkSpaceDir), ffsInf.OverrideGuid, GenFdsGlobalVariable.WorkSpaceDir).Path + + if not NewFileName in self.Profile.InfList: + self.Profile.InfList.append(NewFileName) + FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber) + self.Profile.InfFileLineList.append(FileLineTuple) + if ffsInf.UseArch: + if ffsInf.UseArch not in self.Profile.InfDict: + self.Profile.InfDict[ffsInf.UseArch] = [ffsInf.InfFileName] + else: + self.Profile.InfDict[ffsInf.UseArch].append(ffsInf.InfFileName) + else: + self.Profile.InfDict['ArchTBD'].append(ffsInf.InfFileName) + + + self._GetOptRomOverrides (ffsInf) + + Obj.FfsList.append(ffsInf) + return True + + ## _GetOptRomOverrides() method + # + # Get overrides for OptROM INF & FILE + # + # @param self The object pointer + # @param FfsInfObj for whom overrides is got + # + def _GetOptRomOverrides(self, Obj): + if self._IsToken('{'): + Overrides = OverrideAttribs() + while True: + if self._IsKeyword("PCI_VENDOR_ID"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextHexNumber(): + raise Warning.Expected("Hex vendor id", self.FileName, self.CurrentLineNumber) + Overrides.PciVendorId = self._Token + continue + + if self._IsKeyword("PCI_CLASS_CODE"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextHexNumber(): + raise Warning.Expected("Hex class code", self.FileName, self.CurrentLineNumber) + Overrides.PciClassCode = self._Token + continue + + if self._IsKeyword("PCI_DEVICE_ID"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + # Get a list of PCI IDs + Overrides.PciDeviceId = "" + while (self._GetNextHexNumber()): + Overrides.PciDeviceId = "{} {}".format(Overrides.PciDeviceId, self._Token) + if not Overrides.PciDeviceId: + raise Warning.Expected("one or more Hex device ids", self.FileName, self.CurrentLineNumber) + continue + + if self._IsKeyword("PCI_REVISION"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextHexNumber(): + raise Warning.Expected("Hex revision", self.FileName, self.CurrentLineNumber) + Overrides.PciRevision = self._Token + continue + + if self._IsKeyword("PCI_COMPRESS"): + if not self._IsToken(TAB_EQUAL_SPLIT): + raise Warning.ExpectedEquals(self.FileName, self.CurrentLineNumber) + if not self._GetNextToken(): + raise Warning.Expected("TRUE/FALSE for compress", self.FileName, self.CurrentLineNumber) + Overrides.NeedCompress = self._Token.upper() == 'TRUE' + continue + + if self._IsToken(T_CHAR_BRACE_R): + break + else: + EdkLogger.error("FdfParser", FORMAT_INVALID, File=self.FileName, Line=self.CurrentLineNumber) + + Obj.OverrideAttribs = Overrides + + ## _GetOptRomFileStatement() method + # + # Get FILE statements + # + # @param self The object pointer + # @param Obj for whom FILE statement is got + # @retval True Successfully find FILE statement + # @retval False Not able to find FILE statement + # + def _GetOptRomFileStatement(self, Obj): + if not self._IsKeyword("FILE"): + return False + + FfsFileObj = OptRomFileStatement() + + if not self._IsKeyword("EFI") and not self._IsKeyword(BINARY_FILE_TYPE_BIN): + raise Warning.Expected("Binary type (EFI/BIN)", self.FileName, self.CurrentLineNumber) + FfsFileObj.FileType = self._Token + + if not self._GetNextToken(): + raise Warning.Expected("File path", self.FileName, self.CurrentLineNumber) + FfsFileObj.FileName = self._Token + if FfsFileObj.FileName.replace(TAB_WORKSPACE, '').find('$') == -1: + #check for file path + ErrorCode, ErrorInfo = PathClass(NormPath(FfsFileObj.FileName), GenFdsGlobalVariable.WorkSpaceDir).Validate() + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + + if FfsFileObj.FileType == 'EFI': + self._GetOptRomOverrides(FfsFileObj) + + Obj.FfsList.append(FfsFileObj) + + return True + + ## _GetCapInFd() method + # + # Get Cap list contained in FD + # + # @param self The object pointer + # @param FdName FD name + # @retval CapList List of Capsule in FD + # + def _GetCapInFd (self, FdName): + CapList = [] + if FdName.upper() in self.Profile.FdDict: + FdObj = self.Profile.FdDict[FdName.upper()] + for elementRegion in FdObj.RegionList: + if elementRegion.RegionType == 'CAPSULE': + for elementRegionData in elementRegion.RegionDataList: + if elementRegionData.endswith(".cap"): + continue + if elementRegionData is not None and elementRegionData.upper() not in CapList: + CapList.append(elementRegionData.upper()) + return CapList + + ## _GetReferencedFdCapTuple() method + # + # Get FV and FD list referenced by a capsule image + # + # @param self The object pointer + # @param CapObj Capsule section to be searched + # @param RefFdList referenced FD by section + # @param RefFvList referenced FV by section + # + def _GetReferencedFdCapTuple(self, CapObj, RefFdList = [], RefFvList = []): + for CapsuleDataObj in CapObj.CapsuleDataList: + if hasattr(CapsuleDataObj, 'FvName') and CapsuleDataObj.FvName is not None and CapsuleDataObj.FvName.upper() not in RefFvList: + RefFvList.append (CapsuleDataObj.FvName.upper()) + elif hasattr(CapsuleDataObj, 'FdName') and CapsuleDataObj.FdName is not None and CapsuleDataObj.FdName.upper() not in RefFdList: + RefFdList.append (CapsuleDataObj.FdName.upper()) + elif CapsuleDataObj.Ffs is not None: + if isinstance(CapsuleDataObj.Ffs, FileStatement): + if CapsuleDataObj.Ffs.FvName is not None and CapsuleDataObj.Ffs.FvName.upper() not in RefFvList: + RefFvList.append(CapsuleDataObj.Ffs.FvName.upper()) + elif CapsuleDataObj.Ffs.FdName is not None and CapsuleDataObj.Ffs.FdName.upper() not in RefFdList: + RefFdList.append(CapsuleDataObj.Ffs.FdName.upper()) + else: + self._GetReferencedFdFvTupleFromSection(CapsuleDataObj.Ffs, RefFdList, RefFvList) + + ## _GetFvInFd() method + # + # Get FV list contained in FD + # + # @param self The object pointer + # @param FdName FD name + # @retval FvList list of FV in FD + # + def _GetFvInFd (self, FdName): + FvList = [] + if FdName.upper() in self.Profile.FdDict: + FdObj = self.Profile.FdDict[FdName.upper()] + for elementRegion in FdObj.RegionList: + if elementRegion.RegionType == BINARY_FILE_TYPE_FV: + for elementRegionData in elementRegion.RegionDataList: + if elementRegionData.endswith(".fv"): + continue + if elementRegionData is not None and elementRegionData.upper() not in FvList: + FvList.append(elementRegionData.upper()) + return FvList + + ## _GetReferencedFdFvTuple() method + # + # Get FD and FV list referenced by a FFS file + # + # @param self The object pointer + # @param FfsFile contains sections to be searched + # @param RefFdList referenced FD by section + # @param RefFvList referenced FV by section + # + def _GetReferencedFdFvTuple(self, FvObj, RefFdList = [], RefFvList = []): + for FfsObj in FvObj.FfsList: + if isinstance(FfsObj, FileStatement): + if FfsObj.FvName is not None and FfsObj.FvName.upper() not in RefFvList: + RefFvList.append(FfsObj.FvName.upper()) + elif FfsObj.FdName is not None and FfsObj.FdName.upper() not in RefFdList: + RefFdList.append(FfsObj.FdName.upper()) + else: + self._GetReferencedFdFvTupleFromSection(FfsObj, RefFdList, RefFvList) + + ## _GetReferencedFdFvTupleFromSection() method + # + # Get FD and FV list referenced by a FFS section + # + # @param self The object pointer + # @param FfsFile contains sections to be searched + # @param FdList referenced FD by section + # @param FvList referenced FV by section + # + def _GetReferencedFdFvTupleFromSection(self, FfsFile, FdList = [], FvList = []): + SectionStack = list(FfsFile.SectionList) + while SectionStack != []: + SectionObj = SectionStack.pop() + if isinstance(SectionObj, FvImageSection): + if SectionObj.FvName is not None and SectionObj.FvName.upper() not in FvList: + FvList.append(SectionObj.FvName.upper()) + if SectionObj.Fv is not None and SectionObj.Fv.UiFvName is not None and SectionObj.Fv.UiFvName.upper() not in FvList: + FvList.append(SectionObj.Fv.UiFvName.upper()) + self._GetReferencedFdFvTuple(SectionObj.Fv, FdList, FvList) + + if isinstance(SectionObj, CompressSection) or isinstance(SectionObj, GuidSection): + SectionStack.extend(SectionObj.SectionList) + + ## CycleReferenceCheck() method + # + # Check whether cycle reference exists in FDF + # + # @param self The object pointer + # @retval True cycle reference exists + # @retval False Not exists cycle reference + # + def CycleReferenceCheck(self): + # + # Check the cycle between FV and FD image + # + MaxLength = len (self.Profile.FvDict) + for FvName in self.Profile.FvDict: + LogStr = "\nCycle Reference Checking for FV: %s\n" % FvName + RefFvStack = set(FvName) + FdAnalyzedList = set() + + Index = 0 + while RefFvStack and Index < MaxLength: + Index = Index + 1 + FvNameFromStack = RefFvStack.pop() + if FvNameFromStack.upper() in self.Profile.FvDict: + FvObj = self.Profile.FvDict[FvNameFromStack.upper()] + else: + continue + + RefFdList = [] + RefFvList = [] + self._GetReferencedFdFvTuple(FvObj, RefFdList, RefFvList) + + for RefFdName in RefFdList: + if RefFdName in FdAnalyzedList: + continue + + LogStr += "FV %s contains FD %s\n" % (FvNameFromStack, RefFdName) + FvInFdList = self._GetFvInFd(RefFdName) + if FvInFdList != []: + for FvNameInFd in FvInFdList: + LogStr += "FD %s contains FV %s\n" % (RefFdName, FvNameInFd) + if FvNameInFd not in RefFvStack: + RefFvStack.add(FvNameInFd) + + if FvName in RefFvStack or FvNameFromStack in RefFvStack: + EdkLogger.info(LogStr) + return True + FdAnalyzedList.add(RefFdName) + + for RefFvName in RefFvList: + LogStr += "FV %s contains FV %s\n" % (FvNameFromStack, RefFvName) + if RefFvName not in RefFvStack: + RefFvStack.add(RefFvName) + + if FvName in RefFvStack or FvNameFromStack in RefFvStack: + EdkLogger.info(LogStr) + return True + + # + # Check the cycle between Capsule and FD image + # + MaxLength = len (self.Profile.CapsuleDict) + for CapName in self.Profile.CapsuleDict: + # + # Capsule image to be checked. + # + LogStr = "\n\n\nCycle Reference Checking for Capsule: %s\n" % CapName + RefCapStack = {CapName} + FdAnalyzedList = set() + FvAnalyzedList = set() + + Index = 0 + while RefCapStack and Index < MaxLength: + Index = Index + 1 + CapNameFromStack = RefCapStack.pop() + if CapNameFromStack.upper() in self.Profile.CapsuleDict: + CapObj = self.Profile.CapsuleDict[CapNameFromStack.upper()] + else: + continue + + RefFvList = [] + RefFdList = [] + self._GetReferencedFdCapTuple(CapObj, RefFdList, RefFvList) + + FvListLength = 0 + FdListLength = 0 + while FvListLength < len (RefFvList) or FdListLength < len (RefFdList): + for RefFdName in RefFdList: + if RefFdName in FdAnalyzedList: + continue + + LogStr += "Capsule %s contains FD %s\n" % (CapNameFromStack, RefFdName) + for CapNameInFd in self._GetCapInFd(RefFdName): + LogStr += "FD %s contains Capsule %s\n" % (RefFdName, CapNameInFd) + if CapNameInFd not in RefCapStack: + RefCapStack.append(CapNameInFd) + + if CapName in RefCapStack or CapNameFromStack in RefCapStack: + EdkLogger.info(LogStr) + return True + + for FvNameInFd in self._GetFvInFd(RefFdName): + LogStr += "FD %s contains FV %s\n" % (RefFdName, FvNameInFd) + if FvNameInFd not in RefFvList: + RefFvList.append(FvNameInFd) + + FdAnalyzedList.add(RefFdName) + # + # the number of the parsed FV and FD image + # + FvListLength = len (RefFvList) + FdListLength = len (RefFdList) + for RefFvName in RefFvList: + if RefFvName in FvAnalyzedList: + continue + LogStr += "Capsule %s contains FV %s\n" % (CapNameFromStack, RefFvName) + if RefFvName.upper() in self.Profile.FvDict: + FvObj = self.Profile.FvDict[RefFvName.upper()] + else: + continue + self._GetReferencedFdFvTuple(FvObj, RefFdList, RefFvList) + FvAnalyzedList.add(RefFvName) + + return False + + def GetAllIncludedFile (self): + global AllIncludeFileList + return AllIncludeFileList + +if __name__ == "__main__": + import sys + try: + test_file = sys.argv[1] + except IndexError as v: + print("Usage: %s filename" % sys.argv[0]) + sys.exit(1) + + parser = FdfParser(test_file) + try: + parser.ParseFile() + parser.CycleReferenceCheck() + except Warning as X: + print(str(X)) + else: + print("Success!") + diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/Ffs.py b/roms/edk2/BaseTools/Source/Python/GenFds/Ffs.py new file mode 100644 index 000000000..4e58df279 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/Ffs.py @@ -0,0 +1,49 @@ +## @file +# process FFS generation +# +# Copyright (c) 2007-2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from Common.DataType import * + +# mapping between FILE type in FDF and file type for GenFfs +FdfFvFileTypeToFileType = { + SUP_MODULE_SEC : 'EFI_FV_FILETYPE_SECURITY_CORE', + SUP_MODULE_PEI_CORE : 'EFI_FV_FILETYPE_PEI_CORE', + SUP_MODULE_PEIM : 'EFI_FV_FILETYPE_PEIM', + SUP_MODULE_DXE_CORE : 'EFI_FV_FILETYPE_DXE_CORE', + 'FREEFORM' : 'EFI_FV_FILETYPE_FREEFORM', + 'DRIVER' : 'EFI_FV_FILETYPE_DRIVER', + 'APPLICATION' : 'EFI_FV_FILETYPE_APPLICATION', + 'FV_IMAGE' : 'EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE', + 'RAW' : 'EFI_FV_FILETYPE_RAW', + 'PEI_DXE_COMBO' : 'EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER', + 'SMM' : 'EFI_FV_FILETYPE_SMM', + SUP_MODULE_SMM_CORE : 'EFI_FV_FILETYPE_SMM_CORE', + SUP_MODULE_MM_STANDALONE : 'EFI_FV_FILETYPE_MM_STANDALONE', + SUP_MODULE_MM_CORE_STANDALONE : 'EFI_FV_FILETYPE_MM_CORE_STANDALONE' +} + +# mapping between section type in FDF and file suffix +SectionSuffix = { + BINARY_FILE_TYPE_PE32 : '.pe32', + BINARY_FILE_TYPE_PIC : '.pic', + BINARY_FILE_TYPE_TE : '.te', + BINARY_FILE_TYPE_DXE_DEPEX : '.dpx', + 'VERSION' : '.ver', + BINARY_FILE_TYPE_UI : '.ui', + 'COMPAT16' : '.com16', + 'RAW' : '.raw', + 'FREEFORM_SUBTYPE_GUID': '.guid', + 'SUBTYPE_GUID' : '.guid', + 'FV_IMAGE' : 'fv.sec', + 'COMPRESS' : '.com', + 'GUIDED' : '.guided', + BINARY_FILE_TYPE_PEI_DEPEX : '.dpx', + BINARY_FILE_TYPE_SMM_DEPEX : '.dpx' +} diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/FfsFileStatement.py b/roms/edk2/BaseTools/Source/Python/GenFds/FfsFileStatement.py new file mode 100644 index 000000000..9fb62b0a9 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/FfsFileStatement.py @@ -0,0 +1,172 @@ +## @file +# process FFS generation from FILE statement +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from io import BytesIO +from struct import pack +from CommonDataClass.FdfClass import FileStatementClassObject +from Common import EdkLogger +from Common.BuildToolError import GENFDS_ERROR +from Common.Misc import GuidStructureByteArrayToGuidString, SaveFileOnChange +import Common.LongFilePathOs as os +from .GuidSection import GuidSection +from .FvImageSection import FvImageSection +from .Ffs import FdfFvFileTypeToFileType +from .GenFdsGlobalVariable import GenFdsGlobalVariable + +## generate FFS from FILE +# +# +class FileStatement (FileStatementClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + FileStatementClassObject.__init__(self) + self.CurrentLineNum = None + self.CurrentLineContent = None + self.FileName = None + self.InfFileName = None + self.SubAlignment = None + + ## GenFfs() method + # + # Generate FFS + # + # @param self The object pointer + # @param Dict dictionary contains macro and value pair + # @param FvChildAddr Array of the inside FvImage base address + # @param FvParentAddr Parent Fv base address + # @retval string Generated FFS file name + # + def GenFfs(self, Dict = None, FvChildAddr=[], FvParentAddr=None, IsMakefile=False, FvName=None): + + if self.NameGuid and self.NameGuid.startswith('PCD('): + PcdValue = GenFdsGlobalVariable.GetPcdValue(self.NameGuid) + if len(PcdValue) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, '%s NOT defined.' \ + % (self.NameGuid)) + if PcdValue.startswith('{'): + PcdValue = GuidStructureByteArrayToGuidString(PcdValue) + RegistryGuidStr = PcdValue + if len(RegistryGuidStr) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, 'GUID value for %s in wrong format.' \ + % (self.NameGuid)) + self.NameGuid = RegistryGuidStr + + Str = self.NameGuid + if FvName: + Str += FvName + OutputDir = os.path.join(GenFdsGlobalVariable.FfsDir, Str) + if not os.path.exists(OutputDir): + os.makedirs(OutputDir) + + if Dict is None: + Dict = {} + + Dict.update(self.DefineVarDict) + SectionAlignments = None + if self.FvName: + Buffer = BytesIO() + if self.FvName.upper() not in GenFdsGlobalVariable.FdfParser.Profile.FvDict: + EdkLogger.error("GenFds", GENFDS_ERROR, "FV (%s) is NOT described in FDF file!" % (self.FvName)) + Fv = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(self.FvName.upper()) + FileName = Fv.AddToBuffer(Buffer) + SectionFiles = [FileName] + + elif self.FdName: + if self.FdName.upper() not in GenFdsGlobalVariable.FdfParser.Profile.FdDict: + EdkLogger.error("GenFds", GENFDS_ERROR, "FD (%s) is NOT described in FDF file!" % (self.FdName)) + Fd = GenFdsGlobalVariable.FdfParser.Profile.FdDict.get(self.FdName.upper()) + FileName = Fd.GenFd() + SectionFiles = [FileName] + + elif self.FileName: + if hasattr(self, 'FvFileType') and self.FvFileType == 'RAW': + if isinstance(self.FileName, list) and isinstance(self.SubAlignment, list) and len(self.FileName) == len(self.SubAlignment): + FileContent = BytesIO() + MaxAlignIndex = 0 + MaxAlignValue = 1 + for Index, File in enumerate(self.FileName): + try: + f = open(File, 'rb') + except: + GenFdsGlobalVariable.ErrorLogger("Error opening RAW file %s." % (File)) + Content = f.read() + f.close() + AlignValue = 1 + if self.SubAlignment[Index]: + AlignValue = GenFdsGlobalVariable.GetAlignment(self.SubAlignment[Index]) + if AlignValue > MaxAlignValue: + MaxAlignIndex = Index + MaxAlignValue = AlignValue + FileContent.write(Content) + if len(FileContent.getvalue()) % AlignValue != 0: + Size = AlignValue - len(FileContent.getvalue()) % AlignValue + for i in range(0, Size): + FileContent.write(pack('B', 0xFF)) + + if FileContent.getvalue() != b'': + OutputRAWFile = os.path.join(GenFdsGlobalVariable.FfsDir, self.NameGuid, self.NameGuid + '.raw') + SaveFileOnChange(OutputRAWFile, FileContent.getvalue(), True) + self.FileName = OutputRAWFile + self.SubAlignment = self.SubAlignment[MaxAlignIndex] + + if self.Alignment and self.SubAlignment: + if GenFdsGlobalVariable.GetAlignment (self.Alignment) < GenFdsGlobalVariable.GetAlignment (self.SubAlignment): + self.Alignment = self.SubAlignment + elif self.SubAlignment: + self.Alignment = self.SubAlignment + + self.FileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FileName) + #Replace $(SAPCE) with real space + self.FileName = self.FileName.replace('$(SPACE)', ' ') + SectionFiles = [GenFdsGlobalVariable.MacroExtend(self.FileName, Dict)] + + else: + SectionFiles = [] + Index = 0 + SectionAlignments = [] + for section in self.SectionList: + Index = Index + 1 + SecIndex = '%d' %Index + # process the inside FvImage from FvSection or GuidSection + if FvChildAddr != []: + if isinstance(section, FvImageSection): + section.FvAddr = FvChildAddr.pop(0) + elif isinstance(section, GuidSection): + section.FvAddr = FvChildAddr + if FvParentAddr and isinstance(section, GuidSection): + section.FvParentAddr = FvParentAddr + + if self.KeepReloc == False: + section.KeepReloc = False + sectList, align = section.GenSection(OutputDir, self.NameGuid, SecIndex, self.KeyStringList, None, Dict) + if sectList != []: + for sect in sectList: + SectionFiles.append(sect) + SectionAlignments.append(align) + + # + # Prepare the parameter + # + FfsFileOutput = os.path.join(OutputDir, self.NameGuid + '.ffs') + GenFdsGlobalVariable.GenerateFfs(FfsFileOutput, SectionFiles, + FdfFvFileTypeToFileType.get(self.FvFileType), + self.NameGuid, + Fixed=self.Fixed, + CheckSum=self.CheckSum, + Align=self.Alignment, + SectionAlign=SectionAlignments + ) + + return FfsFileOutput diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/FfsInfStatement.py b/roms/edk2/BaseTools/Source/Python/GenFds/FfsInfStatement.py new file mode 100644 index 000000000..20573ca28 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/FfsInfStatement.py @@ -0,0 +1,1128 @@ +## @file +# process FFS generation from INF statement +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2014-2016 Hewlett-Packard Development Company, L.P.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Rule +import Common.LongFilePathOs as os +from io import BytesIO +from struct import * +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from .Ffs import SectionSuffix,FdfFvFileTypeToFileType +import subprocess +import sys +from . import Section +from . import RuleSimpleFile +from . import RuleComplexFile +from CommonDataClass.FdfClass import FfsInfStatementClassObject +from Common.MultipleWorkspace import MultipleWorkspace as mws +from Common.DataType import SUP_MODULE_USER_DEFINED +from Common.DataType import SUP_MODULE_HOST_APPLICATION +from Common.StringUtils import * +from Common.Misc import PathClass +from Common.Misc import GuidStructureByteArrayToGuidString +from Common.Misc import ProcessDuplicatedInf +from Common.Misc import GetVariableOffset +from Common import EdkLogger +from Common.BuildToolError import * +from .GuidSection import GuidSection +from .FvImageSection import FvImageSection +from Common.Misc import PeImageClass +from AutoGen.GenDepex import DependencyExpression +from PatchPcdValue.PatchPcdValue import PatchBinaryFile +from Common.LongFilePathSupport import CopyLongFilePath +from Common.LongFilePathSupport import OpenLongFilePath as open +import Common.GlobalData as GlobalData +from .DepexSection import DepexSection +from Common.Misc import SaveFileOnChange +from Common.Expression import * +from Common.DataType import * + +## generate FFS from INF +# +# +class FfsInfStatement(FfsInfStatementClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + FfsInfStatementClassObject.__init__(self) + self.TargetOverrideList = [] + self.ShadowFromInfFile = None + self.KeepRelocFromRule = None + self.InDsc = True + self.OptRomDefs = {} + self.PiSpecVersion = '0x00000000' + self.InfModule = None + self.FinalTargetSuffixMap = {} + self.CurrentLineNum = None + self.CurrentLineContent = None + self.FileName = None + self.InfFileName = None + self.OverrideGuid = None + self.PatchedBinFile = '' + self.MacroDict = {} + self.Depex = False + + ## GetFinalTargetSuffixMap() method + # + # Get final build target list + def GetFinalTargetSuffixMap(self): + if not self.InfModule or not self.CurrentArch: + return [] + if not self.FinalTargetSuffixMap: + FinalBuildTargetList = GenFdsGlobalVariable.GetModuleCodaTargetList(self.InfModule, self.CurrentArch) + for File in FinalBuildTargetList: + self.FinalTargetSuffixMap.setdefault(os.path.splitext(File)[1], []).append(File) + + # Check if current INF module has DEPEX + if '.depex' not in self.FinalTargetSuffixMap and self.InfModule.ModuleType != SUP_MODULE_USER_DEFINED and self.InfModule.ModuleType != SUP_MODULE_HOST_APPLICATION \ + and not self.InfModule.DxsFile and not self.InfModule.LibraryClass: + ModuleType = self.InfModule.ModuleType + PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + + if ModuleType != SUP_MODULE_USER_DEFINED and ModuleType != SUP_MODULE_HOST_APPLICATION: + for LibraryClass in PlatformDataBase.LibraryClasses.GetKeys(): + if LibraryClass.startswith("NULL") and PlatformDataBase.LibraryClasses[LibraryClass, ModuleType]: + self.InfModule.LibraryClasses[LibraryClass] = PlatformDataBase.LibraryClasses[LibraryClass, ModuleType] + + StrModule = str(self.InfModule) + PlatformModule = None + if StrModule in PlatformDataBase.Modules: + PlatformModule = PlatformDataBase.Modules[StrModule] + for LibraryClass in PlatformModule.LibraryClasses: + if LibraryClass.startswith("NULL"): + self.InfModule.LibraryClasses[LibraryClass] = PlatformModule.LibraryClasses[LibraryClass] + + DependencyList = [self.InfModule] + LibraryInstance = {} + DepexList = [] + while len(DependencyList) > 0: + Module = DependencyList.pop(0) + if not Module: + continue + for Dep in Module.Depex[self.CurrentArch, ModuleType]: + if DepexList != []: + DepexList.append('AND') + DepexList.append('(') + DepexList.extend(Dep) + if DepexList[-1] == 'END': # no need of a END at this time + DepexList.pop() + DepexList.append(')') + if 'BEFORE' in DepexList or 'AFTER' in DepexList: + break + for LibName in Module.LibraryClasses: + if LibName in LibraryInstance: + continue + if PlatformModule and LibName in PlatformModule.LibraryClasses: + LibraryPath = PlatformModule.LibraryClasses[LibName] + else: + LibraryPath = PlatformDataBase.LibraryClasses[LibName, ModuleType] + if not LibraryPath: + LibraryPath = Module.LibraryClasses[LibName] + if not LibraryPath: + continue + LibraryModule = GenFdsGlobalVariable.WorkSpace.BuildObject[LibraryPath, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + LibraryInstance[LibName] = LibraryModule + DependencyList.append(LibraryModule) + if DepexList: + Dpx = DependencyExpression(DepexList, ModuleType, True) + if len(Dpx.PostfixNotation) != 0: + # It means this module has DEPEX + self.FinalTargetSuffixMap['.depex'] = [os.path.join(self.EfiOutputPath, self.BaseName) + '.depex'] + return self.FinalTargetSuffixMap + + ## __InfParse() method + # + # Parse inf file to get module information + # + # @param self The object pointer + # @param Dict dictionary contains macro and value pair + # + def __InfParse__(self, Dict = None, IsGenFfs=False): + + GenFdsGlobalVariable.VerboseLogger( " Begine parsing INf file : %s" %self.InfFileName) + + self.InfFileName = self.InfFileName.replace('$(WORKSPACE)', '') + if len(self.InfFileName) > 1 and self.InfFileName[0] == '\\' and self.InfFileName[1] == '\\': + pass + elif self.InfFileName[0] == '\\' or self.InfFileName[0] == '/' : + self.InfFileName = self.InfFileName[1:] + + if self.InfFileName.find('$') == -1: + InfPath = NormPath(self.InfFileName) + if not os.path.exists(InfPath): + InfPath = GenFdsGlobalVariable.ReplaceWorkspaceMacro(InfPath) + if not os.path.exists(InfPath): + EdkLogger.error("GenFds", GENFDS_ERROR, "Non-existant Module %s !" % (self.InfFileName)) + + self.CurrentArch = self.GetCurrentArch() + # + # Get the InfClass object + # + + PathClassObj = PathClass(self.InfFileName, GenFdsGlobalVariable.WorkSpaceDir) + ErrorCode, ErrorInfo = PathClassObj.Validate(".inf") + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + + # + # Cache lower case version of INF path before processing FILE_GUID override + # + InfLowerPath = str(PathClassObj).lower() + if self.OverrideGuid: + PathClassObj = ProcessDuplicatedInf(PathClassObj, self.OverrideGuid, GenFdsGlobalVariable.WorkSpaceDir) + if self.CurrentArch is not None: + + Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClassObj, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + # + # Set Ffs BaseName, ModuleGuid, ModuleType, Version, OutputPath + # + self.BaseName = Inf.BaseName + self.ModuleGuid = Inf.Guid + self.ModuleType = Inf.ModuleType + if Inf.Specification is not None and 'PI_SPECIFICATION_VERSION' in Inf.Specification: + self.PiSpecVersion = Inf.Specification['PI_SPECIFICATION_VERSION'] + if Inf.AutoGenVersion < 0x00010005: + self.ModuleType = Inf.ComponentType + self.VersionString = Inf.Version + self.BinFileList = Inf.Binaries + self.SourceFileList = Inf.Sources + if self.KeepReloc is None and Inf.Shadow: + self.ShadowFromInfFile = Inf.Shadow + + else: + Inf = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClassObj, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + self.BaseName = Inf.BaseName + self.ModuleGuid = Inf.Guid + self.ModuleType = Inf.ModuleType + if Inf.Specification is not None and 'PI_SPECIFICATION_VERSION' in Inf.Specification: + self.PiSpecVersion = Inf.Specification['PI_SPECIFICATION_VERSION'] + self.VersionString = Inf.Version + self.BinFileList = Inf.Binaries + self.SourceFileList = Inf.Sources + if self.BinFileList == []: + EdkLogger.error("GenFds", GENFDS_ERROR, + "INF %s specified in FDF could not be found in build ARCH %s!" \ + % (self.InfFileName, GenFdsGlobalVariable.ArchList)) + + if self.OverrideGuid: + self.ModuleGuid = self.OverrideGuid + + if len(self.SourceFileList) != 0 and not self.InDsc: + EdkLogger.warn("GenFds", GENFDS_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % (self.InfFileName)) + + if self.ModuleType == SUP_MODULE_SMM_CORE and int(self.PiSpecVersion, 16) < 0x0001000A: + EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "SMM_CORE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x0001000A", File=self.InfFileName) + + if self.ModuleType == SUP_MODULE_MM_CORE_STANDALONE and int(self.PiSpecVersion, 16) < 0x00010032: + EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "MM_CORE_STANDALONE module type can't be used in the module with PI_SPECIFICATION_VERSION less than 0x00010032", File=self.InfFileName) + + if Inf._Defs is not None and len(Inf._Defs) > 0: + self.OptRomDefs.update(Inf._Defs) + + self.PatchPcds = [] + InfPcds = Inf.Pcds + Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, self.CurrentArch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + FdfPcdDict = GenFdsGlobalVariable.FdfParser.Profile.PcdDict + PlatformPcds = Platform.Pcds + + # Workaround here: both build and GenFds tool convert the workspace path to lower case + # But INF file path in FDF and DSC file may have real case characters. + # Try to convert the path to lower case to see if PCDs value are override by DSC. + DscModules = {} + for DscModule in Platform.Modules: + DscModules[str(DscModule).lower()] = Platform.Modules[DscModule] + for PcdKey in InfPcds: + Pcd = InfPcds[PcdKey] + if not hasattr(Pcd, 'Offset'): + continue + if Pcd.Type != TAB_PCDS_PATCHABLE_IN_MODULE: + continue + # Override Patchable PCD value by the value from DSC + PatchPcd = None + if InfLowerPath in DscModules and PcdKey in DscModules[InfLowerPath].Pcds: + PatchPcd = DscModules[InfLowerPath].Pcds[PcdKey] + elif PcdKey in Platform.Pcds: + PatchPcd = Platform.Pcds[PcdKey] + DscOverride = False + if PatchPcd and Pcd.Type == PatchPcd.Type: + DefaultValue = PatchPcd.DefaultValue + DscOverride = True + + # Override Patchable PCD value by the value from FDF + FdfOverride = False + if PcdKey in FdfPcdDict: + DefaultValue = FdfPcdDict[PcdKey] + FdfOverride = True + + # Override Patchable PCD value by the value from Build Option + BuildOptionOverride = False + if GlobalData.BuildOptionPcd: + for pcd in GlobalData.BuildOptionPcd: + if PcdKey == (pcd[1], pcd[0]): + if pcd[2]: + continue + DefaultValue = pcd[3] + BuildOptionOverride = True + break + + if not DscOverride and not FdfOverride and not BuildOptionOverride: + continue + + # Support Flexible PCD format + if DefaultValue: + try: + DefaultValue = ValueExpressionEx(DefaultValue, Pcd.DatumType, Platform._GuidDict)(True) + except BadExpression: + EdkLogger.error("GenFds", GENFDS_ERROR, 'PCD [%s.%s] Value "%s"' %(Pcd.TokenSpaceGuidCName, Pcd.TokenCName, DefaultValue), File=self.InfFileName) + + if Pcd.InfDefaultValue: + try: + Pcd.InfDefaultValue = ValueExpressionEx(Pcd.InfDefaultValue, Pcd.DatumType, Platform._GuidDict)(True) + except BadExpression: + EdkLogger.error("GenFds", GENFDS_ERROR, 'PCD [%s.%s] Value "%s"' %(Pcd.TokenSpaceGuidCName, Pcd.TokenCName, Pcd.DefaultValue), File=self.InfFileName) + + # Check value, if value are equal, no need to patch + if Pcd.DatumType == TAB_VOID: + if Pcd.InfDefaultValue == DefaultValue or not DefaultValue: + continue + # Get the string size from FDF or DSC + if DefaultValue[0] == 'L': + # Remove L"", but the '\0' must be appended + MaxDatumSize = str((len(DefaultValue) - 2) * 2) + elif DefaultValue[0] == '{': + MaxDatumSize = str(len(DefaultValue.split(','))) + else: + MaxDatumSize = str(len(DefaultValue) - 1) + if DscOverride: + Pcd.MaxDatumSize = PatchPcd.MaxDatumSize + # If no defined the maximum size in DSC, try to get current size from INF + if not Pcd.MaxDatumSize: + Pcd.MaxDatumSize = str(len(Pcd.InfDefaultValue.split(','))) + else: + Base1 = Base2 = 10 + if Pcd.InfDefaultValue.upper().startswith('0X'): + Base1 = 16 + if DefaultValue.upper().startswith('0X'): + Base2 = 16 + try: + PcdValueInImg = int(Pcd.InfDefaultValue, Base1) + PcdValueInDscOrFdf = int(DefaultValue, Base2) + if PcdValueInImg == PcdValueInDscOrFdf: + continue + except: + continue + # Check the Pcd size and data type + if Pcd.DatumType == TAB_VOID: + if int(MaxDatumSize) > int(Pcd.MaxDatumSize): + EdkLogger.error("GenFds", GENFDS_ERROR, "The size of VOID* type PCD '%s.%s' exceeds its maximum size %d bytes." \ + % (Pcd.TokenSpaceGuidCName, Pcd.TokenCName, int(MaxDatumSize) - int(Pcd.MaxDatumSize))) + else: + if PcdValueInDscOrFdf > MAX_VAL_TYPE[Pcd.DatumType] \ + or PcdValueInImg > MAX_VAL_TYPE[Pcd.DatumType]: + EdkLogger.error("GenFds", GENFDS_ERROR, "The size of %s type PCD '%s.%s' doesn't match its data type." \ + % (Pcd.DatumType, Pcd.TokenSpaceGuidCName, Pcd.TokenCName)) + self.PatchPcds.append((Pcd, DefaultValue)) + + self.InfModule = Inf + self.PcdIsDriver = Inf.PcdIsDriver + self.IsBinaryModule = Inf.IsBinaryModule + if len(Inf.Depex.data) > 0 and len(Inf.DepexExpression.data) > 0: + self.Depex = True + + GenFdsGlobalVariable.VerboseLogger("BaseName : %s" % self.BaseName) + GenFdsGlobalVariable.VerboseLogger("ModuleGuid : %s" % self.ModuleGuid) + GenFdsGlobalVariable.VerboseLogger("ModuleType : %s" % self.ModuleType) + GenFdsGlobalVariable.VerboseLogger("VersionString : %s" % self.VersionString) + GenFdsGlobalVariable.VerboseLogger("InfFileName :%s" % self.InfFileName) + + # + # Set OutputPath = ${WorkSpace}\Build\Fv\Ffs\${ModuleGuid}+ ${ModuleName}\ + # + if IsGenFfs: + Rule = self.__GetRule__() + if GlobalData.gGuidPatternEnd.match(Rule.NameGuid): + self.ModuleGuid = Rule.NameGuid + self.OutputPath = os.path.join(GenFdsGlobalVariable.FfsDir, \ + self.ModuleGuid + self.BaseName) + if not os.path.exists(self.OutputPath) : + os.makedirs(self.OutputPath) + + self.EfiOutputPath, self.EfiDebugPath = self.__GetEFIOutPutPath__() + GenFdsGlobalVariable.VerboseLogger( "ModuelEFIPath: " + self.EfiOutputPath) + + ## PatchEfiFile + # + # Patch EFI file with patch PCD + # + # @param EfiFile: EFI file needs to be patched. + # @retval: Full path of patched EFI file: self.OutputPath + EfiFile base name + # If passed in file does not end with efi, return as is + # + def PatchEfiFile(self, EfiFile, FileType): + # + # If the module does not have any patches, then return path to input file + # + if not self.PatchPcds: + return EfiFile + + # + # Only patch file if FileType is PE32 or ModuleType is USER_DEFINED + # + if FileType != BINARY_FILE_TYPE_PE32 and self.ModuleType != SUP_MODULE_USER_DEFINED and self.ModuleType != SUP_MODULE_HOST_APPLICATION: + return EfiFile + + # + # Generate path to patched output file + # + Basename = os.path.basename(EfiFile) + Output = os.path.normpath (os.path.join(self.OutputPath, Basename)) + + # + # If this file has already been patched, then return the path to the patched file + # + if self.PatchedBinFile == Output: + return Output + + # + # If a different file from the same module has already been patched, then generate an error + # + if self.PatchedBinFile: + EdkLogger.error("GenFds", GENFDS_ERROR, + 'Only one binary file can be patched:\n' + ' a binary file has been patched: %s\n' + ' current file: %s' % (self.PatchedBinFile, EfiFile), + File=self.InfFileName) + + # + # Copy unpatched file contents to output file location to perform patching + # + CopyLongFilePath(EfiFile, Output) + + # + # Apply patches to patched output file + # + for Pcd, Value in self.PatchPcds: + RetVal, RetStr = PatchBinaryFile(Output, int(Pcd.Offset, 0), Pcd.DatumType, Value, Pcd.MaxDatumSize) + if RetVal: + EdkLogger.error("GenFds", GENFDS_ERROR, RetStr, File=self.InfFileName) + + # + # Save the path of the patched output file + # + self.PatchedBinFile = Output + + # + # Return path to patched output file + # + return Output + + ## GenFfs() method + # + # Generate FFS + # + # @param self The object pointer + # @param Dict dictionary contains macro and value pair + # @param FvChildAddr Array of the inside FvImage base address + # @param FvParentAddr Parent Fv base address + # @retval string Generated FFS file name + # + def GenFfs(self, Dict = None, FvChildAddr = [], FvParentAddr=None, IsMakefile=False, FvName=None): + # + # Parse Inf file get Module related information + # + if Dict is None: + Dict = {} + self.__InfParse__(Dict, IsGenFfs=True) + Arch = self.GetCurrentArch() + SrcFile = mws.join( GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName); + DestFile = os.path.join( self.OutputPath, self.ModuleGuid + '.ffs') + + SrcFileDir = "." + SrcPath = os.path.dirname(SrcFile) + SrcFileName = os.path.basename(SrcFile) + SrcFileBase, SrcFileExt = os.path.splitext(SrcFileName) + DestPath = os.path.dirname(DestFile) + DestFileName = os.path.basename(DestFile) + DestFileBase, DestFileExt = os.path.splitext(DestFileName) + self.MacroDict = { + # source file + "${src}" : SrcFile, + "${s_path}" : SrcPath, + "${s_dir}" : SrcFileDir, + "${s_name}" : SrcFileName, + "${s_base}" : SrcFileBase, + "${s_ext}" : SrcFileExt, + # destination file + "${dst}" : DestFile, + "${d_path}" : DestPath, + "${d_name}" : DestFileName, + "${d_base}" : DestFileBase, + "${d_ext}" : DestFileExt + } + # + # Allow binary type module not specify override rule in FDF file. + # + if len(self.BinFileList) > 0: + if self.Rule is None or self.Rule == "": + self.Rule = "BINARY" + + if not IsMakefile and GenFdsGlobalVariable.EnableGenfdsMultiThread and self.Rule != 'BINARY': + IsMakefile = True + # + # Get the rule of how to generate Ffs file + # + Rule = self.__GetRule__() + GenFdsGlobalVariable.VerboseLogger( "Packing binaries from inf file : %s" %self.InfFileName) + # + # Convert Fv File Type for PI1.1 SMM driver. + # + if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) >= 0x0001000A: + if Rule.FvFileType == 'DRIVER': + Rule.FvFileType = 'SMM' + # + # Framework SMM Driver has no SMM FV file type + # + if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) < 0x0001000A: + if Rule.FvFileType == 'SMM' or Rule.FvFileType == SUP_MODULE_SMM_CORE: + EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Framework SMM module doesn't support SMM or SMM_CORE FV file type", File=self.InfFileName) + # + # For the rule only has simpleFile + # + MakefilePath = None + if self.IsBinaryModule: + IsMakefile = False + if IsMakefile: + PathClassObj = PathClass(self.InfFileName, GenFdsGlobalVariable.WorkSpaceDir) + if self.OverrideGuid: + PathClassObj = ProcessDuplicatedInf(PathClassObj, self.OverrideGuid, GenFdsGlobalVariable.WorkSpaceDir) + MakefilePath = PathClassObj.Path, Arch + if isinstance (Rule, RuleSimpleFile.RuleSimpleFile): + SectionOutputList = self.__GenSimpleFileSection__(Rule, IsMakefile=IsMakefile) + FfsOutput = self.__GenSimpleFileFfs__(Rule, SectionOutputList, MakefilePath=MakefilePath) + return FfsOutput + # + # For Rule has ComplexFile + # + elif isinstance(Rule, RuleComplexFile.RuleComplexFile): + InputSectList, InputSectAlignments = self.__GenComplexFileSection__(Rule, FvChildAddr, FvParentAddr, IsMakefile=IsMakefile) + FfsOutput = self.__GenComplexFileFfs__(Rule, InputSectList, InputSectAlignments, MakefilePath=MakefilePath) + return FfsOutput + + ## __ExtendMacro__() method + # + # Replace macro with its value + # + # @param self The object pointer + # @param String The string to be replaced + # @retval string Macro replaced string + # + def __ExtendMacro__ (self, String): + MacroDict = { + '$(INF_OUTPUT)' : self.EfiOutputPath, + '$(MODULE_NAME)' : self.BaseName, + '$(BUILD_NUMBER)': self.BuildNum, + '$(INF_VERSION)' : self.VersionString, + '$(NAMED_GUID)' : self.ModuleGuid + } + String = GenFdsGlobalVariable.MacroExtend(String, MacroDict) + String = GenFdsGlobalVariable.MacroExtend(String, self.MacroDict) + return String + + ## __GetRule__() method + # + # Get correct rule for generating FFS for this INF + # + # @param self The object pointer + # @retval Rule Rule object + # + def __GetRule__ (self) : + CurrentArchList = [] + if self.CurrentArch is None: + CurrentArchList = ['common'] + else: + CurrentArchList.append(self.CurrentArch) + + for CurrentArch in CurrentArchList: + RuleName = 'RULE' + \ + '.' + \ + CurrentArch.upper() + \ + '.' + \ + self.ModuleType.upper() + if self.Rule is not None: + RuleName = RuleName + \ + '.' + \ + self.Rule.upper() + + Rule = GenFdsGlobalVariable.FdfParser.Profile.RuleDict.get(RuleName) + if Rule is not None: + GenFdsGlobalVariable.VerboseLogger ("Want To Find Rule Name is : " + RuleName) + return Rule + + RuleName = 'RULE' + \ + '.' + \ + TAB_COMMON + \ + '.' + \ + self.ModuleType.upper() + + if self.Rule is not None: + RuleName = RuleName + \ + '.' + \ + self.Rule.upper() + + GenFdsGlobalVariable.VerboseLogger ('Trying to apply common rule %s for INF %s' % (RuleName, self.InfFileName)) + + Rule = GenFdsGlobalVariable.FdfParser.Profile.RuleDict.get(RuleName) + if Rule is not None: + GenFdsGlobalVariable.VerboseLogger ("Want To Find Rule Name is : " + RuleName) + return Rule + + if Rule is None : + EdkLogger.error("GenFds", GENFDS_ERROR, 'Don\'t Find common rule %s for INF %s' \ + % (RuleName, self.InfFileName)) + + ## __GetPlatformArchList__() method + # + # Get Arch list this INF built under + # + # @param self The object pointer + # @retval list Arch list + # + def __GetPlatformArchList__(self): + + InfFileKey = os.path.normpath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName)) + DscArchList = [] + for Arch in GenFdsGlobalVariable.ArchList : + PlatformDataBase = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + if PlatformDataBase is not None: + if InfFileKey in PlatformDataBase.Modules: + DscArchList.append (Arch) + else: + # + # BaseTools support build same module more than once, the module path with FILE_GUID overridden has + # the file name FILE_GUIDmodule.inf, then PlatformDataBase.Modules use FILE_GUIDmodule.inf as key, + # but the path (self.MetaFile.Path) is the real path + # + for key in PlatformDataBase.Modules: + if InfFileKey == str((PlatformDataBase.Modules[key]).MetaFile.Path): + DscArchList.append (Arch) + break + + return DscArchList + + ## GetCurrentArch() method + # + # Get Arch list of the module from this INF is to be placed into flash + # + # @param self The object pointer + # @retval list Arch list + # + def GetCurrentArch(self) : + + TargetArchList = GenFdsGlobalVariable.ArchList + + PlatformArchList = self.__GetPlatformArchList__() + + CurArchList = TargetArchList + if PlatformArchList != []: + CurArchList = list(set (TargetArchList) & set (PlatformArchList)) + GenFdsGlobalVariable.VerboseLogger ("Valid target architecture(s) is : " + " ".join(CurArchList)) + + ArchList = [] + if self.KeyStringList != []: + for Key in self.KeyStringList: + Key = GenFdsGlobalVariable.MacroExtend(Key) + Target, Tag, Arch = Key.split('_') + if Arch in CurArchList: + ArchList.append(Arch) + if Target not in self.TargetOverrideList: + self.TargetOverrideList.append(Target) + else: + ArchList = CurArchList + + UseArchList = TargetArchList + if self.UseArch is not None: + UseArchList = [] + UseArchList.append(self.UseArch) + ArchList = list(set (UseArchList) & set (ArchList)) + + self.InfFileName = NormPath(self.InfFileName) + if len(PlatformArchList) == 0: + self.InDsc = False + PathClassObj = PathClass(self.InfFileName, GenFdsGlobalVariable.WorkSpaceDir) + ErrorCode, ErrorInfo = PathClassObj.Validate(".inf") + if ErrorCode != 0: + EdkLogger.error("GenFds", ErrorCode, ExtraData=ErrorInfo) + if len(ArchList) == 1: + Arch = ArchList[0] + return Arch + elif len(ArchList) > 1: + if len(PlatformArchList) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, "GenFds command line option has multiple ARCHs %s. Not able to determine which ARCH is valid for Module %s !" % (str(ArchList), self.InfFileName)) + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "Module built under multiple ARCHs %s. Not able to determine which output to put into flash for Module %s !" % (str(ArchList), self.InfFileName)) + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "Module %s appears under ARCH %s in platform %s, but current deduced ARCH is %s, so NO build output could be put into flash." \ + % (self.InfFileName, str(PlatformArchList), GenFdsGlobalVariable.ActivePlatform, str(set (UseArchList) & set (TargetArchList)))) + + ## __GetEFIOutPutPath__() method + # + # Get the output path for generated files + # + # @param self The object pointer + # @retval string Path that output files from this INF go to + # + def __GetEFIOutPutPath__(self): + Arch = '' + OutputPath = '' + DebugPath = '' + (ModulePath, FileName) = os.path.split(self.InfFileName) + Index = FileName.rfind('.') + FileName = FileName[0:Index] + if self.OverrideGuid: + FileName = self.OverrideGuid + Arch = "NoneArch" + if self.CurrentArch is not None: + Arch = self.CurrentArch + + OutputPath = os.path.join(GenFdsGlobalVariable.OutputDirDict[Arch], + Arch, + ModulePath, + FileName, + 'OUTPUT' + ) + DebugPath = os.path.join(GenFdsGlobalVariable.OutputDirDict[Arch], + Arch, + ModulePath, + FileName, + 'DEBUG' + ) + OutputPath = os.path.realpath(OutputPath) + DebugPath = os.path.realpath(DebugPath) + return OutputPath, DebugPath + + ## __GenSimpleFileSection__() method + # + # Generate section by specified file name or a list of files with file extension + # + # @param self The object pointer + # @param Rule The rule object used to generate section + # @retval string File name of the generated section file + # + def __GenSimpleFileSection__(self, Rule, IsMakefile = False): + # + # Prepare the parameter of GenSection + # + FileList = [] + OutputFileList = [] + GenSecInputFile = None + if Rule.FileName is not None: + GenSecInputFile = self.__ExtendMacro__(Rule.FileName) + if os.path.isabs(GenSecInputFile): + GenSecInputFile = os.path.normpath(GenSecInputFile) + else: + GenSecInputFile = os.path.normpath(os.path.join(self.EfiOutputPath, GenSecInputFile)) + else: + FileList, IsSect = Section.Section.GetFileList(self, '', Rule.FileExtension) + + Index = 1 + SectionType = Rule.SectionType + # + # Convert Fv Section Type for PI1.1 SMM driver. + # + if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) >= 0x0001000A: + if SectionType == BINARY_FILE_TYPE_DXE_DEPEX: + SectionType = BINARY_FILE_TYPE_SMM_DEPEX + # + # Framework SMM Driver has no SMM_DEPEX section type + # + if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) < 0x0001000A: + if SectionType == BINARY_FILE_TYPE_SMM_DEPEX: + EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Framework SMM module doesn't support SMM_DEPEX section type", File=self.InfFileName) + NoStrip = True + if self.ModuleType in (SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM): + if self.KeepReloc is not None: + NoStrip = self.KeepReloc + elif Rule.KeepReloc is not None: + NoStrip = Rule.KeepReloc + elif self.ShadowFromInfFile is not None: + NoStrip = self.ShadowFromInfFile + + if FileList != [] : + for File in FileList: + + SecNum = '%d' %Index + GenSecOutputFile= self.__ExtendMacro__(Rule.NameGuid) + \ + SectionSuffix[SectionType] + SUP_MODULE_SEC + SecNum + Index = Index + 1 + OutputFile = os.path.join(self.OutputPath, GenSecOutputFile) + File = GenFdsGlobalVariable.MacroExtend(File, Dict, self.CurrentArch) + + #Get PE Section alignment when align is set to AUTO + if self.Alignment == 'Auto' and (SectionType == BINARY_FILE_TYPE_PE32 or SectionType == BINARY_FILE_TYPE_TE): + ImageObj = PeImageClass (File) + if ImageObj.SectionAlignment < 0x400: + self.Alignment = str (ImageObj.SectionAlignment) + elif ImageObj.SectionAlignment < 0x100000: + self.Alignment = str (ImageObj.SectionAlignment // 0x400) + 'K' + else: + self.Alignment = str (ImageObj.SectionAlignment // 0x100000) + 'M' + + if not NoStrip: + FileBeforeStrip = os.path.join(self.OutputPath, ModuleName + '.reloc') + if not os.path.exists(FileBeforeStrip) or \ + (os.path.getmtime(File) > os.path.getmtime(FileBeforeStrip)): + CopyLongFilePath(File, FileBeforeStrip) + StrippedFile = os.path.join(self.OutputPath, ModuleName + '.stipped') + GenFdsGlobalVariable.GenerateFirmwareImage( + StrippedFile, + [File], + Strip=True, + IsMakefile=IsMakefile + ) + File = StrippedFile + + if SectionType == BINARY_FILE_TYPE_TE: + TeFile = os.path.join( self.OutputPath, self.ModuleGuid + 'Te.raw') + GenFdsGlobalVariable.GenerateFirmwareImage( + TeFile, + [File], + Type='te', + IsMakefile=IsMakefile + ) + File = TeFile + GenFdsGlobalVariable.GenerateSection(OutputFile, [File], Section.Section.SectionType[SectionType], IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + else: + SecNum = '%d' %Index + GenSecOutputFile= self.__ExtendMacro__(Rule.NameGuid) + \ + SectionSuffix[SectionType] + SUP_MODULE_SEC + SecNum + OutputFile = os.path.join(self.OutputPath, GenSecOutputFile) + GenSecInputFile = GenFdsGlobalVariable.MacroExtend(GenSecInputFile, Dict, self.CurrentArch) + + #Get PE Section alignment when align is set to AUTO + if self.Alignment == 'Auto' and (SectionType == BINARY_FILE_TYPE_PE32 or SectionType == BINARY_FILE_TYPE_TE): + ImageObj = PeImageClass (GenSecInputFile) + if ImageObj.SectionAlignment < 0x400: + self.Alignment = str (ImageObj.SectionAlignment) + elif ImageObj.SectionAlignment < 0x100000: + self.Alignment = str (ImageObj.SectionAlignment // 0x400) + 'K' + else: + self.Alignment = str (ImageObj.SectionAlignment // 0x100000) + 'M' + + if not NoStrip: + FileBeforeStrip = os.path.join(self.OutputPath, ModuleName + '.reloc') + if not os.path.exists(FileBeforeStrip) or \ + (os.path.getmtime(GenSecInputFile) > os.path.getmtime(FileBeforeStrip)): + CopyLongFilePath(GenSecInputFile, FileBeforeStrip) + + StrippedFile = os.path.join(self.OutputPath, ModuleName + '.stipped') + GenFdsGlobalVariable.GenerateFirmwareImage( + StrippedFile, + [GenSecInputFile], + Strip=True, + IsMakefile=IsMakefile + ) + GenSecInputFile = StrippedFile + + if SectionType == BINARY_FILE_TYPE_TE: + TeFile = os.path.join( self.OutputPath, self.ModuleGuid + 'Te.raw') + GenFdsGlobalVariable.GenerateFirmwareImage( + TeFile, + [GenSecInputFile], + Type='te', + IsMakefile=IsMakefile + ) + GenSecInputFile = TeFile + GenFdsGlobalVariable.GenerateSection(OutputFile, [GenSecInputFile], Section.Section.SectionType[SectionType], IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + + return OutputFileList + + ## __GenSimpleFileFfs__() method + # + # Generate FFS + # + # @param self The object pointer + # @param Rule The rule object used to generate section + # @param InputFileList The output file list from GenSection + # @retval string Generated FFS file name + # + def __GenSimpleFileFfs__(self, Rule, InputFileList, MakefilePath = None): + FfsOutput = self.OutputPath + \ + os.sep + \ + self.__ExtendMacro__(Rule.NameGuid) + \ + '.ffs' + + GenFdsGlobalVariable.VerboseLogger(self.__ExtendMacro__(Rule.NameGuid)) + InputSection = [] + SectionAlignments = [] + for InputFile in InputFileList: + InputSection.append(InputFile) + SectionAlignments.append(Rule.SectAlignment) + + if Rule.NameGuid is not None and Rule.NameGuid.startswith('PCD('): + PcdValue = GenFdsGlobalVariable.GetPcdValue(Rule.NameGuid) + if len(PcdValue) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, '%s NOT defined.' \ + % (Rule.NameGuid)) + if PcdValue.startswith('{'): + PcdValue = GuidStructureByteArrayToGuidString(PcdValue) + RegistryGuidStr = PcdValue + if len(RegistryGuidStr) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, 'GUID value for %s in wrong format.' \ + % (Rule.NameGuid)) + self.ModuleGuid = RegistryGuidStr + + GenFdsGlobalVariable.GenerateFfs(FfsOutput, InputSection, + FdfFvFileTypeToFileType[Rule.FvFileType], + self.ModuleGuid, Fixed=Rule.Fixed, + CheckSum=Rule.CheckSum, Align=Rule.Alignment, + SectionAlign=SectionAlignments, + MakefilePath=MakefilePath + ) + return FfsOutput + + ## __GenComplexFileSection__() method + # + # Generate section by sections in Rule + # + # @param self The object pointer + # @param Rule The rule object used to generate section + # @param FvChildAddr Array of the inside FvImage base address + # @param FvParentAddr Parent Fv base address + # @retval string File name of the generated section file + # + def __GenComplexFileSection__(self, Rule, FvChildAddr, FvParentAddr, IsMakefile = False): + if self.ModuleType in (SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, SUP_MODULE_MM_CORE_STANDALONE): + if Rule.KeepReloc is not None: + self.KeepRelocFromRule = Rule.KeepReloc + SectFiles = [] + SectAlignments = [] + Index = 1 + HasGeneratedFlag = False + if self.PcdIsDriver == 'PEI_PCD_DRIVER': + if self.IsBinaryModule: + PcdExDbFileName = os.path.join(GenFdsGlobalVariable.FvDir, "PEIPcdDataBase.raw") + else: + PcdExDbFileName = os.path.join(self.EfiOutputPath, "PEIPcdDataBase.raw") + PcdExDbSecName = os.path.join(self.OutputPath, "PEIPcdDataBaseSec.raw") + GenFdsGlobalVariable.GenerateSection(PcdExDbSecName, + [PcdExDbFileName], + "EFI_SECTION_RAW", + IsMakefile = IsMakefile + ) + SectFiles.append(PcdExDbSecName) + SectAlignments.append(None) + elif self.PcdIsDriver == 'DXE_PCD_DRIVER': + if self.IsBinaryModule: + PcdExDbFileName = os.path.join(GenFdsGlobalVariable.FvDir, "DXEPcdDataBase.raw") + else: + PcdExDbFileName = os.path.join(self.EfiOutputPath, "DXEPcdDataBase.raw") + PcdExDbSecName = os.path.join(self.OutputPath, "DXEPcdDataBaseSec.raw") + GenFdsGlobalVariable.GenerateSection(PcdExDbSecName, + [PcdExDbFileName], + "EFI_SECTION_RAW", + IsMakefile = IsMakefile + ) + SectFiles.append(PcdExDbSecName) + SectAlignments.append(None) + for Sect in Rule.SectionList: + SecIndex = '%d' %Index + SectList = [] + # + # Convert Fv Section Type for PI1.1 SMM driver. + # + if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) >= 0x0001000A: + if Sect.SectionType == BINARY_FILE_TYPE_DXE_DEPEX: + Sect.SectionType = BINARY_FILE_TYPE_SMM_DEPEX + # + # Framework SMM Driver has no SMM_DEPEX section type + # + if self.ModuleType == SUP_MODULE_DXE_SMM_DRIVER and int(self.PiSpecVersion, 16) < 0x0001000A: + if Sect.SectionType == BINARY_FILE_TYPE_SMM_DEPEX: + EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Framework SMM module doesn't support SMM_DEPEX section type", File=self.InfFileName) + # + # process the inside FvImage from FvSection or GuidSection + # + if FvChildAddr != []: + if isinstance(Sect, FvImageSection): + Sect.FvAddr = FvChildAddr.pop(0) + elif isinstance(Sect, GuidSection): + Sect.FvAddr = FvChildAddr + if FvParentAddr is not None and isinstance(Sect, GuidSection): + Sect.FvParentAddr = FvParentAddr + + if Rule.KeyStringList != []: + SectList, Align = Sect.GenSection(self.OutputPath, self.ModuleGuid, SecIndex, Rule.KeyStringList, self, IsMakefile = IsMakefile) + else : + SectList, Align = Sect.GenSection(self.OutputPath, self.ModuleGuid, SecIndex, self.KeyStringList, self, IsMakefile = IsMakefile) + + if not HasGeneratedFlag: + UniVfrOffsetFileSection = "" + ModuleFileName = mws.join(GenFdsGlobalVariable.WorkSpaceDir, self.InfFileName) + InfData = GenFdsGlobalVariable.WorkSpace.BuildObject[PathClass(ModuleFileName), self.CurrentArch] + # + # Search the source list in InfData to find if there are .vfr file exist. + # + VfrUniBaseName = {} + VfrUniOffsetList = [] + for SourceFile in InfData.Sources: + if SourceFile.Type.upper() == ".VFR" : + # + # search the .map file to find the offset of vfr binary in the PE32+/TE file. + # + VfrUniBaseName[SourceFile.BaseName] = (SourceFile.BaseName + "Bin") + if SourceFile.Type.upper() == ".UNI" : + # + # search the .map file to find the offset of Uni strings binary in the PE32+/TE file. + # + VfrUniBaseName["UniOffsetName"] = (self.BaseName + "Strings") + + + if len(VfrUniBaseName) > 0: + if IsMakefile: + if InfData.BuildType != 'UEFI_HII': + UniVfrOffsetFileName = os.path.join(self.OutputPath, self.BaseName + '.offset') + UniVfrOffsetFileSection = os.path.join(self.OutputPath, self.BaseName + 'Offset' + '.raw') + UniVfrOffsetFileNameList = [] + UniVfrOffsetFileNameList.append(UniVfrOffsetFileName) + TrimCmd = "Trim --Vfr-Uni-Offset -o %s --ModuleName=%s --DebugDir=%s " % (UniVfrOffsetFileName, self.BaseName, self.EfiDebugPath) + GenFdsGlobalVariable.SecCmdList.append(TrimCmd) + GenFdsGlobalVariable.GenerateSection(UniVfrOffsetFileSection, + [UniVfrOffsetFileName], + "EFI_SECTION_RAW", + IsMakefile = True + ) + else: + VfrUniOffsetList = self.__GetBuildOutputMapFileVfrUniInfo(VfrUniBaseName) + # + # Generate the Raw data of raw section + # + if VfrUniOffsetList: + UniVfrOffsetFileName = os.path.join(self.OutputPath, self.BaseName + '.offset') + UniVfrOffsetFileSection = os.path.join(self.OutputPath, self.BaseName + 'Offset' + '.raw') + FfsInfStatement.__GenUniVfrOffsetFile (VfrUniOffsetList, UniVfrOffsetFileName) + UniVfrOffsetFileNameList = [] + UniVfrOffsetFileNameList.append(UniVfrOffsetFileName) + """Call GenSection""" + + GenFdsGlobalVariable.GenerateSection(UniVfrOffsetFileSection, + UniVfrOffsetFileNameList, + "EFI_SECTION_RAW" + ) + #os.remove(UniVfrOffsetFileName) + if UniVfrOffsetFileSection: + SectList.append(UniVfrOffsetFileSection) + HasGeneratedFlag = True + + for SecName in SectList : + SectFiles.append(SecName) + SectAlignments.append(Align) + Index = Index + 1 + return SectFiles, SectAlignments + + ## __GenComplexFileFfs__() method + # + # Generate FFS + # + # @param self The object pointer + # @param Rule The rule object used to generate section + # @param InputFileList The output file list from GenSection + # @retval string Generated FFS file name + # + def __GenComplexFileFfs__(self, Rule, InputFile, Alignments, MakefilePath = None): + + if Rule.NameGuid is not None and Rule.NameGuid.startswith('PCD('): + PcdValue = GenFdsGlobalVariable.GetPcdValue(Rule.NameGuid) + if len(PcdValue) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, '%s NOT defined.' \ + % (Rule.NameGuid)) + if PcdValue.startswith('{'): + PcdValue = GuidStructureByteArrayToGuidString(PcdValue) + RegistryGuidStr = PcdValue + if len(RegistryGuidStr) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, 'GUID value for %s in wrong format.' \ + % (Rule.NameGuid)) + self.ModuleGuid = RegistryGuidStr + + FfsOutput = os.path.join( self.OutputPath, self.ModuleGuid + '.ffs') + GenFdsGlobalVariable.GenerateFfs(FfsOutput, InputFile, + FdfFvFileTypeToFileType[Rule.FvFileType], + self.ModuleGuid, Fixed=Rule.Fixed, + CheckSum=Rule.CheckSum, Align=Rule.Alignment, + SectionAlign=Alignments, + MakefilePath=MakefilePath + ) + return FfsOutput + + ## __GetBuildOutputMapFileVfrUniInfo() method + # + # Find the offset of UNI/INF object offset in the EFI image file. + # + # @param self The object pointer + # @param VfrUniBaseName A name list contain the UNI/INF object name. + # @retval RetValue A list contain offset of UNI/INF object. + # + def __GetBuildOutputMapFileVfrUniInfo(self, VfrUniBaseName): + MapFileName = os.path.join(self.EfiOutputPath, self.BaseName + ".map") + EfiFileName = os.path.join(self.EfiOutputPath, self.BaseName + ".efi") + return GetVariableOffset(MapFileName, EfiFileName, list(VfrUniBaseName.values())) + + ## __GenUniVfrOffsetFile() method + # + # Generate the offset file for the module which contain VFR or UNI file. + # + # @param VfrUniOffsetList A list contain the VFR/UNI offsets in the EFI image file. + # @param UniVfrOffsetFileName The output offset file name. + # + @staticmethod + def __GenUniVfrOffsetFile(VfrUniOffsetList, UniVfrOffsetFileName): + + # Use a instance of StringIO to cache data + fStringIO = BytesIO() + + for Item in VfrUniOffsetList: + if (Item[0].find("Strings") != -1): + # + # UNI offset in image. + # GUID + Offset + # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } } + # + UniGuid = b'\xe0\xc5\x13\x89\xf63\x86M\x9b\xf1C\xef\x89\xfc\x06f' + fStringIO.write(UniGuid) + UniValue = pack ('Q', int (Item[1], 16)) + fStringIO.write (UniValue) + else: + # + # VFR binary offset in image. + # GUID + Offset + # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }; + # + VfrGuid = b'\xb4|\xbc\xd0Gj_I\xaa\x11q\x07F\xda\x06\xa2' + fStringIO.write(VfrGuid) + type (Item[1]) + VfrValue = pack ('Q', int (Item[1], 16)) + fStringIO.write (VfrValue) + + # + # write data into file. + # + try : + SaveFileOnChange(UniVfrOffsetFileName, fStringIO.getvalue()) + except: + EdkLogger.error("GenFds", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the file been locked or using by other applications." %UniVfrOffsetFileName, None) + + fStringIO.close () + + diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/Fv.py b/roms/edk2/BaseTools/Source/Python/GenFds/Fv.py new file mode 100644 index 000000000..16c944a0b --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/Fv.py @@ -0,0 +1,431 @@ +## @file +# process FV generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +import Common.LongFilePathOs as os +import subprocess +from io import BytesIO +from struct import * +from . import FfsFileStatement +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from Common.Misc import SaveFileOnChange, PackGUID +from Common.LongFilePathSupport import CopyLongFilePath +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.DataType import * + +FV_UI_EXT_ENTY_GUID = 'A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C' + +## generate FV +# +# +class FV (object): + ## The constructor + # + # @param self The object pointer + # + def __init__(self, Name=None): + self.UiFvName = Name + self.CreateFileName = None + self.BlockSizeList = [] + self.DefineVarDict = {} + self.SetVarDict = {} + self.FvAlignment = None + self.FvAttributeDict = {} + self.FvNameGuid = None + self.FvNameString = None + self.AprioriSectionList = [] + self.FfsList = [] + self.BsBaseAddress = None + self.RtBaseAddress = None + self.FvInfFile = None + self.FvAddressFile = None + self.BaseAddress = None + self.InfFileName = None + self.FvAddressFileName = None + self.CapsuleName = None + self.FvBaseAddress = None + self.FvForceRebase = None + self.FvRegionInFD = None + self.UsedSizeEnable = False + self.FvExtEntryTypeValue = [] + self.FvExtEntryType = [] + self.FvExtEntryData = [] + ## AddToBuffer() + # + # Generate Fv and add it to the Buffer + # + # @param self The object pointer + # @param Buffer The buffer generated FV data will be put + # @param BaseAddress base address of FV + # @param BlockSize block size of FV + # @param BlockNum How many blocks in FV + # @param ErasePolarity Flash erase polarity + # @param MacroDict macro value pair + # @retval string Generated FV file path + # + def AddToBuffer (self, Buffer, BaseAddress=None, BlockSize= None, BlockNum=None, ErasePloarity='1', MacroDict = None, Flag=False): + if BaseAddress is None and self.UiFvName.upper() + 'fv' in GenFdsGlobalVariable.ImageBinDict: + return GenFdsGlobalVariable.ImageBinDict[self.UiFvName.upper() + 'fv'] + if MacroDict is None: + MacroDict = {} + + # + # Check whether FV in Capsule is in FD flash region. + # If yes, return error. Doesn't support FV in Capsule image is also in FD flash region. + # + if self.CapsuleName is not None: + for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values(): + for RegionObj in FdObj.RegionList: + if RegionObj.RegionType == BINARY_FILE_TYPE_FV: + for RegionData in RegionObj.RegionDataList: + if RegionData.endswith(".fv"): + continue + elif RegionData.upper() + 'fv' in GenFdsGlobalVariable.ImageBinDict: + continue + elif self.UiFvName.upper() == RegionData.upper(): + GenFdsGlobalVariable.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self.CapsuleName, self.UiFvName.upper())) + if not Flag: + GenFdsGlobalVariable.InfLogger( "\nGenerating %s FV" %self.UiFvName) + GenFdsGlobalVariable.LargeFileInFvFlags.append(False) + FFSGuid = None + + if self.FvBaseAddress is not None: + BaseAddress = self.FvBaseAddress + if not Flag: + self._InitializeInf(BaseAddress, BlockSize, BlockNum, ErasePloarity) + # + # First Process the Apriori section + # + MacroDict.update(self.DefineVarDict) + + GenFdsGlobalVariable.VerboseLogger('First generate Apriori file !') + FfsFileList = [] + for AprSection in self.AprioriSectionList: + FileName = AprSection.GenFfs (self.UiFvName, MacroDict, IsMakefile=Flag) + FfsFileList.append(FileName) + # Add Apriori file name to Inf file + if not Flag: + self.FvInfFile.append("EFI_FILE_NAME = " + \ + FileName + \ + TAB_LINE_BREAK) + + # Process Modules in FfsList + for FfsFile in self.FfsList: + if Flag: + if isinstance(FfsFile, FfsFileStatement.FileStatement): + continue + if GenFdsGlobalVariable.EnableGenfdsMultiThread and GenFdsGlobalVariable.ModuleFile and GenFdsGlobalVariable.ModuleFile.Path.find(os.path.normpath(FfsFile.InfFileName)) == -1: + continue + FileName = FfsFile.GenFfs(MacroDict, FvParentAddr=BaseAddress, IsMakefile=Flag, FvName=self.UiFvName) + FfsFileList.append(FileName) + if not Flag: + self.FvInfFile.append("EFI_FILE_NAME = " + \ + FileName + \ + TAB_LINE_BREAK) + if not Flag: + FvInfFile = ''.join(self.FvInfFile) + SaveFileOnChange(self.InfFileName, FvInfFile, False) + # + # Call GenFv tool + # + FvOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName) + FvOutputFile = FvOutputFile + '.Fv' + # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement) + if self.CreateFileName is not None: + FvOutputFile = self.CreateFileName + + if Flag: + GenFdsGlobalVariable.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile + return FvOutputFile + + FvInfoFileName = os.path.join(GenFdsGlobalVariable.FfsDir, self.UiFvName + '.inf') + if not Flag: + CopyLongFilePath(GenFdsGlobalVariable.FvAddressFileName, FvInfoFileName) + OrigFvInfo = None + if os.path.exists (FvInfoFileName): + OrigFvInfo = open(FvInfoFileName, 'r').read() + if GenFdsGlobalVariable.LargeFileInFvFlags[-1]: + FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID + GenFdsGlobalVariable.GenerateFirmwareVolume( + FvOutputFile, + [self.InfFileName], + AddressFile=FvInfoFileName, + FfsList=FfsFileList, + ForceRebase=self.FvForceRebase, + FileSystemGuid=FFSGuid + ) + + NewFvInfo = None + if os.path.exists (FvInfoFileName): + NewFvInfo = open(FvInfoFileName, 'r').read() + if NewFvInfo is not None and NewFvInfo != OrigFvInfo: + FvChildAddr = [] + AddFileObj = open(FvInfoFileName, 'r') + AddrStrings = AddFileObj.readlines() + AddrKeyFound = False + for AddrString in AddrStrings: + if AddrKeyFound: + #get base address for the inside FvImage + FvChildAddr.append (AddrString) + elif AddrString.find ("[FV_BASE_ADDRESS]") != -1: + AddrKeyFound = True + AddFileObj.close() + + if FvChildAddr != []: + # Update Ffs again + for FfsFile in self.FfsList: + FileName = FfsFile.GenFfs(MacroDict, FvChildAddr, BaseAddress, IsMakefile=Flag, FvName=self.UiFvName) + + if GenFdsGlobalVariable.LargeFileInFvFlags[-1]: + FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID; + #Update GenFv again + GenFdsGlobalVariable.GenerateFirmwareVolume( + FvOutputFile, + [self.InfFileName], + AddressFile=FvInfoFileName, + FfsList=FfsFileList, + ForceRebase=self.FvForceRebase, + FileSystemGuid=FFSGuid + ) + + # + # Write the Fv contents to Buffer + # + if os.path.isfile(FvOutputFile) and os.path.getsize(FvOutputFile) >= 0x48: + FvFileObj = open(FvOutputFile, 'rb') + # PI FvHeader is 0x48 byte + FvHeaderBuffer = FvFileObj.read(0x48) + Signature = FvHeaderBuffer[0x28:0x32] + if Signature and Signature.startswith(b'_FVH'): + GenFdsGlobalVariable.VerboseLogger("\nGenerate %s FV Successfully" % self.UiFvName) + GenFdsGlobalVariable.SharpCounter = 0 + + FvFileObj.seek(0) + Buffer.write(FvFileObj.read()) + # FV alignment position. + FvAlignmentValue = 1 << (ord(FvHeaderBuffer[0x2E:0x2F]) & 0x1F) + if FvAlignmentValue >= 0x400: + if FvAlignmentValue >= 0x100000: + if FvAlignmentValue >= 0x1000000: + #The max alignment supported by FFS is 16M. + self.FvAlignment = "16M" + else: + self.FvAlignment = str(FvAlignmentValue // 0x100000) + "M" + else: + self.FvAlignment = str(FvAlignmentValue // 0x400) + "K" + else: + # FvAlignmentValue is less than 1K + self.FvAlignment = str (FvAlignmentValue) + FvFileObj.close() + GenFdsGlobalVariable.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile + GenFdsGlobalVariable.LargeFileInFvFlags.pop() + else: + GenFdsGlobalVariable.ErrorLogger("Invalid FV file %s." % self.UiFvName) + else: + GenFdsGlobalVariable.ErrorLogger("Failed to generate %s FV file." %self.UiFvName) + return FvOutputFile + + ## _GetBlockSize() + # + # Calculate FV's block size + # Inherit block size from FD if no block size specified in FV + # + def _GetBlockSize(self): + if self.BlockSizeList: + return True + + for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values(): + for RegionObj in FdObj.RegionList: + if RegionObj.RegionType != BINARY_FILE_TYPE_FV: + continue + for RegionData in RegionObj.RegionDataList: + # + # Found the FD and region that contain this FV + # + if self.UiFvName.upper() == RegionData.upper(): + RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, self) + if self.BlockSizeList: + return True + return False + + ## _InitializeInf() + # + # Initialize the inf file to create FV + # + # @param self The object pointer + # @param BaseAddress base address of FV + # @param BlockSize block size of FV + # @param BlockNum How many blocks in FV + # @param ErasePolarity Flash erase polarity + # + def _InitializeInf (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1'): + # + # Create FV inf file + # + self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir, + self.UiFvName + '.inf') + self.FvInfFile = [] + + # + # Add [Options] + # + self.FvInfFile.append("[options]" + TAB_LINE_BREAK) + if BaseAddress is not None: + self.FvInfFile.append("EFI_BASE_ADDRESS = " + \ + BaseAddress + \ + TAB_LINE_BREAK) + + if BlockSize is not None: + self.FvInfFile.append("EFI_BLOCK_SIZE = " + \ + '0x%X' %BlockSize + \ + TAB_LINE_BREAK) + if BlockNum is not None: + self.FvInfFile.append("EFI_NUM_BLOCKS = " + \ + ' 0x%X' %BlockNum + \ + TAB_LINE_BREAK) + else: + if self.BlockSizeList == []: + if not self._GetBlockSize(): + #set default block size is 1 + self.FvInfFile.append("EFI_BLOCK_SIZE = 0x1" + TAB_LINE_BREAK) + + for BlockSize in self.BlockSizeList: + if BlockSize[0] is not None: + self.FvInfFile.append("EFI_BLOCK_SIZE = " + \ + '0x%X' %BlockSize[0] + \ + TAB_LINE_BREAK) + + if BlockSize[1] is not None: + self.FvInfFile.append("EFI_NUM_BLOCKS = " + \ + ' 0x%X' %BlockSize[1] + \ + TAB_LINE_BREAK) + + if self.BsBaseAddress is not None: + self.FvInfFile.append('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \ + '0x%X' %self.BsBaseAddress) + if self.RtBaseAddress is not None: + self.FvInfFile.append('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \ + '0x%X' %self.RtBaseAddress) + # + # Add attribute + # + self.FvInfFile.append("[attributes]" + TAB_LINE_BREAK) + + self.FvInfFile.append("EFI_ERASE_POLARITY = " + \ + ' %s' %ErasePloarity + \ + TAB_LINE_BREAK) + if not (self.FvAttributeDict is None): + for FvAttribute in self.FvAttributeDict.keys(): + if FvAttribute == "FvUsedSizeEnable": + if self.FvAttributeDict[FvAttribute].upper() in ('TRUE', '1'): + self.UsedSizeEnable = True + continue + self.FvInfFile.append("EFI_" + \ + FvAttribute + \ + ' = ' + \ + self.FvAttributeDict[FvAttribute] + \ + TAB_LINE_BREAK ) + if self.FvAlignment is not None: + self.FvInfFile.append("EFI_FVB2_ALIGNMENT_" + \ + self.FvAlignment.strip() + \ + " = TRUE" + \ + TAB_LINE_BREAK) + + # + # Generate FV extension header file + # + if not self.FvNameGuid: + if len(self.FvExtEntryType) > 0 or self.UsedSizeEnable: + GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName)) + else: + TotalSize = 16 + 4 + Buffer = bytearray() + if self.UsedSizeEnable: + TotalSize += (4 + 4) + ## define EFI_FV_EXT_TYPE_USED_SIZE_TYPE 0x03 + #typedef struct + # { + # EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr; + # UINT32 UsedSize; + # } EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE; + Buffer += pack('HHL', 8, 3, 0) + + if self.FvNameString == 'TRUE': + # + # Create EXT entry for FV UI name + # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C + # + FvUiLen = len(self.UiFvName) + TotalSize += (FvUiLen + 16 + 4) + Guid = FV_UI_EXT_ENTY_GUID.split('-') + # + # Layout: + # EFI_FIRMWARE_VOLUME_EXT_ENTRY: size 4 + # GUID: size 16 + # FV UI name + # + Buffer += (pack('HH', (FvUiLen + 16 + 4), 0x0002) + + PackGUID(Guid) + + self.UiFvName.encode('utf-8')) + + for Index in range (0, len(self.FvExtEntryType)): + if self.FvExtEntryType[Index] == 'FILE': + # check if the path is absolute or relative + if os.path.isabs(self.FvExtEntryData[Index]): + FileFullPath = os.path.normpath(self.FvExtEntryData[Index]) + else: + FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index])) + # check if the file path exists or not + if not os.path.isfile(FileFullPath): + GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index])) + FvExtFile = open (FileFullPath, 'rb') + FvExtFile.seek(0, 2) + Size = FvExtFile.tell() + if Size >= 0x10000: + GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index])) + TotalSize += (Size + 4) + FvExtFile.seek(0) + Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16)) + Buffer += FvExtFile.read() + FvExtFile.close() + if self.FvExtEntryType[Index] == 'DATA': + ByteList = self.FvExtEntryData[Index].split(',') + Size = len (ByteList) + if Size >= 0x10000: + GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index])) + TotalSize += (Size + 4) + Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16)) + for Index1 in range (0, Size): + Buffer += pack('B', int(ByteList[Index1], 16)) + + Guid = self.FvNameGuid.split('-') + Buffer = PackGUID(Guid) + pack('=L', TotalSize) + Buffer + + # + # Generate FV extension header file if the total size is not zero + # + if TotalSize > 0: + FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext') + FvExtHeaderFile = BytesIO() + FvExtHeaderFile.write(Buffer) + Changed = SaveFileOnChange(FvExtHeaderFileName, FvExtHeaderFile.getvalue(), True) + FvExtHeaderFile.close() + if Changed: + if os.path.exists (self.InfFileName): + os.remove (self.InfFileName) + self.FvInfFile.append("EFI_FV_EXT_HEADER_FILE_NAME = " + \ + FvExtHeaderFileName + \ + TAB_LINE_BREAK) + + # + # Add [Files] + # + self.FvInfFile.append("[files]" + TAB_LINE_BREAK) diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/FvImageSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/FvImageSection.py new file mode 100644 index 000000000..ff2d5ca3c --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/FvImageSection.py @@ -0,0 +1,158 @@ +## @file +# process FV image section generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Section +from io import BytesIO +from .Ffs import SectionSuffix +import subprocess +from .GenFdsGlobalVariable import GenFdsGlobalVariable +import Common.LongFilePathOs as os +from CommonDataClass.FdfClass import FvImageSectionClassObject +from Common.MultipleWorkspace import MultipleWorkspace as mws +from Common import EdkLogger +from Common.BuildToolError import * +from Common.DataType import * + +## generate FV image section +# +# +class FvImageSection(FvImageSectionClassObject): + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + FvImageSectionClassObject.__init__(self) + + ## GenSection() method + # + # Generate FV image section + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # @retval tuple (Generated file name, section alignment) + # + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf = None, Dict = None, IsMakefile = False): + + OutputFileList = [] + if Dict is None: + Dict = {} + if self.FvFileType is not None: + FileList, IsSect = Section.Section.GetFileList(FfsInf, self.FvFileType, self.FvFileExtension) + if IsSect : + return FileList, self.Alignment + + Num = SecNum + + MaxFvAlignment = 0 + for FvFileName in FileList: + FvAlignmentValue = 0 + if os.path.isfile(FvFileName): + FvFileObj = open (FvFileName, 'rb') + FvFileObj.seek(0) + # PI FvHeader is 0x48 byte + FvHeaderBuffer = FvFileObj.read(0x48) + # FV alignment position. + if isinstance(FvHeaderBuffer[0x2E], str): + FvAlignmentValue = 1 << (ord(FvHeaderBuffer[0x2E]) & 0x1F) + else: + FvAlignmentValue = 1 << (FvHeaderBuffer[0x2E] & 0x1F) + FvFileObj.close() + if FvAlignmentValue > MaxFvAlignment: + MaxFvAlignment = FvAlignmentValue + + OutputFile = os.path.join(OutputPath, ModuleName + SUP_MODULE_SEC + Num + SectionSuffix.get("FV_IMAGE")) + GenFdsGlobalVariable.GenerateSection(OutputFile, [FvFileName], 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE', IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + + # MaxFvAlignment is larger than or equal to 1K + if MaxFvAlignment >= 0x400: + if MaxFvAlignment >= 0x100000: + #The max alignment supported by FFS is 16M. + if MaxFvAlignment >= 0x1000000: + self.Alignment = "16M" + else: + self.Alignment = str(MaxFvAlignment // 0x100000) + "M" + else: + self.Alignment = str (MaxFvAlignment // 0x400) + "K" + else: + # MaxFvAlignment is less than 1K + self.Alignment = str (MaxFvAlignment) + + return OutputFileList, self.Alignment + # + # Generate Fv + # + if self.FvName is not None: + Buffer = BytesIO() + Fv = GenFdsGlobalVariable.FdfParser.Profile.FvDict.get(self.FvName) + if Fv is not None: + self.Fv = Fv + if not self.FvAddr and self.Fv.BaseAddress: + self.FvAddr = self.Fv.BaseAddress + FvFileName = Fv.AddToBuffer(Buffer, self.FvAddr, MacroDict = Dict, Flag=IsMakefile) + if Fv.FvAlignment is not None: + if self.Alignment is None: + self.Alignment = Fv.FvAlignment + else: + if GenFdsGlobalVariable.GetAlignment (Fv.FvAlignment) > GenFdsGlobalVariable.GetAlignment (self.Alignment): + self.Alignment = Fv.FvAlignment + else: + if self.FvFileName is not None: + FvFileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FvFileName) + if os.path.isfile(FvFileName): + FvFileObj = open (FvFileName, 'rb') + FvFileObj.seek(0) + # PI FvHeader is 0x48 byte + FvHeaderBuffer = FvFileObj.read(0x48) + # FV alignment position. + if isinstance(FvHeaderBuffer[0x2E], str): + FvAlignmentValue = 1 << (ord(FvHeaderBuffer[0x2E]) & 0x1F) + else: + FvAlignmentValue = 1 << (FvHeaderBuffer[0x2E] & 0x1F) + # FvAlignmentValue is larger than or equal to 1K + if FvAlignmentValue >= 0x400: + if FvAlignmentValue >= 0x100000: + #The max alignment supported by FFS is 16M. + if FvAlignmentValue >= 0x1000000: + self.Alignment = "16M" + else: + self.Alignment = str(FvAlignmentValue // 0x100000) + "M" + else: + self.Alignment = str (FvAlignmentValue // 0x400) + "K" + else: + # FvAlignmentValue is less than 1K + self.Alignment = str (FvAlignmentValue) + FvFileObj.close() + else: + if len (mws.getPkgPath()) == 0: + EdkLogger.error("GenFds", FILE_NOT_FOUND, "%s is not found in WORKSPACE: %s" % self.FvFileName, GenFdsGlobalVariable.WorkSpaceDir) + else: + EdkLogger.error("GenFds", FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.FvFileName, '\n\t'.join(mws.getPkgPath()))) + + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "FvImageSection Failed! %s NOT found in FDF" % self.FvName) + + # + # Prepare the parameter of GenSection + # + OutputFile = os.path.join(OutputPath, ModuleName + SUP_MODULE_SEC + SecNum + SectionSuffix.get("FV_IMAGE")) + GenFdsGlobalVariable.GenerateSection(OutputFile, [FvFileName], 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE', IsMakefile=IsMakefile) + OutputFileList.append(OutputFile) + + return OutputFileList, self.Alignment diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/GenFds.py b/roms/edk2/BaseTools/Source/Python/GenFds/GenFds.py new file mode 100644 index 000000000..d5511f4c4 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/GenFds.py @@ -0,0 +1,797 @@ +## @file +# generate flash image +# +# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import print_function +from __future__ import absolute_import +from re import compile +from optparse import OptionParser +from sys import exit +from glob import glob +from struct import unpack +from linecache import getlines +from io import BytesIO + +import Common.LongFilePathOs as os +from Common.TargetTxtClassObject import TargetTxtDict +from Common.DataType import * +import Common.GlobalData as GlobalData +from Common import EdkLogger +from Common.StringUtils import NormPath +from Common.Misc import DirCache, PathClass, GuidStructureStringToGuidString +from Common.Misc import SaveFileOnChange, ClearDuplicatedInf +from Common.BuildVersion import gBUILD_VERSION +from Common.MultipleWorkspace import MultipleWorkspace as mws +from 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 +from Workspace.WorkspaceDatabase import WorkspaceDatabase + +from .FdfParser import FdfParser, Warning +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from .FfsFileStatement import FileStatement +import Common.DataType as DataType +from struct import Struct + +## Version and Copyright +versionNumber = "1.0" + ' ' + gBUILD_VERSION +__version__ = "%prog Version " + versionNumber +__copyright__ = "Copyright (c) 2007 - 2018, Intel Corporation All rights reserved." + +## Tool entrance method +# +# This method mainly dispatch specific methods per the command line options. +# If no error found, return zero value so the caller of this tool can know +# if it's executed successfully or not. +# +# @retval 0 Tool was successful +# @retval 1 Tool failed +# +def main(): + global Options + Options = myOptionParser() + EdkLogger.Initialize() + return GenFdsApi(OptionsToCommandDict(Options)) + +def resetFdsGlobalVariable(): + GenFdsGlobalVariable.FvDir = '' + GenFdsGlobalVariable.OutputDirDict = {} + GenFdsGlobalVariable.BinDir = '' + # will be FvDir + os.sep + 'Ffs' + GenFdsGlobalVariable.FfsDir = '' + GenFdsGlobalVariable.FdfParser = None + GenFdsGlobalVariable.LibDir = '' + GenFdsGlobalVariable.WorkSpace = None + GenFdsGlobalVariable.WorkSpaceDir = '' + GenFdsGlobalVariable.ConfDir = '' + GenFdsGlobalVariable.OutputDirFromDscDict = {} + GenFdsGlobalVariable.TargetName = '' + GenFdsGlobalVariable.ToolChainTag = '' + GenFdsGlobalVariable.RuleDict = {} + GenFdsGlobalVariable.ArchList = None + GenFdsGlobalVariable.ActivePlatform = None + GenFdsGlobalVariable.FvAddressFileName = '' + GenFdsGlobalVariable.VerboseMode = False + GenFdsGlobalVariable.DebugLevel = -1 + GenFdsGlobalVariable.SharpCounter = 0 + GenFdsGlobalVariable.SharpNumberPerLine = 40 + GenFdsGlobalVariable.FdfFile = '' + GenFdsGlobalVariable.FdfFileTimeStamp = 0 + GenFdsGlobalVariable.FixedLoadAddress = False + GenFdsGlobalVariable.PlatformName = '' + + GenFdsGlobalVariable.BuildRuleFamily = DataType.TAB_COMPILER_MSFT + GenFdsGlobalVariable.ToolChainFamily = DataType.TAB_COMPILER_MSFT + GenFdsGlobalVariable.__BuildRuleDatabase = None + GenFdsGlobalVariable.GuidToolDefinition = {} + GenFdsGlobalVariable.FfsCmdDict = {} + GenFdsGlobalVariable.SecCmdList = [] + GenFdsGlobalVariable.CopyList = [] + GenFdsGlobalVariable.ModuleFile = '' + GenFdsGlobalVariable.EnableGenfdsMultiThread = True + + GenFdsGlobalVariable.LargeFileInFvFlags = [] + GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID = '5473C07A-3DCB-4dca-BD6F-1E9689E7349A' + GenFdsGlobalVariable.LARGE_FILE_SIZE = 0x1000000 + + GenFdsGlobalVariable.SectionHeader = Struct("3B 1B") + + # FvName, FdName, CapName in FDF, Image file name + GenFdsGlobalVariable.ImageBinDict = {} + +def GenFdsApi(FdsCommandDict, WorkSpaceDataBase=None): + global Workspace + Workspace = "" + ArchList = None + ReturnCode = 0 + resetFdsGlobalVariable() + + try: + if FdsCommandDict.get("verbose"): + EdkLogger.SetLevel(EdkLogger.VERBOSE) + GenFdsGlobalVariable.VerboseMode = True + + if FdsCommandDict.get("FixedAddress"): + GenFdsGlobalVariable.FixedLoadAddress = True + + if FdsCommandDict.get("quiet"): + EdkLogger.SetLevel(EdkLogger.QUIET) + if FdsCommandDict.get("debug"): + EdkLogger.SetLevel(FdsCommandDict.get("debug") + 1) + GenFdsGlobalVariable.DebugLevel = FdsCommandDict.get("debug") + else: + EdkLogger.SetLevel(EdkLogger.INFO) + + if not FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE')): + EdkLogger.error("GenFds", OPTION_MISSING, "WORKSPACE not defined", + ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.") + elif not os.path.exists(FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE'))): + EdkLogger.error("GenFds", PARAMETER_INVALID, "WORKSPACE is invalid", + ExtraData="Please use '-w' switch to pass it or set the WORKSPACE environment variable.") + else: + Workspace = os.path.normcase(FdsCommandDict.get("Workspace",os.environ.get('WORKSPACE'))) + GenFdsGlobalVariable.WorkSpaceDir = Workspace + if FdsCommandDict.get("debug"): + GenFdsGlobalVariable.VerboseLogger("Using Workspace:" + Workspace) + if FdsCommandDict.get("GenfdsMultiThread"): + GenFdsGlobalVariable.EnableGenfdsMultiThread = True + else: + GenFdsGlobalVariable.EnableGenfdsMultiThread = False + os.chdir(GenFdsGlobalVariable.WorkSpaceDir) + + # set multiple workspace + PackagesPath = os.getenv("PACKAGES_PATH") + mws.setWs(GenFdsGlobalVariable.WorkSpaceDir, PackagesPath) + + if FdsCommandDict.get("fdf_file"): + FdfFilename = FdsCommandDict.get("fdf_file")[0].Path + FdfFilename = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdfFilename) + + if FdfFilename[0:2] == '..': + FdfFilename = os.path.realpath(FdfFilename) + if not os.path.isabs(FdfFilename): + FdfFilename = mws.join(GenFdsGlobalVariable.WorkSpaceDir, FdfFilename) + if not os.path.exists(FdfFilename): + EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=FdfFilename) + + GenFdsGlobalVariable.FdfFile = FdfFilename + GenFdsGlobalVariable.FdfFileTimeStamp = os.path.getmtime(FdfFilename) + else: + EdkLogger.error("GenFds", OPTION_MISSING, "Missing FDF filename") + + if FdsCommandDict.get("build_target"): + GenFdsGlobalVariable.TargetName = FdsCommandDict.get("build_target") + + if FdsCommandDict.get("toolchain_tag"): + GenFdsGlobalVariable.ToolChainTag = FdsCommandDict.get("toolchain_tag") + + if FdsCommandDict.get("active_platform"): + ActivePlatform = FdsCommandDict.get("active_platform") + ActivePlatform = GenFdsGlobalVariable.ReplaceWorkspaceMacro(ActivePlatform) + + if ActivePlatform[0:2] == '..': + ActivePlatform = os.path.realpath(ActivePlatform) + + if not os.path.isabs (ActivePlatform): + ActivePlatform = mws.join(GenFdsGlobalVariable.WorkSpaceDir, ActivePlatform) + + if not os.path.exists(ActivePlatform): + EdkLogger.error("GenFds", FILE_NOT_FOUND, "ActivePlatform doesn't exist!") + else: + EdkLogger.error("GenFds", OPTION_MISSING, "Missing active platform") + + GenFdsGlobalVariable.ActivePlatform = PathClass(NormPath(ActivePlatform)) + + if FdsCommandDict.get("conf_directory"): + # Get alternate Conf location, if it is absolute, then just use the absolute directory name + ConfDirectoryPath = os.path.normpath(FdsCommandDict.get("conf_directory")) + if ConfDirectoryPath.startswith('"'): + ConfDirectoryPath = ConfDirectoryPath[1:] + if ConfDirectoryPath.endswith('"'): + ConfDirectoryPath = ConfDirectoryPath[:-1] + if not os.path.isabs(ConfDirectoryPath): + # Since alternate directory name is not absolute, the alternate directory is located within the WORKSPACE + # This also handles someone specifying the Conf directory in the workspace. Using --conf=Conf + ConfDirectoryPath = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, ConfDirectoryPath) + else: + if "CONF_PATH" in os.environ: + ConfDirectoryPath = os.path.normcase(os.environ["CONF_PATH"]) + else: + # Get standard WORKSPACE/Conf, use the absolute path to the WORKSPACE/Conf + ConfDirectoryPath = mws.join(GenFdsGlobalVariable.WorkSpaceDir, 'Conf') + GenFdsGlobalVariable.ConfDir = ConfDirectoryPath + if not GlobalData.gConfDirectory: + GlobalData.gConfDirectory = GenFdsGlobalVariable.ConfDir + BuildConfigurationFile = os.path.normpath(os.path.join(ConfDirectoryPath, "target.txt")) + if os.path.isfile(BuildConfigurationFile) == True: + # if no build target given in command line, get it from target.txt + TargetObj = TargetTxtDict() + TargetTxt = TargetObj.Target + if not GenFdsGlobalVariable.TargetName: + BuildTargetList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TARGET] + if len(BuildTargetList) != 1: + EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for Target.") + GenFdsGlobalVariable.TargetName = BuildTargetList[0] + + # if no tool chain given in command line, get it from target.txt + if not GenFdsGlobalVariable.ToolChainTag: + ToolChainList = TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_TAG] + if ToolChainList is None or len(ToolChainList) == 0: + EdkLogger.error("GenFds", RESOURCE_NOT_AVAILABLE, ExtraData="No toolchain given. Don't know how to build.") + if len(ToolChainList) != 1: + EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="Only allows one instance for ToolChain.") + GenFdsGlobalVariable.ToolChainTag = ToolChainList[0] + else: + EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=BuildConfigurationFile) + + #Set global flag for build mode + GlobalData.gIgnoreSource = FdsCommandDict.get("IgnoreSources") + + if FdsCommandDict.get("macro"): + for Pair in FdsCommandDict.get("macro"): + if Pair.startswith('"'): + Pair = Pair[1:] + if Pair.endswith('"'): + Pair = Pair[:-1] + List = Pair.split('=') + if len(List) == 2: + if not List[1].strip(): + EdkLogger.error("GenFds", OPTION_VALUE_INVALID, ExtraData="No Value given for Macro %s" %List[0]) + if List[0].strip() in ["WORKSPACE", "TARGET", "TOOLCHAIN"]: + GlobalData.gGlobalDefines[List[0].strip()] = List[1].strip() + else: + GlobalData.gCommandLineDefines[List[0].strip()] = List[1].strip() + else: + GlobalData.gCommandLineDefines[List[0].strip()] = "TRUE" + os.environ["WORKSPACE"] = Workspace + + # Use the -t and -b option as gGlobalDefines's TOOLCHAIN and TARGET if they are not defined + if "TARGET" not in GlobalData.gGlobalDefines: + GlobalData.gGlobalDefines["TARGET"] = GenFdsGlobalVariable.TargetName + if "TOOLCHAIN" not in GlobalData.gGlobalDefines: + GlobalData.gGlobalDefines["TOOLCHAIN"] = GenFdsGlobalVariable.ToolChainTag + if "TOOL_CHAIN_TAG" not in GlobalData.gGlobalDefines: + GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = GenFdsGlobalVariable.ToolChainTag + + """call Workspace build create database""" + GlobalData.gDatabasePath = os.path.normpath(os.path.join(ConfDirectoryPath, GlobalData.gDatabasePath)) + + if WorkSpaceDataBase: + BuildWorkSpace = WorkSpaceDataBase + else: + BuildWorkSpace = WorkspaceDatabase() + # + # Get files real name in workspace dir + # + GlobalData.gAllFiles = DirCache(Workspace) + GlobalData.gWorkspace = Workspace + + if FdsCommandDict.get("build_architecture_list"): + ArchList = FdsCommandDict.get("build_architecture_list").split(',') + else: + ArchList = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList + + TargetArchList = set(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].SupArchList) & set(ArchList) + if len(TargetArchList) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, "Target ARCH %s not in platform supported ARCH %s" % (str(ArchList), str(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, TAB_COMMON].SupArchList))) + + for Arch in ArchList: + GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = NormPath(BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].OutputDirectory) + + # assign platform name based on last entry in ArchList + GenFdsGlobalVariable.PlatformName = BuildWorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, ArchList[-1], FdsCommandDict.get("build_target"), FdsCommandDict.get("toolchain_tag")].PlatformName + + if FdsCommandDict.get("platform_build_directory"): + OutputDirFromCommandLine = GenFdsGlobalVariable.ReplaceWorkspaceMacro(FdsCommandDict.get("platform_build_directory")) + if not os.path.isabs (OutputDirFromCommandLine): + OutputDirFromCommandLine = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, OutputDirFromCommandLine) + for Arch in ArchList: + GenFdsGlobalVariable.OutputDirDict[Arch] = OutputDirFromCommandLine + else: + for Arch in ArchList: + GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.join(GenFdsGlobalVariable.OutputDirFromDscDict[Arch], GenFdsGlobalVariable.TargetName + '_' + GenFdsGlobalVariable.ToolChainTag) + + for Key in GenFdsGlobalVariable.OutputDirDict: + OutputDir = GenFdsGlobalVariable.OutputDirDict[Key] + if OutputDir[0:2] == '..': + OutputDir = os.path.realpath(OutputDir) + + if OutputDir[1] != ':': + OutputDir = os.path.join (GenFdsGlobalVariable.WorkSpaceDir, OutputDir) + + if not os.path.exists(OutputDir): + EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=OutputDir) + GenFdsGlobalVariable.OutputDirDict[Key] = OutputDir + + """ Parse Fdf file, has to place after build Workspace as FDF may contain macros from DSC file """ + if WorkSpaceDataBase: + FdfParserObj = GlobalData.gFdfParser + else: + FdfParserObj = FdfParser(FdfFilename) + FdfParserObj.ParseFile() + + if FdfParserObj.CycleReferenceCheck(): + EdkLogger.error("GenFds", FORMAT_NOT_SUPPORTED, "Cycle Reference Detected in FDF file") + + if FdsCommandDict.get("fd"): + if FdsCommandDict.get("fd")[0].upper() in FdfParserObj.Profile.FdDict: + GenFds.OnlyGenerateThisFd = FdsCommandDict.get("fd")[0] + else: + EdkLogger.error("GenFds", OPTION_VALUE_INVALID, + "No such an FD in FDF file: %s" % FdsCommandDict.get("fd")[0]) + + if FdsCommandDict.get("fv"): + if FdsCommandDict.get("fv")[0].upper() in FdfParserObj.Profile.FvDict: + GenFds.OnlyGenerateThisFv = FdsCommandDict.get("fv")[0] + else: + EdkLogger.error("GenFds", OPTION_VALUE_INVALID, + "No such an FV in FDF file: %s" % FdsCommandDict.get("fv")[0]) + + if FdsCommandDict.get("cap"): + if FdsCommandDict.get("cap")[0].upper() in FdfParserObj.Profile.CapsuleDict: + GenFds.OnlyGenerateThisCap = FdsCommandDict.get("cap")[0] + else: + EdkLogger.error("GenFds", OPTION_VALUE_INVALID, + "No such a Capsule in FDF file: %s" % FdsCommandDict.get("cap")[0]) + + GenFdsGlobalVariable.WorkSpace = BuildWorkSpace + if ArchList: + GenFdsGlobalVariable.ArchList = ArchList + + # Dsc Build Data will handle Pcd Settings from CommandLine. + + """Modify images from build output if the feature of loading driver at fixed address is on.""" + if GenFdsGlobalVariable.FixedLoadAddress: + GenFds.PreprocessImage(BuildWorkSpace, GenFdsGlobalVariable.ActivePlatform) + + # Record the FV Region info that may specific in the FD + if FdfParserObj.Profile.FvDict and FdfParserObj.Profile.FdDict: + for FvObj in FdfParserObj.Profile.FvDict.values(): + for FdObj in FdfParserObj.Profile.FdDict.values(): + for RegionObj in FdObj.RegionList: + if RegionObj.RegionType != BINARY_FILE_TYPE_FV: + continue + for RegionData in RegionObj.RegionDataList: + if FvObj.UiFvName.upper() == RegionData.upper(): + if not FvObj.BaseAddress: + FvObj.BaseAddress = '0x%x' % (int(FdObj.BaseAddress, 0) + RegionObj.Offset) + if FvObj.FvRegionInFD: + if FvObj.FvRegionInFD != RegionObj.Size: + EdkLogger.error("GenFds", FORMAT_INVALID, "The FV %s's region is specified in multiple FD with different value." %FvObj.UiFvName) + else: + FvObj.FvRegionInFD = RegionObj.Size + RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, FvObj) + + """Call GenFds""" + GenFds.GenFd('', FdfParserObj, BuildWorkSpace, ArchList) + + """Generate GUID cross reference file""" + GenFds.GenerateGuidXRefFile(BuildWorkSpace, ArchList, FdfParserObj) + + """Display FV space info.""" + GenFds.DisplayFvSpaceInfo(FdfParserObj) + + except Warning as X: + EdkLogger.error(X.ToolName, FORMAT_INVALID, File=X.FileName, Line=X.LineNumber, ExtraData=X.Message, RaiseError=False) + ReturnCode = FORMAT_INVALID + except FatalError as X: + if FdsCommandDict.get("debug") is not None: + import traceback + EdkLogger.quiet(traceback.format_exc()) + ReturnCode = X.args[0] + except: + import traceback + EdkLogger.error( + "\nPython", + CODE_ERROR, + "Tools code failure", + ExtraData="Please send email to %s for help, attaching following call stack trace!\n" % MSG_EDKII_MAIL_ADDR, + RaiseError=False + ) + EdkLogger.quiet(traceback.format_exc()) + ReturnCode = CODE_ERROR + finally: + ClearDuplicatedInf() + return ReturnCode + +def OptionsToCommandDict(Options): + FdsCommandDict = {} + FdsCommandDict["verbose"] = Options.verbose + FdsCommandDict["FixedAddress"] = Options.FixedAddress + FdsCommandDict["quiet"] = Options.quiet + FdsCommandDict["debug"] = Options.debug + FdsCommandDict["Workspace"] = Options.Workspace + FdsCommandDict["GenfdsMultiThread"] = not Options.NoGenfdsMultiThread + FdsCommandDict["fdf_file"] = [PathClass(Options.filename)] if Options.filename else [] + FdsCommandDict["build_target"] = Options.BuildTarget + FdsCommandDict["toolchain_tag"] = Options.ToolChain + FdsCommandDict["active_platform"] = Options.activePlatform + FdsCommandDict["OptionPcd"] = Options.OptionPcd + FdsCommandDict["conf_directory"] = Options.ConfDirectory + FdsCommandDict["IgnoreSources"] = Options.IgnoreSources + FdsCommandDict["macro"] = Options.Macros + FdsCommandDict["build_architecture_list"] = Options.archList + FdsCommandDict["platform_build_directory"] = Options.outputDir + FdsCommandDict["fd"] = [Options.uiFdName] if Options.uiFdName else [] + FdsCommandDict["fv"] = [Options.uiFvName] if Options.uiFvName else [] + FdsCommandDict["cap"] = [Options.uiCapName] if Options.uiCapName else [] + return FdsCommandDict + + +gParamCheck = [] +def SingleCheckCallback(option, opt_str, value, parser): + if option not in gParamCheck: + setattr(parser.values, option.dest, value) + gParamCheck.append(option) + else: + parser.error("Option %s only allows one instance in command line!" % option) + +## Parse command line options +# +# Using standard Python module optparse to parse command line option of this tool. +# +# @retval Opt A optparse.Values object containing the parsed options +# +def myOptionParser(): + usage = "%prog [options] -f input_file -a arch_list -b build_target -p active_platform -t tool_chain_tag -D \"MacroName [= MacroValue]\"" + Parser = OptionParser(usage=usage, description=__copyright__, version="%prog " + str(versionNumber)) + Parser.add_option("-f", "--file", dest="filename", type="string", help="Name of FDF file to convert", action="callback", callback=SingleCheckCallback) + 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") + Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.") + Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed.") + Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.") + Parser.add_option("-p", "--platform", type="string", dest="activePlatform", help="Set the ACTIVE_PLATFORM, overrides target.txt ACTIVE_PLATFORM setting.", + action="callback", callback=SingleCheckCallback) + Parser.add_option("-w", "--workspace", type="string", dest="Workspace", default=os.environ.get('WORKSPACE'), help="Set the WORKSPACE", + action="callback", callback=SingleCheckCallback) + Parser.add_option("-o", "--outputDir", type="string", dest="outputDir", help="Name of Build Output directory", + action="callback", callback=SingleCheckCallback) + Parser.add_option("-r", "--rom_image", dest="uiFdName", help="Build the image using the [FD] section named by FdUiName.") + Parser.add_option("-i", "--FvImage", dest="uiFvName", help="Build the FV image using the [FV] section named by UiFvName") + Parser.add_option("-C", "--CapsuleImage", dest="uiCapName", help="Build the Capsule image using the [Capsule] section named by UiCapName") + Parser.add_option("-b", "--buildtarget", type="string", dest="BuildTarget", help="Set the build TARGET, overrides target.txt TARGET setting.", + action="callback", callback=SingleCheckCallback) + Parser.add_option("-t", "--tagname", type="string", dest="ToolChain", help="Using the tools: TOOL_CHAIN_TAG name to build the platform.", + action="callback", callback=SingleCheckCallback) + Parser.add_option("-D", "--define", action="append", type="string", dest="Macros", help="Macro: \"Name [= Value]\".") + Parser.add_option("-s", "--specifyaddress", dest="FixedAddress", action="store_true", type=None, help="Specify driver load address.") + Parser.add_option("--conf", action="store", type="string", dest="ConfDirectory", help="Specify the customized Conf directory.") + Parser.add_option("--ignore-sources", action="store_true", dest="IgnoreSources", default=False, help="Focus to a binary build and ignore all source files") + Parser.add_option("--pcd", action="append", dest="OptionPcd", help="Set PCD value by command line. Format: \"PcdName=Value\" ") + Parser.add_option("--genfds-multi-thread", action="store_true", dest="GenfdsMultiThread", default=True, help="Enable GenFds multi thread to generate ffs file.") + Parser.add_option("--no-genfds-multi-thread", action="store_true", dest="NoGenfdsMultiThread", default=False, help="Disable GenFds multi thread to generate ffs file.") + + Options, _ = Parser.parse_args() + return Options + +## The class implementing the EDK2 flash image generation process +# +# This process includes: +# 1. Collect workspace information, includes platform and module information +# 2. Call methods of Fd class to generate FD +# 3. Call methods of Fv class to generate FV that not belong to FD +# +class GenFds(object): + FdfParsef = None + OnlyGenerateThisFd = None + OnlyGenerateThisFv = None + OnlyGenerateThisCap = None + + ## GenFd() + # + # @param OutputDir Output directory + # @param FdfParserObject FDF contents parser + # @param Workspace The directory of workspace + # @param ArchList The Arch list of platform + # + @staticmethod + def GenFd (OutputDir, FdfParserObject, WorkSpace, ArchList): + GenFdsGlobalVariable.SetDir ('', FdfParserObject, WorkSpace, ArchList) + + GenFdsGlobalVariable.VerboseLogger(" Generate all Fd images and their required FV and Capsule images!") + if GenFds.OnlyGenerateThisCap is not None and GenFds.OnlyGenerateThisCap.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict: + CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[GenFds.OnlyGenerateThisCap.upper()] + if CapsuleObj is not None: + CapsuleObj.GenCapsule() + return + + if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict: + FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()] + if FdObj is not None: + FdObj.GenFd() + return + elif GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisFv is None: + for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values(): + FdObj.GenFd() + + GenFdsGlobalVariable.VerboseLogger("\n Generate other FV images! ") + if GenFds.OnlyGenerateThisFv is not None and GenFds.OnlyGenerateThisFv.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict: + FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[GenFds.OnlyGenerateThisFv.upper()] + if FvObj is not None: + Buffer = BytesIO() + FvObj.AddToBuffer(Buffer) + Buffer.close() + return + elif GenFds.OnlyGenerateThisFv is None: + for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values(): + Buffer = BytesIO() + FvObj.AddToBuffer(Buffer) + Buffer.close() + + if GenFds.OnlyGenerateThisFv is None and GenFds.OnlyGenerateThisFd is None and GenFds.OnlyGenerateThisCap is None: + if GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict != {}: + GenFdsGlobalVariable.VerboseLogger("\n Generate other Capsule images!") + for CapsuleObj in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict.values(): + CapsuleObj.GenCapsule() + + if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}: + GenFdsGlobalVariable.VerboseLogger("\n Generate all Option ROM!") + for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values(): + OptRomObj.AddToBuffer(None) + + @staticmethod + def GenFfsMakefile(OutputDir, FdfParserObject, WorkSpace, ArchList, GlobalData): + GenFdsGlobalVariable.SetEnv(FdfParserObject, WorkSpace, ArchList, GlobalData) + for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values(): + FdObj.GenFd(Flag=True) + + for FvObj in GenFdsGlobalVariable.FdfParser.Profile.FvDict.values(): + FvObj.AddToBuffer(Buffer=None, Flag=True) + + if GenFdsGlobalVariable.FdfParser.Profile.OptRomDict != {}: + for OptRomObj in GenFdsGlobalVariable.FdfParser.Profile.OptRomDict.values(): + OptRomObj.AddToBuffer(Buffer=None, Flag=True) + + return GenFdsGlobalVariable.FfsCmdDict + + ## GetFvBlockSize() + # + # @param FvObj Whose block size to get + # @retval int Block size value + # + @staticmethod + def GetFvBlockSize(FvObj): + DefaultBlockSize = 0x1 + FdObj = None + if GenFds.OnlyGenerateThisFd is not None and GenFds.OnlyGenerateThisFd.upper() in GenFdsGlobalVariable.FdfParser.Profile.FdDict: + FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[GenFds.OnlyGenerateThisFd.upper()] + if FdObj is None: + for ElementFd in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values(): + for ElementRegion in ElementFd.RegionList: + if ElementRegion.RegionType == BINARY_FILE_TYPE_FV: + for ElementRegionData in ElementRegion.RegionDataList: + if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName: + if FvObj.BlockSizeList != []: + return FvObj.BlockSizeList[0][0] + else: + return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList) + if FvObj.BlockSizeList != []: + return FvObj.BlockSizeList[0][0] + return DefaultBlockSize + else: + for ElementRegion in FdObj.RegionList: + if ElementRegion.RegionType == BINARY_FILE_TYPE_FV: + for ElementRegionData in ElementRegion.RegionDataList: + if ElementRegionData is not None and ElementRegionData.upper() == FvObj.UiFvName: + if FvObj.BlockSizeList != []: + return FvObj.BlockSizeList[0][0] + else: + return ElementRegion.BlockSizeOfRegion(ElementFd.BlockSizeList) + return DefaultBlockSize + + ## DisplayFvSpaceInfo() + # + # @param FvObj Whose block size to get + # @retval None + # + @staticmethod + def DisplayFvSpaceInfo(FdfParserObject): + + FvSpaceInfoList = [] + MaxFvNameLength = 0 + for FvName in FdfParserObject.Profile.FvDict: + if len(FvName) > MaxFvNameLength: + MaxFvNameLength = len(FvName) + FvSpaceInfoFileName = os.path.join(GenFdsGlobalVariable.FvDir, FvName.upper() + '.Fv.map') + if os.path.exists(FvSpaceInfoFileName): + FileLinesList = getlines(FvSpaceInfoFileName) + TotalFound = False + Total = '' + UsedFound = False + Used = '' + FreeFound = False + Free = '' + for Line in FileLinesList: + NameValue = Line.split('=') + if len(NameValue) == 2: + if NameValue[0].strip() == 'EFI_FV_TOTAL_SIZE': + TotalFound = True + Total = NameValue[1].strip() + if NameValue[0].strip() == 'EFI_FV_TAKEN_SIZE': + UsedFound = True + Used = NameValue[1].strip() + if NameValue[0].strip() == 'EFI_FV_SPACE_SIZE': + FreeFound = True + Free = NameValue[1].strip() + + if TotalFound and UsedFound and FreeFound: + FvSpaceInfoList.append((FvName, Total, Used, Free)) + + GenFdsGlobalVariable.InfLogger('\nFV Space Information') + for FvSpaceInfo in FvSpaceInfoList: + Name = FvSpaceInfo[0] + TotalSizeValue = int(FvSpaceInfo[1], 0) + UsedSizeValue = int(FvSpaceInfo[2], 0) + FreeSizeValue = int(FvSpaceInfo[3], 0) + if UsedSizeValue == TotalSizeValue: + Percentage = '100' + else: + Percentage = str((UsedSizeValue + 0.0) / TotalSizeValue)[0:4].lstrip('0.') + + GenFdsGlobalVariable.InfLogger(Name + ' ' + '[' + Percentage + '%Full] ' + str(TotalSizeValue) + ' total, ' + str(UsedSizeValue) + ' used, ' + str(FreeSizeValue) + ' free') + + ## PreprocessImage() + # + # @param BuildDb Database from build meta data files + # @param DscFile modules from dsc file will be preprocessed + # @retval None + # + @staticmethod + def PreprocessImage(BuildDb, DscFile): + PcdDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Pcds + PcdValue = '' + for Key in PcdDict: + PcdObj = PcdDict[Key] + if PcdObj.TokenCName == 'PcdBsBaseAddress': + PcdValue = PcdObj.DefaultValue + break + + if PcdValue == '': + return + + Int64PcdValue = int(PcdValue, 0) + if Int64PcdValue == 0 or Int64PcdValue < -1: + return + + TopAddress = 0 + if Int64PcdValue > 0: + TopAddress = Int64PcdValue + + ModuleDict = BuildDb.BuildObject[DscFile, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].Modules + for Key in ModuleDict: + ModuleObj = BuildDb.BuildObject[Key, TAB_COMMON, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + print(ModuleObj.BaseName + ' ' + ModuleObj.ModuleType) + + @staticmethod + def GenerateGuidXRefFile(BuildDb, ArchList, FdfParserObj): + GuidXRefFileName = os.path.join(GenFdsGlobalVariable.FvDir, "Guid.xref") + GuidXRefFile = [] + PkgGuidDict = {} + GuidDict = {} + ModuleList = [] + FileGuidList = [] + VariableGuidSet = set() + for Arch in ArchList: + PlatformDataBase = BuildDb.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + PkgList = GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag) + for P in PkgList: + PkgGuidDict.update(P.Guids) + for Name, Guid in PlatformDataBase.Pcds: + Pcd = PlatformDataBase.Pcds[Name, Guid] + if Pcd.Type in [TAB_PCDS_DYNAMIC_HII, TAB_PCDS_DYNAMIC_EX_HII]: + for SkuId in Pcd.SkuInfoList: + Sku = Pcd.SkuInfoList[SkuId] + if Sku.VariableGuid in VariableGuidSet:continue + VariableGuidSet.add(Sku.VariableGuid) + if Sku.VariableGuid and Sku.VariableGuid in PkgGuidDict.keys(): + GuidDict[Sku.VariableGuid] = PkgGuidDict[Sku.VariableGuid] + for ModuleFile in PlatformDataBase.Modules: + Module = BuildDb.BuildObject[ModuleFile, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + if Module in ModuleList: + continue + else: + ModuleList.append(Module) + if GlobalData.gGuidPattern.match(ModuleFile.BaseName): + GuidXRefFile.append("%s %s\n" % (ModuleFile.BaseName, Module.BaseName)) + else: + GuidXRefFile.append("%s %s\n" % (Module.Guid, Module.BaseName)) + GuidDict.update(Module.Protocols) + GuidDict.update(Module.Guids) + GuidDict.update(Module.Ppis) + for FvName in FdfParserObj.Profile.FvDict: + for FfsObj in FdfParserObj.Profile.FvDict[FvName].FfsList: + if not isinstance(FfsObj, FileStatement): + InfPath = PathClass(NormPath(mws.join(GenFdsGlobalVariable.WorkSpaceDir, FfsObj.InfFileName))) + FdfModule = BuildDb.BuildObject[InfPath, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + if FdfModule in ModuleList: + continue + else: + ModuleList.append(FdfModule) + GuidXRefFile.append("%s %s\n" % (FdfModule.Guid, FdfModule.BaseName)) + GuidDict.update(FdfModule.Protocols) + GuidDict.update(FdfModule.Guids) + GuidDict.update(FdfModule.Ppis) + else: + FileStatementGuid = FfsObj.NameGuid + if FileStatementGuid in FileGuidList: + continue + else: + FileGuidList.append(FileStatementGuid) + Name = [] + FfsPath = os.path.join(GenFdsGlobalVariable.FvDir, 'Ffs') + FfsPath = glob(os.path.join(FfsPath, FileStatementGuid) + TAB_STAR) + if not FfsPath: + continue + if not os.path.exists(FfsPath[0]): + continue + MatchDict = {} + ReFileEnds = compile('\S+(.ui)$|\S+(fv.sec.txt)$|\S+(.pe32.txt)$|\S+(.te.txt)$|\S+(.pic.txt)$|\S+(.raw.txt)$|\S+(.ffs.txt)$') + FileList = os.listdir(FfsPath[0]) + for File in FileList: + Match = ReFileEnds.search(File) + if Match: + for Index in range(1, 8): + if Match.group(Index) and Match.group(Index) in MatchDict: + MatchDict[Match.group(Index)].append(File) + elif Match.group(Index): + MatchDict[Match.group(Index)] = [File] + if not MatchDict: + continue + if '.ui' in MatchDict: + for File in MatchDict['.ui']: + with open(os.path.join(FfsPath[0], File), 'rb') as F: + F.read() + length = F.tell() + F.seek(4) + TmpStr = unpack('%dh' % ((length - 4) // 2), F.read()) + Name = ''.join(chr(c) for c in TmpStr[:-1]) + else: + FileList = [] + if 'fv.sec.txt' in MatchDict: + FileList = MatchDict['fv.sec.txt'] + elif '.pe32.txt' in MatchDict: + FileList = MatchDict['.pe32.txt'] + elif '.te.txt' in MatchDict: + FileList = MatchDict['.te.txt'] + elif '.pic.txt' in MatchDict: + FileList = MatchDict['.pic.txt'] + elif '.raw.txt' in MatchDict: + FileList = MatchDict['.raw.txt'] + elif '.ffs.txt' in MatchDict: + FileList = MatchDict['.ffs.txt'] + else: + pass + for File in FileList: + with open(os.path.join(FfsPath[0], File), 'r') as F: + Name.append((F.read().split()[-1])) + if not Name: + continue + + Name = ' '.join(Name) if isinstance(Name, type([])) else Name + GuidXRefFile.append("%s %s\n" %(FileStatementGuid, Name)) + + # Append GUIDs, Protocols, and PPIs to the Xref file + GuidXRefFile.append("\n") + for key, item in GuidDict.items(): + GuidXRefFile.append("%s %s\n" % (GuidStructureStringToGuidString(item).upper(), key)) + + if GuidXRefFile: + GuidXRefFile = ''.join(GuidXRefFile) + SaveFileOnChange(GuidXRefFileName, GuidXRefFile, False) + GenFdsGlobalVariable.InfLogger("\nGUID cross reference file can be found at %s" % GuidXRefFileName) + elif os.path.exists(GuidXRefFileName): + os.remove(GuidXRefFileName) + + +if __name__ == '__main__': + r = main() + ## 0-127 is a safe return range, and 1 is a standard default error + if r < 0 or r > 127: + r = 1 + exit(r) + diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py b/roms/edk2/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py new file mode 100644 index 000000000..dc1727c46 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/GenFdsGlobalVariable.py @@ -0,0 +1,919 @@ +## @file +# Global variables for GenFds +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import print_function +from __future__ import absolute_import + +import Common.LongFilePathOs as os +import sys +from sys import stdout +from subprocess import PIPE,Popen +from struct import Struct +from array import array + +from Common.BuildToolError import COMMAND_FAILURE,GENFDS_ERROR +from Common import EdkLogger +from Common.Misc import SaveFileOnChange + +from Common.TargetTxtClassObject import TargetTxtDict +from Common.ToolDefClassObject import ToolDefDict +from AutoGen.BuildEngine import ToolBuildRule +import Common.DataType as DataType +from Common.Misc import PathClass +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws +import Common.GlobalData as GlobalData + +## Global variables +# +# +class GenFdsGlobalVariable: + FvDir = '' + OutputDirDict = {} + BinDir = '' + # will be FvDir + os.sep + 'Ffs' + FfsDir = '' + FdfParser = None + LibDir = '' + WorkSpace = None + WorkSpaceDir = '' + ConfDir = '' + OutputDirFromDscDict = {} + TargetName = '' + ToolChainTag = '' + RuleDict = {} + ArchList = None + ActivePlatform = None + FvAddressFileName = '' + VerboseMode = False + DebugLevel = -1 + SharpCounter = 0 + SharpNumberPerLine = 40 + FdfFile = '' + FdfFileTimeStamp = 0 + FixedLoadAddress = False + PlatformName = '' + + BuildRuleFamily = DataType.TAB_COMPILER_MSFT + ToolChainFamily = DataType.TAB_COMPILER_MSFT + __BuildRuleDatabase = None + GuidToolDefinition = {} + FfsCmdDict = {} + SecCmdList = [] + CopyList = [] + ModuleFile = '' + EnableGenfdsMultiThread = True + + # + # The list whose element are flags to indicate if large FFS or SECTION files exist in FV. + # At the beginning of each generation of FV, false flag is appended to the list, + # after the call to GenerateSection returns, check the size of the output file, + # if it is greater than 0xFFFFFF, the tail flag in list is set to true, + # and EFI_FIRMWARE_FILE_SYSTEM3_GUID is passed to C GenFv. + # At the end of generation of FV, pop the flag. + # List is used as a stack to handle nested FV generation. + # + LargeFileInFvFlags = [] + EFI_FIRMWARE_FILE_SYSTEM3_GUID = '5473C07A-3DCB-4dca-BD6F-1E9689E7349A' + LARGE_FILE_SIZE = 0x1000000 + + SectionHeader = Struct("3B 1B") + + # FvName, FdName, CapName in FDF, Image file name + ImageBinDict = {} + + ## LoadBuildRule + # + @staticmethod + def _LoadBuildRule(): + if GenFdsGlobalVariable.__BuildRuleDatabase: + return GenFdsGlobalVariable.__BuildRuleDatabase + BuildRule = ToolBuildRule() + GenFdsGlobalVariable.__BuildRuleDatabase = BuildRule.ToolBuildRule + TargetObj = TargetTxtDict() + ToolDefinitionFile = TargetObj.Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF] + if ToolDefinitionFile == '': + ToolDefinitionFile = "Conf/tools_def.txt" + if os.path.isfile(ToolDefinitionFile): + ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf"))) + ToolDefinition = ToolDefObj.ToolDef.ToolsDefTxtDatabase + if DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY in ToolDefinition \ + and GenFdsGlobalVariable.ToolChainTag in ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY] \ + and ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY][GenFdsGlobalVariable.ToolChainTag]: + GenFdsGlobalVariable.BuildRuleFamily = ToolDefinition[DataType.TAB_TOD_DEFINES_BUILDRULEFAMILY][GenFdsGlobalVariable.ToolChainTag] + + if DataType.TAB_TOD_DEFINES_FAMILY in ToolDefinition \ + and GenFdsGlobalVariable.ToolChainTag in ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY] \ + and ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY][GenFdsGlobalVariable.ToolChainTag]: + GenFdsGlobalVariable.ToolChainFamily = ToolDefinition[DataType.TAB_TOD_DEFINES_FAMILY][GenFdsGlobalVariable.ToolChainTag] + return GenFdsGlobalVariable.__BuildRuleDatabase + + ## GetBuildRules + # @param Inf: object of InfBuildData + # @param Arch: current arch + # + @staticmethod + def GetBuildRules(Inf, Arch): + if not Arch: + Arch = DataType.TAB_COMMON + + if not Arch in GenFdsGlobalVariable.OutputDirDict: + return {} + + BuildRuleDatabase = GenFdsGlobalVariable._LoadBuildRule() + if not BuildRuleDatabase: + return {} + + PathClassObj = PathClass(Inf.MetaFile.File, + GenFdsGlobalVariable.WorkSpaceDir) + BuildDir = os.path.join( + GenFdsGlobalVariable.OutputDirDict[Arch], + Arch, + PathClassObj.SubDir, + PathClassObj.BaseName + ) + BinDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[Arch], Arch) + Macro = { + "WORKSPACE":GenFdsGlobalVariable.WorkSpaceDir, + "MODULE_NAME":Inf.BaseName, + "MODULE_GUID":Inf.Guid, + "MODULE_VERSION":Inf.Version, + "MODULE_TYPE":Inf.ModuleType, + "MODULE_FILE":str(PathClassObj), + "MODULE_FILE_BASE_NAME":PathClassObj.BaseName, + "MODULE_RELATIVE_DIR":PathClassObj.SubDir, + "MODULE_DIR":PathClassObj.SubDir, + "BASE_NAME":Inf.BaseName, + "ARCH":Arch, + "TOOLCHAIN":GenFdsGlobalVariable.ToolChainTag, + "TOOLCHAIN_TAG":GenFdsGlobalVariable.ToolChainTag, + "TOOL_CHAIN_TAG":GenFdsGlobalVariable.ToolChainTag, + "TARGET":GenFdsGlobalVariable.TargetName, + "BUILD_DIR":GenFdsGlobalVariable.OutputDirDict[Arch], + "BIN_DIR":BinDir, + "LIB_DIR":BinDir, + "MODULE_BUILD_DIR":BuildDir, + "OUTPUT_DIR":os.path.join(BuildDir, "OUTPUT"), + "DEBUG_DIR":os.path.join(BuildDir, "DEBUG") + } + + BuildRules = {} + for Type in BuildRuleDatabase.FileTypeList: + #first try getting build rule by BuildRuleFamily + RuleObject = BuildRuleDatabase[Type, Inf.BuildType, Arch, GenFdsGlobalVariable.BuildRuleFamily] + if not RuleObject: + # build type is always module type, but ... + if Inf.ModuleType != Inf.BuildType: + RuleObject = BuildRuleDatabase[Type, Inf.ModuleType, Arch, GenFdsGlobalVariable.BuildRuleFamily] + #second try getting build rule by ToolChainFamily + if not RuleObject: + RuleObject = BuildRuleDatabase[Type, Inf.BuildType, Arch, GenFdsGlobalVariable.ToolChainFamily] + if not RuleObject: + # build type is always module type, but ... + if Inf.ModuleType != Inf.BuildType: + RuleObject = BuildRuleDatabase[Type, Inf.ModuleType, Arch, GenFdsGlobalVariable.ToolChainFamily] + if not RuleObject: + continue + RuleObject = RuleObject.Instantiate(Macro) + BuildRules[Type] = RuleObject + for Ext in RuleObject.SourceFileExtList: + BuildRules[Ext] = RuleObject + return BuildRules + + ## GetModuleCodaTargetList + # + # @param Inf: object of InfBuildData + # @param Arch: current arch + # + @staticmethod + def GetModuleCodaTargetList(Inf, Arch): + BuildRules = GenFdsGlobalVariable.GetBuildRules(Inf, Arch) + if not BuildRules: + return [] + + TargetList = set() + FileList = [] + + if not Inf.IsBinaryModule: + for File in Inf.Sources: + if File.TagName in {"", DataType.TAB_STAR, GenFdsGlobalVariable.ToolChainTag} and \ + File.ToolChainFamily in {"", DataType.TAB_STAR, GenFdsGlobalVariable.ToolChainFamily}: + FileList.append((File, DataType.TAB_UNKNOWN_FILE)) + + for File in Inf.Binaries: + if File.Target in {DataType.TAB_COMMON, DataType.TAB_STAR, GenFdsGlobalVariable.TargetName}: + FileList.append((File, File.Type)) + + for File, FileType in FileList: + LastTarget = None + RuleChain = [] + SourceList = [File] + Index = 0 + while Index < len(SourceList): + Source = SourceList[Index] + Index = Index + 1 + + if File.IsBinary and File == Source and Inf.Binaries and File in Inf.Binaries: + # Skip all files that are not binary libraries + if not Inf.LibraryClass: + continue + RuleObject = BuildRules[DataType.TAB_DEFAULT_BINARY_FILE] + elif FileType in BuildRules: + RuleObject = BuildRules[FileType] + elif Source.Ext in BuildRules: + RuleObject = BuildRules[Source.Ext] + else: + # stop at no more rules + if LastTarget: + TargetList.add(str(LastTarget)) + break + + FileType = RuleObject.SourceFileType + + # stop at STATIC_LIBRARY for library + if Inf.LibraryClass and FileType == DataType.TAB_STATIC_LIBRARY: + if LastTarget: + TargetList.add(str(LastTarget)) + break + + Target = RuleObject.Apply(Source) + if not Target: + if LastTarget: + TargetList.add(str(LastTarget)) + break + elif not Target.Outputs: + # Only do build for target with outputs + TargetList.add(str(Target)) + + # to avoid cyclic rule + if FileType in RuleChain: + break + + RuleChain.append(FileType) + SourceList.extend(Target.Outputs) + LastTarget = Target + FileType = DataType.TAB_UNKNOWN_FILE + for Cmd in Target.Commands: + if "$(CP)" == Cmd.split()[0]: + CpTarget = Cmd.split()[2] + TargetList.add(CpTarget) + + return list(TargetList) + + ## SetDir() + # + # @param OutputDir Output directory + # @param FdfParser FDF contents parser + # @param Workspace The directory of workspace + # @param ArchList The Arch list of platform + # + @staticmethod + def SetDir (OutputDir, FdfParser, WorkSpace, ArchList): + GenFdsGlobalVariable.VerboseLogger("GenFdsGlobalVariable.OutputDir:%s" % OutputDir) + GenFdsGlobalVariable.FdfParser = FdfParser + GenFdsGlobalVariable.WorkSpace = WorkSpace + GenFdsGlobalVariable.FvDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[ArchList[0]], DataType.TAB_FV_DIRECTORY) + 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) + + # + # Create FV Address inf file + # + GenFdsGlobalVariable.FvAddressFileName = os.path.join(GenFdsGlobalVariable.FfsDir, 'FvAddress.inf') + FvAddressFile = open(GenFdsGlobalVariable.FvAddressFileName, 'w') + # + # Add [Options] + # + FvAddressFile.writelines("[options]" + DataType.TAB_LINE_BREAK) + BsAddress = '0' + for Arch in ArchList: + if GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].BsBaseAddress: + BsAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].BsBaseAddress + break + + FvAddressFile.writelines("EFI_BOOT_DRIVER_BASE_ADDRESS = " + \ + BsAddress + \ + DataType.TAB_LINE_BREAK) + + RtAddress = '0' + for Arch in reversed(ArchList): + temp = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag].RtBaseAddress + if temp: + RtAddress = temp + break + + FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \ + RtAddress + \ + DataType.TAB_LINE_BREAK) + + FvAddressFile.close() + + @staticmethod + def SetEnv(FdfParser, WorkSpace, ArchList, GlobalData): + GenFdsGlobalVariable.ModuleFile = WorkSpace.ModuleFile + GenFdsGlobalVariable.FdfParser = FdfParser + GenFdsGlobalVariable.WorkSpace = WorkSpace.Db + GenFdsGlobalVariable.ArchList = ArchList + GenFdsGlobalVariable.ToolChainTag = GlobalData.gGlobalDefines["TOOL_CHAIN_TAG"] + GenFdsGlobalVariable.TargetName = GlobalData.gGlobalDefines["TARGET"] + GenFdsGlobalVariable.ActivePlatform = GlobalData.gActivePlatform + GenFdsGlobalVariable.ConfDir = GlobalData.gConfDirectory + GenFdsGlobalVariable.EnableGenfdsMultiThread = GlobalData.gEnableGenfdsMultiThread + for Arch in ArchList: + GenFdsGlobalVariable.OutputDirDict[Arch] = os.path.normpath( + os.path.join(GlobalData.gWorkspace, + WorkSpace.Db.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GlobalData.gGlobalDefines['TARGET'], + GlobalData.gGlobalDefines['TOOLCHAIN']].OutputDirectory, + GlobalData.gGlobalDefines['TARGET'] +'_' + GlobalData.gGlobalDefines['TOOLCHAIN'])) + GenFdsGlobalVariable.OutputDirFromDscDict[Arch] = os.path.normpath( + WorkSpace.Db.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, + GlobalData.gGlobalDefines['TARGET'], GlobalData.gGlobalDefines['TOOLCHAIN']].OutputDirectory) + GenFdsGlobalVariable.PlatformName = WorkSpace.Db.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, + GlobalData.gGlobalDefines['TARGET'], + GlobalData.gGlobalDefines['TOOLCHAIN']].PlatformName + GenFdsGlobalVariable.FvDir = os.path.join(GenFdsGlobalVariable.OutputDirDict[ArchList[0]], DataType.TAB_FV_DIRECTORY) + 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) + + # + # Create FV Address inf file + # + GenFdsGlobalVariable.FvAddressFileName = os.path.join(GenFdsGlobalVariable.FfsDir, 'FvAddress.inf') + FvAddressFile = open(GenFdsGlobalVariable.FvAddressFileName, 'w') + # + # Add [Options] + # + FvAddressFile.writelines("[options]" + DataType.TAB_LINE_BREAK) + BsAddress = '0' + for Arch in ArchList: + BsAddress = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, + GlobalData.gGlobalDefines['TARGET'], + GlobalData.gGlobalDefines["TOOL_CHAIN_TAG"]].BsBaseAddress + if BsAddress: + break + + FvAddressFile.writelines("EFI_BOOT_DRIVER_BASE_ADDRESS = " + \ + BsAddress + \ + DataType.TAB_LINE_BREAK) + + RtAddress = '0' + for Arch in reversed(ArchList): + temp = GenFdsGlobalVariable.WorkSpace.BuildObject[ + GenFdsGlobalVariable.ActivePlatform, Arch, GlobalData.gGlobalDefines['TARGET'], + GlobalData.gGlobalDefines["TOOL_CHAIN_TAG"]].RtBaseAddress + if temp: + RtAddress = temp + break + + FvAddressFile.writelines("EFI_RUNTIME_DRIVER_BASE_ADDRESS = " + \ + RtAddress + \ + DataType.TAB_LINE_BREAK) + + FvAddressFile.close() + + ## ReplaceWorkspaceMacro() + # + # @param String String that may contain macro + # + @staticmethod + def ReplaceWorkspaceMacro(String): + String = mws.handleWsMacro(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 = mws.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 not Input: + 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=[], BuildNumber=None, DummyFile=None, IsMakefile=False): + Cmd = ["GenSec"] + if Type: + Cmd += ("-s", Type) + if CompressionType: + Cmd += ("-c", CompressionType) + if Guid: + Cmd += ("-g", Guid) + if DummyFile: + Cmd += ("--dummy", DummyFile) + if GuidHdrLen: + Cmd += ("-l", GuidHdrLen) + #Add each guided attribute + for Attr in GuidAttr: + Cmd += ("-r", Attr) + #Section Align is only for dummy section without section type + for SecAlign in InputAlign: + Cmd += ("--sectionalign", SecAlign) + + CommandFile = Output + '.txt' + if Ui: + if IsMakefile: + if Ui == "$(MODULE_NAME)": + Cmd += ('-n', Ui) + else: + Cmd += ("-n", '"' + Ui + '"') + Cmd += ("-o", Output) + if ' '.join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList: + GenFdsGlobalVariable.SecCmdList.append(' '.join(Cmd).strip()) + else: + SectionData = 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: + Cmd += ("-n", Ver) + if BuildNumber: + Cmd += ("-j", BuildNumber) + Cmd += ("-o", Output) + + SaveFileOnChange(CommandFile, ' '.join(Cmd), False) + if IsMakefile: + if ' '.join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList: + GenFdsGlobalVariable.SecCmdList.append(' '.join(Cmd).strip()) + else: + if not GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]): + return + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section") + else: + Cmd += ("-o", Output) + Cmd += Input + + SaveFileOnChange(CommandFile, ' '.join(Cmd), False) + if IsMakefile: + if sys.platform == "win32": + Cmd = ['if', 'exist', Input[0]] + Cmd + else: + Cmd = ['-test', '-e', Input[0], "&&"] + Cmd + if ' '.join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList: + GenFdsGlobalVariable.SecCmdList.append(' '.join(Cmd).strip()) + elif GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]): + GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate section") + if (os.path.getsize(Output) >= GenFdsGlobalVariable.LARGE_FILE_SIZE and + GenFdsGlobalVariable.LargeFileInFvFlags): + GenFdsGlobalVariable.LargeFileInFvFlags[-1] = True + + @staticmethod + def GetAlignment (AlignString): + if not AlignString: + return 0 + if AlignString.endswith('K'): + return int (AlignString.rstrip('K')) * 1024 + if AlignString.endswith('M'): + return int (AlignString.rstrip('M')) * 1024 * 1024 + if AlignString.endswith('G'): + return int (AlignString.rstrip('G')) * 1024 * 1024 * 1024 + return int (AlignString) + + @staticmethod + def GenerateFfs(Output, Input, Type, Guid, Fixed=False, CheckSum=False, Align=None, + SectionAlign=None, MakefilePath=None): + Cmd = ["GenFfs", "-t", Type, "-g", Guid] + mFfsValidAlign = ["0", "8", "16", "128", "512", "1K", "4K", "32K", "64K", "128K", "256K", "512K", "1M", "2M", "4M", "8M", "16M"] + if Fixed == True: + Cmd.append("-x") + if CheckSum: + Cmd.append("-s") + if Align: + if Align not in mFfsValidAlign: + Align = GenFdsGlobalVariable.GetAlignment (Align) + for index in range(0, len(mFfsValidAlign) - 1): + if ((Align > GenFdsGlobalVariable.GetAlignment(mFfsValidAlign[index])) and (Align <= GenFdsGlobalVariable.GetAlignment(mFfsValidAlign[index + 1]))): + break + Align = mFfsValidAlign[index + 1] + Cmd += ("-a", Align) + + Cmd += ("-o", Output) + for I in range(0, len(Input)): + if MakefilePath: + Cmd += ("-oi", Input[I]) + else: + Cmd += ("-i", Input[I]) + if SectionAlign and SectionAlign[I]: + Cmd += ("-n", SectionAlign[I]) + + CommandFile = Output + '.txt' + SaveFileOnChange(CommandFile, ' '.join(Cmd), False) + + GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) + if MakefilePath: + if (tuple(Cmd), tuple(GenFdsGlobalVariable.SecCmdList), tuple(GenFdsGlobalVariable.CopyList)) not in GenFdsGlobalVariable.FfsCmdDict: + GenFdsGlobalVariable.FfsCmdDict[tuple(Cmd), tuple(GenFdsGlobalVariable.SecCmdList), tuple(GenFdsGlobalVariable.CopyList)] = MakefilePath + GenFdsGlobalVariable.SecCmdList = [] + GenFdsGlobalVariable.CopyList = [] + else: + if not GenFdsGlobalVariable.NeedsUpdate(Output, list(Input) + [CommandFile]): + return + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FFS") + + @staticmethod + def GenerateFirmwareVolume(Output, Input, BaseAddress=None, ForceRebase=None, Capsule=False, Dump=False, + AddressFile=None, MapFile=None, FfsList=[], FileSystemGuid=None): + 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: + Cmd += ("-r", BaseAddress) + + if ForceRebase == False: + Cmd += ("-F", "FALSE") + elif ForceRebase == True: + Cmd += ("-F", "TRUE") + + if Capsule: + Cmd.append("-c") + if Dump: + Cmd.append("-p") + if AddressFile: + Cmd += ("-a", AddressFile) + if MapFile: + Cmd += ("-m", MapFile) + if FileSystemGuid: + Cmd += ("-g", FileSystemGuid) + Cmd += ("-o", Output) + for I in Input: + Cmd += ("-i", I) + + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate FV") + + @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, IsMakefile=False): + if not GenFdsGlobalVariable.NeedsUpdate(Output, Input) and not IsMakefile: + return + GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, Input)) + + Cmd = ["GenFw"] + if Type.lower() == "te": + Cmd.append("-t") + if SubType: + Cmd += ("-e", SubType) + if TimeStamp: + Cmd += ("-s", TimeStamp) + if Align: + Cmd += ("-a", Align) + if Padding: + Cmd += ("-p", Padding) + if Zero: + Cmd.append("-z") + if Strip: + Cmd.append("-l") + if Replace: + Cmd.append("-r") + if Join: + Cmd.append("-j") + if Convert: + Cmd.append("-m") + Cmd += ("-o", Output) + Cmd += Input + if IsMakefile: + if " ".join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList: + GenFdsGlobalVariable.SecCmdList.append(" ".join(Cmd).strip()) + else: + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate firmware image") + + @staticmethod + def GenerateOptionRom(Output, EfiInput, BinaryInput, Compress=False, ClassCode=None, + Revision=None, DeviceId=None, VendorId=None, IsMakefile=False): + InputList = [] + Cmd = ["EfiRom"] + if EfiInput: + + if Compress: + Cmd.append("-ec") + else: + Cmd.append("-e") + + for EfiFile in EfiInput: + Cmd.append(EfiFile) + InputList.append (EfiFile) + + if BinaryInput: + Cmd.append("-b") + for BinFile in BinaryInput: + Cmd.append(BinFile) + InputList.append (BinFile) + + # Check List + if not GenFdsGlobalVariable.NeedsUpdate(Output, InputList) and not IsMakefile: + return + GenFdsGlobalVariable.DebugLogger(EdkLogger.DEBUG_5, "%s needs update because of newer %s" % (Output, InputList)) + + if ClassCode: + Cmd += ("-l", ClassCode) + if Revision: + Cmd += ("-r", Revision) + if DeviceId: + Cmd += ("-i", DeviceId) + if VendorId: + Cmd += ("-f", VendorId) + + Cmd += ("-o", Output) + if IsMakefile: + if " ".join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList: + GenFdsGlobalVariable.SecCmdList.append(" ".join(Cmd).strip()) + else: + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to generate option rom") + + @staticmethod + def GuidTool(Output, Input, ToolPath, Options='', returnValue=[], IsMakefile=False): + if not GenFdsGlobalVariable.NeedsUpdate(Output, Input) and not IsMakefile: + 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 + if IsMakefile: + if " ".join(Cmd).strip() not in GenFdsGlobalVariable.SecCmdList: + GenFdsGlobalVariable.SecCmdList.append(" ".join(Cmd).strip()) + else: + GenFdsGlobalVariable.CallExternalTool(Cmd, "Failed to call " + ToolPath, returnValue) + + @staticmethod + 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: + stdout.write ('#') + stdout.flush() + GenFdsGlobalVariable.SharpCounter = GenFdsGlobalVariable.SharpCounter + 1 + if GenFdsGlobalVariable.SharpCounter % GenFdsGlobalVariable.SharpNumberPerLine == 0: + stdout.write('\n') + + try: + PopenObject = Popen(' '.join(cmd), stdout=PIPE, stderr=PIPE, shell=True) + except Exception as X: + EdkLogger.error("GenFds", COMMAND_FAILURE, ExtraData="%s: %s" % (str(X), cmd[0])) + (out, error) = PopenObject.communicate() + + while PopenObject.returncode is 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.decode(encoding='utf-8', errors='ignore')) + GenFdsGlobalVariable.InfLogger(error.decode(encoding='utf-8', errors='ignore')) + if PopenObject.returncode != 0: + print("###", cmd) + EdkLogger.error("GenFds", COMMAND_FAILURE, errorMess) + + @staticmethod + def VerboseLogger (msg): + EdkLogger.verbose(msg) + + @staticmethod + def InfLogger (msg): + EdkLogger.info(msg) + + @staticmethod + def ErrorLogger (msg, File=None, Line=None, ExtraData=None): + EdkLogger.error('GenFds', GENFDS_ERROR, msg, File, Line, ExtraData) + + @staticmethod + def DebugLogger (Level, msg): + EdkLogger.debug(Level, msg) + + ## MacroExtend() + # + # @param Str String that may contain macro + # @param MacroDict Dictionary that contains macro value pair + # + @staticmethod + def MacroExtend (Str, MacroDict=None, Arch=DataType.TAB_COMMON): + if Str is None: + return None + + Dict = {'$(WORKSPACE)': GenFdsGlobalVariable.WorkSpaceDir, +# '$(OUTPUT_DIRECTORY)': GenFdsGlobalVariable.OutputDirFromDsc, + '$(TARGET)': GenFdsGlobalVariable.TargetName, + '$(TOOL_CHAIN_TAG)': GenFdsGlobalVariable.ToolChainTag, + '$(SPACE)': ' ' + } + + if Arch != DataType.TAB_COMMON and Arch in GenFdsGlobalVariable.ArchList: + OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[Arch] + else: + OutputDir = GenFdsGlobalVariable.OutputDirFromDscDict[GenFdsGlobalVariable.ArchList[0]] + + Dict['$(OUTPUT_DIRECTORY)'] = OutputDir + + if MacroDict: + Dict.update(MacroDict) + + for key in Dict: + 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. + # + @staticmethod + def GetPcdValue (PcdPattern): + if PcdPattern is None: + return None + if PcdPattern.startswith('PCD('): + PcdPair = PcdPattern[4:].rstrip(')').strip().split('.') + else: + PcdPair = PcdPattern.strip().split('.') + TokenSpace = PcdPair[0] + TokenCName = PcdPair[1] + + for Arch in GenFdsGlobalVariable.ArchList: + Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + PcdDict = Platform.Pcds + for Key in PcdDict: + PcdObj = PcdDict[Key] + if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace): + if PcdObj.Type != DataType.TAB_PCDS_FIXED_AT_BUILD: + EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern) + if PcdObj.DatumType != DataType.TAB_VOID: + EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern) + + return PcdObj.DefaultValue + + for Package in GenFdsGlobalVariable.WorkSpace.GetPackageList(GenFdsGlobalVariable.ActivePlatform, + Arch, + GenFdsGlobalVariable.TargetName, + GenFdsGlobalVariable.ToolChainTag): + PcdDict = Package.Pcds + for Key in PcdDict: + PcdObj = PcdDict[Key] + if (PcdObj.TokenCName == TokenCName) and (PcdObj.TokenSpaceGuidCName == TokenSpace): + if PcdObj.Type != DataType.TAB_PCDS_FIXED_AT_BUILD: + EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not FixedAtBuild type." % PcdPattern) + if PcdObj.DatumType != DataType.TAB_VOID: + EdkLogger.error("GenFds", GENFDS_ERROR, "%s is not VOID* datum type." % PcdPattern) + + return PcdObj.DefaultValue + + return '' + +## FindExtendTool() +# +# Find location of tools to process data +# +# @param KeyStringList Filter for inputs of section generation +# @param CurrentArchList Arch list +# @param NameGuid The Guid name +# +def FindExtendTool(KeyStringList, CurrentArchList, NameGuid): + ToolDefObj = ToolDefDict((os.path.join(os.getenv("WORKSPACE"), "Conf"))) + ToolDef = ToolDefObj.ToolDef + ToolDb = ToolDef.ToolsDefTxtDatabase + # if user not specify filter, try to deduce it from global data. + if KeyStringList is None or KeyStringList == []: + Target = GenFdsGlobalVariable.TargetName + ToolChain = GenFdsGlobalVariable.ToolChainTag + if ToolChain not in ToolDb['TOOL_CHAIN_TAG']: + EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain) + KeyStringList = [Target + '_' + ToolChain + '_' + CurrentArchList[0]] + for Arch in CurrentArchList: + if Target + '_' + ToolChain + '_' + Arch not in KeyStringList: + KeyStringList.append(Target + '_' + ToolChain + '_' + Arch) + + if GenFdsGlobalVariable.GuidToolDefinition: + if NameGuid in GenFdsGlobalVariable.GuidToolDefinition: + return GenFdsGlobalVariable.GuidToolDefinition[NameGuid] + + ToolDefinition = ToolDef.ToolsDefTxtDictionary + ToolPathTmp = None + ToolOption = None + ToolPathKey = None + ToolOptionKey = None + KeyList = None + for tool_def in ToolDefinition.items(): + if NameGuid.lower() == tool_def[1].lower(): + KeyList = tool_def[0].split('_') + Key = KeyList[0] + \ + '_' + \ + KeyList[1] + \ + '_' + \ + KeyList[2] + if Key in KeyStringList and KeyList[4] == DataType.TAB_GUID: + ToolPathKey = Key + '_' + KeyList[3] + '_PATH' + ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS' + ToolPath = ToolDefinition.get(ToolPathKey) + ToolOption = ToolDefinition.get(ToolOptionKey) + if ToolPathTmp is None: + ToolPathTmp = ToolPath + else: + if ToolPathTmp != ToolPath: + EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath)) + + BuildOption = {} + for Arch in CurrentArchList: + Platform = GenFdsGlobalVariable.WorkSpace.BuildObject[GenFdsGlobalVariable.ActivePlatform, Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag] + # key is (ToolChainFamily, ToolChain, CodeBase) + for item in Platform.BuildOptions: + if '_PATH' in item[1] or '_FLAGS' in item[1] or '_GUID' in item[1]: + if not item[0] or (item[0] and GenFdsGlobalVariable.ToolChainFamily== item[0]): + if item[1] not in BuildOption: + BuildOption[item[1]] = Platform.BuildOptions[item] + if BuildOption: + ToolList = [DataType.TAB_TOD_DEFINES_TARGET, DataType.TAB_TOD_DEFINES_TOOL_CHAIN_TAG, DataType.TAB_TOD_DEFINES_TARGET_ARCH] + for Index in range(2, -1, -1): + for Key in list(BuildOption.keys()): + List = Key.split('_') + if List[Index] == DataType.TAB_STAR: + for String in ToolDb[ToolList[Index]]: + if String in [Arch, GenFdsGlobalVariable.TargetName, GenFdsGlobalVariable.ToolChainTag]: + List[Index] = String + NewKey = '%s_%s_%s_%s_%s' % tuple(List) + if NewKey not in BuildOption: + BuildOption[NewKey] = BuildOption[Key] + continue + del BuildOption[Key] + elif List[Index] not in ToolDb[ToolList[Index]]: + del BuildOption[Key] + if BuildOption: + if not KeyList: + for Op in BuildOption: + if NameGuid == BuildOption[Op]: + KeyList = Op.split('_') + Key = KeyList[0] + '_' + KeyList[1] +'_' + KeyList[2] + if Key in KeyStringList and KeyList[4] == DataType.TAB_GUID: + ToolPathKey = Key + '_' + KeyList[3] + '_PATH' + ToolOptionKey = Key + '_' + KeyList[3] + '_FLAGS' + if ToolPathKey in BuildOption: + ToolPathTmp = BuildOption[ToolPathKey] + if ToolOptionKey in BuildOption: + ToolOption = BuildOption[ToolOptionKey] + + GenFdsGlobalVariable.GuidToolDefinition[NameGuid] = (ToolPathTmp, ToolOption) + return ToolPathTmp, ToolOption diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/GuidSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/GuidSection.py new file mode 100644 index 000000000..8db6e2feb --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/GuidSection.py @@ -0,0 +1,278 @@ +## @file +# process GUIDed section generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Section +import subprocess +from .Ffs import SectionSuffix +import Common.LongFilePathOs as os +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from .GenFdsGlobalVariable import FindExtendTool +from CommonDataClass.FdfClass import GuidSectionClassObject +import sys +from Common import EdkLogger +from Common.BuildToolError import * +from .FvImageSection import FvImageSection +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.DataType import * + +## generate GUIDed section +# +# +class GuidSection(GuidSectionClassObject) : + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + GuidSectionClassObject.__init__(self) + + ## GenSection() method + # + # Generate GUIDed section + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # @retval tuple (Generated file name, section alignment) + # + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf=None, Dict=None, IsMakefile=False): + # + # Generate all section + # + self.KeyStringList = KeyStringList + self.CurrentArchList = GenFdsGlobalVariable.ArchList + if FfsInf is not None: + self.Alignment = FfsInf.__ExtendMacro__(self.Alignment) + self.NameGuid = FfsInf.__ExtendMacro__(self.NameGuid) + self.SectionType = FfsInf.__ExtendMacro__(self.SectionType) + self.CurrentArchList = [FfsInf.CurrentArch] + + SectFile = tuple() + SectAlign = [] + Index = 0 + MaxAlign = None + if Dict is None: + Dict = {} + if self.FvAddr != []: + FvAddrIsSet = True + else: + FvAddrIsSet = False + + if self.ProcessRequired in ("TRUE", "1"): + if self.FvAddr != []: + #no use FvAddr when the image is processed. + self.FvAddr = [] + if self.FvParentAddr is not None: + #no use Parent Addr when the image is processed. + self.FvParentAddr = None + + for Sect in self.SectionList: + Index = Index + 1 + SecIndex = '%s.%d' % (SecNum, Index) + # set base address for inside FvImage + if isinstance(Sect, FvImageSection): + if self.FvAddr != []: + Sect.FvAddr = self.FvAddr.pop(0) + self.IncludeFvSection = True + elif isinstance(Sect, GuidSection): + Sect.FvAddr = self.FvAddr + Sect.FvParentAddr = self.FvParentAddr + ReturnSectList, align = Sect.GenSection(OutputPath, ModuleName, SecIndex, KeyStringList, FfsInf, Dict, IsMakefile=IsMakefile) + if isinstance(Sect, GuidSection): + if Sect.IncludeFvSection: + self.IncludeFvSection = Sect.IncludeFvSection + + if align is not None: + if MaxAlign is None: + MaxAlign = align + if GenFdsGlobalVariable.GetAlignment (align) > GenFdsGlobalVariable.GetAlignment (MaxAlign): + MaxAlign = align + if ReturnSectList != []: + if align is None: + align = "1" + for file in ReturnSectList: + SectFile += (file,) + SectAlign.append(align) + + if MaxAlign is not None: + if self.Alignment is None: + self.Alignment = MaxAlign + else: + if GenFdsGlobalVariable.GetAlignment (MaxAlign) > GenFdsGlobalVariable.GetAlignment (self.Alignment): + self.Alignment = MaxAlign + + OutputFile = OutputPath + \ + os.sep + \ + ModuleName + \ + SUP_MODULE_SEC + \ + SecNum + \ + SectionSuffix['GUIDED'] + OutputFile = os.path.normpath(OutputFile) + + ExternalTool = None + ExternalOption = None + if self.NameGuid is not None: + ExternalTool, ExternalOption = FindExtendTool(self.KeyStringList, self.CurrentArchList, self.NameGuid) + + # + # If not have GUID , call default + # GENCRC32 section + # + if self.NameGuid is None : + GenFdsGlobalVariable.VerboseLogger("Use GenSection function Generate CRC32 Section") + GenFdsGlobalVariable.GenerateSection(OutputFile, SectFile, Section.Section.SectionType[self.SectionType], InputAlign=SectAlign, IsMakefile=IsMakefile) + OutputFileList = [] + OutputFileList.append(OutputFile) + return OutputFileList, self.Alignment + #or GUID not in External Tool List + elif ExternalTool is None: + EdkLogger.error("GenFds", GENFDS_ERROR, "No tool found with GUID %s" % self.NameGuid) + else: + DummyFile = OutputFile + ".dummy" + # + # Call GenSection with DUMMY section type. + # + GenFdsGlobalVariable.GenerateSection(DummyFile, SectFile, InputAlign=SectAlign, IsMakefile=IsMakefile) + # + # Use external tool process the Output + # + TempFile = OutputPath + \ + os.sep + \ + ModuleName + \ + SUP_MODULE_SEC + \ + SecNum + \ + '.tmp' + TempFile = os.path.normpath(TempFile) + # + # Remove temp file if its time stamp is older than dummy file + # Just in case the external tool fails at this time but succeeded before + # Error should be reported if the external tool does not generate a new output based on new input + # + if os.path.exists(TempFile) and os.path.exists(DummyFile) and os.path.getmtime(TempFile) < os.path.getmtime(DummyFile): + os.remove(TempFile) + + FirstCall = False + CmdOption = '-e' + if ExternalOption is not None: + CmdOption = CmdOption + ' ' + ExternalOption + if not GenFdsGlobalVariable.EnableGenfdsMultiThread: + if self.ProcessRequired not in ("TRUE", "1") and self.IncludeFvSection and not FvAddrIsSet and self.FvParentAddr is not None: + #FirstCall is only set for the encapsulated flash FV image without process required attribute. + FirstCall = True + # + # Call external tool + # + ReturnValue = [1] + if FirstCall: + #first try to call the guided tool with -z option and CmdOption for the no process required guided tool. + GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, '-z' + ' ' + CmdOption, ReturnValue) + + # + # when no call or first call failed, ReturnValue are not 1. + # Call the guided tool with CmdOption + # + if ReturnValue[0] != 0: + FirstCall = False + ReturnValue[0] = 0 + GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, CmdOption) + # + # There is external tool which does not follow standard rule which return nonzero if tool fails + # The output file has to be checked + # + + if not os.path.exists(TempFile) : + EdkLogger.error("GenFds", COMMAND_FAILURE, 'Fail to call %s, no output file was generated' % ExternalTool) + + FileHandleIn = open(DummyFile, 'rb') + FileHandleIn.seek(0, 2) + InputFileSize = FileHandleIn.tell() + + FileHandleOut = open(TempFile, 'rb') + FileHandleOut.seek(0, 2) + TempFileSize = FileHandleOut.tell() + + Attribute = [] + HeaderLength = None + if self.ExtraHeaderSize != -1: + HeaderLength = str(self.ExtraHeaderSize) + + if self.ProcessRequired == "NONE" and HeaderLength is None: + if TempFileSize > InputFileSize: + FileHandleIn.seek(0) + BufferIn = FileHandleIn.read() + FileHandleOut.seek(0) + BufferOut = FileHandleOut.read() + if BufferIn == BufferOut[TempFileSize - InputFileSize:]: + HeaderLength = str(TempFileSize - InputFileSize) + #auto sec guided attribute with process required + if HeaderLength is None: + Attribute.append('PROCESSING_REQUIRED') + + FileHandleIn.close() + FileHandleOut.close() + + if FirstCall and 'PROCESSING_REQUIRED' in Attribute: + # Guided data by -z option on first call is the process required data. Call the guided tool with the real option. + GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, CmdOption) + + # + # Call Gensection Add Section Header + # + if self.ProcessRequired in ("TRUE", "1"): + if 'PROCESSING_REQUIRED' not in Attribute: + Attribute.append('PROCESSING_REQUIRED') + + if self.AuthStatusValid in ("TRUE", "1"): + Attribute.append('AUTH_STATUS_VALID') + GenFdsGlobalVariable.GenerateSection(OutputFile, [TempFile], Section.Section.SectionType['GUIDED'], + Guid=self.NameGuid, GuidAttr=Attribute, GuidHdrLen=HeaderLength) + + else: + #add input file for GenSec get PROCESSING_REQUIRED + GenFdsGlobalVariable.GuidTool(TempFile, [DummyFile], ExternalTool, CmdOption, IsMakefile=IsMakefile) + Attribute = [] + HeaderLength = None + if self.ExtraHeaderSize != -1: + HeaderLength = str(self.ExtraHeaderSize) + if self.AuthStatusValid in ("TRUE", "1"): + Attribute.append('AUTH_STATUS_VALID') + if self.ProcessRequired == "NONE" and HeaderLength is None: + GenFdsGlobalVariable.GenerateSection(OutputFile, [TempFile], Section.Section.SectionType['GUIDED'], + Guid=self.NameGuid, GuidAttr=Attribute, + GuidHdrLen=HeaderLength, DummyFile=DummyFile, IsMakefile=IsMakefile) + else: + if self.ProcessRequired in ("TRUE", "1"): + if 'PROCESSING_REQUIRED' not in Attribute: + Attribute.append('PROCESSING_REQUIRED') + GenFdsGlobalVariable.GenerateSection(OutputFile, [TempFile], Section.Section.SectionType['GUIDED'], + Guid=self.NameGuid, GuidAttr=Attribute, + GuidHdrLen=HeaderLength, IsMakefile=IsMakefile) + + OutputFileList = [] + OutputFileList.append(OutputFile) + if 'PROCESSING_REQUIRED' in Attribute: + # reset guided section alignment to none for the processed required guided data + self.Alignment = None + self.IncludeFvSection = False + self.ProcessRequired = "TRUE" + if IsMakefile and self.Alignment is not None and self.Alignment.strip() == '0': + self.Alignment = '1' + return OutputFileList, self.Alignment + + + diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/OptRomFileStatement.py b/roms/edk2/BaseTools/Source/Python/GenFds/OptRomFileStatement.py new file mode 100644 index 000000000..1bd4d4572 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/OptRomFileStatement.py @@ -0,0 +1,48 @@ +## @file +# process OptionROM generation from FILE statement +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +import Common.LongFilePathOs as os + +from .GenFdsGlobalVariable import GenFdsGlobalVariable +## +# +# +class OptRomFileStatement: + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + self.FileName = None + self.FileType = None + self.OverrideAttribs = None + + ## GenFfs() method + # + # Generate FFS + # + # @param self The object pointer + # @param Dict dictionary contains macro and value pair + # @retval string Generated FFS file name + # + def GenFfs(self, Dict = None, IsMakefile=False): + + if Dict is None: + Dict = {} + + if self.FileName is not None: + self.FileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FileName) + + return self.FileName + + + diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/OptRomInfStatement.py b/roms/edk2/BaseTools/Source/Python/GenFds/OptRomInfStatement.py new file mode 100644 index 000000000..8b570ed6b --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/OptRomInfStatement.py @@ -0,0 +1,159 @@ +## @file +# process OptionROM generation from INF statement +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import RuleSimpleFile +from . import RuleComplexFile +from . import Section +import Common.GlobalData as GlobalData + +from Common.DataType import * +from Common.StringUtils import * +from .FfsInfStatement import FfsInfStatement +from .GenFdsGlobalVariable import GenFdsGlobalVariable + +## +# +# +class OptRomInfStatement (FfsInfStatement): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + FfsInfStatement.__init__(self) + self.OverrideAttribs = None + + ## __GetOptRomParams() method + # + # Parse inf file to get option ROM related parameters + # + # @param self The object pointer + # + def __GetOptRomParams(self): + if self.OverrideAttribs is None: + self.OverrideAttribs = OverrideAttribs() + + if self.OverrideAttribs.NeedCompress is None: + self.OverrideAttribs.NeedCompress = self.OptRomDefs.get ('PCI_COMPRESS') + if self.OverrideAttribs.NeedCompress is not None: + if self.OverrideAttribs.NeedCompress.upper() not in ('TRUE', 'FALSE'): + GenFdsGlobalVariable.ErrorLogger( "Expected TRUE/FALSE for PCI_COMPRESS: %s" %self.InfFileName) + self.OverrideAttribs.NeedCompress = \ + self.OverrideAttribs.NeedCompress.upper() == 'TRUE' + + if self.OverrideAttribs.PciVendorId is None: + self.OverrideAttribs.PciVendorId = self.OptRomDefs.get ('PCI_VENDOR_ID') + + if self.OverrideAttribs.PciClassCode is None: + self.OverrideAttribs.PciClassCode = self.OptRomDefs.get ('PCI_CLASS_CODE') + + if self.OverrideAttribs.PciDeviceId is None: + self.OverrideAttribs.PciDeviceId = self.OptRomDefs.get ('PCI_DEVICE_ID') + + if self.OverrideAttribs.PciRevision is None: + self.OverrideAttribs.PciRevision = self.OptRomDefs.get ('PCI_REVISION') + +# InfObj = GenFdsGlobalVariable.WorkSpace.BuildObject[self.PathClassObj, self.CurrentArch] +# RecordList = InfObj._RawData[MODEL_META_DATA_HEADER, InfObj._Arch, InfObj._Platform] +# for Record in RecordList: +# Record = ReplaceMacros(Record, GlobalData.gEdkGlobal, False) +# Name = Record[0] + ## GenFfs() method + # + # Generate FFS + # + # @param self The object pointer + # @retval string Generated .efi file name + # + def GenFfs(self, IsMakefile=False): + # + # Parse Inf file get Module related information + # + + self.__InfParse__() + self.__GetOptRomParams() + # + # Get the rule of how to generate Ffs file + # + Rule = self.__GetRule__() + GenFdsGlobalVariable.VerboseLogger( "Packing binaries from inf file : %s" %self.InfFileName) + # + # For the rule only has simpleFile + # + if isinstance (Rule, RuleSimpleFile.RuleSimpleFile) : + EfiOutputList = self.__GenSimpleFileSection__(Rule, IsMakefile=IsMakefile) + return EfiOutputList + # + # For Rule has ComplexFile + # + elif isinstance(Rule, RuleComplexFile.RuleComplexFile): + EfiOutputList = self.__GenComplexFileSection__(Rule, IsMakefile=IsMakefile) + return EfiOutputList + + ## __GenSimpleFileSection__() method + # + # Get .efi files according to simple rule. + # + # @param self The object pointer + # @param Rule The rule object used to generate section + # @retval string File name of the generated section file + # + def __GenSimpleFileSection__(self, Rule, IsMakefile = False): + # + # Prepare the parameter of GenSection + # + + OutputFileList = [] + if Rule.FileName is not None: + GenSecInputFile = self.__ExtendMacro__(Rule.FileName) + OutputFileList.append(GenSecInputFile) + else: + OutputFileList, IsSect = Section.Section.GetFileList(self, '', Rule.FileExtension) + + return OutputFileList + + + ## __GenComplexFileSection__() method + # + # Get .efi by sections in complex Rule + # + # @param self The object pointer + # @param Rule The rule object used to generate section + # @retval string File name of the generated section file + # + def __GenComplexFileSection__(self, Rule, IsMakefile=False): + + OutputFileList = [] + for Sect in Rule.SectionList: + if Sect.SectionType == BINARY_FILE_TYPE_PE32: + if Sect.FileName is not None: + GenSecInputFile = self.__ExtendMacro__(Sect.FileName) + OutputFileList.append(GenSecInputFile) + else: + FileList, IsSect = Section.Section.GetFileList(self, '', Sect.FileExtension) + OutputFileList.extend(FileList) + + return OutputFileList + +class OverrideAttribs: + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + + self.PciVendorId = None + self.PciClassCode = None + self.PciDeviceId = None + self.PciRevision = None + self.NeedCompress = None diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/OptionRom.py b/roms/edk2/BaseTools/Source/Python/GenFds/OptionRom.py new file mode 100644 index 000000000..61d669de8 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/OptionRom.py @@ -0,0 +1,131 @@ +## @file +# process OptionROM generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +import Common.LongFilePathOs as os +import subprocess + +from . import OptRomInfStatement +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from CommonDataClass.FdfClass import OptionRomClassObject +from Common.Misc import SaveFileOnChange +from Common import EdkLogger +from Common.BuildToolError import * + +## +# +# +class OPTIONROM (OptionRomClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self, Name = ""): + OptionRomClassObject.__init__(self) + self.DriverName = Name + + ## AddToBuffer() + # + # Generate Option ROM + # + # @param self The object pointer + # @param Buffer The buffer generated OptROM data will be put + # @retval string Generated OptROM file path + # + def AddToBuffer (self, Buffer, Flag=False) : + if not Flag: + GenFdsGlobalVariable.InfLogger( "\nGenerating %s Option ROM ..." %self.DriverName) + + EfiFileList = [] + BinFileList = [] + + # Process Modules in FfsList + for FfsFile in self.FfsList : + + if isinstance(FfsFile, OptRomInfStatement.OptRomInfStatement): + FilePathNameList = FfsFile.GenFfs(IsMakefile=Flag) + if len(FilePathNameList) == 0: + EdkLogger.error("GenFds", GENFDS_ERROR, "Module %s not produce .efi files, so NO file could be put into option ROM." % (FfsFile.InfFileName)) + if FfsFile.OverrideAttribs is None: + EfiFileList.extend(FilePathNameList) + else: + FileName = os.path.basename(FilePathNameList[0]) + TmpOutputDir = os.path.join(GenFdsGlobalVariable.FvDir, self.DriverName, FfsFile.CurrentArch) + if not os.path.exists(TmpOutputDir) : + os.makedirs(TmpOutputDir) + TmpOutputFile = os.path.join(TmpOutputDir, FileName+'.tmp') + + GenFdsGlobalVariable.GenerateOptionRom(TmpOutputFile, + FilePathNameList, + [], + FfsFile.OverrideAttribs.NeedCompress, + FfsFile.OverrideAttribs.PciClassCode, + FfsFile.OverrideAttribs.PciRevision, + FfsFile.OverrideAttribs.PciDeviceId, + FfsFile.OverrideAttribs.PciVendorId, + IsMakefile = Flag) + BinFileList.append(TmpOutputFile) + else: + FilePathName = FfsFile.GenFfs(IsMakefile=Flag) + if FfsFile.OverrideAttribs is not None: + FileName = os.path.basename(FilePathName) + TmpOutputDir = os.path.join(GenFdsGlobalVariable.FvDir, self.DriverName, FfsFile.CurrentArch) + if not os.path.exists(TmpOutputDir) : + os.makedirs(TmpOutputDir) + TmpOutputFile = os.path.join(TmpOutputDir, FileName+'.tmp') + + GenFdsGlobalVariable.GenerateOptionRom(TmpOutputFile, + [FilePathName], + [], + FfsFile.OverrideAttribs.NeedCompress, + FfsFile.OverrideAttribs.PciClassCode, + FfsFile.OverrideAttribs.PciRevision, + FfsFile.OverrideAttribs.PciDeviceId, + FfsFile.OverrideAttribs.PciVendorId, + IsMakefile=Flag) + BinFileList.append(TmpOutputFile) + else: + if FfsFile.FileType == 'EFI': + EfiFileList.append(FilePathName) + else: + BinFileList.append(FilePathName) + + # + # Call EfiRom tool + # + OutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.DriverName) + OutputFile = OutputFile + '.rom' + + GenFdsGlobalVariable.GenerateOptionRom( + OutputFile, + EfiFileList, + BinFileList, + IsMakefile=Flag) + + if not Flag: + GenFdsGlobalVariable.InfLogger( "\nGenerate %s Option ROM Successfully" %self.DriverName) + GenFdsGlobalVariable.SharpCounter = 0 + + return OutputFile + +class OverrideAttribs: + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + + self.PciVendorId = None + self.PciClassCode = None + self.PciDeviceId = None + self.PciRevision = None + self.NeedCompress = None diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/Region.py b/roms/edk2/BaseTools/Source/Python/GenFds/Region.py new file mode 100644 index 000000000..e95cfcf96 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/Region.py @@ -0,0 +1,348 @@ +## @file +# process FD Region generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from struct import * +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from io import BytesIO +import string +import Common.LongFilePathOs as os +from stat import * +from Common import EdkLogger +from Common.BuildToolError import * +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws +from Common.DataType import BINARY_FILE_TYPE_FV + +## generate Region +# +# +class Region(object): + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + self.Offset = None # The begin position of the Region + self.Size = None # The Size of the Region + self.PcdOffset = None + self.PcdSize = None + self.SetVarDict = {} + self.RegionType = None + self.RegionDataList = [] + + ## PadBuffer() + # + # Add padding bytes to the Buffer + # + # @param Buffer The buffer the generated region data will be put + # in + # @param ErasePolarity Flash erase polarity + # @param Size Number of padding bytes requested + # + + def PadBuffer(self, Buffer, ErasePolarity, Size): + if Size > 0: + if (ErasePolarity == '1') : + PadByte = pack('B', 0xFF) + else: + PadByte = pack('B', 0) + for i in range(0, Size): + Buffer.write(PadByte) + + ## AddToBuffer() + # + # Add region data to the Buffer + # + # @param self The object pointer + # @param Buffer The buffer generated region data will be put + # @param BaseAddress base address of region + # @param BlockSize block size of region + # @param BlockNum How many blocks in region + # @param ErasePolarity Flash erase polarity + # @param MacroDict macro value pair + # @retval string Generated FV file path + # + + def AddToBuffer(self, Buffer, BaseAddress, BlockSizeList, ErasePolarity, ImageBinDict, MacroDict=None, Flag=False): + Size = self.Size + if MacroDict is None: + MacroDict = {} + if not Flag: + GenFdsGlobalVariable.InfLogger('\nGenerate Region at Offset 0x%X' % self.Offset) + GenFdsGlobalVariable.InfLogger(" Region Size = 0x%X" % Size) + GenFdsGlobalVariable.SharpCounter = 0 + if Flag and (self.RegionType != BINARY_FILE_TYPE_FV): + return + + if self.RegionType == BINARY_FILE_TYPE_FV: + # + # Get Fv from FvDict + # + self.FvAddress = int(BaseAddress, 16) + self.Offset + FvBaseAddress = '0x%X' % self.FvAddress + FvOffset = 0 + for RegionData in self.RegionDataList: + FileName = None + if RegionData.endswith(".fv"): + RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) + if not Flag: + GenFdsGlobalVariable.InfLogger(' Region FV File Name = .fv : %s' % RegionData) + if RegionData[1] != ':' : + RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) + if not os.path.exists(RegionData): + EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) + + FileName = RegionData + elif RegionData.upper() + 'fv' in ImageBinDict: + if not Flag: + GenFdsGlobalVariable.InfLogger(' Region Name = FV') + FileName = ImageBinDict[RegionData.upper() + 'fv'] + else: + # + # Generate FvImage. + # + FvObj = None + if RegionData.upper() in GenFdsGlobalVariable.FdfParser.Profile.FvDict: + FvObj = GenFdsGlobalVariable.FdfParser.Profile.FvDict[RegionData.upper()] + + if FvObj is not None : + if not Flag: + GenFdsGlobalVariable.InfLogger(' Region Name = FV') + # + # Call GenFv tool + # + self.BlockInfoOfRegion(BlockSizeList, FvObj) + self.FvAddress = self.FvAddress + FvOffset + FvAlignValue = GenFdsGlobalVariable.GetAlignment(FvObj.FvAlignment) + if self.FvAddress % FvAlignValue != 0: + EdkLogger.error("GenFds", GENFDS_ERROR, + "FV (%s) is NOT %s Aligned!" % (FvObj.UiFvName, FvObj.FvAlignment)) + FvBuffer = BytesIO() + FvBaseAddress = '0x%X' % self.FvAddress + BlockSize = None + BlockNum = None + FvObj.AddToBuffer(FvBuffer, FvBaseAddress, BlockSize, BlockNum, ErasePolarity, Flag=Flag) + if Flag: + continue + + FvBufferLen = len(FvBuffer.getvalue()) + if FvBufferLen > Size: + FvBuffer.close() + EdkLogger.error("GenFds", GENFDS_ERROR, + "Size of FV (%s) is larger than Region Size 0x%X specified." % (RegionData, Size)) + # + # Put the generated image into FD buffer. + # + Buffer.write(FvBuffer.getvalue()) + FvBuffer.close() + FvOffset = FvOffset + FvBufferLen + Size = Size - FvBufferLen + continue + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "FV (%s) is NOT described in FDF file!" % (RegionData)) + # + # Add the exist Fv image into FD buffer + # + if not Flag: + if FileName is not None: + FileLength = os.stat(FileName)[ST_SIZE] + if FileLength > Size: + EdkLogger.error("GenFds", GENFDS_ERROR, + "Size of FV File (%s) is larger than Region Size 0x%X specified." \ + % (RegionData, Size)) + BinFile = open(FileName, 'rb') + Buffer.write(BinFile.read()) + BinFile.close() + Size = Size - FileLength + # + # Pad the left buffer + # + if not Flag: + self.PadBuffer(Buffer, ErasePolarity, Size) + + if self.RegionType == 'CAPSULE': + # + # Get Capsule from Capsule Dict + # + for RegionData in self.RegionDataList: + if RegionData.endswith(".cap"): + RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) + GenFdsGlobalVariable.InfLogger(' Region CAPSULE Image Name = .cap : %s' % RegionData) + if RegionData[1] != ':' : + RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) + if not os.path.exists(RegionData): + EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) + + FileName = RegionData + elif RegionData.upper() + 'cap' in ImageBinDict: + GenFdsGlobalVariable.InfLogger(' Region Name = CAPSULE') + FileName = ImageBinDict[RegionData.upper() + 'cap'] + else: + # + # Generate Capsule image and Put it into FD buffer + # + CapsuleObj = None + if RegionData.upper() in GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict: + CapsuleObj = GenFdsGlobalVariable.FdfParser.Profile.CapsuleDict[RegionData.upper()] + + if CapsuleObj is not None : + CapsuleObj.CapsuleName = RegionData.upper() + GenFdsGlobalVariable.InfLogger(' Region Name = CAPSULE') + # + # Call GenFv tool to generate Capsule Image + # + FileName = CapsuleObj.GenCapsule() + CapsuleObj.CapsuleName = None + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "Capsule (%s) is NOT described in FDF file!" % (RegionData)) + + # + # Add the capsule image into FD buffer + # + FileLength = os.stat(FileName)[ST_SIZE] + if FileLength > Size: + EdkLogger.error("GenFds", GENFDS_ERROR, + "Size 0x%X of Capsule File (%s) is larger than Region Size 0x%X specified." \ + % (FileLength, RegionData, Size)) + BinFile = open(FileName, 'rb') + Buffer.write(BinFile.read()) + BinFile.close() + Size = Size - FileLength + # + # Pad the left buffer + # + self.PadBuffer(Buffer, ErasePolarity, Size) + + if self.RegionType in ('FILE', 'INF'): + for RegionData in self.RegionDataList: + if self.RegionType == 'INF': + RegionData.__InfParse__(None) + if len(RegionData.BinFileList) != 1: + EdkLogger.error('GenFds', GENFDS_ERROR, 'INF in FD region can only contain one binary: %s' % RegionData) + File = RegionData.BinFileList[0] + RegionData = RegionData.PatchEfiFile(File.Path, File.Type) + else: + RegionData = GenFdsGlobalVariable.MacroExtend(RegionData, MacroDict) + if RegionData[1] != ':' : + RegionData = mws.join (GenFdsGlobalVariable.WorkSpaceDir, RegionData) + if not os.path.exists(RegionData): + EdkLogger.error("GenFds", FILE_NOT_FOUND, ExtraData=RegionData) + # + # Add the file image into FD buffer + # + FileLength = os.stat(RegionData)[ST_SIZE] + if FileLength > Size: + EdkLogger.error("GenFds", GENFDS_ERROR, + "Size of File (%s) is larger than Region Size 0x%X specified." \ + % (RegionData, Size)) + GenFdsGlobalVariable.InfLogger(' Region File Name = %s' % RegionData) + BinFile = open(RegionData, 'rb') + Buffer.write(BinFile.read()) + BinFile.close() + Size = Size - FileLength + # + # Pad the left buffer + # + self.PadBuffer(Buffer, ErasePolarity, Size) + + if self.RegionType == 'DATA' : + GenFdsGlobalVariable.InfLogger(' Region Name = DATA') + DataSize = 0 + for RegionData in self.RegionDataList: + Data = RegionData.split(',') + DataSize = DataSize + len(Data) + if DataSize > Size: + EdkLogger.error("GenFds", GENFDS_ERROR, "Size of DATA is larger than Region Size ") + else: + for item in Data : + Buffer.write(pack('B', int(item, 16))) + Size = Size - DataSize + # + # Pad the left buffer + # + self.PadBuffer(Buffer, ErasePolarity, Size) + + if self.RegionType is None: + GenFdsGlobalVariable.InfLogger(' Region Name = None') + self.PadBuffer(Buffer, ErasePolarity, Size) + + ## BlockSizeOfRegion() + # + # @param BlockSizeList List of block information + # @param FvObj The object for FV + # + def BlockInfoOfRegion(self, BlockSizeList, FvObj): + Start = 0 + End = 0 + RemindingSize = self.Size + ExpectedList = [] + for (BlockSize, BlockNum, pcd) in BlockSizeList: + End = Start + BlockSize * BlockNum + # region not started yet + if self.Offset >= End: + Start = End + continue + # region located in current blocks + else: + # region ended within current blocks + if self.Offset + self.Size <= End: + ExpectedList.append((BlockSize, (RemindingSize + BlockSize - 1) // BlockSize)) + break + # region not ended yet + else: + # region not started in middle of current blocks + if self.Offset <= Start: + UsedBlockNum = BlockNum + # region started in middle of current blocks + else: + UsedBlockNum = (End - self.Offset) // BlockSize + Start = End + ExpectedList.append((BlockSize, UsedBlockNum)) + RemindingSize -= BlockSize * UsedBlockNum + + if FvObj.BlockSizeList == []: + FvObj.BlockSizeList = ExpectedList + else: + # first check whether FvObj.BlockSizeList items have only "BlockSize" or "NumBlocks", + # if so, use ExpectedList + for Item in FvObj.BlockSizeList: + if Item[0] is None or Item[1] is None: + FvObj.BlockSizeList = ExpectedList + break + # make sure region size is no smaller than the summed block size in FV + Sum = 0 + for Item in FvObj.BlockSizeList: + Sum += Item[0] * Item[1] + if self.Size < Sum: + EdkLogger.error("GenFds", GENFDS_ERROR, "Total Size of FV %s 0x%x is larger than Region Size 0x%x " + % (FvObj.UiFvName, Sum, self.Size)) + # check whether the BlockStatements in FV section is appropriate + ExpectedListData = '' + for Item in ExpectedList: + ExpectedListData += "BlockSize = 0x%x\n\tNumBlocks = 0x%x\n\t" % Item + Index = 0 + for Item in FvObj.BlockSizeList: + if Item[0] != ExpectedList[Index][0]: + EdkLogger.error("GenFds", GENFDS_ERROR, "BlockStatements of FV %s are not align with FD's, suggested FV BlockStatement" + % FvObj.UiFvName, ExtraData=ExpectedListData) + elif Item[1] != ExpectedList[Index][1]: + if (Item[1] < ExpectedList[Index][1]) and (Index == len(FvObj.BlockSizeList) - 1): + break; + else: + EdkLogger.error("GenFds", GENFDS_ERROR, "BlockStatements of FV %s are not align with FD's, suggested FV BlockStatement" + % FvObj.UiFvName, ExtraData=ExpectedListData) + else: + Index += 1 + + + diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/Rule.py b/roms/edk2/BaseTools/Source/Python/GenFds/Rule.py new file mode 100644 index 000000000..6561c0efd --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/Rule.py @@ -0,0 +1,23 @@ +## @file +# Rule object for generating FFS +# +# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from CommonDataClass.FdfClass import RuleClassObject + +## Rule base class +# +# +class Rule(RuleClassObject): + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + RuleClassObject.__init__(self) diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/RuleComplexFile.py b/roms/edk2/BaseTools/Source/Python/GenFds/RuleComplexFile.py new file mode 100644 index 000000000..198f4f0a9 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/RuleComplexFile.py @@ -0,0 +1,25 @@ +## @file +# Complex Rule object for generating FFS +# +# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Rule +from CommonDataClass.FdfClass import RuleComplexFileClassObject + +## complex rule +# +# +class RuleComplexFile(RuleComplexFileClassObject) : + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + RuleComplexFileClassObject.__init__(self) diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/RuleSimpleFile.py b/roms/edk2/BaseTools/Source/Python/GenFds/RuleSimpleFile.py new file mode 100644 index 000000000..772c768cc --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/RuleSimpleFile.py @@ -0,0 +1,25 @@ +## @file +# Simple Rule object for generating FFS +# +# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Rule +from CommonDataClass.FdfClass import RuleSimpleFileClassObject + +## simple rule +# +# +class RuleSimpleFile (RuleSimpleFileClassObject) : + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + RuleSimpleFileClassObject.__init__(self) diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/Section.py b/roms/edk2/BaseTools/Source/Python/GenFds/Section.py new file mode 100644 index 000000000..2acb70f41 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/Section.py @@ -0,0 +1,169 @@ +## @file +# section base class +# +# Copyright (c) 2007-2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from CommonDataClass.FdfClass import SectionClassObject +from .GenFdsGlobalVariable import GenFdsGlobalVariable +import Common.LongFilePathOs as os, glob +from Common import EdkLogger +from Common.BuildToolError import * +from Common.DataType import * + +## section base class +# +# +class Section (SectionClassObject): + SectionType = { + 'RAW' : 'EFI_SECTION_RAW', + 'FREEFORM' : 'EFI_SECTION_FREEFORM_SUBTYPE_GUID', + BINARY_FILE_TYPE_PE32 : 'EFI_SECTION_PE32', + BINARY_FILE_TYPE_PIC : 'EFI_SECTION_PIC', + BINARY_FILE_TYPE_TE : 'EFI_SECTION_TE', + 'FV_IMAGE' : 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE', + BINARY_FILE_TYPE_DXE_DEPEX : 'EFI_SECTION_DXE_DEPEX', + BINARY_FILE_TYPE_PEI_DEPEX : 'EFI_SECTION_PEI_DEPEX', + 'GUIDED' : 'EFI_SECTION_GUID_DEFINED', + 'COMPRESS' : 'EFI_SECTION_COMPRESSION', + BINARY_FILE_TYPE_UI : 'EFI_SECTION_USER_INTERFACE', + BINARY_FILE_TYPE_SMM_DEPEX : 'EFI_SECTION_SMM_DEPEX' + } + + BinFileType = { + BINARY_FILE_TYPE_GUID : '.guid', + 'ACPI' : '.acpi', + 'ASL' : '.asl' , + BINARY_FILE_TYPE_UEFI_APP : '.app', + BINARY_FILE_TYPE_LIB : '.lib', + BINARY_FILE_TYPE_PE32 : '.pe32', + BINARY_FILE_TYPE_PIC : '.pic', + BINARY_FILE_TYPE_PEI_DEPEX : '.depex', + 'SEC_PEI_DEPEX' : '.depex', + BINARY_FILE_TYPE_TE : '.te', + BINARY_FILE_TYPE_UNI_VER : '.ver', + BINARY_FILE_TYPE_VER : '.ver', + BINARY_FILE_TYPE_UNI_UI : '.ui', + BINARY_FILE_TYPE_UI : '.ui', + BINARY_FILE_TYPE_BIN : '.bin', + 'RAW' : '.raw', + 'COMPAT16' : '.comp16', + BINARY_FILE_TYPE_FV : '.fv' + } + + SectFileType = { + 'SEC_GUID' : '.sec' , + 'SEC_PE32' : '.sec' , + 'SEC_PIC' : '.sec', + 'SEC_TE' : '.sec', + 'SEC_VER' : '.sec', + 'SEC_UI' : '.sec', + 'SEC_COMPAT16' : '.sec', + 'SEC_BIN' : '.sec' + } + + ToolGuid = { + '0xa31280ad-0x481e-0x41b6-0x95e8-0x127f-0x4c984779' : 'TianoCompress', + '0xee4e5898-0x3914-0x4259-0x9d6e-0xdc7b-0xd79403cf' : 'LzmaCompress' + } + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + SectionClassObject.__init__(self) + + ## GenSection() method + # + # virtual function + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # + def GenSection(self, OutputPath, GuidName, SecNum, keyStringList, FfsInf = None, Dict = None): + pass + + ## GetFileList() method + # + # Generate compressed section + # + # @param self The object pointer + # @param FfsInf FfsInfStatement object that contains file list + # @param FileType File type to get + # @param FileExtension File extension to get + # @param Dict dictionary contains macro and its value + # @retval tuple (File list, boolean) + # + def GetFileList(FfsInf, FileType, FileExtension, Dict = None, IsMakefile=False, SectionType=None): + IsSect = FileType in Section.SectFileType + + if FileExtension is not None: + Suffix = FileExtension + elif IsSect : + Suffix = Section.SectionType.get(FileType) + else: + Suffix = Section.BinFileType.get(FileType) + if FfsInf is None: + EdkLogger.error("GenFds", GENFDS_ERROR, 'Inf File does not exist!') + + FileList = [] + if FileType is not None: + for File in FfsInf.BinFileList: + if File.Arch == TAB_ARCH_COMMON or FfsInf.CurrentArch == File.Arch: + if File.Type == FileType or (int(FfsInf.PiSpecVersion, 16) >= 0x0001000A \ + and FileType == 'DXE_DPEX' and File.Type == BINARY_FILE_TYPE_SMM_DEPEX) \ + or (FileType == BINARY_FILE_TYPE_TE and File.Type == BINARY_FILE_TYPE_PE32): + if TAB_STAR in FfsInf.TargetOverrideList or File.Target == TAB_STAR or File.Target in FfsInf.TargetOverrideList or FfsInf.TargetOverrideList == []: + FileList.append(FfsInf.PatchEfiFile(File.Path, File.Type)) + else: + GenFdsGlobalVariable.InfLogger ("\nBuild Target \'%s\' of File %s is not in the Scope of %s specified by INF %s in FDF" %(File.Target, File.File, FfsInf.TargetOverrideList, FfsInf.InfFileName)) + else: + GenFdsGlobalVariable.VerboseLogger ("\nFile Type \'%s\' of File %s in %s is not same with file type \'%s\' from Rule in FDF" %(File.Type, File.File, FfsInf.InfFileName, FileType)) + else: + GenFdsGlobalVariable.InfLogger ("\nCurrent ARCH \'%s\' of File %s is not in the Support Arch Scope of %s specified by INF %s in FDF" %(FfsInf.CurrentArch, File.File, File.Arch, FfsInf.InfFileName)) + + elif FileType is None and SectionType == BINARY_FILE_TYPE_RAW: + for File in FfsInf.BinFileList: + if File.Ext == Suffix: + FileList.append(File.Path) + + if (not IsMakefile and Suffix is not None and os.path.exists(FfsInf.EfiOutputPath)) or (IsMakefile and Suffix is not None): + # + # Get Makefile path and time stamp + # + MakefileDir = FfsInf.EfiOutputPath[:-len('OUTPUT')] + Makefile = os.path.join(MakefileDir, 'Makefile') + if not os.path.exists(Makefile): + Makefile = os.path.join(MakefileDir, 'GNUmakefile') + if os.path.exists(Makefile): + # Update to search files with suffix in all sub-dirs. + Tuple = os.walk(FfsInf.EfiOutputPath) + for Dirpath, Dirnames, Filenames in Tuple: + for F in Filenames: + if os.path.splitext(F)[1] == Suffix: + FullName = os.path.join(Dirpath, F) + if os.path.getmtime(FullName) > os.path.getmtime(Makefile): + FileList.append(FullName) + if not FileList: + SuffixMap = FfsInf.GetFinalTargetSuffixMap() + if Suffix in SuffixMap: + FileList.extend(SuffixMap[Suffix]) + + #Process the file lists is alphabetical for a same section type + if len (FileList) > 1: + FileList.sort() + + return FileList, IsSect + GetFileList = staticmethod(GetFileList) diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/UiSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/UiSection.py new file mode 100644 index 000000000..f643058bd --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/UiSection.py @@ -0,0 +1,74 @@ +## @file +# process UI section generation +# +# Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from . import Section +from .Ffs import SectionSuffix +import subprocess +import Common.LongFilePathOs as os +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from CommonDataClass.FdfClass import UiSectionClassObject +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.DataType import * + +## generate UI section +# +# +class UiSection (UiSectionClassObject): + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + UiSectionClassObject.__init__(self) + + ## GenSection() method + # + # Generate UI section + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # @retval tuple (Generated file name, section alignment) + # + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf=None, Dict=None, IsMakefile = False): + # + # Prepare the parameter of GenSection + # + if FfsInf is not None: + self.Alignment = FfsInf.__ExtendMacro__(self.Alignment) + self.StringData = FfsInf.__ExtendMacro__(self.StringData) + self.FileName = FfsInf.__ExtendMacro__(self.FileName) + + OutputFile = os.path.join(OutputPath, ModuleName + SUP_MODULE_SEC + SecNum + SectionSuffix.get(BINARY_FILE_TYPE_UI)) + + if self.StringData is not None : + NameString = self.StringData + elif self.FileName is not None: + if Dict is None: + Dict = {} + FileNameStr = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FileName) + FileNameStr = GenFdsGlobalVariable.MacroExtend(FileNameStr, Dict) + FileObj = open(FileNameStr, 'r') + NameString = FileObj.read() + FileObj.close() + else: + NameString = '' + GenFdsGlobalVariable.GenerateSection(OutputFile, None, 'EFI_SECTION_USER_INTERFACE', Ui=NameString, IsMakefile=IsMakefile) + + OutputFileList = [] + OutputFileList.append(OutputFile) + return OutputFileList, self.Alignment diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/VerSection.py b/roms/edk2/BaseTools/Source/Python/GenFds/VerSection.py new file mode 100644 index 000000000..7280e80cb --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/VerSection.py @@ -0,0 +1,76 @@ +## @file +# process Version section generation +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +## +# Import Modules +# +from __future__ import absolute_import +from .Ffs import SectionSuffix +import Common.LongFilePathOs as os +from .GenFdsGlobalVariable import GenFdsGlobalVariable +from CommonDataClass.FdfClass import VerSectionClassObject +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.DataType import SUP_MODULE_SEC + +## generate version section +# +# +class VerSection (VerSectionClassObject): + + ## The constructor + # + # @param self The object pointer + # + def __init__(self): + VerSectionClassObject.__init__(self) + + ## GenSection() method + # + # Generate version section + # + # @param self The object pointer + # @param OutputPath Where to place output file + # @param ModuleName Which module this section belongs to + # @param SecNum Index of section + # @param KeyStringList Filter for inputs of section generation + # @param FfsInf FfsInfStatement object that contains this section data + # @param Dict dictionary contains macro and its value + # @retval tuple (Generated file name, section alignment) + # + def GenSection(self, OutputPath, ModuleName, SecNum, KeyStringList, FfsInf=None, Dict=None, IsMakefile = False): + # + # Prepare the parameter of GenSection + # + if FfsInf: + self.Alignment = FfsInf.__ExtendMacro__(self.Alignment) + self.BuildNum = FfsInf.__ExtendMacro__(self.BuildNum) + self.StringData = FfsInf.__ExtendMacro__(self.StringData) + self.FileName = FfsInf.__ExtendMacro__(self.FileName) + + OutputFile = os.path.join(OutputPath, + ModuleName + SUP_MODULE_SEC + SecNum + SectionSuffix.get('VERSION')) + OutputFile = os.path.normpath(OutputFile) + + # Get String Data + StringData = '' + if self.StringData: + StringData = self.StringData + elif self.FileName: + if Dict is None: + Dict = {} + FileNameStr = GenFdsGlobalVariable.ReplaceWorkspaceMacro(self.FileName) + FileNameStr = GenFdsGlobalVariable.MacroExtend(FileNameStr, Dict) + FileObj = open(FileNameStr, 'r') + StringData = FileObj.read() + StringData = '"' + StringData + '"' + FileObj.close() + GenFdsGlobalVariable.GenerateSection(OutputFile, [], 'EFI_SECTION_VERSION', + Ver=StringData, BuildNumber=self.BuildNum, IsMakefile=IsMakefile) + OutputFileList = [] + OutputFileList.append(OutputFile) + return OutputFileList, self.Alignment diff --git a/roms/edk2/BaseTools/Source/Python/GenFds/__init__.py b/roms/edk2/BaseTools/Source/Python/GenFds/__init__.py new file mode 100644 index 000000000..09ea47ea5 --- /dev/null +++ b/roms/edk2/BaseTools/Source/Python/GenFds/__init__.py @@ -0,0 +1,9 @@ +## @file +# Python 'GenFds' package initialization file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# -- cgit