pldmfw_private.h (7898B)
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 binary 8 * following the "PLDM For Firmware Update Specification", DMTF standard 9 * #DSP0267. 10 * 11 * pldmfw.c uses these structures to implement a simple engine that will parse 12 * a fw binary file in this format and perform a firmware update for a given 13 * device. 14 * 15 * Due to the variable sized data layout, alignment of fields within these 16 * structures is not guaranteed when reading. For this reason, all multi-byte 17 * field accesses should be done using the unaligned access macros. 18 * Additionally, the standard specifies that multi-byte fields are in 19 * LittleEndian format. 20 * 21 * The structure definitions are not made public, in order to keep direct 22 * accesses within code that is prepared to deal with the limitation of 23 * 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 0x01 33 34/* timestamp104 structure defined in PLDM Base specification */ 35#define PLDM_TIMESTAMP_SIZE 13 36struct __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 the 52 * end of this structure: 53 * 54 * PackageVersionString, length is version_len. 55 * 56 * The total size of this section is 57 * 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 the 73 * end of this structure: 74 * 75 * ApplicableComponents, length is component_bitmap_len from header 76 * ComponentImageSetVersionString, length is version_len 77 * RecordDescriptors, a series of TLVs with 16bit type and length 78 * FirmwareDevicePackageData, length is package_data_len 79 * 80 * The total size of each record is 81 * sizeof(pldmfw_record_info) + 82 * component_bitmap_len (converted to bytes!) + 83 * version_len + 84 * <length of RecordDescriptors> + 85 * package_data_len 86 */ 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 the 118 * end of this structure: 119 * 120 * ComponentVersionString, length is version_len 121 * 122 * The total size of this section is 123 * 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_tlv 137 * @start: byte offset of the start of the descriptor TLVs 138 * 139 * Converts the starting offset of the descriptor TLVs into a pointer to the 140 * first descriptor. 141 */ 142#define pldm_first_desc_tlv(start) \ 143 ((const struct __pldmfw_desc_tlv *)(start)) 144 145/** 146 * pldm_next_desc_tlv 147 * @desc: pointer to a descriptor TLV 148 * 149 * Finds the pointer to the next descriptor following a given descriptor 150 */ 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_tlv 157 * @i: variable to store descriptor index 158 * @desc: variable to store descriptor pointer 159 * @start: byte offset of the start of the descriptors 160 * @count: the number of descriptors 161 * 162 * for loop macro to iterate over all of the descriptors of a given PLDM 163 * 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_record 172 * @start: byte offset of the start of the PLDM records 173 * 174 * Converts a starting offset of the PLDM records into a pointer to the first 175 * record. 176 */ 177#define pldm_first_record(start) \ 178 ((const struct __pldmfw_record_info *)(start)) 179 180/** 181 * pldm_next_record 182 * @record: pointer to a PLDM record 183 * 184 * Finds a pointer to the next record following a given record 185 */ 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_record 192 * @i: variable to store record index 193 * @record: variable to store record pointer 194 * @start: byte offset of the start of the records 195 * @count: the number of records 196 * 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_component 206 * @start: byte offset of the start of the PLDM components 207 * 208 * Convert a starting offset of the PLDM components into a pointer to the 209 * first component 210 */ 211#define pldm_first_component(start) \ 212 ((const struct __pldmfw_component_info *)(start)) 213 214/** 215 * pldm_next_component 216 * @component: pointer to a PLDM component 217 * 218 * Finds a pointer to the next component following a given component 219 */ 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_component 226 * @i: variable to store component index 227 * @component: variable to store component pointer 228 * @start: byte offset to the start of the first component 229 * @count: the number of components 230 * 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#endif