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