|  | /* 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 |