From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Common/Uefi/Capsule/CapsuleDependency.py | 409 +++++++++++++++++++++ .../Python/Common/Uefi/Capsule/FmpAuthHeader.py | 190 ++++++++++ .../Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | 310 ++++++++++++++++ .../Common/Uefi/Capsule/UefiCapsuleHeader.py | 130 +++++++ .../Source/Python/Common/Uefi/Capsule/__init__.py | 9 + .../Source/Python/Common/Uefi/__init__.py | 9 + 6 files changed, 1057 insertions(+) create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py create mode 100755 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py create mode 100644 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py create mode 100644 src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi/__init__.py (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Common/Uefi') 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.
+# 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 ('': [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.
+# 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 = ' +# 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 = ' 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.
+# 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.
+# 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.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# -- cgit v1.2.3