]>
Commit | Line | Data |
---|---|---|
b8265621 JK |
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 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 | |
36 | struct __pldm_timestamp { | |
37 | u8 b[PLDM_TIMESTAMP_SIZE]; | |
38 | } __packed __aligned(1); | |
39 | ||
40 | /* Package Header Information */ | |
41 | struct __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 */ | |
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 |