blob: ad60bbf2b52820cb7bff2eb415abd051c43e0535 [file] [log] [blame]
Deepak Kodihalli4ac93442021-04-20 14:44:48 +05301#!/usr/bin/env python3
2
3"""Script to create PLDM FW update package"""
4
5import argparse
6import binascii
Deepak Kodihalli4ac93442021-04-20 14:44:48 +05307import json
Patrick Williamsc44715d2022-12-08 06:18:18 -06008import math
Deepak Kodihalli4ac93442021-04-20 14:44:48 +05309import os
10import struct
11import sys
Patrick Williamsc44715d2022-12-08 06:18:18 -060012from datetime import datetime
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053013
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053014from bitarray import bitarray
15from bitarray.util import ba2int
16
Patrick Williamsc44715d2022-12-08 06:18:18 -060017string_types = dict(
18 [
19 ("Unknown", 0),
20 ("ASCII", 1),
21 ("UTF8", 2),
22 ("UTF16", 3),
23 ("UTF16LE", 4),
24 ("UTF16BE", 5),
25 ]
26)
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053027
Tom Josephda2aaab2021-08-01 19:23:09 -070028initial_descriptor_type_name_length = {
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053029 0x0000: ["PCI Vendor ID", 2],
30 0x0001: ["IANA Enterprise ID", 4],
31 0x0002: ["UUID", 16],
32 0x0003: ["PnP Vendor ID", 3],
Patrick Williamsc44715d2022-12-08 06:18:18 -060033 0x0004: ["ACPI Vendor ID", 4],
34}
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053035
Tom Josephda2aaab2021-08-01 19:23:09 -070036descriptor_type_name_length = {
37 0x0000: ["PCI Vendor ID", 2],
38 0x0001: ["IANA Enterprise ID", 4],
39 0x0002: ["UUID", 16],
40 0x0003: ["PnP Vendor ID", 3],
41 0x0004: ["ACPI Vendor ID", 4],
42 0x0100: ["PCI Device ID", 2],
43 0x0101: ["PCI Subsystem Vendor ID", 2],
44 0x0102: ["PCI Subsystem ID", 2],
45 0x0103: ["PCI Revision ID", 1],
46 0x0104: ["PnP Product Identifier", 4],
Patrick Williamsc44715d2022-12-08 06:18:18 -060047 0x0105: ["ACPI Product Identifier", 4],
48}
Tom Josephda2aaab2021-08-01 19:23:09 -070049
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053050
51def check_string_length(string):
52 """Check if the length of the string is not greater than 255."""
53 if len(string) > 255:
54 sys.exit("ERROR: Max permitted string length is 255")
55
56
57def write_pkg_release_date_time(pldm_fw_up_pkg, release_date_time):
Patrick Williamsc44715d2022-12-08 06:18:18 -060058 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053059 Write the timestamp into the package header. The timestamp is formatted as
60 series of 13 bytes defined in DSP0240 specification.
61
62 Parameters:
63 pldm_fw_up_pkg: PLDM FW update package
64 release_date_time: Package Release Date Time
Patrick Williamsc44715d2022-12-08 06:18:18 -060065 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053066 time = release_date_time.time()
67 date = release_date_time.date()
Patrick Williamsc44715d2022-12-08 06:18:18 -060068 us_bytes = time.microsecond.to_bytes(3, byteorder="little")
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053069 pldm_fw_up_pkg.write(
70 struct.pack(
Patrick Williamsc44715d2022-12-08 06:18:18 -060071 "<hBBBBBBBBHB",
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053072 0,
73 us_bytes[0],
74 us_bytes[1],
75 us_bytes[2],
76 time.second,
77 time.minute,
78 time.hour,
79 date.day,
80 date.month,
81 date.year,
Patrick Williamsc44715d2022-12-08 06:18:18 -060082 0,
83 )
84 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053085
86
87def write_package_version_string(pldm_fw_up_pkg, metadata):
Patrick Williamsc44715d2022-12-08 06:18:18 -060088 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053089 Write PackageVersionStringType, PackageVersionStringLength and
90 PackageVersionString to the package header.
91
92 Parameters:
93 pldm_fw_up_pkg: PLDM FW update package
94 metadata: metadata about PLDM FW update package
Patrick Williamsc44715d2022-12-08 06:18:18 -060095 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +053096 # Hardcoded string type to ASCII
97 string_type = string_types["ASCII"]
Patrick Williamsc44715d2022-12-08 06:18:18 -060098 package_version_string = metadata["PackageHeaderInformation"][
99 "PackageVersionString"
100 ]
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530101 check_string_length(package_version_string)
Patrick Williamsc44715d2022-12-08 06:18:18 -0600102 format_string = "<BB" + str(len(package_version_string)) + "s"
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530103 pldm_fw_up_pkg.write(
104 struct.pack(
105 format_string,
106 string_type,
107 len(package_version_string),
Patrick Williamsc44715d2022-12-08 06:18:18 -0600108 package_version_string.encode("ascii"),
109 )
110 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530111
112
113def write_component_bitmap_bit_length(pldm_fw_up_pkg, metadata):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600114 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530115 ComponentBitmapBitLength in the package header indicates the number of bits
116 that will be used represent the bitmap in the ApplicableComponents field
117 for a matching device. The value shall be a multiple of 8 and be large
118 enough to contain a bit for each component in the package. The number of
119 components in the JSON file is used to populate the bitmap length.
120
121 Parameters:
122 pldm_fw_up_pkg: PLDM FW update package
123 metadata: metadata about PLDM FW update package
124
125 Returns:
126 ComponentBitmapBitLength: number of bits that will be used
127 represent the bitmap in the ApplicableComponents field for a
128 matching device
Patrick Williamsc44715d2022-12-08 06:18:18 -0600129 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530130 # The script supports upto 32 components now
131 max_components = 32
132 bitmap_multiple = 8
133
134 num_components = len(metadata["ComponentImageInformationArea"])
135 if num_components > max_components:
136 sys.exit("ERROR: only upto 32 components supported now")
Patrick Williamsc44715d2022-12-08 06:18:18 -0600137 component_bitmap_bit_length = bitmap_multiple * math.ceil(
138 num_components / bitmap_multiple
139 )
140 pldm_fw_up_pkg.write(struct.pack("<H", int(component_bitmap_bit_length)))
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530141 return component_bitmap_bit_length
142
143
144def write_pkg_header_info(pldm_fw_up_pkg, metadata):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600145 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530146 ComponentBitmapBitLength in the package header indicates the number of bits
147 that will be used represent the bitmap in the ApplicableComponents field
148 for a matching device. The value shall be a multiple of 8 and be large
149 enough to contain a bit for each component in the package. The number of
150 components in the JSON file is used to populate the bitmap length.
151
152 Parameters:
153 pldm_fw_up_pkg: PLDM FW update package
154 metadata: metadata about PLDM FW update package
155
156 Returns:
157 ComponentBitmapBitLength: number of bits that will be used
158 represent the bitmap in the ApplicableComponents field for a
159 matching device
Patrick Williamsc44715d2022-12-08 06:18:18 -0600160 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530161 uuid = metadata["PackageHeaderInformation"]["PackageHeaderIdentifier"]
162 package_header_identifier = bytearray.fromhex(uuid)
163 pldm_fw_up_pkg.write(package_header_identifier)
164
Patrick Williamsc44715d2022-12-08 06:18:18 -0600165 package_header_format_revision = metadata["PackageHeaderInformation"][
166 "PackageHeaderFormatVersion"
167 ]
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530168 # Size will be computed and updated subsequently
169 package_header_size = 0
170 pldm_fw_up_pkg.write(
Patrick Williamsc44715d2022-12-08 06:18:18 -0600171 struct.pack("<BH", package_header_format_revision, package_header_size)
172 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530173
174 try:
175 release_date_time = datetime.strptime(
176 metadata["PackageHeaderInformation"]["PackageReleaseDateTime"],
Patrick Williamsc44715d2022-12-08 06:18:18 -0600177 "%d/%m/%Y %H:%M:%S",
178 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530179 write_pkg_release_date_time(pldm_fw_up_pkg, release_date_time)
180 except KeyError:
181 write_pkg_release_date_time(pldm_fw_up_pkg, datetime.now())
182
183 component_bitmap_bit_length = write_component_bitmap_bit_length(
Patrick Williamsc44715d2022-12-08 06:18:18 -0600184 pldm_fw_up_pkg, metadata
185 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530186 write_package_version_string(pldm_fw_up_pkg, metadata)
187 return component_bitmap_bit_length
188
189
190def get_applicable_components(device, components, component_bitmap_bit_length):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600191 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530192 This function figures out the components applicable for the device and sets
193 the ApplicableComponents bitfield accordingly.
194
195 Parameters:
196 device: device information
197 components: list of components in the package
198 component_bitmap_bit_length: length of the ComponentBitmapBitLength
199
200 Returns:
201 The ApplicableComponents bitfield
Patrick Williamsc44715d2022-12-08 06:18:18 -0600202 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530203 applicable_components_list = device["ApplicableComponents"]
Patrick Williamsc44715d2022-12-08 06:18:18 -0600204 applicable_components = bitarray(
205 component_bitmap_bit_length, endian="little"
206 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530207 applicable_components.setall(0)
208 for component in components:
209 if component["ComponentIdentifier"] in applicable_components_list:
210 applicable_components[components.index(component)] = 1
211 return applicable_components
212
213
Tom Josephda2aaab2021-08-01 19:23:09 -0700214def prepare_record_descriptors(descriptors):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600215 """
Tom Josephda2aaab2021-08-01 19:23:09 -0700216 This function processes the Descriptors and prepares the RecordDescriptors
217 section of the the firmware device ID record.
218
219 Parameters:
220 descriptors: Descriptors entry
221
222 Returns:
223 RecordDescriptors, DescriptorCount
Patrick Williamsc44715d2022-12-08 06:18:18 -0600224 """
Tom Josephda2aaab2021-08-01 19:23:09 -0700225 record_descriptors = bytearray()
226 vendor_defined_desc_type = 65535
227 vendor_desc_title_str_type_len = 1
228 vendor_desc_title_str_len_len = 1
229 descriptor_count = 0
230
231 for descriptor in descriptors:
Tom Josephda2aaab2021-08-01 19:23:09 -0700232 descriptor_type = descriptor["DescriptorType"]
233 if descriptor_count == 0:
Patrick Williamsc44715d2022-12-08 06:18:18 -0600234 if (
235 initial_descriptor_type_name_length.get(descriptor_type)
236 is None
237 ):
Tom Josephda2aaab2021-08-01 19:23:09 -0700238 sys.exit("ERROR: Initial descriptor type not supported")
239 else:
Patrick Williamsc44715d2022-12-08 06:18:18 -0600240 if (
241 descriptor_type_name_length.get(descriptor_type) is None
242 and descriptor_type != vendor_defined_desc_type
243 ):
Tom Josephda2aaab2021-08-01 19:23:09 -0700244 sys.exit("ERROR: Descriptor type not supported")
245
246 if descriptor_type == vendor_defined_desc_type:
Patrick Williamsc44715d2022-12-08 06:18:18 -0600247 vendor_desc_title_str = descriptor[
248 "VendorDefinedDescriptorTitleString"
249 ]
Tom Josephda2aaab2021-08-01 19:23:09 -0700250 vendor_desc_data = descriptor["VendorDefinedDescriptorData"]
251 check_string_length(vendor_desc_title_str)
252 vendor_desc_title_str_type = string_types["ASCII"]
Patrick Williamsc44715d2022-12-08 06:18:18 -0600253 descriptor_length = (
254 vendor_desc_title_str_type_len
255 + vendor_desc_title_str_len_len
256 + len(vendor_desc_title_str)
257 + len(bytearray.fromhex(vendor_desc_data))
258 )
259 format_string = "<HHBB" + str(len(vendor_desc_title_str)) + "s"
260 record_descriptors.extend(
261 struct.pack(
262 format_string,
263 descriptor_type,
264 descriptor_length,
265 vendor_desc_title_str_type,
266 len(vendor_desc_title_str),
267 vendor_desc_title_str.encode("ascii"),
268 )
269 )
Tom Josephda2aaab2021-08-01 19:23:09 -0700270 record_descriptors.extend(bytearray.fromhex(vendor_desc_data))
271 descriptor_count += 1
272 else:
273 descriptor_type = descriptor["DescriptorType"]
274 descriptor_data = descriptor["DescriptorData"]
275 descriptor_length = len(bytearray.fromhex(descriptor_data))
Patrick Williamsc44715d2022-12-08 06:18:18 -0600276 if (
277 descriptor_length
278 != descriptor_type_name_length.get(descriptor_type)[1]
279 ):
280 err_string = (
281 "ERROR: Descriptor type - "
282 + descriptor_type_name_length.get(descriptor_type)[0]
283 + " length is incorrect"
284 )
Tom Josephda2aaab2021-08-01 19:23:09 -0700285 sys.exit(err_string)
Patrick Williamsc44715d2022-12-08 06:18:18 -0600286 format_string = "<HH"
287 record_descriptors.extend(
288 struct.pack(format_string, descriptor_type, descriptor_length)
289 )
Tom Josephda2aaab2021-08-01 19:23:09 -0700290 record_descriptors.extend(bytearray.fromhex(descriptor_data))
291 descriptor_count += 1
292 return record_descriptors, descriptor_count
293
294
Patrick Williamsc44715d2022-12-08 06:18:18 -0600295def write_fw_device_identification_area(
296 pldm_fw_up_pkg, metadata, component_bitmap_bit_length
297):
298 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530299 Write firmware device ID records into the PLDM package header
300
301 This function writes the DeviceIDRecordCount and the
302 FirmwareDeviceIDRecords into the firmware update package by processing the
303 metadata JSON. Currently there is no support for optional
Tom Josephda2aaab2021-08-01 19:23:09 -0700304 FirmwareDevicePackageData.
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530305
306 Parameters:
307 pldm_fw_up_pkg: PLDM FW update package
308 metadata: metadata about PLDM FW update package
309 component_bitmap_bit_length: length of the ComponentBitmapBitLength
Patrick Williamsc44715d2022-12-08 06:18:18 -0600310 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530311 # The spec limits the number of firmware device ID records to 255
312 max_device_id_record_count = 255
313 devices = metadata["FirmwareDeviceIdentificationArea"]
314 device_id_record_count = len(devices)
315 if device_id_record_count > max_device_id_record_count:
316 sys.exit(
Patrick Williamsc44715d2022-12-08 06:18:18 -0600317 "ERROR: there can be only upto 255 entries in the "
318 " FirmwareDeviceIdentificationArea section"
319 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530320
321 # DeviceIDRecordCount
Patrick Williamsc44715d2022-12-08 06:18:18 -0600322 pldm_fw_up_pkg.write(struct.pack("<B", device_id_record_count))
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530323
324 for device in devices:
325 # RecordLength size
326 record_length = 2
327
Tom Josephda2aaab2021-08-01 19:23:09 -0700328 # DescriptorCount
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530329 record_length += 1
330
331 # DeviceUpdateOptionFlags
Patrick Williamsc44715d2022-12-08 06:18:18 -0600332 device_update_option_flags = bitarray(32, endian="little")
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530333 device_update_option_flags.setall(0)
334 # Continue component updates after failure
335 supported_device_update_option_flags = [0]
336 for option in device["DeviceUpdateOptionFlags"]:
337 if option not in supported_device_update_option_flags:
338 sys.exit("ERROR: unsupported DeviceUpdateOptionFlag entry")
339 device_update_option_flags[option] = 1
340 record_length += 4
341
342 # ComponentImageSetVersionStringType supports only ASCII for now
343 component_image_set_version_string_type = string_types["ASCII"]
344 record_length += 1
345
346 # ComponentImageSetVersionStringLength
Patrick Williamsc44715d2022-12-08 06:18:18 -0600347 component_image_set_version_string = device[
348 "ComponentImageSetVersionString"
349 ]
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530350 check_string_length(component_image_set_version_string)
351 record_length += len(component_image_set_version_string)
352 record_length += 1
353
354 # Optional FirmwareDevicePackageData not supported now,
355 # FirmwareDevicePackageDataLength is set to 0x0000
356 fw_device_pkg_data_length = 0
357 record_length += 2
358
359 # ApplicableComponents
360 components = metadata["ComponentImageInformationArea"]
Patrick Williamsc44715d2022-12-08 06:18:18 -0600361 applicable_components = get_applicable_components(
362 device, components, component_bitmap_bit_length
363 )
364 applicable_components_bitfield_length = round(
365 len(applicable_components) / 8
366 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530367 record_length += applicable_components_bitfield_length
368
Tom Josephda2aaab2021-08-01 19:23:09 -0700369 # RecordDescriptors
370 descriptors = device["Descriptors"]
Patrick Williamsc44715d2022-12-08 06:18:18 -0600371 record_descriptors, descriptor_count = prepare_record_descriptors(
372 descriptors
373 )
Tom Josephda2aaab2021-08-01 19:23:09 -0700374 record_length += len(record_descriptors)
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530375
Patrick Williamsc44715d2022-12-08 06:18:18 -0600376 format_string = (
377 "<HBIBBH"
378 + str(applicable_components_bitfield_length)
379 + "s"
380 + str(len(component_image_set_version_string))
381 + "s"
382 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530383 pldm_fw_up_pkg.write(
384 struct.pack(
385 format_string,
386 record_length,
387 descriptor_count,
388 ba2int(device_update_option_flags),
389 component_image_set_version_string_type,
390 len(component_image_set_version_string),
391 fw_device_pkg_data_length,
392 applicable_components.tobytes(),
Patrick Williamsc44715d2022-12-08 06:18:18 -0600393 component_image_set_version_string.encode("ascii"),
394 )
395 )
Tom Josephda2aaab2021-08-01 19:23:09 -0700396 pldm_fw_up_pkg.write(record_descriptors)
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530397
398
399def write_component_image_info_area(pldm_fw_up_pkg, metadata, image_files):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600400 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530401 Write component image information area into the PLDM package header
402
403 This function writes the ComponentImageCount and the
404 ComponentImageInformation into the firmware update package by processing
405 the metadata JSON. Currently there is no support for
406 ComponentComparisonStamp field and the component option use component
407 comparison stamp.
408
409 Parameters:
410 pldm_fw_up_pkg: PLDM FW update package
411 metadata: metadata about PLDM FW update package
412 image_files: component images
Patrick Williamsc44715d2022-12-08 06:18:18 -0600413 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530414 components = metadata["ComponentImageInformationArea"]
415 # ComponentImageCount
Patrick Williamsc44715d2022-12-08 06:18:18 -0600416 pldm_fw_up_pkg.write(struct.pack("<H", len(components)))
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530417 component_location_offsets = []
418 # ComponentLocationOffset position in individual component image
419 # information
420 component_location_offset_pos = 12
421
422 for component in components:
423 # Record the location of the ComponentLocationOffset to be updated
424 # after appending images to the firmware update package
Patrick Williamsc44715d2022-12-08 06:18:18 -0600425 component_location_offsets.append(
426 pldm_fw_up_pkg.tell() + component_location_offset_pos
427 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530428
429 # ComponentClassification
430 component_classification = component["ComponentClassification"]
431 if component_classification < 0 or component_classification > 0xFFFF:
432 sys.exit(
Patrick Williamsc44715d2022-12-08 06:18:18 -0600433 "ERROR: ComponentClassification should be [0x0000 - 0xFFFF]"
434 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530435
436 # ComponentIdentifier
437 component_identifier = component["ComponentIdentifier"]
438 if component_identifier < 0 or component_identifier > 0xFFFF:
Patrick Williamsc44715d2022-12-08 06:18:18 -0600439 sys.exit("ERROR: ComponentIdentifier should be [0x0000 - 0xFFFF]")
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530440
441 # ComponentComparisonStamp not supported
442 component_comparison_stamp = 0xFFFFFFFF
443
444 # ComponentOptions
Patrick Williamsc44715d2022-12-08 06:18:18 -0600445 component_options = bitarray(16, endian="little")
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530446 component_options.setall(0)
Tom Josephd207b592021-10-27 15:33:16 +0530447 supported_component_options = [0, 1, 2]
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530448 for option in component["ComponentOptions"]:
449 if option not in supported_component_options:
450 sys.exit(
Patrick Williamsc44715d2022-12-08 06:18:18 -0600451 "ERROR: unsupported ComponentOption in "
452 " ComponentImageInformationArea section"
453 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530454 component_options[option] = 1
455
456 # RequestedComponentActivationMethod
Patrick Williamsc44715d2022-12-08 06:18:18 -0600457 requested_component_activation_method = bitarray(16, endian="little")
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530458 requested_component_activation_method.setall(0)
459 supported_requested_component_activation_method = [0, 1, 2, 3, 4, 5]
460 for option in component["RequestedComponentActivationMethod"]:
461 if option not in supported_requested_component_activation_method:
462 sys.exit(
Patrick Williamsc44715d2022-12-08 06:18:18 -0600463 "ERROR: unsupported RequestedComponent "
464 " ActivationMethod entry"
465 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530466 requested_component_activation_method[option] = 1
467
468 # ComponentLocationOffset
469 component_location_offset = 0
470 # ComponentSize
471 component_size = 0
472 # ComponentVersionStringType
473 component_version_string_type = string_types["ASCII"]
474 # ComponentVersionStringlength
475 # ComponentVersionString
476 component_version_string = component["ComponentVersionString"]
477 check_string_length(component_version_string)
478
Patrick Williamsc44715d2022-12-08 06:18:18 -0600479 format_string = "<HHIHHIIBB" + str(len(component_version_string)) + "s"
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530480 pldm_fw_up_pkg.write(
481 struct.pack(
482 format_string,
483 component_classification,
484 component_identifier,
485 component_comparison_stamp,
486 ba2int(component_options),
487 ba2int(requested_component_activation_method),
488 component_location_offset,
489 component_size,
490 component_version_string_type,
491 len(component_version_string),
Patrick Williamsc44715d2022-12-08 06:18:18 -0600492 component_version_string.encode("ascii"),
493 )
494 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530495
496 index = 0
497 pkg_header_checksum_size = 4
498 start_offset = pldm_fw_up_pkg.tell() + pkg_header_checksum_size
499 # Update ComponentLocationOffset and ComponentSize for all the components
500 for offset in component_location_offsets:
501 file_size = os.stat(image_files[index]).st_size
502 pldm_fw_up_pkg.seek(offset)
Patrick Williamsc44715d2022-12-08 06:18:18 -0600503 pldm_fw_up_pkg.write(struct.pack("<II", start_offset, file_size))
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530504 start_offset += file_size
505 index += 1
506 pldm_fw_up_pkg.seek(0, os.SEEK_END)
507
508
509def write_pkg_header_checksum(pldm_fw_up_pkg):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600510 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530511 Write PackageHeaderChecksum into the PLDM package header.
512
513 Parameters:
514 pldm_fw_up_pkg: PLDM FW update package
Patrick Williamsc44715d2022-12-08 06:18:18 -0600515 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530516 pldm_fw_up_pkg.seek(0)
517 package_header_checksum = binascii.crc32(pldm_fw_up_pkg.read())
518 pldm_fw_up_pkg.seek(0, os.SEEK_END)
Patrick Williamsc44715d2022-12-08 06:18:18 -0600519 pldm_fw_up_pkg.write(struct.pack("<I", package_header_checksum))
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530520
521
522def update_pkg_header_size(pldm_fw_up_pkg):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600523 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530524 Update PackageHeader in the PLDM package header. The package header size
525 which is the count of all bytes in the PLDM package header structure is
526 calculated once the package header contents is complete.
527
528 Parameters:
529 pldm_fw_up_pkg: PLDM FW update package
Patrick Williamsc44715d2022-12-08 06:18:18 -0600530 """
Tom Joseph33ac59d2021-07-30 11:09:54 -0700531 pkg_header_checksum_size = 4
532 file_size = pldm_fw_up_pkg.tell() + pkg_header_checksum_size
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530533 pkg_header_size_offset = 17
534 # Seek past PackageHeaderIdentifier and PackageHeaderFormatRevision
535 pldm_fw_up_pkg.seek(pkg_header_size_offset)
Patrick Williamsc44715d2022-12-08 06:18:18 -0600536 pldm_fw_up_pkg.write(struct.pack("<H", file_size))
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530537 pldm_fw_up_pkg.seek(0, os.SEEK_END)
538
539
540def append_component_images(pldm_fw_up_pkg, image_files):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600541 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530542 Append the component images to the firmware update package.
543
544 Parameters:
545 pldm_fw_up_pkg: PLDM FW update package
546 image_files: component images
Patrick Williamsc44715d2022-12-08 06:18:18 -0600547 """
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530548 for image in image_files:
Patrick Williamsc44715d2022-12-08 06:18:18 -0600549 with open(image, "rb") as file:
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530550 for line in file:
551 pldm_fw_up_pkg.write(line)
552
553
554def main():
555 """Create PLDM FW update (DSP0267) package based on a JSON metadata file"""
556 parser = argparse.ArgumentParser()
Patrick Williamsc44715d2022-12-08 06:18:18 -0600557 parser.add_argument(
558 "pldmfwuppkgname", help="Name of the PLDM FW update package"
559 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530560 parser.add_argument("metadatafile", help="Path of metadata JSON file")
561 parser.add_argument(
Patrick Williamsc44715d2022-12-08 06:18:18 -0600562 "images",
563 nargs="+",
564 help=(
565 "One or more firmware image paths, in the same order as "
566 " ComponentImageInformationArea entries"
567 ),
568 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530569
570 args = parser.parse_args()
571 image_files = args.images
572 with open(args.metadatafile) as file:
573 try:
574 metadata = json.load(file)
575 except ValueError:
576 sys.exit("ERROR: Invalid metadata JSON file")
577
578 # Validate the number of component images
579 if len(image_files) != len(metadata["ComponentImageInformationArea"]):
Patrick Williamsc44715d2022-12-08 06:18:18 -0600580 sys.exit(
581 "ERROR: number of images passed != number of entries "
582 " in ComponentImageInformationArea"
583 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530584
585 try:
Patrick Williamsc44715d2022-12-08 06:18:18 -0600586 with open(args.pldmfwuppkgname, "w+b") as pldm_fw_up_pkg:
587 component_bitmap_bit_length = write_pkg_header_info(
588 pldm_fw_up_pkg, metadata
589 )
590 write_fw_device_identification_area(
591 pldm_fw_up_pkg, metadata, component_bitmap_bit_length
592 )
593 write_component_image_info_area(
594 pldm_fw_up_pkg, metadata, image_files
595 )
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530596 update_pkg_header_size(pldm_fw_up_pkg)
Tom Joseph33ac59d2021-07-30 11:09:54 -0700597 write_pkg_header_checksum(pldm_fw_up_pkg)
Deepak Kodihalli4ac93442021-04-20 14:44:48 +0530598 append_component_images(pldm_fw_up_pkg, image_files)
599 pldm_fw_up_pkg.close()
600 except BaseException:
601 pldm_fw_up_pkg.close()
602 os.remove(args.pldmfwuppkgname)
603 raise
604
605
606if __name__ == "__main__":
607 main()