239 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: GPL-2.0 */
 | |
| /* Copyright (C) 2018-2019, Intel Corporation. */
 | |
| 
 | |
| #ifndef _PLDMFW_PRIVATE_H_
 | |
| #define _PLDMFW_PRIVATE_H_
 | |
| 
 | |
| /* The following data structures define the layout of a firmware binary
 | |
|  * following the "PLDM For Firmware Update Specification", DMTF standard
 | |
|  * #DSP0267.
 | |
|  *
 | |
|  * pldmfw.c uses these structures to implement a simple engine that will parse
 | |
|  * a fw binary file in this format and perform a firmware update for a given
 | |
|  * device.
 | |
|  *
 | |
|  * Due to the variable sized data layout, alignment of fields within these
 | |
|  * structures is not guaranteed when reading. For this reason, all multi-byte
 | |
|  * field accesses should be done using the unaligned access macros.
 | |
|  * Additionally, the standard specifies that multi-byte fields are in
 | |
|  * LittleEndian format.
 | |
|  *
 | |
|  * The structure definitions are not made public, in order to keep direct
 | |
|  * accesses within code that is prepared to deal with the limitation of
 | |
|  * unaligned access.
 | |
|  */
 | |
| 
 | |
| /* UUID for PLDM firmware packages: f018878c-cb7d-4943-9800-a02f059aca02 */
 | |
| static const uuid_t pldm_firmware_header_id =
 | |
| 	UUID_INIT(0xf018878c, 0xcb7d, 0x4943,
 | |
| 		  0x98, 0x00, 0xa0, 0x2f, 0x05, 0x9a, 0xca, 0x02);
 | |
| 
 | |
| /* Revision number of the PLDM header format this code supports */
 | |
| #define PACKAGE_HEADER_FORMAT_REVISION 0x01
 | |
| 
 | |
| /* timestamp104 structure defined in PLDM Base specification */
 | |
| #define PLDM_TIMESTAMP_SIZE 13
 | |
| struct __pldm_timestamp {
 | |
| 	u8 b[PLDM_TIMESTAMP_SIZE];
 | |
| } __packed __aligned(1);
 | |
| 
 | |
| /* Package Header Information */
 | |
| struct __pldm_header {
 | |
| 	uuid_t id;			    /* PackageHeaderIdentifier */
 | |
| 	u8 revision;			    /* PackageHeaderFormatRevision */
 | |
| 	__le16 size;			    /* PackageHeaderSize */
 | |
| 	struct __pldm_timestamp release_date; /* PackageReleaseDateTime */
 | |
| 	__le16 component_bitmap_len;	    /* ComponentBitmapBitLength */
 | |
| 	u8 version_type;		    /* PackageVersionStringType */
 | |
| 	u8 version_len;			    /* PackageVersionStringLength */
 | |
| 
 | |
| 	/*
 | |
| 	 * DSP0267 also includes the following variable length fields at the
 | |
| 	 * end of this structure:
 | |
| 	 *
 | |
| 	 * PackageVersionString, length is version_len.
 | |
| 	 *
 | |
| 	 * The total size of this section is
 | |
| 	 *   sizeof(pldm_header) + version_len;
 | |
| 	 */
 | |
| 	u8 version_string[];		/* PackageVersionString */
 | |
| } __packed __aligned(1);
 | |
| 
 | |
| /* Firmware Device ID Record */
 | |
| struct __pldmfw_record_info {
 | |
| 	__le16 record_len;		/* RecordLength */
 | |
| 	u8 descriptor_count;		/* DescriptorCount */
 | |
| 	__le32 device_update_flags;	/* DeviceUpdateOptionFlags */
 | |
| 	u8 version_type;		/* ComponentImageSetVersionType */
 | |
| 	u8 version_len;			/* ComponentImageSetVersionLength */
 | |
| 	__le16 package_data_len;	/* FirmwareDevicePackageDataLength */
 | |
| 
 | |
| 	/*
 | |
| 	 * DSP0267 also includes the following variable length fields at the
 | |
| 	 * end of this structure:
 | |
| 	 *
 | |
| 	 * ApplicableComponents, length is component_bitmap_len from header
 | |
| 	 * ComponentImageSetVersionString, length is version_len
 | |
| 	 * RecordDescriptors, a series of TLVs with 16bit type and length
 | |
| 	 * FirmwareDevicePackageData, length is package_data_len
 | |
| 	 *
 | |
| 	 * The total size of each record is
 | |
| 	 *   sizeof(pldmfw_record_info) +
 | |
| 	 *   component_bitmap_len (converted to bytes!) +
 | |
| 	 *   version_len +
 | |
| 	 *   <length of RecordDescriptors> +
 | |
| 	 *   package_data_len
 | |
| 	 */
 | |
| 	u8 variable_record_data[];
 | |
| } __packed __aligned(1);
 | |
| 
 | |
| /* Firmware Descriptor Definition */
 | |
| struct __pldmfw_desc_tlv {
 | |
| 	__le16 type;			/* DescriptorType */
 | |
| 	__le16 size;			/* DescriptorSize */
 | |
| 	u8 data[];			/* DescriptorData */
 | |
| } __aligned(1);
 | |
| 
 | |
| /* Firmware Device Identification Area */
 | |
| struct __pldmfw_record_area {
 | |
| 	u8 record_count;		/* DeviceIDRecordCount */
 | |
| 	/* This is not a struct type because the size of each record varies */
 | |
| 	u8 records[];
 | |
| } __aligned(1);
 | |
| 
 | |
| /* Individual Component Image Information */
 | |
| struct __pldmfw_component_info {
 | |
| 	__le16 classification;		/* ComponentClassfication */
 | |
| 	__le16 identifier;		/* ComponentIdentifier */
 | |
| 	__le32 comparison_stamp;	/* ComponentComparisonStamp */
 | |
| 	__le16 options;			/* componentOptions */
 | |
| 	__le16 activation_method;	/* RequestedComponentActivationMethod */
 | |
| 	__le32 location_offset;		/* ComponentLocationOffset */
 | |
| 	__le32 size;			/* ComponentSize */
 | |
| 	u8 version_type;		/* ComponentVersionStringType */
 | |
| 	u8 version_len;		/* ComponentVersionStringLength */
 | |
| 
 | |
| 	/*
 | |
| 	 * DSP0267 also includes the following variable length fields at the
 | |
| 	 * end of this structure:
 | |
| 	 *
 | |
| 	 * ComponentVersionString, length is version_len
 | |
| 	 *
 | |
| 	 * The total size of this section is
 | |
| 	 *   sizeof(pldmfw_component_info) + version_len;
 | |
| 	 */
 | |
| 	u8 version_string[];		/* ComponentVersionString */
 | |
| } __packed __aligned(1);
 | |
| 
 | |
| /* Component Image Information Area */
 | |
| struct __pldmfw_component_area {
 | |
| 	__le16 component_image_count;
 | |
| 	/* This is not a struct type because the component size varies */
 | |
| 	u8 components[];
 | |
| } __aligned(1);
 | |
| 
 | |
| /**
 | |
|  * pldm_first_desc_tlv
 | |
|  * @start: byte offset of the start of the descriptor TLVs
 | |
|  *
 | |
|  * Converts the starting offset of the descriptor TLVs into a pointer to the
 | |
|  * first descriptor.
 | |
|  */
 | |
| #define pldm_first_desc_tlv(start)					\
 | |
| 	((const struct __pldmfw_desc_tlv *)(start))
 | |
| 
 | |
| /**
 | |
|  * pldm_next_desc_tlv
 | |
|  * @desc: pointer to a descriptor TLV
 | |
|  *
 | |
|  * Finds the pointer to the next descriptor following a given descriptor
 | |
|  */
 | |
| #define pldm_next_desc_tlv(desc)						\
 | |
| 	((const struct __pldmfw_desc_tlv *)((desc)->data +			\
 | |
| 					     get_unaligned_le16(&(desc)->size)))
 | |
| 
 | |
| /**
 | |
|  * pldm_for_each_desc_tlv
 | |
|  * @i: variable to store descriptor index
 | |
|  * @desc: variable to store descriptor pointer
 | |
|  * @start: byte offset of the start of the descriptors
 | |
|  * @count: the number of descriptors
 | |
|  *
 | |
|  * for loop macro to iterate over all of the descriptors of a given PLDM
 | |
|  * record.
 | |
|  */
 | |
| #define pldm_for_each_desc_tlv(i, desc, start, count)			\
 | |
| 	for ((i) = 0, (desc) = pldm_first_desc_tlv(start);		\
 | |
| 	     (i) < (count);						\
 | |
| 	     (i)++, (desc) = pldm_next_desc_tlv(desc))
 | |
| 
 | |
| /**
 | |
|  * pldm_first_record
 | |
|  * @start: byte offset of the start of the PLDM records
 | |
|  *
 | |
|  * Converts a starting offset of the PLDM records into a pointer to the first
 | |
|  * record.
 | |
|  */
 | |
| #define pldm_first_record(start)					\
 | |
| 	((const struct __pldmfw_record_info *)(start))
 | |
| 
 | |
| /**
 | |
|  * pldm_next_record
 | |
|  * @record: pointer to a PLDM record
 | |
|  *
 | |
|  * Finds a pointer to the next record following a given record
 | |
|  */
 | |
| #define pldm_next_record(record)					\
 | |
| 	((const struct __pldmfw_record_info *)				\
 | |
| 	 ((const u8 *)(record) + get_unaligned_le16(&(record)->record_len)))
 | |
| 
 | |
| /**
 | |
|  * pldm_for_each_record
 | |
|  * @i: variable to store record index
 | |
|  * @record: variable to store record pointer
 | |
|  * @start: byte offset of the start of the records
 | |
|  * @count: the number of records
 | |
|  *
 | |
|  * for loop macro to iterate over all of the records of a PLDM file.
 | |
|  */
 | |
| #define pldm_for_each_record(i, record, start, count)			\
 | |
| 	for ((i) = 0, (record) = pldm_first_record(start);		\
 | |
| 	     (i) < (count);						\
 | |
| 	     (i)++, (record) = pldm_next_record(record))
 | |
| 
 | |
| /**
 | |
|  * pldm_first_component
 | |
|  * @start: byte offset of the start of the PLDM components
 | |
|  *
 | |
|  * Convert a starting offset of the PLDM components into a pointer to the
 | |
|  * first component
 | |
|  */
 | |
| #define pldm_first_component(start)					\
 | |
| 	((const struct __pldmfw_component_info *)(start))
 | |
| 
 | |
| /**
 | |
|  * pldm_next_component
 | |
|  * @component: pointer to a PLDM component
 | |
|  *
 | |
|  * Finds a pointer to the next component following a given component
 | |
|  */
 | |
| #define pldm_next_component(component)						\
 | |
| 	((const struct __pldmfw_component_info *)((component)->version_string +	\
 | |
| 						  (component)->version_len))
 | |
| 
 | |
| /**
 | |
|  * pldm_for_each_component
 | |
|  * @i: variable to store component index
 | |
|  * @component: variable to store component pointer
 | |
|  * @start: byte offset to the start of the first component
 | |
|  * @count: the number of components
 | |
|  *
 | |
|  * for loop macro to iterate over all of the components of a PLDM file.
 | |
|  */
 | |
| #define pldm_for_each_component(i, component, start, count)		\
 | |
| 	for ((i) = 0, (component) = pldm_first_component(start);	\
 | |
| 	     (i) < (count);						\
 | |
| 	     (i)++, (component) = pldm_next_component(component))
 | |
| 
 | |
| #endif
 |