1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
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 ('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 ()
|