summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common')
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/BuildToolError.py160
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/BuildVersion.py10
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/DataType.py539
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py85
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py9
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/__init__.py9
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/EdkLogger.py421
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Expression.py1054
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/GlobalData.py124
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathOs.py79
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathOsPath.py47
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathSupport.py45
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Misc.py1929
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/MultipleWorkspace.py150
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Parsing.py906
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/RangeExpression.py694
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/StringUtils.py873
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/TargetTxtClassObject.py199
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/ToolDefClassObject.py290
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py409
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py190
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py310
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py130
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py9
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/__init__.py9
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VariableAttributes.py51
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VpdInfoFile.py255
-rw-r--r--src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/__init__.py9
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/caching.py41
29 files changed, 9036 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/BuildToolError.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/BuildToolError.py
new file mode 100644
index 00000000..c0a3269b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/BuildToolError.py
@@ -0,0 +1,160 @@
+## @file
+# Standardized Error Handling infrastructures.
+#
+# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+FILE_OPEN_FAILURE = 1
+FILE_WRITE_FAILURE = 2
+FILE_PARSE_FAILURE = 3
+FILE_READ_FAILURE = 4
+FILE_CREATE_FAILURE = 5
+FILE_CHECKSUM_FAILURE = 6
+FILE_COMPRESS_FAILURE = 7
+FILE_DECOMPRESS_FAILURE = 8
+FILE_MOVE_FAILURE = 9
+FILE_DELETE_FAILURE = 10
+FILE_COPY_FAILURE = 11
+FILE_POSITIONING_FAILURE = 12
+FILE_ALREADY_EXIST = 13
+FILE_NOT_FOUND = 14
+FILE_TYPE_MISMATCH = 15
+FILE_CASE_MISMATCH = 16
+FILE_DUPLICATED = 17
+FILE_UNKNOWN_ERROR = 0x0FFF
+
+OPTION_UNKNOWN = 0x1000
+OPTION_MISSING = 0x1001
+OPTION_CONFLICT = 0x1002
+OPTION_VALUE_INVALID = 0x1003
+OPTION_DEPRECATED = 0x1004
+OPTION_NOT_SUPPORTED = 0x1005
+OPTION_UNKNOWN_ERROR = 0x1FFF
+
+PARAMETER_INVALID = 0x2000
+PARAMETER_MISSING = 0x2001
+PARAMETER_UNKNOWN_ERROR =0x2FFF
+
+FORMAT_INVALID = 0x3000
+FORMAT_NOT_SUPPORTED = 0x3001
+FORMAT_UNKNOWN = 0x3002
+FORMAT_UNKNOWN_ERROR = 0x3FFF
+
+RESOURCE_NOT_AVAILABLE = 0x4000
+RESOURCE_ALLOCATE_FAILURE = 0x4001
+RESOURCE_FULL = 0x4002
+RESOURCE_OVERFLOW = 0x4003
+RESOURCE_UNDERRUN = 0x4004
+RESOURCE_UNKNOWN_ERROR = 0x4FFF
+
+ATTRIBUTE_NOT_AVAILABLE = 0x5000
+ATTRIBUTE_GET_FAILURE = 0x5001
+ATTRIBUTE_SET_FAILURE = 0x5002
+ATTRIBUTE_UPDATE_FAILURE = 0x5003
+ATTRIBUTE_ACCESS_DENIED = 0x5004
+ATTRIBUTE_UNKNOWN_ERROR = 0x5FFF
+
+IO_NOT_READY = 0x6000
+IO_BUSY = 0x6001
+IO_TIMEOUT = 0x6002
+IO_UNKNOWN_ERROR = 0x6FFF
+
+COMMAND_FAILURE = 0x7000
+
+PERMISSION_FAILURE = 0x8000
+
+FV_FREESIZE_ERROR = 0x9000
+
+CODE_ERROR = 0xC0DE
+
+AUTOGEN_ERROR = 0xF000
+PARSER_ERROR = 0xF001
+BUILD_ERROR = 0xF002
+GENFDS_ERROR = 0xF003
+ECC_ERROR = 0xF004
+EOT_ERROR = 0xF005
+PREBUILD_ERROR = 0xF007
+POSTBUILD_ERROR = 0xF008
+DDC_ERROR = 0xF009
+WARNING_AS_ERROR = 0xF006
+MIGRATION_ERROR = 0xF010
+PCD_VALIDATION_INFO_ERROR = 0xF011
+PCD_VARIABLE_ATTRIBUTES_ERROR = 0xF012
+PCD_VARIABLE_INFO_ERROR = 0xF016
+PCD_VARIABLE_ATTRIBUTES_CONFLICT_ERROR = 0xF013
+PCD_STRUCTURE_PCD_INVALID_FIELD_ERROR = 0xF014
+PCD_STRUCTURE_PCD_ERROR = 0xF015
+ERROR_STATEMENT = 0xFFFD
+ABORT_ERROR = 0xFFFE
+UNKNOWN_ERROR = 0xFFFF
+
+## Error message of each error code
+gErrorMessage = {
+ FILE_NOT_FOUND : "File/directory not found in workspace",
+ FILE_OPEN_FAILURE : "File open failure",
+ FILE_WRITE_FAILURE : "File write failure",
+ FILE_PARSE_FAILURE : "File parse failure",
+ FILE_READ_FAILURE : "File read failure",
+ FILE_CREATE_FAILURE : "File create failure",
+ FILE_CHECKSUM_FAILURE : "Invalid checksum of file",
+ FILE_COMPRESS_FAILURE : "File compress failure",
+ FILE_DECOMPRESS_FAILURE : "File decompress failure",
+ FILE_MOVE_FAILURE : "File move failure",
+ FILE_DELETE_FAILURE : "File delete failure",
+ FILE_COPY_FAILURE : "File copy failure",
+ FILE_POSITIONING_FAILURE: "Failed to seeking position",
+ FILE_ALREADY_EXIST : "File or directory already exists",
+ FILE_TYPE_MISMATCH : "Incorrect file type",
+ FILE_CASE_MISMATCH : "File name case mismatch",
+ FILE_DUPLICATED : "Duplicated file found",
+ FILE_UNKNOWN_ERROR : "Unknown error encountered on file",
+
+ OPTION_UNKNOWN : "Unknown option",
+ OPTION_MISSING : "Missing option",
+ OPTION_CONFLICT : "Conflict options",
+ OPTION_VALUE_INVALID : "Invalid value of option",
+ OPTION_DEPRECATED : "Deprecated option",
+ OPTION_NOT_SUPPORTED : "Unsupported option",
+ OPTION_UNKNOWN_ERROR : "Unknown error when processing options",
+
+ PARAMETER_INVALID : "Invalid parameter",
+ PARAMETER_MISSING : "Missing parameter",
+ PARAMETER_UNKNOWN_ERROR : "Unknown error in parameters",
+
+ FORMAT_INVALID : "Invalid syntax/format",
+ FORMAT_NOT_SUPPORTED : "Not supported syntax/format",
+ FORMAT_UNKNOWN : "Unknown format",
+ FORMAT_UNKNOWN_ERROR : "Unknown error in syntax/format ",
+
+ RESOURCE_NOT_AVAILABLE : "Not available",
+ RESOURCE_ALLOCATE_FAILURE : "Allocate failure",
+ RESOURCE_FULL : "Full",
+ RESOURCE_OVERFLOW : "Overflow",
+ RESOURCE_UNDERRUN : "Underrun",
+ RESOURCE_UNKNOWN_ERROR : "Unknown error",
+
+ ATTRIBUTE_NOT_AVAILABLE : "Not available",
+ ATTRIBUTE_GET_FAILURE : "Failed to retrieve",
+ ATTRIBUTE_SET_FAILURE : "Failed to set",
+ ATTRIBUTE_UPDATE_FAILURE: "Failed to update",
+ ATTRIBUTE_ACCESS_DENIED : "Access denied",
+ ATTRIBUTE_UNKNOWN_ERROR : "Unknown error when accessing",
+
+ COMMAND_FAILURE : "Failed to execute command",
+
+ IO_NOT_READY : "Not ready",
+ IO_BUSY : "Busy",
+ IO_TIMEOUT : "Timeout",
+ IO_UNKNOWN_ERROR : "Unknown error in IO operation",
+
+ ERROR_STATEMENT : "!error statement",
+ UNKNOWN_ERROR : "Unknown error",
+}
+
+## Exception indicating a fatal error
+class FatalError(Exception):
+ pass
+
+if __name__ == "__main__":
+ pass
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/BuildVersion.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/BuildVersion.py
new file mode 100644
index 00000000..d0758824
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/BuildVersion.py
@@ -0,0 +1,10 @@
+## @file
+#
+# This file is for build version number auto generation
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+gBUILD_VERSION = "Developer Build based on Revision: Unknown"
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/DataType.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/DataType.py
new file mode 100644
index 00000000..1ab829f1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/DataType.py
@@ -0,0 +1,539 @@
+## @file
+# This file is used to define common static strings used by INF/DEC/DSC files
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
+# Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+
+##
+# Common Definitions
+#
+TAB_SPLIT = '.'
+TAB_COMMENT_EDK_START = '/*'
+TAB_COMMENT_EDK_END = '*/'
+TAB_COMMENT_EDK_SPLIT = '//'
+TAB_COMMENT_SPLIT = '#'
+TAB_SPECIAL_COMMENT = '##'
+TAB_EQUAL_SPLIT = '='
+TAB_VALUE_SPLIT = '|'
+TAB_COMMA_SPLIT = ','
+TAB_SPACE_SPLIT = ' '
+TAB_SEMI_COLON_SPLIT = ';'
+TAB_SECTION_START = '['
+TAB_SECTION_END = ']'
+TAB_OPTION_START = '<'
+TAB_OPTION_END = '>'
+TAB_SLASH = '\\'
+TAB_BACK_SLASH = '/'
+TAB_STAR = '*'
+TAB_LINE_BREAK = '\n'
+TAB_PRINTCHAR_VT = '\x0b'
+TAB_PRINTCHAR_BS = '\b'
+TAB_PRINTCHAR_NUL = '\0'
+TAB_UINT8 = 'UINT8'
+TAB_UINT16 = 'UINT16'
+TAB_UINT32 = 'UINT32'
+TAB_UINT64 = 'UINT64'
+TAB_VOID = 'VOID*'
+TAB_GUID = 'GUID'
+
+TAB_PCD_CLEAN_NUMERIC_TYPES = {TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64}
+TAB_PCD_NUMERIC_TYPES = {TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, 'BOOLEAN'}
+TAB_PCD_NUMERIC_TYPES_VOID = {TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, 'BOOLEAN', TAB_VOID}
+
+TAB_WORKSPACE = '$(WORKSPACE)'
+TAB_FV_DIRECTORY = 'FV'
+
+TAB_ARCH_NULL = ''
+TAB_ARCH_COMMON = 'COMMON'
+TAB_ARCH_IA32 = 'IA32'
+TAB_ARCH_X64 = 'X64'
+TAB_ARCH_ARM = 'ARM'
+TAB_ARCH_EBC = 'EBC'
+TAB_ARCH_AARCH64 = 'AARCH64'
+
+TAB_ARCH_RISCV64 = 'RISCV64'
+
+ARCH_SET_FULL = {TAB_ARCH_IA32, TAB_ARCH_X64, TAB_ARCH_ARM, TAB_ARCH_EBC, TAB_ARCH_AARCH64, TAB_ARCH_RISCV64, TAB_ARCH_COMMON}
+
+SUP_MODULE_BASE = 'BASE'
+SUP_MODULE_SEC = 'SEC'
+SUP_MODULE_PEI_CORE = 'PEI_CORE'
+SUP_MODULE_PEIM = 'PEIM'
+SUP_MODULE_DXE_CORE = 'DXE_CORE'
+SUP_MODULE_DXE_DRIVER = 'DXE_DRIVER'
+SUP_MODULE_DXE_RUNTIME_DRIVER = 'DXE_RUNTIME_DRIVER'
+SUP_MODULE_DXE_SAL_DRIVER = 'DXE_SAL_DRIVER'
+SUP_MODULE_DXE_SMM_DRIVER = 'DXE_SMM_DRIVER'
+SUP_MODULE_UEFI_DRIVER = 'UEFI_DRIVER'
+SUP_MODULE_UEFI_APPLICATION = 'UEFI_APPLICATION'
+SUP_MODULE_USER_DEFINED = 'USER_DEFINED'
+SUP_MODULE_HOST_APPLICATION = 'HOST_APPLICATION'
+SUP_MODULE_SMM_CORE = 'SMM_CORE'
+SUP_MODULE_MM_STANDALONE = 'MM_STANDALONE'
+SUP_MODULE_MM_CORE_STANDALONE = 'MM_CORE_STANDALONE'
+
+SUP_MODULE_LIST = [SUP_MODULE_BASE, SUP_MODULE_SEC, SUP_MODULE_PEI_CORE, SUP_MODULE_PEIM, SUP_MODULE_DXE_CORE, SUP_MODULE_DXE_DRIVER, \
+ SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_DXE_SMM_DRIVER, SUP_MODULE_UEFI_DRIVER, \
+ SUP_MODULE_UEFI_APPLICATION, SUP_MODULE_USER_DEFINED, SUP_MODULE_HOST_APPLICATION, SUP_MODULE_SMM_CORE, SUP_MODULE_MM_STANDALONE, SUP_MODULE_MM_CORE_STANDALONE]
+SUP_MODULE_LIST_STRING = TAB_VALUE_SPLIT.join(SUP_MODULE_LIST)
+SUP_MODULE_SET_PEI = {SUP_MODULE_PEIM, SUP_MODULE_PEI_CORE}
+
+EDK_COMPONENT_TYPE_LIBRARY = 'LIBRARY'
+EDK_COMPONENT_TYPE_SECURITY_CORE = 'SECURITY_CORE'
+EDK_COMPONENT_TYPE_PEI_CORE = SUP_MODULE_PEI_CORE
+EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER = 'COMBINED_PEIM_DRIVER'
+EDK_COMPONENT_TYPE_PIC_PEIM = 'PIC_PEIM'
+EDK_COMPONENT_TYPE_RELOCATABLE_PEIM = 'RELOCATABLE_PEIM'
+EDK_COMPONENT_TYPE_BS_DRIVER = 'BS_DRIVER'
+EDK_COMPONENT_TYPE_RT_DRIVER = 'RT_DRIVER'
+EDK_COMPONENT_TYPE_SAL_RT_DRIVER = 'SAL_RT_DRIVER'
+EDK_COMPONENT_TYPE_APPLICATION = 'APPLICATION'
+EDK_NAME = 'EDK'
+EDKII_NAME = 'EDKII'
+MSG_EDKII_MAIL_ADDR = 'devel@edk2.groups.io'
+
+COMPONENT_TO_MODULE_MAP_DICT = {
+ EDK_COMPONENT_TYPE_LIBRARY : SUP_MODULE_BASE,
+ EDK_COMPONENT_TYPE_SECURITY_CORE : SUP_MODULE_SEC,
+ EDK_COMPONENT_TYPE_PEI_CORE : SUP_MODULE_PEI_CORE,
+ EDK_COMPONENT_TYPE_COMBINED_PEIM_DRIVER : SUP_MODULE_PEIM,
+ EDK_COMPONENT_TYPE_PIC_PEIM : SUP_MODULE_PEIM,
+ EDK_COMPONENT_TYPE_RELOCATABLE_PEIM : SUP_MODULE_PEIM,
+ "PE32_PEIM" : SUP_MODULE_PEIM,
+ EDK_COMPONENT_TYPE_BS_DRIVER : SUP_MODULE_DXE_DRIVER,
+ EDK_COMPONENT_TYPE_RT_DRIVER : SUP_MODULE_DXE_RUNTIME_DRIVER,
+ EDK_COMPONENT_TYPE_SAL_RT_DRIVER : SUP_MODULE_DXE_SAL_DRIVER,
+ EDK_COMPONENT_TYPE_APPLICATION : SUP_MODULE_UEFI_APPLICATION,
+ "LOGO" : SUP_MODULE_BASE,
+}
+
+BINARY_FILE_TYPE_FW = 'FW'
+BINARY_FILE_TYPE_GUID = 'GUID'
+BINARY_FILE_TYPE_PREEFORM = 'PREEFORM'
+BINARY_FILE_TYPE_UEFI_APP = 'UEFI_APP'
+BINARY_FILE_TYPE_UNI_UI = 'UNI_UI'
+BINARY_FILE_TYPE_UNI_VER = 'UNI_VER'
+BINARY_FILE_TYPE_LIB = 'LIB'
+BINARY_FILE_TYPE_PE32 = 'PE32'
+BINARY_FILE_TYPE_PIC = 'PIC'
+BINARY_FILE_TYPE_PEI_DEPEX = 'PEI_DEPEX'
+BINARY_FILE_TYPE_DXE_DEPEX = 'DXE_DEPEX'
+BINARY_FILE_TYPE_SMM_DEPEX = 'SMM_DEPEX'
+BINARY_FILE_TYPE_TE = 'TE'
+BINARY_FILE_TYPE_VER = 'VER'
+BINARY_FILE_TYPE_UI = 'UI'
+BINARY_FILE_TYPE_BIN = 'BIN'
+BINARY_FILE_TYPE_FV = 'FV'
+BINARY_FILE_TYPE_RAW = 'RAW_BINARY'
+
+PLATFORM_COMPONENT_TYPE_LIBRARY_CLASS = 'LIBRARY_CLASS'
+PLATFORM_COMPONENT_TYPE_MODULE = 'MODULE'
+
+TAB_SOURCES = 'Sources'
+TAB_SOURCES_COMMON = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_SOURCES_IA32 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_IA32
+TAB_SOURCES_X64 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_X64
+TAB_SOURCES_ARM = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_ARM
+TAB_SOURCES_EBC = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_EBC
+TAB_SOURCES_AARCH64 = TAB_SOURCES + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_BINARIES = 'Binaries'
+TAB_BINARIES_COMMON = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_BINARIES_IA32 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_IA32
+TAB_BINARIES_X64 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_X64
+TAB_BINARIES_ARM = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_ARM
+TAB_BINARIES_EBC = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_EBC
+TAB_BINARIES_AARCH64 = TAB_BINARIES + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_INCLUDES = 'Includes'
+TAB_INCLUDES_COMMON = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_INCLUDES_IA32 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_IA32
+TAB_INCLUDES_X64 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_X64
+TAB_INCLUDES_ARM = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_ARM
+TAB_INCLUDES_EBC = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_EBC
+TAB_INCLUDES_AARCH64 = TAB_INCLUDES + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_GUIDS = 'Guids'
+TAB_GUIDS_COMMON = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_GUIDS_IA32 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_IA32
+TAB_GUIDS_X64 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_X64
+TAB_GUIDS_ARM = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_ARM
+TAB_GUIDS_EBC = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_EBC
+TAB_GUIDS_AARCH64 = TAB_GUIDS + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PROTOCOLS = 'Protocols'
+TAB_PROTOCOLS_COMMON = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_PROTOCOLS_IA32 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_IA32
+TAB_PROTOCOLS_X64 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_X64
+TAB_PROTOCOLS_ARM = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_ARM
+TAB_PROTOCOLS_EBC = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_EBC
+TAB_PROTOCOLS_AARCH64 = TAB_PROTOCOLS + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PPIS = 'Ppis'
+TAB_PPIS_COMMON = TAB_PPIS + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_PPIS_IA32 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_IA32
+TAB_PPIS_X64 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_X64
+TAB_PPIS_ARM = TAB_PPIS + TAB_SPLIT + TAB_ARCH_ARM
+TAB_PPIS_EBC = TAB_PPIS + TAB_SPLIT + TAB_ARCH_EBC
+TAB_PPIS_AARCH64 = TAB_PPIS + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_LIBRARY_CLASSES = 'LibraryClasses'
+TAB_LIBRARY_CLASSES_COMMON = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_LIBRARY_CLASSES_IA32 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_IA32
+TAB_LIBRARY_CLASSES_X64 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_X64
+TAB_LIBRARY_CLASSES_ARM = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_ARM
+TAB_LIBRARY_CLASSES_EBC = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_EBC
+TAB_LIBRARY_CLASSES_AARCH64 = TAB_LIBRARY_CLASSES + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PACKAGES = 'Packages'
+TAB_PACKAGES_COMMON = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_PACKAGES_IA32 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_IA32
+TAB_PACKAGES_X64 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_X64
+TAB_PACKAGES_ARM = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_ARM
+TAB_PACKAGES_EBC = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_EBC
+TAB_PACKAGES_AARCH64 = TAB_PACKAGES + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PCDS = 'Pcds'
+TAB_PCDS_FIXED_AT_BUILD = 'FixedAtBuild'
+TAB_PCDS_PATCHABLE_IN_MODULE = 'PatchableInModule'
+TAB_PCDS_FEATURE_FLAG = 'FeatureFlag'
+TAB_PCDS_DYNAMIC_EX = 'DynamicEx'
+TAB_PCDS_DYNAMIC_EX_DEFAULT = 'DynamicExDefault'
+TAB_PCDS_DYNAMIC_EX_VPD = 'DynamicExVpd'
+TAB_PCDS_DYNAMIC_EX_HII = 'DynamicExHii'
+TAB_PCDS_DYNAMIC = 'Dynamic'
+TAB_PCDS_DYNAMIC_DEFAULT = 'DynamicDefault'
+TAB_PCDS_DYNAMIC_VPD = 'DynamicVpd'
+TAB_PCDS_DYNAMIC_HII = 'DynamicHii'
+
+PCD_DYNAMIC_TYPE_SET = {TAB_PCDS_DYNAMIC, TAB_PCDS_DYNAMIC_DEFAULT, TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_HII}
+PCD_DYNAMIC_EX_TYPE_SET = {TAB_PCDS_DYNAMIC_EX, TAB_PCDS_DYNAMIC_EX_DEFAULT, TAB_PCDS_DYNAMIC_EX_VPD, TAB_PCDS_DYNAMIC_EX_HII}
+
+# leave as a list for order
+PCD_TYPE_LIST = [TAB_PCDS_FIXED_AT_BUILD, TAB_PCDS_PATCHABLE_IN_MODULE, TAB_PCDS_FEATURE_FLAG, TAB_PCDS_DYNAMIC, TAB_PCDS_DYNAMIC_EX]
+
+TAB_PCDS_FIXED_AT_BUILD_NULL = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD
+TAB_PCDS_FIXED_AT_BUILD_COMMON = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_PCDS_FIXED_AT_BUILD_IA32 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_IA32
+TAB_PCDS_FIXED_AT_BUILD_X64 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_X64
+TAB_PCDS_FIXED_AT_BUILD_ARM = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_ARM
+TAB_PCDS_FIXED_AT_BUILD_EBC = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_EBC
+TAB_PCDS_FIXED_AT_BUILD_AARCH64 = TAB_PCDS + TAB_PCDS_FIXED_AT_BUILD + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PCDS_PATCHABLE_IN_MODULE_NULL = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE
+TAB_PCDS_PATCHABLE_IN_MODULE_COMMON = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_PCDS_PATCHABLE_IN_MODULE_IA32 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_IA32
+TAB_PCDS_PATCHABLE_IN_MODULE_X64 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_X64
+TAB_PCDS_PATCHABLE_IN_MODULE_ARM = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_ARM
+TAB_PCDS_PATCHABLE_IN_MODULE_EBC = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_EBC
+TAB_PCDS_PATCHABLE_IN_MODULE_AARCH64 = TAB_PCDS + TAB_PCDS_PATCHABLE_IN_MODULE + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PCDS_FEATURE_FLAG_NULL = TAB_PCDS + TAB_PCDS_FEATURE_FLAG
+TAB_PCDS_FEATURE_FLAG_COMMON = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_PCDS_FEATURE_FLAG_IA32 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_IA32
+TAB_PCDS_FEATURE_FLAG_X64 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_X64
+TAB_PCDS_FEATURE_FLAG_ARM = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_ARM
+TAB_PCDS_FEATURE_FLAG_EBC = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_EBC
+TAB_PCDS_FEATURE_FLAG_AARCH64 = TAB_PCDS + TAB_PCDS_FEATURE_FLAG + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PCDS_DYNAMIC_EX_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX
+TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_DEFAULT
+TAB_PCDS_DYNAMIC_EX_HII_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_HII
+TAB_PCDS_DYNAMIC_EX_VPD_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_EX_VPD
+TAB_PCDS_DYNAMIC_EX_COMMON = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_PCDS_DYNAMIC_EX_IA32 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_IA32
+TAB_PCDS_DYNAMIC_EX_X64 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_X64
+TAB_PCDS_DYNAMIC_EX_ARM = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_ARM
+TAB_PCDS_DYNAMIC_EX_EBC = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_EBC
+TAB_PCDS_DYNAMIC_EX_AARCH64 = TAB_PCDS + TAB_PCDS_DYNAMIC_EX + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PCDS_DYNAMIC_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC
+TAB_PCDS_DYNAMIC_DEFAULT_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_DEFAULT
+TAB_PCDS_DYNAMIC_HII_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_HII
+TAB_PCDS_DYNAMIC_VPD_NULL = TAB_PCDS + TAB_PCDS_DYNAMIC_VPD
+TAB_PCDS_DYNAMIC_COMMON = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_PCDS_DYNAMIC_IA32 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_IA32
+TAB_PCDS_DYNAMIC_X64 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_X64
+TAB_PCDS_DYNAMIC_ARM = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_ARM
+TAB_PCDS_DYNAMIC_EBC = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_EBC
+TAB_PCDS_DYNAMIC_AARCH64 = TAB_PCDS + TAB_PCDS_DYNAMIC + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE = 'PcdLoadFixAddressPeiCodePageNumber'
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE_DATA_TYPE = 'UINT32'
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE = 'PcdLoadFixAddressBootTimeCodePageNumber'
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE_DATA_TYPE = 'UINT32'
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE = 'PcdLoadFixAddressRuntimeCodePageNumber'
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE_DATA_TYPE = 'UINT32'
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE = 'PcdLoadFixAddressSmmCodePageNumber'
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE_DATA_TYPE = 'UINT32'
+TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SET = {TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_PEI_PAGE_SIZE, \
+ TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_DXE_PAGE_SIZE, \
+ TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_RUNTIME_PAGE_SIZE, \
+ TAB_PCDS_PATCHABLE_LOAD_FIX_ADDRESS_SMM_PAGE_SIZE}
+
+## The mapping dictionary from datum type to its maximum number.
+MAX_VAL_TYPE = {"BOOLEAN":0x01, TAB_UINT8:0xFF, TAB_UINT16:0xFFFF, TAB_UINT32:0xFFFFFFFF, TAB_UINT64:0xFFFFFFFFFFFFFFFF}
+## The mapping dictionary from datum type to size string.
+MAX_SIZE_TYPE = {"BOOLEAN":1, TAB_UINT8:1, TAB_UINT16:2, TAB_UINT32:4, TAB_UINT64:8}
+
+TAB_DEPEX = 'Depex'
+TAB_DEPEX_COMMON = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_DEPEX_IA32 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_IA32
+TAB_DEPEX_X64 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_X64
+TAB_DEPEX_ARM = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_ARM
+TAB_DEPEX_EBC = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_EBC
+TAB_DEPEX_AARCH64 = TAB_DEPEX + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_SKUIDS = 'SkuIds'
+TAB_DEFAULT_STORES = 'DefaultStores'
+TAB_DEFAULT_STORES_DEFAULT = 'STANDARD'
+
+TAB_LIBRARIES = 'Libraries'
+TAB_LIBRARIES_COMMON = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_LIBRARIES_IA32 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_IA32
+TAB_LIBRARIES_X64 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_X64
+TAB_LIBRARIES_ARM = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_ARM
+TAB_LIBRARIES_EBC = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_EBC
+TAB_LIBRARIES_AARCH64 = TAB_LIBRARIES + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_COMPONENTS = 'Components'
+TAB_COMPONENTS_COMMON = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_COMMON
+TAB_COMPONENTS_IA32 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_IA32
+TAB_COMPONENTS_X64 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_X64
+TAB_COMPONENTS_ARM = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_ARM
+TAB_COMPONENTS_EBC = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_EBC
+TAB_COMPONENTS_AARCH64 = TAB_COMPONENTS + TAB_SPLIT + TAB_ARCH_AARCH64
+
+TAB_BUILD_OPTIONS = 'BuildOptions'
+
+TAB_DEFINE = 'DEFINE'
+TAB_NMAKE = 'Nmake'
+TAB_USER_EXTENSIONS = 'UserExtensions'
+TAB_INCLUDE = '!include'
+TAB_DEFAULT = 'DEFAULT'
+TAB_COMMON = 'COMMON'
+
+#
+# Common Define
+#
+TAB_COMMON_DEFINES = 'Defines'
+
+#
+# Inf Definitions
+#
+TAB_INF_DEFINES = TAB_COMMON_DEFINES
+TAB_INF_DEFINES_INF_VERSION = 'INF_VERSION'
+TAB_INF_DEFINES_BASE_NAME = 'BASE_NAME'
+TAB_INF_DEFINES_FILE_GUID = 'FILE_GUID'
+TAB_INF_DEFINES_MODULE_TYPE = 'MODULE_TYPE'
+TAB_INF_DEFINES_EFI_SPECIFICATION_VERSION = 'EFI_SPECIFICATION_VERSION'
+TAB_INF_DEFINES_UEFI_SPECIFICATION_VERSION = 'UEFI_SPECIFICATION_VERSION'
+TAB_INF_DEFINES_PI_SPECIFICATION_VERSION = 'PI_SPECIFICATION_VERSION'
+TAB_INF_DEFINES_EDK_RELEASE_VERSION = 'EDK_RELEASE_VERSION'
+TAB_INF_DEFINES_BINARY_MODULE = 'BINARY_MODULE'
+TAB_INF_DEFINES_LIBRARY_CLASS = 'LIBRARY_CLASS'
+TAB_INF_DEFINES_COMPONENT_TYPE = 'COMPONENT_TYPE'
+TAB_INF_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME'
+TAB_INF_DEFINES_DPX_SOURCE = 'DPX_SOURCE'
+TAB_INF_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER'
+TAB_INF_DEFINES_BUILD_TYPE = 'BUILD_TYPE'
+TAB_INF_DEFINES_FFS_EXT = 'FFS_EXT'
+TAB_INF_DEFINES_FV_EXT = 'FV_EXT'
+TAB_INF_DEFINES_SOURCE_FV = 'SOURCE_FV'
+TAB_INF_DEFINES_VERSION_NUMBER = 'VERSION_NUMBER'
+TAB_INF_DEFINES_VERSION = 'VERSION' # for Edk inf, the same as VERSION_NUMBER
+TAB_INF_DEFINES_VERSION_STRING = 'VERSION_STRING'
+TAB_INF_DEFINES_PCD_IS_DRIVER = 'PCD_IS_DRIVER'
+TAB_INF_DEFINES_TIANO_EDK_FLASHMAP_H = 'TIANO_EDK_FLASHMAP_H'
+TAB_INF_DEFINES_ENTRY_POINT = 'ENTRY_POINT'
+TAB_INF_DEFINES_UNLOAD_IMAGE = 'UNLOAD_IMAGE'
+TAB_INF_DEFINES_CONSTRUCTOR = 'CONSTRUCTOR'
+TAB_INF_DEFINES_DESTRUCTOR = 'DESTRUCTOR'
+TAB_INF_DEFINES_DEFINE = 'DEFINE'
+TAB_INF_DEFINES_SPEC = 'SPEC'
+TAB_INF_DEFINES_CUSTOM_MAKEFILE = 'CUSTOM_MAKEFILE'
+TAB_INF_DEFINES_MACRO = '__MACROS__'
+TAB_INF_DEFINES_SHADOW = 'SHADOW'
+TAB_INF_FIXED_PCD = 'FixedPcd'
+TAB_INF_FEATURE_PCD = 'FeaturePcd'
+TAB_INF_PATCH_PCD = 'PatchPcd'
+TAB_INF_PCD = 'Pcd'
+TAB_INF_PCD_EX = 'PcdEx'
+TAB_INF_USAGE_PRO = 'PRODUCES'
+TAB_INF_USAGE_SOME_PRO = 'SOMETIMES_PRODUCES'
+TAB_INF_USAGE_CON = 'CONSUMES'
+TAB_INF_USAGE_SOME_CON = 'SOMETIMES_CONSUMES'
+TAB_INF_USAGE_NOTIFY = 'NOTIFY'
+TAB_INF_USAGE_TO_START = 'TO_START'
+TAB_INF_USAGE_BY_START = 'BY_START'
+TAB_INF_GUIDTYPE_EVENT = 'Event'
+TAB_INF_GUIDTYPE_FILE = 'File'
+TAB_INF_GUIDTYPE_FV = 'FV'
+TAB_INF_GUIDTYPE_GUID = 'GUID'
+TAB_INF_GUIDTYPE_HII = 'HII'
+TAB_INF_GUIDTYPE_HOB = 'HOB'
+TAB_INF_GUIDTYPE_ST = 'SystemTable'
+TAB_INF_GUIDTYPE_TSG = 'TokenSpaceGuid'
+TAB_INF_GUIDTYPE_VAR = 'Variable'
+TAB_INF_GUIDTYPE_PROTOCOL = 'PROTOCOL'
+TAB_INF_GUIDTYPE_PPI = 'PPI'
+TAB_INF_USAGE_UNDEFINED = 'UNDEFINED'
+
+#
+# Dec Definitions
+#
+TAB_DEC_DEFINES = TAB_COMMON_DEFINES
+TAB_DEC_DEFINES_DEC_SPECIFICATION = 'DEC_SPECIFICATION'
+TAB_DEC_DEFINES_PACKAGE_NAME = 'PACKAGE_NAME'
+TAB_DEC_DEFINES_PACKAGE_GUID = 'PACKAGE_GUID'
+TAB_DEC_DEFINES_PACKAGE_VERSION = 'PACKAGE_VERSION'
+TAB_DEC_DEFINES_PKG_UNI_FILE = 'PKG_UNI_FILE'
+
+#
+# Dsc Definitions
+#
+TAB_DSC_DEFINES = TAB_COMMON_DEFINES
+TAB_DSC_DEFINES_PLATFORM_NAME = 'PLATFORM_NAME'
+TAB_DSC_DEFINES_PLATFORM_GUID = 'PLATFORM_GUID'
+TAB_DSC_DEFINES_PLATFORM_VERSION = 'PLATFORM_VERSION'
+TAB_DSC_DEFINES_DSC_SPECIFICATION = 'DSC_SPECIFICATION'
+TAB_DSC_DEFINES_OUTPUT_DIRECTORY = 'OUTPUT_DIRECTORY'
+TAB_DSC_DEFINES_SUPPORTED_ARCHITECTURES = 'SUPPORTED_ARCHITECTURES'
+TAB_DSC_DEFINES_BUILD_TARGETS = 'BUILD_TARGETS'
+TAB_DSC_DEFINES_SKUID_IDENTIFIER = 'SKUID_IDENTIFIER'
+TAB_DSC_DEFINES_PCD_INFO_GENERATION = 'PCD_INFO_GENERATION'
+TAB_DSC_DEFINES_PCD_VAR_CHECK_GENERATION = 'PCD_VAR_CHECK_GENERATION'
+TAB_DSC_DEFINES_FLASH_DEFINITION = 'FLASH_DEFINITION'
+TAB_DSC_DEFINES_BUILD_NUMBER = 'BUILD_NUMBER'
+TAB_DSC_DEFINES_MAKEFILE_NAME = 'MAKEFILE_NAME'
+TAB_DSC_DEFINES_BS_BASE_ADDRESS = 'BsBaseAddress'
+TAB_DSC_DEFINES_RT_BASE_ADDRESS = 'RtBaseAddress'
+TAB_DSC_DEFINES_RFC_LANGUAGES = 'RFC_LANGUAGES'
+TAB_DSC_DEFINES_ISO_LANGUAGES = 'ISO_LANGUAGES'
+TAB_DSC_DEFINES_DEFINE = 'DEFINE'
+TAB_DSC_DEFINES_VPD_TOOL_GUID = 'VPD_TOOL_GUID'
+TAB_FIX_LOAD_TOP_MEMORY_ADDRESS = 'FIX_LOAD_TOP_MEMORY_ADDRESS'
+TAB_DSC_DEFINES_EDKGLOBAL = 'EDK_GLOBAL'
+TAB_DSC_PREBUILD = 'PREBUILD'
+TAB_DSC_POSTBUILD = 'POSTBUILD'
+#
+# TargetTxt Definitions
+#
+TAB_TAT_DEFINES_ACTIVE_PLATFORM = 'ACTIVE_PLATFORM'
+TAB_TAT_DEFINES_ACTIVE_MODULE = 'ACTIVE_MODULE'
+TAB_TAT_DEFINES_TOOL_CHAIN_CONF = 'TOOL_CHAIN_CONF'
+TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER = 'MAX_CONCURRENT_THREAD_NUMBER'
+TAB_TAT_DEFINES_TARGET = 'TARGET'
+TAB_TAT_DEFINES_TOOL_CHAIN_TAG = 'TOOL_CHAIN_TAG'
+TAB_TAT_DEFINES_TARGET_ARCH = 'TARGET_ARCH'
+TAB_TAT_DEFINES_BUILD_RULE_CONF = "BUILD_RULE_CONF"
+
+#
+# ToolDef Definitions
+#
+TAB_TOD_DEFINES_TARGET = 'TARGET'
+TAB_TOD_DEFINES_TOOL_CHAIN_TAG = 'TOOL_CHAIN_TAG'
+TAB_TOD_DEFINES_TARGET_ARCH = 'TARGET_ARCH'
+TAB_TOD_DEFINES_COMMAND_TYPE = 'COMMAND_TYPE'
+TAB_TOD_DEFINES_FAMILY = 'FAMILY'
+TAB_TOD_DEFINES_BUILDRULEFAMILY = 'BUILDRULEFAMILY'
+TAB_TOD_DEFINES_BUILDRULEORDER = 'BUILDRULEORDER'
+
+#
+# Conditional Statements
+#
+TAB_IF = '!if'
+TAB_END_IF = '!endif'
+TAB_ELSE_IF = '!elseif'
+TAB_ELSE = '!else'
+TAB_IF_DEF = '!ifdef'
+TAB_IF_N_DEF = '!ifndef'
+TAB_IF_EXIST = '!if exist'
+TAB_ERROR = '!error'
+
+#
+# Unknown section
+#
+TAB_UNKNOWN = 'UNKNOWN'
+
+#
+# Build database path
+#
+DATABASE_PATH = ":memory:" #"BuildDatabase.db"
+
+# used by ECC
+MODIFIER_SET = {'IN', 'OUT', 'OPTIONAL', 'UNALIGNED', 'EFI_RUNTIMESERVICE', 'EFI_BOOTSERVICE', 'EFIAPI'}
+
+# Dependency Opcodes
+DEPEX_OPCODE_BEFORE = "BEFORE"
+DEPEX_OPCODE_AFTER = "AFTER"
+DEPEX_OPCODE_PUSH = "PUSH"
+DEPEX_OPCODE_AND = "AND"
+DEPEX_OPCODE_OR = "OR"
+DEPEX_OPCODE_NOT = "NOT"
+DEPEX_OPCODE_END = "END"
+DEPEX_OPCODE_SOR = "SOR"
+DEPEX_OPCODE_TRUE = "TRUE"
+DEPEX_OPCODE_FALSE = "FALSE"
+
+# Dependency Expression
+DEPEX_SUPPORTED_OPCODE_SET = {"BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "END", "SOR", "TRUE", "FALSE", '(', ')'}
+
+TAB_STATIC_LIBRARY = "STATIC-LIBRARY-FILE"
+TAB_DYNAMIC_LIBRARY = "DYNAMIC-LIBRARY-FILE"
+TAB_FRAMEWORK_IMAGE = "EFI-IMAGE-FILE"
+TAB_C_CODE_FILE = "C-CODE-FILE"
+TAB_C_HEADER_FILE = "C-HEADER-FILE"
+TAB_UNICODE_FILE = "UNICODE-TEXT-FILE"
+TAB_IMAGE_FILE = "IMAGE-DEFINITION-FILE"
+TAB_DEPENDENCY_EXPRESSION_FILE = "DEPENDENCY-EXPRESSION-FILE"
+TAB_UNKNOWN_FILE = "UNKNOWN-TYPE-FILE"
+TAB_DEFAULT_BINARY_FILE = "_BINARY_FILE_"
+TAB_OBJECT_FILE = "OBJECT-FILE"
+TAB_VFR_FILE = 'VISUAL-FORM-REPRESENTATION-FILE'
+
+# used by BRG
+TAB_BRG_PCD = 'PCD'
+TAB_BRG_LIBRARY = 'Library'
+
+#
+# Build Rule File Version Definition
+#
+TAB_BUILD_RULE_VERSION = "build_rule_version"
+
+# section name for PCDs
+PCDS_DYNAMIC_DEFAULT = "PcdsDynamicDefault"
+PCDS_DYNAMIC_VPD = "PcdsDynamicVpd"
+PCDS_DYNAMIC_HII = "PcdsDynamicHii"
+PCDS_DYNAMICEX_DEFAULT = "PcdsDynamicExDefault"
+PCDS_DYNAMICEX_VPD = "PcdsDynamicExVpd"
+PCDS_DYNAMICEX_HII = "PcdsDynamicExHii"
+
+SECTIONS_HAVE_ITEM_PCD_SET = {PCDS_DYNAMIC_DEFAULT.upper(), PCDS_DYNAMIC_VPD.upper(), PCDS_DYNAMIC_HII.upper(), \
+ PCDS_DYNAMICEX_DEFAULT.upper(), PCDS_DYNAMICEX_VPD.upper(), PCDS_DYNAMICEX_HII.upper()}
+# Section allowed to have items after arch
+SECTIONS_HAVE_ITEM_AFTER_ARCH_SET = {TAB_LIBRARY_CLASSES.upper(), TAB_DEPEX.upper(), TAB_USER_EXTENSIONS.upper(),
+ PCDS_DYNAMIC_DEFAULT.upper(),
+ PCDS_DYNAMIC_VPD.upper(),
+ PCDS_DYNAMIC_HII.upper(),
+ PCDS_DYNAMICEX_DEFAULT.upper(),
+ PCDS_DYNAMICEX_VPD.upper(),
+ PCDS_DYNAMICEX_HII.upper(),
+ TAB_BUILD_OPTIONS.upper(),
+ TAB_PACKAGES.upper(),
+ TAB_INCLUDES.upper()}
+
+#
+# pack codes as used in PcdDb and elsewhere
+#
+PACK_PATTERN_GUID = '=LHHBBBBBBBB'
+PACK_CODE_BY_SIZE = {8:'=Q',
+ 4:'=L',
+ 2:'=H',
+ 1:'=B',
+ 0:'=B',
+ 16:""}
+
+TAB_COMPILER_MSFT = 'MSFT'
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py
new file mode 100755
index 00000000..aa45c3a9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py
@@ -0,0 +1,85 @@
+## @file
+# Module that encodes and decodes a FMP_PAYLOAD_HEADER with a payload.
+# The FMP_PAYLOAD_HEADER is processed by the FmpPayloadHeaderLib in the
+# FmpDevicePkg.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+'''
+FmpPayloadHeader
+'''
+
+import struct
+
+def _SIGNATURE_32 (A, B, C, D):
+ return struct.unpack ('=I',bytearray (A + B + C + D, 'ascii'))[0]
+
+def _SIGNATURE_32_TO_STRING (Signature):
+ return struct.pack ("<I", Signature).decode ()
+
+class FmpPayloadHeaderClass (object):
+ #
+ # typedef struct {
+ # UINT32 Signature;
+ # UINT32 HeaderSize;
+ # UINT32 FwVersion;
+ # UINT32 LowestSupportedVersion;
+ # } FMP_PAYLOAD_HEADER;
+ #
+ # #define FMP_PAYLOAD_HEADER_SIGNATURE SIGNATURE_32 ('M', 'S', 'S', '1')
+ #
+ _StructFormat = '<IIII'
+ _StructSize = struct.calcsize (_StructFormat)
+
+ _FMP_PAYLOAD_HEADER_SIGNATURE = _SIGNATURE_32 ('M', 'S', 'S', '1')
+
+ def __init__ (self):
+ self._Valid = False
+ self.Signature = self._FMP_PAYLOAD_HEADER_SIGNATURE
+ self.HeaderSize = self._StructSize
+ self.FwVersion = 0x00000000
+ self.LowestSupportedVersion = 0x00000000
+ self.Payload = b''
+
+ def Encode (self):
+ FmpPayloadHeader = struct.pack (
+ self._StructFormat,
+ self.Signature,
+ self.HeaderSize,
+ self.FwVersion,
+ self.LowestSupportedVersion
+ )
+ self._Valid = True
+ return FmpPayloadHeader + self.Payload
+
+ def Decode (self, Buffer):
+ if len (Buffer) < self._StructSize:
+ raise ValueError
+ (Signature, HeaderSize, FwVersion, LowestSupportedVersion) = \
+ struct.unpack (
+ self._StructFormat,
+ Buffer[0:self._StructSize]
+ )
+ if Signature != self._FMP_PAYLOAD_HEADER_SIGNATURE:
+ raise ValueError
+ if HeaderSize < self._StructSize:
+ raise ValueError
+ self.Signature = Signature
+ self.HeaderSize = HeaderSize
+ self.FwVersion = FwVersion
+ self.LowestSupportedVersion = LowestSupportedVersion
+ self.Payload = Buffer[self.HeaderSize:]
+
+ self._Valid = True
+ return self.Payload
+
+ def DumpInfo (self):
+ if not self._Valid:
+ raise ValueError
+ print ('FMP_PAYLOAD_HEADER.Signature = {Signature:08X} ({SignatureString})'.format (Signature = self.Signature, SignatureString = _SIGNATURE_32_TO_STRING (self.Signature)))
+ print ('FMP_PAYLOAD_HEADER.HeaderSize = {HeaderSize:08X}'.format (HeaderSize = self.HeaderSize))
+ print ('FMP_PAYLOAD_HEADER.FwVersion = {FwVersion:08X}'.format (FwVersion = self.FwVersion))
+ print ('FMP_PAYLOAD_HEADER.LowestSupportedVersion = {LowestSupportedVersion:08X}'.format (LowestSupportedVersion = self.LowestSupportedVersion))
+ print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload)))
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py
new file mode 100644
index 00000000..119f1f2a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py
@@ -0,0 +1,9 @@
+## @file
+# Python 'Common.Edk2.Capsule' package initialization file.
+#
+# This file is required to make Python interpreter treat the directory
+# as containing package.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/__init__.py
new file mode 100644
index 00000000..0d26bda5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Edk2/__init__.py
@@ -0,0 +1,9 @@
+## @file
+# Python 'Common.Edk2' package initialization file.
+#
+# This file is required to make Python interpreter treat the directory
+# as containing package.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/EdkLogger.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/EdkLogger.py
new file mode 100755
index 00000000..ee088687
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/EdkLogger.py
@@ -0,0 +1,421 @@
+## @file
+# This file implements the log mechanism for Python tools.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+# Copyright 2001-2016 by Vinay Sajip. All Rights Reserved.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice appear in all copies and that
+# both that copyright notice and this permission notice appear in
+# supporting documentation, and that the name of Vinay Sajip
+# not be used in advertising or publicity pertaining to distribution
+# of the software without specific, written prior permission.
+# VINAY SAJIP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# VINAY SAJIP BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+# This copyright is for QueueHandler.
+
+## Import modules
+from __future__ import absolute_import
+import Common.LongFilePathOs as os, sys, logging
+import traceback
+from .BuildToolError import *
+try:
+ from logging.handlers import QueueHandler
+except:
+ class QueueHandler(logging.Handler):
+ """
+ This handler sends events to a queue. Typically, it would be used together
+ with a multiprocessing Queue to centralise logging to file in one process
+ (in a multi-process application), so as to avoid file write contention
+ between processes.
+
+ This code is new in Python 3.2, but this class can be copy pasted into
+ user code for use with earlier Python versions.
+ """
+
+ def __init__(self, queue):
+ """
+ Initialise an instance, using the passed queue.
+ """
+ logging.Handler.__init__(self)
+ self.queue = queue
+
+ def enqueue(self, record):
+ """
+ Enqueue a record.
+
+ The base implementation uses put_nowait. You may want to override
+ this method if you want to use blocking, timeouts or custom queue
+ implementations.
+ """
+ self.queue.put_nowait(record)
+
+ def prepare(self, record):
+ """
+ Prepares a record for queuing. The object returned by this method is
+ enqueued.
+
+ The base implementation formats the record to merge the message
+ and arguments, and removes unpickleable items from the record
+ in-place.
+
+ You might want to override this method if you want to convert
+ the record to a dict or JSON string, or send a modified copy
+ of the record while leaving the original intact.
+ """
+ # The format operation gets traceback text into record.exc_text
+ # (if there's exception data), and also returns the formatted
+ # message. We can then use this to replace the original
+ # msg + args, as these might be unpickleable. We also zap the
+ # exc_info and exc_text attributes, as they are no longer
+ # needed and, if not None, will typically not be pickleable.
+ msg = self.format(record)
+ record.message = msg
+ record.msg = msg
+ record.args = None
+ record.exc_info = None
+ record.exc_text = None
+ return record
+
+ def emit(self, record):
+ """
+ Emit a record.
+
+ Writes the LogRecord to the queue, preparing it for pickling first.
+ """
+ try:
+ self.enqueue(self.prepare(record))
+ except Exception:
+ self.handleError(record)
+class BlockQueueHandler(QueueHandler):
+ def enqueue(self, record):
+ self.queue.put(record,True)
+## Log level constants
+DEBUG_0 = 1
+DEBUG_1 = 2
+DEBUG_2 = 3
+DEBUG_3 = 4
+DEBUG_4 = 5
+DEBUG_5 = 6
+DEBUG_6 = 7
+DEBUG_7 = 8
+DEBUG_8 = 9
+DEBUG_9 = 10
+VERBOSE = 15
+INFO = 20
+WARN = 30
+QUIET = 40
+ERROR = 50
+SILENT = 99
+
+IsRaiseError = True
+
+# Tool name
+_ToolName = os.path.basename(sys.argv[0])
+
+# For validation purpose
+_LogLevels = [DEBUG_0, DEBUG_1, DEBUG_2, DEBUG_3, DEBUG_4, DEBUG_5,
+ DEBUG_6, DEBUG_7, DEBUG_8, DEBUG_9, VERBOSE, WARN, INFO,
+ ERROR, QUIET, SILENT]
+
+# For DEBUG level (All DEBUG_0~9 are applicable)
+_DebugLogger = logging.getLogger("tool_debug")
+_DebugFormatter = logging.Formatter("[%(asctime)s.%(msecs)d]: %(message)s", datefmt="%H:%M:%S")
+
+# For VERBOSE, INFO, WARN level
+_InfoLogger = logging.getLogger("tool_info")
+_InfoFormatter = logging.Formatter("%(message)s")
+
+# For ERROR level
+_ErrorLogger = logging.getLogger("tool_error")
+_ErrorFormatter = logging.Formatter("%(message)s")
+
+# String templates for ERROR/WARN/DEBUG log message
+_ErrorMessageTemplate = '\n\n%(tool)s...\n%(file)s(%(line)s): error %(errorcode)04X: %(msg)s\n\t%(extra)s'
+_ErrorMessageTemplateWithoutFile = '\n\n%(tool)s...\n : error %(errorcode)04X: %(msg)s\n\t%(extra)s'
+_WarningMessageTemplate = '%(tool)s...\n%(file)s(%(line)s): warning: %(msg)s'
+_WarningMessageTemplateWithoutFile = '%(tool)s: : warning: %(msg)s'
+_DebugMessageTemplate = '%(file)s(%(line)s): debug: \n %(msg)s'
+
+#
+# Flag used to take WARN as ERROR.
+# By default, only ERROR message will break the tools execution.
+#
+_WarningAsError = False
+
+## Log debug message
+#
+# @param Level DEBUG level (DEBUG0~9)
+# @param Message Debug information
+# @param ExtraData More information associated with "Message"
+#
+def debug(Level, Message, ExtraData=None):
+ if _DebugLogger.level > Level:
+ return
+ if Level > DEBUG_9:
+ return
+
+ # Find out the caller method information
+ CallerStack = traceback.extract_stack()[-2]
+ TemplateDict = {
+ "file" : CallerStack[0],
+ "line" : CallerStack[1],
+ "msg" : Message,
+ }
+
+ if ExtraData is not None:
+ LogText = _DebugMessageTemplate % TemplateDict + "\n %s" % ExtraData
+ else:
+ LogText = _DebugMessageTemplate % TemplateDict
+
+ _DebugLogger.log(Level, LogText)
+
+## Log verbose message
+#
+# @param Message Verbose information
+#
+def verbose(Message):
+ return _InfoLogger.log(VERBOSE, Message)
+
+## Log warning message
+#
+# Warning messages are those which might be wrong but won't fail the tool.
+#
+# @param ToolName The name of the tool. If not given, the name of caller
+# method will be used.
+# @param Message Warning information
+# @param File The name of file which caused the warning.
+# @param Line The line number in the "File" which caused the warning.
+# @param ExtraData More information associated with "Message"
+#
+def warn(ToolName, Message, File=None, Line=None, ExtraData=None):
+ if _InfoLogger.level > WARN:
+ return
+
+ # if no tool name given, use caller's source file name as tool name
+ if ToolName is None or ToolName == "":
+ ToolName = os.path.basename(traceback.extract_stack()[-2][0])
+
+ if Line is None:
+ Line = "..."
+ else:
+ Line = "%d" % Line
+
+ TemplateDict = {
+ "tool" : ToolName,
+ "file" : File,
+ "line" : Line,
+ "msg" : Message,
+ }
+
+ if File is not None:
+ LogText = _WarningMessageTemplate % TemplateDict
+ else:
+ LogText = _WarningMessageTemplateWithoutFile % TemplateDict
+
+ if ExtraData is not None:
+ LogText += "\n %s" % ExtraData
+
+ _InfoLogger.log(WARN, LogText)
+
+ # Raise an exception if indicated
+ if _WarningAsError == True:
+ raise FatalError(WARNING_AS_ERROR)
+
+## Log INFO message
+info = _InfoLogger.info
+
+## Log ERROR message
+#
+# Once an error messages is logged, the tool's execution will be broken by raising
+# an exception. If you don't want to break the execution later, you can give
+# "RaiseError" with "False" value.
+#
+# @param ToolName The name of the tool. If not given, the name of caller
+# method will be used.
+# @param ErrorCode The error code
+# @param Message Warning information
+# @param File The name of file which caused the error.
+# @param Line The line number in the "File" which caused the warning.
+# @param ExtraData More information associated with "Message"
+# @param RaiseError Raise an exception to break the tool's execution if
+# it's True. This is the default behavior.
+#
+def error(ToolName, ErrorCode, Message=None, File=None, Line=None, ExtraData=None, RaiseError=IsRaiseError):
+ if Line is None:
+ Line = "..."
+ else:
+ Line = "%d" % Line
+
+ if Message is None:
+ if ErrorCode in gErrorMessage:
+ Message = gErrorMessage[ErrorCode]
+ else:
+ Message = gErrorMessage[UNKNOWN_ERROR]
+
+ if ExtraData is None:
+ ExtraData = ""
+
+ TemplateDict = {
+ "tool" : _ToolName,
+ "file" : File,
+ "line" : Line,
+ "errorcode" : ErrorCode,
+ "msg" : Message,
+ "extra" : ExtraData
+ }
+
+ if File is not None:
+ LogText = _ErrorMessageTemplate % TemplateDict
+ else:
+ LogText = _ErrorMessageTemplateWithoutFile % TemplateDict
+
+ # VBox - begin
+ LogText += '\n' + getSimpleStack(3);
+ # VBox - endi
+
+ _ErrorLogger.log(ERROR, LogText)
+
+ if RaiseError and IsRaiseError:
+ raise FatalError(ErrorCode)
+
+# Log information which should be always put out
+quiet = _ErrorLogger.error
+
+# VBox - begin
+
+## Get caller info
+# @return String with caller name, file and line number.
+# @param iFrame The frame number of the caller to get.
+def getCallerName(oFrame = None, iFrame = 2):
+ if oFrame is None:
+ try:
+ raise Exception();
+ except:
+ oFrame = sys.exc_info()[2].tb_frame.f_back;
+ while iFrame > 1:
+ if oFrame is not None:
+ oFrame = oFrame.f_back;
+ iFrame = iFrame - 1;
+ if oFrame is not None:
+ return '%s %s:%u' % (oFrame.f_code.co_name, oFrame.f_code.co_filename, oFrame.f_lineno);
+ return None;
+
+## @Get a simple stack trace.
+# @return simple stack trace (string).
+# @param iFrame The frame to start with.
+# @param cMaxFrames The maximum number of frames to dump.
+def getSimpleStack(iFrame = 2, cMaxFrames = 7):
+ sStack = 'Stack:\n'
+ for i in range(cMaxFrames):
+ sCaller = getCallerName(iFrame = iFrame + i);
+ if sCaller is None:
+ break;
+ sStack += '[%u] %s\n' % (i + 1, sCaller);
+ return sStack;
+
+# VBox - end
+
+## Initialize log system
+def LogClientInitialize(log_q):
+ #
+ # Since we use different format to log different levels of message into different
+ # place (stdout or stderr), we have to use different "Logger" objects to do this.
+ #
+ # For DEBUG level (All DEBUG_0~9 are applicable)
+ _DebugLogger.setLevel(INFO)
+ _DebugChannel = BlockQueueHandler(log_q)
+ _DebugChannel.setFormatter(_DebugFormatter)
+ _DebugLogger.addHandler(_DebugChannel)
+
+ # For VERBOSE, INFO, WARN level
+ _InfoLogger.setLevel(INFO)
+ _InfoChannel = BlockQueueHandler(log_q)
+ _InfoChannel.setFormatter(_InfoFormatter)
+ _InfoLogger.addHandler(_InfoChannel)
+
+ # For ERROR level
+ _ErrorLogger.setLevel(INFO)
+ _ErrorCh = BlockQueueHandler(log_q)
+ _ErrorCh.setFormatter(_ErrorFormatter)
+ _ErrorLogger.addHandler(_ErrorCh)
+
+## Set log level
+#
+# @param Level One of log level in _LogLevel
+def SetLevel(Level):
+ if Level not in _LogLevels:
+ info("Not supported log level (%d). Use default level instead." % Level)
+ Level = INFO
+ _DebugLogger.setLevel(Level)
+ _InfoLogger.setLevel(Level)
+ _ErrorLogger.setLevel(Level)
+
+## Initialize log system
+def Initialize():
+ #
+ # Since we use different format to log different levels of message into different
+ # place (stdout or stderr), we have to use different "Logger" objects to do this.
+ #
+ # For DEBUG level (All DEBUG_0~9 are applicable)
+ _DebugLogger.setLevel(INFO)
+ _DebugChannel = logging.StreamHandler(sys.stdout)
+ _DebugChannel.setFormatter(_DebugFormatter)
+ _DebugLogger.addHandler(_DebugChannel)
+
+ # For VERBOSE, INFO, WARN level
+ _InfoLogger.setLevel(INFO)
+ _InfoChannel = logging.StreamHandler(sys.stdout)
+ _InfoChannel.setFormatter(_InfoFormatter)
+ _InfoLogger.addHandler(_InfoChannel)
+
+ # For ERROR level
+ _ErrorLogger.setLevel(INFO)
+ _ErrorCh = logging.StreamHandler(sys.stderr)
+ _ErrorCh.setFormatter(_ErrorFormatter)
+ _ErrorLogger.addHandler(_ErrorCh)
+
+def InitializeForUnitTest():
+ Initialize()
+ SetLevel(SILENT)
+
+## Get current log level
+def GetLevel():
+ return _InfoLogger.getEffectiveLevel()
+
+## Raise up warning as error
+def SetWarningAsError():
+ global _WarningAsError
+ _WarningAsError = True
+
+## Specify a file to store the log message as well as put on console
+#
+# @param LogFile The file path used to store the log message
+#
+def SetLogFile(LogFile):
+ if os.path.exists(LogFile):
+ os.remove(LogFile)
+
+ _Ch = logging.FileHandler(LogFile)
+ _Ch.setFormatter(_DebugFormatter)
+ _DebugLogger.addHandler(_Ch)
+
+ _Ch= logging.FileHandler(LogFile)
+ _Ch.setFormatter(_InfoFormatter)
+ _InfoLogger.addHandler(_Ch)
+
+ _Ch = logging.FileHandler(LogFile)
+ _Ch.setFormatter(_ErrorFormatter)
+ _ErrorLogger.addHandler(_Ch)
+
+if __name__ == '__main__':
+ pass
+
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Expression.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Expression.py
new file mode 100755
index 00000000..e6228862
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Expression.py
@@ -0,0 +1,1054 @@
+## @file
+# This file is used to parse and evaluate expression in directive or PCD value.
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+
+## Import Modules
+#
+from __future__ import print_function
+from __future__ import absolute_import
+from Common.GlobalData import *
+from CommonDataClass.Exceptions import BadExpression
+from CommonDataClass.Exceptions import WrnExpression
+from .Misc import GuidStringToGuidStructureString, ParseFieldValue,CopyDict
+import Common.EdkLogger as EdkLogger
+import copy
+from Common.DataType import *
+import sys
+from random import sample
+import string
+
+ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'
+ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'
+ERR_MATCH = 'No matching right parenthesis.'
+ERR_STRING_TOKEN = 'Bad string token: [%s].'
+ERR_MACRO_TOKEN = 'Bad macro token: [%s].'
+ERR_EMPTY_TOKEN = 'Empty token is not allowed.'
+ERR_PCD_RESOLVE = 'The PCD should be FeatureFlag type or FixedAtBuild type: [%s].'
+ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'
+ERR_EXPR_TYPE = 'Different types found in expression.'
+ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'
+ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'
+WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'
+WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'
+WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
+ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
+ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'
+ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'
+ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'
+ERR_EMPTY_EXPR = 'Empty expression is not allowed.'
+ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
+
+__ValidString = re.compile(r'[_a-zA-Z][_0-9a-zA-Z]*$')
+_ReLabel = re.compile('LABEL\((\w+)\)')
+_ReOffset = re.compile('OFFSET_OF\((\w+)\)')
+PcdPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*\.[_a-zA-Z][0-9A-Za-z_]*$')
+
+## SplitString
+# Split string to list according double quote
+# For example: abc"de\"f"ghi"jkl"mn will be: ['abc', '"de\"f"', 'ghi', '"jkl"', 'mn']
+#
+def SplitString(String):
+ # There might be escaped quote: "abc\"def\\\"ghi", 'abc\'def\\\'ghi'
+ RanStr = ''.join(sample(string.ascii_letters + string.digits, 8))
+ String = String.replace('\\\\', RanStr).strip()
+ RetList = []
+ InSingleQuote = False
+ InDoubleQuote = False
+ Item = ''
+ for i, ch in enumerate(String):
+ if ch == '"' and not InSingleQuote:
+ if String[i - 1] != '\\':
+ InDoubleQuote = not InDoubleQuote
+ if not InDoubleQuote:
+ Item += String[i]
+ RetList.append(Item)
+ Item = ''
+ continue
+ if Item:
+ RetList.append(Item)
+ Item = ''
+ elif ch == "'" and not InDoubleQuote:
+ if String[i - 1] != '\\':
+ InSingleQuote = not InSingleQuote
+ if not InSingleQuote:
+ Item += String[i]
+ RetList.append(Item)
+ Item = ''
+ continue
+ if Item:
+ RetList.append(Item)
+ Item = ''
+ Item += String[i]
+ if InSingleQuote or InDoubleQuote:
+ raise BadExpression(ERR_STRING_TOKEN % Item)
+ if Item:
+ RetList.append(Item)
+ for i, ch in enumerate(RetList):
+ if RanStr in ch:
+ RetList[i] = ch.replace(RanStr,'\\\\')
+ return RetList
+
+def SplitPcdValueString(String):
+ # There might be escaped comma in GUID() or DEVICE_PATH() or " "
+ # or ' ' or L' ' or L" "
+ RanStr = ''.join(sample(string.ascii_letters + string.digits, 8))
+ String = String.replace('\\\\', RanStr).strip()
+ RetList = []
+ InParenthesis = 0
+ InSingleQuote = False
+ InDoubleQuote = False
+ Item = ''
+ for i, ch in enumerate(String):
+ if ch == '(':
+ InParenthesis += 1
+ elif ch == ')':
+ if InParenthesis:
+ InParenthesis -= 1
+ else:
+ raise BadExpression(ERR_STRING_TOKEN % Item)
+ elif ch == '"' and not InSingleQuote:
+ if String[i-1] != '\\':
+ InDoubleQuote = not InDoubleQuote
+ elif ch == "'" and not InDoubleQuote:
+ if String[i-1] != '\\':
+ InSingleQuote = not InSingleQuote
+ elif ch == ',':
+ if InParenthesis or InSingleQuote or InDoubleQuote:
+ Item += String[i]
+ continue
+ elif Item:
+ RetList.append(Item)
+ Item = ''
+ continue
+ Item += String[i]
+ if InSingleQuote or InDoubleQuote or InParenthesis:
+ raise BadExpression(ERR_STRING_TOKEN % Item)
+ if Item:
+ RetList.append(Item)
+ for i, ch in enumerate(RetList):
+ if RanStr in ch:
+ RetList[i] = ch.replace(RanStr,'\\\\')
+ return RetList
+
+def IsValidCName(Str):
+ return True if __ValidString.match(Str) else False
+
+def BuildOptionValue(PcdValue, GuidDict):
+ if PcdValue.startswith('H'):
+ InputValue = PcdValue[1:]
+ elif PcdValue.startswith("L'") or PcdValue.startswith("'"):
+ InputValue = PcdValue
+ elif PcdValue.startswith('L'):
+ InputValue = 'L"' + PcdValue[1:] + '"'
+ else:
+ InputValue = PcdValue
+ try:
+ PcdValue = ValueExpressionEx(InputValue, TAB_VOID, GuidDict)(True)
+ except:
+ pass
+
+ return PcdValue
+
+## ReplaceExprMacro
+#
+def ReplaceExprMacro(String, Macros, ExceptionList = None):
+ StrList = SplitString(String)
+ for i, String in enumerate(StrList):
+ InQuote = False
+ if String.startswith('"'):
+ InQuote = True
+ MacroStartPos = String.find('$(')
+ if MacroStartPos < 0:
+ for Pcd in gPlatformPcds:
+ if Pcd in String:
+ if Pcd not in gConditionalPcds:
+ gConditionalPcds.append(Pcd)
+ continue
+ RetStr = ''
+ while MacroStartPos >= 0:
+ RetStr = String[0:MacroStartPos]
+ MacroEndPos = String.find(')', MacroStartPos)
+ if MacroEndPos < 0:
+ raise BadExpression(ERR_MACRO_TOKEN % String[MacroStartPos:])
+ Macro = String[MacroStartPos+2:MacroEndPos]
+ if Macro not in Macros:
+ # From C reference manual:
+ # If an undefined macro name appears in the constant-expression of
+ # !if or !elif, it is replaced by the integer constant 0.
+ RetStr += '0'
+ elif not InQuote:
+ Tklst = RetStr.split()
+ if Tklst and Tklst[-1] in {'IN', 'in'} and ExceptionList and Macro not in ExceptionList:
+ raise BadExpression(ERR_IN_OPERAND)
+ # Make sure the macro in exception list is encapsulated by double quote
+ # For example: DEFINE ARCH = IA32 X64
+ # $(ARCH) is replaced with "IA32 X64"
+ if ExceptionList and Macro in ExceptionList:
+ RetStr += '"' + Macros[Macro] + '"'
+ elif Macros[Macro].strip():
+ RetStr += Macros[Macro]
+ else:
+ RetStr += '""'
+ else:
+ RetStr += Macros[Macro]
+ RetStr += String[MacroEndPos+1:]
+ String = RetStr
+ MacroStartPos = String.find('$(')
+ StrList[i] = RetStr
+ return ''.join(StrList)
+
+# transfer int to string for in/not in expression
+def IntToStr(Value):
+ StrList = []
+ while Value > 0:
+ StrList.append(chr(Value & 0xff))
+ Value = Value >> 8
+ Value = '"' + ''.join(StrList) + '"'
+ return Value
+
+SupportedInMacroList = ['TARGET', 'TOOL_CHAIN_TAG', 'ARCH', 'FAMILY']
+
+class BaseExpression(object):
+ def __init__(self, *args, **kwargs):
+ super(BaseExpression, self).__init__()
+
+ # Check if current token matches the operators given from parameter
+ def _IsOperator(self, OpSet):
+ Idx = self._Idx
+ self._GetOperator()
+ if self._Token in OpSet:
+ if self._Token in self.LogicalOperators:
+ self._Token = self.LogicalOperators[self._Token]
+ return True
+ self._Idx = Idx
+ return False
+
+class ValueExpression(BaseExpression):
+ # Logical operator mapping
+ LogicalOperators = {
+ '&&' : 'and', '||' : 'or',
+ '!' : 'not', 'AND': 'and',
+ 'OR' : 'or' , 'NOT': 'not',
+ 'XOR': '^' , 'xor': '^',
+ 'EQ' : '==' , 'NE' : '!=',
+ 'GT' : '>' , 'LT' : '<',
+ 'GE' : '>=' , 'LE' : '<=',
+ 'IN' : 'in'
+ }
+
+ NonLetterOpLst = ['+', '-', TAB_STAR, '/', '%', '&', '|', '^', '~', '<<', '>>', '!', '=', '>', '<', '?', ':']
+
+
+ SymbolPattern = re.compile("("
+ "\$\([A-Z][A-Z0-9_]*\)|\$\(\w+\.\w+\)|\w+\.\w+|"
+ "&&|\|\||!(?!=)|"
+ "(?<=\W)AND(?=\W)|(?<=\W)OR(?=\W)|(?<=\W)NOT(?=\W)|(?<=\W)XOR(?=\W)|"
+ "(?<=\W)EQ(?=\W)|(?<=\W)NE(?=\W)|(?<=\W)GT(?=\W)|(?<=\W)LT(?=\W)|(?<=\W)GE(?=\W)|(?<=\W)LE(?=\W)"
+ ")")
+
+ @staticmethod
+ def Eval(Operator, Oprand1, Oprand2 = None):
+ WrnExp = None
+
+ if Operator not in {"==", "!=", ">=", "<=", ">", "<", "in", "not in"} and \
+ (isinstance(Oprand1, type('')) or isinstance(Oprand2, type(''))):
+ raise BadExpression(ERR_STRING_EXPR % Operator)
+ if Operator in {'in', 'not in'}:
+ if not isinstance(Oprand1, type('')):
+ Oprand1 = IntToStr(Oprand1)
+ if not isinstance(Oprand2, type('')):
+ Oprand2 = IntToStr(Oprand2)
+ TypeDict = {
+ type(0) : 0,
+ # For python2 long type
+ type(sys.maxsize + 1) : 0,
+ type('') : 1,
+ type(True) : 2
+ }
+
+ EvalStr = ''
+ if Operator in {"!", "NOT", "not"}:
+ if isinstance(Oprand1, type('')):
+ raise BadExpression(ERR_STRING_EXPR % Operator)
+ EvalStr = 'not Oprand1'
+ elif Operator in {"~"}:
+ if isinstance(Oprand1, type('')):
+ raise BadExpression(ERR_STRING_EXPR % Operator)
+ EvalStr = '~ Oprand1'
+ else:
+ if Operator in {"+", "-"} and (type(True) in {type(Oprand1), type(Oprand2)}):
+ # Boolean in '+'/'-' will be evaluated but raise warning
+ WrnExp = WrnExpression(WRN_BOOL_EXPR)
+ elif type('') in {type(Oprand1), type(Oprand2)} and not isinstance(Oprand1, type(Oprand2)):
+ # == between string and number/boolean will always return False, != return True
+ if Operator == "==":
+ WrnExp = WrnExpression(WRN_EQCMP_STR_OTHERS)
+ WrnExp.result = False
+ raise WrnExp
+ elif Operator == "!=":
+ WrnExp = WrnExpression(WRN_NECMP_STR_OTHERS)
+ WrnExp.result = True
+ raise WrnExp
+ else:
+ raise BadExpression(ERR_RELCMP_STR_OTHERS % Operator)
+ elif TypeDict[type(Oprand1)] != TypeDict[type(Oprand2)]:
+ if Operator in {"==", "!=", ">=", "<=", ">", "<"} and set((TypeDict[type(Oprand1)], TypeDict[type(Oprand2)])) == set((TypeDict[type(True)], TypeDict[type(0)])):
+ # comparison between number and boolean is allowed
+ pass
+ elif Operator in {'&', '|', '^', "and", "or"} and set((TypeDict[type(Oprand1)], TypeDict[type(Oprand2)])) == set((TypeDict[type(True)], TypeDict[type(0)])):
+ # bitwise and logical operation between number and boolean is allowed
+ pass
+ else:
+ raise BadExpression(ERR_EXPR_TYPE)
+ if isinstance(Oprand1, type('')) and isinstance(Oprand2, type('')):
+ if ((Oprand1.startswith('L"') or Oprand1.startswith("L'")) and (not Oprand2.startswith('L"')) and (not Oprand2.startswith("L'"))) or \
+ (((not Oprand1.startswith('L"')) and (not Oprand1.startswith("L'"))) and (Oprand2.startswith('L"') or Oprand2.startswith("L'"))):
+ raise BadExpression(ERR_STRING_CMP % (Oprand1, Operator, Oprand2))
+ if 'in' in Operator and isinstance(Oprand2, type('')):
+ Oprand2 = Oprand2.split()
+ EvalStr = 'Oprand1 ' + Operator + ' Oprand2'
+
+ # Local symbols used by built in eval function
+ Dict = {
+ 'Oprand1' : Oprand1,
+ 'Oprand2' : Oprand2
+ }
+ try:
+ Val = eval(EvalStr, {}, Dict)
+ except Exception as Excpt:
+ raise BadExpression(str(Excpt))
+
+ if Operator in {'and', 'or'}:
+ if Val:
+ Val = True
+ else:
+ Val = False
+
+ if WrnExp:
+ WrnExp.result = Val
+ raise WrnExp
+ return Val
+
+ def __init__(self, Expression, SymbolTable={}):
+ super(ValueExpression, self).__init__(self, Expression, SymbolTable)
+ self._NoProcess = False
+ if not isinstance(Expression, type('')):
+ self._Expr = Expression
+ self._NoProcess = True
+ return
+
+ self._Expr = ReplaceExprMacro(Expression.strip(),
+ SymbolTable,
+ SupportedInMacroList)
+
+ if not self._Expr.strip():
+ raise BadExpression(ERR_EMPTY_EXPR)
+
+ #
+ # The symbol table including PCD and macro mapping
+ #
+ self._Symb = CopyDict(SymbolTable)
+ self._Symb.update(self.LogicalOperators)
+ self._Idx = 0
+ self._Len = len(self._Expr)
+ self._Token = ''
+ self._WarnExcept = None
+
+ # Literal token without any conversion
+ self._LiteralToken = ''
+
+ # Public entry for this class
+ # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
+ # True : return the evaluated str(value), used for PCD value
+ #
+ # @return: True or False if RealValue is False
+ # Evaluated value of string format if RealValue is True
+ #
+ def __call__(self, RealValue=False, Depth=0):
+ if self._NoProcess:
+ return self._Expr
+
+ self._Depth = Depth
+
+ self._Expr = self._Expr.strip()
+ if RealValue and Depth == 0:
+ self._Token = self._Expr
+ if self.__IsNumberToken():
+ return self._Expr
+ Token = ''
+ try:
+ Token = self._GetToken()
+ except BadExpression:
+ pass
+ if isinstance(Token, type('')) and Token.startswith('{') and Token.endswith('}') and self._Idx >= self._Len:
+ return self._Expr
+
+ self._Idx = 0
+ self._Token = ''
+
+ Val = self._ConExpr()
+ RealVal = Val
+ if isinstance(Val, type('')):
+ if Val == 'L""':
+ Val = False
+ elif not Val:
+ Val = False
+ RealVal = '""'
+ elif not Val.startswith('L"') and not Val.startswith('{') and not Val.startswith("L'") and not Val.startswith("'"):
+ Val = True
+ RealVal = '"' + RealVal + '"'
+
+ # The expression has been parsed, but the end of expression is not reached
+ # It means the rest does not comply EBNF of <Expression>
+ if self._Idx != self._Len:
+ raise BadExpression(ERR_SNYTAX % self._Expr[self._Idx:])
+
+ if RealValue:
+ RetVal = str(RealVal)
+ elif Val:
+ RetVal = True
+ else:
+ RetVal = False
+
+ if self._WarnExcept:
+ self._WarnExcept.result = RetVal
+ raise self._WarnExcept
+ else:
+ return RetVal
+
+ # Template function to parse binary operators which have same precedence
+ # Expr [Operator Expr]*
+ def _ExprFuncTemplate(self, EvalFunc, OpSet):
+ Val = EvalFunc()
+ while self._IsOperator(OpSet):
+ Op = self._Token
+ if Op == '?':
+ Val2 = EvalFunc()
+ if self._IsOperator({':'}):
+ Val3 = EvalFunc()
+ if Val:
+ Val = Val2
+ else:
+ Val = Val3
+ continue
+ #
+ # PEP 238 -- Changing the Division Operator
+ # x/y to return a reasonable approximation of the mathematical result of the division ("true division")
+ # x//y to return the floor ("floor division")
+ #
+ if Op == '/':
+ Op = '//'
+ try:
+ Val = self.Eval(Op, Val, EvalFunc())
+ except WrnExpression as Warn:
+ self._WarnExcept = Warn
+ Val = Warn.result
+ return Val
+ # A [? B]*
+ def _ConExpr(self):
+ return self._ExprFuncTemplate(self._OrExpr, {'?', ':'})
+
+ # A [|| B]*
+ def _OrExpr(self):
+ return self._ExprFuncTemplate(self._AndExpr, {"OR", "or", "||"})
+
+ # A [&& B]*
+ def _AndExpr(self):
+ return self._ExprFuncTemplate(self._BitOr, {"AND", "and", "&&"})
+
+ # A [ | B]*
+ def _BitOr(self):
+ return self._ExprFuncTemplate(self._BitXor, {"|"})
+
+ # A [ ^ B]*
+ def _BitXor(self):
+ return self._ExprFuncTemplate(self._BitAnd, {"XOR", "xor", "^"})
+
+ # A [ & B]*
+ def _BitAnd(self):
+ return self._ExprFuncTemplate(self._EqExpr, {"&"})
+
+ # A [ == B]*
+ def _EqExpr(self):
+ Val = self._RelExpr()
+ while self._IsOperator({"==", "!=", "EQ", "NE", "IN", "in", "!", "NOT", "not"}):
+ Op = self._Token
+ if Op in {"!", "NOT", "not"}:
+ if not self._IsOperator({"IN", "in"}):
+ raise BadExpression(ERR_REL_NOT_IN)
+ Op += ' ' + self._Token
+ try:
+ Val = self.Eval(Op, Val, self._RelExpr())
+ except WrnExpression as Warn:
+ self._WarnExcept = Warn
+ Val = Warn.result
+ return Val
+
+ # A [ > B]*
+ def _RelExpr(self):
+ return self._ExprFuncTemplate(self._ShiftExpr, {"<=", ">=", "<", ">", "LE", "GE", "LT", "GT"})
+
+ def _ShiftExpr(self):
+ return self._ExprFuncTemplate(self._AddExpr, {"<<", ">>"})
+
+ # A [ + B]*
+ def _AddExpr(self):
+ return self._ExprFuncTemplate(self._MulExpr, {"+", "-"})
+
+ # A [ * B]*
+ def _MulExpr(self):
+ return self._ExprFuncTemplate(self._UnaryExpr, {TAB_STAR, "/", "%"})
+
+ # [!]*A
+ def _UnaryExpr(self):
+ if self._IsOperator({"!", "NOT", "not"}):
+ Val = self._UnaryExpr()
+ try:
+ return self.Eval('not', Val)
+ except WrnExpression as Warn:
+ self._WarnExcept = Warn
+ return Warn.result
+ if self._IsOperator({"~"}):
+ Val = self._UnaryExpr()
+ try:
+ return self.Eval('~', Val)
+ except WrnExpression as Warn:
+ self._WarnExcept = Warn
+ return Warn.result
+ return self._IdenExpr()
+
+ # Parse identifier or encapsulated expression
+ def _IdenExpr(self):
+ Tk = self._GetToken()
+ if Tk == '(':
+ Val = self._ConExpr()
+ try:
+ # _GetToken may also raise BadExpression
+ if self._GetToken() != ')':
+ raise BadExpression(ERR_MATCH)
+ except BadExpression:
+ raise BadExpression(ERR_MATCH)
+ return Val
+ return Tk
+
+ # Skip whitespace or tab
+ def __SkipWS(self):
+ for Char in self._Expr[self._Idx:]:
+ if Char not in ' \t':
+ break
+ self._Idx += 1
+
+ # Try to convert string to number
+ def __IsNumberToken(self):
+ Radix = 10
+ if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:
+ Radix = 16
+ if self._Token.startswith('"') or self._Token.startswith('L"'):
+ Flag = 0
+ for Index in range(len(self._Token)):
+ if self._Token[Index] in {'"'}:
+ if self._Token[Index - 1] == '\\':
+ continue
+ Flag += 1
+ if Flag == 2 and self._Token.endswith('"'):
+ return True
+ if self._Token.startswith("'") or self._Token.startswith("L'"):
+ Flag = 0
+ for Index in range(len(self._Token)):
+ if self._Token[Index] in {"'"}:
+ if self._Token[Index - 1] == '\\':
+ continue
+ Flag += 1
+ if Flag == 2 and self._Token.endswith("'"):
+ return True
+ try:
+ self._Token = int(self._Token, Radix)
+ return True
+ except ValueError:
+ return False
+ except TypeError:
+ return False
+
+ # Parse array: {...}
+ def __GetArray(self):
+ Token = '{'
+ self._Idx += 1
+ self.__GetNList(True)
+ Token += self._LiteralToken
+ if self._Idx >= self._Len or self._Expr[self._Idx] != '}':
+ raise BadExpression(ERR_ARRAY_TOKEN % Token)
+ Token += '}'
+
+ # All whitespace and tabs in array are already stripped.
+ IsArray = IsGuid = False
+ if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \
+ and len(Token.split('},')) == 1:
+ HexLen = [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]
+ HexList= Token.split(',')
+ if HexList[3].startswith('{') and \
+ not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:
+ IsGuid = True
+ if Token.lstrip('{').rstrip('}').find('{') == -1:
+ if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:
+ IsArray = True
+ if not IsArray and not IsGuid:
+ raise BadExpression(ERR_ARRAY_TOKEN % Token)
+ self._Idx += 1
+ self._Token = self._LiteralToken = Token
+ return self._Token
+
+ # Parse string, the format must be: "..."
+ def __GetString(self):
+ Idx = self._Idx
+
+ # Skip left quote
+ self._Idx += 1
+
+ # Replace escape \\\", \"
+ if self._Expr[Idx] == '"':
+ Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')
+ for Ch in Expr:
+ self._Idx += 1
+ if Ch == '"':
+ break
+ self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]
+ if not self._Token.endswith('"'):
+ raise BadExpression(ERR_STRING_TOKEN % self._Token)
+ #Replace escape \\\', \'
+ elif self._Expr[Idx] == "'":
+ Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace("\\\'", "\\\"")
+ for Ch in Expr:
+ self._Idx += 1
+ if Ch == "'":
+ break
+ self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]
+ if not self._Token.endswith("'"):
+ raise BadExpression(ERR_STRING_TOKEN % self._Token)
+ self._Token = self._Token[1:-1]
+ return self._Token
+
+ # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
+ # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
+ def __GetIdToken(self, IsAlphaOp = False):
+ IdToken = ''
+ for Ch in self._Expr[self._Idx:]:
+ if not self.__IsIdChar(Ch) or ('?' in self._Expr and Ch == ':'):
+ break
+ self._Idx += 1
+ IdToken += Ch
+
+ self._Token = self._LiteralToken = IdToken
+ if not IsAlphaOp:
+ self.__ResolveToken()
+ return self._Token
+
+ # Try to resolve token
+ def __ResolveToken(self):
+ if not self._Token:
+ raise BadExpression(ERR_EMPTY_TOKEN)
+
+ # PCD token
+ if PcdPattern.match(self._Token):
+ if self._Token not in self._Symb:
+ Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)
+ Ex.Pcd = self._Token
+ raise Ex
+ self._Token = ValueExpression(self._Symb[self._Token], self._Symb)(True, self._Depth+1)
+ if not isinstance(self._Token, type('')):
+ self._LiteralToken = hex(self._Token)
+ return
+
+ if self._Token.startswith('"'):
+ self._Token = self._Token[1:-1]
+ elif self._Token in {"FALSE", "false", "False"}:
+ self._Token = False
+ elif self._Token in {"TRUE", "true", "True"}:
+ self._Token = True
+ else:
+ self.__IsNumberToken()
+
+ def __GetNList(self, InArray=False):
+ self._GetSingleToken()
+ if not self.__IsHexLiteral():
+ if InArray:
+ raise BadExpression(ERR_ARRAY_ELE % self._Token)
+ return self._Token
+
+ self.__SkipWS()
+ Expr = self._Expr[self._Idx:]
+ if not Expr.startswith(','):
+ return self._Token
+
+ NList = self._LiteralToken
+ while Expr.startswith(','):
+ NList += ','
+ self._Idx += 1
+ self.__SkipWS()
+ self._GetSingleToken()
+ if not self.__IsHexLiteral():
+ raise BadExpression(ERR_ARRAY_ELE % self._Token)
+ NList += self._LiteralToken
+ self.__SkipWS()
+ Expr = self._Expr[self._Idx:]
+ self._Token = self._LiteralToken = NList
+ return self._Token
+
+ def __IsHexLiteral(self):
+ if self._LiteralToken.startswith('{') and \
+ self._LiteralToken.endswith('}'):
+ return True
+
+ if gHexPattern.match(self._LiteralToken):
+ Token = self._LiteralToken[2:]
+ if not Token:
+ self._LiteralToken = '0x0'
+ else:
+ self._LiteralToken = '0x' + Token
+ return True
+ return False
+
+ def _GetToken(self):
+ return self.__GetNList()
+
+ @staticmethod
+ def __IsIdChar(Ch):
+ return Ch in '._:' or Ch.isalnum()
+
+ # Parse operand
+ def _GetSingleToken(self):
+ self.__SkipWS()
+ Expr = self._Expr[self._Idx:]
+ if Expr.startswith('L"'):
+ # Skip L
+ self._Idx += 1
+ UStr = self.__GetString()
+ self._Token = 'L"' + UStr + '"'
+ return self._Token
+ elif Expr.startswith("L'"):
+ # Skip L
+ self._Idx += 1
+ UStr = self.__GetString()
+ self._Token = "L'" + UStr + "'"
+ return self._Token
+ elif Expr.startswith("'"):
+ UStr = self.__GetString()
+ self._Token = "'" + UStr + "'"
+ return self._Token
+ elif Expr.startswith('UINT'):
+ Re = re.compile('(?:UINT8|UINT16|UINT32|UINT64)\((.+)\)')
+ try:
+ RetValue = Re.search(Expr).group(1)
+ except:
+ raise BadExpression('Invalid Expression %s' % Expr)
+ Idx = self._Idx
+ for Ch in Expr:
+ self._Idx += 1
+ if Ch == '(':
+ Prefix = self._Expr[Idx:self._Idx - 1]
+ Idx = self._Idx
+ if Ch == ')':
+ TmpValue = self._Expr[Idx :self._Idx - 1]
+ TmpValue = ValueExpression(TmpValue)(True)
+ TmpValue = '0x%x' % int(TmpValue) if not isinstance(TmpValue, type('')) else TmpValue
+ break
+ self._Token, Size = ParseFieldValue(Prefix + '(' + TmpValue + ')')
+ return self._Token
+
+ self._Token = ''
+ if Expr:
+ Ch = Expr[0]
+ Match = gGuidPattern.match(Expr)
+ if Match and not Expr[Match.end():Match.end()+1].isalnum() \
+ and Expr[Match.end():Match.end()+1] != '_':
+ self._Idx += Match.end()
+ self._Token = ValueExpression(GuidStringToGuidStructureString(Expr[0:Match.end()]))(True, self._Depth+1)
+ return self._Token
+ elif self.__IsIdChar(Ch):
+ return self.__GetIdToken()
+ elif Ch == '"':
+ return self.__GetString()
+ elif Ch == '{':
+ return self.__GetArray()
+ elif Ch == '(' or Ch == ')':
+ self._Idx += 1
+ self._Token = Ch
+ return self._Token
+
+ raise BadExpression(ERR_VALID_TOKEN % Expr)
+
+ # Parse operator
+ def _GetOperator(self):
+ self.__SkipWS()
+ LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst + ['?', ':']
+
+ self._Token = ''
+ Expr = self._Expr[self._Idx:]
+
+ # Reach end of expression
+ if not Expr:
+ return ''
+
+ # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
+ if Expr[0].isalpha():
+ return self.__GetIdToken(True)
+
+ # Start to get regular operator: +, -, <, > ...
+ if Expr[0] not in self.NonLetterOpLst:
+ return ''
+
+ OpToken = ''
+ for Ch in Expr:
+ if Ch in self.NonLetterOpLst:
+ if Ch in ['!', '~'] and OpToken:
+ break
+ self._Idx += 1
+ OpToken += Ch
+ else:
+ break
+
+ if OpToken not in LegalOpLst:
+ raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)
+ self._Token = OpToken
+ return OpToken
+
+class ValueExpressionEx(ValueExpression):
+ def __init__(self, PcdValue, PcdType, SymbolTable={}):
+ ValueExpression.__init__(self, PcdValue, SymbolTable)
+ self.PcdValue = PcdValue
+ self.PcdType = PcdType
+
+ def __call__(self, RealValue=False, Depth=0):
+ PcdValue = self.PcdValue
+ if "{CODE(" not in PcdValue:
+ try:
+ PcdValue = ValueExpression.__call__(self, RealValue, Depth)
+ if self.PcdType == TAB_VOID and (PcdValue.startswith("'") or PcdValue.startswith("L'")):
+ PcdValue, Size = ParseFieldValue(PcdValue)
+ PcdValueList = []
+ for I in range(Size):
+ PcdValueList.append('0x%02X'%(PcdValue & 0xff))
+ PcdValue = PcdValue >> 8
+ PcdValue = '{' + ','.join(PcdValueList) + '}'
+ elif self.PcdType in TAB_PCD_NUMERIC_TYPES and (PcdValue.startswith("'") or \
+ PcdValue.startswith('"') or PcdValue.startswith("L'") or PcdValue.startswith('L"') or PcdValue.startswith('{')):
+ raise BadExpression
+ except WrnExpression as Value:
+ PcdValue = Value.result
+ except BadExpression as Value:
+ if self.PcdType in TAB_PCD_NUMERIC_TYPES:
+ PcdValue = PcdValue.strip()
+ if PcdValue.startswith('{') and PcdValue.endswith('}'):
+ PcdValue = SplitPcdValueString(PcdValue[1:-1])
+ if isinstance(PcdValue, type([])):
+ TmpValue = 0
+ Size = 0
+ ValueType = ''
+ for Item in PcdValue:
+ Item = Item.strip()
+ if Item.startswith(TAB_UINT8):
+ ItemSize = 1
+ ValueType = TAB_UINT8
+ elif Item.startswith(TAB_UINT16):
+ ItemSize = 2
+ ValueType = TAB_UINT16
+ elif Item.startswith(TAB_UINT32):
+ ItemSize = 4
+ ValueType = TAB_UINT32
+ elif Item.startswith(TAB_UINT64):
+ ItemSize = 8
+ ValueType = TAB_UINT64
+ elif Item[0] in {'"', "'", 'L'}:
+ ItemSize = 0
+ ValueType = TAB_VOID
+ else:
+ ItemSize = 0
+ ValueType = TAB_UINT8
+ Item = ValueExpressionEx(Item, ValueType, self._Symb)(True)
+ if ItemSize == 0:
+ try:
+ tmpValue = int(Item, 0)
+ if tmpValue > 255:
+ raise BadExpression("Byte array number %s should less than 0xFF." % Item)
+ except BadExpression as Value:
+ raise BadExpression(Value)
+ except ValueError:
+ pass
+ ItemValue, ItemSize = ParseFieldValue(Item)
+ else:
+ ItemValue = ParseFieldValue(Item)[0]
+
+ if isinstance(ItemValue, type('')):
+ ItemValue = int(ItemValue, 0)
+
+ TmpValue = (ItemValue << (Size * 8)) | TmpValue
+ Size = Size + ItemSize
+ else:
+ try:
+ TmpValue, Size = ParseFieldValue(PcdValue)
+ except BadExpression as Value:
+ raise BadExpression("Type: %s, Value: %s, %s" % (self.PcdType, PcdValue, Value))
+ if isinstance(TmpValue, type('')):
+ try:
+ TmpValue = int(TmpValue)
+ except:
+ raise BadExpression(Value)
+ else:
+ PcdValue = '0x%0{}X'.format(Size) % (TmpValue)
+ if TmpValue < 0:
+ raise BadExpression('Type %s PCD Value is negative' % self.PcdType)
+ if self.PcdType == TAB_UINT8 and Size > 1:
+ raise BadExpression('Type %s PCD Value Size is Larger than 1 byte' % self.PcdType)
+ if self.PcdType == TAB_UINT16 and Size > 2:
+ raise BadExpression('Type %s PCD Value Size is Larger than 2 byte' % self.PcdType)
+ if self.PcdType == TAB_UINT32 and Size > 4:
+ raise BadExpression('Type %s PCD Value Size is Larger than 4 byte' % self.PcdType)
+ if self.PcdType == TAB_UINT64 and Size > 8:
+ raise BadExpression('Type %s PCD Value Size is Larger than 8 byte' % self.PcdType)
+ else:
+ try:
+ TmpValue = int(PcdValue)
+ TmpList = []
+ if TmpValue.bit_length() == 0:
+ PcdValue = '{0x00}'
+ else:
+ for I in range((TmpValue.bit_length() + 7) // 8):
+ TmpList.append('0x%02x' % ((TmpValue >> I * 8) & 0xff))
+ PcdValue = '{' + ', '.join(TmpList) + '}'
+ except:
+ if PcdValue.strip().startswith('{'):
+ PcdValueList = SplitPcdValueString(PcdValue.strip()[1:-1])
+ LabelDict = {}
+ NewPcdValueList = []
+ LabelOffset = 0
+ for Item in PcdValueList:
+ # compute byte offset of every LABEL
+ LabelList = _ReLabel.findall(Item)
+ Item = _ReLabel.sub('', Item)
+ Item = Item.strip()
+ if LabelList:
+ for Label in LabelList:
+ if not IsValidCName(Label):
+ raise BadExpression('%s is not a valid c variable name' % Label)
+ if Label not in LabelDict:
+ LabelDict[Label] = str(LabelOffset)
+ if Item.startswith(TAB_UINT8):
+ LabelOffset = LabelOffset + 1
+ elif Item.startswith(TAB_UINT16):
+ LabelOffset = LabelOffset + 2
+ elif Item.startswith(TAB_UINT32):
+ LabelOffset = LabelOffset + 4
+ elif Item.startswith(TAB_UINT64):
+ LabelOffset = LabelOffset + 8
+ else:
+ try:
+ ItemValue, ItemSize = ParseFieldValue(Item)
+ LabelOffset = LabelOffset + ItemSize
+ except:
+ LabelOffset = LabelOffset + 1
+
+ for Item in PcdValueList:
+ # for LABEL parse
+ Item = Item.strip()
+ try:
+ Item = _ReLabel.sub('', Item)
+ except:
+ pass
+ try:
+ OffsetList = _ReOffset.findall(Item)
+ except:
+ pass
+ # replace each offset, except errors
+ for Offset in OffsetList:
+ try:
+ Item = Item.replace('OFFSET_OF({})'.format(Offset), LabelDict[Offset])
+ except:
+ raise BadExpression('%s not defined' % Offset)
+
+ NewPcdValueList.append(Item)
+
+ AllPcdValueList = []
+ for Item in NewPcdValueList:
+ Size = 0
+ ValueStr = ''
+ TokenSpaceGuidName = ''
+ if Item.startswith(TAB_GUID) and Item.endswith(')'):
+ try:
+ TokenSpaceGuidName = re.search('GUID\((\w+)\)', Item).group(1)
+ except:
+ pass
+ if TokenSpaceGuidName and TokenSpaceGuidName in self._Symb:
+ Item = 'GUID(' + self._Symb[TokenSpaceGuidName] + ')'
+ elif TokenSpaceGuidName:
+ raise BadExpression('%s not found in DEC file' % TokenSpaceGuidName)
+ Item, Size = ParseFieldValue(Item)
+ for Index in range(0, Size):
+ ValueStr = '0x%02X' % (int(Item) & 255)
+ Item >>= 8
+ AllPcdValueList.append(ValueStr)
+ continue
+ elif Item.startswith('DEVICE_PATH') and Item.endswith(')'):
+ Item, Size = ParseFieldValue(Item)
+ AllPcdValueList.append(Item[1:-1])
+ continue
+ else:
+ ValueType = ""
+ if Item.startswith(TAB_UINT8):
+ ItemSize = 1
+ ValueType = TAB_UINT8
+ elif Item.startswith(TAB_UINT16):
+ ItemSize = 2
+ ValueType = TAB_UINT16
+ elif Item.startswith(TAB_UINT32):
+ ItemSize = 4
+ ValueType = TAB_UINT32
+ elif Item.startswith(TAB_UINT64):
+ ItemSize = 8
+ ValueType = TAB_UINT64
+ else:
+ ItemSize = 0
+ if ValueType:
+ TmpValue = ValueExpressionEx(Item, ValueType, self._Symb)(True)
+ else:
+ TmpValue = ValueExpressionEx(Item, self.PcdType, self._Symb)(True)
+ Item = '0x%x' % TmpValue if not isinstance(TmpValue, type('')) else TmpValue
+ if ItemSize == 0:
+ ItemValue, ItemSize = ParseFieldValue(Item)
+ if Item[0] not in {'"', 'L', '{'} and ItemSize > 1:
+ raise BadExpression("Byte array number %s should less than 0xFF." % Item)
+ else:
+ ItemValue = ParseFieldValue(Item)[0]
+ for I in range(0, ItemSize):
+ ValueStr = '0x%02X' % (int(ItemValue) & 255)
+ ItemValue >>= 8
+ AllPcdValueList.append(ValueStr)
+ Size += ItemSize
+
+ if Size > 0:
+ PcdValue = '{' + ','.join(AllPcdValueList) + '}'
+ else:
+ raise BadExpression("Type: %s, Value: %s, %s"%(self.PcdType, PcdValue, Value))
+
+ if PcdValue == 'True':
+ PcdValue = '1'
+ if PcdValue == 'False':
+ PcdValue = '0'
+
+ if RealValue:
+ return PcdValue
+
+if __name__ == '__main__':
+ pass
+ while True:
+ input = raw_input('Input expr: ')
+ if input in 'qQ':
+ break
+ try:
+ print(ValueExpression(input)(True))
+ print(ValueExpression(input)(False))
+ except WrnExpression as Ex:
+ print(Ex.result)
+ print(str(Ex))
+ except Exception as Ex:
+ print(str(Ex))
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/GlobalData.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/GlobalData.py
new file mode 100644
index 00000000..13248d94
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/GlobalData.py
@@ -0,0 +1,124 @@
+## @file
+# This file is used to define common static strings used by INF/DEC/DSC files
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+
+import re
+
+gIsWindows = None
+gWorkspace = "."
+gOptions = None
+gCaseInsensitive = False
+gAllFiles = None
+gCommand = None
+gSKUID_CMD = None
+
+gGlobalDefines = {}
+gPlatformDefines = {}
+# PCD name and value pair for fixed at build and feature flag
+gPlatformPcds = {}
+# PCDs with type that are not fixed at build and feature flag
+gPlatformOtherPcds = {}
+gActivePlatform = None
+gCommandLineDefines = {}
+gEdkGlobal = {}
+gCommandMaxLength = 4096
+# for debug trace purpose when problem occurs
+gProcessingFile = ''
+gBuildingModule = ''
+gSkuids = []
+gDefaultStores = []
+gGuidDict = {}
+
+# definition for a MACRO name. used to create regular expressions below.
+_MacroNamePattern = "[A-Z][A-Z0-9_]*"
+
+## Regular expression for matching macro used in DSC/DEC/INF file inclusion
+gMacroRefPattern = re.compile("\$\(({})\)".format(_MacroNamePattern), re.UNICODE)
+gMacroDefPattern = re.compile("^(DEFINE|EDK_GLOBAL)[ \t]+")
+gMacroNamePattern = re.compile("^{}$".format(_MacroNamePattern))
+
+# definition for a GUID. used to create regular expressions below.
+_HexChar = r"[0-9a-fA-F]"
+_GuidPattern = r"{Hex}{{8}}-{Hex}{{4}}-{Hex}{{4}}-{Hex}{{4}}-{Hex}{{12}}".format(Hex=_HexChar)
+
+## Regular expressions for GUID matching
+gGuidPattern = re.compile(r'{}'.format(_GuidPattern))
+gGuidPatternEnd = re.compile(r'{}$'.format(_GuidPattern))
+
+## Regular expressions for HEX matching
+g4HexChar = re.compile(r'{}{{4}}'.format(_HexChar))
+gHexPattern = re.compile(r'0[xX]{}+'.format(_HexChar))
+gHexPatternAll = re.compile(r'0[xX]{}+$'.format(_HexChar))
+
+## Regular expressions for string identifier checking
+gIdentifierPattern = re.compile('^[a-zA-Z][a-zA-Z0-9_]*$', re.UNICODE)
+## Regular expression for GUID c structure format
+_GuidCFormatPattern = r"{{\s*0[xX]{Hex}{{1,8}}\s*,\s*0[xX]{Hex}{{1,4}}\s*,\s*0[xX]{Hex}{{1,4}}" \
+ r"\s*,\s*{{\s*0[xX]{Hex}{{1,2}}\s*,\s*0[xX]{Hex}{{1,2}}" \
+ r"\s*,\s*0[xX]{Hex}{{1,2}}\s*,\s*0[xX]{Hex}{{1,2}}" \
+ r"\s*,\s*0[xX]{Hex}{{1,2}}\s*,\s*0[xX]{Hex}{{1,2}}" \
+ r"\s*,\s*0[xX]{Hex}{{1,2}}\s*,\s*0[xX]{Hex}{{1,2}}\s*}}\s*}}".format(Hex=_HexChar)
+gGuidCFormatPattern = re.compile(r"{}".format(_GuidCFormatPattern))
+
+#
+# A global variable for whether current build in AutoGen phase or not.
+#
+gAutoGenPhase = False
+
+#
+# The Conf dir outside the workspace dir
+#
+gConfDirectory = ''
+gCmdConfDir = ''
+gBuildDirectory = ''
+#
+# The relative default database file path
+#
+gDatabasePath = ".cache/build.db"
+
+#
+# Build flag for binary build
+#
+gIgnoreSource = False
+
+#
+# FDF parser
+#
+gFdfParser = None
+
+BuildOptionPcd = []
+
+#
+# Mixed PCD name dict
+#
+MixedPcd = {}
+
+# Structure Pcd dict
+gStructurePcd = {}
+gPcdSkuOverrides={}
+# Pcd name for the Pcd which used in the Conditional directives
+gConditionalPcds = []
+
+gUseHashCache = None
+gBinCacheDest = None
+gBinCacheSource = None
+gPlatformHash = None
+gPlatformHashFile = None
+gPackageHash = None
+gPackageHashFile = None
+gModuleHashFile = None
+gCMakeHashFile = None
+gHashChainStatus = None
+gModulePreMakeCacheStatus = None
+gModuleMakeCacheStatus = None
+gFileHashDict = None
+gModuleAllCacheStatus = None
+gModuleCacheHit = None
+
+gEnableGenfdsMultiThread = True
+gSikpAutoGenCache = set()
+# Common lock for the file access in multiple process AutoGens
+file_lock = None
+
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathOs.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathOs.py
new file mode 100755
index 00000000..3b3f1444
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathOs.py
@@ -0,0 +1,79 @@
+## @file
+# Override built in module os to provide support for long file path
+#
+# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+from __future__ import absolute_import
+import os
+from . import LongFilePathOsPath
+from Common.LongFilePathSupport import LongFilePath
+import time
+
+path = LongFilePathOsPath
+
+def access(path, mode):
+ return os.access(LongFilePath(path), mode)
+
+def remove(path):
+ Timeout = 0.0
+ while Timeout < 5.0:
+ try:
+ return os.remove(LongFilePath(path))
+ except:
+ time.sleep(0.1)
+ Timeout = Timeout + 0.1
+ return os.remove(LongFilePath(path))
+
+def removedirs(name):
+ return os.removedirs(LongFilePath(name))
+
+def rmdir(path):
+ return os.rmdir(LongFilePath(path))
+
+def mkdir(path):
+ return os.mkdir(LongFilePath(path))
+
+def makedirs(name, mode=0o777):
+ return os.makedirs(LongFilePath(name), mode)
+
+def rename(old, new):
+ return os.rename(LongFilePath(old), LongFilePath(new))
+
+def chdir(path):
+ return os.chdir(LongFilePath(path))
+
+def chmod(path, mode):
+ return os.chmod(LongFilePath(path), mode)
+
+def stat(path):
+ return os.stat(LongFilePath(path))
+
+def utime(path, times):
+ return os.utime(LongFilePath(path), times)
+
+def listdir(path):
+ List = []
+ uList = os.listdir(u"%s" % LongFilePath(path))
+ for Item in uList:
+ List.append(Item)
+ return List
+
+if hasattr(os, 'replace'):
+ def replace(src, dst):
+ return os.replace(LongFilePath(src), LongFilePath(dst))
+
+environ = os.environ
+getcwd = os.getcwd
+chdir = os.chdir
+walk = os.walk
+W_OK = os.W_OK
+F_OK = os.F_OK
+sep = os.sep
+linesep = os.linesep
+getenv = os.getenv
+pathsep = os.pathsep
+name = os.name
+SEEK_SET = os.SEEK_SET
+SEEK_END = os.SEEK_END
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathOsPath.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathOsPath.py
new file mode 100755
index 00000000..54d4dded
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathOsPath.py
@@ -0,0 +1,47 @@
+## @file
+# Override built in module os.path to provide support for long file path
+#
+# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+import os
+from Common.LongFilePathSupport import LongFilePath
+
+def isfile(path):
+ return os.path.isfile(LongFilePath(path))
+
+def isdir(path):
+ return os.path.isdir(LongFilePath(path))
+
+def exists(path):
+ return os.path.exists(LongFilePath(path))
+
+def getsize(filename):
+ return os.path.getsize(LongFilePath(filename))
+
+def getmtime(filename):
+ return os.path.getmtime(LongFilePath(filename))
+
+def getatime(filename):
+ return os.path.getatime(LongFilePath(filename))
+
+def getctime(filename):
+ return os.path.getctime(LongFilePath(filename))
+
+join = os.path.join
+splitext = os.path.splitext
+splitdrive = os.path.splitdrive
+split = os.path.split
+abspath = os.path.abspath
+basename = os.path.basename
+commonprefix = os.path.commonprefix
+sep = os.path.sep
+normpath = os.path.normpath
+normcase = os.path.normcase
+dirname = os.path.dirname
+islink = os.path.islink
+isabs = os.path.isabs
+realpath = os.path.realpath
+relpath = os.path.relpath
+pardir = os.path.pardir
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathSupport.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathSupport.py
new file mode 100755
index 00000000..193abd26
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/LongFilePathSupport.py
@@ -0,0 +1,45 @@
+## @file
+# Override built in function file.open to provide support for long file path
+#
+# Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+import os
+import platform
+import shutil
+import codecs
+
+##
+# OpenLongPath
+# Convert a file path to a long file path
+#
+def LongFilePath(FileName):
+ FileName = os.path.normpath(FileName)
+ if platform.system() == 'Windows':
+ if FileName.startswith('\\\\?\\'):
+ return FileName
+ if FileName.startswith('\\\\'):
+ return '\\\\?\\UNC\\' + FileName[2:]
+ if os.path.isabs(FileName):
+ return '\\\\?\\' + FileName
+ return FileName
+
+##
+# OpenLongFilePath
+# wrap open to support opening a long file path
+#
+def OpenLongFilePath(FileName, Mode='r', Buffer= -1):
+ return open(LongFilePath(FileName), Mode, Buffer)
+
+def CodecOpenLongFilePath(Filename, Mode='rb', Encoding=None, Errors='strict', Buffering=1):
+ return codecs.open(LongFilePath(Filename), Mode, Encoding, Errors, Buffering)
+
+##
+# CopyLongFilePath
+# wrap copyfile to support copy a long file path
+#
+def CopyLongFilePath(src, dst):
+ with open(LongFilePath(src), 'rb') as fsrc:
+ with open(LongFilePath(dst), 'wb') as fdst:
+ shutil.copyfileobj(fsrc, fdst)
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Misc.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Misc.py
new file mode 100755
index 00000000..980fa839
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Misc.py
@@ -0,0 +1,1929 @@
+## @file
+# Common routines used by all tools
+#
+# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+##
+# Import Modules
+#
+from __future__ import absolute_import
+
+import sys
+import string
+import threading
+import time
+import re
+import pickle
+import array
+import shutil
+import filecmp
+from random import sample
+from struct import pack
+import uuid
+import subprocess
+import tempfile
+from collections import OrderedDict
+
+import Common.LongFilePathOs as os
+from Common import EdkLogger as EdkLogger
+from Common import GlobalData as GlobalData
+from Common.DataType import *
+from Common.BuildToolError import *
+from CommonDataClass.DataClass import *
+from Common.Parsing import GetSplitValueList
+from Common.LongFilePathSupport import OpenLongFilePath as open
+from Common.LongFilePathSupport import CopyLongFilePath as CopyLong
+from Common.LongFilePathSupport import LongFilePath as LongFilePath
+from Common.MultipleWorkspace import MultipleWorkspace as mws
+from CommonDataClass.Exceptions import BadExpression
+from Common.caching import cached_property
+import struct
+
+ArrayIndex = re.compile("\[\s*[0-9a-fA-FxX]*\s*\]")
+## Regular expression used to find out place holders in string template
+gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE)
+
+## regular expressions for map file processing
+startPatternGeneral = re.compile("^Start[' ']+Length[' ']+Name[' ']+Class")
+addressPatternGeneral = re.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")
+valuePatternGcc = re.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')
+pcdPatternGcc = re.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')
+secReGeneral = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE)
+
+StructPattern = re.compile(r'[_a-zA-Z][0-9A-Za-z_]*$')
+
+## Dictionary used to store dependencies of files
+gDependencyDatabase = {} # arch : {file path : [dependent files list]}
+
+#
+# If a module is built more than once with different PCDs or library classes
+# a temporary INF file with same content is created, the temporary file is removed
+# when build exits.
+#
+_TempInfs = []
+
+def GetVariableOffset(mapfilepath, efifilepath, varnames):
+ """ Parse map file to get variable offset in current EFI file
+ @param mapfilepath Map file absolution path
+ @param efifilepath: EFI binary file full path
+ @param varnames iteratable container whose elements are variable names to be searched
+
+ @return List whos elements are tuple with variable name and raw offset
+ """
+ lines = []
+ try:
+ f = open(mapfilepath, 'r')
+ lines = f.readlines()
+ f.close()
+ except:
+ return None
+
+ if len(lines) == 0: return None
+ firstline = lines[0].strip()
+ if re.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', firstline):
+ return _parseForXcodeAndClang9(lines, efifilepath, varnames)
+ if (firstline.startswith("Archive member included ") and
+ firstline.endswith(" file (symbol)")):
+ return _parseForGCC(lines, efifilepath, varnames)
+ if firstline.startswith("# Path:"):
+ return _parseForXcodeAndClang9(lines, efifilepath, varnames)
+ return _parseGeneral(lines, efifilepath, varnames)
+
+def _parseForXcodeAndClang9(lines, efifilepath, varnames):
+ status = 0
+ ret = []
+ for line in lines:
+ line = line.strip()
+ if status == 0 and (re.match('^\s*Address\s*Size\s*Align\s*Out\s*In\s*Symbol\s*$', line) \
+ or line == "# Symbols:"):
+ status = 1
+ continue
+ if status == 1 and len(line) != 0:
+ for varname in varnames:
+ if varname in line:
+ # cannot pregenerate this RegEx since it uses varname from varnames.
+ m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line)
+ if m is not None:
+ ret.append((varname, m.group(1)))
+ return ret
+
+def _parseForGCC(lines, efifilepath, varnames):
+ """ Parse map file generated by GCC linker """
+ status = 0
+ sections = []
+ varoffset = []
+ for index, line in enumerate(lines):
+ line = line.strip()
+ # status machine transection
+ if status == 0 and line == "Memory Configuration":
+ status = 1
+ continue
+ elif status == 1 and line == 'Linker script and memory map':
+ status = 2
+ continue
+ elif status ==2 and line == 'START GROUP':
+ status = 3
+ continue
+
+ # status handler
+ if status == 3:
+ m = valuePatternGcc.match(line)
+ if m is not None:
+ sections.append(m.groups(0))
+ for varname in varnames:
+ Str = ''
+ m = re.match("^.data.(%s)" % varname, line)
+ if m is not None:
+ m = re.match(".data.(%s)$" % varname, line)
+ if m is not None:
+ Str = lines[index + 1]
+ else:
+ Str = line[len(".data.%s" % varname):]
+ if Str:
+ m = pcdPatternGcc.match(Str.strip())
+ if m is not None:
+ varoffset.append((varname, int(m.groups(0)[0], 16), int(sections[-1][1], 16), sections[-1][0]))
+
+ if not varoffset:
+ return []
+ # get section information from efi file
+ efisecs = PeImageClass(efifilepath).SectionHeaderList
+ if efisecs is None or len(efisecs) == 0:
+ return []
+ #redirection
+ redirection = 0
+ for efisec in efisecs:
+ for section in sections:
+ if section[0].strip() == efisec[0].strip() and section[0].strip() == '.text':
+ redirection = int(section[1], 16) - efisec[1]
+
+ ret = []
+ for var in varoffset:
+ for efisec in efisecs:
+ if var[1] >= efisec[1] and var[1] < efisec[1]+efisec[3]:
+ ret.append((var[0], hex(efisec[2] + var[1] - efisec[1] - redirection)))
+ return ret
+
+def _parseGeneral(lines, efifilepath, varnames):
+ status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table
+ secs = [] # key = section name
+ varoffset = []
+ symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$-]+) +([\da-fA-F]+)', re.UNICODE)
+
+ for line in lines:
+ line = line.strip()
+ if startPatternGeneral.match(line):
+ status = 1
+ continue
+ if addressPatternGeneral.match(line):
+ status = 2
+ continue
+ if line.startswith("entry point at"):
+ status = 3
+ continue
+ if status == 1 and len(line) != 0:
+ m = secReGeneral.match(line)
+ assert m is not None, "Fail to parse the section in map file , line is %s" % line
+ sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0)
+ secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class])
+ if status == 2 and len(line) != 0:
+ for varname in varnames:
+ m = symRe.match(line)
+ assert m is not None, "Fail to parse the symbol in map file, line is %s" % line
+ sec_no, sym_offset, sym_name, vir_addr = m.groups(0)
+ sec_no = int(sec_no, 16)
+ sym_offset = int(sym_offset, 16)
+ vir_addr = int(vir_addr, 16)
+ # cannot pregenerate this RegEx since it uses varname from varnames.
+ m2 = re.match('^[_]*(%s)' % varname, sym_name)
+ if m2 is not None:
+ # fond a binary pcd entry in map file
+ for sec in secs:
+ if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]):
+ varoffset.append([varname, sec[3], sym_offset, vir_addr, sec_no])
+
+ if not varoffset: return []
+
+ # get section information from efi file
+ efisecs = PeImageClass(efifilepath).SectionHeaderList
+ if efisecs is None or len(efisecs) == 0:
+ return []
+
+ ret = []
+ for var in varoffset:
+ index = 0
+ for efisec in efisecs:
+ index = index + 1
+ if var[1].strip() == efisec[0].strip():
+ ret.append((var[0], hex(efisec[2] + var[2])))
+ elif var[4] == index:
+ ret.append((var[0], hex(efisec[2] + var[2])))
+
+ return ret
+
+## Routine to process duplicated INF
+#
+# This function is called by following two cases:
+# Case 1 in DSC:
+# [components.arch]
+# Pkg/module/module.inf
+# Pkg/module/module.inf {
+# <Defines>
+# FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836
+# }
+# Case 2 in FDF:
+# INF Pkg/module/module.inf
+# INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf
+#
+# This function copies Pkg/module/module.inf to
+# Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf
+#
+# @param Path Original PathClass object
+# @param BaseName New file base name
+#
+# @retval return the new PathClass object
+#
+def ProcessDuplicatedInf(Path, BaseName, Workspace):
+ Filename = os.path.split(Path.File)[1]
+ if '.' in Filename:
+ Filename = BaseName + Path.BaseName + Filename[Filename.rfind('.'):]
+ else:
+ Filename = BaseName + Path.BaseName
+
+ DbDir = os.path.split(GlobalData.gDatabasePath)[0]
+
+ #
+ # A temporary INF is copied to database path which must have write permission
+ # The temporary will be removed at the end of build
+ # In case of name conflict, the file name is
+ # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)
+ #
+ TempFullPath = os.path.join(DbDir,
+ Filename)
+ RtPath = PathClass(Path.File, Workspace)
+ #
+ # Modify the full path to temporary path, keep other unchanged
+ #
+ # To build same module more than once, the module path with FILE_GUID overridden has
+ # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
+ # in DSC which is used as relative path by C files and other files in INF.
+ # A trick was used: all module paths are PathClass instances, after the initialization
+ # of PathClass, the PathClass.Path is overridden by the temporary INF path.
+ #
+ # The reason for creating a temporary INF is:
+ # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,
+ # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.
+ # A different key for the same module is needed to create different output directory,
+ # retrieve overridden PCDs, library instances.
+ #
+ # The BaseName is the FILE_GUID which is also the output directory name.
+ #
+ #
+ RtPath.Path = TempFullPath
+ RtPath.BaseName = BaseName
+ RtPath.OriginalPath = Path
+ #
+ # If file exists, compare contents
+ #
+ if os.path.exists(TempFullPath):
+ with open(str(Path), 'rb') as f1, open(TempFullPath, 'rb') as f2:
+ if f1.read() == f2.read():
+ return RtPath
+ _TempInfs.append(TempFullPath)
+ shutil.copy2(str(Path), TempFullPath)
+ return RtPath
+
+## Remove temporary created INFs whose paths were saved in _TempInfs
+#
+def ClearDuplicatedInf():
+ while _TempInfs:
+ File = _TempInfs.pop()
+ if os.path.exists(File):
+ os.remove(File)
+
+## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
+#
+# @param Guid The GUID string
+#
+# @retval string The GUID string in C structure style
+#
+def GuidStringToGuidStructureString(Guid):
+ GuidList = Guid.split('-')
+ Result = '{'
+ for Index in range(0, 3, 1):
+ Result = Result + '0x' + GuidList[Index] + ', '
+ Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]
+ for Index in range(0, 12, 2):
+ Result = Result + ', 0x' + GuidList[4][Index:Index + 2]
+ Result += '}}'
+ return Result
+
+## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+#
+# @param GuidValue The GUID value in byte array
+#
+# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
+#
+def GuidStructureByteArrayToGuidString(GuidValue):
+ guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
+ guidValueList = guidValueString.split(",")
+ if len(guidValueList) != 16:
+ return ''
+ #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
+ try:
+ return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
+ int(guidValueList[3], 16),
+ int(guidValueList[2], 16),
+ int(guidValueList[1], 16),
+ int(guidValueList[0], 16),
+ int(guidValueList[5], 16),
+ int(guidValueList[4], 16),
+ int(guidValueList[7], 16),
+ int(guidValueList[6], 16),
+ int(guidValueList[8], 16),
+ int(guidValueList[9], 16),
+ int(guidValueList[10], 16),
+ int(guidValueList[11], 16),
+ int(guidValueList[12], 16),
+ int(guidValueList[13], 16),
+ int(guidValueList[14], 16),
+ int(guidValueList[15], 16)
+ )
+ except:
+ return ''
+
+## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+#
+# @param GuidValue The GUID value in C structure format
+#
+# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
+#
+def GuidStructureStringToGuidString(GuidValue):
+ if not GlobalData.gGuidCFormatPattern.match(GuidValue):
+ return ''
+ guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
+ guidValueList = guidValueString.split(",")
+ if len(guidValueList) != 11:
+ return ''
+ #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
+ try:
+ return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
+ int(guidValueList[0], 16),
+ int(guidValueList[1], 16),
+ int(guidValueList[2], 16),
+ int(guidValueList[3], 16),
+ int(guidValueList[4], 16),
+ int(guidValueList[5], 16),
+ int(guidValueList[6], 16),
+ int(guidValueList[7], 16),
+ int(guidValueList[8], 16),
+ int(guidValueList[9], 16),
+ int(guidValueList[10], 16)
+ )
+ except:
+ return ''
+
+## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
+#
+# @param GuidValue The GUID value in C structure format
+#
+# @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
+#
+def GuidStructureStringToGuidValueName(GuidValue):
+ guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")
+ guidValueList = guidValueString.split(",")
+ if len(guidValueList) != 11:
+ EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue)
+ return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
+ int(guidValueList[0], 16),
+ int(guidValueList[1], 16),
+ int(guidValueList[2], 16),
+ int(guidValueList[3], 16),
+ int(guidValueList[4], 16),
+ int(guidValueList[5], 16),
+ int(guidValueList[6], 16),
+ int(guidValueList[7], 16),
+ int(guidValueList[8], 16),
+ int(guidValueList[9], 16),
+ int(guidValueList[10], 16)
+ )
+
+## Create directories
+#
+# @param Directory The directory name
+#
+def CreateDirectory(Directory):
+ if Directory is None or Directory.strip() == "":
+ return True
+ try:
+ if not os.access(Directory, os.F_OK):
+ os.makedirs(Directory)
+ except:
+ return False
+ return True
+
+## Remove directories, including files and sub-directories in it
+#
+# @param Directory The directory name
+#
+def RemoveDirectory(Directory, Recursively=False):
+ if Directory is None or Directory.strip() == "" or not os.path.exists(Directory):
+ return
+ if Recursively:
+ CurrentDirectory = os.getcwd()
+ os.chdir(Directory)
+ for File in os.listdir("."):
+ if os.path.isdir(File):
+ RemoveDirectory(File, Recursively)
+ else:
+ os.remove(File)
+ os.chdir(CurrentDirectory)
+ os.rmdir(Directory)
+
+## Store content in file
+#
+# This method is used to save file only when its content is changed. This is
+# quite useful for "make" system to decide what will be re-built and what won't.
+#
+# @param File The path of file
+# @param Content The new content of the file
+# @param IsBinaryFile The flag indicating if the file is binary file or not
+#
+# @retval True If the file content is changed and the file is renewed
+# @retval False If the file content is the same
+#
+def SaveFileOnChange(File, Content, IsBinaryFile=True, FileLock=None):
+
+ # Convert to long file path format
+ File = LongFilePath(File)
+
+ if os.path.exists(File):
+ if IsBinaryFile:
+ try:
+ with open(File, "rb") as f:
+ if Content == f.read():
+ return False
+ except:
+ EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)
+ else:
+ try:
+ with open(File, "r") as f:
+ if Content == f.read():
+ return False
+ except:
+ EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)
+
+ DirName = os.path.dirname(File)
+ if not CreateDirectory(DirName):
+ EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)
+ else:
+ if DirName == '':
+ DirName = os.getcwd()
+ if not os.access(DirName, os.W_OK):
+ EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)
+
+ OpenMode = "w"
+ if IsBinaryFile:
+ OpenMode = "wb"
+
+ # use default file_lock if no input new lock
+ if not FileLock:
+ FileLock = GlobalData.file_lock
+ if FileLock:
+ FileLock.acquire()
+
+
+ if GlobalData.gIsWindows and not os.path.exists(File):
+ try:
+ with open(File, OpenMode) as tf:
+ tf.write(Content)
+ except IOError as X:
+ if GlobalData.gBinCacheSource:
+ EdkLogger.quiet("[cache error]:fails to save file with error: %s" % (X))
+ else:
+ EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)
+ finally:
+ if FileLock:
+ FileLock.release()
+ else:
+ try:
+ with open(File, OpenMode) as Fd:
+ Fd.write(Content)
+ except IOError as X:
+ if GlobalData.gBinCacheSource:
+ EdkLogger.quiet("[cache error]:fails to save file with error: %s" % (X))
+ else:
+ EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)
+ finally:
+ if FileLock:
+ FileLock.release()
+
+ return True
+
+## Copy source file only if it is different from the destination file
+#
+# This method is used to copy file only if the source file and destination
+# file content are different. This is quite useful to avoid duplicated
+# file writing.
+#
+# @param SrcFile The path of source file
+# @param Dst The path of destination file or folder
+#
+# @retval True The two files content are different and the file is copied
+# @retval False No copy really happen
+#
+def CopyFileOnChange(SrcFile, Dst, FileLock=None):
+
+ # Convert to long file path format
+ SrcFile = LongFilePath(SrcFile)
+ Dst = LongFilePath(Dst)
+
+ if os.path.isdir(SrcFile):
+ EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='CopyFileOnChange SrcFile is a dir, not a file: %s' % SrcFile)
+ return False
+
+ if os.path.isdir(Dst):
+ DstFile = os.path.join(Dst, os.path.basename(SrcFile))
+ else:
+ DstFile = Dst
+
+ if os.path.exists(DstFile) and filecmp.cmp(SrcFile, DstFile, shallow=False):
+ return False
+
+ DirName = os.path.dirname(DstFile)
+ if not CreateDirectory(DirName):
+ EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)
+ else:
+ if DirName == '':
+ DirName = os.getcwd()
+ if not os.access(DirName, os.W_OK):
+ EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)
+
+ # use default file_lock if no input new lock
+ if not FileLock:
+ FileLock = GlobalData.file_lock
+ if FileLock:
+ FileLock.acquire()
+
+ try:
+ CopyLong(SrcFile, DstFile)
+ except IOError as X:
+ if GlobalData.gBinCacheSource:
+ EdkLogger.quiet("[cache error]:fails to copy file with error: %s" % (X))
+ else:
+ EdkLogger.error(None, FILE_COPY_FAILURE, ExtraData='IOError %s' % X)
+ finally:
+ if FileLock:
+ FileLock.release()
+
+ return True
+
+## Retrieve and cache the real path name in file system
+#
+# @param Root The root directory of path relative to
+#
+# @retval str The path string if the path exists
+# @retval None If path doesn't exist
+#
+class DirCache:
+ _CACHE_ = set()
+ _UPPER_CACHE_ = {}
+
+ def __init__(self, Root):
+ self._Root = Root
+ for F in os.listdir(Root):
+ self._CACHE_.add(F)
+ self._UPPER_CACHE_[F.upper()] = F
+
+ # =[] operator
+ def __getitem__(self, Path):
+ Path = Path[len(os.path.commonprefix([Path, self._Root])):]
+ if not Path:
+ return self._Root
+ if Path and Path[0] == os.path.sep:
+ Path = Path[1:]
+ if Path in self._CACHE_:
+ return os.path.join(self._Root, Path)
+ UpperPath = Path.upper()
+ if UpperPath in self._UPPER_CACHE_:
+ return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
+
+ IndexList = []
+ LastSepIndex = -1
+ SepIndex = Path.find(os.path.sep)
+ while SepIndex > -1:
+ Parent = UpperPath[:SepIndex]
+ if Parent not in self._UPPER_CACHE_:
+ break
+ LastSepIndex = SepIndex
+ SepIndex = Path.find(os.path.sep, LastSepIndex + 1)
+
+ if LastSepIndex == -1:
+ return None
+
+ Cwd = os.getcwd()
+ os.chdir(self._Root)
+ SepIndex = LastSepIndex
+ while SepIndex > -1:
+ Parent = Path[:SepIndex]
+ ParentKey = UpperPath[:SepIndex]
+ if ParentKey not in self._UPPER_CACHE_:
+ os.chdir(Cwd)
+ return None
+
+ if Parent in self._CACHE_:
+ ParentDir = Parent
+ else:
+ ParentDir = self._UPPER_CACHE_[ParentKey]
+ for F in os.listdir(ParentDir):
+ Dir = os.path.join(ParentDir, F)
+ self._CACHE_.add(Dir)
+ self._UPPER_CACHE_[Dir.upper()] = Dir
+
+ SepIndex = Path.find(os.path.sep, SepIndex + 1)
+
+ os.chdir(Cwd)
+ if Path in self._CACHE_:
+ return os.path.join(self._Root, Path)
+ elif UpperPath in self._UPPER_CACHE_:
+ return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])
+ return None
+
+def RealPath(File, Dir='', OverrideDir=''):
+ NewFile = os.path.normpath(os.path.join(Dir, File))
+ NewFile = GlobalData.gAllFiles[NewFile]
+ if not NewFile and OverrideDir:
+ NewFile = os.path.normpath(os.path.join(OverrideDir, File))
+ NewFile = GlobalData.gAllFiles[NewFile]
+ return NewFile
+
+## Get GUID value from given packages
+#
+# @param CName The CName of the GUID
+# @param PackageList List of packages looking-up in
+# @param Inffile The driver file
+#
+# @retval GuidValue if the CName is found in any given package
+# @retval None if the CName is not found in all given packages
+#
+def GuidValue(CName, PackageList, Inffile = None):
+ for P in PackageList:
+ GuidKeys = list(P.Guids.keys())
+ if Inffile and P._PrivateGuids:
+ if not Inffile.startswith(P.MetaFile.Dir):
+ GuidKeys = [x for x in P.Guids if x not in P._PrivateGuids]
+ if CName in GuidKeys:
+ return P.Guids[CName]
+ return None
+
+## A string template class
+#
+# This class implements a template for string replacement. A string template
+# looks like following
+#
+# ${BEGIN} other_string ${placeholder_name} other_string ${END}
+#
+# The string between ${BEGIN} and ${END} will be repeated as many times as the
+# length of "placeholder_name", which is a list passed through a dict. The
+# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
+# be not used and, in this case, the "placeholder_name" must not a list and it
+# will just be replaced once.
+#
+class TemplateString(object):
+ _REPEAT_START_FLAG = "BEGIN"
+ _REPEAT_END_FLAG = "END"
+
+ class Section(object):
+ _LIST_TYPES = [type([]), type(set()), type((0,))]
+
+ def __init__(self, TemplateSection, PlaceHolderList):
+ self._Template = TemplateSection
+ self._PlaceHolderList = []
+
+ # Split the section into sub-sections according to the position of placeholders
+ if PlaceHolderList:
+ self._SubSectionList = []
+ SubSectionStart = 0
+ #
+ # The placeholders passed in must be in the format of
+ #
+ # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
+ #
+ for PlaceHolder, Start, End in PlaceHolderList:
+ self._SubSectionList.append(TemplateSection[SubSectionStart:Start])
+ self._SubSectionList.append(TemplateSection[Start:End])
+ self._PlaceHolderList.append(PlaceHolder)
+ SubSectionStart = End
+ if SubSectionStart < len(TemplateSection):
+ self._SubSectionList.append(TemplateSection[SubSectionStart:])
+ else:
+ self._SubSectionList = [TemplateSection]
+
+ def __str__(self):
+ return self._Template + " : " + str(self._PlaceHolderList)
+
+ def Instantiate(self, PlaceHolderValues):
+ RepeatTime = -1
+ RepeatPlaceHolders = {}
+ NonRepeatPlaceHolders = {}
+
+ for PlaceHolder in self._PlaceHolderList:
+ if PlaceHolder not in PlaceHolderValues:
+ continue
+ Value = PlaceHolderValues[PlaceHolder]
+ if type(Value) in self._LIST_TYPES:
+ if RepeatTime < 0:
+ RepeatTime = len(Value)
+ elif RepeatTime != len(Value):
+ EdkLogger.error(
+ "TemplateString",
+ PARAMETER_INVALID,
+ "${%s} has different repeat time from others!" % PlaceHolder,
+ ExtraData=str(self._Template)
+ )
+ RepeatPlaceHolders["${%s}" % PlaceHolder] = Value
+ else:
+ NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value
+
+ if NonRepeatPlaceHolders:
+ StringList = []
+ for S in self._SubSectionList:
+ if S not in NonRepeatPlaceHolders:
+ StringList.append(S)
+ else:
+ StringList.append(str(NonRepeatPlaceHolders[S]))
+ else:
+ StringList = self._SubSectionList
+
+ if RepeatPlaceHolders:
+ TempStringList = []
+ for Index in range(RepeatTime):
+ for S in StringList:
+ if S not in RepeatPlaceHolders:
+ TempStringList.append(S)
+ else:
+ TempStringList.append(str(RepeatPlaceHolders[S][Index]))
+ StringList = TempStringList
+
+ return "".join(StringList)
+
+ ## Constructor
+ def __init__(self, Template=None):
+ self.String = []
+ self.IsBinary = False
+ self._Template = Template
+ self._TemplateSectionList = self._Parse(Template)
+
+ ## str() operator
+ #
+ # @retval string The string replaced
+ #
+ def __str__(self):
+ return "".join(self.String)
+
+ ## Split the template string into fragments per the ${BEGIN} and ${END} flags
+ #
+ # @retval list A list of TemplateString.Section objects
+ #
+ def _Parse(self, Template):
+ SectionStart = 0
+ SearchFrom = 0
+ MatchEnd = 0
+ PlaceHolderList = []
+ TemplateSectionList = []
+ while Template:
+ MatchObj = gPlaceholderPattern.search(Template, SearchFrom)
+ if not MatchObj:
+ if MatchEnd <= len(Template):
+ TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)
+ TemplateSectionList.append(TemplateSection)
+ break
+
+ MatchString = MatchObj.group(1)
+ MatchStart = MatchObj.start()
+ MatchEnd = MatchObj.end()
+
+ if MatchString == self._REPEAT_START_FLAG:
+ if MatchStart > SectionStart:
+ TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
+ TemplateSectionList.append(TemplateSection)
+ SectionStart = MatchEnd
+ PlaceHolderList = []
+ elif MatchString == self._REPEAT_END_FLAG:
+ TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)
+ TemplateSectionList.append(TemplateSection)
+ SectionStart = MatchEnd
+ PlaceHolderList = []
+ else:
+ PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))
+ SearchFrom = MatchEnd
+ return TemplateSectionList
+
+ ## Replace the string template with dictionary of placeholders and append it to previous one
+ #
+ # @param AppendString The string template to append
+ # @param Dictionary The placeholder dictionaries
+ #
+ def Append(self, AppendString, Dictionary=None):
+ if Dictionary:
+ SectionList = self._Parse(AppendString)
+ self.String.append( "".join(S.Instantiate(Dictionary) for S in SectionList))
+ else:
+ if isinstance(AppendString,list):
+ self.String.extend(AppendString)
+ else:
+ self.String.append(AppendString)
+
+ ## Replace the string template with dictionary of placeholders
+ #
+ # @param Dictionary The placeholder dictionaries
+ #
+ # @retval str The string replaced with placeholder values
+ #
+ def Replace(self, Dictionary=None):
+ return "".join(S.Instantiate(Dictionary) for S in self._TemplateSectionList)
+
+## Progress indicator class
+#
+# This class makes use of thread to print progress on console.
+#
+class Progressor:
+ # for avoiding deadloop
+ _StopFlag = None
+ _ProgressThread = None
+ _CheckInterval = 0.25
+
+ ## Constructor
+ #
+ # @param OpenMessage The string printed before progress characters
+ # @param CloseMessage The string printed after progress characters
+ # @param ProgressChar The character used to indicate the progress
+ # @param Interval The interval in seconds between two progress characters
+ #
+ def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):
+ self.PromptMessage = OpenMessage
+ self.CodaMessage = CloseMessage
+ self.ProgressChar = ProgressChar
+ self.Interval = Interval
+ if Progressor._StopFlag is None:
+ Progressor._StopFlag = threading.Event()
+
+ ## Start to print progress character
+ #
+ # @param OpenMessage The string printed before progress characters
+ #
+ def Start(self, OpenMessage=None):
+ if OpenMessage is not None:
+ self.PromptMessage = OpenMessage
+ Progressor._StopFlag.clear()
+ if Progressor._ProgressThread is None:
+ Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)
+ Progressor._ProgressThread.setDaemon(False)
+ Progressor._ProgressThread.start()
+
+ ## Stop printing progress character
+ #
+ # @param CloseMessage The string printed after progress characters
+ #
+ def Stop(self, CloseMessage=None):
+ OriginalCodaMessage = self.CodaMessage
+ if CloseMessage is not None:
+ self.CodaMessage = CloseMessage
+ self.Abort()
+ self.CodaMessage = OriginalCodaMessage
+
+ ## Thread entry method
+ def _ProgressThreadEntry(self):
+ sys.stdout.write(self.PromptMessage + " ")
+ sys.stdout.flush()
+ TimeUp = 0.0
+ while not Progressor._StopFlag.isSet():
+ if TimeUp <= 0.0:
+ sys.stdout.write(self.ProgressChar)
+ sys.stdout.flush()
+ TimeUp = self.Interval
+ time.sleep(self._CheckInterval)
+ TimeUp -= self._CheckInterval
+ sys.stdout.write(" " + self.CodaMessage + "\n")
+ sys.stdout.flush()
+
+ ## Abort the progress display
+ @staticmethod
+ def Abort():
+ if Progressor._StopFlag is not None:
+ Progressor._StopFlag.set()
+ if Progressor._ProgressThread is not None:
+ Progressor._ProgressThread.join()
+ Progressor._ProgressThread = None
+
+
+## Dictionary using prioritized list as key
+#
+class tdict:
+ _ListType = type([])
+ _TupleType = type(())
+ _Wildcard = 'COMMON'
+ _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', TAB_STAR, 'PLATFORM']
+
+ def __init__(self, _Single_=False, _Level_=2):
+ self._Level_ = _Level_
+ self.data = {}
+ self._Single_ = _Single_
+
+ # =[] operator
+ def __getitem__(self, key):
+ KeyType = type(key)
+ RestKeys = None
+ if KeyType == self._ListType or KeyType == self._TupleType:
+ FirstKey = key[0]
+ if len(key) > 1:
+ RestKeys = key[1:]
+ elif self._Level_ > 1:
+ RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
+ else:
+ FirstKey = key
+ if self._Level_ > 1:
+ RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
+
+ if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList:
+ FirstKey = self._Wildcard
+
+ if self._Single_:
+ return self._GetSingleValue(FirstKey, RestKeys)
+ else:
+ return self._GetAllValues(FirstKey, RestKeys)
+
+ def _GetSingleValue(self, FirstKey, RestKeys):
+ Value = None
+ #print "%s-%s" % (FirstKey, self._Level_) ,
+ if self._Level_ > 1:
+ if FirstKey == self._Wildcard:
+ if FirstKey in self.data:
+ Value = self.data[FirstKey][RestKeys]
+ if Value is None:
+ for Key in self.data:
+ Value = self.data[Key][RestKeys]
+ if Value is not None: break
+ else:
+ if FirstKey in self.data:
+ Value = self.data[FirstKey][RestKeys]
+ if Value is None and self._Wildcard in self.data:
+ #print "Value=None"
+ Value = self.data[self._Wildcard][RestKeys]
+ else:
+ if FirstKey == self._Wildcard:
+ if FirstKey in self.data:
+ Value = self.data[FirstKey]
+ if Value is None:
+ for Key in self.data:
+ Value = self.data[Key]
+ if Value is not None: break
+ else:
+ if FirstKey in self.data:
+ Value = self.data[FirstKey]
+ elif self._Wildcard in self.data:
+ Value = self.data[self._Wildcard]
+ return Value
+
+ def _GetAllValues(self, FirstKey, RestKeys):
+ Value = []
+ if self._Level_ > 1:
+ if FirstKey == self._Wildcard:
+ for Key in self.data:
+ Value += self.data[Key][RestKeys]
+ else:
+ if FirstKey in self.data:
+ Value += self.data[FirstKey][RestKeys]
+ if self._Wildcard in self.data:
+ Value += self.data[self._Wildcard][RestKeys]
+ else:
+ if FirstKey == self._Wildcard:
+ for Key in self.data:
+ Value.append(self.data[Key])
+ else:
+ if FirstKey in self.data:
+ Value.append(self.data[FirstKey])
+ if self._Wildcard in self.data:
+ Value.append(self.data[self._Wildcard])
+ return Value
+
+ ## []= operator
+ def __setitem__(self, key, value):
+ KeyType = type(key)
+ RestKeys = None
+ if KeyType == self._ListType or KeyType == self._TupleType:
+ FirstKey = key[0]
+ if len(key) > 1:
+ RestKeys = key[1:]
+ else:
+ RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
+ else:
+ FirstKey = key
+ if self._Level_ > 1:
+ RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]
+
+ if FirstKey in self._ValidWildcardList:
+ FirstKey = self._Wildcard
+
+ if FirstKey not in self.data and self._Level_ > 0:
+ self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)
+
+ if self._Level_ > 1:
+ self.data[FirstKey][RestKeys] = value
+ else:
+ self.data[FirstKey] = value
+
+ def SetGreedyMode(self):
+ self._Single_ = False
+ if self._Level_ > 1:
+ for Key in self.data:
+ self.data[Key].SetGreedyMode()
+
+ def SetSingleMode(self):
+ self._Single_ = True
+ if self._Level_ > 1:
+ for Key in self.data:
+ self.data[Key].SetSingleMode()
+
+ def GetKeys(self, KeyIndex=0):
+ assert KeyIndex >= 0
+ if KeyIndex == 0:
+ return set(self.data.keys())
+ else:
+ keys = set()
+ for Key in self.data:
+ keys |= self.data[Key].GetKeys(KeyIndex - 1)
+ return keys
+
+def AnalyzePcdExpression(Setting):
+ RanStr = ''.join(sample(string.ascii_letters + string.digits, 8))
+ Setting = Setting.replace('\\\\', RanStr).strip()
+ # There might be escaped quote in a string: \", \\\" , \', \\\'
+ Data = Setting
+ # There might be '|' in string and in ( ... | ... ), replace it with '-'
+ NewStr = ''
+ InSingleQuoteStr = False
+ InDoubleQuoteStr = False
+ Pair = 0
+ for Index, ch in enumerate(Data):
+ if ch == '"' and not InSingleQuoteStr:
+ if Data[Index - 1] != '\\':
+ InDoubleQuoteStr = not InDoubleQuoteStr
+ elif ch == "'" and not InDoubleQuoteStr:
+ if Data[Index - 1] != '\\':
+ InSingleQuoteStr = not InSingleQuoteStr
+ elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr):
+ Pair += 1
+ elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr):
+ Pair -= 1
+
+ if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT:
+ NewStr += '-'
+ else:
+ NewStr += ch
+ FieldList = []
+ StartPos = 0
+ while True:
+ Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)
+ if Pos < 0:
+ FieldList.append(Setting[StartPos:].strip())
+ break
+ FieldList.append(Setting[StartPos:Pos].strip())
+ StartPos = Pos + 1
+ for i, ch in enumerate(FieldList):
+ if RanStr in ch:
+ FieldList[i] = ch.replace(RanStr,'\\\\')
+ return FieldList
+
+def ParseFieldValue (Value):
+ def ParseDevPathValue (Value):
+ if '\\' in Value:
+ Value.replace('\\', '/').replace(' ', '')
+
+ Cmd = 'DevicePath ' + '"' + Value + '"'
+ try:
+ p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ out, err = p.communicate()
+ except Exception as X:
+ raise BadExpression("DevicePath: %s" % (str(X)) )
+ finally:
+ subprocess._cleanup()
+ p.stdout.close()
+ p.stderr.close()
+ if err:
+ raise BadExpression("DevicePath: %s" % str(err))
+ out = out.decode()
+ Size = len(out.split())
+ out = ','.join(out.split())
+ return '{' + out + '}', Size
+
+ if "{CODE(" in Value:
+ return Value, len(Value.split(","))
+ if isinstance(Value, type(0)):
+ return Value, (Value.bit_length() + 7) // 8
+ if not isinstance(Value, type('')):
+ raise BadExpression('Type %s is %s' %(Value, type(Value)))
+ Value = Value.strip()
+ if Value.startswith(TAB_UINT8) and Value.endswith(')'):
+ Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])
+ if Size > 1:
+ raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))
+ return Value, 1
+ if Value.startswith(TAB_UINT16) and Value.endswith(')'):
+ Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])
+ if Size > 2:
+ raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))
+ return Value, 2
+ if Value.startswith(TAB_UINT32) and Value.endswith(')'):
+ Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])
+ if Size > 4:
+ raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))
+ return Value, 4
+ if Value.startswith(TAB_UINT64) and Value.endswith(')'):
+ Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])
+ if Size > 8:
+ raise BadExpression('Value (%s) Size larger than %d' % (Value, Size))
+ return Value, 8
+ if Value.startswith(TAB_GUID) and Value.endswith(')'):
+ Value = Value.split('(', 1)[1][:-1].strip()
+ if Value[0] == '{' and Value[-1] == '}':
+ TmpValue = GuidStructureStringToGuidString(Value)
+ if not TmpValue:
+ raise BadExpression("Invalid GUID value string %s" % Value)
+ Value = TmpValue
+ if Value[0] == '"' and Value[-1] == '"':
+ Value = Value[1:-1]
+ try:
+ Value = uuid.UUID(Value).bytes_le
+ ValueL, ValueH = struct.unpack('2Q', Value)
+ Value = (ValueH << 64 ) | ValueL
+
+ except ValueError as Message:
+ raise BadExpression(Message)
+ return Value, 16
+ if Value.startswith('L"') and Value.endswith('"'):
+ # Unicode String
+ # translate escape character
+ Value = Value[1:]
+ try:
+ Value = eval(Value)
+ except:
+ Value = Value[1:-1]
+ List = list(Value)
+ List.reverse()
+ Value = 0
+ for Char in List:
+ Value = (Value << 16) | ord(Char)
+ return Value, (len(List) + 1) * 2
+ if Value.startswith('"') and Value.endswith('"'):
+ # ASCII String
+ # translate escape character
+ try:
+ Value = eval(Value)
+ except:
+ Value = Value[1:-1]
+ List = list(Value)
+ List.reverse()
+ Value = 0
+ for Char in List:
+ Value = (Value << 8) | ord(Char)
+ return Value, len(List) + 1
+ if Value.startswith("L'") and Value.endswith("'"):
+ # Unicode Character Constant
+ # translate escape character
+ Value = Value[1:]
+ try:
+ Value = eval(Value)
+ except:
+ Value = Value[1:-1]
+ List = list(Value)
+ if len(List) == 0:
+ raise BadExpression('Length %s is %s' % (Value, len(List)))
+ List.reverse()
+ Value = 0
+ for Char in List:
+ Value = (Value << 16) | ord(Char)
+ return Value, len(List) * 2
+ if Value.startswith("'") and Value.endswith("'"):
+ # Character constant
+ # translate escape character
+ try:
+ Value = eval(Value)
+ except:
+ Value = Value[1:-1]
+ List = list(Value)
+ if len(List) == 0:
+ raise BadExpression('Length %s is %s' % (Value, len(List)))
+ List.reverse()
+ Value = 0
+ for Char in List:
+ Value = (Value << 8) | ord(Char)
+ return Value, len(List)
+ if Value.startswith('{') and Value.endswith('}'):
+ # Byte array
+ Value = Value[1:-1]
+ List = [Item.strip() for Item in Value.split(',')]
+ List.reverse()
+ Value = 0
+ RetSize = 0
+ for Item in List:
+ ItemValue, Size = ParseFieldValue(Item)
+ RetSize += Size
+ for I in range(Size):
+ Value = (Value << 8) | ((ItemValue >> 8 * I) & 0xff)
+ return Value, RetSize
+ if Value.startswith('DEVICE_PATH(') and Value.endswith(')'):
+ Value = Value.replace("DEVICE_PATH(", '').rstrip(')')
+ Value = Value.strip().strip('"')
+ return ParseDevPathValue(Value)
+ if Value.lower().startswith('0x'):
+ try:
+ Value = int(Value, 16)
+ except:
+ raise BadExpression("invalid hex value: %s" % Value)
+ if Value == 0:
+ return 0, 1
+ return Value, (Value.bit_length() + 7) // 8
+ if Value[0].isdigit():
+ Value = int(Value, 10)
+ if Value == 0:
+ return 0, 1
+ return Value, (Value.bit_length() + 7) // 8
+ if Value.lower() == 'true':
+ return 1, 1
+ if Value.lower() == 'false':
+ return 0, 1
+ return Value, 1
+
+## AnalyzeDscPcd
+#
+# Analyze DSC PCD value, since there is no data type info in DSC
+# This function is used to match functions (AnalyzePcdData) used for retrieving PCD value from database
+# 1. Feature flag: TokenSpace.PcdCName|PcdValue
+# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
+# 3. Dynamic default:
+# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]
+# TokenSpace.PcdCName|PcdValue
+# 4. Dynamic VPD:
+# TokenSpace.PcdCName|VpdOffset[|VpdValue]
+# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]
+# 5. Dynamic HII:
+# TokenSpace.PcdCName|HiiString|VariableGuid|VariableOffset[|HiiValue]
+# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which
+# there might have "|" operator, also in string value.
+#
+# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped
+# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII
+# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL
+# @retval:
+# ValueList: A List contain fields described above
+# IsValid: True if conforming EBNF, otherwise False
+# Index: The index where PcdValue is in ValueList
+#
+def AnalyzeDscPcd(Setting, PcdType, DataType=''):
+ FieldList = AnalyzePcdExpression(Setting)
+
+ IsValid = True
+ if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):
+ Value = FieldList[0]
+ Size = ''
+ if len(FieldList) > 1 and FieldList[1]:
+ DataType = FieldList[1]
+ if FieldList[1] != TAB_VOID and StructPattern.match(FieldList[1]) is None:
+ IsValid = False
+ if len(FieldList) > 2:
+ Size = FieldList[2]
+ if IsValid:
+ if DataType == "":
+ IsValid = (len(FieldList) <= 1)
+ else:
+ IsValid = (len(FieldList) <= 3)
+
+ if Size:
+ try:
+ int(Size, 16) if Size.upper().startswith("0X") else int(Size)
+ except:
+ IsValid = False
+ Size = -1
+ return [str(Value), DataType, str(Size)], IsValid, 0
+ elif PcdType == MODEL_PCD_FEATURE_FLAG:
+ Value = FieldList[0]
+ Size = ''
+ IsValid = (len(FieldList) <= 1)
+ return [Value, DataType, str(Size)], IsValid, 0
+ elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):
+ VpdOffset = FieldList[0]
+ Value = Size = ''
+ if not DataType == TAB_VOID:
+ if len(FieldList) > 1:
+ Value = FieldList[1]
+ else:
+ if len(FieldList) > 1:
+ Size = FieldList[1]
+ if len(FieldList) > 2:
+ Value = FieldList[2]
+ if DataType == "":
+ IsValid = (len(FieldList) <= 1)
+ else:
+ IsValid = (len(FieldList) <= 3)
+ if Size:
+ try:
+ int(Size, 16) if Size.upper().startswith("0X") else int(Size)
+ except:
+ IsValid = False
+ Size = -1
+ return [VpdOffset, str(Size), Value], IsValid, 2
+ elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):
+ IsValid = (3 <= len(FieldList) <= 5)
+ HiiString = FieldList[0]
+ Guid = Offset = Value = Attribute = ''
+ if len(FieldList) > 1:
+ Guid = FieldList[1]
+ if len(FieldList) > 2:
+ Offset = FieldList[2]
+ if len(FieldList) > 3:
+ Value = FieldList[3]
+ if len(FieldList) > 4:
+ Attribute = FieldList[4]
+ return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3
+ return [], False, 0
+
+## AnalyzePcdData
+#
+# Analyze the pcd Value, Datum type and TokenNumber.
+# Used to avoid split issue while the value string contain "|" character
+#
+# @param[in] Setting: A String contain value/datum type/token number information;
+#
+# @retval ValueList: A List contain value, datum type and toke number.
+#
+def AnalyzePcdData(Setting):
+ ValueList = ['', '', '']
+
+ ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
+ PtrValue = ValueRe.findall(Setting)
+
+ ValueUpdateFlag = False
+
+ if len(PtrValue) >= 1:
+ Setting = re.sub(ValueRe, '', Setting)
+ ValueUpdateFlag = True
+
+ TokenList = Setting.split(TAB_VALUE_SPLIT)
+ ValueList[0:len(TokenList)] = TokenList
+
+ if ValueUpdateFlag:
+ ValueList[0] = PtrValue[0]
+
+ return ValueList
+
+## check format of PCD value against its the datum type
+#
+# For PCD value setting
+#
+def CheckPcdDatum(Type, Value):
+ if Type == TAB_VOID:
+ ValueRe = re.compile(r'\s*L?\".*\"\s*$')
+ if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))
+ or (Value.startswith('{') and Value.endswith('}')) or (Value.startswith("L'") or Value.startswith("'") and Value.endswith("'"))
+ ):
+ return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
+ ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value, Type)
+ elif ValueRe.match(Value):
+ # Check the chars in UnicodeString or CString is printable
+ if Value.startswith("L"):
+ Value = Value[2:-1]
+ else:
+ Value = Value[1:-1]
+ Printset = set(string.printable)
+ Printset.remove(TAB_PRINTCHAR_VT)
+ Printset.add(TAB_PRINTCHAR_BS)
+ Printset.add(TAB_PRINTCHAR_NUL)
+ if not set(Value).issubset(Printset):
+ PrintList = sorted(Printset)
+ return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)
+ elif Type == 'BOOLEAN':
+ if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
+ return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
+ ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)
+ elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:
+ if Value.startswith('0') and not Value.lower().startswith('0x') and len(Value) > 1 and Value.lstrip('0'):
+ Value = Value.lstrip('0')
+ try:
+ if Value and int(Value, 0) < 0:
+ return False, "PCD can't be set to negative value[%s] for datum type [%s]" % (Value, Type)
+ Value = int(Value, 0)
+ if Value > MAX_VAL_TYPE[Type]:
+ return False, "Too large PCD value[%s] for datum type [%s]" % (Value, Type)
+ except:
+ return False, "Invalid value [%s] of type [%s];"\
+ " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)
+ else:
+ return True, "StructurePcd"
+
+ return True, ""
+
+def CommonPath(PathList):
+ P1 = min(PathList).split(os.path.sep)
+ P2 = max(PathList).split(os.path.sep)
+ for Index in range(min(len(P1), len(P2))):
+ if P1[Index] != P2[Index]:
+ return os.path.sep.join(P1[:Index])
+ return os.path.sep.join(P1)
+
+class PathClass(object):
+ def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
+ Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):
+ self.Arch = Arch
+ self.File = str(File)
+ if os.path.isabs(self.File):
+ self.Root = ''
+ self.AlterRoot = ''
+ else:
+ self.Root = str(Root)
+ self.AlterRoot = str(AlterRoot)
+
+ # Remove any '.' and '..' in path
+ if self.Root:
+ self.Root = mws.getWs(self.Root, self.File)
+ self.Path = os.path.normpath(os.path.join(self.Root, self.File))
+ self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
+ # eliminate the side-effect of 'C:'
+ if self.Root[-1] == ':':
+ self.Root += os.path.sep
+ # file path should not start with path separator
+ if self.Root[-1] == os.path.sep:
+ self.File = self.Path[len(self.Root):]
+ else:
+ self.File = self.Path[len(self.Root) + 1:]
+ else:
+ self.Path = os.path.normpath(self.File)
+
+ self.SubDir, self.Name = os.path.split(self.File)
+ self.BaseName, self.Ext = os.path.splitext(self.Name)
+
+ if self.Root:
+ if self.SubDir:
+ self.Dir = os.path.join(self.Root, self.SubDir)
+ else:
+ self.Dir = self.Root
+ else:
+ self.Dir = self.SubDir
+
+ if IsBinary:
+ self.Type = Type
+ else:
+ self.Type = self.Ext.lower()
+
+ self.IsBinary = IsBinary
+ self.Target = Target
+ self.TagName = TagName
+ self.ToolCode = ToolCode
+ self.ToolChainFamily = ToolChainFamily
+ self.OriginalPath = self
+
+ ## Convert the object of this class to a string
+ #
+ # Convert member Path of the class to a string
+ #
+ # @retval string Formatted String
+ #
+ def __str__(self):
+ return self.Path
+
+ ## Override __eq__ function
+ #
+ # Check whether PathClass are the same
+ #
+ # @retval False The two PathClass are different
+ # @retval True The two PathClass are the same
+ #
+ def __eq__(self, Other):
+ return self.Path == str(Other)
+
+ ## Override __cmp__ function
+ #
+ # Customize the comparison operation of two PathClass
+ #
+ # @retval 0 The two PathClass are different
+ # @retval -1 The first PathClass is less than the second PathClass
+ # @retval 1 The first PathClass is Bigger than the second PathClass
+ def __cmp__(self, Other):
+ OtherKey = str(Other)
+
+ SelfKey = self.Path
+ if SelfKey == OtherKey:
+ return 0
+ elif SelfKey > OtherKey:
+ return 1
+ else:
+ return -1
+
+ ## Override __hash__ function
+ #
+ # Use Path as key in hash table
+ #
+ # @retval string Key for hash table
+ #
+ def __hash__(self):
+ return hash(self.Path)
+
+ @cached_property
+ def Key(self):
+ return self.Path.upper()
+
+ @property
+ def TimeStamp(self):
+ return os.stat(self.Path)[8]
+
+ def Validate(self, Type='', CaseSensitive=True):
+ def RealPath2(File, Dir='', OverrideDir=''):
+ NewFile = None
+ if OverrideDir:
+ NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]
+ if NewFile:
+ if OverrideDir[-1] == os.path.sep:
+ return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]
+ else:
+ return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)]
+ if GlobalData.gAllFiles:
+ NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]
+ if not NewFile:
+ NewFile = os.path.normpath(os.path.join(Dir, File))
+ if not os.path.exists(NewFile):
+ return None, None
+ if NewFile:
+ if Dir:
+ if Dir[-1] == os.path.sep:
+ return NewFile[len(Dir):], NewFile[0:len(Dir)]
+ else:
+ return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]
+ else:
+ return NewFile, ''
+
+ return None, None
+
+ if GlobalData.gCaseInsensitive:
+ CaseSensitive = False
+ if Type and Type.lower() != self.Type:
+ return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)
+
+ RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
+ if not RealRoot and not RealFile:
+ RealFile = self.File
+ if self.AlterRoot:
+ RealFile = os.path.join(self.AlterRoot, self.File)
+ elif self.Root:
+ RealFile = os.path.join(self.Root, self.File)
+ if len (mws.getPkgPath()) == 0:
+ return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
+ else:
+ return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))
+
+ ErrorCode = 0
+ ErrorInfo = ''
+ if RealRoot != self.Root or RealFile != self.File:
+ if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):
+ ErrorCode = FILE_CASE_MISMATCH
+ ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"
+
+ self.SubDir, self.Name = os.path.split(RealFile)
+ self.BaseName, self.Ext = os.path.splitext(self.Name)
+ if self.SubDir:
+ self.Dir = os.path.join(RealRoot, self.SubDir)
+ else:
+ self.Dir = RealRoot
+ self.File = RealFile
+ self.Root = RealRoot
+ self.Path = os.path.join(RealRoot, RealFile)
+ return ErrorCode, ErrorInfo
+
+## Parse PE image to get the required PE information.
+#
+class PeImageClass():
+ ## Constructor
+ #
+ # @param File FilePath of PeImage
+ #
+ def __init__(self, PeFile):
+ self.FileName = PeFile
+ self.IsValid = False
+ self.Size = 0
+ self.EntryPoint = 0
+ self.SectionAlignment = 0
+ self.SectionHeaderList = []
+ self.ErrorInfo = ''
+ try:
+ PeObject = open(PeFile, 'rb')
+ except:
+ self.ErrorInfo = self.FileName + ' can not be found\n'
+ return
+ # Read DOS header
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, 0x3E)
+ ByteList = ByteArray.tolist()
+ # DOS signature should be 'MZ'
+ if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':
+ self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'
+ return
+
+ # Read 4 byte PE Signature
+ PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])
+ PeObject.seek(PeOffset)
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, 4)
+ # PE signature should be 'PE\0\0'
+ if ByteArray.tolist() != [ord('P'), ord('E'), 0, 0]:
+ self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'
+ return
+
+ # Read PE file header
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, 0x14)
+ ByteList = ByteArray.tolist()
+ SecNumber = self._ByteListToInt(ByteList[0x2:0x4])
+ if SecNumber == 0:
+ self.ErrorInfo = self.FileName + ' has no section header'
+ return
+
+ # Read PE optional header
+ OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, OptionalHeaderSize)
+ ByteList = ByteArray.tolist()
+ self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])
+ self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])
+ self.Size = self._ByteListToInt(ByteList[0x38:0x3C])
+
+ # Read each Section Header
+ for Index in range(SecNumber):
+ ByteArray = array.array('B')
+ ByteArray.fromfile(PeObject, 0x28)
+ ByteList = ByteArray.tolist()
+ SecName = self._ByteListToStr(ByteList[0:8])
+ SecVirtualSize = self._ByteListToInt(ByteList[8:12])
+ SecRawAddress = self._ByteListToInt(ByteList[20:24])
+ SecVirtualAddress = self._ByteListToInt(ByteList[12:16])
+ self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))
+ self.IsValid = True
+ PeObject.close()
+
+ def _ByteListToStr(self, ByteList):
+ String = ''
+ for index in range(len(ByteList)):
+ if ByteList[index] == 0:
+ break
+ String += chr(ByteList[index])
+ return String
+
+ def _ByteListToInt(self, ByteList):
+ Value = 0
+ for index in range(len(ByteList) - 1, -1, -1):
+ Value = (Value << 8) | int(ByteList[index])
+ return Value
+
+class DefaultStore():
+ def __init__(self, DefaultStores ):
+
+ self.DefaultStores = DefaultStores
+ def DefaultStoreID(self, DefaultStoreName):
+ for key, value in self.DefaultStores.items():
+ if value == DefaultStoreName:
+ return key
+ return None
+ def GetDefaultDefault(self):
+ if not self.DefaultStores or "0" in self.DefaultStores:
+ return "0", TAB_DEFAULT_STORES_DEFAULT
+ else:
+ minvalue = min(int(value_str) for value_str in self.DefaultStores)
+ return (str(minvalue), self.DefaultStores[str(minvalue)])
+ def GetMin(self, DefaultSIdList):
+ if not DefaultSIdList:
+ return TAB_DEFAULT_STORES_DEFAULT
+ storeidset = {storeid for storeid, storename in self.DefaultStores.values() if storename in DefaultSIdList}
+ if not storeidset:
+ return ""
+ minid = min(storeidset )
+ for sid, name in self.DefaultStores.values():
+ if sid == minid:
+ return name
+
+class SkuClass():
+ DEFAULT = 0
+ SINGLE = 1
+ MULTIPLE =2
+
+ def __init__(self,SkuIdentifier='', SkuIds=None):
+ if SkuIds is None:
+ SkuIds = {}
+
+ for SkuName in SkuIds:
+ SkuId = SkuIds[SkuName][0]
+ skuid_num = int(SkuId, 16) if SkuId.upper().startswith("0X") else int(SkuId)
+ if skuid_num > 0xFFFFFFFFFFFFFFFF:
+ EdkLogger.error("build", PARAMETER_INVALID,
+ ExtraData = "SKU-ID [%s] value %s exceeds the max value of UINT64"
+ % (SkuName, SkuId))
+
+ self.AvailableSkuIds = OrderedDict()
+ self.SkuIdSet = []
+ self.SkuIdNumberSet = []
+ self.SkuData = SkuIds
+ self._SkuInherit = {}
+ self._SkuIdentifier = SkuIdentifier
+ if SkuIdentifier == '' or SkuIdentifier is None:
+ self.SkuIdSet = ['DEFAULT']
+ self.SkuIdNumberSet = ['0U']
+ elif SkuIdentifier == 'ALL':
+ self.SkuIdSet = list(SkuIds.keys())
+ self.SkuIdNumberSet = [num[0].strip() + 'U' for num in SkuIds.values()]
+ else:
+ r = SkuIdentifier.split('|')
+ self.SkuIdSet=[(r[k].strip()).upper() for k in range(len(r))]
+ k = None
+ try:
+ self.SkuIdNumberSet = [SkuIds[k][0].strip() + 'U' for k in self.SkuIdSet]
+ except Exception:
+ EdkLogger.error("build", PARAMETER_INVALID,
+ ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
+ % (k, " | ".join(SkuIds.keys())))
+ for each in self.SkuIdSet:
+ if each in SkuIds:
+ self.AvailableSkuIds[each] = SkuIds[each][0]
+ else:
+ EdkLogger.error("build", PARAMETER_INVALID,
+ ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"
+ % (each, " | ".join(SkuIds.keys())))
+ if self.SkuUsageType != SkuClass.SINGLE:
+ self.AvailableSkuIds.update({'DEFAULT':0, 'COMMON':0})
+ if self.SkuIdSet:
+ GlobalData.gSkuids = (self.SkuIdSet)
+ if 'COMMON' in GlobalData.gSkuids:
+ GlobalData.gSkuids.remove('COMMON')
+ if self.SkuUsageType == self.SINGLE:
+ if len(GlobalData.gSkuids) != 1:
+ if 'DEFAULT' in GlobalData.gSkuids:
+ GlobalData.gSkuids.remove('DEFAULT')
+ if GlobalData.gSkuids:
+ GlobalData.gSkuids.sort()
+
+ def GetNextSkuId(self, skuname):
+ if not self._SkuInherit:
+ self._SkuInherit = {}
+ for item in self.SkuData.values():
+ self._SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT"
+ return self._SkuInherit.get(skuname, "DEFAULT")
+
+ def GetSkuChain(self, sku):
+ if sku == "DEFAULT":
+ return ["DEFAULT"]
+ skulist = [sku]
+ nextsku = sku
+ while True:
+ nextsku = self.GetNextSkuId(nextsku)
+ skulist.append(nextsku)
+ if nextsku == "DEFAULT":
+ break
+ skulist.reverse()
+ return skulist
+ def SkuOverrideOrder(self):
+ skuorderset = []
+ for skuname in self.SkuIdSet:
+ skuorderset.append(self.GetSkuChain(skuname))
+
+ skuorder = []
+ for index in range(max(len(item) for item in skuorderset)):
+ for subset in skuorderset:
+ if index > len(subset)-1:
+ continue
+ if subset[index] in skuorder:
+ continue
+ skuorder.append(subset[index])
+
+ return skuorder
+
+ @property
+ def SkuUsageType(self):
+ if self._SkuIdentifier.upper() == "ALL":
+ return SkuClass.MULTIPLE
+
+ if len(self.SkuIdSet) == 1:
+ if self.SkuIdSet[0] == 'DEFAULT':
+ return SkuClass.DEFAULT
+ return SkuClass.SINGLE
+ if len(self.SkuIdSet) == 2 and 'DEFAULT' in self.SkuIdSet:
+ return SkuClass.SINGLE
+ return SkuClass.MULTIPLE
+
+ def DumpSkuIdArrary(self):
+ if self.SkuUsageType == SkuClass.SINGLE:
+ return "{0x0}"
+ ArrayStrList = []
+ for skuname in self.AvailableSkuIds:
+ if skuname == "COMMON":
+ continue
+ while skuname != "DEFAULT":
+ ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname])))
+ skuname = self.GetNextSkuId(skuname)
+ ArrayStrList.append("0x0")
+ return "{{{myList}}}".format(myList=",".join(ArrayStrList))
+
+ @property
+ def AvailableSkuIdSet(self):
+ return self.AvailableSkuIds
+
+ @property
+ def SystemSkuId(self):
+ if self.SkuUsageType == SkuClass.SINGLE:
+ if len(self.SkuIdSet) == 1:
+ return self.SkuIdSet[0]
+ else:
+ return self.SkuIdSet[0] if self.SkuIdSet[0] != 'DEFAULT' else self.SkuIdSet[1]
+ else:
+ return 'DEFAULT'
+
+## Get the integer value from string like "14U" or integer like 2
+#
+# @param Input The object that may be either a integer value or a string
+#
+# @retval Value The integer value that the input represents
+#
+def GetIntegerValue(Input):
+ if not isinstance(Input, str):
+ return Input
+ String = Input
+ if String.endswith("U"):
+ String = String[:-1]
+ if String.endswith("ULL"):
+ String = String[:-3]
+ if String.endswith("LL"):
+ String = String[:-2]
+
+ if String.startswith("0x") or String.startswith("0X"):
+ return int(String, 16)
+ elif String == '':
+ return 0
+ else:
+ return int(String)
+
+#
+# Pack a GUID (registry format) list into a buffer and return it
+#
+def PackGUID(Guid):
+ return pack(PACK_PATTERN_GUID,
+ 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)
+ )
+
+#
+# Pack a GUID (byte) list into a buffer and return it
+#
+def PackByteFormatGUID(Guid):
+ return pack(PACK_PATTERN_GUID,
+ Guid[0],
+ Guid[1],
+ Guid[2],
+ Guid[3],
+ Guid[4],
+ Guid[5],
+ Guid[6],
+ Guid[7],
+ Guid[8],
+ Guid[9],
+ Guid[10],
+ )
+
+## DeepCopy dict/OrderedDict recusively
+#
+# @param ori_dict a nested dict or ordereddict
+#
+# @retval new dict or orderdict
+#
+def CopyDict(ori_dict):
+ dict_type = ori_dict.__class__
+ if dict_type not in (dict,OrderedDict):
+ return ori_dict
+ new_dict = dict_type()
+ for key in ori_dict:
+ if isinstance(ori_dict[key],(dict,OrderedDict)):
+ new_dict[key] = CopyDict(ori_dict[key])
+ else:
+ new_dict[key] = ori_dict[key]
+ return new_dict
+
+#
+# Remove the c/c++ comments: // and /* */
+#
+def RemoveCComments(ctext):
+ return re.sub('//.*?\n|/\*.*?\*/', '\n', ctext, flags=re.S)
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/MultipleWorkspace.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/MultipleWorkspace.py
new file mode 100755
index 00000000..df461f28
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/MultipleWorkspace.py
@@ -0,0 +1,150 @@
+## @file
+# manage multiple workspace file.
+#
+# This file is required to make Python interpreter treat the directory
+# as containing package.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+import Common.LongFilePathOs as os
+from Common.DataType import TAB_WORKSPACE
+
+## MultipleWorkspace
+#
+# This class manage multiple workspace behavior
+#
+# @param class:
+#
+# @var WORKSPACE: defined the current WORKSPACE
+# @var PACKAGES_PATH: defined the other WORKSPACE, if current WORKSPACE is invalid, search valid WORKSPACE from PACKAGES_PATH
+#
+class MultipleWorkspace(object):
+ WORKSPACE = ''
+ PACKAGES_PATH = None
+
+ ## convertPackagePath()
+ #
+ # Convert path to match workspace.
+ #
+ # @param cls The class pointer
+ # @param Ws The current WORKSPACE
+ # @param Path Path to be converted to match workspace.
+ #
+ @classmethod
+ def convertPackagePath(cls, Ws, Path):
+ if str(os.path.normcase (Path)).startswith(Ws):
+ return os.path.join(Ws, os.path.relpath(Path, Ws))
+ return Path
+
+ ## setWs()
+ #
+ # set WORKSPACE and PACKAGES_PATH environment
+ #
+ # @param cls The class pointer
+ # @param Ws initialize WORKSPACE variable
+ # @param PackagesPath initialize PackagesPath variable
+ #
+ @classmethod
+ def setWs(cls, Ws, PackagesPath=None):
+ cls.WORKSPACE = Ws
+ if PackagesPath:
+ cls.PACKAGES_PATH = [cls.convertPackagePath (Ws, os.path.normpath(Path.strip())) for Path in PackagesPath.split(os.pathsep)]
+ else:
+ cls.PACKAGES_PATH = []
+
+ ## join()
+ #
+ # rewrite os.path.join function
+ #
+ # @param cls The class pointer
+ # @param Ws the current WORKSPACE
+ # @param *p path of the inf/dec/dsc/fdf/conf file
+ # @retval Path the absolute path of specified file
+ #
+ @classmethod
+ def join(cls, Ws, *p):
+ Path = os.path.join(Ws, *p)
+ if not os.path.exists(Path):
+ for Pkg in cls.PACKAGES_PATH:
+ Path = os.path.join(Pkg, *p)
+ if os.path.exists(Path):
+ return Path
+ Path = os.path.join(Ws, *p)
+ return Path
+
+ ## relpath()
+ #
+ # rewrite os.path.relpath function
+ #
+ # @param cls The class pointer
+ # @param Path path of the inf/dec/dsc/fdf/conf file
+ # @param Ws the current WORKSPACE
+ # @retval Path the relative path of specified file
+ #
+ @classmethod
+ def relpath(cls, Path, Ws):
+ for Pkg in cls.PACKAGES_PATH:
+ if Path.lower().startswith(Pkg.lower()):
+ Path = os.path.relpath(Path, Pkg)
+ return Path
+ if Path.lower().startswith(Ws.lower()):
+ Path = os.path.relpath(Path, Ws)
+ return Path
+
+ ## getWs()
+ #
+ # get valid workspace for the path
+ #
+ # @param cls The class pointer
+ # @param Ws the current WORKSPACE
+ # @param Path path of the inf/dec/dsc/fdf/conf file
+ # @retval Ws the valid workspace relative to the specified file path
+ #
+ @classmethod
+ def getWs(cls, Ws, Path):
+ absPath = os.path.join(Ws, Path)
+ if not os.path.exists(absPath):
+ for Pkg in cls.PACKAGES_PATH:
+ absPath = os.path.join(Pkg, Path)
+ if os.path.exists(absPath):
+ return Pkg
+ return Ws
+
+ ## handleWsMacro()
+ #
+ # handle the $(WORKSPACE) tag, if current workspace is invalid path relative the tool, replace it.
+ #
+ # @param cls The class pointer
+ # @retval PathStr Path string include the $(WORKSPACE)
+ #
+ @classmethod
+ def handleWsMacro(cls, PathStr):
+ if TAB_WORKSPACE in PathStr:
+ PathList = PathStr.split()
+ if PathList:
+ for i, str in enumerate(PathList):
+ MacroStartPos = str.find(TAB_WORKSPACE)
+ if MacroStartPos != -1:
+ Substr = str[MacroStartPos:]
+ Path = Substr.replace(TAB_WORKSPACE, cls.WORKSPACE).strip()
+ if not os.path.exists(Path):
+ for Pkg in cls.PACKAGES_PATH:
+ Path = Substr.replace(TAB_WORKSPACE, Pkg).strip()
+ if os.path.exists(Path):
+ break
+ PathList[i] = str[0:MacroStartPos] + Path
+ PathStr = ' '.join(PathList)
+ return PathStr
+
+ ## getPkgPath()
+ #
+ # get all package paths.
+ #
+ # @param cls The class pointer
+ #
+ @classmethod
+ def getPkgPath(cls):
+ return cls.PACKAGES_PATH
+
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Parsing.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Parsing.py
new file mode 100755
index 00000000..5ae50402
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Parsing.py
@@ -0,0 +1,906 @@
+## @file
+# This file is used to define common parsing related functions used in parsing INF/DEC/DSC process
+#
+# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+##
+# Import Modules
+#
+from __future__ import absolute_import
+from .StringUtils import *
+from CommonDataClass.DataClass import *
+from .DataType import *
+
+## ParseDefineMacro
+#
+# Search whole table to find all defined Macro and replaced them with the real values
+#
+def ParseDefineMacro2(Table, RecordSets, GlobalMacro):
+ Macros = {}
+ #
+ # Find all DEFINE macros in section [Header] and its section
+ #
+ SqlCommand = """select Value1, Value2, BelongsToItem, StartLine, Arch from %s
+ where Model = %s
+ and Enabled > -1""" % (Table.Table, MODEL_META_DATA_DEFINE)
+ RecordSet = Table.Exec(SqlCommand)
+ for Record in RecordSet:
+ Macros[Record[0]] = Record[1]
+
+ #
+ # Overridden by Global Macros
+ #
+ Macros.update(GlobalMacro)
+
+ #
+ # Replace the Macros
+ #
+ for Value in (v for v in RecordSets.values() if v):
+ for Item in Value:
+ Item[0] = ReplaceMacro(Item[0], Macros)
+
+## ParseDefineMacro
+#
+# Search whole table to find all defined Macro and replaced them with the real values
+#
+def ParseDefineMacro(Table, GlobalMacro):
+ Macros = {}
+ #
+ # Find all DEFINE macros
+ #
+ SqlCommand = """select Value1, Value2, BelongsToItem, StartLine, Arch from %s
+ where Model = %s
+ and Enabled > -1""" % (Table.Table, MODEL_META_DATA_DEFINE)
+ RecordSet = Table.Exec(SqlCommand)
+ for Record in RecordSet:
+#***************************************************************************************************************************************************
+# The follow SqlCommand (expr replace) is not supported in Sqlite 3.3.4 which is used in Python 2.5 *
+# Reserved Only *
+# SqlCommand = """update %s set Value1 = replace(Value1, '%s', '%s') *
+# where ID in (select ID from %s *
+# where Model = %s *
+# and Value1 like '%%%s%%' *
+# and StartLine > %s *
+# and Enabled > -1 *
+# and Arch = '%s')""" % \ *
+# (self.TblDsc.Table, Record[0], Record[1], self.TblDsc.Table, Record[2], Record[1], Record[3], Record[4]) *
+#***************************************************************************************************************************************************
+ Macros[Record[0]] = Record[1]
+
+ #
+ # Overridden by Global Macros
+ #
+ Macros.update(GlobalMacro)
+
+ #
+ # Found all defined macro and replaced
+ #
+ SqlCommand = """select ID, Value1 from %s
+ where Model != %s
+ and Value1 like '%%$(%%' and Value1 like '%%)%%'
+ and Enabled > -1""" % (Table.Table, MODEL_META_DATA_DEFINE)
+ FoundRecords = Table.Exec(SqlCommand)
+ for FoundRecord in FoundRecords:
+ NewValue = ReplaceMacro(FoundRecord[1], Macros)
+ SqlCommand = """update %s set Value1 = '%s'
+ where ID = %s""" % (Table.Table, ConvertToSqlString2(NewValue), FoundRecord[0])
+ Table.Exec(SqlCommand)
+
+##QueryDefinesItem
+#
+# Search item of section [Defines] by name, return its values
+#
+# @param Table: The Table to be executed
+# @param Name: The Name of item of section [Defines]
+# @param Arch: The Arch of item of section [Defines]
+#
+# @retval RecordSet: A list of all matched records
+#
+def QueryDefinesItem(Table, Name, Arch, BelongsToFile):
+ SqlCommand = """select Value2 from %s
+ where Model = %s
+ and Value1 = '%s'
+ and Arch = '%s'
+ and BelongsToFile = %s
+ and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Name), ConvertToSqlString2(Arch), BelongsToFile)
+ RecordSet = Table.Exec(SqlCommand)
+ if len(RecordSet) < 1:
+ SqlCommand = """select Value2 from %s
+ where Model = %s
+ and Value1 = '%s'
+ and Arch = '%s'
+ and BelongsToFile = %s
+ and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Name), ConvertToSqlString2(TAB_ARCH_COMMON.upper()), BelongsToFile)
+ RecordSet = Table.Exec(SqlCommand)
+ if len(RecordSet) == 1:
+ if Name == TAB_INF_DEFINES_LIBRARY_CLASS:
+ return [RecordSet[0][0]]
+ else:
+ return GetSplitValueList(RecordSet[0][0])
+ elif len(RecordSet) < 1:
+ return ['']
+ elif len(RecordSet) > 1:
+ RetVal = []
+ for Record in RecordSet:
+ if Name == TAB_INF_DEFINES_LIBRARY_CLASS:
+ RetVal.append(Record[0])
+ else:
+ Items = GetSplitValueList(Record[0])
+ for Item in Items:
+ RetVal.append(Item)
+ return RetVal
+
+##QueryDefinesItem
+#
+# Search item of section [Defines] by name, return its values
+#
+# @param Table: The Table to be executed
+# @param Name: The Name of item of section [Defines]
+# @param Arch: The Arch of item of section [Defines]
+#
+# @retval RecordSet: A list of all matched records
+#
+def QueryDefinesItem2(Table, Arch, BelongsToFile):
+ SqlCommand = """select Value1, Value2, StartLine from %s
+ where Model = %s
+ and Arch = '%s'
+ and BelongsToFile = %s
+ and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Arch), BelongsToFile)
+ RecordSet = Table.Exec(SqlCommand)
+ if len(RecordSet) < 1:
+ SqlCommand = """select Value1, Value2, StartLine from %s
+ where Model = %s
+ and Arch = '%s'
+ and BelongsToFile = %s
+ and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(TAB_ARCH_COMMON), BelongsToFile)
+ RecordSet = Table.Exec(SqlCommand)
+
+ return RecordSet
+
+##QueryDscItem
+#
+# Search all dsc item for a specific section
+#
+# @param Table: The Table to be executed
+# @param Model: The type of section
+#
+# @retval RecordSet: A list of all matched records
+#
+def QueryDscItem(Table, Model, BelongsToItem, BelongsToFile):
+ SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s
+ where Model = %s
+ and BelongsToItem = %s
+ and BelongsToFile = %s
+ and Enabled > -1""" % (Table.Table, Model, BelongsToItem, BelongsToFile)
+ return Table.Exec(SqlCommand)
+
+##QueryDecItem
+#
+# Search all dec item for a specific section
+#
+# @param Table: The Table to be executed
+# @param Model: The type of section
+#
+# @retval RecordSet: A list of all matched records
+#
+def QueryDecItem(Table, Model, BelongsToItem):
+ SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s
+ where Model = %s
+ and BelongsToItem = %s
+ and Enabled > -1""" % (Table.Table, Model, BelongsToItem)
+ return Table.Exec(SqlCommand)
+
+##QueryInfItem
+#
+# Search all dec item for a specific section
+#
+# @param Table: The Table to be executed
+# @param Model: The type of section
+#
+# @retval RecordSet: A list of all matched records
+#
+def QueryInfItem(Table, Model, BelongsToItem):
+ SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s
+ where Model = %s
+ and BelongsToItem = %s
+ and Enabled > -1""" % (Table.Table, Model, BelongsToItem)
+ return Table.Exec(SqlCommand)
+
+## GetBuildOption
+#
+# Parse a string with format "[<Family>:]<ToolFlag>=Flag"
+# Return (Family, ToolFlag, Flag)
+#
+# @param String: String with BuildOption statement
+# @param File: The file which defines build option, used in error report
+#
+# @retval truple() A truple structure as (Family, ToolChain, Flag)
+#
+def GetBuildOption(String, File, LineNo = -1):
+ (Family, ToolChain, Flag) = ('', '', '')
+ if String.find(TAB_EQUAL_SPLIT) < 0:
+ RaiseParserError(String, 'BuildOptions', File, '[<Family>:]<ToolFlag>=Flag', LineNo)
+ else:
+ List = GetSplitValueList(String, TAB_EQUAL_SPLIT, MaxSplit = 1)
+ if List[0].find(':') > -1:
+ Family = List[0][ : List[0].find(':')].strip()
+ ToolChain = List[0][List[0].find(':') + 1 : ].strip()
+ else:
+ ToolChain = List[0].strip()
+ Flag = List[1].strip()
+ return (Family, ToolChain, Flag)
+
+## Get Library Class
+#
+# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance>
+#
+# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance>
+# @param ContainerFile: The file which describes the library class, used for error report
+#
+# @retval (LibraryClassKeyWord, LibraryInstance, [SUP_MODULE_LIST]) Formatted Library Item
+#
+def GetLibraryClass(Item, ContainerFile, WorkspaceDir, LineNo = -1):
+ List = GetSplitValueList(Item[0])
+ SupMod = SUP_MODULE_LIST_STRING
+ if len(List) != 2:
+ RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, '<LibraryClassKeyWord>|<LibraryInstance>')
+ else:
+ CheckFileType(List[1], '.Inf', ContainerFile, 'library class instance', Item[0], LineNo)
+ CheckFileExist(WorkspaceDir, List[1], ContainerFile, 'LibraryClasses', Item[0], LineNo)
+ if Item[1] != '':
+ SupMod = Item[1]
+
+ return (List[0], List[1], SupMod)
+
+## Get Library Class
+#
+# Get Library of Dsc as <LibraryClassKeyWord>[|<LibraryInstance>][|<TokenSpaceGuidCName>.<PcdCName>]
+#
+# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance>
+# @param ContainerFile: The file which describes the library class, used for error report
+#
+# @retval (LibraryClassKeyWord, LibraryInstance, [SUP_MODULE_LIST]) Formatted Library Item
+#
+def GetLibraryClassOfInf(Item, ContainerFile, WorkspaceDir, LineNo = -1):
+ ItemList = GetSplitValueList((Item[0] + DataType.TAB_VALUE_SPLIT * 2))
+ SupMod = SUP_MODULE_LIST_STRING
+
+ if len(ItemList) > 5:
+ RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, '<LibraryClassKeyWord>[|<LibraryInstance>][|<TokenSpaceGuidCName>.<PcdCName>]')
+ else:
+ CheckFileType(ItemList[1], '.Inf', ContainerFile, 'LibraryClasses', Item[0], LineNo)
+ CheckFileExist(WorkspaceDir, ItemList[1], ContainerFile, 'LibraryClasses', Item[0], LineNo)
+ if ItemList[2] != '':
+ CheckPcdTokenInfo(ItemList[2], 'LibraryClasses', ContainerFile, LineNo)
+ if Item[1] != '':
+ SupMod = Item[1]
+
+ return (ItemList[0], ItemList[1], ItemList[2], SupMod)
+
+## CheckPcdTokenInfo
+#
+# Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName>
+#
+# @param TokenInfoString: String to be checked
+# @param Section: Used for error report
+# @param File: Used for error report
+#
+# @retval True PcdTokenInfo is in correct format
+#
+def CheckPcdTokenInfo(TokenInfoString, Section, File, LineNo = -1):
+ Format = '<TokenSpaceGuidCName>.<PcdCName>'
+ if TokenInfoString != '' and TokenInfoString is not None:
+ TokenInfoList = GetSplitValueList(TokenInfoString, TAB_SPLIT)
+ if len(TokenInfoList) == 2:
+ return True
+
+ RaiseParserError(TokenInfoString, Section, File, Format, LineNo)
+
+## Get Pcd
+#
+# Get Pcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>]
+#
+# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>]
+# @param ContainerFile: The file which describes the pcd, used for error report
+#
+# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], Type)
+#
+def GetPcd(Item, Type, ContainerFile, LineNo = -1):
+ TokenGuid, TokenName, Value, MaximumDatumSize, Token = '', '', '', '', ''
+ List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2)
+
+ if len(List) < 4 or len(List) > 6:
+ RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>]', LineNo)
+ else:
+ Value = List[1]
+ MaximumDatumSize = List[2]
+ Token = List[3]
+
+ if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
+ (TokenGuid, TokenName) = GetSplitValueList(List[0], TAB_SPLIT)
+
+ return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type)
+
+## Get FeatureFlagPcd
+#
+# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
+#
+# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
+# @param ContainerFile: The file which describes the pcd, used for error report
+#
+# @retval (TokenInfo[1], TokenInfo[0], List[1], Type)
+#
+def GetFeatureFlagPcd(Item, Type, ContainerFile, LineNo = -1):
+ TokenGuid, TokenName, Value = '', '', ''
+ List = GetSplitValueList(Item)
+ if len(List) != 2:
+ RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE', LineNo)
+ else:
+ Value = List[1]
+ if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
+ (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
+
+ return (TokenName, TokenGuid, Value, Type)
+
+## Get DynamicDefaultPcd
+#
+# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<DatumTyp>[|<MaxDatumSize>]]
+#
+# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
+# @param ContainerFile: The file which describes the pcd, used for error report
+#
+# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], Type)
+#
+def GetDynamicDefaultPcd(Item, Type, ContainerFile, LineNo = -1):
+ TokenGuid, TokenName, Value, DatumTyp, MaxDatumSize = '', '', '', '', ''
+ List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2)
+ if len(List) < 4 or len(List) > 8:
+ RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<DatumTyp>[|<MaxDatumSize>]]', LineNo)
+ else:
+ Value = List[1]
+ DatumTyp = List[2]
+ MaxDatumSize = List[3]
+ if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
+ (TokenGuid, TokenName) = GetSplitValueList(List[0], TAB_SPLIT)
+
+ return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type)
+
+## Get DynamicHiiPcd
+#
+# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>|<VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]
+#
+# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
+# @param ContainerFile: The file which describes the pcd, used for error report
+#
+# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], List[4], List[5], Type)
+#
+def GetDynamicHiiPcd(Item, Type, ContainerFile, LineNo = -1):
+ TokenGuid, TokenName, L1, L2, L3, L4, L5 = '', '', '', '', '', '', ''
+ List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2)
+ if len(List) < 6 or len(List) > 8:
+ RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|<String>|<VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]', LineNo)
+ else:
+ L1, L2, L3, L4, L5 = List[1], List[2], List[3], List[4], List[5]
+ if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
+ (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
+
+ return (TokenName, TokenGuid, L1, L2, L3, L4, L5, Type)
+
+## Get DynamicVpdPcd
+#
+# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>[|<MaximumDatumSize>]
+#
+# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
+# @param ContainerFile: The file which describes the pcd, used for error report
+#
+# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], Type)
+#
+def GetDynamicVpdPcd(Item, Type, ContainerFile, LineNo = -1):
+ TokenGuid, TokenName, L1, L2 = '', '', '', ''
+ List = GetSplitValueList(Item + TAB_VALUE_SPLIT)
+ if len(List) < 3 or len(List) > 4:
+ RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>[|<MaximumDatumSize>]', LineNo)
+ else:
+ L1, L2 = List[1], List[2]
+ if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
+ (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
+
+ return (TokenName, TokenGuid, L1, L2, Type)
+
+## GetComponent
+#
+# Parse block of the components defined in dsc file
+# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
+#
+# @param Lines: The content to be parsed
+# @param KeyValues: To store data after parsing
+#
+# @retval True Get component successfully
+#
+def GetComponent(Lines, KeyValues):
+ (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)
+ ListItem = None
+ LibraryClassItem = []
+ BuildOption = []
+ Pcd = []
+
+ for Line in Lines:
+ Line = Line[0]
+
+ #
+ # Ignore !include statement
+ #
+ if Line.upper().find(TAB_INCLUDE.upper() + ' ') > -1 or Line.upper().find(TAB_DEFINE + ' ') > -1:
+ continue
+
+ if findBlock == False:
+ ListItem = Line
+ #
+ # find '{' at line tail
+ #
+ if Line.endswith('{'):
+ findBlock = True
+ ListItem = CleanString(Line.rsplit('{', 1)[0], DataType.TAB_COMMENT_SPLIT)
+
+ #
+ # Parse a block content
+ #
+ if findBlock:
+ if Line.find('<LibraryClasses>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (True, False, False, False, False, False, False)
+ continue
+ if Line.find('<BuildOptions>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, True, False, False, False, False, False)
+ continue
+ if Line.find('<PcdsFeatureFlag>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, True, False, False, False, False)
+ continue
+ if Line.find('<PcdsPatchableInModule>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, True, False, False, False)
+ continue
+ if Line.find('<PcdsFixedAtBuild>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, True, False, False)
+ continue
+ if Line.find('<PcdsDynamic>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, True, False)
+ continue
+ if Line.find('<PcdsDynamicEx>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, True)
+ continue
+ if Line.endswith('}'):
+ #
+ # find '}' at line tail
+ #
+ KeyValues.append([ListItem, LibraryClassItem, BuildOption, Pcd])
+ (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)
+ LibraryClassItem, BuildOption, Pcd = [], [], []
+ continue
+
+ if findBlock:
+ if findLibraryClass:
+ LibraryClassItem.append(Line)
+ elif findBuildOption:
+ BuildOption.append(Line)
+ elif findPcdsFeatureFlag:
+ Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG_NULL, Line))
+ elif findPcdsPatchableInModule:
+ Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE_NULL, Line))
+ elif findPcdsFixedAtBuild:
+ Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD_NULL, Line))
+ elif findPcdsDynamic:
+ Pcd.append((DataType.TAB_PCDS_DYNAMIC_DEFAULT_NULL, Line))
+ elif findPcdsDynamicEx:
+ Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, Line))
+ else:
+ KeyValues.append([ListItem, [], [], []])
+
+ return True
+
+## GetExec
+#
+# Parse a string with format "InfFilename [EXEC = ExecFilename]"
+# Return (InfFilename, ExecFilename)
+#
+# @param String: String with EXEC statement
+#
+# @retval truple() A pair as (InfFilename, ExecFilename)
+#
+def GetExec(String):
+ InfFilename = ''
+ ExecFilename = ''
+ if String.find('EXEC') > -1:
+ InfFilename = String[ : String.find('EXEC')].strip()
+ ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip()
+ else:
+ InfFilename = String.strip()
+
+ return (InfFilename, ExecFilename)
+
+## GetComponents
+#
+# Parse block of the components defined in dsc file
+# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
+#
+# @param Lines: The content to be parsed
+# @param Key: Reserved
+# @param KeyValues: To store data after parsing
+# @param CommentCharacter: Comment char, used to ignore comment content
+#
+# @retval True Get component successfully
+#
+def GetComponents(Lines, Key, KeyValues, CommentCharacter):
+ if Lines.find(DataType.TAB_SECTION_END) > -1:
+ Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
+ (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)
+ ListItem = None
+ LibraryClassItem = []
+ BuildOption = []
+ Pcd = []
+
+ LineList = Lines.split('\n')
+ for Line in LineList:
+ Line = CleanString(Line, CommentCharacter)
+ if Line is None or Line == '':
+ continue
+
+ if findBlock == False:
+ ListItem = Line
+ #
+ # find '{' at line tail
+ #
+ if Line.endswith('{'):
+ findBlock = True
+ ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter)
+
+ #
+ # Parse a block content
+ #
+ if findBlock:
+ if Line.find('<LibraryClasses>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (True, False, False, False, False, False, False)
+ continue
+ if Line.find('<BuildOptions>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, True, False, False, False, False, False)
+ continue
+ if Line.find('<PcdsFeatureFlag>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, True, False, False, False, False)
+ continue
+ if Line.find('<PcdsPatchableInModule>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, True, False, False, False)
+ continue
+ if Line.find('<PcdsFixedAtBuild>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, True, False, False)
+ continue
+ if Line.find('<PcdsDynamic>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, True, False)
+ continue
+ if Line.find('<PcdsDynamicEx>') != -1:
+ (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, True)
+ continue
+ if Line.endswith('}'):
+ #
+ # find '}' at line tail
+ #
+ KeyValues.append([ListItem, LibraryClassItem, BuildOption, Pcd])
+ (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)
+ LibraryClassItem, BuildOption, Pcd = [], [], []
+ continue
+
+ if findBlock:
+ if findLibraryClass:
+ LibraryClassItem.append(Line)
+ elif findBuildOption:
+ BuildOption.append(Line)
+ elif findPcdsFeatureFlag:
+ Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line))
+ elif findPcdsPatchableInModule:
+ Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line))
+ elif findPcdsFixedAtBuild:
+ Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line))
+ elif findPcdsDynamic:
+ Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line))
+ elif findPcdsDynamicEx:
+ Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line))
+ else:
+ KeyValues.append([ListItem, [], [], []])
+
+ return True
+
+## Get Source
+#
+# Get Source of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
+#
+# @param Item: String as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
+# @param ContainerFile: The file which describes the library class, used for error report
+#
+# @retval (List[0], List[1], List[2], List[3], List[4])
+#
+def GetSource(Item, ContainerFile, FileRelativePath, LineNo = -1):
+ ItemNew = Item + DataType.TAB_VALUE_SPLIT * 4
+ List = GetSplitValueList(ItemNew)
+ if len(List) < 5 or len(List) > 9:
+ RaiseParserError(Item, 'Sources', ContainerFile, '<Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]', LineNo)
+ List[0] = NormPath(List[0])
+ CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Sources', Item, LineNo)
+ if List[4] != '':
+ CheckPcdTokenInfo(List[4], 'Sources', ContainerFile, LineNo)
+
+ return (List[0], List[1], List[2], List[3], List[4])
+
+## Get Binary
+#
+# Get Binary of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
+#
+# @param Item: String as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
+# @param ContainerFile: The file which describes the library class, used for error report
+#
+# @retval (List[0], List[1], List[2], List[3])
+# @retval List
+#
+def GetBinary(Item, ContainerFile, FileRelativePath, LineNo = -1):
+ ItemNew = Item + DataType.TAB_VALUE_SPLIT
+ List = GetSplitValueList(ItemNew)
+ if len(List) != 4 and len(List) != 5:
+ RaiseParserError(Item, 'Binaries', ContainerFile, "<FileType>|<Filename>|<Target>[|<TokenSpaceGuidCName>.<PcdCName>]", LineNo)
+ else:
+ if List[3] != '':
+ CheckPcdTokenInfo(List[3], 'Binaries', ContainerFile, LineNo)
+
+ if len(List) == 4:
+ return (List[0], List[1], List[2], List[3])
+ elif len(List) == 3:
+ return (List[0], List[1], List[2], '')
+ elif len(List) == 2:
+ return (List[0], List[1], '', '')
+ elif len(List) == 1:
+ return (List[0], '', '', '')
+
+## Get Guids/Protocols/Ppis
+#
+# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>]
+#
+# @param Item: String as <GuidCName>[|<PcdFeatureFlag>]
+# @param Type: Type of parsing string
+# @param ContainerFile: The file which describes the library class, used for error report
+#
+# @retval (List[0], List[1])
+#
+def GetGuidsProtocolsPpisOfInf(Item, Type, ContainerFile, LineNo = -1):
+ ItemNew = Item + TAB_VALUE_SPLIT
+ List = GetSplitValueList(ItemNew)
+ if List[1] != '':
+ CheckPcdTokenInfo(List[1], Type, ContainerFile, LineNo)
+
+ return (List[0], List[1])
+
+## Get Guids/Protocols/Ppis
+#
+# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue>
+#
+# @param Item: String as <GuidCName>=<GuidValue>
+# @param Type: Type of parsing string
+# @param ContainerFile: The file which describes the library class, used for error report
+#
+# @retval (List[0], List[1])
+#
+def GetGuidsProtocolsPpisOfDec(Item, Type, ContainerFile, LineNo = -1):
+ List = GetSplitValueList(Item, DataType.TAB_EQUAL_SPLIT)
+ if len(List) != 2:
+ RaiseParserError(Item, Type, ContainerFile, '<CName>=<GuidValue>', LineNo)
+
+ return (List[0], List[1])
+
+## GetPackage
+#
+# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>]
+#
+# @param Item: String as <PackagePath>[|<PcdFeatureFlag>]
+# @param Type: Type of parsing string
+# @param ContainerFile: The file which describes the library class, used for error report
+#
+# @retval (List[0], List[1])
+#
+def GetPackage(Item, ContainerFile, FileRelativePath, LineNo = -1):
+ ItemNew = Item + TAB_VALUE_SPLIT
+ List = GetSplitValueList(ItemNew)
+ CheckFileType(List[0], '.Dec', ContainerFile, 'package', List[0], LineNo)
+ CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Packages', List[0], LineNo)
+
+ if List[1] != '':
+ CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo)
+
+ return (List[0], List[1])
+
+## Get Pcd Values of Inf
+#
+# Get Pcd of Inf as <TokenSpaceGuidCName>.<PcdCName>[|<Value>]
+#
+# @param Item: The string describes pcd
+# @param Type: The type of Pcd
+# @param File: The file which describes the pcd, used for error report
+#
+# @retval (TokenSpcCName, TokenCName, Value, ItemType) Formatted Pcd Item
+#
+def GetPcdOfInf(Item, Type, File, LineNo):
+ Format = '<TokenSpaceGuidCName>.<PcdCName>[|<Value>]'
+ TokenGuid, TokenName, Value, InfType = '', '', '', ''
+
+ if Type == TAB_PCDS_FIXED_AT_BUILD:
+ InfType = TAB_INF_FIXED_PCD
+ elif Type == TAB_PCDS_PATCHABLE_IN_MODULE:
+ InfType = TAB_INF_PATCH_PCD
+ elif Type == TAB_PCDS_FEATURE_FLAG:
+ InfType = TAB_INF_FEATURE_PCD
+ elif Type == TAB_PCDS_DYNAMIC_EX:
+ InfType = TAB_INF_PCD_EX
+ elif Type == TAB_PCDS_DYNAMIC:
+ InfType = TAB_INF_PCD
+ List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT)
+ if len(List) < 2 or len(List) > 3:
+ RaiseParserError(Item, InfType, File, Format, LineNo)
+ else:
+ Value = List[1]
+ TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
+ if len(TokenInfo) != 2:
+ RaiseParserError(Item, InfType, File, Format, LineNo)
+ else:
+ TokenGuid = TokenInfo[0]
+ TokenName = TokenInfo[1]
+
+ return (TokenGuid, TokenName, Value, Type)
+
+
+## Get Pcd Values of Dec
+#
+# Get Pcd of Dec as <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token>
+# @retval (TokenSpcCName, TokenCName, Value, DatumType, Token, ItemType) Formatted Pcd Item
+#
+def GetPcdOfDec(Item, Type, File, LineNo = -1):
+ Format = '<TokenSpaceGuidCName>.<PcdCName>|<Value>|<DatumType>|<Token>'
+ TokenGuid, TokenName, Value, DatumType, Token = '', '', '', '', ''
+ List = GetSplitValueList(Item)
+ if len(List) != 4:
+ RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
+ else:
+ Value = List[1]
+ DatumType = List[2]
+ Token = List[3]
+ TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
+ if len(TokenInfo) != 2:
+ RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
+ else:
+ TokenGuid = TokenInfo[0]
+ TokenName = TokenInfo[1]
+
+ return (TokenGuid, TokenName, Value, DatumType, Token, Type)
+
+## Parse DEFINE statement
+#
+# Get DEFINE macros
+#
+# 1. Insert a record into TblDec
+# Value1: Macro Name
+# Value2: Macro Value
+#
+def ParseDefine(LineValue, StartLine, Table, FileID, Filename, SectionName, SectionModel, Arch):
+ EdkLogger.debug(EdkLogger.DEBUG_2, "DEFINE statement '%s' found in section %s" % (LineValue, SectionName))
+ Define = GetSplitValueList(CleanString(LineValue[LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') + len(DataType.TAB_DEFINE + ' ') : ]), TAB_EQUAL_SPLIT, 1)
+ Table.Insert(MODEL_META_DATA_DEFINE, Define[0], Define[1], '', '', '', Arch, SectionModel, FileID, StartLine, -1, StartLine, -1, 0)
+
+## InsertSectionItems
+#
+# Insert item data of a section to a dict
+#
+def InsertSectionItems(Model, CurrentSection, SectionItemList, ArchList, ThirdList, RecordSet):
+ # Insert each item data of a section
+ for Index in range(0, len(ArchList)):
+ Arch = ArchList[Index]
+ Third = ThirdList[Index]
+ if Arch == '':
+ Arch = TAB_ARCH_COMMON
+
+ Records = RecordSet[Model]
+ for SectionItem in SectionItemList:
+ BelongsToItem, EndLine, EndColumn = -1, -1, -1
+ LineValue, StartLine, EndLine, Comment = SectionItem[0], SectionItem[1], SectionItem[1], SectionItem[2]
+
+ EdkLogger.debug(4, "Parsing %s ..." %LineValue)
+ # And then parse DEFINE statement
+ if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1:
+ continue
+
+ # At last parse other sections
+ ID = -1
+ Records.append([LineValue, Arch, StartLine, ID, Third, Comment])
+
+ if RecordSet != {}:
+ RecordSet[Model] = Records
+
+## Insert records to database
+#
+# Insert item data of a section to database
+# @param Table: The Table to be inserted
+# @param FileID: The ID of belonging file
+# @param Filename: The name of belonging file
+# @param CurrentSection: The name of current section
+# @param SectionItemList: A list of items of the section
+# @param ArchList: A list of arches
+# @param ThirdList: A list of third parameters, ModuleType for LibraryClass and SkuId for Dynamic Pcds
+# @param IfDefList: A list of all conditional statements
+# @param RecordSet: A dict of all parsed records
+#
+def InsertSectionItemsIntoDatabase(Table, FileID, Filename, Model, CurrentSection, SectionItemList, ArchList, ThirdList, IfDefList, RecordSet):
+ #
+ # Insert each item data of a section
+ #
+ for Index in range(0, len(ArchList)):
+ Arch = ArchList[Index]
+ Third = ThirdList[Index]
+ if Arch == '':
+ Arch = TAB_ARCH_COMMON
+
+ Records = RecordSet[Model]
+ for SectionItem in SectionItemList:
+ BelongsToItem, EndLine, EndColumn = -1, -1, -1
+ LineValue, StartLine, EndLine = SectionItem[0], SectionItem[1], SectionItem[1]
+
+ EdkLogger.debug(4, "Parsing %s ..." %LineValue)
+ #
+ # And then parse DEFINE statement
+ #
+ if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1:
+ ParseDefine(LineValue, StartLine, Table, FileID, Filename, CurrentSection, Model, Arch)
+ continue
+
+ #
+ # At last parse other sections
+ #
+ ID = Table.Insert(Model, LineValue, Third, Third, '', '', Arch, -1, FileID, StartLine, -1, StartLine, -1, 0)
+ Records.append([LineValue, Arch, StartLine, ID, Third])
+
+ if RecordSet != {}:
+ RecordSet[Model] = Records
+
+## GenMetaDatSectionItem
+def GenMetaDatSectionItem(Key, Value, List):
+ if Key not in List:
+ List[Key] = [Value]
+ else:
+ List[Key].append(Value)
+
+## IsValidWord
+#
+# Check whether the word is valid.
+# <Word> ::= (a-zA-Z0-9_)(a-zA-Z0-9_-){0,} Alphanumeric characters with
+# optional
+# dash "-" and/or underscore "_" characters. No whitespace
+# characters are permitted.
+#
+# @param Word: The word string need to be checked.
+#
+def IsValidWord(Word):
+ if not Word:
+ return False
+ #
+ # The first char should be alpha, _ or Digit.
+ #
+ if not Word[0].isalnum() and \
+ not Word[0] == '_' and \
+ not Word[0].isdigit():
+ return False
+
+ LastChar = ''
+ for Char in Word[1:]:
+ if (not Char.isalpha()) and \
+ (not Char.isdigit()) and \
+ Char != '-' and \
+ Char != '_' and \
+ Char != '.':
+ return False
+ if Char == '.' and LastChar == '.':
+ return False
+ LastChar = Char
+
+ return True
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/RangeExpression.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/RangeExpression.py
new file mode 100755
index 00000000..88a177a4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/RangeExpression.py
@@ -0,0 +1,694 @@
+# # @file
+# This file is used to parse and evaluate range expression in Pcd declaration.
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+
+# # Import Modules
+#
+from __future__ import print_function
+from Common.GlobalData import *
+from CommonDataClass.Exceptions import BadExpression
+from CommonDataClass.Exceptions import WrnExpression
+import uuid
+from Common.Expression import PcdPattern, BaseExpression
+from Common.DataType import *
+from re import compile
+
+ERR_STRING_EXPR = 'This operator cannot be used in string expression: [%s].'
+ERR_SNYTAX = 'Syntax error, the rest of expression cannot be evaluated: [%s].'
+ERR_MATCH = 'No matching right parenthesis.'
+ERR_STRING_TOKEN = 'Bad string token: [%s].'
+ERR_MACRO_TOKEN = 'Bad macro token: [%s].'
+ERR_EMPTY_TOKEN = 'Empty token is not allowed.'
+ERR_PCD_RESOLVE = 'The PCD should be FeatureFlag type or FixedAtBuild type: [%s].'
+ERR_VALID_TOKEN = 'No more valid token found from rest of string: [%s].'
+ERR_EXPR_TYPE = 'Different types found in expression.'
+ERR_OPERATOR_UNSUPPORT = 'Unsupported operator: [%s]'
+ERR_REL_NOT_IN = 'Expect "IN" after "not" operator.'
+WRN_BOOL_EXPR = 'Operand of boolean type cannot be used in arithmetic expression.'
+WRN_EQCMP_STR_OTHERS = '== Comparison between Operand of string type and Boolean/Number Type always return False.'
+WRN_NECMP_STR_OTHERS = '!= Comparison between Operand of string type and Boolean/Number Type always return True.'
+ERR_RELCMP_STR_OTHERS = 'Operator taking Operand of string type and Boolean/Number Type is not allowed: [%s].'
+ERR_STRING_CMP = 'Unicode string and general string cannot be compared: [%s %s %s]'
+ERR_ARRAY_TOKEN = 'Bad C array or C format GUID token: [%s].'
+ERR_ARRAY_ELE = 'This must be HEX value for NList or Array: [%s].'
+ERR_EMPTY_EXPR = 'Empty expression is not allowed.'
+ERR_IN_OPERAND = 'Macro after IN operator can only be: $(FAMILY), $(ARCH), $(TOOL_CHAIN_TAG) and $(TARGET).'
+
+class RangeObject(object):
+ def __init__(self, start, end, empty = False):
+
+ if int(start) < int(end):
+ self.start = int(start)
+ self.end = int(end)
+ else:
+ self.start = int(end)
+ self.end = int(start)
+ self.empty = empty
+
+class RangeContainer(object):
+ def __init__(self):
+ self.rangelist = []
+
+ def push(self, RangeObject):
+ self.rangelist.append(RangeObject)
+ self.rangelist = sorted(self.rangelist, key = lambda rangeobj : rangeobj.start)
+ self.merge()
+
+ def pop(self):
+ for item in self.rangelist:
+ yield item
+
+ def __clean__(self):
+ newrangelist = []
+ for rangeobj in self.rangelist:
+ if rangeobj.empty == True:
+ continue
+ else:
+ newrangelist.append(rangeobj)
+ self.rangelist = newrangelist
+ def merge(self):
+ self.__clean__()
+ for i in range(0, len(self.rangelist) - 1):
+ if self.rangelist[i + 1].start > self.rangelist[i].end:
+ continue
+ else:
+ self.rangelist[i + 1].start = self.rangelist[i].start
+ self.rangelist[i + 1].end = self.rangelist[i + 1].end > self.rangelist[i].end and self.rangelist[i + 1].end or self.rangelist[i].end
+ self.rangelist[i].empty = True
+
+ self.__clean__()
+
+ def dump(self):
+ print("----------------------")
+ rangelist = ""
+ for object in self.rangelist:
+ rangelist = rangelist + "[%d , %d]" % (object.start, object.end)
+ print(rangelist)
+
+
+class XOROperatorObject(object):
+ def __init__(self):
+ pass
+ def Calculate(self, Operand, DataType, SymbolTable):
+ if isinstance(Operand, type('')) and not Operand.isalnum():
+ Expr = "XOR ..."
+ raise BadExpression(ERR_SNYTAX % Expr)
+ rangeId = str(uuid.uuid1())
+ rangeContainer = RangeContainer()
+ rangeContainer.push(RangeObject(0, int(Operand) - 1))
+ rangeContainer.push(RangeObject(int(Operand) + 1, MAX_VAL_TYPE[DataType]))
+ SymbolTable[rangeId] = rangeContainer
+ return rangeId
+
+class LEOperatorObject(object):
+ def __init__(self):
+ pass
+ def Calculate(self, Operand, DataType, SymbolTable):
+ if isinstance(Operand, type('')) and not Operand.isalnum():
+ Expr = "LE ..."
+ raise BadExpression(ERR_SNYTAX % Expr)
+ rangeId1 = str(uuid.uuid1())
+ rangeContainer = RangeContainer()
+ rangeContainer.push(RangeObject(0, int(Operand)))
+ SymbolTable[rangeId1] = rangeContainer
+ return rangeId1
+class LTOperatorObject(object):
+ def __init__(self):
+ pass
+ def Calculate(self, Operand, DataType, SymbolTable):
+ if isinstance(Operand, type('')) and not Operand.isalnum():
+ Expr = "LT ..."
+ raise BadExpression(ERR_SNYTAX % Expr)
+ rangeId1 = str(uuid.uuid1())
+ rangeContainer = RangeContainer()
+ rangeContainer.push(RangeObject(0, int(Operand) - 1))
+ SymbolTable[rangeId1] = rangeContainer
+ return rangeId1
+
+class GEOperatorObject(object):
+ def __init__(self):
+ pass
+ def Calculate(self, Operand, DataType, SymbolTable):
+ if isinstance(Operand, type('')) and not Operand.isalnum():
+ Expr = "GE ..."
+ raise BadExpression(ERR_SNYTAX % Expr)
+ rangeId1 = str(uuid.uuid1())
+ rangeContainer = RangeContainer()
+ rangeContainer.push(RangeObject(int(Operand), MAX_VAL_TYPE[DataType]))
+ SymbolTable[rangeId1] = rangeContainer
+ return rangeId1
+
+class GTOperatorObject(object):
+ def __init__(self):
+ pass
+ def Calculate(self, Operand, DataType, SymbolTable):
+ if isinstance(Operand, type('')) and not Operand.isalnum():
+ Expr = "GT ..."
+ raise BadExpression(ERR_SNYTAX % Expr)
+ rangeId1 = str(uuid.uuid1())
+ rangeContainer = RangeContainer()
+ rangeContainer.push(RangeObject(int(Operand) + 1, MAX_VAL_TYPE[DataType]))
+ SymbolTable[rangeId1] = rangeContainer
+ return rangeId1
+
+class EQOperatorObject(object):
+ def __init__(self):
+ pass
+ def Calculate(self, Operand, DataType, SymbolTable):
+ if isinstance(Operand, type('')) and not Operand.isalnum():
+ Expr = "EQ ..."
+ raise BadExpression(ERR_SNYTAX % Expr)
+ rangeId1 = str(uuid.uuid1())
+ rangeContainer = RangeContainer()
+ rangeContainer.push(RangeObject(int(Operand), int(Operand)))
+ SymbolTable[rangeId1] = rangeContainer
+ return rangeId1
+
+def GetOperatorObject(Operator):
+ if Operator == '>':
+ return GTOperatorObject()
+ elif Operator == '>=':
+ return GEOperatorObject()
+ elif Operator == '<':
+ return LTOperatorObject()
+ elif Operator == '<=':
+ return LEOperatorObject()
+ elif Operator == '==':
+ return EQOperatorObject()
+ elif Operator == '^':
+ return XOROperatorObject()
+ else:
+ raise BadExpression("Bad Operator")
+
+class RangeExpression(BaseExpression):
+ # Logical operator mapping
+ LogicalOperators = {
+ '&&' : 'and', '||' : 'or',
+ '!' : 'not', 'AND': 'and',
+ 'OR' : 'or' , 'NOT': 'not',
+ 'XOR': '^' , 'xor': '^',
+ 'EQ' : '==' , 'NE' : '!=',
+ 'GT' : '>' , 'LT' : '<',
+ 'GE' : '>=' , 'LE' : '<=',
+ 'IN' : 'in'
+ }
+
+ NonLetterOpLst = ['+', '-', '&', '|', '^', '!', '=', '>', '<']
+
+ RangePattern = compile(r'[0-9]+ - [0-9]+')
+
+ def preProcessRangeExpr(self, expr):
+ # convert hex to int
+ # convert interval to object index. ex. 1 - 10 to a GUID
+ expr = expr.strip()
+ NumberDict = {}
+ for HexNumber in gHexPattern.findall(expr):
+ Number = str(int(HexNumber, 16))
+ NumberDict[HexNumber] = Number
+ for HexNum in NumberDict:
+ expr = expr.replace(HexNum, NumberDict[HexNum])
+
+ rangedict = {}
+ for validrange in self.RangePattern.findall(expr):
+ start, end = validrange.split(" - ")
+ start = start.strip()
+ end = end.strip()
+ rangeid = str(uuid.uuid1())
+ rangeContainer = RangeContainer()
+ rangeContainer.push(RangeObject(start, end))
+ self.operanddict[str(rangeid)] = rangeContainer
+ rangedict[validrange] = str(rangeid)
+
+ for validrange in rangedict:
+ expr = expr.replace(validrange, rangedict[validrange])
+
+ self._Expr = expr
+ return expr
+
+
+ def EvalRange(self, Operator, Oprand):
+
+ operatorobj = GetOperatorObject(Operator)
+ return operatorobj.Calculate(Oprand, self.PcdDataType, self.operanddict)
+
+ def Rangeintersection(self, Oprand1, Oprand2):
+ rangeContainer1 = self.operanddict[Oprand1]
+ rangeContainer2 = self.operanddict[Oprand2]
+ rangeContainer = RangeContainer()
+ for range1 in rangeContainer1.pop():
+ for range2 in rangeContainer2.pop():
+ start1 = range1.start
+ end1 = range1.end
+ start2 = range2.start
+ end2 = range2.end
+ if start1 >= start2:
+ start1, start2 = start2, start1
+ end1, end2 = end2, end1
+ if range1.empty:
+ rangeid = str(uuid.uuid1())
+ rangeContainer.push(RangeObject(0, 0, True))
+ if end1 < start2:
+ rangeid = str(uuid.uuid1())
+ rangeContainer.push(RangeObject(0, 0, True))
+ elif end1 == start2:
+ rangeid = str(uuid.uuid1())
+ rangeContainer.push(RangeObject(end1, end1))
+ elif end1 <= end2 and end1 > start2:
+ rangeid = str(uuid.uuid1())
+ rangeContainer.push(RangeObject(start2, end1))
+ elif end1 >= end2:
+ rangeid = str(uuid.uuid1())
+ rangeContainer.push(RangeObject(start2, end2))
+
+ self.operanddict[rangeid] = rangeContainer
+# rangeContainer.dump()
+ return rangeid
+
+ def Rangecollections(self, Oprand1, Oprand2):
+
+ rangeContainer1 = self.operanddict[Oprand1]
+ rangeContainer2 = self.operanddict[Oprand2]
+ rangeContainer = RangeContainer()
+
+ for rangeobj in rangeContainer2.pop():
+ rangeContainer.push(rangeobj)
+ for rangeobj in rangeContainer1.pop():
+ rangeContainer.push(rangeobj)
+
+ rangeid = str(uuid.uuid1())
+ self.operanddict[rangeid] = rangeContainer
+
+# rangeContainer.dump()
+ return rangeid
+
+
+ def NegativeRange(self, Oprand1):
+ rangeContainer1 = self.operanddict[Oprand1]
+
+
+ rangeids = []
+
+ for rangeobj in rangeContainer1.pop():
+ rangeContainer = RangeContainer()
+ rangeid = str(uuid.uuid1())
+ if rangeobj.empty:
+ rangeContainer.push(RangeObject(0, MAX_VAL_TYPE[self.PcdDataType]))
+ else:
+ if rangeobj.start > 0:
+ rangeContainer.push(RangeObject(0, rangeobj.start - 1))
+ if rangeobj.end < MAX_VAL_TYPE[self.PcdDataType]:
+ rangeContainer.push(RangeObject(rangeobj.end + 1, MAX_VAL_TYPE[self.PcdDataType]))
+ self.operanddict[rangeid] = rangeContainer
+ rangeids.append(rangeid)
+
+ if len(rangeids) == 0:
+ rangeContainer = RangeContainer()
+ rangeContainer.push(RangeObject(0, MAX_VAL_TYPE[self.PcdDataType]))
+ rangeid = str(uuid.uuid1())
+ self.operanddict[rangeid] = rangeContainer
+ return rangeid
+
+ if len(rangeids) == 1:
+ return rangeids[0]
+
+ re = self.Rangeintersection(rangeids[0], rangeids[1])
+ for i in range(2, len(rangeids)):
+ re = self.Rangeintersection(re, rangeids[i])
+
+ rangeid2 = str(uuid.uuid1())
+ self.operanddict[rangeid2] = self.operanddict[re]
+ return rangeid2
+
+ def Eval(self, Operator, Oprand1, Oprand2 = None):
+
+ if Operator in ["!", "NOT", "not"]:
+ if not gGuidPattern.match(Oprand1.strip()):
+ raise BadExpression(ERR_STRING_EXPR % Operator)
+ return self.NegativeRange(Oprand1)
+ else:
+ if Operator in ["==", ">=", "<=", ">", "<", '^']:
+ return self.EvalRange(Operator, Oprand1)
+ elif Operator == 'and' :
+ if not gGuidPatternEnd.match(Oprand1.strip()) or not gGuidPatternEnd.match(Oprand2.strip()):
+ raise BadExpression(ERR_STRING_EXPR % Operator)
+ return self.Rangeintersection(Oprand1, Oprand2)
+ elif Operator == 'or':
+ if not gGuidPatternEnd.match(Oprand1.strip()) or not gGuidPatternEnd.match(Oprand2.strip()):
+ raise BadExpression(ERR_STRING_EXPR % Operator)
+ return self.Rangecollections(Oprand1, Oprand2)
+ else:
+ raise BadExpression(ERR_STRING_EXPR % Operator)
+
+
+ def __init__(self, Expression, PcdDataType, SymbolTable = None):
+ if SymbolTable is None:
+ SymbolTable = {}
+ super(RangeExpression, self).__init__(self, Expression, PcdDataType, SymbolTable)
+ self._NoProcess = False
+ if not isinstance(Expression, type('')):
+ self._Expr = Expression
+ self._NoProcess = True
+ return
+
+ self._Expr = Expression.strip()
+
+ if not self._Expr.strip():
+ raise BadExpression(ERR_EMPTY_EXPR)
+
+ #
+ # The symbol table including PCD and macro mapping
+ #
+ self._Symb = SymbolTable
+ self._Symb.update(self.LogicalOperators)
+ self._Idx = 0
+ self._Len = len(self._Expr)
+ self._Token = ''
+ self._WarnExcept = None
+
+
+ # Literal token without any conversion
+ self._LiteralToken = ''
+
+ # store the operand object
+ self.operanddict = {}
+ # The Pcd max value depends on PcdDataType
+ self.PcdDataType = PcdDataType
+
+ # Public entry for this class
+ # @param RealValue: False: only evaluate if the expression is true or false, used for conditional expression
+ # True : return the evaluated str(value), used for PCD value
+ #
+ # @return: True or False if RealValue is False
+ # Evaluated value of string format if RealValue is True
+ #
+ def __call__(self, RealValue = False, Depth = 0):
+ if self._NoProcess:
+ return self._Expr
+
+ self._Depth = Depth
+
+ self._Expr = self._Expr.strip()
+
+ self.preProcessRangeExpr(self._Expr)
+
+ # check if the expression does not need to evaluate
+ if RealValue and Depth == 0:
+ self._Token = self._Expr
+ if gGuidPatternEnd.match(self._Expr):
+ return [self.operanddict[self._Expr] ]
+
+ self._Idx = 0
+ self._Token = ''
+
+ Val = self._OrExpr()
+ RealVal = Val
+
+ RangeIdList = RealVal.split("or")
+ RangeList = []
+ for rangeid in RangeIdList:
+ RangeList.append(self.operanddict[rangeid.strip()])
+
+ return RangeList
+
+ # Template function to parse binary operators which have same precedence
+ # Expr [Operator Expr]*
+ def _ExprFuncTemplate(self, EvalFunc, OpSet):
+ Val = EvalFunc()
+ while self._IsOperator(OpSet):
+ Op = self._Token
+ try:
+ Val = self.Eval(Op, Val, EvalFunc())
+ except WrnExpression as Warn:
+ self._WarnExcept = Warn
+ Val = Warn.result
+ return Val
+
+ # A [|| B]*
+ def _OrExpr(self):
+ return self._ExprFuncTemplate(self._AndExpr, {"OR", "or"})
+
+ # A [&& B]*
+ def _AndExpr(self):
+ return self._ExprFuncTemplate(self._NeExpr, {"AND", "and"})
+
+ def _NeExpr(self):
+ Val = self._RelExpr()
+ while self._IsOperator({"!=", "NOT", "not"}):
+ Op = self._Token
+ if Op in ["!", "NOT", "not"]:
+ if not self._IsOperator({"IN", "in"}):
+ raise BadExpression(ERR_REL_NOT_IN)
+ Op += ' ' + self._Token
+ try:
+ Val = self.Eval(Op, Val, self._RelExpr())
+ except WrnExpression as Warn:
+ self._WarnExcept = Warn
+ Val = Warn.result
+ return Val
+
+ # [!]*A
+ def _RelExpr(self):
+ if self._IsOperator({"NOT", "LE", "GE", "LT", "GT", "EQ", "XOR"}):
+ Token = self._Token
+ Val = self._NeExpr()
+ try:
+ return self.Eval(Token, Val)
+ except WrnExpression as Warn:
+ self._WarnExcept = Warn
+ return Warn.result
+ return self._IdenExpr()
+
+ # Parse identifier or encapsulated expression
+ def _IdenExpr(self):
+ Tk = self._GetToken()
+ if Tk == '(':
+ Val = self._OrExpr()
+ try:
+ # _GetToken may also raise BadExpression
+ if self._GetToken() != ')':
+ raise BadExpression(ERR_MATCH)
+ except BadExpression:
+ raise BadExpression(ERR_MATCH)
+ return Val
+ return Tk
+
+ # Skip whitespace or tab
+ def __SkipWS(self):
+ for Char in self._Expr[self._Idx:]:
+ if Char not in ' \t':
+ break
+ self._Idx += 1
+
+ # Try to convert string to number
+ def __IsNumberToken(self):
+ Radix = 10
+ if self._Token.lower()[0:2] == '0x' and len(self._Token) > 2:
+ Radix = 16
+ try:
+ self._Token = int(self._Token, Radix)
+ return True
+ except ValueError:
+ return False
+ except TypeError:
+ return False
+
+ # Parse array: {...}
+ def __GetArray(self):
+ Token = '{'
+ self._Idx += 1
+ self.__GetNList(True)
+ Token += self._LiteralToken
+ if self._Idx >= self._Len or self._Expr[self._Idx] != '}':
+ raise BadExpression(ERR_ARRAY_TOKEN % Token)
+ Token += '}'
+
+ # All whitespace and tabs in array are already stripped.
+ IsArray = IsGuid = False
+ if len(Token.split(',')) == 11 and len(Token.split(',{')) == 2 \
+ and len(Token.split('},')) == 1:
+ HexLen = [11, 6, 6, 5, 4, 4, 4, 4, 4, 4, 6]
+ HexList = Token.split(',')
+ if HexList[3].startswith('{') and \
+ not [Index for Index, Hex in enumerate(HexList) if len(Hex) > HexLen[Index]]:
+ IsGuid = True
+ if Token.lstrip('{').rstrip('}').find('{') == -1:
+ if not [Hex for Hex in Token.lstrip('{').rstrip('}').split(',') if len(Hex) > 4]:
+ IsArray = True
+ if not IsArray and not IsGuid:
+ raise BadExpression(ERR_ARRAY_TOKEN % Token)
+ self._Idx += 1
+ self._Token = self._LiteralToken = Token
+ return self._Token
+
+ # Parse string, the format must be: "..."
+ def __GetString(self):
+ Idx = self._Idx
+
+ # Skip left quote
+ self._Idx += 1
+
+ # Replace escape \\\", \"
+ Expr = self._Expr[self._Idx:].replace('\\\\', '//').replace('\\\"', '\\\'')
+ for Ch in Expr:
+ self._Idx += 1
+ if Ch == '"':
+ break
+ self._Token = self._LiteralToken = self._Expr[Idx:self._Idx]
+ if not self._Token.endswith('"'):
+ raise BadExpression(ERR_STRING_TOKEN % self._Token)
+ self._Token = self._Token[1:-1]
+ return self._Token
+
+ # Get token that is comprised by alphanumeric, underscore or dot(used by PCD)
+ # @param IsAlphaOp: Indicate if parsing general token or script operator(EQ, NE...)
+ def __GetIdToken(self, IsAlphaOp = False):
+ IdToken = ''
+ for Ch in self._Expr[self._Idx:]:
+ if not self.__IsIdChar(Ch):
+ break
+ self._Idx += 1
+ IdToken += Ch
+
+ self._Token = self._LiteralToken = IdToken
+ if not IsAlphaOp:
+ self.__ResolveToken()
+ return self._Token
+
+ # Try to resolve token
+ def __ResolveToken(self):
+ if not self._Token:
+ raise BadExpression(ERR_EMPTY_TOKEN)
+
+ # PCD token
+ if PcdPattern.match(self._Token):
+ if self._Token not in self._Symb:
+ Ex = BadExpression(ERR_PCD_RESOLVE % self._Token)
+ Ex.Pcd = self._Token
+ raise Ex
+ self._Token = RangeExpression(self._Symb[self._Token], self._Symb)(True, self._Depth + 1)
+ if not isinstance(self._Token, type('')):
+ self._LiteralToken = hex(self._Token)
+ return
+
+ if self._Token.startswith('"'):
+ self._Token = self._Token[1:-1]
+ elif self._Token in ["FALSE", "false", "False"]:
+ self._Token = False
+ elif self._Token in ["TRUE", "true", "True"]:
+ self._Token = True
+ else:
+ self.__IsNumberToken()
+
+ def __GetNList(self, InArray = False):
+ self._GetSingleToken()
+ if not self.__IsHexLiteral():
+ if InArray:
+ raise BadExpression(ERR_ARRAY_ELE % self._Token)
+ return self._Token
+
+ self.__SkipWS()
+ Expr = self._Expr[self._Idx:]
+ if not Expr.startswith(','):
+ return self._Token
+
+ NList = self._LiteralToken
+ while Expr.startswith(','):
+ NList += ','
+ self._Idx += 1
+ self.__SkipWS()
+ self._GetSingleToken()
+ if not self.__IsHexLiteral():
+ raise BadExpression(ERR_ARRAY_ELE % self._Token)
+ NList += self._LiteralToken
+ self.__SkipWS()
+ Expr = self._Expr[self._Idx:]
+ self._Token = self._LiteralToken = NList
+ return self._Token
+
+ def __IsHexLiteral(self):
+ if self._LiteralToken.startswith('{') and \
+ self._LiteralToken.endswith('}'):
+ return True
+
+ if gHexPattern.match(self._LiteralToken):
+ Token = self._LiteralToken[2:]
+ Token = Token.lstrip('0')
+ if not Token:
+ self._LiteralToken = '0x0'
+ else:
+ self._LiteralToken = '0x' + Token.lower()
+ return True
+ return False
+
+ def _GetToken(self):
+ return self.__GetNList()
+
+ @staticmethod
+ def __IsIdChar(Ch):
+ return Ch in '._/:' or Ch.isalnum()
+
+ # Parse operand
+ def _GetSingleToken(self):
+ self.__SkipWS()
+ Expr = self._Expr[self._Idx:]
+ if Expr.startswith('L"'):
+ # Skip L
+ self._Idx += 1
+ UStr = self.__GetString()
+ self._Token = 'L"' + UStr + '"'
+ return self._Token
+
+ self._Token = ''
+ if Expr:
+ Ch = Expr[0]
+ Match = gGuidPattern.match(Expr)
+ if Match and not Expr[Match.end():Match.end() + 1].isalnum() \
+ and Expr[Match.end():Match.end() + 1] != '_':
+ self._Idx += Match.end()
+ self._Token = Expr[0:Match.end()]
+ return self._Token
+ elif self.__IsIdChar(Ch):
+ return self.__GetIdToken()
+ elif Ch == '(' or Ch == ')':
+ self._Idx += 1
+ self._Token = Ch
+ return self._Token
+
+ raise BadExpression(ERR_VALID_TOKEN % Expr)
+
+ # Parse operator
+ def _GetOperator(self):
+ self.__SkipWS()
+ LegalOpLst = ['&&', '||', '!=', '==', '>=', '<='] + self.NonLetterOpLst
+
+ self._Token = ''
+ Expr = self._Expr[self._Idx:]
+
+ # Reach end of expression
+ if not Expr:
+ return ''
+
+ # Script operator: LT, GT, LE, GE, EQ, NE, and, or, xor, not
+ if Expr[0].isalpha():
+ return self.__GetIdToken(True)
+
+ # Start to get regular operator: +, -, <, > ...
+ if Expr[0] not in self.NonLetterOpLst:
+ return ''
+
+ OpToken = ''
+ for Ch in Expr:
+ if Ch in self.NonLetterOpLst:
+ if '!' == Ch and OpToken:
+ break
+ self._Idx += 1
+ OpToken += Ch
+ else:
+ break
+
+ if OpToken not in LegalOpLst:
+ raise BadExpression(ERR_OPERATOR_UNSUPPORT % OpToken)
+ self._Token = OpToken
+ return OpToken
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/StringUtils.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/StringUtils.py
new file mode 100755
index 00000000..904c39c9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/StringUtils.py
@@ -0,0 +1,873 @@
+## @file
+# This file is used to define common string related functions used in parsing process
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+##
+# Import Modules
+#
+from __future__ import absolute_import
+import re
+from . import DataType
+import Common.LongFilePathOs as os
+import string
+from . import EdkLogger as EdkLogger
+
+from . import GlobalData
+from .BuildToolError import *
+from CommonDataClass.Exceptions import *
+from Common.LongFilePathSupport import OpenLongFilePath as open
+from Common.MultipleWorkspace import MultipleWorkspace as mws
+
+gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE)
+gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$')
+
+## GetSplitValueList
+#
+# Get a value list from a string with multiple values split with SplitTag
+# The default SplitTag is DataType.TAB_VALUE_SPLIT
+# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']
+#
+# @param String: The input string to be splitted
+# @param SplitTag: The split key, default is DataType.TAB_VALUE_SPLIT
+# @param MaxSplit: The max number of split values, default is -1
+#
+# @retval list() A list for splitted string
+#
+def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1):
+ ValueList = []
+ Last = 0
+ Escaped = False
+ InSingleQuoteString = False
+ InDoubleQuoteString = False
+ InParenthesis = 0
+ for Index in range(0, len(String)):
+ Char = String[Index]
+
+ if not Escaped:
+ # Found a splitter not in a string, split it
+ if (not InSingleQuoteString or not InDoubleQuoteString) and InParenthesis == 0 and Char == SplitTag:
+ ValueList.append(String[Last:Index].strip())
+ Last = Index + 1
+ if MaxSplit > 0 and len(ValueList) >= MaxSplit:
+ break
+
+ if Char == '\\' and (InSingleQuoteString or InDoubleQuoteString):
+ Escaped = True
+ elif Char == '"' and not InSingleQuoteString:
+ if not InDoubleQuoteString:
+ InDoubleQuoteString = True
+ else:
+ InDoubleQuoteString = False
+ elif Char == "'" and not InDoubleQuoteString:
+ if not InSingleQuoteString:
+ InSingleQuoteString = True
+ else:
+ InSingleQuoteString = False
+ elif Char == '(':
+ InParenthesis = InParenthesis + 1
+ elif Char == ')':
+ InParenthesis = InParenthesis - 1
+ else:
+ Escaped = False
+
+ if Last < len(String):
+ ValueList.append(String[Last:].strip())
+ elif Last == len(String):
+ ValueList.append('')
+
+ return ValueList
+
+## GetSplitList
+#
+# Get a value list from a string with multiple values split with SplitString
+# The default SplitTag is DataType.TAB_VALUE_SPLIT
+# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']
+#
+# @param String: The input string to be splitted
+# @param SplitStr: The split key, default is DataType.TAB_VALUE_SPLIT
+# @param MaxSplit: The max number of split values, default is -1
+#
+# @retval list() A list for splitted string
+#
+def GetSplitList(String, SplitStr=DataType.TAB_VALUE_SPLIT, MaxSplit= -1):
+ return list(map(lambda l: l.strip(), String.split(SplitStr, MaxSplit)))
+
+## MergeArches
+#
+# Find a key's all arches in dict, add the new arch to the list
+# If not exist any arch, set the arch directly
+#
+# @param Dict: The input value for Dict
+# @param Key: The input value for Key
+# @param Arch: The Arch to be added or merged
+#
+def MergeArches(Dict, Key, Arch):
+ if Key in Dict:
+ Dict[Key].append(Arch)
+ else:
+ Dict[Key] = Arch.split()
+
+## GenDefines
+#
+# Parse a string with format "DEFINE <VarName> = <PATH>"
+# Generate a map Defines[VarName] = PATH
+# Return False if invalid format
+#
+# @param String: String with DEFINE statement
+# @param Arch: Supported Arch
+# @param Defines: DEFINE statement to be parsed
+#
+# @retval 0 DEFINE statement found, and valid
+# @retval 1 DEFINE statement found, but not valid
+# @retval -1 DEFINE statement not found
+#
+def GenDefines(String, Arch, Defines):
+ if String.find(DataType.TAB_DEFINE + ' ') > -1:
+ List = String.replace(DataType.TAB_DEFINE + ' ', '').split(DataType.TAB_EQUAL_SPLIT)
+ if len(List) == 2:
+ Defines[(CleanString(List[0]), Arch)] = CleanString(List[1])
+ return 0
+ else:
+ return -1
+
+ return 1
+
+## GenInclude
+#
+# Parse a string with format "!include <Filename>"
+# Return the file path
+# Return False if invalid format or NOT FOUND
+#
+# @param String: String with INCLUDE statement
+# @param IncludeFiles: INCLUDE statement to be parsed
+# @param Arch: Supported Arch
+#
+# @retval True
+# @retval False
+#
+def GenInclude(String, IncludeFiles, Arch):
+ if String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1:
+ IncludeFile = CleanString(String[String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') + len(DataType.TAB_INCLUDE + ' ') : ])
+ MergeArches(IncludeFiles, IncludeFile, Arch)
+ return True
+ else:
+ return False
+
+## GetLibraryClassesWithModuleType
+#
+# Get Library Class definition when no module type defined
+#
+# @param Lines: The content to be parsed
+# @param Key: Reserved
+# @param KeyValues: To store data after parsing
+# @param CommentCharacter: Comment char, used to ignore comment content
+#
+# @retval True Get library classes successfully
+#
+def GetLibraryClassesWithModuleType(Lines, Key, KeyValues, CommentCharacter):
+ newKey = SplitModuleType(Key)
+ Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
+ LineList = Lines.splitlines()
+ for Line in LineList:
+ Line = CleanString(Line, CommentCharacter)
+ if Line != '' and Line[0] != CommentCharacter:
+ KeyValues.append([CleanString(Line, CommentCharacter), newKey[1]])
+
+ return True
+
+## GetDynamics
+#
+# Get Dynamic Pcds
+#
+# @param Lines: The content to be parsed
+# @param Key: Reserved
+# @param KeyValues: To store data after parsing
+# @param CommentCharacter: Comment char, used to ignore comment content
+#
+# @retval True Get Dynamic Pcds successfully
+#
+def GetDynamics(Lines, Key, KeyValues, CommentCharacter):
+ #
+ # Get SkuId Name List
+ #
+ SkuIdNameList = SplitModuleType(Key)
+
+ Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
+ LineList = Lines.splitlines()
+ for Line in LineList:
+ Line = CleanString(Line, CommentCharacter)
+ if Line != '' and Line[0] != CommentCharacter:
+ KeyValues.append([CleanString(Line, CommentCharacter), SkuIdNameList[1]])
+
+ return True
+
+## SplitModuleType
+#
+# Split ModuleType out of section defien to get key
+# [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [ 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ]
+#
+# @param Key: String to be parsed
+#
+# @retval ReturnValue A list for module types
+#
+def SplitModuleType(Key):
+ KeyList = Key.split(DataType.TAB_SPLIT)
+ #
+ # Fill in for arch
+ #
+ KeyList.append('')
+ #
+ # Fill in for moduletype
+ #
+ KeyList.append('')
+ ReturnValue = []
+ KeyValue = KeyList[0]
+ if KeyList[1] != '':
+ KeyValue = KeyValue + DataType.TAB_SPLIT + KeyList[1]
+ ReturnValue.append(KeyValue)
+ ReturnValue.append(GetSplitValueList(KeyList[2]))
+
+ return ReturnValue
+
+## Replace macro in strings list
+#
+# This method replace macros used in a given string list. The macros are
+# given in a dictionary.
+#
+# @param StringList StringList to be processed
+# @param MacroDefinitions The macro definitions in the form of dictionary
+# @param SelfReplacement To decide whether replace un-defined macro to ''
+#
+# @retval NewList A new string list whose macros are replaced
+#
+def ReplaceMacros(StringList, MacroDefinitions=None, SelfReplacement=False):
+ NewList = []
+ if MacroDefinitions is None:
+ MacroDefinitions = {}
+ for String in StringList:
+ if isinstance(String, type('')):
+ NewList.append(ReplaceMacro(String, MacroDefinitions, SelfReplacement))
+ else:
+ NewList.append(String)
+
+ return NewList
+
+## Replace macro in string
+#
+# This method replace macros used in given string. The macros are given in a
+# dictionary.
+#
+# @param String String to be processed
+# @param MacroDefinitions The macro definitions in the form of dictionary
+# @param SelfReplacement To decide whether replace un-defined macro to ''
+#
+# @retval string The string whose macros are replaced
+#
+def ReplaceMacro(String, MacroDefinitions=None, SelfReplacement=False, RaiseError=False):
+ LastString = String
+ if MacroDefinitions is None:
+ MacroDefinitions = {}
+ while String and MacroDefinitions:
+ MacroUsed = GlobalData.gMacroRefPattern.findall(String)
+ # no macro found in String, stop replacing
+ if len(MacroUsed) == 0:
+ break
+
+ for Macro in MacroUsed:
+ if Macro not in MacroDefinitions:
+ if RaiseError:
+ raise SymbolNotFound("%s not defined" % Macro)
+ if SelfReplacement:
+ String = String.replace("$(%s)" % Macro, '')
+ continue
+ if "$(%s)" % Macro not in MacroDefinitions[Macro]:
+ String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro])
+ # in case there's macro not defined
+ if String == LastString:
+ break
+ LastString = String
+
+ return String
+
+## NormPath
+#
+# Create a normal path
+# And replace DEFINE in the path
+#
+# @param Path: The input value for Path to be converted
+# @param Defines: A set for DEFINE statement
+#
+# @retval Path Formatted path
+#
+def NormPath(Path, Defines=None):
+ IsRelativePath = False
+ if Path:
+ if Path[0] == '.':
+ IsRelativePath = True
+ #
+ # Replace with Define
+ #
+ if Defines:
+ Path = ReplaceMacro(Path, Defines)
+ #
+ # To local path format
+ #
+ Path = os.path.normpath(Path)
+ if Path.startswith(GlobalData.gWorkspace) and not Path.startswith(GlobalData.gBuildDirectory) and not os.path.exists(Path):
+ Path = Path[len (GlobalData.gWorkspace):]
+ if Path[0] == os.path.sep:
+ Path = Path[1:]
+ Path = mws.join(GlobalData.gWorkspace, Path)
+
+ if IsRelativePath and Path[0] != '.':
+ Path = os.path.join('.', Path)
+
+ return Path
+
+## CleanString
+#
+# Remove comments in a string
+# Remove spaces
+#
+# @param Line: The string to be cleaned
+# @param CommentCharacter: Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT
+#
+# @retval Path Formatted path
+#
+def CleanString(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False, BuildOption=False):
+ #
+ # remove whitespace
+ #
+ Line = Line.strip();
+ #
+ # Replace Edk's comment character
+ #
+ if AllowCppStyleComment:
+ Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter)
+ #
+ # remove comments, but we should escape comment character in string
+ #
+ InDoubleQuoteString = False
+ InSingleQuoteString = False
+ CommentInString = False
+ for Index in range(0, len(Line)):
+ if Line[Index] == '"' and not InSingleQuoteString:
+ InDoubleQuoteString = not InDoubleQuoteString
+ elif Line[Index] == "'" and not InDoubleQuoteString:
+ InSingleQuoteString = not InSingleQuoteString
+ elif Line[Index] == CommentCharacter and (InSingleQuoteString or InDoubleQuoteString):
+ CommentInString = True
+ elif Line[Index] == CommentCharacter and not (InSingleQuoteString or InDoubleQuoteString):
+ Line = Line[0: Index]
+ break
+
+ if CommentInString and BuildOption:
+ Line = Line.replace('"', '')
+ ChIndex = Line.find('#')
+ while ChIndex >= 0:
+ if GlobalData.gIsWindows:
+ if ChIndex == 0 or Line[ChIndex - 1] != '^':
+ Line = Line[0:ChIndex] + '^' + Line[ChIndex:]
+ ChIndex = Line.find('#', ChIndex + 2)
+ else:
+ ChIndex = Line.find('#', ChIndex + 1)
+ else:
+ if ChIndex == 0 or Line[ChIndex - 1] != '\\':
+ Line = Line[0:ChIndex] + '\\' + Line[ChIndex:]
+ ChIndex = Line.find('#', ChIndex + 2)
+ else:
+ ChIndex = Line.find('#', ChIndex + 1)
+ #
+ # remove whitespace again
+ #
+ Line = Line.strip();
+
+ return Line
+
+## CleanString2
+#
+# Split statement with comments in a string
+# Remove spaces
+#
+# @param Line: The string to be cleaned
+# @param CommentCharacter: Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT
+#
+# @retval Path Formatted path
+#
+def CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):
+ #
+ # remove whitespace
+ #
+ Line = Line.strip();
+ #
+ # Replace Edk's comment character
+ #
+ if AllowCppStyleComment:
+ Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter)
+ #
+ # separate comments and statements, but we should escape comment character in string
+ #
+ InDoubleQuoteString = False
+ InSingleQuoteString = False
+ CommentInString = False
+ Comment = ''
+ for Index in range(0, len(Line)):
+ if Line[Index] == '"' and not InSingleQuoteString:
+ InDoubleQuoteString = not InDoubleQuoteString
+ elif Line[Index] == "'" and not InDoubleQuoteString:
+ InSingleQuoteString = not InSingleQuoteString
+ elif Line[Index] == CommentCharacter and (InDoubleQuoteString or InSingleQuoteString):
+ CommentInString = True
+ elif Line[Index] == CommentCharacter and not (InDoubleQuoteString or InSingleQuoteString):
+ Comment = Line[Index:].strip()
+ Line = Line[0:Index].strip()
+ break
+
+ return Line, Comment
+
+## GetMultipleValuesOfKeyFromLines
+#
+# Parse multiple strings to clean comment and spaces
+# The result is saved to KeyValues
+#
+# @param Lines: The content to be parsed
+# @param Key: Reserved
+# @param KeyValues: To store data after parsing
+# @param CommentCharacter: Comment char, used to ignore comment content
+#
+# @retval True Successfully executed
+#
+def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter):
+ Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
+ LineList = Lines.split('\n')
+ for Line in LineList:
+ Line = CleanString(Line, CommentCharacter)
+ if Line != '' and Line[0] != CommentCharacter:
+ KeyValues.append(Line)
+
+ return True
+
+## GetDefineValue
+#
+# Parse a DEFINE statement to get defined value
+# DEFINE Key Value
+#
+# @param String: The content to be parsed
+# @param Key: The key of DEFINE statement
+# @param CommentCharacter: Comment char, used to ignore comment content
+#
+# @retval string The defined value
+#
+def GetDefineValue(String, Key, CommentCharacter):
+ String = CleanString(String)
+ return String[String.find(Key + ' ') + len(Key + ' ') : ]
+
+## GetHexVerValue
+#
+# Get a Hex Version Value
+#
+# @param VerString: The version string to be parsed
+#
+#
+# @retval: If VerString is incorrectly formatted, return "None" which will break the build.
+# If VerString is correctly formatted, return a Hex value of the Version Number (0xmmmmnnnn)
+# where mmmm is the major number and nnnn is the adjusted minor number.
+#
+def GetHexVerValue(VerString):
+ VerString = CleanString(VerString)
+
+ if gHumanReadableVerPatt.match(VerString):
+ ValueList = VerString.split('.')
+ Major = ValueList[0]
+ Minor = ValueList[1]
+ if len(Minor) == 1:
+ Minor += '0'
+ DeciValue = (int(Major) << 16) + int(Minor);
+ return "0x%08x" % DeciValue
+ elif gHexVerPatt.match(VerString):
+ return VerString
+ else:
+ return None
+
+
+## GetSingleValueOfKeyFromLines
+#
+# Parse multiple strings as below to get value of each definition line
+# Key1 = Value1
+# Key2 = Value2
+# The result is saved to Dictionary
+#
+# @param Lines: The content to be parsed
+# @param Dictionary: To store data after parsing
+# @param CommentCharacter: Comment char, be used to ignore comment content
+# @param KeySplitCharacter: Key split char, between key name and key value. Key1 = Value1, '=' is the key split char
+# @param ValueSplitFlag: Value split flag, be used to decide if has multiple values
+# @param ValueSplitCharacter: Value split char, be used to split multiple values. Key1 = Value1|Value2, '|' is the value split char
+#
+# @retval True Successfully executed
+#
+def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter):
+ Lines = Lines.split('\n')
+ Keys = []
+ Value = ''
+ DefineValues = ['']
+ SpecValues = ['']
+
+ for Line in Lines:
+ #
+ # Handle DEFINE and SPEC
+ #
+ if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1:
+ if '' in DefineValues:
+ DefineValues.remove('')
+ DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter))
+ continue
+ if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1:
+ if '' in SpecValues:
+ SpecValues.remove('')
+ SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter))
+ continue
+
+ #
+ # Handle Others
+ #
+ LineList = Line.split(KeySplitCharacter, 1)
+ if len(LineList) >= 2:
+ Key = LineList[0].split()
+ if len(Key) == 1 and Key[0][0] != CommentCharacter:
+ #
+ # Remove comments and white spaces
+ #
+ LineList[1] = CleanString(LineList[1], CommentCharacter)
+ if ValueSplitFlag:
+ Value = list(map(string.strip, LineList[1].split(ValueSplitCharacter)))
+ else:
+ Value = CleanString(LineList[1], CommentCharacter).splitlines()
+
+ if Key[0] in Dictionary:
+ if Key[0] not in Keys:
+ Dictionary[Key[0]] = Value
+ Keys.append(Key[0])
+ else:
+ Dictionary[Key[0]].extend(Value)
+ else:
+ Dictionary[DataType.TAB_INF_DEFINES_MACRO][Key[0]] = Value[0]
+
+ if DefineValues == []:
+ DefineValues = ['']
+ if SpecValues == []:
+ SpecValues = ['']
+ Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues
+ Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues
+
+ return True
+
+## The content to be parsed
+#
+# Do pre-check for a file before it is parsed
+# Check $()
+# Check []
+#
+# @param FileName: Used for error report
+# @param FileContent: File content to be parsed
+# @param SupSectionTag: Used for error report
+#
+def PreCheck(FileName, FileContent, SupSectionTag):
+ LineNo = 0
+ IsFailed = False
+ NewFileContent = ''
+ for Line in FileContent.splitlines():
+ LineNo = LineNo + 1
+ #
+ # Clean current line
+ #
+ Line = CleanString(Line)
+
+ #
+ # Remove commented line
+ #
+ if Line.find(DataType.TAB_COMMA_SPLIT) == 0:
+ Line = ''
+ #
+ # Check $()
+ #
+ if Line.find('$') > -1:
+ if Line.find('$(') < 0 or Line.find(')') < 0:
+ EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)
+
+ #
+ # Check []
+ #
+ if Line.find('[') > -1 or Line.find(']') > -1:
+ #
+ # Only get one '[' or one ']'
+ #
+ if not (Line.find('[') > -1 and Line.find(']') > -1):
+ EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)
+
+ #
+ # Regenerate FileContent
+ #
+ NewFileContent = NewFileContent + Line + '\r\n'
+
+ if IsFailed:
+ EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)
+
+ return NewFileContent
+
+## CheckFileType
+#
+# Check if the Filename is including ExtName
+# Return True if it exists
+# Raise a error message if it not exists
+#
+# @param CheckFilename: Name of the file to be checked
+# @param ExtName: Ext name of the file to be checked
+# @param ContainerFilename: The container file which describes the file to be checked, used for error report
+# @param SectionName: Used for error report
+# @param Line: The line in container file which defines the file to be checked
+#
+# @retval True The file type is correct
+#
+def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1):
+ if CheckFilename != '' and CheckFilename is not None:
+ (Root, Ext) = os.path.splitext(CheckFilename)
+ if Ext.upper() != ExtName.upper():
+ ContainerFile = open(ContainerFilename, 'r').read()
+ if LineNo == -1:
+ LineNo = GetLineNo(ContainerFile, Line)
+ ErrorMsg = "Invalid %s. '%s' is found, but '%s' file is needed" % (SectionName, CheckFilename, ExtName)
+ EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo,
+ File=ContainerFilename, RaiseError=EdkLogger.IsRaiseError)
+
+ return True
+
+## CheckFileExist
+#
+# Check if the file exists
+# Return True if it exists
+# Raise a error message if it not exists
+#
+# @param CheckFilename: Name of the file to be checked
+# @param WorkspaceDir: Current workspace dir
+# @param ContainerFilename: The container file which describes the file to be checked, used for error report
+# @param SectionName: Used for error report
+# @param Line: The line in container file which defines the file to be checked
+#
+# @retval The file full path if the file exists
+#
+def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1):
+ CheckFile = ''
+ if CheckFilename != '' and CheckFilename is not None:
+ CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename)
+ if not os.path.isfile(CheckFile):
+ ContainerFile = open(ContainerFilename, 'r').read()
+ if LineNo == -1:
+ LineNo = GetLineNo(ContainerFile, Line)
+ ErrorMsg = "Can't find file '%s' defined in section '%s'" % (CheckFile, SectionName)
+ EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg,
+ File=ContainerFilename, Line=LineNo, RaiseError=EdkLogger.IsRaiseError)
+
+ return CheckFile
+
+## GetLineNo
+#
+# Find the index of a line in a file
+#
+# @param FileContent: Search scope
+# @param Line: Search key
+#
+# @retval int Index of the line
+# @retval -1 The line is not found
+#
+def GetLineNo(FileContent, Line, IsIgnoreComment=True):
+ LineList = FileContent.splitlines()
+ for Index in range(len(LineList)):
+ if LineList[Index].find(Line) > -1:
+ #
+ # Ignore statement in comment
+ #
+ if IsIgnoreComment:
+ if LineList[Index].strip()[0] == DataType.TAB_COMMENT_SPLIT:
+ continue
+ return Index + 1
+
+ return -1
+
+## RaiseParserError
+#
+# Raise a parser error
+#
+# @param Line: String which has error
+# @param Section: Used for error report
+# @param File: File which has the string
+# @param Format: Correct format
+#
+def RaiseParserError(Line, Section, File, Format='', LineNo= -1):
+ if LineNo == -1:
+ LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line)
+ ErrorMsg = "Invalid statement '%s' is found in section '%s'" % (Line, Section)
+ if Format != '':
+ Format = "Correct format is " + Format
+ EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError=EdkLogger.IsRaiseError)
+
+## WorkspaceFile
+#
+# Return a full path with workspace dir
+#
+# @param WorkspaceDir: Workspace dir
+# @param Filename: Relative file name
+#
+# @retval string A full path
+#
+def WorkspaceFile(WorkspaceDir, Filename):
+ return mws.join(NormPath(WorkspaceDir), NormPath(Filename))
+
+## Split string
+#
+# Remove '"' which startswith and endswith string
+#
+# @param String: The string need to be split
+#
+# @retval String: The string after removed '""'
+#
+def SplitString(String):
+ if String.startswith('\"'):
+ String = String[1:]
+ if String.endswith('\"'):
+ String = String[:-1]
+
+ return String
+
+## Convert To Sql String
+#
+# 1. Replace "'" with "''" in each item of StringList
+#
+# @param StringList: A list for strings to be converted
+#
+def ConvertToSqlString(StringList):
+ return list(map(lambda s: s.replace("'", "''"), StringList))
+
+## Convert To Sql String
+#
+# 1. Replace "'" with "''" in the String
+#
+# @param String: A String to be converted
+#
+def ConvertToSqlString2(String):
+ return String.replace("'", "''")
+
+#
+# Remove comment block
+#
+def RemoveBlockComment(Lines):
+ IsFindBlockComment = False
+ IsFindBlockCode = False
+ ReservedLine = ''
+ NewLines = []
+
+ for Line in Lines:
+ Line = Line.strip()
+ #
+ # Remove comment block
+ #
+ if Line.find(DataType.TAB_COMMENT_EDK_START) > -1:
+ ReservedLine = GetSplitList(Line, DataType.TAB_COMMENT_EDK_START, 1)[0]
+ IsFindBlockComment = True
+ if Line.find(DataType.TAB_COMMENT_EDK_END) > -1:
+ Line = ReservedLine + GetSplitList(Line, DataType.TAB_COMMENT_EDK_END, 1)[1]
+ ReservedLine = ''
+ IsFindBlockComment = False
+ if IsFindBlockComment:
+ NewLines.append('')
+ continue
+
+ NewLines.append(Line)
+ return NewLines
+
+#
+# Get String of a List
+#
+def GetStringOfList(List, Split=' '):
+ if not isinstance(List, type([])):
+ return List
+ Str = ''
+ for Item in List:
+ Str = Str + Item + Split
+
+ return Str.strip()
+
+#
+# Get HelpTextList from HelpTextClassList
+#
+def GetHelpTextList(HelpTextClassList):
+ List = []
+ if HelpTextClassList:
+ for HelpText in HelpTextClassList:
+ if HelpText.String.endswith('\n'):
+ HelpText.String = HelpText.String[0: len(HelpText.String) - len('\n')]
+ List.extend(HelpText.String.split('\n'))
+
+ return List
+
+def StringToArray(String):
+ if String.startswith('L"'):
+ if String == "L\"\"":
+ return "{0x00,0x00}"
+ else:
+ return "{%s,0x00,0x00}" % ",".join("0x%02x,0x00" % ord(C) for C in String[2:-1])
+ elif String.startswith('"'):
+ if String == "\"\"":
+ return "{0x00,0x00}"
+ else:
+ StringLen = len(String[1:-1])
+ if StringLen % 2:
+ return "{%s,0x00}" % ",".join("0x%02x" % ord(C) for C in String[1:-1])
+ else:
+ return "{%s,0x00,0x00}" % ",".join("0x%02x" % ord(C) for C in String[1:-1])
+ elif String.startswith('{'):
+ return "{%s}" % ",".join(C.strip() for C in String[1:-1].split(','))
+ else:
+ if len(String.split()) % 2:
+ return '{%s,0}' % ','.join(String.split())
+ else:
+ return '{%s,0,0}' % ','.join(String.split())
+
+def StringArrayLength(String):
+ if String.startswith('L"'):
+ return (len(String) - 3 + 1) * 2
+ elif String.startswith('"'):
+ return (len(String) - 2 + 1)
+ else:
+ return len(String.split()) + 1
+
+def RemoveDupOption(OptionString, Which="/I", Against=None):
+ OptionList = OptionString.split()
+ ValueList = []
+ if Against:
+ ValueList += Against
+ for Index in range(len(OptionList)):
+ Opt = OptionList[Index]
+ if not Opt.startswith(Which):
+ continue
+ if len(Opt) > len(Which):
+ Val = Opt[len(Which):]
+ else:
+ Val = ""
+ if Val in ValueList:
+ OptionList[Index] = ""
+ else:
+ ValueList.append(Val)
+ return " ".join(OptionList)
+
+##
+#
+# This acts like the main() function for the script, unless it is 'import'ed into another
+# script.
+#
+if __name__ == '__main__':
+ pass
+
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/TargetTxtClassObject.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/TargetTxtClassObject.py
new file mode 100755
index 00000000..ff2e4be9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/TargetTxtClassObject.py
@@ -0,0 +1,199 @@
+## @file
+# This file is used to define each component of Target.txt file
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+##
+# Import Modules
+#
+from __future__ import print_function
+from __future__ import absolute_import
+
+import Common.GlobalData as GlobalData
+import Common.LongFilePathOs as os
+from . import EdkLogger
+from . import DataType
+from .BuildToolError import *
+
+from Common.LongFilePathSupport import OpenLongFilePath as open
+from Common.MultipleWorkspace import MultipleWorkspace as mws
+
+gDefaultTargetTxtFile = "target.txt"
+
+## TargetTxtClassObject
+#
+# This class defined content used in file target.txt
+#
+# @param object: Inherited from object class
+# @param Filename: Input value for full path of target.txt
+#
+# @var TargetTxtDictionary: To store keys and values defined in target.txt
+#
+class TargetTxtClassObject(object):
+ def __init__(self, Filename = None):
+ self.TargetTxtDictionary = {
+ DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM : '',
+ DataType.TAB_TAT_DEFINES_ACTIVE_MODULE : '',
+ DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF : '',
+ DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER : '',
+ DataType.TAB_TAT_DEFINES_TARGET : [],
+ DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG : [],
+ DataType.TAB_TAT_DEFINES_TARGET_ARCH : [],
+ DataType.TAB_TAT_DEFINES_BUILD_RULE_CONF : '',
+ }
+ self.ConfDirectoryPath = ""
+ if Filename is not None:
+ self.LoadTargetTxtFile(Filename)
+
+ ## LoadTargetTxtFile
+ #
+ # Load target.txt file and parse it, return a set structure to store keys and values
+ #
+ # @param Filename: Input value for full path of target.txt
+ #
+ # @retval set() A set structure to store keys and values
+ # @retval 1 Error happenes in parsing
+ #
+ def LoadTargetTxtFile(self, Filename):
+ if os.path.exists(Filename) and os.path.isfile(Filename):
+ return self.ConvertTextFileToDict(Filename, '#', '=')
+ else:
+ EdkLogger.error("Target.txt Parser", FILE_NOT_FOUND, ExtraData=Filename)
+ return 1
+
+ ## ConvertTextFileToDict
+ #
+ # Convert a text file to a dictionary of (name:value) pairs.
+ # The data is saved to self.TargetTxtDictionary
+ #
+ # @param FileName: Text filename
+ # @param CommentCharacter: Comment char, be used to ignore comment content
+ # @param KeySplitCharacter: Key split char, between key name and key value. Key1 = Value1, '=' is the key split char
+ #
+ # @retval 0 Convert successfully
+ # @retval 1 Open file failed
+ #
+ def ConvertTextFileToDict(self, FileName, CommentCharacter, KeySplitCharacter):
+ F = None
+ try:
+ F = open(FileName, 'r')
+ self.ConfDirectoryPath = os.path.dirname(FileName)
+ except:
+ EdkLogger.error("build", FILE_OPEN_FAILURE, ExtraData=FileName)
+ if F is not None:
+ F.close()
+
+ for Line in F:
+ Line = Line.strip()
+ if Line.startswith(CommentCharacter) or Line == '':
+ continue
+
+ LineList = Line.split(KeySplitCharacter, 1)
+ Key = LineList[0].strip()
+ if len(LineList) == 2:
+ Value = LineList[1].strip()
+ else:
+ Value = ""
+
+ if Key in [DataType.TAB_TAT_DEFINES_ACTIVE_PLATFORM, DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF, \
+ DataType.TAB_TAT_DEFINES_ACTIVE_MODULE, DataType.TAB_TAT_DEFINES_BUILD_RULE_CONF]:
+ self.TargetTxtDictionary[Key] = Value.replace('\\', '/')
+ if Key == DataType.TAB_TAT_DEFINES_TOOL_CHAIN_CONF and self.TargetTxtDictionary[Key]:
+ if self.TargetTxtDictionary[Key].startswith("Conf/"):
+ Tools_Def = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].strip())
+ if not os.path.exists(Tools_Def) or not os.path.isfile(Tools_Def):
+ # If Conf/Conf does not exist, try just the Conf/ directory
+ Tools_Def = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].replace("Conf/", "", 1).strip())
+ else:
+ # The File pointed to by TOOL_CHAIN_CONF is not in a Conf/ directory
+ Tools_Def = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].strip())
+ self.TargetTxtDictionary[Key] = Tools_Def
+ if Key == DataType.TAB_TAT_DEFINES_BUILD_RULE_CONF and self.TargetTxtDictionary[Key]:
+ if self.TargetTxtDictionary[Key].startswith("Conf/"):
+ Build_Rule = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].strip())
+ if not os.path.exists(Build_Rule) or not os.path.isfile(Build_Rule):
+ # If Conf/Conf does not exist, try just the Conf/ directory
+ Build_Rule = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].replace("Conf/", "", 1).strip())
+ else:
+ # The File pointed to by BUILD_RULE_CONF is not in a Conf/ directory
+ Build_Rule = os.path.join(self.ConfDirectoryPath, self.TargetTxtDictionary[Key].strip())
+ self.TargetTxtDictionary[Key] = Build_Rule
+ elif Key in [DataType.TAB_TAT_DEFINES_TARGET, DataType.TAB_TAT_DEFINES_TARGET_ARCH, \
+ DataType.TAB_TAT_DEFINES_TOOL_CHAIN_TAG]:
+ self.TargetTxtDictionary[Key] = Value.split()
+ elif Key == DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER:
+ try:
+ V = int(Value, 0)
+ except:
+ EdkLogger.error("build", FORMAT_INVALID, "Invalid number of [%s]: %s." % (Key, Value),
+ File=FileName)
+ self.TargetTxtDictionary[Key] = Value
+ #elif Key not in GlobalData.gGlobalDefines:
+ # GlobalData.gGlobalDefines[Key] = Value
+
+ F.close()
+ return 0
+
+## TargetTxtDict
+#
+# Load target.txt in input Conf dir
+#
+# @param ConfDir: Conf dir
+#
+# @retval Target An instance of TargetTxtClassObject() with loaded target.txt
+#
+
+class TargetTxtDict():
+
+ def __new__(cls, *args, **kw):
+ if not hasattr(cls, '_instance'):
+ orig = super(TargetTxtDict, cls)
+ cls._instance = orig.__new__(cls, *args, **kw)
+ return cls._instance
+
+ def __init__(self):
+ if not hasattr(self, 'Target'):
+ self.TxtTarget = None
+
+ @property
+ def Target(self):
+ if not self.TxtTarget:
+ self._GetTarget()
+ return self.TxtTarget
+
+ def _GetTarget(self):
+ Target = TargetTxtClassObject()
+ ConfDirectory = GlobalData.gCmdConfDir
+ if ConfDirectory:
+ # Get alternate Conf location, if it is absolute, then just use the absolute directory name
+ ConfDirectoryPath = os.path.normpath(ConfDirectory)
+
+ 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 = mws.join(os.environ["WORKSPACE"], ConfDirectoryPath)
+ else:
+ if "CONF_PATH" in os.environ:
+ ConfDirectoryPath = os.path.normcase(os.path.normpath(os.environ["CONF_PATH"]))
+ else:
+ # Get standard WORKSPACE/Conf use the absolute path to the WORKSPACE/Conf
+ ConfDirectoryPath = mws.join(os.environ["WORKSPACE"], 'Conf')
+ GlobalData.gConfDirectory = ConfDirectoryPath
+ targettxt = os.path.normpath(os.path.join(ConfDirectoryPath, gDefaultTargetTxtFile))
+ if os.path.exists(targettxt):
+ Target.LoadTargetTxtFile(targettxt)
+ self.TxtTarget = Target
+
+##
+#
+# This acts like the main() function for the script, unless it is 'import'ed into another
+# script.
+#
+if __name__ == '__main__':
+ pass
+ Target = TargetTxtDict(os.getenv("WORKSPACE"))
+ print(Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_MAX_CONCURRENT_THREAD_NUMBER])
+ print(Target.TargetTxtDictionary[DataType.TAB_TAT_DEFINES_TARGET])
+ print(Target.TargetTxtDictionary)
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/ToolDefClassObject.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/ToolDefClassObject.py
new file mode 100755
index 00000000..2319a7c4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/ToolDefClassObject.py
@@ -0,0 +1,290 @@
+## @file
+# This file is used to define each component of tools_def.txt file
+#
+# Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+##
+# Import Modules
+#
+from __future__ import absolute_import
+import Common.LongFilePathOs as os
+import re
+from . import EdkLogger
+
+from .BuildToolError import *
+from Common.TargetTxtClassObject import TargetTxtDict
+from Common.LongFilePathSupport import OpenLongFilePath as open
+from Common.Misc import PathClass
+from Common.StringUtils import NormPath
+import Common.GlobalData as GlobalData
+from Common import GlobalData
+from Common.MultipleWorkspace import MultipleWorkspace as mws
+from .DataType import TAB_TOD_DEFINES_TARGET, TAB_TOD_DEFINES_TOOL_CHAIN_TAG,\
+ TAB_TOD_DEFINES_TARGET_ARCH, TAB_TOD_DEFINES_COMMAND_TYPE\
+ , TAB_TOD_DEFINES_FAMILY, TAB_TOD_DEFINES_BUILDRULEFAMILY,\
+ TAB_STAR, TAB_TAT_DEFINES_TOOL_CHAIN_CONF
+
+
+##
+# Static variables used for pattern
+#
+gMacroRefPattern = re.compile('(DEF\([^\(\)]+\))')
+gEnvRefPattern = re.compile('(ENV\([^\(\)]+\))')
+gMacroDefPattern = re.compile("DEFINE\s+([^\s]+)")
+gDefaultToolsDefFile = "tools_def.txt"
+
+## ToolDefClassObject
+#
+# This class defined content used in file tools_def.txt
+#
+# @param object: Inherited from object class
+# @param Filename: Input value for full path of tools_def.txt
+#
+# @var ToolsDefTxtDictionary: To store keys and values defined in target.txt
+# @var MacroDictionary: To store keys and values defined in DEFINE statement
+#
+class ToolDefClassObject(object):
+ def __init__(self, FileName=None):
+ self.ToolsDefTxtDictionary = {}
+ self.MacroDictionary = {}
+ for Env in os.environ:
+ self.MacroDictionary["ENV(%s)" % Env] = os.environ[Env]
+
+ if FileName is not None:
+ self.LoadToolDefFile(FileName)
+
+ ## LoadToolDefFile
+ #
+ # Load target.txt file and parse it
+ #
+ # @param Filename: Input value for full path of tools_def.txt
+ #
+ def LoadToolDefFile(self, FileName):
+ # set multiple workspace
+ PackagesPath = os.getenv("PACKAGES_PATH")
+ mws.setWs(GlobalData.gWorkspace, PackagesPath)
+
+ self.ToolsDefTxtDatabase = {
+ TAB_TOD_DEFINES_TARGET : [],
+ TAB_TOD_DEFINES_TOOL_CHAIN_TAG : [],
+ TAB_TOD_DEFINES_TARGET_ARCH : [],
+ TAB_TOD_DEFINES_COMMAND_TYPE : []
+ }
+
+ self.IncludeToolDefFile(FileName)
+
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET]))
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG]))
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH]))
+
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] = list(set(self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE]))
+
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET].sort()
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG].sort()
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH].sort()
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE].sort()
+
+ ## IncludeToolDefFile
+ #
+ # Load target.txt file and parse it as if its contents were inside the main file
+ #
+ # @param Filename: Input value for full path of tools_def.txt
+ #
+ def IncludeToolDefFile(self, FileName):
+ FileContent = []
+ if os.path.isfile(FileName):
+ try:
+ F = open(FileName, 'r')
+ FileContent = F.readlines()
+ except:
+ EdkLogger.error("tools_def.txt parser", FILE_OPEN_FAILURE, ExtraData=FileName)
+ else:
+ EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=FileName)
+
+ for Index in range(len(FileContent)):
+ Line = FileContent[Index].strip()
+ if Line == "" or Line[0] == '#':
+ continue
+
+ if Line.startswith("!include"):
+ IncFile = Line[8:].strip()
+ Done, IncFile = self.ExpandMacros(IncFile)
+ if not Done:
+ EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,
+ "Macro or Environment has not been defined",
+ ExtraData=IncFile[4:-1], File=FileName, Line=Index+1)
+ IncFile = NormPath(IncFile)
+
+ if not os.path.isabs(IncFile):
+ #
+ # try WORKSPACE
+ #
+ IncFileTmp = PathClass(IncFile, GlobalData.gWorkspace)
+ ErrorCode = IncFileTmp.Validate()[0]
+ if ErrorCode != 0:
+ #
+ # try PACKAGES_PATH
+ #
+ IncFileTmp = mws.join(GlobalData.gWorkspace, IncFile)
+ if not os.path.exists(IncFileTmp):
+ #
+ # try directory of current file
+ #
+ IncFileTmp = PathClass(IncFile, os.path.dirname(FileName))
+ ErrorCode = IncFileTmp.Validate()[0]
+ if ErrorCode != 0:
+ EdkLogger.error("tools_def.txt parser", FILE_NOT_FOUND, ExtraData=IncFile)
+
+ if isinstance(IncFileTmp, PathClass):
+ IncFile = IncFileTmp.Path
+ else:
+ IncFile = IncFileTmp
+
+ self.IncludeToolDefFile(IncFile)
+ continue
+
+ NameValuePair = Line.split("=", 1)
+ if len(NameValuePair) != 2:
+ EdkLogger.warn("tools_def.txt parser", "Line %d: not correct assignment statement, skipped" % (Index + 1))
+ continue
+
+ Name = NameValuePair[0].strip()
+ Value = NameValuePair[1].strip()
+
+ if Name == "IDENTIFIER":
+ EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found identifier statement, skipped: %s" % ((Index + 1), Value))
+ continue
+
+ MacroDefinition = gMacroDefPattern.findall(Name)
+ if MacroDefinition != []:
+ Done, Value = self.ExpandMacros(Value)
+ if not Done:
+ EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,
+ "Macro or Environment has not been defined",
+ ExtraData=Value[4:-1], File=FileName, Line=Index+1)
+
+ MacroName = MacroDefinition[0].strip()
+ self.MacroDictionary["DEF(%s)" % MacroName] = Value
+ EdkLogger.debug(EdkLogger.DEBUG_8, "Line %d: Found macro: %s = %s" % ((Index + 1), MacroName, Value))
+ continue
+
+ Done, Value = self.ExpandMacros(Value)
+ if not Done:
+ EdkLogger.error("tools_def.txt parser", ATTRIBUTE_NOT_AVAILABLE,
+ "Macro or Environment has not been defined",
+ ExtraData=Value[4:-1], File=FileName, Line=Index+1)
+
+ List = Name.split('_')
+ if len(List) != 5:
+ EdkLogger.verbose("Line %d: Not a valid name of definition: %s" % ((Index + 1), Name))
+ continue
+ elif List[4] == TAB_STAR:
+ EdkLogger.verbose("Line %d: '*' is not allowed in last field: %s" % ((Index + 1), Name))
+ continue
+ else:
+ self.ToolsDefTxtDictionary[Name] = Value
+ if List[0] != TAB_STAR:
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET] += [List[0]]
+ if List[1] != TAB_STAR:
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TOOL_CHAIN_TAG] += [List[1]]
+ if List[2] != TAB_STAR:
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_TARGET_ARCH] += [List[2]]
+ if List[3] != TAB_STAR:
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_COMMAND_TYPE] += [List[3]]
+ if List[4] == TAB_TOD_DEFINES_FAMILY and List[2] == TAB_STAR and List[3] == TAB_STAR:
+ if TAB_TOD_DEFINES_FAMILY not in self.ToolsDefTxtDatabase:
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY] = {}
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY] = {}
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value
+ elif List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] = Value
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value
+ elif self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY][List[1]] != Value:
+ EdkLogger.verbose("Line %d: No override allowed for the family of a tool chain: %s" % ((Index + 1), Name))
+ if List[4] == TAB_TOD_DEFINES_BUILDRULEFAMILY and List[2] == TAB_STAR and List[3] == TAB_STAR:
+ if TAB_TOD_DEFINES_BUILDRULEFAMILY not in self.ToolsDefTxtDatabase \
+ or List[1] not in self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_FAMILY]:
+ EdkLogger.verbose("Line %d: The family is not specified, but BuildRuleFamily is specified for the tool chain: %s" % ((Index + 1), Name))
+ self.ToolsDefTxtDatabase[TAB_TOD_DEFINES_BUILDRULEFAMILY][List[1]] = Value
+
+ ## ExpandMacros
+ #
+ # Replace defined macros with real value
+ #
+ # @param Value: The string with unreplaced macros
+ #
+ # @retval Value: The string which has been replaced with real value
+ #
+ def ExpandMacros(self, Value):
+ # os.environ contains all environment variables uppercase on Windows which cause the key in the self.MacroDictionary is uppercase, but Ref may not
+ EnvReference = gEnvRefPattern.findall(Value)
+ for Ref in EnvReference:
+ if Ref not in self.MacroDictionary and Ref.upper() not in self.MacroDictionary:
+ Value = Value.replace(Ref, "")
+ else:
+ if Ref in self.MacroDictionary:
+ Value = Value.replace(Ref, self.MacroDictionary[Ref])
+ else:
+ Value = Value.replace(Ref, self.MacroDictionary[Ref.upper()])
+ MacroReference = gMacroRefPattern.findall(Value)
+ for Ref in MacroReference:
+ if Ref not in self.MacroDictionary:
+ return False, Ref
+ Value = Value.replace(Ref, self.MacroDictionary[Ref])
+
+ return True, Value
+
+## ToolDefDict
+#
+# Load tools_def.txt in input Conf dir
+#
+# @param ConfDir: Conf dir
+#
+# @retval ToolDef An instance of ToolDefClassObject() with loaded tools_def.txt
+#
+
+
+class ToolDefDict():
+
+ def __new__(cls, ConfDir, *args, **kw):
+ if not hasattr(cls, '_instance'):
+ orig = super(ToolDefDict, cls)
+ cls._instance = orig.__new__(cls, *args, **kw)
+ return cls._instance
+
+ def __init__(self, ConfDir):
+ self.ConfDir = ConfDir
+ if not hasattr(self, 'ToolDef'):
+ self._ToolDef = None
+
+ @property
+ def ToolDef(self):
+ if not self._ToolDef:
+ self._GetToolDef()
+ return self._ToolDef
+
+ def _GetToolDef(self):
+ TargetObj = TargetTxtDict()
+ Target = TargetObj.Target
+ ToolDef = ToolDefClassObject()
+ if TAB_TAT_DEFINES_TOOL_CHAIN_CONF in Target.TargetTxtDictionary:
+ ToolsDefFile = Target.TargetTxtDictionary[TAB_TAT_DEFINES_TOOL_CHAIN_CONF]
+ if ToolsDefFile:
+ ToolDef.LoadToolDefFile(os.path.normpath(ToolsDefFile))
+ else:
+ ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(self.ConfDir, gDefaultToolsDefFile)))
+ else:
+ ToolDef.LoadToolDefFile(os.path.normpath(os.path.join(self.ConfDir, gDefaultToolsDefFile)))
+ self._ToolDef = ToolDef
+
+##
+#
+# This acts like the main() function for the script, unless it is 'import'ed into another
+# script.
+#
+if __name__ == '__main__':
+ ToolDef = ToolDefDict(os.getenv("WORKSPACE"))
+ pass
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py
new file mode 100755
index 00000000..96cf4b40
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py
@@ -0,0 +1,409 @@
+## @file
+# Module that encodes and decodes a capsule dependency.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+import struct
+import json
+import sys
+import uuid
+import re
+
+'''
+CapsuleDependency
+'''
+
+class OpConvert (object):
+ def __init__ (self):
+ # Opcode: (OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert)
+ self._DepexOperations = {0x00: (16, 16, 's', self.Str2Guid, self.Guid2Str),
+ 0x01: (4, 1, 'I', self.Str2Uint, self.Uint2Str),
+ 0x02: (1, 0, 's', self.Str2Utf8, self.Byte2Str),
+ }
+
+ def Str2Uint (self, Data):
+ try:
+ Value = int (Data, 16)
+ except:
+ Message = '{Data} is not a valid integer value.'.format (Data = Data)
+ raise ValueError (Message)
+ if Value < 0 or Value > 0xFFFFFFFF:
+ Message = '{Data} is not an UINT32.'.format (Data = Data)
+ raise ValueError (Message)
+ return Value
+
+ def Uint2Str (self, Data):
+ if Data < 0 or Data > 0xFFFFFFFF:
+ Message = '{Data} is not an UINT32.'.format (Data = Data)
+ raise ValueError (Message)
+ return "0x{Data:08x}".format (Data = Data)
+
+ def Str2Guid (self, Data):
+ try:
+ Guid = uuid.UUID (Data)
+ except:
+ Message = '{Data} is not a valid registry format GUID value.'.format (Data = Data)
+ raise ValueError (Message)
+ return Guid.bytes_le
+
+ def Guid2Str (self, Data):
+ try:
+ Guid = uuid.UUID (bytes_le = Data)
+ except:
+ Message = '{Data} is not a valid binary format GUID value.'.format (Data = Data)
+ raise ValueError (Message)
+ return str (Guid).upper ()
+
+ def Str2Utf8 (self, Data):
+ if isinstance (Data, str):
+ return Data.encode ('utf-8')
+ else:
+ Message = '{Data} is not a valid string.'.format (Data = Data)
+ raise ValueError (Message)
+
+ def Byte2Str (self, Data):
+ if isinstance (Data, bytes):
+ if Data[-1:] == b'\x00':
+ return str (Data[:-1], 'utf-8')
+ else:
+ return str (Data, 'utf-8')
+ else:
+ Message = '{Data} is not a valid binary string.'.format (Data = Data)
+ raise ValueError (Message)
+
+ def OpEncode (self, Opcode, Operand = None):
+ BinTemp = struct.pack ('<b', Opcode)
+ if Opcode <= 0x02 and Operand != None:
+ OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert = self._DepexOperations[Opcode]
+ Value = EncodeConvert (Operand)
+ if Opcode == 0x02:
+ PackSize = len (Value) + 1
+ BinTemp += struct.pack ('<{PackSize}{PackFmt}'.format (PackSize = PackSize, PackFmt = PackFmt), Value)
+ return BinTemp
+
+ def OpDecode (self, Buffer):
+ Opcode = struct.unpack ('<b', Buffer[0:1])[0]
+ if Opcode <= 0x02:
+ OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert = self._DepexOperations[Opcode]
+ if Opcode == 0x02:
+ try:
+ PackSize = Buffer[1:].index (b'\x00') + 1
+ OperandSize = PackSize
+ except:
+ Message = 'CapsuleDependency: OpConvert: error: decode failed with wrong opcode/string.'
+ raise ValueError (Message)
+ try:
+ Operand = DecodeConvert (struct.unpack ('<{PackSize}{PackFmt}'.format (PackSize = PackSize, PackFmt = PackFmt), Buffer[1:1+OperandSize])[0])
+ except:
+ Message = 'CapsuleDependency: OpConvert: error: decode failed with unpack failure.'
+ raise ValueError (Message)
+ else:
+ Operand = None
+ OperandSize = 0
+ return (Opcode, Operand, OperandSize)
+
+class CapsuleDependencyClass (object):
+ # //**************************************************************
+ # // Image Attribute - Dependency
+ # //**************************************************************
+ # typedef struct {
+ # UINT8 Dependencies[];
+ # } EFI_FIRMWARE_IMAGE_DEP
+
+ # {expression operator : [precedence, opcode, type (1:unary/2:binocular)]}
+ _opReference = {'&&': [2, 0x03, 2],
+ '||': [1, 0x04, 2],
+ '~': [5, 0x05, 1],
+ '==': [3, 0x08, 2],
+ '>': [4, 0x09, 2],
+ '>=': [4, 0x0A, 2],
+ '<': [4, 0x0B, 2],
+ '<=': [4, 0x0C, 2],
+ }
+
+ def __init__ (self):
+ self.Payload = b''
+ self._DepexExp = None
+ self._DepexList = []
+ self._DepexDump = []
+ self.Depex = b''
+ self._Valid = False
+ self._DepexSize = 0
+ self._opReferenceReverse = {v[1] : k for k, v in self._opReference.items ()}
+ self.OpConverter = OpConvert ()
+
+ @property
+ def DepexExp (self):
+ return self._DepexExp
+
+ @DepexExp.setter
+ def DepexExp (self, DepexExp = ''):
+ if isinstance (DepexExp, str):
+ DepexExp = re.sub (r'\n',r' ',DepexExp)
+ DepexExp = re.sub (r'\(',r' ( ',DepexExp)
+ DepexExp = re.sub (r'\)',r' ) ',DepexExp)
+ DepexExp = re.sub (r'~',r' ~ ',DepexExp)
+ self._DepexList = re.findall(r"[^\s\"\']+|\"[^\"]*\"|\'[^\']*\'",DepexExp)
+ self._DepexExp = " ".join(self._DepexList)
+
+ else:
+ Msg = 'Input Depex Expression is not valid string.'
+ raise ValueError (Msg)
+
+ def IsValidOperator (self, op):
+ return op in self._opReference.keys ()
+
+ def IsValidUnaryOperator (self, op):
+ return op in self._opReference.keys () and self._opReference[op][2] == 1
+
+ def IsValidBinocularOperator (self, op):
+ return op in self._opReference.keys () and self._opReference[op][2] == 2
+
+ def IsValidGuid (self, operand):
+ try:
+ uuid.UUID (operand)
+ except:
+ return False
+ return True
+
+ def IsValidVersion (self, operand):
+ try:
+ Value = int (operand, 16)
+ if Value < 0 or Value > 0xFFFFFFFF:
+ return False
+ except:
+ return False
+ return True
+
+ def IsValidBoolean (self, operand):
+ try:
+ return operand.upper () in ['TRUE', 'FALSE']
+ except:
+ return False
+
+ def IsValidOperand (self, operand):
+ return self.IsValidVersion (operand) or self.IsValidGuid (operand) or self.IsValidBoolean (operand)
+
+ def IsValidString (self, operand):
+ return operand[0] == "\"" and operand[-1] == "\"" and len(operand) >= 2
+
+ # Check if priority of current operater is greater than pervious op
+ def PriorityNotGreater (self, prevOp, currOp):
+ return self._opReference[currOp][0] <= self._opReference[prevOp][0]
+
+ def ValidateDepex (self):
+ OpList = self._DepexList
+
+ i = 0
+ while i < len (OpList):
+ Op = OpList[i]
+
+ if Op == 'DECLARE':
+ i += 1
+ if i >= len (OpList):
+ Msg = 'No more Operand after {Op}.'.format (Op = OpList[i-1])
+ raise IndexError (Msg)
+ # Check valid string
+ if not self.IsValidString(OpList[i]):
+ Msg = '{Operand} after {Op} is not a valid expression input.'.format (Operand = OpList[i], Op = OpList[i-1])
+ raise ValueError (Msg)
+
+ elif Op == '(':
+ # Expression cannot end with (
+ if i == len (OpList) - 1:
+ Msg = 'Expression cannot end with \'(\''
+ raise ValueError (Msg)
+ # The previous op after '(' cannot be a binocular operator
+ if self.IsValidBinocularOperator (OpList[i+1]) :
+ Msg = '{Op} after \'(\' is not a valid expression input.'.format (Op = OpList[i+1])
+ raise ValueError (Msg)
+
+ elif Op == ')':
+ # Expression cannot start with )
+ if i == 0:
+ Msg = 'Expression cannot start with \')\''
+ raise ValueError (Msg)
+ # The previous op before ')' cannot be an operator
+ if self.IsValidOperator (OpList[i-1]):
+ Msg = '{Op} before \')\' is not a valid expression input.'.format (Op = OpList[i-1])
+ raise ValueError (Msg)
+ # The next op after ')' cannot be operand or unary operator
+ if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])):
+ Msg = '{Op} after \')\' is not a valid expression input.'.format (Op = OpList[i+1])
+ raise ValueError (Msg)
+
+ elif self.IsValidOperand (Op):
+ # The next expression of operand cannot be operand or unary operator
+ if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+
+ elif self.IsValidOperator (Op):
+ # The next op of operator cannot binocular operator
+ if (i + 1) < len (OpList) and self.IsValidBinocularOperator (OpList[i+1]):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+ # The first op can not be binocular operator
+ if i == 0 and self.IsValidBinocularOperator (Op):
+ Msg = 'Expression cannot start with an operator {Op}.'.format (Op = Op)
+ raise ValueError (Msg)
+ # The last op can not be operator
+ if i == len (OpList) - 1:
+ Msg = 'Expression cannot ended with an operator {Op}.'.format (Op = Op)
+ raise ValueError (Msg)
+ # The next op of unary operator cannot be guid / version
+ if self.IsValidUnaryOperator (Op) and (self.IsValidGuid (OpList[i+1]) or self.IsValidVersion (OpList[i+1])):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+
+ else:
+ Msg = '{Op} is not a valid expression input.'.format (Op = Op)
+ raise ValueError (Msg)
+ i += 1
+
+ def Encode (self):
+ # initialize
+ self.Depex = b''
+ self._DepexDump = []
+ OperandStack = []
+ OpeartorStack = []
+ OpList = self._DepexList
+
+ self.ValidateDepex ()
+
+ # convert
+ i = 0
+ while i < len (OpList):
+ Op = OpList[i]
+ if Op == 'DECLARE':
+ # This declare next expression value is a VERSION_STRING
+ i += 1
+ self.Depex += self.OpConverter.OpEncode (0x02, OpList[i][1:-1])
+
+ elif Op == '(':
+ OpeartorStack.append (Op)
+
+ elif Op == ')':
+ while (OpeartorStack and OpeartorStack[-1] != '('):
+ Operator = OpeartorStack.pop ()
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ try:
+ OpeartorStack.pop () # pop out '('
+ except:
+ Msg = 'Pop out \'(\' failed, too many \')\''
+ raise ValueError (Msg)
+
+ elif self.IsValidGuid (Op):
+ if not OperandStack:
+ OperandStack.append (self.OpConverter.OpEncode (0x00, Op))
+ else:
+ # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison.
+ self.Depex += self.OpConverter.OpEncode (0x00, Op)
+ self.Depex += OperandStack.pop ()
+
+ elif self.IsValidVersion (Op):
+ if not OperandStack:
+ OperandStack.append (self.OpConverter.OpEncode (0x01, Op))
+ else:
+ # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison.
+ self.Depex += self.OpConverter.OpEncode (0x01, Op)
+ self.Depex += OperandStack.pop ()
+
+ elif self.IsValidBoolean (Op):
+ if Op.upper () == 'FALSE':
+ self.Depex += self.OpConverter.OpEncode (0x07)
+ elif Op.upper () == 'TRUE':
+ self.Depex += self.OpConverter.OpEncode (0x06)
+
+ elif self.IsValidOperator (Op):
+ while (OpeartorStack and OpeartorStack[-1] != '(' and self.PriorityNotGreater (OpeartorStack[-1], Op)):
+ Operator = OpeartorStack.pop ()
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ OpeartorStack.append (Op)
+
+ i += 1
+
+ while OpeartorStack:
+ Operator = OpeartorStack.pop ()
+ if Operator == '(':
+ Msg = 'Too many \'(\'.'
+ raise ValueError (Msg)
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ self.Depex += self.OpConverter.OpEncode (0x0D)
+
+ self._Valid = True
+ self._DepexSize = len (self.Depex)
+ return self.Depex + self.Payload
+
+ def Decode (self, Buffer):
+ # initialize
+ self.Depex = Buffer
+ OperandStack = []
+ DepexLen = 0
+
+ while True:
+ Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:])
+ DepexLen += OperandSize + 1
+
+ if Opcode == 0x0D:
+ break
+
+ elif Opcode == 0x02:
+ if not OperandStack:
+ OperandStack.append ('DECLARE \"{String}\"'.format (String = Operand))
+ else:
+ PrevOperand = OperandStack.pop ()
+ OperandStack.append ('{Operand} DECLARE \"{String}\"'.format (Operand = PrevOperand, String = Operand))
+
+ elif Opcode in [0x00, 0x01]:
+ OperandStack.append (Operand)
+
+ elif Opcode == 0x06:
+ OperandStack.append ('TRUE')
+
+ elif Opcode == 0x07:
+ OperandStack.append ('FALSE')
+
+ elif self.IsValidOperator (self._opReferenceReverse[Opcode]):
+ Operator = self._opReferenceReverse[Opcode]
+ if self.IsValidUnaryOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 1:
+ Oprand = OperandStack.pop ()
+ OperandStack.append (' ( {Operator} {Oprand} )'.format (Operator = Operator, Oprand = Oprand))
+ elif self.IsValidBinocularOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 2:
+ Oprand1 = OperandStack.pop ()
+ Oprand2 = OperandStack.pop ()
+ OperandStack.append (' ( {Oprand1} {Operator} {Oprand2} )'.format (Operator = Operator, Oprand1 = Oprand1, Oprand2 = Oprand2))
+ else:
+ Msg = 'No enough Operands for {Opcode:02X}.'.format (Opcode = Opcode)
+ raise ValueError (Msg)
+
+ else:
+ Msg = '{Opcode:02X} is not a valid OpCode.'.format (Opcode = Opcode)
+ raise ValueError (Msg)
+
+ self.DepexExp = OperandStack[0].strip (' ')
+ self.Payload = Buffer[DepexLen:]
+ self._Valid = True
+ self._DepexSize = DepexLen
+ return self.Payload
+
+
+ def DumpInfo (self):
+ DepexLen = 0
+ Opcode = None
+ Buffer = self.Depex
+
+ if self._Valid == True:
+ print ('EFI_FIRMWARE_IMAGE_DEP.Dependencies = {')
+ while Opcode != 0x0D:
+ Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:])
+ DepexLen += OperandSize + 1
+ if Operand:
+ print (' {Opcode:02X}, {Operand},'.format (Opcode = Opcode, Operand = Operand))
+ else:
+ print (' {Opcode:02X},'.format (Opcode = Opcode))
+ print ('}')
+
+ print ('sizeof (EFI_FIRMWARE_IMAGE_DEP.Dependencies) = {Size:08X}'.format (Size = self._DepexSize))
+ print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload)))
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
new file mode 100755
index 00000000..cd64cc7a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
@@ -0,0 +1,190 @@
+## @file
+# Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with
+# certificate data and payload data.
+#
+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+'''
+FmpAuthHeader
+'''
+
+import struct
+import uuid
+
+class FmpAuthHeaderClass (object):
+ # ///
+ # /// Image Attribute -Authentication Required
+ # ///
+ # typedef struct {
+ # ///
+ # /// It is included in the signature of AuthInfo. It is used to ensure freshness/no replay.
+ # /// It is incremented during each firmware image operation.
+ # ///
+ # UINT64 MonotonicCount;
+ # ///
+ # /// Provides the authorization for the firmware image operations. It is a signature across
+ # /// the image data and the Monotonic Count value. Caller uses the private key that is
+ # /// associated with a public key that has been provisioned via the key exchange.
+ # /// Because this is defined as a signature, WIN_CERTIFICATE_UEFI_GUID.CertType must
+ # /// be EFI_CERT_TYPE_PKCS7_GUID.
+ # ///
+ # WIN_CERTIFICATE_UEFI_GUID AuthInfo;
+ # } EFI_FIRMWARE_IMAGE_AUTHENTICATION;
+ #
+ # ///
+ # /// Certificate which encapsulates a GUID-specific digital signature
+ # ///
+ # typedef struct {
+ # ///
+ # /// This is the standard WIN_CERTIFICATE header, where
+ # /// wCertificateType is set to WIN_CERT_TYPE_EFI_GUID.
+ # ///
+ # WIN_CERTIFICATE Hdr;
+ # ///
+ # /// This is the unique id which determines the
+ # /// format of the CertData. .
+ # ///
+ # EFI_GUID CertType;
+ # ///
+ # /// The following is the certificate data. The format of
+ # /// the data is determined by the CertType.
+ # /// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID,
+ # /// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure.
+ # ///
+ # UINT8 CertData[1];
+ # } WIN_CERTIFICATE_UEFI_GUID;
+ #
+ # ///
+ # /// The WIN_CERTIFICATE structure is part of the PE/COFF specification.
+ # ///
+ # typedef struct {
+ # ///
+ # /// The length of the entire certificate,
+ # /// including the length of the header, in bytes.
+ # ///
+ # UINT32 dwLength;
+ # ///
+ # /// The revision level of the WIN_CERTIFICATE
+ # /// structure. The current revision level is 0x0200.
+ # ///
+ # UINT16 wRevision;
+ # ///
+ # /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI
+ # /// certificate types. The UEFI specification reserves the range of
+ # /// certificate type values from 0x0EF0 to 0x0EFF.
+ # ///
+ # UINT16 wCertificateType;
+ # ///
+ # /// The following is the actual certificate. The format of
+ # /// the certificate depends on wCertificateType.
+ # ///
+ # /// UINT8 bCertificate[ANYSIZE_ARRAY];
+ # ///
+ # } WIN_CERTIFICATE;
+ #
+ # #define WIN_CERT_TYPE_EFI_GUID 0x0EF1
+ #
+ # ///
+ # /// This identifies a signature containing a DER-encoded PKCS #7 version 1.5 [RFC2315]
+ # /// SignedData value.
+ # ///
+ # #define EFI_CERT_TYPE_PKCS7_GUID \
+ # { \
+ # 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \
+ # }
+
+ _StructFormat = '<QIHH16s'
+ _StructSize = struct.calcsize (_StructFormat)
+
+ _MonotonicCountFormat = '<Q'
+ _MonotonicCountSize = struct.calcsize (_MonotonicCountFormat)
+
+ _StructAuthInfoFormat = '<IHH16s'
+ _StructAuthInfoSize = struct.calcsize (_StructAuthInfoFormat)
+
+ _WIN_CERT_REVISION = 0x0200
+ _WIN_CERT_TYPE_EFI_GUID = 0x0EF1
+ _EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID ('4aafd29d-68df-49ee-8aa9-347d375665a7')
+
+ def __init__ (self):
+ self._Valid = False
+ self.MonotonicCount = 0
+ self.dwLength = self._StructAuthInfoSize
+ self.wRevision = self._WIN_CERT_REVISION
+ self.wCertificateType = self._WIN_CERT_TYPE_EFI_GUID
+ self.CertType = self._EFI_CERT_TYPE_PKCS7_GUID
+ self.CertData = b''
+ self.Payload = b''
+
+
+ def Encode (self):
+ if self.wRevision != self._WIN_CERT_REVISION:
+ raise ValueError
+ if self.wCertificateType != self._WIN_CERT_TYPE_EFI_GUID:
+ raise ValueError
+ if self.CertType != self._EFI_CERT_TYPE_PKCS7_GUID:
+ raise ValueError
+ self.dwLength = self._StructAuthInfoSize + len (self.CertData)
+
+ FmpAuthHeader = struct.pack (
+ self._StructFormat,
+ self.MonotonicCount,
+ self.dwLength,
+ self.wRevision,
+ self.wCertificateType,
+ self.CertType.bytes_le
+ )
+ self._Valid = True
+
+ return FmpAuthHeader + self.CertData + self.Payload
+
+ def Decode (self, Buffer):
+ if len (Buffer) < self._StructSize:
+ raise ValueError
+ (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \
+ struct.unpack (
+ self._StructFormat,
+ Buffer[0:self._StructSize]
+ )
+ if dwLength < self._StructAuthInfoSize:
+ raise ValueError
+ if wRevision != self._WIN_CERT_REVISION:
+ raise ValueError
+ if wCertificateType != self._WIN_CERT_TYPE_EFI_GUID:
+ raise ValueError
+ if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le:
+ raise ValueError
+ self.MonotonicCount = MonotonicCount
+ self.dwLength = dwLength
+ self.wRevision = wRevision
+ self.wCertificateType = wCertificateType
+ self.CertType = uuid.UUID (bytes_le = CertType)
+ self.CertData = Buffer[self._StructSize:self._MonotonicCountSize + self.dwLength]
+ self.Payload = Buffer[self._MonotonicCountSize + self.dwLength:]
+ self._Valid = True
+ return self.Payload
+
+ def IsSigned (self, Buffer):
+ if len (Buffer) < self._StructSize:
+ return False
+ (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \
+ struct.unpack (
+ self._StructFormat,
+ Buffer[0:self._StructSize]
+ )
+ if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le:
+ return False
+ return True
+
+ def DumpInfo (self):
+ if not self._Valid:
+ raise ValueError
+ print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.MonotonicCount = {MonotonicCount:016X}'.format (MonotonicCount = self.MonotonicCount))
+ print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.dwLength = {dwLength:08X}'.format (dwLength = self.dwLength))
+ print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wRevision = {wRevision:04X}'.format (wRevision = self.wRevision))
+ print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wCertificateType = {wCertificateType:04X}'.format (wCertificateType = self.wCertificateType))
+ print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertType = {Guid}'.format (Guid = str(self.CertType).upper()))
+ print ('sizeof (EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertData) = {Size:08X}'.format (Size = len (self.CertData)))
+ print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload)))
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py
new file mode 100755
index 00000000..44bdcbc4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py
@@ -0,0 +1,310 @@
+## @file
+# Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with
+# a payload.
+#
+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+'''
+FmpCapsuleHeader
+'''
+
+import struct
+import uuid
+
+class FmpCapsuleImageHeaderClass (object):
+ # typedef struct {
+ # UINT32 Version;
+ #
+ # ///
+ # /// Used to identify device firmware targeted by this update. This guid is matched by
+ # /// system firmware against ImageTypeId field within a EFI_FIRMWARE_IMAGE_DESCRIPTOR
+ # ///
+ # EFI_GUID UpdateImageTypeId;
+ #
+ # ///
+ # /// Passed as ImageIndex in call to EFI_FIRMWARE_MANAGEMENT_PROTOCOL.SetImage ()
+ # ///
+ # UINT8 UpdateImageIndex;
+ # UINT8 reserved_bytes[3];
+ #
+ # ///
+ # /// Size of the binary update image which immediately follows this structure
+ # ///
+ # UINT32 UpdateImageSize;
+ #
+ # ///
+ # /// Size of the VendorCode bytes which optionally immediately follow binary update image in the capsule
+ # ///
+ # UINT32 UpdateVendorCodeSize;
+ #
+ # ///
+ # /// The HardwareInstance to target with this update. If value is zero it means match all
+ # /// HardwareInstances. This field allows update software to target only a single device in
+ # /// cases where there are more than one device with the same ImageTypeId GUID.
+ # /// This header is outside the signed data of the Authentication Info structure and
+ # /// therefore can be modified without changing the Auth data.
+ # ///
+ # UINT64 UpdateHardwareInstance;
+ #
+ # ///
+ # /// Bits which indicate authentication and depex information for the image that follows this structure
+ # ///
+ # UINT64 ImageCapsuleSupport
+ # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER;
+ #
+ # #define EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION 0x00000003
+
+ _StructFormat = '<I16sB3BIIQQ'
+ _StructSize = struct.calcsize (_StructFormat)
+
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION = 0x00000003
+
+ def __init__ (self):
+ self._Valid = False
+ self.Version = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION
+ self.UpdateImageTypeId = uuid.UUID ('00000000-0000-0000-0000-000000000000')
+ self.UpdateImageIndex = 0
+ self.UpdateImageSize = 0
+ self.UpdateVendorCodeSize = 0
+ self.UpdateHardwareInstance = 0x0000000000000000
+ self.ImageCapsuleSupport = 0x0000000000000000
+ self.Payload = b''
+ self.VendorCodeBytes = b''
+
+ def Encode (self):
+ self.UpdateImageSize = len (self.Payload)
+ self.UpdateVendorCodeSize = len (self.VendorCodeBytes)
+ FmpCapsuleImageHeader = struct.pack (
+ self._StructFormat,
+ self.Version,
+ self.UpdateImageTypeId.bytes_le,
+ self.UpdateImageIndex,
+ 0,0,0,
+ self.UpdateImageSize,
+ self.UpdateVendorCodeSize,
+ self.UpdateHardwareInstance,
+ self.ImageCapsuleSupport
+ )
+ self._Valid = True
+ return FmpCapsuleImageHeader + self.Payload + self.VendorCodeBytes
+
+ def Decode (self, Buffer):
+ if len (Buffer) < self._StructSize:
+ raise ValueError
+ (Version, UpdateImageTypeId, UpdateImageIndex, r0, r1, r2, UpdateImageSize, UpdateVendorCodeSize, UpdateHardwareInstance, ImageCapsuleSupport) = \
+ struct.unpack (
+ self._StructFormat,
+ Buffer[0:self._StructSize]
+ )
+
+ if Version < self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION:
+ raise ValueError
+ if UpdateImageIndex < 1:
+ raise ValueError
+ if UpdateImageSize + UpdateVendorCodeSize != len (Buffer[self._StructSize:]):
+ raise ValueError
+
+ self.Version = Version
+ self.UpdateImageTypeId = uuid.UUID (bytes_le = UpdateImageTypeId)
+ self.UpdateImageIndex = UpdateImageIndex
+ self.UpdateImageSize = UpdateImageSize
+ self.UpdateVendorCodeSize = UpdateVendorCodeSize
+ self.UpdateHardwareInstance = UpdateHardwareInstance
+ self.ImageCapsuleSupport = ImageCapsuleSupport
+ self.Payload = Buffer[self._StructSize:self._StructSize + UpdateImageSize]
+ self.VendorCodeBytes = Buffer[self._StructSize + UpdateImageSize:]
+ self._Valid = True
+ return Buffer[self._StructSize:]
+
+ def DumpInfo (self):
+ if not self._Valid:
+ raise ValueError
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.Version = {Version:08X}'.format (Version = self.Version))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageTypeId = {UpdateImageTypeId}'.format (UpdateImageTypeId = str(self.UpdateImageTypeId).upper()))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageIndex = {UpdateImageIndex:08X}'.format (UpdateImageIndex = self.UpdateImageIndex))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageSize = {UpdateImageSize:08X}'.format (UpdateImageSize = self.UpdateImageSize))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateVendorCodeSize = {UpdateVendorCodeSize:08X}'.format (UpdateVendorCodeSize = self.UpdateVendorCodeSize))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateHardwareInstance = {UpdateHardwareInstance:016X}'.format (UpdateHardwareInstance = self.UpdateHardwareInstance))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.ImageCapsuleSupport = {ImageCapsuleSupport:016X}'.format (ImageCapsuleSupport = self.ImageCapsuleSupport))
+ print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload)))
+ print ('sizeof (VendorCodeBytes) = {Size:08X}'.format (Size = len (self.VendorCodeBytes)))
+
+class FmpCapsuleHeaderClass (object):
+ # typedef struct {
+ # UINT32 Version;
+ #
+ # ///
+ # /// The number of drivers included in the capsule and the number of corresponding
+ # /// offsets stored in ItemOffsetList array.
+ # ///
+ # UINT16 EmbeddedDriverCount;
+ #
+ # ///
+ # /// The number of payload items included in the capsule and the number of
+ # /// corresponding offsets stored in the ItemOffsetList array.
+ # ///
+ # UINT16 PayloadItemCount;
+ #
+ # ///
+ # /// Variable length array of dimension [EmbeddedDriverCount + PayloadItemCount]
+ # /// containing offsets of each of the drivers and payload items contained within the capsule
+ # ///
+ # // UINT64 ItemOffsetList[];
+ # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER;
+ #
+ # #define EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION 0x00000001
+ _StructFormat = '<IHH'
+ _StructSize = struct.calcsize (_StructFormat)
+
+ _ItemOffsetFormat = '<Q'
+ _ItemOffsetSize = struct.calcsize (_ItemOffsetFormat)
+
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION = 0x00000001
+ CAPSULE_SUPPORT_AUTHENTICATION = 0x0000000000000001
+ CAPSULE_SUPPORT_DEPENDENCY = 0x0000000000000002
+
+ def __init__ (self):
+ self._Valid = False
+ self.Version = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION
+ self.EmbeddedDriverCount = 0
+ self.PayloadItemCount = 0
+ self._ItemOffsetList = []
+ self._EmbeddedDriverList = []
+ self._PayloadList = []
+ self._FmpCapsuleImageHeaderList = []
+
+ def AddEmbeddedDriver (self, EmbeddedDriver):
+ self._EmbeddedDriverList.append (EmbeddedDriver)
+
+ def GetEmbeddedDriver (self, Index):
+ if Index > len (self._EmbeddedDriverList):
+ raise ValueError
+ return self._EmbeddedDriverList[Index]
+
+ def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0, UpdateImageIndex = 1, CapsuleSupport = 0):
+ self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex, CapsuleSupport))
+
+ def GetFmpCapsuleImageHeader (self, Index):
+ if Index >= len (self._FmpCapsuleImageHeaderList):
+ raise ValueError
+ return self._FmpCapsuleImageHeaderList[Index]
+
+ def Encode (self):
+ self.EmbeddedDriverCount = len (self._EmbeddedDriverList)
+ self.PayloadItemCount = len (self._PayloadList)
+
+ FmpCapsuleHeader = struct.pack (
+ self._StructFormat,
+ self.Version,
+ self.EmbeddedDriverCount,
+ self.PayloadItemCount
+ )
+
+ FmpCapsuleData = b''
+ Offset = self._StructSize + (self.EmbeddedDriverCount + self.PayloadItemCount) * self._ItemOffsetSize
+ for EmbeddedDriver in self._EmbeddedDriverList:
+ FmpCapsuleData = FmpCapsuleData + EmbeddedDriver
+ self._ItemOffsetList.append (Offset)
+ Offset = Offset + len (EmbeddedDriver)
+ Index = 1
+ for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex, CapsuleSupport) in self._PayloadList:
+ FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass ()
+ FmpCapsuleImageHeader.UpdateImageTypeId = UpdateImageTypeId
+ FmpCapsuleImageHeader.UpdateImageIndex = UpdateImageIndex
+ FmpCapsuleImageHeader.Payload = Payload
+ FmpCapsuleImageHeader.VendorCodeBytes = VendorCodeBytes
+ FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance
+ FmpCapsuleImageHeader.ImageCapsuleSupport = CapsuleSupport
+ FmpCapsuleImage = FmpCapsuleImageHeader.Encode ()
+ FmpCapsuleData = FmpCapsuleData + FmpCapsuleImage
+
+ self._ItemOffsetList.append (Offset)
+ self._FmpCapsuleImageHeaderList.append (FmpCapsuleImageHeader)
+
+ Offset = Offset + len (FmpCapsuleImage)
+ Index = Index + 1
+
+ for Offset in self._ItemOffsetList:
+ FmpCapsuleHeader = FmpCapsuleHeader + struct.pack (self._ItemOffsetFormat, Offset)
+
+ self._Valid = True
+ return FmpCapsuleHeader + FmpCapsuleData
+
+ def Decode (self, Buffer):
+ if len (Buffer) < self._StructSize:
+ raise ValueError
+ (Version, EmbeddedDriverCount, PayloadItemCount) = \
+ struct.unpack (
+ self._StructFormat,
+ Buffer[0:self._StructSize]
+ )
+ if Version < self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION:
+ raise ValueError
+
+ self.Version = Version
+ self.EmbeddedDriverCount = EmbeddedDriverCount
+ self.PayloadItemCount = PayloadItemCount
+ self._ItemOffsetList = []
+ self._EmbeddedDriverList = []
+ self._PayloadList = []
+ self._FmpCapsuleImageHeaderList = []
+
+ #
+ # Parse the ItemOffsetList values
+ #
+ Offset = self._StructSize
+ for Index in range (0, EmbeddedDriverCount + PayloadItemCount):
+ ItemOffset = struct.unpack (self._ItemOffsetFormat, Buffer[Offset:Offset + self._ItemOffsetSize])[0]
+ if ItemOffset >= len (Buffer):
+ raise ValueError
+ self._ItemOffsetList.append (ItemOffset)
+ Offset = Offset + self._ItemOffsetSize
+ Result = Buffer[Offset:]
+
+ #
+ # Parse the EmbeddedDrivers
+ #
+ for Index in range (0, EmbeddedDriverCount):
+ Offset = self._ItemOffsetList[Index]
+ if Index < (len (self._ItemOffsetList) - 1):
+ Length = self._ItemOffsetList[Index + 1] - Offset
+ else:
+ Length = len (Buffer) - Offset
+ self.AddEmbeddedDriver (Buffer[Offset:Offset + Length])
+
+ #
+ # Parse the Payloads that are FMP Capsule Images
+ #
+ for Index in range (EmbeddedDriverCount, EmbeddedDriverCount + PayloadItemCount):
+ Offset = self._ItemOffsetList[Index]
+ if Index < (len (self._ItemOffsetList) - 1):
+ Length = self._ItemOffsetList[Index + 1] - Offset
+ else:
+ Length = len (Buffer) - Offset
+ FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass ()
+ FmpCapsuleImageHeader.Decode (Buffer[Offset:Offset + Length])
+ self.AddPayload (
+ FmpCapsuleImageHeader.UpdateImageTypeId,
+ FmpCapsuleImageHeader.Payload,
+ FmpCapsuleImageHeader.VendorCodeBytes
+ )
+ self._FmpCapsuleImageHeaderList.append (FmpCapsuleImageHeader)
+
+ self._Valid = True
+ return Result
+
+ def DumpInfo (self):
+ if not self._Valid:
+ raise ValueError
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version = {Version:08X}'.format (Version = self.Version))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverCount = {EmbeddedDriverCount:08X}'.format (EmbeddedDriverCount = self.EmbeddedDriverCount))
+ for EmbeddedDriver in self._EmbeddedDriverList:
+ print (' sizeof (EmbeddedDriver) = {Size:08X}'.format (Size = len (EmbeddedDriver)))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCount = {PayloadItemCount:08X}'.format (PayloadItemCount = self.PayloadItemCount))
+ print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList = ')
+ for Offset in self._ItemOffsetList:
+ print (' {Offset:016X}'.format (Offset = Offset))
+ for FmpCapsuleImageHeader in self._FmpCapsuleImageHeaderList:
+ FmpCapsuleImageHeader.DumpInfo ()
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py
new file mode 100755
index 00000000..109c1e49
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py
@@ -0,0 +1,130 @@
+## @file
+# Module that encodes and decodes a EFI_CAPSULE_HEADER with a payload
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+'''
+UefiCapsuleHeader
+'''
+
+import struct
+import uuid
+
+class UefiCapsuleHeaderClass (object):
+ # typedef struct {
+ # ///
+ # /// A GUID that defines the contents of a capsule.
+ # ///
+ # EFI_GUID CapsuleGuid;
+ # ///
+ # /// The size of the capsule header. This may be larger than the size of
+ # /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply
+ # /// extended header entries
+ # ///
+ # UINT32 HeaderSize;
+ # ///
+ # /// Bit-mapped list describing the capsule attributes. The Flag values
+ # /// of 0x0000 - 0xFFFF are defined by CapsuleGuid. Flag values
+ # /// of 0x10000 - 0xFFFFFFFF are defined by this specification
+ # ///
+ # UINT32 Flags;
+ # ///
+ # /// Size in bytes of the capsule.
+ # ///
+ # UINT32 CapsuleImageSize;
+ # } EFI_CAPSULE_HEADER;
+ #
+ # #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000
+ # #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000
+ # #define CAPSULE_FLAGS_INITIATE_RESET 0x00040000
+ #
+ _StructFormat = '<16sIIII'
+ _StructSize = struct.calcsize (_StructFormat)
+
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID = uuid.UUID ('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')
+
+ _CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000
+ _CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000
+ _CAPSULE_FLAGS_INITIATE_RESET = 0x00040000
+
+ def __init__ (self):
+ self._Valid = False
+ self.CapsuleGuid = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID
+ self.HeaderSize = self._StructSize
+ self.OemFlags = 0x0000
+ self.PersistAcrossReset = False
+ self.PopulateSystemTable = False
+ self.InitiateReset = False
+ self.CapsuleImageSize = self.HeaderSize
+ self.Payload = b''
+
+ def Encode (self):
+ Flags = self.OemFlags
+ if self.PersistAcrossReset:
+ Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET
+ if self.PopulateSystemTable:
+ Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
+ if self.InitiateReset:
+ Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET
+
+ self.CapsuleImageSize = self.HeaderSize + len (self.Payload)
+
+ UefiCapsuleHeader = struct.pack (
+ self._StructFormat,
+ self.CapsuleGuid.bytes_le,
+ self.HeaderSize,
+ Flags,
+ self.CapsuleImageSize,
+ 0
+ )
+ self._Valid = True
+ return UefiCapsuleHeader + self.Payload
+
+ def Decode (self, Buffer):
+ if len (Buffer) < self._StructSize:
+ raise ValueError
+ (CapsuleGuid, HeaderSize, Flags, CapsuleImageSize, Reserved) = \
+ struct.unpack (
+ self._StructFormat,
+ Buffer[0:self._StructSize]
+ )
+ if HeaderSize < self._StructSize:
+ raise ValueError
+ if CapsuleImageSize != len (Buffer):
+ raise ValueError
+ self.CapsuleGuid = uuid.UUID (bytes_le = CapsuleGuid)
+ self.HeaderSize = HeaderSize
+ self.OemFlags = Flags & 0xffff
+ self.PersistAcrossReset = (Flags & self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0
+ self.PopulateSystemTable = (Flags & self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0
+ self.InitiateReset = (Flags & self._CAPSULE_FLAGS_INITIATE_RESET) != 0
+ self.CapsuleImageSize = CapsuleImageSize
+ self.Payload = Buffer[self.HeaderSize:]
+
+ self._Valid = True
+ return self.Payload
+
+ def DumpInfo (self):
+ if not self._Valid:
+ raise ValueError
+ Flags = self.OemFlags
+ if self.PersistAcrossReset:
+ Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET
+ if self.PopulateSystemTable:
+ Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
+ if self.InitiateReset:
+ Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET
+ print ('EFI_CAPSULE_HEADER.CapsuleGuid = {Guid}'.format (Guid = str(self.CapsuleGuid).upper()))
+ print ('EFI_CAPSULE_HEADER.HeaderSize = {Size:08X}'.format (Size = self.HeaderSize))
+ print ('EFI_CAPSULE_HEADER.Flags = {Flags:08X}'.format (Flags = Flags))
+ print (' OEM Flags = {Flags:04X}'.format (Flags = self.OemFlags))
+ if self.PersistAcrossReset:
+ print (' CAPSULE_FLAGS_PERSIST_ACROSS_RESET')
+ if self.PopulateSystemTable:
+ print (' CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE')
+ if self.InitiateReset:
+ print (' CAPSULE_FLAGS_INITIATE_RESET')
+ print ('EFI_CAPSULE_HEADER.CapsuleImageSize = {Size:08X}'.format (Size = self.CapsuleImageSize))
+ print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload)))
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py
new file mode 100644
index 00000000..f9a73858
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py
@@ -0,0 +1,9 @@
+## @file
+# Python 'Common.Uefi.Capsule' package initialization file.
+#
+# This file is required to make Python interpreter treat the directory
+# as containing package.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/__init__.py
new file mode 100644
index 00000000..47322db6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/__init__.py
@@ -0,0 +1,9 @@
+## @file
+# Python 'Common.Uefi' package initialization file.
+#
+# This file is required to make Python interpreter treat the directory
+# as containing package.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VariableAttributes.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VariableAttributes.py
new file mode 100755
index 00000000..1b451a89
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VariableAttributes.py
@@ -0,0 +1,51 @@
+# # @file
+#
+# This file is used to handle the variable attributes and property information
+#
+#
+# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+class VariableAttributes(object):
+ EFI_VARIABLE_NON_VOLATILE = 0x00000001
+ EFI_VARIABLE_BOOTSERVICE_ACCESS = 0x00000002
+ EFI_VARIABLE_RUNTIME_ACCESS = 0x00000004
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY = 0x00000001
+ VarAttributesMap = {
+ "NV":EFI_VARIABLE_NON_VOLATILE,
+ "BS":EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ "RT":EFI_VARIABLE_RUNTIME_ACCESS,
+ "RO":VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
+ }
+
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def GetVarAttributes(var_attr_str):
+ VarAttr = 0x00000000
+ VarProp = 0x00000000
+
+ attr_list = var_attr_str.split(",")
+ for attr in attr_list:
+ attr = attr.strip()
+ if attr == 'RO':
+ VarProp = VariableAttributes.VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY
+ else:
+ VarAttr = VarAttr | VariableAttributes.VarAttributesMap.get(attr, 0x00000000)
+ return VarAttr, VarProp
+ @staticmethod
+ def ValidateVarAttributes(var_attr_str):
+ if not var_attr_str:
+ return True, ""
+ attr_list = var_attr_str.split(",")
+ attr_temp = []
+ for attr in attr_list:
+ attr = attr.strip()
+ attr_temp.append(attr)
+ if attr not in VariableAttributes.VarAttributesMap:
+ return False, "The variable attribute %s is not support to be specified in dsc file. Supported variable attribute are ['BS','NV','RT','RO'] "
+ if 'RT' in attr_temp and 'BS' not in attr_temp:
+ return False, "the RT attribute need the BS attribute to be present"
+ return True, ""
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VpdInfoFile.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VpdInfoFile.py
new file mode 100755
index 00000000..ac099a14
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/VpdInfoFile.py
@@ -0,0 +1,255 @@
+## @file
+#
+# This package manage the VPD PCD information file which will be generated
+# by build tool's autogen.
+# The VPD PCD information file will be input for third-party BPDG tool which
+# is pointed by *_*_*_VPD_TOOL_GUID in conf/tools_def.txt
+#
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+from __future__ import print_function
+import Common.LongFilePathOs as os
+import re
+import Common.EdkLogger as EdkLogger
+import Common.BuildToolError as BuildToolError
+import subprocess
+import Common.GlobalData as GlobalData
+from Common.LongFilePathSupport import OpenLongFilePath as open
+from Common.Misc import SaveFileOnChange
+from Common.DataType import *
+
+FILE_COMMENT_TEMPLATE = \
+"""
+## @file
+#
+# THIS IS AUTO-GENERATED FILE BY BUILD TOOLS AND PLEASE DO NOT MAKE MODIFICATION.
+#
+# This file lists all VPD informations for a platform collected by build.exe.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+
+"""
+
+## The class manage VpdInfoFile.
+#
+# This file contains an ordered (based on position in the DSC file) list of the PCDs specified in the platform description file (DSC). The Value field that will be assigned to the PCD comes from the DSC file, INF file (if not defined in the DSC file) or the DEC file (if not defined in the INF file). This file is used as an input to the BPDG tool.
+# Format for this file (using EBNF notation) is:
+# <File> :: = [<CommentBlock>]
+# [<PcdEntry>]*
+# <CommentBlock> ::= ["#" <String> <EOL>]*
+# <PcdEntry> ::= <PcdName> "|" <Offset> "|" <Size> "|" <Value> <EOL>
+# <PcdName> ::= <TokenSpaceCName> "." <PcdCName>
+# <TokenSpaceCName> ::= C Variable Name of the Token Space GUID
+# <PcdCName> ::= C Variable Name of the PCD
+# <Offset> ::= {TAB_STAR} {<HexNumber>}
+# <HexNumber> ::= "0x" (a-fA-F0-9){1,8}
+# <Size> ::= <HexNumber>
+# <Value> ::= {<HexNumber>} {<NonNegativeInt>} {<QString>} {<Array>}
+# <NonNegativeInt> ::= (0-9)+
+# <QString> ::= ["L"] <DblQuote> <String> <DblQuote>
+# <DblQuote> ::= 0x22
+# <Array> ::= {<CArray>} {<NList>}
+# <CArray> ::= "{" <HexNumber> ["," <HexNumber>]* "}"
+# <NList> ::= <HexNumber> ["," <HexNumber>]*
+#
+class VpdInfoFile:
+
+ _rVpdPcdLine = None
+ ## Constructor
+ def __init__(self):
+ ## Dictionary for VPD in following format
+ #
+ # Key : PcdClassObject instance.
+ # @see BuildClassObject.PcdClassObject
+ # Value : offset in different SKU such as [sku1_offset, sku2_offset]
+ self._VpdArray = {}
+ self._VpdInfo = {}
+
+ ## Add a VPD PCD collected from platform's autogen when building.
+ #
+ # @param vpds The list of VPD PCD collected for a platform.
+ # @see BuildClassObject.PcdClassObject
+ #
+ # @param offset integer value for VPD's offset in specific SKU.
+ #
+ def Add(self, Vpd, skuname, Offset):
+ if (Vpd is None):
+ EdkLogger.error("VpdInfoFile", BuildToolError.ATTRIBUTE_UNKNOWN_ERROR, "Invalid VPD PCD entry.")
+
+ if not (Offset >= "0" or Offset == TAB_STAR):
+ EdkLogger.error("VpdInfoFile", BuildToolError.PARAMETER_INVALID, "Invalid offset parameter: %s." % Offset)
+
+ if Vpd.DatumType == TAB_VOID:
+ if Vpd.MaxDatumSize <= "0":
+ EdkLogger.error("VpdInfoFile", BuildToolError.PARAMETER_INVALID,
+ "Invalid max datum size for VPD PCD %s.%s" % (Vpd.TokenSpaceGuidCName, Vpd.TokenCName))
+ elif Vpd.DatumType in TAB_PCD_NUMERIC_TYPES:
+ if not Vpd.MaxDatumSize:
+ Vpd.MaxDatumSize = MAX_SIZE_TYPE[Vpd.DatumType]
+ else:
+ if Vpd.MaxDatumSize <= "0":
+ EdkLogger.error("VpdInfoFile", BuildToolError.PARAMETER_INVALID,
+ "Invalid max datum size for VPD PCD %s.%s" % (Vpd.TokenSpaceGuidCName, Vpd.TokenCName))
+
+ if Vpd not in self._VpdArray:
+ #
+ # If there is no Vpd instance in dict, that imply this offset for a given SKU is a new one
+ #
+ self._VpdArray[Vpd] = {}
+
+ self._VpdArray[Vpd].update({skuname:Offset})
+
+
+ ## Generate VPD PCD information into a text file
+ #
+ # If parameter FilePath is invalid, then assert.
+ # If
+ # @param FilePath The given file path which would hold VPD information
+ def Write(self, FilePath):
+ if not (FilePath is not None or len(FilePath) != 0):
+ EdkLogger.error("VpdInfoFile", BuildToolError.PARAMETER_INVALID,
+ "Invalid parameter FilePath: %s." % FilePath)
+
+ Content = FILE_COMMENT_TEMPLATE
+ Pcds = sorted(self._VpdArray.keys(), key=lambda x: x.TokenCName)
+ for Pcd in Pcds:
+ i = 0
+ PcdTokenCName = Pcd.TokenCName
+ for PcdItem in GlobalData.MixedPcd:
+ if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
+ PcdTokenCName = PcdItem[0]
+ for skuname in self._VpdArray[Pcd]:
+ PcdValue = str(Pcd.SkuInfoList[skuname].DefaultValue).strip()
+ if PcdValue == "" :
+ PcdValue = Pcd.DefaultValue
+
+ Content += "%s.%s|%s|%s|%s|%s \n" % (Pcd.TokenSpaceGuidCName, PcdTokenCName, skuname, str(self._VpdArray[Pcd][skuname]).strip(), str(Pcd.MaxDatumSize).strip(), PcdValue)
+ i += 1
+
+ return SaveFileOnChange(FilePath, Content, False)
+
+ ## Read an existing VPD PCD info file.
+ #
+ # This routine will read VPD PCD information from existing file and construct
+ # internal PcdClassObject array.
+ # This routine could be used by third-party tool to parse VPD info file content.
+ #
+ # @param FilePath The full path string for existing VPD PCD info file.
+ def Read(self, FilePath):
+ try:
+ fd = open(FilePath, "r")
+ except:
+ EdkLogger.error("VpdInfoFile",
+ BuildToolError.FILE_OPEN_FAILURE,
+ "Fail to open file %s for written." % FilePath)
+ Lines = fd.readlines()
+ for Line in Lines:
+ Line = Line.strip()
+ if len(Line) == 0 or Line.startswith("#"):
+ continue
+
+ #
+ # the line must follow output format defined in BPDG spec.
+ #
+ try:
+ PcdName, SkuId, Offset, Size, Value = Line.split("#")[0].split("|")
+ PcdName, SkuId, Offset, Size, Value = PcdName.strip(), SkuId.strip(), Offset.strip(), Size.strip(), Value.strip()
+ TokenSpaceName, PcdTokenName = PcdName.split(".")
+ except:
+ EdkLogger.error("BPDG", BuildToolError.PARSER_ERROR, "Fail to parse VPD information file %s" % FilePath)
+
+ Found = False
+
+ if (TokenSpaceName, PcdTokenName) not in self._VpdInfo:
+ self._VpdInfo[(TokenSpaceName, PcdTokenName)] = {}
+ self._VpdInfo[(TokenSpaceName, PcdTokenName)][(SkuId, Offset)] = Value
+ for VpdObject in self._VpdArray:
+ VpdObjectTokenCName = VpdObject.TokenCName
+ for PcdItem in GlobalData.MixedPcd:
+ if (VpdObject.TokenCName, VpdObject.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
+ VpdObjectTokenCName = PcdItem[0]
+ for sku in VpdObject.SkuInfoList:
+ if VpdObject.TokenSpaceGuidCName == TokenSpaceName and VpdObjectTokenCName == PcdTokenName.strip() and sku == SkuId:
+ if self._VpdArray[VpdObject][sku] == TAB_STAR:
+ if Offset == TAB_STAR:
+ EdkLogger.error("BPDG", BuildToolError.FORMAT_INVALID, "The offset of %s has not been fixed up by third-party BPDG tool." % PcdName)
+ self._VpdArray[VpdObject][sku] = Offset
+ Found = True
+ if not Found:
+ EdkLogger.error("BPDG", BuildToolError.PARSER_ERROR, "Can not find PCD defined in VPD guid file.")
+
+ ## Get count of VPD PCD collected from platform's autogen when building.
+ #
+ # @return The integer count value
+ def GetCount(self):
+ Count = 0
+ for OffsetList in self._VpdArray.values():
+ Count += len(OffsetList)
+
+ return Count
+
+ ## Get an offset value for a given VPD PCD
+ #
+ # Because BPDG only support one Sku, so only return offset for SKU default.
+ #
+ # @param vpd A given VPD PCD
+ def GetOffset(self, vpd):
+ if vpd not in self._VpdArray:
+ return None
+
+ if len(self._VpdArray[vpd]) == 0:
+ return None
+
+ return self._VpdArray[vpd]
+ def GetVpdInfo(self, arg):
+ (PcdTokenName, TokenSpaceName) = arg
+ return [(sku,offset,value) for (sku,offset),value in self._VpdInfo.get((TokenSpaceName, PcdTokenName)).items()]
+
+## Call external BPDG tool to process VPD file
+#
+# @param ToolPath The string path name for BPDG tool
+# @param VpdFileName The string path name for VPD information guid.txt
+#
+def CallExtenalBPDGTool(ToolPath, VpdFileName):
+ assert ToolPath is not None, "Invalid parameter ToolPath"
+ assert VpdFileName is not None and os.path.exists(VpdFileName), "Invalid parameter VpdFileName"
+
+ OutputDir = os.path.dirname(VpdFileName)
+ FileName = os.path.basename(VpdFileName)
+ BaseName, ext = os.path.splitext(FileName)
+ OutputMapFileName = os.path.join(OutputDir, "%s.map" % BaseName)
+ OutputBinFileName = os.path.join(OutputDir, "%s.bin" % BaseName)
+
+ try:
+ PopenObject = subprocess.Popen(' '.join([ToolPath,
+ '-o', OutputBinFileName,
+ '-m', OutputMapFileName,
+ '-q',
+ '-f',
+ VpdFileName]),
+ stdout=subprocess.PIPE,
+ stderr= subprocess.PIPE,
+ shell=True)
+ except Exception as X:
+ EdkLogger.error("BPDG", BuildToolError.COMMAND_FAILURE, ExtraData=str(X))
+ (out, error) = PopenObject.communicate()
+ print(out.decode())
+ while PopenObject.returncode is None :
+ PopenObject.wait()
+
+ if PopenObject.returncode != 0:
+ EdkLogger.debug(EdkLogger.DEBUG_1, "Fail to call BPDG tool", str(error))
+ EdkLogger.error("BPDG", BuildToolError.COMMAND_FAILURE, "Fail to execute BPDG tool with exit code: %d, the error message is: \n %s" % \
+ (PopenObject.returncode, str(error)))
+
+ return PopenObject.returncode
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/__init__.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/__init__.py
new file mode 100644
index 00000000..b28ac448
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/__init__.py
@@ -0,0 +1,9 @@
+## @file
+# Python 'Common' 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.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/caching.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/caching.py
new file mode 100755
index 00000000..681740c1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/caching.py
@@ -0,0 +1,41 @@
+## @file
+# help with caching in BaseTools
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+## Import Modules
+#
+
+# for class function
+class cached_class_function(object):
+ def __init__(self, function):
+ self._function = function
+ def __get__(self, obj, cls):
+ def CallMeHere(*args,**kwargs):
+ Value = self._function(obj, *args,**kwargs)
+ obj.__dict__[self._function.__name__] = lambda *args,**kwargs:Value
+ return Value
+ return CallMeHere
+
+# for class property
+class cached_property(object):
+ def __init__(self, function):
+ self._function = function
+ def __get__(self, obj, cls):
+ Value = obj.__dict__[self._function.__name__] = self._function(obj)
+ return Value
+
+# for non-class function
+class cached_basic_function(object):
+ def __init__(self, function):
+ self._function = function
+ # wrapper to call _do since <class>.__dict__ doesn't support changing __call__
+ def __call__(self,*args,**kwargs):
+ return self._do(*args,**kwargs)
+ def _do(self,*args,**kwargs):
+ Value = self._function(*args,**kwargs)
+ self.__dict__['_do'] = lambda self,*args,**kwargs:Value
+ return Value