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