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 */ |
27 | static const uuid_t = |
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 0x01 |
33 | |
34 | /* timestamp104 structure defined in PLDM Base specification */ |
35 | #define PLDM_TIMESTAMP_SIZE 13 |
36 | struct __pldm_timestamp { |
37 | u8 b[PLDM_TIMESTAMP_SIZE]; |
38 | } __packed __aligned(1); |
39 | |
40 | /* Package Header Information */ |
41 | struct { |
42 | uuid_t ; /* PackageHeaderIdentifier */ |
43 | u8 ; /* PackageHeaderFormatRevision */ |
44 | __le16 ; /* PackageHeaderSize */ |
45 | struct __pldm_timestamp ; /* PackageReleaseDateTime */ |
46 | __le16 ; /* ComponentBitmapBitLength */ |
47 | u8 ; /* PackageVersionStringType */ |
48 | u8 ; /* 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 []; /* PackageVersionString */ |
60 | } __packed __aligned(1); |
61 | |
62 | /* Firmware Device ID Record */ |
63 | struct __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 */ |
91 | struct __pldmfw_desc_tlv { |
92 | __le16 type; /* DescriptorType */ |
93 | __le16 size; /* DescriptorSize */ |
94 | u8 data[]; /* DescriptorData */ |
95 | } __aligned(1); |
96 | |
97 | /* Firmware Device Identification Area */ |
98 | struct __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 */ |
105 | struct __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 */ |
129 | struct __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 | |