| ## @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 ('Buffer is too small for decoding') | |
| (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 ('Incorrect capsule image header version') | |
| if UpdateImageIndex < 1: | |
| raise ValueError ('Update image index is less than 1') | |
| if UpdateImageSize + UpdateVendorCodeSize != len (Buffer[self._StructSize:]): | |
| raise ValueError ('Non-vendor and vendor parts do not add up') | |
| 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 ('Can not dump an invalid header') | |
| 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 ('Invalid embedded driver index') | |
| 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 ('Invalid capsule image index') | |
| 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 ('Buffer is too small for decoding') | |
| (Version, EmbeddedDriverCount, PayloadItemCount) = \ | |
| struct.unpack ( | |
| self._StructFormat, | |
| Buffer[0:self._StructSize] | |
| ) | |
| if Version < self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION: | |
| raise ValueError ('Incorrect capsule header version') | |
| 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 ('Item offset is outside of buffer') | |
| 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 ('Can not dump an invalid header') | |
| 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 () |