diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Workspace/DecBuildData.py | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Workspace/DecBuildData.py')
-rwxr-xr-x | src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Workspace/DecBuildData.py | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Workspace/DecBuildData.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Workspace/DecBuildData.py new file mode 100755 index 00000000..78377286 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Workspace/DecBuildData.py @@ -0,0 +1,475 @@ +## @file +# This file is used to create a database used by build tool +# +# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> +# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +from Common.StringUtils import * +from Common.DataType import * +from Common.Misc import * +from types import * +from collections import OrderedDict +from CommonDataClass.DataClass import * +from Workspace.BuildClassObject import PackageBuildClassObject, StructurePcd, PcdClassObject +from Common.GlobalData import gGlobalDefines +from re import compile + +## Platform build information from DEC file +# +# This class is used to retrieve information stored in database and convert them +# into PackageBuildClassObject form for easier use for AutoGen. +# +class DecBuildData(PackageBuildClassObject): + # dict used to convert PCD type in database to string used by build tool + _PCD_TYPE_STRING_ = { + MODEL_PCD_FIXED_AT_BUILD : TAB_PCDS_FIXED_AT_BUILD, + MODEL_PCD_PATCHABLE_IN_MODULE : TAB_PCDS_PATCHABLE_IN_MODULE, + MODEL_PCD_FEATURE_FLAG : TAB_PCDS_FEATURE_FLAG, + MODEL_PCD_DYNAMIC : TAB_PCDS_DYNAMIC, + MODEL_PCD_DYNAMIC_DEFAULT : TAB_PCDS_DYNAMIC, + MODEL_PCD_DYNAMIC_HII : TAB_PCDS_DYNAMIC_HII, + MODEL_PCD_DYNAMIC_VPD : TAB_PCDS_DYNAMIC_VPD, + MODEL_PCD_DYNAMIC_EX : TAB_PCDS_DYNAMIC_EX, + MODEL_PCD_DYNAMIC_EX_DEFAULT : TAB_PCDS_DYNAMIC_EX, + MODEL_PCD_DYNAMIC_EX_HII : TAB_PCDS_DYNAMIC_EX_HII, + MODEL_PCD_DYNAMIC_EX_VPD : TAB_PCDS_DYNAMIC_EX_VPD, + } + + # dict used to convert part of [Defines] to members of DecBuildData directly + _PROPERTY_ = { + # + # Required Fields + # + TAB_DEC_DEFINES_PACKAGE_NAME : "_PackageName", + TAB_DEC_DEFINES_PACKAGE_GUID : "_Guid", + TAB_DEC_DEFINES_PACKAGE_VERSION : "_Version", + TAB_DEC_DEFINES_PKG_UNI_FILE : "_PkgUniFile", + } + + + ## Constructor of DecBuildData + # + # Initialize object of DecBuildData + # + # @param FilePath The path of package description file + # @param RawData The raw data of DEC file + # @param BuildDataBase Database used to retrieve module information + # @param Arch The target architecture + # @param Platform (not used for DecBuildData) + # @param Macros Macros used for replacement in DSC file + # + def __init__(self, File, RawData, BuildDataBase, Arch=TAB_ARCH_COMMON, Target=None, Toolchain=None): + self.MetaFile = File + self._PackageDir = File.Dir + self._RawData = RawData + self._Bdb = BuildDataBase + self._Arch = Arch + self._Target = Target + self._Toolchain = Toolchain + self._Clear() + + ## XXX[key] = value + def __setitem__(self, key, value): + self.__dict__[self._PROPERTY_[key]] = value + + ## value = XXX[key] + def __getitem__(self, key): + return self.__dict__[self._PROPERTY_[key]] + + ## "in" test support + def __contains__(self, key): + return key in self._PROPERTY_ + + ## Set all internal used members of DecBuildData to None + def _Clear(self): + self._Header = None + self._PackageName = None + self._Guid = None + self._Version = None + self._PkgUniFile = None + self._Protocols = None + self._Ppis = None + self._Guids = None + self._Includes = None + self._CommonIncludes = None + self._LibraryClasses = None + self._Pcds = None + self._MacroDict = None + self._PrivateProtocols = None + self._PrivatePpis = None + self._PrivateGuids = None + self._PrivateIncludes = None + + ## Get current effective macros + @property + def _Macros(self): + if self._MacroDict is None: + self._MacroDict = dict(gGlobalDefines) + return self._MacroDict + + ## Get architecture + @property + def Arch(self): + return self._Arch + + ## Retrieve all information in [Defines] section + # + # (Retrieving all [Defines] information in one-shot is just to save time.) + # + def _GetHeaderInfo(self): + RecordList = self._RawData[MODEL_META_DATA_HEADER, self._Arch] + for Record in RecordList: + Name = Record[1] + if Name in self: + self[Name] = Record[2] + self._Header = 'DUMMY' + + ## Retrieve package name + @property + def PackageName(self): + if self._PackageName is None: + if self._Header is None: + self._GetHeaderInfo() + if self._PackageName is None: + EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_NAME", File=self.MetaFile) + return self._PackageName + + ## Retrieve file guid + @property + def PackageName(self): + if self._Guid is None: + if self._Header is None: + self._GetHeaderInfo() + if self._Guid is None: + EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "No PACKAGE_GUID", File=self.MetaFile) + return self._Guid + + ## Retrieve package version + @property + def Version(self): + if self._Version is None: + if self._Header is None: + self._GetHeaderInfo() + if self._Version is None: + self._Version = '' + return self._Version + + ## Retrieve protocol definitions (name/value pairs) + @property + def Protocols(self): + if self._Protocols is None: + # + # tdict is a special kind of dict, used for selecting correct + # protocol definition for given ARCH + # + ProtocolDict = tdict(True) + PrivateProtocolDict = tdict(True) + NameList = [] + PrivateNameList = [] + PublicNameList = [] + # find out all protocol definitions for specific and 'common' arch + RecordList = self._RawData[MODEL_EFI_PROTOCOL, self._Arch] + for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList: + if PrivateFlag == 'PRIVATE': + if Name not in PrivateNameList: + PrivateNameList.append(Name) + PrivateProtocolDict[Arch, Name] = Guid + if Name in PublicNameList: + EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) + else: + if Name not in PublicNameList: + PublicNameList.append(Name) + if Name in PrivateNameList: + EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) + if Name not in NameList: + NameList.append(Name) + ProtocolDict[Arch, Name] = Guid + # use OrderedDict to keep the order + self._Protocols = OrderedDict() + self._PrivateProtocols = OrderedDict() + for Name in NameList: + # + # limit the ARCH to self._Arch, if no self._Arch found, tdict + # will automatically turn to 'common' ARCH for trying + # + self._Protocols[Name] = ProtocolDict[self._Arch, Name] + for Name in PrivateNameList: + self._PrivateProtocols[Name] = PrivateProtocolDict[self._Arch, Name] + return self._Protocols + + ## Retrieve PPI definitions (name/value pairs) + @property + def Ppis(self): + if self._Ppis is None: + # + # tdict is a special kind of dict, used for selecting correct + # PPI definition for given ARCH + # + PpiDict = tdict(True) + PrivatePpiDict = tdict(True) + NameList = [] + PrivateNameList = [] + PublicNameList = [] + # find out all PPI definitions for specific arch and 'common' arch + RecordList = self._RawData[MODEL_EFI_PPI, self._Arch] + for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList: + if PrivateFlag == 'PRIVATE': + if Name not in PrivateNameList: + PrivateNameList.append(Name) + PrivatePpiDict[Arch, Name] = Guid + if Name in PublicNameList: + EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) + else: + if Name not in PublicNameList: + PublicNameList.append(Name) + if Name in PrivateNameList: + EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) + if Name not in NameList: + NameList.append(Name) + PpiDict[Arch, Name] = Guid + # use OrderedDict to keep the order + self._Ppis = OrderedDict() + self._PrivatePpis = OrderedDict() + for Name in NameList: + # + # limit the ARCH to self._Arch, if no self._Arch found, tdict + # will automatically turn to 'common' ARCH for trying + # + self._Ppis[Name] = PpiDict[self._Arch, Name] + for Name in PrivateNameList: + self._PrivatePpis[Name] = PrivatePpiDict[self._Arch, Name] + return self._Ppis + + ## Retrieve GUID definitions (name/value pairs) + @property + def Guids(self): + if self._Guids is None: + # + # tdict is a special kind of dict, used for selecting correct + # GUID definition for given ARCH + # + GuidDict = tdict(True) + PrivateGuidDict = tdict(True) + NameList = [] + PrivateNameList = [] + PublicNameList = [] + # find out all protocol definitions for specific and 'common' arch + RecordList = self._RawData[MODEL_EFI_GUID, self._Arch] + for Name, Guid, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList: + if PrivateFlag == 'PRIVATE': + if Name not in PrivateNameList: + PrivateNameList.append(Name) + PrivateGuidDict[Arch, Name] = Guid + if Name in PublicNameList: + EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) + else: + if Name not in PublicNameList: + PublicNameList.append(Name) + if Name in PrivateNameList: + EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % Name, File=self.MetaFile, Line=LineNo) + if Name not in NameList: + NameList.append(Name) + GuidDict[Arch, Name] = Guid + # use OrderedDict to keep the order + self._Guids = OrderedDict() + self._PrivateGuids = OrderedDict() + for Name in NameList: + # + # limit the ARCH to self._Arch, if no self._Arch found, tdict + # will automatically turn to 'common' ARCH for trying + # + self._Guids[Name] = GuidDict[self._Arch, Name] + for Name in PrivateNameList: + self._PrivateGuids[Name] = PrivateGuidDict[self._Arch, Name] + return self._Guids + + ## Retrieve public include paths declared in this package + @property + def Includes(self): + if self._Includes is None or self._CommonIncludes is None: + self._CommonIncludes = [] + self._Includes = [] + self._PrivateIncludes = [] + PublicInclues = [] + RecordList = self._RawData[MODEL_EFI_INCLUDE, self._Arch] + Macros = self._Macros + for Record in RecordList: + File = PathClass(NormPath(Record[0], Macros), self._PackageDir, Arch=self._Arch) + LineNo = Record[-1] + # validate the path + ErrorCode, ErrorInfo = File.Validate() + if ErrorCode != 0: + EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo) + + # avoid duplicate include path + if File not in self._Includes: + self._Includes.append(File) + if Record[4] == 'PRIVATE': + if File not in self._PrivateIncludes: + self._PrivateIncludes.append(File) + if File in PublicInclues: + EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo) + else: + if File not in PublicInclues: + PublicInclues.append(File) + if File in self._PrivateIncludes: + EdkLogger.error('build', OPTION_CONFLICT, "Can't determine %s's attribute, it is both defined as Private and non-Private attribute in DEC file." % File, File=self.MetaFile, Line=LineNo) + if Record[3] == TAB_COMMON: + self._CommonIncludes.append(File) + return self._Includes + + ## Retrieve library class declarations (not used in build at present) + @property + def LibraryClasses(self): + if self._LibraryClasses is None: + # + # tdict is a special kind of dict, used for selecting correct + # library class declaration for given ARCH + # + LibraryClassDict = tdict(True) + LibraryClassSet = set() + RecordList = self._RawData[MODEL_EFI_LIBRARY_CLASS, self._Arch] + Macros = self._Macros + for LibraryClass, File, Dummy, Arch, PrivateFlag, ID, LineNo in RecordList: + File = PathClass(NormPath(File, Macros), self._PackageDir, Arch=self._Arch) + # check the file validation + ErrorCode, ErrorInfo = File.Validate() + if ErrorCode != 0: + EdkLogger.error('build', ErrorCode, ExtraData=ErrorInfo, File=self.MetaFile, Line=LineNo) + LibraryClassSet.add(LibraryClass) + LibraryClassDict[Arch, LibraryClass] = File + self._LibraryClasses = OrderedDict() + for LibraryClass in LibraryClassSet: + self._LibraryClasses[LibraryClass] = LibraryClassDict[self._Arch, LibraryClass] + return self._LibraryClasses + + ## Retrieve PCD declarations + @property + def Pcds(self): + if self._Pcds is None: + self._Pcds = OrderedDict() + self._Pcds.update(self._GetPcd(MODEL_PCD_FIXED_AT_BUILD)) + self._Pcds.update(self._GetPcd(MODEL_PCD_PATCHABLE_IN_MODULE)) + self._Pcds.update(self._GetPcd(MODEL_PCD_FEATURE_FLAG)) + self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC)) + self._Pcds.update(self._GetPcd(MODEL_PCD_DYNAMIC_EX)) + return self._Pcds + + def ParsePcdName(self,TokenCName): + TokenCName = TokenCName.strip() + if TokenCName.startswith("["): + if "." in TokenCName: + Demesionattr = TokenCName[:TokenCName.index(".")] + Fields = TokenCName[TokenCName.index(".")+1:] + else: + Demesionattr = TokenCName + Fields = "" + else: + Demesionattr = "" + Fields = TokenCName + + return Demesionattr,Fields + + def ProcessStructurePcd(self, StructurePcdRawDataSet): + s_pcd_set = OrderedDict() + for s_pcd, LineNo in StructurePcdRawDataSet: + if s_pcd.TokenSpaceGuidCName not in s_pcd_set: + s_pcd_set[s_pcd.TokenSpaceGuidCName] = [] + s_pcd_set[s_pcd.TokenSpaceGuidCName].append((s_pcd, LineNo)) + + str_pcd_set = [] + for pcdname in s_pcd_set: + dep_pkgs = [] + struct_pcd = StructurePcd() + for item, LineNo in s_pcd_set[pcdname]: + if not item.TokenCName: + continue + if "<HeaderFiles>" in item.TokenCName: + struct_pcd.StructuredPcdIncludeFile.append(item.DefaultValue) + elif "<Packages>" in item.TokenCName: + dep_pkgs.append(item.DefaultValue) + elif item.DatumType == item.TokenCName: + struct_pcd.copy(item) + struct_pcd.TokenValue = struct_pcd.TokenValue.strip("{").strip() + struct_pcd.TokenSpaceGuidCName, struct_pcd.TokenCName = pcdname.split(".") + struct_pcd.PcdDefineLineNo = LineNo + struct_pcd.PkgPath = self.MetaFile.File + struct_pcd.SetDecDefaultValue(item.DefaultValue,self.MetaFile.File,LineNo) + else: + DemesionAttr, Fields = self.ParsePcdName(item.TokenCName) + struct_pcd.AddDefaultValue(Fields, item.DefaultValue, self.MetaFile.File, LineNo,DemesionAttr) + + struct_pcd.PackageDecs = dep_pkgs + str_pcd_set.append(struct_pcd) + return str_pcd_set + + ## Retrieve PCD declarations for given type + def _GetPcd(self, Type): + Pcds = OrderedDict() + # + # tdict is a special kind of dict, used for selecting correct + # PCD declaration for given ARCH + # + PcdDict = tdict(True, 3) + # for summarizing PCD + PcdSet = [] + # find out all PCDs of the 'type' + + StrPcdSet = [] + RecordList = self._RawData[Type, self._Arch] + for TokenSpaceGuid, PcdCName, Setting, Arch, PrivateFlag, Dummy1, Dummy2 in RecordList: + PcdDict[Arch, PcdCName, TokenSpaceGuid] = (Setting, Dummy2) + if not (PcdCName, TokenSpaceGuid) in PcdSet: + PcdSet.append((PcdCName, TokenSpaceGuid)) + + DefinitionPosition = {} + for PcdCName, TokenSpaceGuid in PcdSet: + # + # limit the ARCH to self._Arch, if no self._Arch found, tdict + # will automatically turn to 'common' ARCH and try again + # + Setting, LineNo = PcdDict[self._Arch, PcdCName, TokenSpaceGuid] + if Setting is None: + continue + + DefaultValue, DatumType, TokenNumber = AnalyzePcdData(Setting) + validateranges, validlists, expressions = self._RawData.GetValidExpression(TokenSpaceGuid, PcdCName) + PcdObj = PcdClassObject( + PcdCName, + TokenSpaceGuid, + self._PCD_TYPE_STRING_[Type], + DatumType, + DefaultValue, + TokenNumber, + '', + {}, + False, + None, + list(validateranges), + list(validlists), + list(expressions) + ) + DefinitionPosition[PcdObj] = (self.MetaFile.File, LineNo) + if "." in TokenSpaceGuid: + StrPcdSet.append((PcdObj, LineNo)) + else: + Pcds[PcdCName, TokenSpaceGuid, self._PCD_TYPE_STRING_[Type]] = PcdObj + + StructurePcds = self.ProcessStructurePcd(StrPcdSet) + for pcd in StructurePcds: + Pcds[pcd.TokenCName, pcd.TokenSpaceGuidCName, self._PCD_TYPE_STRING_[Type]] = pcd + StructPattern = compile(r'[_a-zA-Z][0-9A-Za-z_]*$') + for pcd in Pcds.values(): + if pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]: + if not pcd.IsAggregateDatumType(): + EdkLogger.error('build', FORMAT_INVALID, "DatumType only support BOOLEAN, UINT8, UINT16, UINT32, UINT64, VOID* or a valid struct name.", DefinitionPosition[pcd][0], DefinitionPosition[pcd][1]) + elif not pcd.IsArray() and not pcd.StructuredPcdIncludeFile: + EdkLogger.error("build", PCD_STRUCTURE_PCD_ERROR, "The structure Pcd %s.%s header file is not found in %s line %s \n" % (pcd.TokenSpaceGuidCName, pcd.TokenCName, pcd.DefinitionPosition[0], pcd.DefinitionPosition[1] )) + return Pcds + + @property + def CommonIncludes(self): + if self._CommonIncludes is None: + self.Includes + return self._CommonIncludes |