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
239

source code of linux/lib/pldmfw/pldmfw_private.h