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