Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /* Copyright (C) 2018-2019, Intel Corporation. */
0003 
0004 #ifndef _PLDMFW_PRIVATE_H_
0005 #define _PLDMFW_PRIVATE_H_
0006 
0007 /* The following data structures define the layout of a firmware binary
0008  * following the "PLDM For Firmware Update Specification", DMTF standard
0009  * #DSP0267.
0010  *
0011  * pldmfw.c uses these structures to implement a simple engine that will parse
0012  * a fw binary file in this format and perform a firmware update for a given
0013  * device.
0014  *
0015  * Due to the variable sized data layout, alignment of fields within these
0016  * structures is not guaranteed when reading. For this reason, all multi-byte
0017  * field accesses should be done using the unaligned access macros.
0018  * Additionally, the standard specifies that multi-byte fields are in
0019  * LittleEndian format.
0020  *
0021  * The structure definitions are not made public, in order to keep direct
0022  * accesses within code that is prepared to deal with the limitation of
0023  * unaligned access.
0024  */
0025 
0026 /* UUID for PLDM firmware packages: f018878c-cb7d-4943-9800-a02f059aca02 */
0027 static const uuid_t pldm_firmware_header_id =
0028     UUID_INIT(0xf018878c, 0xcb7d, 0x4943,
0029           0x98, 0x00, 0xa0, 0x2f, 0x05, 0x9a, 0xca, 0x02);
0030 
0031 /* Revision number of the PLDM header format this code supports */
0032 #define PACKAGE_HEADER_FORMAT_REVISION 0x01
0033 
0034 /* timestamp104 structure defined in PLDM Base specification */
0035 #define PLDM_TIMESTAMP_SIZE 13
0036 struct __pldm_timestamp {
0037     u8 b[PLDM_TIMESTAMP_SIZE];
0038 } __packed __aligned(1);
0039 
0040 /* Package Header Information */
0041 struct __pldm_header {
0042     uuid_t id;              /* PackageHeaderIdentifier */
0043     u8 revision;                /* PackageHeaderFormatRevision */
0044     __le16 size;                /* PackageHeaderSize */
0045     struct __pldm_timestamp release_date; /* PackageReleaseDateTime */
0046     __le16 component_bitmap_len;        /* ComponentBitmapBitLength */
0047     u8 version_type;            /* PackageVersionStringType */
0048     u8 version_len;             /* PackageVersionStringLength */
0049 
0050     /*
0051      * DSP0267 also includes the following variable length fields at the
0052      * end of this structure:
0053      *
0054      * PackageVersionString, length is version_len.
0055      *
0056      * The total size of this section is
0057      *   sizeof(pldm_header) + version_len;
0058      */
0059     u8 version_string[];        /* PackageVersionString */
0060 } __packed __aligned(1);
0061 
0062 /* Firmware Device ID Record */
0063 struct __pldmfw_record_info {
0064     __le16 record_len;      /* RecordLength */
0065     u8 descriptor_count;        /* DescriptorCount */
0066     __le32 device_update_flags; /* DeviceUpdateOptionFlags */
0067     u8 version_type;        /* ComponentImageSetVersionType */
0068     u8 version_len;         /* ComponentImageSetVersionLength */
0069     __le16 package_data_len;    /* FirmwareDevicePackageDataLength */
0070 
0071     /*
0072      * DSP0267 also includes the following variable length fields at the
0073      * end of this structure:
0074      *
0075      * ApplicableComponents, length is component_bitmap_len from header
0076      * ComponentImageSetVersionString, length is version_len
0077      * RecordDescriptors, a series of TLVs with 16bit type and length
0078      * FirmwareDevicePackageData, length is package_data_len
0079      *
0080      * The total size of each record is
0081      *   sizeof(pldmfw_record_info) +
0082      *   component_bitmap_len (converted to bytes!) +
0083      *   version_len +
0084      *   <length of RecordDescriptors> +
0085      *   package_data_len
0086      */
0087     u8 variable_record_data[];
0088 } __packed __aligned(1);
0089 
0090 /* Firmware Descriptor Definition */
0091 struct __pldmfw_desc_tlv {
0092     __le16 type;            /* DescriptorType */
0093     __le16 size;            /* DescriptorSize */
0094     u8 data[];          /* DescriptorData */
0095 } __aligned(1);
0096 
0097 /* Firmware Device Identification Area */
0098 struct __pldmfw_record_area {
0099     u8 record_count;        /* DeviceIDRecordCount */
0100     /* This is not a struct type because the size of each record varies */
0101     u8 records[];
0102 } __aligned(1);
0103 
0104 /* Individual Component Image Information */
0105 struct __pldmfw_component_info {
0106     __le16 classification;      /* ComponentClassfication */
0107     __le16 identifier;      /* ComponentIdentifier */
0108     __le32 comparison_stamp;    /* ComponentComparisonStamp */
0109     __le16 options;         /* componentOptions */
0110     __le16 activation_method;   /* RequestedComponentActivationMethod */
0111     __le32 location_offset;     /* ComponentLocationOffset */
0112     __le32 size;            /* ComponentSize */
0113     u8 version_type;        /* ComponentVersionStringType */
0114     u8 version_len;     /* ComponentVersionStringLength */
0115 
0116     /*
0117      * DSP0267 also includes the following variable length fields at the
0118      * end of this structure:
0119      *
0120      * ComponentVersionString, length is version_len
0121      *
0122      * The total size of this section is
0123      *   sizeof(pldmfw_component_info) + version_len;
0124      */
0125     u8 version_string[];        /* ComponentVersionString */
0126 } __packed __aligned(1);
0127 
0128 /* Component Image Information Area */
0129 struct __pldmfw_component_area {
0130     __le16 component_image_count;
0131     /* This is not a struct type because the component size varies */
0132     u8 components[];
0133 } __aligned(1);
0134 
0135 /**
0136  * pldm_first_desc_tlv
0137  * @start: byte offset of the start of the descriptor TLVs
0138  *
0139  * Converts the starting offset of the descriptor TLVs into a pointer to the
0140  * first descriptor.
0141  */
0142 #define pldm_first_desc_tlv(start)                  \
0143     ((const struct __pldmfw_desc_tlv *)(start))
0144 
0145 /**
0146  * pldm_next_desc_tlv
0147  * @desc: pointer to a descriptor TLV
0148  *
0149  * Finds the pointer to the next descriptor following a given descriptor
0150  */
0151 #define pldm_next_desc_tlv(desc)                        \
0152     ((const struct __pldmfw_desc_tlv *)((desc)->data +          \
0153                          get_unaligned_le16(&(desc)->size)))
0154 
0155 /**
0156  * pldm_for_each_desc_tlv
0157  * @i: variable to store descriptor index
0158  * @desc: variable to store descriptor pointer
0159  * @start: byte offset of the start of the descriptors
0160  * @count: the number of descriptors
0161  *
0162  * for loop macro to iterate over all of the descriptors of a given PLDM
0163  * record.
0164  */
0165 #define pldm_for_each_desc_tlv(i, desc, start, count)           \
0166     for ((i) = 0, (desc) = pldm_first_desc_tlv(start);      \
0167          (i) < (count);                     \
0168          (i)++, (desc) = pldm_next_desc_tlv(desc))
0169 
0170 /**
0171  * pldm_first_record
0172  * @start: byte offset of the start of the PLDM records
0173  *
0174  * Converts a starting offset of the PLDM records into a pointer to the first
0175  * record.
0176  */
0177 #define pldm_first_record(start)                    \
0178     ((const struct __pldmfw_record_info *)(start))
0179 
0180 /**
0181  * pldm_next_record
0182  * @record: pointer to a PLDM record
0183  *
0184  * Finds a pointer to the next record following a given record
0185  */
0186 #define pldm_next_record(record)                    \
0187     ((const struct __pldmfw_record_info *)              \
0188      ((const u8 *)(record) + get_unaligned_le16(&(record)->record_len)))
0189 
0190 /**
0191  * pldm_for_each_record
0192  * @i: variable to store record index
0193  * @record: variable to store record pointer
0194  * @start: byte offset of the start of the records
0195  * @count: the number of records
0196  *
0197  * for loop macro to iterate over all of the records of a PLDM file.
0198  */
0199 #define pldm_for_each_record(i, record, start, count)           \
0200     for ((i) = 0, (record) = pldm_first_record(start);      \
0201          (i) < (count);                     \
0202          (i)++, (record) = pldm_next_record(record))
0203 
0204 /**
0205  * pldm_first_component
0206  * @start: byte offset of the start of the PLDM components
0207  *
0208  * Convert a starting offset of the PLDM components into a pointer to the
0209  * first component
0210  */
0211 #define pldm_first_component(start)                 \
0212     ((const struct __pldmfw_component_info *)(start))
0213 
0214 /**
0215  * pldm_next_component
0216  * @component: pointer to a PLDM component
0217  *
0218  * Finds a pointer to the next component following a given component
0219  */
0220 #define pldm_next_component(component)                      \
0221     ((const struct __pldmfw_component_info *)((component)->version_string + \
0222                           (component)->version_len))
0223 
0224 /**
0225  * pldm_for_each_component
0226  * @i: variable to store component index
0227  * @component: variable to store component pointer
0228  * @start: byte offset to the start of the first component
0229  * @count: the number of components
0230  *
0231  * for loop macro to iterate over all of the components of a PLDM file.
0232  */
0233 #define pldm_for_each_component(i, component, start, count)     \
0234     for ((i) = 0, (component) = pldm_first_component(start);    \
0235          (i) < (count);                     \
0236          (i)++, (component) = pldm_next_component(component))
0237 
0238 #endif