18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/* Copyright (C) 2018-2019, Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#ifndef _PLDMFW_PRIVATE_H_
58c2ecf20Sopenharmony_ci#define _PLDMFW_PRIVATE_H_
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/* The following data structures define the layout of a firmware binary
88c2ecf20Sopenharmony_ci * following the "PLDM For Firmware Update Specification", DMTF standard
98c2ecf20Sopenharmony_ci * #DSP0267.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * pldmfw.c uses these structures to implement a simple engine that will parse
128c2ecf20Sopenharmony_ci * a fw binary file in this format and perform a firmware update for a given
138c2ecf20Sopenharmony_ci * device.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * Due to the variable sized data layout, alignment of fields within these
168c2ecf20Sopenharmony_ci * structures is not guaranteed when reading. For this reason, all multi-byte
178c2ecf20Sopenharmony_ci * field accesses should be done using the unaligned access macros.
188c2ecf20Sopenharmony_ci * Additionally, the standard specifies that multi-byte fields are in
198c2ecf20Sopenharmony_ci * LittleEndian format.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * The structure definitions are not made public, in order to keep direct
228c2ecf20Sopenharmony_ci * accesses within code that is prepared to deal with the limitation of
238c2ecf20Sopenharmony_ci * unaligned access.
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* UUID for PLDM firmware packages: f018878c-cb7d-4943-9800-a02f059aca02 */
278c2ecf20Sopenharmony_cistatic const uuid_t pldm_firmware_header_id =
288c2ecf20Sopenharmony_ci	UUID_INIT(0xf018878c, 0xcb7d, 0x4943,
298c2ecf20Sopenharmony_ci		  0x98, 0x00, 0xa0, 0x2f, 0x05, 0x9a, 0xca, 0x02);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* Revision number of the PLDM header format this code supports */
328c2ecf20Sopenharmony_ci#define PACKAGE_HEADER_FORMAT_REVISION 0x01
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* timestamp104 structure defined in PLDM Base specification */
358c2ecf20Sopenharmony_ci#define PLDM_TIMESTAMP_SIZE 13
368c2ecf20Sopenharmony_cistruct __pldm_timestamp {
378c2ecf20Sopenharmony_ci	u8 b[PLDM_TIMESTAMP_SIZE];
388c2ecf20Sopenharmony_ci} __packed __aligned(1);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* Package Header Information */
418c2ecf20Sopenharmony_cistruct __pldm_header {
428c2ecf20Sopenharmony_ci	uuid_t id;			    /* PackageHeaderIdentifier */
438c2ecf20Sopenharmony_ci	u8 revision;			    /* PackageHeaderFormatRevision */
448c2ecf20Sopenharmony_ci	__le16 size;			    /* PackageHeaderSize */
458c2ecf20Sopenharmony_ci	struct __pldm_timestamp release_date; /* PackageReleaseDateTime */
468c2ecf20Sopenharmony_ci	__le16 component_bitmap_len;	    /* ComponentBitmapBitLength */
478c2ecf20Sopenharmony_ci	u8 version_type;		    /* PackageVersionStringType */
488c2ecf20Sopenharmony_ci	u8 version_len;			    /* PackageVersionStringLength */
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	/*
518c2ecf20Sopenharmony_ci	 * DSP0267 also includes the following variable length fields at the
528c2ecf20Sopenharmony_ci	 * end of this structure:
538c2ecf20Sopenharmony_ci	 *
548c2ecf20Sopenharmony_ci	 * PackageVersionString, length is version_len.
558c2ecf20Sopenharmony_ci	 *
568c2ecf20Sopenharmony_ci	 * The total size of this section is
578c2ecf20Sopenharmony_ci	 *   sizeof(pldm_header) + version_len;
588c2ecf20Sopenharmony_ci	 */
598c2ecf20Sopenharmony_ci	u8 version_string[];		/* PackageVersionString */
608c2ecf20Sopenharmony_ci} __packed __aligned(1);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* Firmware Device ID Record */
638c2ecf20Sopenharmony_cistruct __pldmfw_record_info {
648c2ecf20Sopenharmony_ci	__le16 record_len;		/* RecordLength */
658c2ecf20Sopenharmony_ci	u8 descriptor_count;		/* DescriptorCount */
668c2ecf20Sopenharmony_ci	__le32 device_update_flags;	/* DeviceUpdateOptionFlags */
678c2ecf20Sopenharmony_ci	u8 version_type;		/* ComponentImageSetVersionType */
688c2ecf20Sopenharmony_ci	u8 version_len;			/* ComponentImageSetVersionLength */
698c2ecf20Sopenharmony_ci	__le16 package_data_len;	/* FirmwareDevicePackageDataLength */
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 * DSP0267 also includes the following variable length fields at the
738c2ecf20Sopenharmony_ci	 * end of this structure:
748c2ecf20Sopenharmony_ci	 *
758c2ecf20Sopenharmony_ci	 * ApplicableComponents, length is component_bitmap_len from header
768c2ecf20Sopenharmony_ci	 * ComponentImageSetVersionString, length is version_len
778c2ecf20Sopenharmony_ci	 * RecordDescriptors, a series of TLVs with 16bit type and length
788c2ecf20Sopenharmony_ci	 * FirmwareDevicePackageData, length is package_data_len
798c2ecf20Sopenharmony_ci	 *
808c2ecf20Sopenharmony_ci	 * The total size of each record is
818c2ecf20Sopenharmony_ci	 *   sizeof(pldmfw_record_info) +
828c2ecf20Sopenharmony_ci	 *   component_bitmap_len (converted to bytes!) +
838c2ecf20Sopenharmony_ci	 *   version_len +
848c2ecf20Sopenharmony_ci	 *   <length of RecordDescriptors> +
858c2ecf20Sopenharmony_ci	 *   package_data_len
868c2ecf20Sopenharmony_ci	 */
878c2ecf20Sopenharmony_ci	u8 variable_record_data[];
888c2ecf20Sopenharmony_ci} __packed __aligned(1);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/* Firmware Descriptor Definition */
918c2ecf20Sopenharmony_cistruct __pldmfw_desc_tlv {
928c2ecf20Sopenharmony_ci	__le16 type;			/* DescriptorType */
938c2ecf20Sopenharmony_ci	__le16 size;			/* DescriptorSize */
948c2ecf20Sopenharmony_ci	u8 data[];			/* DescriptorData */
958c2ecf20Sopenharmony_ci} __aligned(1);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* Firmware Device Identification Area */
988c2ecf20Sopenharmony_cistruct __pldmfw_record_area {
998c2ecf20Sopenharmony_ci	u8 record_count;		/* DeviceIDRecordCount */
1008c2ecf20Sopenharmony_ci	/* This is not a struct type because the size of each record varies */
1018c2ecf20Sopenharmony_ci	u8 records[];
1028c2ecf20Sopenharmony_ci} __aligned(1);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/* Individual Component Image Information */
1058c2ecf20Sopenharmony_cistruct __pldmfw_component_info {
1068c2ecf20Sopenharmony_ci	__le16 classification;		/* ComponentClassfication */
1078c2ecf20Sopenharmony_ci	__le16 identifier;		/* ComponentIdentifier */
1088c2ecf20Sopenharmony_ci	__le32 comparison_stamp;	/* ComponentComparisonStamp */
1098c2ecf20Sopenharmony_ci	__le16 options;			/* componentOptions */
1108c2ecf20Sopenharmony_ci	__le16 activation_method;	/* RequestedComponentActivationMethod */
1118c2ecf20Sopenharmony_ci	__le32 location_offset;		/* ComponentLocationOffset */
1128c2ecf20Sopenharmony_ci	__le32 size;			/* ComponentSize */
1138c2ecf20Sopenharmony_ci	u8 version_type;		/* ComponentVersionStringType */
1148c2ecf20Sopenharmony_ci	u8 version_len;		/* ComponentVersionStringLength */
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/*
1178c2ecf20Sopenharmony_ci	 * DSP0267 also includes the following variable length fields at the
1188c2ecf20Sopenharmony_ci	 * end of this structure:
1198c2ecf20Sopenharmony_ci	 *
1208c2ecf20Sopenharmony_ci	 * ComponentVersionString, length is version_len
1218c2ecf20Sopenharmony_ci	 *
1228c2ecf20Sopenharmony_ci	 * The total size of this section is
1238c2ecf20Sopenharmony_ci	 *   sizeof(pldmfw_component_info) + version_len;
1248c2ecf20Sopenharmony_ci	 */
1258c2ecf20Sopenharmony_ci	u8 version_string[];		/* ComponentVersionString */
1268c2ecf20Sopenharmony_ci} __packed __aligned(1);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* Component Image Information Area */
1298c2ecf20Sopenharmony_cistruct __pldmfw_component_area {
1308c2ecf20Sopenharmony_ci	__le16 component_image_count;
1318c2ecf20Sopenharmony_ci	/* This is not a struct type because the component size varies */
1328c2ecf20Sopenharmony_ci	u8 components[];
1338c2ecf20Sopenharmony_ci} __aligned(1);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/**
1368c2ecf20Sopenharmony_ci * pldm_first_desc_tlv
1378c2ecf20Sopenharmony_ci * @start: byte offset of the start of the descriptor TLVs
1388c2ecf20Sopenharmony_ci *
1398c2ecf20Sopenharmony_ci * Converts the starting offset of the descriptor TLVs into a pointer to the
1408c2ecf20Sopenharmony_ci * first descriptor.
1418c2ecf20Sopenharmony_ci */
1428c2ecf20Sopenharmony_ci#define pldm_first_desc_tlv(start)					\
1438c2ecf20Sopenharmony_ci	((const struct __pldmfw_desc_tlv *)(start))
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/**
1468c2ecf20Sopenharmony_ci * pldm_next_desc_tlv
1478c2ecf20Sopenharmony_ci * @desc: pointer to a descriptor TLV
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * Finds the pointer to the next descriptor following a given descriptor
1508c2ecf20Sopenharmony_ci */
1518c2ecf20Sopenharmony_ci#define pldm_next_desc_tlv(desc)						\
1528c2ecf20Sopenharmony_ci	((const struct __pldmfw_desc_tlv *)((desc)->data +			\
1538c2ecf20Sopenharmony_ci					     get_unaligned_le16(&(desc)->size)))
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/**
1568c2ecf20Sopenharmony_ci * pldm_for_each_desc_tlv
1578c2ecf20Sopenharmony_ci * @i: variable to store descriptor index
1588c2ecf20Sopenharmony_ci * @desc: variable to store descriptor pointer
1598c2ecf20Sopenharmony_ci * @start: byte offset of the start of the descriptors
1608c2ecf20Sopenharmony_ci * @count: the number of descriptors
1618c2ecf20Sopenharmony_ci *
1628c2ecf20Sopenharmony_ci * for loop macro to iterate over all of the descriptors of a given PLDM
1638c2ecf20Sopenharmony_ci * record.
1648c2ecf20Sopenharmony_ci */
1658c2ecf20Sopenharmony_ci#define pldm_for_each_desc_tlv(i, desc, start, count)			\
1668c2ecf20Sopenharmony_ci	for ((i) = 0, (desc) = pldm_first_desc_tlv(start);		\
1678c2ecf20Sopenharmony_ci	     (i) < (count);						\
1688c2ecf20Sopenharmony_ci	     (i)++, (desc) = pldm_next_desc_tlv(desc))
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci/**
1718c2ecf20Sopenharmony_ci * pldm_first_record
1728c2ecf20Sopenharmony_ci * @start: byte offset of the start of the PLDM records
1738c2ecf20Sopenharmony_ci *
1748c2ecf20Sopenharmony_ci * Converts a starting offset of the PLDM records into a pointer to the first
1758c2ecf20Sopenharmony_ci * record.
1768c2ecf20Sopenharmony_ci */
1778c2ecf20Sopenharmony_ci#define pldm_first_record(start)					\
1788c2ecf20Sopenharmony_ci	((const struct __pldmfw_record_info *)(start))
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci/**
1818c2ecf20Sopenharmony_ci * pldm_next_record
1828c2ecf20Sopenharmony_ci * @record: pointer to a PLDM record
1838c2ecf20Sopenharmony_ci *
1848c2ecf20Sopenharmony_ci * Finds a pointer to the next record following a given record
1858c2ecf20Sopenharmony_ci */
1868c2ecf20Sopenharmony_ci#define pldm_next_record(record)					\
1878c2ecf20Sopenharmony_ci	((const struct __pldmfw_record_info *)				\
1888c2ecf20Sopenharmony_ci	 ((const u8 *)(record) + get_unaligned_le16(&(record)->record_len)))
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci/**
1918c2ecf20Sopenharmony_ci * pldm_for_each_record
1928c2ecf20Sopenharmony_ci * @i: variable to store record index
1938c2ecf20Sopenharmony_ci * @record: variable to store record pointer
1948c2ecf20Sopenharmony_ci * @start: byte offset of the start of the records
1958c2ecf20Sopenharmony_ci * @count: the number of records
1968c2ecf20Sopenharmony_ci *
1978c2ecf20Sopenharmony_ci * for loop macro to iterate over all of the records of a PLDM file.
1988c2ecf20Sopenharmony_ci */
1998c2ecf20Sopenharmony_ci#define pldm_for_each_record(i, record, start, count)			\
2008c2ecf20Sopenharmony_ci	for ((i) = 0, (record) = pldm_first_record(start);		\
2018c2ecf20Sopenharmony_ci	     (i) < (count);						\
2028c2ecf20Sopenharmony_ci	     (i)++, (record) = pldm_next_record(record))
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci/**
2058c2ecf20Sopenharmony_ci * pldm_first_component
2068c2ecf20Sopenharmony_ci * @start: byte offset of the start of the PLDM components
2078c2ecf20Sopenharmony_ci *
2088c2ecf20Sopenharmony_ci * Convert a starting offset of the PLDM components into a pointer to the
2098c2ecf20Sopenharmony_ci * first component
2108c2ecf20Sopenharmony_ci */
2118c2ecf20Sopenharmony_ci#define pldm_first_component(start)					\
2128c2ecf20Sopenharmony_ci	((const struct __pldmfw_component_info *)(start))
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/**
2158c2ecf20Sopenharmony_ci * pldm_next_component
2168c2ecf20Sopenharmony_ci * @component: pointer to a PLDM component
2178c2ecf20Sopenharmony_ci *
2188c2ecf20Sopenharmony_ci * Finds a pointer to the next component following a given component
2198c2ecf20Sopenharmony_ci */
2208c2ecf20Sopenharmony_ci#define pldm_next_component(component)						\
2218c2ecf20Sopenharmony_ci	((const struct __pldmfw_component_info *)((component)->version_string +	\
2228c2ecf20Sopenharmony_ci						  (component)->version_len))
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/**
2258c2ecf20Sopenharmony_ci * pldm_for_each_component
2268c2ecf20Sopenharmony_ci * @i: variable to store component index
2278c2ecf20Sopenharmony_ci * @component: variable to store component pointer
2288c2ecf20Sopenharmony_ci * @start: byte offset to the start of the first component
2298c2ecf20Sopenharmony_ci * @count: the number of components
2308c2ecf20Sopenharmony_ci *
2318c2ecf20Sopenharmony_ci * for loop macro to iterate over all of the components of a PLDM file.
2328c2ecf20Sopenharmony_ci */
2338c2ecf20Sopenharmony_ci#define pldm_for_each_component(i, component, start, count)		\
2348c2ecf20Sopenharmony_ci	for ((i) = 0, (component) = pldm_first_component(start);	\
2358c2ecf20Sopenharmony_ci	     (i) < (count);						\
2368c2ecf20Sopenharmony_ci	     (i)++, (component) = pldm_next_component(component))
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci#endif
239