239 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/* Copyright (C) 2018-2019, Intel Corporation. */3 4#ifndef _PLDMFW_PRIVATE_H_5#define _PLDMFW_PRIVATE_H_6 7/* The following data structures define the layout of a firmware binary8 * following the "PLDM For Firmware Update Specification", DMTF standard9 * #DSP0267.10 *11 * pldmfw.c uses these structures to implement a simple engine that will parse12 * a fw binary file in this format and perform a firmware update for a given13 * device.14 *15 * Due to the variable sized data layout, alignment of fields within these16 * structures is not guaranteed when reading. For this reason, all multi-byte17 * field accesses should be done using the unaligned access macros.18 * Additionally, the standard specifies that multi-byte fields are in19 * LittleEndian format.20 *21 * The structure definitions are not made public, in order to keep direct22 * accesses within code that is prepared to deal with the limitation of23 * unaligned access.24 */25 26/* UUID for PLDM firmware packages: f018878c-cb7d-4943-9800-a02f059aca02 */27static const uuid_t pldm_firmware_header_id =28 UUID_INIT(0xf018878c, 0xcb7d, 0x4943,29 0x98, 0x00, 0xa0, 0x2f, 0x05, 0x9a, 0xca, 0x02);30 31/* Revision number of the PLDM header format this code supports */32#define PACKAGE_HEADER_FORMAT_REVISION 0x0133 34/* timestamp104 structure defined in PLDM Base specification */35#define PLDM_TIMESTAMP_SIZE 1336struct __pldm_timestamp {37 u8 b[PLDM_TIMESTAMP_SIZE];38} __packed __aligned(1);39 40/* Package Header Information */41struct __pldm_header {42 uuid_t id; /* PackageHeaderIdentifier */43 u8 revision; /* PackageHeaderFormatRevision */44 __le16 size; /* PackageHeaderSize */45 struct __pldm_timestamp release_date; /* PackageReleaseDateTime */46 __le16 component_bitmap_len; /* ComponentBitmapBitLength */47 u8 version_type; /* PackageVersionStringType */48 u8 version_len; /* PackageVersionStringLength */49 50 /*51 * DSP0267 also includes the following variable length fields at the52 * end of this structure:53 *54 * PackageVersionString, length is version_len.55 *56 * The total size of this section is57 * sizeof(pldm_header) + version_len;58 */59 u8 version_string[]; /* PackageVersionString */60} __packed __aligned(1);61 62/* Firmware Device ID Record */63struct __pldmfw_record_info {64 __le16 record_len; /* RecordLength */65 u8 descriptor_count; /* DescriptorCount */66 __le32 device_update_flags; /* DeviceUpdateOptionFlags */67 u8 version_type; /* ComponentImageSetVersionType */68 u8 version_len; /* ComponentImageSetVersionLength */69 __le16 package_data_len; /* FirmwareDevicePackageDataLength */70 71 /*72 * DSP0267 also includes the following variable length fields at the73 * end of this structure:74 *75 * ApplicableComponents, length is component_bitmap_len from header76 * ComponentImageSetVersionString, length is version_len77 * RecordDescriptors, a series of TLVs with 16bit type and length78 * FirmwareDevicePackageData, length is package_data_len79 *80 * The total size of each record is81 * sizeof(pldmfw_record_info) +82 * component_bitmap_len (converted to bytes!) +83 * version_len +84 * <length of RecordDescriptors> +85 * package_data_len86 */87 u8 variable_record_data[];88} __packed __aligned(1);89 90/* Firmware Descriptor Definition */91struct __pldmfw_desc_tlv {92 __le16 type; /* DescriptorType */93 __le16 size; /* DescriptorSize */94 u8 data[]; /* DescriptorData */95} __aligned(1);96 97/* Firmware Device Identification Area */98struct __pldmfw_record_area {99 u8 record_count; /* DeviceIDRecordCount */100 /* This is not a struct type because the size of each record varies */101 u8 records[];102} __aligned(1);103 104/* Individual Component Image Information */105struct __pldmfw_component_info {106 __le16 classification; /* ComponentClassfication */107 __le16 identifier; /* ComponentIdentifier */108 __le32 comparison_stamp; /* ComponentComparisonStamp */109 __le16 options; /* componentOptions */110 __le16 activation_method; /* RequestedComponentActivationMethod */111 __le32 location_offset; /* ComponentLocationOffset */112 __le32 size; /* ComponentSize */113 u8 version_type; /* ComponentVersionStringType */114 u8 version_len; /* ComponentVersionStringLength */115 116 /*117 * DSP0267 also includes the following variable length fields at the118 * end of this structure:119 *120 * ComponentVersionString, length is version_len121 *122 * The total size of this section is123 * sizeof(pldmfw_component_info) + version_len;124 */125 u8 version_string[]; /* ComponentVersionString */126} __packed __aligned(1);127 128/* Component Image Information Area */129struct __pldmfw_component_area {130 __le16 component_image_count;131 /* This is not a struct type because the component size varies */132 u8 components[];133} __aligned(1);134 135/**136 * pldm_first_desc_tlv137 * @start: byte offset of the start of the descriptor TLVs138 *139 * Converts the starting offset of the descriptor TLVs into a pointer to the140 * first descriptor.141 */142#define pldm_first_desc_tlv(start) \143 ((const struct __pldmfw_desc_tlv *)(start))144 145/**146 * pldm_next_desc_tlv147 * @desc: pointer to a descriptor TLV148 *149 * Finds the pointer to the next descriptor following a given descriptor150 */151#define pldm_next_desc_tlv(desc) \152 ((const struct __pldmfw_desc_tlv *)((desc)->data + \153 get_unaligned_le16(&(desc)->size)))154 155/**156 * pldm_for_each_desc_tlv157 * @i: variable to store descriptor index158 * @desc: variable to store descriptor pointer159 * @start: byte offset of the start of the descriptors160 * @count: the number of descriptors161 *162 * for loop macro to iterate over all of the descriptors of a given PLDM163 * record.164 */165#define pldm_for_each_desc_tlv(i, desc, start, count) \166 for ((i) = 0, (desc) = pldm_first_desc_tlv(start); \167 (i) < (count); \168 (i)++, (desc) = pldm_next_desc_tlv(desc))169 170/**171 * pldm_first_record172 * @start: byte offset of the start of the PLDM records173 *174 * Converts a starting offset of the PLDM records into a pointer to the first175 * record.176 */177#define pldm_first_record(start) \178 ((const struct __pldmfw_record_info *)(start))179 180/**181 * pldm_next_record182 * @record: pointer to a PLDM record183 *184 * Finds a pointer to the next record following a given record185 */186#define pldm_next_record(record) \187 ((const struct __pldmfw_record_info *) \188 ((const u8 *)(record) + get_unaligned_le16(&(record)->record_len)))189 190/**191 * pldm_for_each_record192 * @i: variable to store record index193 * @record: variable to store record pointer194 * @start: byte offset of the start of the records195 * @count: the number of records196 *197 * for loop macro to iterate over all of the records of a PLDM file.198 */199#define pldm_for_each_record(i, record, start, count) \200 for ((i) = 0, (record) = pldm_first_record(start); \201 (i) < (count); \202 (i)++, (record) = pldm_next_record(record))203 204/**205 * pldm_first_component206 * @start: byte offset of the start of the PLDM components207 *208 * Convert a starting offset of the PLDM components into a pointer to the209 * first component210 */211#define pldm_first_component(start) \212 ((const struct __pldmfw_component_info *)(start))213 214/**215 * pldm_next_component216 * @component: pointer to a PLDM component217 *218 * Finds a pointer to the next component following a given component219 */220#define pldm_next_component(component) \221 ((const struct __pldmfw_component_info *)((component)->version_string + \222 (component)->version_len))223 224/**225 * pldm_for_each_component226 * @i: variable to store component index227 * @component: variable to store component pointer228 * @start: byte offset to the start of the first component229 * @count: the number of components230 *231 * for loop macro to iterate over all of the components of a PLDM file.232 */233#define pldm_for_each_component(i, component, start, count) \234 for ((i) = 0, (component) = pldm_first_component(start); \235 (i) < (count); \236 (i)++, (component) = pldm_next_component(component))237 238#endif239