xref: /OK3568_Linux_fs/kernel/lib/pldmfw/pldmfw_private.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun /* Copyright (C) 2018-2019, Intel Corporation. */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #ifndef _PLDMFW_PRIVATE_H_
5*4882a593Smuzhiyun #define _PLDMFW_PRIVATE_H_
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun /* The following data structures define the layout of a firmware binary
8*4882a593Smuzhiyun  * following the "PLDM For Firmware Update Specification", DMTF standard
9*4882a593Smuzhiyun  * #DSP0267.
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * pldmfw.c uses these structures to implement a simple engine that will parse
12*4882a593Smuzhiyun  * a fw binary file in this format and perform a firmware update for a given
13*4882a593Smuzhiyun  * device.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * Due to the variable sized data layout, alignment of fields within these
16*4882a593Smuzhiyun  * structures is not guaranteed when reading. For this reason, all multi-byte
17*4882a593Smuzhiyun  * field accesses should be done using the unaligned access macros.
18*4882a593Smuzhiyun  * Additionally, the standard specifies that multi-byte fields are in
19*4882a593Smuzhiyun  * LittleEndian format.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * The structure definitions are not made public, in order to keep direct
22*4882a593Smuzhiyun  * accesses within code that is prepared to deal with the limitation of
23*4882a593Smuzhiyun  * unaligned access.
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /* UUID for PLDM firmware packages: f018878c-cb7d-4943-9800-a02f059aca02 */
27*4882a593Smuzhiyun static const uuid_t pldm_firmware_header_id =
28*4882a593Smuzhiyun 	UUID_INIT(0xf018878c, 0xcb7d, 0x4943,
29*4882a593Smuzhiyun 		  0x98, 0x00, 0xa0, 0x2f, 0x05, 0x9a, 0xca, 0x02);
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* Revision number of the PLDM header format this code supports */
32*4882a593Smuzhiyun #define PACKAGE_HEADER_FORMAT_REVISION 0x01
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* timestamp104 structure defined in PLDM Base specification */
35*4882a593Smuzhiyun #define PLDM_TIMESTAMP_SIZE 13
36*4882a593Smuzhiyun struct __pldm_timestamp {
37*4882a593Smuzhiyun 	u8 b[PLDM_TIMESTAMP_SIZE];
38*4882a593Smuzhiyun } __packed __aligned(1);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* Package Header Information */
41*4882a593Smuzhiyun struct __pldm_header {
42*4882a593Smuzhiyun 	uuid_t id;			    /* PackageHeaderIdentifier */
43*4882a593Smuzhiyun 	u8 revision;			    /* PackageHeaderFormatRevision */
44*4882a593Smuzhiyun 	__le16 size;			    /* PackageHeaderSize */
45*4882a593Smuzhiyun 	struct __pldm_timestamp release_date; /* PackageReleaseDateTime */
46*4882a593Smuzhiyun 	__le16 component_bitmap_len;	    /* ComponentBitmapBitLength */
47*4882a593Smuzhiyun 	u8 version_type;		    /* PackageVersionStringType */
48*4882a593Smuzhiyun 	u8 version_len;			    /* PackageVersionStringLength */
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	/*
51*4882a593Smuzhiyun 	 * DSP0267 also includes the following variable length fields at the
52*4882a593Smuzhiyun 	 * end of this structure:
53*4882a593Smuzhiyun 	 *
54*4882a593Smuzhiyun 	 * PackageVersionString, length is version_len.
55*4882a593Smuzhiyun 	 *
56*4882a593Smuzhiyun 	 * The total size of this section is
57*4882a593Smuzhiyun 	 *   sizeof(pldm_header) + version_len;
58*4882a593Smuzhiyun 	 */
59*4882a593Smuzhiyun 	u8 version_string[];		/* PackageVersionString */
60*4882a593Smuzhiyun } __packed __aligned(1);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /* Firmware Device ID Record */
63*4882a593Smuzhiyun struct __pldmfw_record_info {
64*4882a593Smuzhiyun 	__le16 record_len;		/* RecordLength */
65*4882a593Smuzhiyun 	u8 descriptor_count;		/* DescriptorCount */
66*4882a593Smuzhiyun 	__le32 device_update_flags;	/* DeviceUpdateOptionFlags */
67*4882a593Smuzhiyun 	u8 version_type;		/* ComponentImageSetVersionType */
68*4882a593Smuzhiyun 	u8 version_len;			/* ComponentImageSetVersionLength */
69*4882a593Smuzhiyun 	__le16 package_data_len;	/* FirmwareDevicePackageDataLength */
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	/*
72*4882a593Smuzhiyun 	 * DSP0267 also includes the following variable length fields at the
73*4882a593Smuzhiyun 	 * end of this structure:
74*4882a593Smuzhiyun 	 *
75*4882a593Smuzhiyun 	 * ApplicableComponents, length is component_bitmap_len from header
76*4882a593Smuzhiyun 	 * ComponentImageSetVersionString, length is version_len
77*4882a593Smuzhiyun 	 * RecordDescriptors, a series of TLVs with 16bit type and length
78*4882a593Smuzhiyun 	 * FirmwareDevicePackageData, length is package_data_len
79*4882a593Smuzhiyun 	 *
80*4882a593Smuzhiyun 	 * The total size of each record is
81*4882a593Smuzhiyun 	 *   sizeof(pldmfw_record_info) +
82*4882a593Smuzhiyun 	 *   component_bitmap_len (converted to bytes!) +
83*4882a593Smuzhiyun 	 *   version_len +
84*4882a593Smuzhiyun 	 *   <length of RecordDescriptors> +
85*4882a593Smuzhiyun 	 *   package_data_len
86*4882a593Smuzhiyun 	 */
87*4882a593Smuzhiyun 	u8 variable_record_data[];
88*4882a593Smuzhiyun } __packed __aligned(1);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /* Firmware Descriptor Definition */
91*4882a593Smuzhiyun struct __pldmfw_desc_tlv {
92*4882a593Smuzhiyun 	__le16 type;			/* DescriptorType */
93*4882a593Smuzhiyun 	__le16 size;			/* DescriptorSize */
94*4882a593Smuzhiyun 	u8 data[];			/* DescriptorData */
95*4882a593Smuzhiyun } __aligned(1);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun /* Firmware Device Identification Area */
98*4882a593Smuzhiyun struct __pldmfw_record_area {
99*4882a593Smuzhiyun 	u8 record_count;		/* DeviceIDRecordCount */
100*4882a593Smuzhiyun 	/* This is not a struct type because the size of each record varies */
101*4882a593Smuzhiyun 	u8 records[];
102*4882a593Smuzhiyun } __aligned(1);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /* Individual Component Image Information */
105*4882a593Smuzhiyun struct __pldmfw_component_info {
106*4882a593Smuzhiyun 	__le16 classification;		/* ComponentClassfication */
107*4882a593Smuzhiyun 	__le16 identifier;		/* ComponentIdentifier */
108*4882a593Smuzhiyun 	__le32 comparison_stamp;	/* ComponentComparisonStamp */
109*4882a593Smuzhiyun 	__le16 options;			/* componentOptions */
110*4882a593Smuzhiyun 	__le16 activation_method;	/* RequestedComponentActivationMethod */
111*4882a593Smuzhiyun 	__le32 location_offset;		/* ComponentLocationOffset */
112*4882a593Smuzhiyun 	__le32 size;			/* ComponentSize */
113*4882a593Smuzhiyun 	u8 version_type;		/* ComponentVersionStringType */
114*4882a593Smuzhiyun 	u8 version_len;		/* ComponentVersionStringLength */
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	/*
117*4882a593Smuzhiyun 	 * DSP0267 also includes the following variable length fields at the
118*4882a593Smuzhiyun 	 * end of this structure:
119*4882a593Smuzhiyun 	 *
120*4882a593Smuzhiyun 	 * ComponentVersionString, length is version_len
121*4882a593Smuzhiyun 	 *
122*4882a593Smuzhiyun 	 * The total size of this section is
123*4882a593Smuzhiyun 	 *   sizeof(pldmfw_component_info) + version_len;
124*4882a593Smuzhiyun 	 */
125*4882a593Smuzhiyun 	u8 version_string[];		/* ComponentVersionString */
126*4882a593Smuzhiyun } __packed __aligned(1);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /* Component Image Information Area */
129*4882a593Smuzhiyun struct __pldmfw_component_area {
130*4882a593Smuzhiyun 	__le16 component_image_count;
131*4882a593Smuzhiyun 	/* This is not a struct type because the component size varies */
132*4882a593Smuzhiyun 	u8 components[];
133*4882a593Smuzhiyun } __aligned(1);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun /**
136*4882a593Smuzhiyun  * pldm_first_desc_tlv
137*4882a593Smuzhiyun  * @start: byte offset of the start of the descriptor TLVs
138*4882a593Smuzhiyun  *
139*4882a593Smuzhiyun  * Converts the starting offset of the descriptor TLVs into a pointer to the
140*4882a593Smuzhiyun  * first descriptor.
141*4882a593Smuzhiyun  */
142*4882a593Smuzhiyun #define pldm_first_desc_tlv(start)					\
143*4882a593Smuzhiyun 	((const struct __pldmfw_desc_tlv *)(start))
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /**
146*4882a593Smuzhiyun  * pldm_next_desc_tlv
147*4882a593Smuzhiyun  * @desc: pointer to a descriptor TLV
148*4882a593Smuzhiyun  *
149*4882a593Smuzhiyun  * Finds the pointer to the next descriptor following a given descriptor
150*4882a593Smuzhiyun  */
151*4882a593Smuzhiyun #define pldm_next_desc_tlv(desc)						\
152*4882a593Smuzhiyun 	((const struct __pldmfw_desc_tlv *)((desc)->data +			\
153*4882a593Smuzhiyun 					     get_unaligned_le16(&(desc)->size)))
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun /**
156*4882a593Smuzhiyun  * pldm_for_each_desc_tlv
157*4882a593Smuzhiyun  * @i: variable to store descriptor index
158*4882a593Smuzhiyun  * @desc: variable to store descriptor pointer
159*4882a593Smuzhiyun  * @start: byte offset of the start of the descriptors
160*4882a593Smuzhiyun  * @count: the number of descriptors
161*4882a593Smuzhiyun  *
162*4882a593Smuzhiyun  * for loop macro to iterate over all of the descriptors of a given PLDM
163*4882a593Smuzhiyun  * record.
164*4882a593Smuzhiyun  */
165*4882a593Smuzhiyun #define pldm_for_each_desc_tlv(i, desc, start, count)			\
166*4882a593Smuzhiyun 	for ((i) = 0, (desc) = pldm_first_desc_tlv(start);		\
167*4882a593Smuzhiyun 	     (i) < (count);						\
168*4882a593Smuzhiyun 	     (i)++, (desc) = pldm_next_desc_tlv(desc))
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun /**
171*4882a593Smuzhiyun  * pldm_first_record
172*4882a593Smuzhiyun  * @start: byte offset of the start of the PLDM records
173*4882a593Smuzhiyun  *
174*4882a593Smuzhiyun  * Converts a starting offset of the PLDM records into a pointer to the first
175*4882a593Smuzhiyun  * record.
176*4882a593Smuzhiyun  */
177*4882a593Smuzhiyun #define pldm_first_record(start)					\
178*4882a593Smuzhiyun 	((const struct __pldmfw_record_info *)(start))
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun /**
181*4882a593Smuzhiyun  * pldm_next_record
182*4882a593Smuzhiyun  * @record: pointer to a PLDM record
183*4882a593Smuzhiyun  *
184*4882a593Smuzhiyun  * Finds a pointer to the next record following a given record
185*4882a593Smuzhiyun  */
186*4882a593Smuzhiyun #define pldm_next_record(record)					\
187*4882a593Smuzhiyun 	((const struct __pldmfw_record_info *)				\
188*4882a593Smuzhiyun 	 ((const u8 *)(record) + get_unaligned_le16(&(record)->record_len)))
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun /**
191*4882a593Smuzhiyun  * pldm_for_each_record
192*4882a593Smuzhiyun  * @i: variable to store record index
193*4882a593Smuzhiyun  * @record: variable to store record pointer
194*4882a593Smuzhiyun  * @start: byte offset of the start of the records
195*4882a593Smuzhiyun  * @count: the number of records
196*4882a593Smuzhiyun  *
197*4882a593Smuzhiyun  * for loop macro to iterate over all of the records of a PLDM file.
198*4882a593Smuzhiyun  */
199*4882a593Smuzhiyun #define pldm_for_each_record(i, record, start, count)			\
200*4882a593Smuzhiyun 	for ((i) = 0, (record) = pldm_first_record(start);		\
201*4882a593Smuzhiyun 	     (i) < (count);						\
202*4882a593Smuzhiyun 	     (i)++, (record) = pldm_next_record(record))
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun /**
205*4882a593Smuzhiyun  * pldm_first_component
206*4882a593Smuzhiyun  * @start: byte offset of the start of the PLDM components
207*4882a593Smuzhiyun  *
208*4882a593Smuzhiyun  * Convert a starting offset of the PLDM components into a pointer to the
209*4882a593Smuzhiyun  * first component
210*4882a593Smuzhiyun  */
211*4882a593Smuzhiyun #define pldm_first_component(start)					\
212*4882a593Smuzhiyun 	((const struct __pldmfw_component_info *)(start))
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun /**
215*4882a593Smuzhiyun  * pldm_next_component
216*4882a593Smuzhiyun  * @component: pointer to a PLDM component
217*4882a593Smuzhiyun  *
218*4882a593Smuzhiyun  * Finds a pointer to the next component following a given component
219*4882a593Smuzhiyun  */
220*4882a593Smuzhiyun #define pldm_next_component(component)						\
221*4882a593Smuzhiyun 	((const struct __pldmfw_component_info *)((component)->version_string +	\
222*4882a593Smuzhiyun 						  (component)->version_len))
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun /**
225*4882a593Smuzhiyun  * pldm_for_each_component
226*4882a593Smuzhiyun  * @i: variable to store component index
227*4882a593Smuzhiyun  * @component: variable to store component pointer
228*4882a593Smuzhiyun  * @start: byte offset to the start of the first component
229*4882a593Smuzhiyun  * @count: the number of components
230*4882a593Smuzhiyun  *
231*4882a593Smuzhiyun  * for loop macro to iterate over all of the components of a PLDM file.
232*4882a593Smuzhiyun  */
233*4882a593Smuzhiyun #define pldm_for_each_component(i, component, start, count)		\
234*4882a593Smuzhiyun 	for ((i) = 0, (component) = pldm_first_component(start);	\
235*4882a593Smuzhiyun 	     (i) < (count);						\
236*4882a593Smuzhiyun 	     (i)++, (component) = pldm_next_component(component))
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun #endif
239