xref: /openbmc/libpldm/include/libpldm/base.h (revision efb400697eede42f14ad6290660a4aecbc314141)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #ifndef BASE_H
3 #define BASE_H
4 
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8 
9 #include <libpldm/pldm_types.h>
10 
11 #include <asm/byteorder.h>
12 #include <stdbool.h>
13 #include <stddef.h>
14 #include <stdint.h>
15 
16 typedef uint8_t pldm_tid_t;
17 
18 /** @brief PLDM Types
19  */
20 enum pldm_supported_types {
21 	PLDM_BASE = 0x00,
22 	PLDM_SMBIOS = 0x01,
23 	PLDM_PLATFORM = 0x02,
24 	PLDM_BIOS = 0x03,
25 	PLDM_FRU = 0x04,
26 	PLDM_FWUP = 0x05,
27 	PLDM_RDE = 0x06,
28 	PLDM_OEM = 0x3F,
29 };
30 
31 /** @brief PLDM Commands
32  */
33 enum pldm_supported_commands {
34 	PLDM_SET_TID = 0x1,
35 	PLDM_GET_TID = 0x2,
36 	PLDM_GET_PLDM_VERSION = 0x3,
37 	PLDM_GET_PLDM_TYPES = 0x4,
38 	PLDM_GET_PLDM_COMMANDS = 0x5,
39 	PLDM_MULTIPART_RECEIVE = 0x9,
40 };
41 
42 /** @brief PLDM base codes
43  */
44 enum pldm_completion_codes {
45 	PLDM_SUCCESS = 0x00,
46 	PLDM_ERROR = 0x01,
47 	PLDM_ERROR_INVALID_DATA = 0x02,
48 	PLDM_ERROR_INVALID_LENGTH = 0x03,
49 	PLDM_ERROR_NOT_READY = 0x04,
50 	PLDM_ERROR_UNSUPPORTED_PLDM_CMD = 0x05,
51 	PLDM_ERROR_INVALID_PLDM_TYPE = 0x20,
52 	PLDM_INVALID_TRANSFER_OPERATION_FLAG = 0x21
53 };
54 
55 enum transfer_op_flag {
56 	PLDM_GET_NEXTPART = 0,
57 	PLDM_GET_FIRSTPART = 1,
58 	PLDM_ACKNOWLEDGEMENT_ONLY = 2,
59 };
60 
61 enum transfer_multipart_op_flag {
62 	PLDM_XFER_FIRST_PART = 0,
63 	PLDM_XFER_NEXT_PART = 1,
64 	PLDM_XFER_ABORT = 2,
65 	PLDM_XFER_COMPLETE = 3,
66 	PLDM_XFER_CURRENT_PART = 4,
67 };
68 
69 enum transfer_resp_flag {
70 	PLDM_START = 0x01,
71 	PLDM_MIDDLE = 0x02,
72 	PLDM_END = 0x04,
73 	PLDM_START_AND_END = 0x05,
74 };
75 
76 /** @brief PLDM transport protocol type
77  */
78 enum pldm_transport_protocol_type {
79 	PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP = 0x00,
80 	PLDM_TRANSPORT_PROTOCOL_TYPE_OEM = 0xFF,
81 };
82 
83 /** @enum MessageType
84  *
85  *  The different message types supported by the PLDM specification.
86  */
87 typedef enum {
88 	PLDM_RESPONSE,		   //!< PLDM response
89 	PLDM_REQUEST,		   //!< PLDM request
90 	PLDM_RESERVED,		   //!< Reserved
91 	PLDM_ASYNC_REQUEST_NOTIFY, //!< Unacknowledged PLDM request messages
92 } MessageType;
93 
94 #define PLDM_INSTANCE_MAX      31
95 #define PLDM_MAX_TYPES	       64
96 #define PLDM_MAX_CMDS_PER_TYPE 256
97 #define PLDM_MAX_TIDS	       256
98 
99 /* Message payload lengths */
100 #define PLDM_GET_COMMANDS_REQ_BYTES 5
101 #define PLDM_GET_VERSION_REQ_BYTES  6
102 
103 /* Response lengths are inclusive of completion code */
104 #define PLDM_GET_TYPES_RESP_BYTES    9
105 #define PLDM_GET_TID_RESP_BYTES	     2
106 #define PLDM_SET_TID_RESP_BYTES	     1
107 #define PLDM_GET_COMMANDS_RESP_BYTES 33
108 /* Response data has only one version and does not contain the checksum */
109 #define PLDM_GET_VERSION_RESP_BYTES	 10
110 #define PLDM_MULTIPART_RECEIVE_REQ_BYTES 18
111 
112 #define PLDM_VERSION_0	     0
113 #define PLDM_CURRENT_VERSION PLDM_VERSION_0
114 
115 #define PLDM_TIMESTAMP104_SIZE 13
116 
117 /** @struct pldm_msg_hdr
118  *
119  * Structure representing PLDM message header fields
120  */
121 struct pldm_msg_hdr {
122 #if defined(__LITTLE_ENDIAN_BITFIELD)
123 	uint8_t instance_id : 5; //!< Instance ID
124 	uint8_t reserved : 1;	 //!< Reserved
125 	uint8_t datagram : 1;	 //!< Datagram bit
126 	uint8_t request : 1;	 //!< Request bit
127 #elif defined(__BIG_ENDIAN_BITFIELD)
128 	uint8_t request : 1;	 //!< Request bit
129 	uint8_t datagram : 1;	 //!< Datagram bit
130 	uint8_t reserved : 1;	 //!< Reserved
131 	uint8_t instance_id : 5; //!< Instance ID
132 #endif
133 
134 #if defined(__LITTLE_ENDIAN_BITFIELD)
135 	uint8_t type : 6;	//!< PLDM type
136 	uint8_t header_ver : 2; //!< Header version
137 #elif defined(__BIG_ENDIAN_BITFIELD)
138 	uint8_t header_ver : 2; //!< Header version
139 	uint8_t type : 6;	//!< PLDM type
140 #endif
141 	uint8_t command; //!< PLDM command code
142 } __attribute__((packed));
143 
144 // Macros for byte-swapping variables in-place
145 #define HTOLE32(X) ((X) = htole32(X))
146 #define HTOLE16(X) ((X) = htole16(X))
147 #define LE32TOH(X) ((X) = le32toh(X))
148 #define LE16TOH(X) ((X) = le16toh(X))
149 
150 /** @struct pldm_msg
151  *
152  * Structure representing PLDM message
153  */
154 struct pldm_msg {
155 	struct pldm_msg_hdr hdr; //!< PLDM message header
156 	uint8_t payload[1]; //!< &payload[0] is the beginning of the payload
157 } __attribute__((packed));
158 
159 /**
160  * @brief Compare the headers from two PLDM messages to determine if the latter
161  * is a message representing a response to the former, where the former must be
162  * a request.
163  *
164  * @param[in] req - A pointer to a PLDM header object, which must represent a
165  *                  request
166  * @param[in] resp - A pointer to a PLDM header object, which may represent a
167  *		     response to the provided request.
168  *
169  * @return true if the header pointed to by resp represents a message that is a
170  *	   response to the header pointed to by req, otherwise false.
171  */
172 bool pldm_msg_hdr_correlate_response(const struct pldm_msg_hdr *req,
173 				     const struct pldm_msg_hdr *resp);
174 
175 /** @struct pldm_header_info
176  *
177  *  The information needed to prepare PLDM header and this is passed to the
178  *  pack_pldm_header and unpack_pldm_header API.
179  */
180 struct pldm_header_info {
181 	MessageType msg_type;	 //!< PLDM message type
182 	uint8_t instance;	 //!< PLDM instance id
183 	uint8_t pldm_type;	 //!< PLDM type
184 	uint8_t command;	 //!< PLDM command code
185 	uint8_t completion_code; //!< PLDM completion code, applies for response
186 };
187 
188 /** @struct pldm_get_types_resp
189  *
190  *  Structure representing PLDM get types response.
191  */
192 struct pldm_get_types_resp {
193 	uint8_t completion_code; //!< completion code
194 	bitfield8_t types[8]; //!< each bit represents whether a given PLDM Type
195 			      //!< is supported
196 } __attribute__((packed));
197 
198 /** @struct pldm_get_commands_req
199  *
200  *  Structure representing PLDM get commands request.
201  */
202 struct pldm_get_commands_req {
203 	uint8_t type;	 //!< PLDM Type for which command support information is
204 			 //!< being requested
205 	ver32_t version; //!< version for the specified PLDM Type
206 } __attribute__((packed));
207 
208 /** @struct pldm_get_commands_resp
209  *
210  *  Structure representing PLDM get commands response.
211  */
212 struct pldm_get_commands_resp {
213 	uint8_t completion_code;  //!< completion code
214 	bitfield8_t commands[32]; //!< each bit represents whether a given PLDM
215 				  //!< command is supported
216 } __attribute__((packed));
217 
218 /** @struct pldm_get_version_req
219  *
220  *  Structure representing PLDM get version request.
221  */
222 struct pldm_get_version_req {
223 	uint32_t transfer_handle; //!< handle to identify PLDM version data transfer
224 	uint8_t transfer_opflag; //!< PLDM GetVersion operation flag
225 	uint8_t type; //!< PLDM Type for which version information is being requested
226 } __attribute__((packed));
227 
228 /** @struct pldm_get_version_resp
229  *
230  *  Structure representing PLDM get version response.
231  */
232 
233 struct pldm_get_version_resp {
234 	uint8_t completion_code;       //!< completion code
235 	uint32_t next_transfer_handle; //!< next portion of PLDM version data
236 				       //!< transfer
237 	uint8_t transfer_flag;	       //!< PLDM GetVersion transfer flag
238 	uint8_t version_data[1];       //!< PLDM GetVersion version field
239 } __attribute__((packed));
240 
241 /** @struct pldm_set_tid_req
242  *
243  *  Structure representing PLDM set tid request.
244  */
245 
246 struct pldm_set_tid_req {
247 	uint8_t tid; //!< PLDM SetTID TID field
248 } __attribute__((packed));
249 
250 /** @struct pldm_get_tid_resp
251  *
252  *  Structure representing PLDM get tid response.
253  */
254 
255 struct pldm_get_tid_resp {
256 	uint8_t completion_code; //!< completion code
257 	uint8_t tid;		 //!< PLDM GetTID TID field
258 } __attribute__((packed));
259 
260 /** @struct pldm_multipart_receive_req
261  *
262  * Structure representing PLDM multipart receive request.
263  */
264 struct pldm_multipart_receive_req {
265 	uint8_t pldm_type;	  //!< PLDM Type for the MultipartReceive
266 				  //!< command.
267 	uint8_t transfer_opflag;  //!< PLDM MultipartReceive operation flag.
268 	uint32_t transfer_ctx;	  //!< Protocol-specifc context for this
269 				  //!< transfer.
270 	uint32_t transfer_handle; //!< handle to identify the part of data to be
271 				  //!< received.
272 	uint32_t section_offset;  //!< The start offset for the requested
273 				  //!< section.
274 	uint32_t section_length;  //!< The length (in bytes) of the section
275 				  //!< requested.
276 } __attribute__((packed));
277 /**
278  * @brief Populate the PLDM message with the PLDM header.The caller of this API
279  *        allocates buffer for the PLDM header when forming the PLDM message.
280  *        The buffer is passed to this API to pack the PLDM header.
281  *
282  * @param[in] hdr - Pointer to the PLDM header information
283  * @param[out] msg - Pointer to PLDM message header
284  *
285  * @return 0 on success, otherwise PLDM error codes.
286  * @note   Caller is responsible for alloc and dealloc of msg
287  *         and hdr params
288  */
289 uint8_t pack_pldm_header(const struct pldm_header_info *hdr,
290 			 struct pldm_msg_hdr *msg);
291 
292 /**
293  * @brief Unpack the PLDM header from the PLDM message.
294  *
295  * @param[in] msg - Pointer to the PLDM message header
296  * @param[out] hdr - Pointer to the PLDM header information
297  *
298  * @return 0 on success, otherwise PLDM error codes.
299  * @note   Caller is responsible for alloc and dealloc of msg
300  *         and hdr params
301  */
302 uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg,
303 			   struct pldm_header_info *hdr);
304 
305 /* Requester */
306 
307 /* GetPLDMTypes */
308 
309 /** @brief Create a PLDM request message for GetPLDMTypes
310  *
311  *  @param[in] instance_id - Message's instance id
312  *  @param[in,out] msg - Message will be written to this
313  *  @return pldm_completion_codes
314  *  @note  Caller is responsible for memory alloc and dealloc of param
315  *         'msg.payload'
316  */
317 int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg);
318 
319 /** @brief Decode a GetPLDMTypes response message
320  *
321  *  Note:
322  *  * If the return value is not PLDM_SUCCESS, it represents a
323  * transport layer error.
324  *  * If the completion_code value is not PLDM_SUCCESS, it represents a
325  * protocol layer error and all the out-parameters are invalid.
326  *
327  *  @param[in] msg - Response message
328  *  @param[in] payload_length - Length of response message payload
329  *  @param[out] completion_code - Pointer to response msg's PLDM completion code
330  *  @param[out] types - pointer to array bitfield8_t[8] containing supported
331  *              types (MAX_TYPES/8) = 8), as per DSP0240
332  *  @return pldm_completion_codes
333  */
334 int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length,
335 			  uint8_t *completion_code, bitfield8_t *types);
336 
337 /* GetPLDMCommands */
338 
339 /** @brief Create a PLDM request message for GetPLDMCommands
340  *
341  *  @param[in] instance_id - Message's instance id
342  *  @param[in] type - PLDM Type
343  *  @param[in] version - Version for PLDM Type
344  *  @param[in,out] msg - Message will be written to this
345  *  @return pldm_completion_codes
346  *  @note  Caller is responsible for memory alloc and dealloc of param
347  *         'msg.payload'
348  */
349 int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version,
350 			    struct pldm_msg *msg);
351 
352 /** @brief Decode a GetPLDMCommands response message
353  *
354  *  Note:
355  *  * If the return value is not PLDM_SUCCESS, it represents a
356  * transport layer error.
357  *  * If the completion_code value is not PLDM_SUCCESS, it represents a
358  * protocol layer error and all the out-parameters are invalid.
359  *
360  *  @param[in] msg - Response message
361  *  @param[in] payload_length - Length of reponse message payload
362  *  @param[out] completion_code - Pointer to response msg's PLDM completion code
363  *  @param[in] commands - pointer to array bitfield8_t[32] containing supported
364  *             commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240
365  *  @return pldm_completion_codes
366  */
367 int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length,
368 			     uint8_t *completion_code, bitfield8_t *commands);
369 
370 /* GetPLDMVersion */
371 
372 /** @brief Create a PLDM request for GetPLDMVersion
373  *
374  *  @param[in] instance_id - Message's instance id
375  *  @param[in] transfer_handle - Handle to identify PLDM version data transfer.
376  *         This handle is ignored by the responder when the
377  *         transferop_flag is set to getFirstPart.
378  *  @param[in] transfer_opflag - flag to indicate whether it is start of
379  *         transfer
380  *  @param[in] type -  PLDM Type for which version is requested
381  *  @param[in,out] msg - Message will be written to this
382  *  @return pldm_completion_codes
383  *  @note  Caller is responsible for memory alloc and dealloc of param
384  *         'msg.payload'
385  */
386 int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle,
387 			   uint8_t transfer_opflag, uint8_t type,
388 			   struct pldm_msg *msg);
389 
390 /** @brief Decode a GetPLDMVersion response message
391  *
392  *  Note:
393  *  * If the return value is not PLDM_SUCCESS, it represents a
394  * transport layer error.
395  *  * If the completion_code value is not PLDM_SUCCESS, it represents a
396  * protocol layer error and all the out-parameters are invalid.
397  *
398  *  @param[in] msg - Response message
399  *  @param[in] payload_length - Length of reponse message payload
400  *  @param[out] completion_code - Pointer to response msg's PLDM completion code
401  *  @param[out] next_transfer_handle - the next handle for the next part of data
402  *  @param[out] transfer_flag - flag to indicate the part of data
403  *  @return pldm_completion_codes
404  */
405 int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length,
406 			    uint8_t *completion_code,
407 			    uint32_t *next_transfer_handle,
408 			    uint8_t *transfer_flag, ver32_t *version);
409 
410 /* GetTID */
411 
412 /** @brief Decode a GetTID response message
413  *
414  *  Note:
415  *  * If the return value is not PLDM_SUCCESS, it represents a
416  * transport layer error.
417  *  * If the completion_code value is not PLDM_SUCCESS, it represents a
418  * protocol layer error and all the out-parameters are invalid.
419  *
420  *  @param[in] msg - Response message
421  *  @param[in] payload_length - Length of response message payload
422  *  @param[out] completion_code - Pointer to response msg's PLDM completion code
423  *  @param[out] tid - Pointer to the terminus id
424  *  @return pldm_completion_codes
425  */
426 int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length,
427 			uint8_t *completion_code, uint8_t *tid);
428 
429 /* Responder */
430 
431 /* GetPLDMTypes */
432 
433 /** @brief Create a PLDM response message for GetPLDMTypes
434  *
435  *  @param[in] instance_id - Message's instance id
436  *  @param[in] completion_code - PLDM completion code
437  *  @param[in] types - pointer to array bitfield8_t[8] containing supported
438  *             types (MAX_TYPES/8) = 8), as per DSP0240
439  *  @param[in,out] msg - Message will be written to this
440  *  @return pldm_completion_codes
441  *  @note  Caller is responsible for memory alloc and dealloc of param
442  *         'msg.payload'
443  */
444 int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
445 			  const bitfield8_t *types, struct pldm_msg *msg);
446 
447 /* GetPLDMCommands */
448 
449 /** @brief Decode GetPLDMCommands' request data
450  *
451  *  @param[in] msg - Request message
452  *  @param[in] payload_length - Length of request message payload
453  *  @param[out] type - PLDM Type
454  *  @param[out] version - Version for PLDM Type
455  *  @return pldm_completion_codes
456  */
457 int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length,
458 			    uint8_t *type, ver32_t *version);
459 
460 /** @brief Create a PLDM response message for GetPLDMCommands
461  *
462  *  @param[in] instance_id - Message's instance id
463  *  @param[in] completion_code - PLDM completion code
464  *  @param[in] commands - pointer to array bitfield8_t[32] containing supported
465  *             commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240
466  *  @param[in,out] msg - Message will be written to this
467  *  @return pldm_completion_codes
468  *  @note  Caller is responsible for memory alloc and dealloc of param
469  *         'msg.payload'
470  */
471 int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
472 			     const bitfield8_t *commands, struct pldm_msg *msg);
473 
474 /* GetPLDMVersion */
475 
476 /** @brief Create a PLDM response for GetPLDMVersion
477  *
478  *  @param[in] instance_id - Message's instance id
479  *  @param[in] completion_code - PLDM completion code
480  *  @param[in] next_transfer_handle - Handle to identify next portion of
481  *              data transfer
482  *  @param[in] transfer_flag - Represents the part of transfer
483  *  @param[in] version_data - the version data
484  *  @param[in] version_size - size of version data
485  *  @param[in,out] msg - Message will be written to this
486  *  @return pldm_completion_codes
487  *  @note  Caller is responsible for memory alloc and dealloc of param
488  *         'msg.payload'
489  */
490 int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code,
491 			    uint32_t next_transfer_handle,
492 			    uint8_t transfer_flag, const ver32_t *version_data,
493 			    size_t version_size, struct pldm_msg *msg);
494 
495 /** @brief Decode a GetPLDMVersion request message
496  *
497  *  @param[in] msg - Request message
498  *  @param[in] payload_length - length of request message payload
499  *  @param[out] transfer_handle - the handle of data
500  *  @param[out] transfer_opflag - Transfer Flag
501  *  @param[out] type - PLDM type for which version is requested
502  *  @return pldm_completion_codes
503  */
504 int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length,
505 			   uint32_t *transfer_handle, uint8_t *transfer_opflag,
506 			   uint8_t *type);
507 
508 /* Requester */
509 
510 /* GetTID */
511 
512 /** @brief Create a PLDM request message for GetTID
513  *
514  *  @param[in] instance_id - Message's instance id
515  *  @param[in,out] msg - Message will be written to this
516  *  @return pldm_completion_codes
517  *  @note  Caller is responsible for memory alloc and dealloc of param
518  *         'msg.payload'
519  */
520 int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg);
521 
522 /** @brief Create a PLDM response message for GetTID
523  *
524  *  @param[in] instance_id - Message's instance id
525  *  @param[in] completion_code - PLDM completion code
526  *  @param[in] tid - Terminus ID
527  *  @param[in,out] msg - Message will be written to this
528  *  @return pldm_completion_codes
529  *  @note  Caller is responsible for memory alloc and dealloc of param
530  *         'msg.payload'
531  */
532 int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code,
533 			uint8_t tid, struct pldm_msg *msg);
534 
535 /** @brief Create a PLDM request message for SetTID
536  *
537  *  @param[in] instance_id - Message's instance id
538  *  @param[in] tid - Terminus ID
539  *  @param[in,out] msg - Message will be written to this
540  *  @return pldm_completion_codes
541  *  @note  Caller is responsible for memory alloc and dealloc of param
542  *         'msg.payload'
543  */
544 int encode_set_tid_req(uint8_t instance_id, uint8_t tid, struct pldm_msg *msg);
545 
546 /* Responder */
547 
548 /* MultipartRecieve */
549 
550 /** @brief Decode a PLDM MultipartReceive request message
551  *
552  *  @param[in] msg - Request message
553  *  @param[in] payload_length - length of request message payload
554  *  @param[out] pldm_type - PLDM type for which version is requested
555  *  @param[out] transfer_opflag - Transfer Flag
556  *  @param[out] transfer_ctx - The context of the packet
557  *  @param[out] transfer_handle - The handle of data
558  *  @param[out] section_offset - The start of the requested section
559  *  @param[out] section_length - The length of the requested section
560  *  @return pldm_completion_codes
561  */
562 int decode_multipart_receive_req(const struct pldm_msg *msg,
563 				 size_t payload_length, uint8_t *pldm_type,
564 				 uint8_t *transfer_opflag,
565 				 uint32_t *transfer_ctx,
566 				 uint32_t *transfer_handle,
567 				 uint32_t *section_offset,
568 				 uint32_t *section_length);
569 
570 /** @brief Create a PLDM response message containing only cc
571  *
572  *  @param[in] instance_id - Message's instance id
573  *  @param[in] type - PLDM Type
574  *  @param[in] command - PLDM Command
575  *  @param[in] cc - PLDM Completion Code
576  *  @param[out] msg - Message will be written to this
577  *  @return pldm_completion_codes
578  */
579 int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command,
580 			uint8_t cc, struct pldm_msg *msg);
581 
582 /** @brief Create a PLDM message only with the header
583  *
584  *	@param[in] msg_type - PLDM message type
585  *	@param[in] instance_id - Message's instance id
586  *	@param[in] pldm_type - PLDM Type
587  *	@param[in] command - PLDM Command
588  *	@param[out] msg - Message will be written to this
589  *
590  *	@return pldm_completion_codes
591  */
592 int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id,
593 			    uint8_t pldm_type, uint8_t command,
594 			    struct pldm_msg *msg);
595 
596 #ifdef __cplusplus
597 }
598 #endif
599 
600 #endif /* BASE_H */
601