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