^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (C) 2018-2019, Intel Corporation. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #ifndef _PLDMFW_PRIVATE_H_
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #define _PLDMFW_PRIVATE_H_
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) /* The following data structures define the layout of a firmware binary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * following the "PLDM For Firmware Update Specification", DMTF standard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * #DSP0267.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * pldmfw.c uses these structures to implement a simple engine that will parse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * a fw binary file in this format and perform a firmware update for a given
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Due to the variable sized data layout, alignment of fields within these
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * structures is not guaranteed when reading. For this reason, all multi-byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * field accesses should be done using the unaligned access macros.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Additionally, the standard specifies that multi-byte fields are in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * LittleEndian format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * The structure definitions are not made public, in order to keep direct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * accesses within code that is prepared to deal with the limitation of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * unaligned access.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* UUID for PLDM firmware packages: f018878c-cb7d-4943-9800-a02f059aca02 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static const uuid_t pldm_firmware_header_id =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) UUID_INIT(0xf018878c, 0xcb7d, 0x4943,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) 0x98, 0x00, 0xa0, 0x2f, 0x05, 0x9a, 0xca, 0x02);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* Revision number of the PLDM header format this code supports */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define PACKAGE_HEADER_FORMAT_REVISION 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* timestamp104 structure defined in PLDM Base specification */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define PLDM_TIMESTAMP_SIZE 13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct __pldm_timestamp {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u8 b[PLDM_TIMESTAMP_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) } __packed __aligned(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* Package Header Information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct __pldm_header {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) uuid_t id; /* PackageHeaderIdentifier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) u8 revision; /* PackageHeaderFormatRevision */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) __le16 size; /* PackageHeaderSize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct __pldm_timestamp release_date; /* PackageReleaseDateTime */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) __le16 component_bitmap_len; /* ComponentBitmapBitLength */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) u8 version_type; /* PackageVersionStringType */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u8 version_len; /* PackageVersionStringLength */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * DSP0267 also includes the following variable length fields at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * end of this structure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * PackageVersionString, length is version_len.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * The total size of this section is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * sizeof(pldm_header) + version_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) u8 version_string[]; /* PackageVersionString */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) } __packed __aligned(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* Firmware Device ID Record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct __pldmfw_record_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) __le16 record_len; /* RecordLength */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u8 descriptor_count; /* DescriptorCount */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) __le32 device_update_flags; /* DeviceUpdateOptionFlags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u8 version_type; /* ComponentImageSetVersionType */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u8 version_len; /* ComponentImageSetVersionLength */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) __le16 package_data_len; /* FirmwareDevicePackageDataLength */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * DSP0267 also includes the following variable length fields at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * end of this structure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * ApplicableComponents, length is component_bitmap_len from header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * ComponentImageSetVersionString, length is version_len
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * RecordDescriptors, a series of TLVs with 16bit type and length
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * FirmwareDevicePackageData, length is package_data_len
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * The total size of each record is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * sizeof(pldmfw_record_info) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * component_bitmap_len (converted to bytes!) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * version_len +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * <length of RecordDescriptors> +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * package_data_len
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) u8 variable_record_data[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) } __packed __aligned(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* Firmware Descriptor Definition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct __pldmfw_desc_tlv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) __le16 type; /* DescriptorType */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) __le16 size; /* DescriptorSize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) u8 data[]; /* DescriptorData */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) } __aligned(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* Firmware Device Identification Area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct __pldmfw_record_area {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u8 record_count; /* DeviceIDRecordCount */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* This is not a struct type because the size of each record varies */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u8 records[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) } __aligned(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* Individual Component Image Information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) struct __pldmfw_component_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) __le16 classification; /* ComponentClassfication */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) __le16 identifier; /* ComponentIdentifier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) __le32 comparison_stamp; /* ComponentComparisonStamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) __le16 options; /* componentOptions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) __le16 activation_method; /* RequestedComponentActivationMethod */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) __le32 location_offset; /* ComponentLocationOffset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) __le32 size; /* ComponentSize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u8 version_type; /* ComponentVersionStringType */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) u8 version_len; /* ComponentVersionStringLength */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * DSP0267 also includes the following variable length fields at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * end of this structure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * ComponentVersionString, length is version_len
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * The total size of this section is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * sizeof(pldmfw_component_info) + version_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) u8 version_string[]; /* ComponentVersionString */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) } __packed __aligned(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* Component Image Information Area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct __pldmfw_component_area {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) __le16 component_image_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* This is not a struct type because the component size varies */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) u8 components[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) } __aligned(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * pldm_first_desc_tlv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * @start: byte offset of the start of the descriptor TLVs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * Converts the starting offset of the descriptor TLVs into a pointer to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * first descriptor.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define pldm_first_desc_tlv(start) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) ((const struct __pldmfw_desc_tlv *)(start))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * pldm_next_desc_tlv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * @desc: pointer to a descriptor TLV
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * Finds the pointer to the next descriptor following a given descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define pldm_next_desc_tlv(desc) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) ((const struct __pldmfw_desc_tlv *)((desc)->data + \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) get_unaligned_le16(&(desc)->size)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * pldm_for_each_desc_tlv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * @i: variable to store descriptor index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * @desc: variable to store descriptor pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * @start: byte offset of the start of the descriptors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * @count: the number of descriptors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * for loop macro to iterate over all of the descriptors of a given PLDM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * record.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #define pldm_for_each_desc_tlv(i, desc, start, count) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) for ((i) = 0, (desc) = pldm_first_desc_tlv(start); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) (i) < (count); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) (i)++, (desc) = pldm_next_desc_tlv(desc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * pldm_first_record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * @start: byte offset of the start of the PLDM records
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * Converts a starting offset of the PLDM records into a pointer to the first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * record.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) #define pldm_first_record(start) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) ((const struct __pldmfw_record_info *)(start))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * pldm_next_record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * @record: pointer to a PLDM record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * Finds a pointer to the next record following a given record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #define pldm_next_record(record) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) ((const struct __pldmfw_record_info *) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) ((const u8 *)(record) + get_unaligned_le16(&(record)->record_len)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * pldm_for_each_record
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * @i: variable to store record index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * @record: variable to store record pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * @start: byte offset of the start of the records
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * @count: the number of records
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * for loop macro to iterate over all of the records of a PLDM file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) #define pldm_for_each_record(i, record, start, count) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) for ((i) = 0, (record) = pldm_first_record(start); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) (i) < (count); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) (i)++, (record) = pldm_next_record(record))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * pldm_first_component
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * @start: byte offset of the start of the PLDM components
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * Convert a starting offset of the PLDM components into a pointer to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * first component
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #define pldm_first_component(start) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) ((const struct __pldmfw_component_info *)(start))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * pldm_next_component
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * @component: pointer to a PLDM component
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * Finds a pointer to the next component following a given component
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) #define pldm_next_component(component) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) ((const struct __pldmfw_component_info *)((component)->version_string + \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) (component)->version_len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * pldm_for_each_component
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * @i: variable to store component index
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * @component: variable to store component pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * @start: byte offset to the start of the first component
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * @count: the number of components
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * for loop macro to iterate over all of the components of a PLDM file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) #define pldm_for_each_component(i, component, start, count) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) for ((i) = 0, (component) = pldm_first_component(start); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) (i) < (count); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) (i)++, (component) = pldm_next_component(component))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) #endif