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