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