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 #define PLDM_TID_UNASSIGNED 0x00 99 #define PLDM_TID_RESERVED 0xff 100 101 /* Message payload lengths */ 102 #define PLDM_GET_COMMANDS_REQ_BYTES 5 103 #define PLDM_GET_VERSION_REQ_BYTES 6 104 105 /* Response lengths are inclusive of completion code */ 106 #define PLDM_GET_TYPES_RESP_BYTES 9 107 #define PLDM_GET_TID_RESP_BYTES 2 108 #define PLDM_SET_TID_RESP_BYTES 1 109 #define PLDM_GET_COMMANDS_RESP_BYTES 33 110 /* Response data has only one version and does not contain the checksum */ 111 #define PLDM_GET_VERSION_RESP_BYTES 10 112 #define PLDM_MULTIPART_RECEIVE_REQ_BYTES 18 113 114 #define PLDM_VERSION_0 0 115 #define PLDM_CURRENT_VERSION PLDM_VERSION_0 116 117 #define PLDM_TIMESTAMP104_SIZE 13 118 119 /** @brief Minimum length of response for a optional PLDM command 120 * 121 * For a optional PLDM command, the command handler might not be 122 * implemented in a device's firmware, a response contains only CC 123 * might come in, such as ERROR_UNSUPPORTED_PLDM_CMD. 124 * 125 * The description can be found in DSP0240: 126 * > For an unsupported PLDM command, the ERROR_UNSUPPORTED_PLDM_CMD 127 * > completion code shall be returned unless the responder is in a 128 * > transient state (not ready), in which it cannot process the PLDM 129 * > command. If the responder is in a transient state, it may return 130 * > the ERROR_NOT_READY completion code. 131 */ 132 #define PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN 1 133 134 /** @struct pldm_msg_hdr 135 * 136 * Structure representing PLDM message header fields 137 */ 138 struct pldm_msg_hdr { 139 #if defined(__LITTLE_ENDIAN_BITFIELD) 140 uint8_t instance_id : 5; //!< Instance ID 141 uint8_t reserved : 1; //!< Reserved 142 uint8_t datagram : 1; //!< Datagram bit 143 uint8_t request : 1; //!< Request bit 144 #elif defined(__BIG_ENDIAN_BITFIELD) 145 uint8_t request : 1; //!< Request bit 146 uint8_t datagram : 1; //!< Datagram bit 147 uint8_t reserved : 1; //!< Reserved 148 uint8_t instance_id : 5; //!< Instance ID 149 #endif 150 151 #if defined(__LITTLE_ENDIAN_BITFIELD) 152 uint8_t type : 6; //!< PLDM type 153 uint8_t header_ver : 2; //!< Header version 154 #elif defined(__BIG_ENDIAN_BITFIELD) 155 uint8_t header_ver : 2; //!< Header version 156 uint8_t type : 6; //!< PLDM type 157 #endif 158 uint8_t command; //!< PLDM command code 159 } __attribute__((packed)); 160 161 // Macros for byte-swapping variables in-place 162 #define HTOLE32(X) ((X) = htole32(X)) 163 #define HTOLE16(X) ((X) = htole16(X)) 164 #define LE32TOH(X) ((X) = le32toh(X)) 165 #define LE16TOH(X) ((X) = le16toh(X)) 166 167 /** @struct pldm_msg 168 * 169 * Structure representing PLDM message 170 */ 171 struct pldm_msg { 172 struct pldm_msg_hdr hdr; //!< PLDM message header 173 uint8_t payload[1]; //!< &payload[0] is the beginning of the payload 174 } __attribute__((packed)); 175 176 /** 177 * @brief Compare the headers from two PLDM messages to determine if the latter 178 * is a message representing a response to the former, where the former must be 179 * a request. 180 * 181 * @param[in] req - A pointer to a PLDM header object, which must represent a 182 * request 183 * @param[in] resp - A pointer to a PLDM header object, which may represent a 184 * response to the provided request. 185 * 186 * @return true if the header pointed to by resp represents a message that is a 187 * response to the header pointed to by req, otherwise false. 188 */ 189 bool pldm_msg_hdr_correlate_response(const struct pldm_msg_hdr *req, 190 const struct pldm_msg_hdr *resp); 191 192 /** @struct pldm_header_info 193 * 194 * The information needed to prepare PLDM header and this is passed to the 195 * pack_pldm_header and unpack_pldm_header API. 196 */ 197 struct pldm_header_info { 198 MessageType msg_type; //!< PLDM message type 199 uint8_t instance; //!< PLDM instance id 200 uint8_t pldm_type; //!< PLDM type 201 uint8_t command; //!< PLDM command code 202 uint8_t completion_code; //!< PLDM completion code, applies for response 203 }; 204 205 /** @struct pldm_get_types_resp 206 * 207 * Structure representing PLDM get types response. 208 */ 209 struct pldm_get_types_resp { 210 uint8_t completion_code; //!< completion code 211 bitfield8_t types[8]; //!< each bit represents whether a given PLDM Type 212 //!< is supported 213 } __attribute__((packed)); 214 215 /** @struct pldm_get_commands_req 216 * 217 * Structure representing PLDM get commands request. 218 */ 219 struct pldm_get_commands_req { 220 uint8_t type; //!< PLDM Type for which command support information is 221 //!< being requested 222 ver32_t version; //!< version for the specified PLDM Type 223 } __attribute__((packed)); 224 225 /** @struct pldm_get_commands_resp 226 * 227 * Structure representing PLDM get commands response. 228 */ 229 struct pldm_get_commands_resp { 230 uint8_t completion_code; //!< completion code 231 bitfield8_t commands[32]; //!< each bit represents whether a given PLDM 232 //!< command is supported 233 } __attribute__((packed)); 234 235 /** @struct pldm_get_version_req 236 * 237 * Structure representing PLDM get version request. 238 */ 239 struct pldm_get_version_req { 240 uint32_t transfer_handle; //!< handle to identify PLDM version data transfer 241 uint8_t transfer_opflag; //!< PLDM GetVersion operation flag 242 uint8_t type; //!< PLDM Type for which version information is being requested 243 } __attribute__((packed)); 244 245 /** @struct pldm_get_version_resp 246 * 247 * Structure representing PLDM get version response. 248 */ 249 250 struct pldm_get_version_resp { 251 uint8_t completion_code; //!< completion code 252 uint32_t next_transfer_handle; //!< next portion of PLDM version data 253 //!< transfer 254 uint8_t transfer_flag; //!< PLDM GetVersion transfer flag 255 uint8_t version_data[1]; //!< PLDM GetVersion version field 256 } __attribute__((packed)); 257 258 /** @struct pldm_set_tid_req 259 * 260 * Structure representing PLDM set tid request. 261 */ 262 263 struct pldm_set_tid_req { 264 uint8_t tid; //!< PLDM SetTID TID field 265 } __attribute__((packed)); 266 267 /** @struct pldm_get_tid_resp 268 * 269 * Structure representing PLDM get tid response. 270 */ 271 272 struct pldm_get_tid_resp { 273 uint8_t completion_code; //!< completion code 274 uint8_t tid; //!< PLDM GetTID TID field 275 } __attribute__((packed)); 276 277 /** @struct pldm_multipart_receive_req 278 * 279 * Structure representing PLDM multipart receive request. 280 */ 281 struct pldm_multipart_receive_req { 282 uint8_t pldm_type; //!< PLDM Type for the MultipartReceive 283 //!< command. 284 uint8_t transfer_opflag; //!< PLDM MultipartReceive operation flag. 285 uint32_t transfer_ctx; //!< Protocol-specifc context for this 286 //!< transfer. 287 uint32_t transfer_handle; //!< handle to identify the part of data to be 288 //!< received. 289 uint32_t section_offset; //!< The start offset for the requested 290 //!< section. 291 uint32_t section_length; //!< The length (in bytes) of the section 292 //!< requested. 293 } __attribute__((packed)); 294 /** 295 * @brief Populate the PLDM message with the PLDM header.The caller of this API 296 * allocates buffer for the PLDM header when forming the PLDM message. 297 * The buffer is passed to this API to pack the PLDM header. 298 * 299 * @param[in] hdr - Pointer to the PLDM header information 300 * @param[out] msg - Pointer to PLDM message header 301 * 302 * @return 0 on success, otherwise PLDM error codes. 303 * @note Caller is responsible for alloc and dealloc of msg 304 * and hdr params 305 */ 306 uint8_t pack_pldm_header(const struct pldm_header_info *hdr, 307 struct pldm_msg_hdr *msg); 308 309 /** 310 * @brief Unpack the PLDM header from the PLDM message. 311 * 312 * @param[in] msg - Pointer to the PLDM message header 313 * @param[out] hdr - Pointer to the PLDM header information 314 * 315 * @return 0 on success, otherwise PLDM error codes. 316 * @note Caller is responsible for alloc and dealloc of msg 317 * and hdr params 318 */ 319 uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg, 320 struct pldm_header_info *hdr); 321 322 /* Requester */ 323 324 /* GetPLDMTypes */ 325 326 /** @brief Create a PLDM request message for GetPLDMTypes 327 * 328 * @param[in] instance_id - Message's instance id 329 * @param[in,out] msg - Message will be written to this 330 * @return pldm_completion_codes 331 * @note Caller is responsible for memory alloc and dealloc of param 332 * 'msg.payload' 333 */ 334 int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg); 335 336 /** @brief Decode a GetPLDMTypes response message 337 * 338 * Note: 339 * * If the return value is not PLDM_SUCCESS, it represents a 340 * transport layer error. 341 * * If the completion_code value is not PLDM_SUCCESS, it represents a 342 * protocol layer error and all the out-parameters are invalid. 343 * 344 * @param[in] msg - Response message 345 * @param[in] payload_length - Length of response message payload 346 * @param[out] completion_code - Pointer to response msg's PLDM completion code 347 * @param[out] types - pointer to array bitfield8_t[8] containing supported 348 * types (MAX_TYPES/8) = 8), as per DSP0240 349 * @return pldm_completion_codes 350 */ 351 int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length, 352 uint8_t *completion_code, bitfield8_t *types); 353 354 /* GetPLDMCommands */ 355 356 /** @brief Create a PLDM request message for GetPLDMCommands 357 * 358 * @param[in] instance_id - Message's instance id 359 * @param[in] type - PLDM Type 360 * @param[in] version - Version for PLDM Type 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_commands_req(uint8_t instance_id, uint8_t type, ver32_t version, 367 struct pldm_msg *msg); 368 369 /** @brief Decode a GetPLDMCommands response message 370 * 371 * Note: 372 * * If the return value is not PLDM_SUCCESS, it represents a 373 * transport layer error. 374 * * If the completion_code value is not PLDM_SUCCESS, it represents a 375 * protocol layer error and all the out-parameters are invalid. 376 * 377 * @param[in] msg - Response message 378 * @param[in] payload_length - Length of response message payload 379 * @param[out] completion_code - Pointer to response msg's PLDM completion code 380 * @param[in] commands - pointer to array bitfield8_t[32] containing supported 381 * commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240 382 * @return pldm_completion_codes 383 */ 384 int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length, 385 uint8_t *completion_code, bitfield8_t *commands); 386 387 /* GetPLDMVersion */ 388 389 /** @brief Create a PLDM request for GetPLDMVersion 390 * 391 * @param[in] instance_id - Message's instance id 392 * @param[in] transfer_handle - Handle to identify PLDM version data transfer. 393 * This handle is ignored by the responder when the 394 * transferop_flag is set to getFirstPart. 395 * @param[in] transfer_opflag - flag to indicate whether it is start of 396 * transfer 397 * @param[in] type - PLDM Type for which version is requested 398 * @param[in,out] msg - Message will be written to this 399 * @return pldm_completion_codes 400 * @note Caller is responsible for memory alloc and dealloc of param 401 * 'msg.payload' 402 */ 403 int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle, 404 uint8_t transfer_opflag, uint8_t type, 405 struct pldm_msg *msg); 406 407 /** @brief Decode a GetPLDMVersion response message 408 * 409 * Note: 410 * * If the return value is not PLDM_SUCCESS, it represents a 411 * transport layer error. 412 * * If the completion_code value is not PLDM_SUCCESS, it represents a 413 * protocol layer error and all the out-parameters are invalid. 414 * 415 * @param[in] msg - Response message 416 * @param[in] payload_length - Length of response message payload 417 * @param[out] completion_code - Pointer to response msg's PLDM completion code 418 * @param[out] next_transfer_handle - the next handle for the next part of data 419 * @param[out] transfer_flag - flag to indicate the part of data 420 * @return pldm_completion_codes 421 */ 422 int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length, 423 uint8_t *completion_code, 424 uint32_t *next_transfer_handle, 425 uint8_t *transfer_flag, ver32_t *version); 426 427 /* GetTID */ 428 429 /** @brief Decode a GetTID response message 430 * 431 * Note: 432 * * If the return value is not PLDM_SUCCESS, it represents a 433 * transport layer error. 434 * * If the completion_code value is not PLDM_SUCCESS, it represents a 435 * protocol layer error and all the out-parameters are invalid. 436 * 437 * @param[in] msg - Response message 438 * @param[in] payload_length - Length of response message payload 439 * @param[out] completion_code - Pointer to response msg's PLDM completion code 440 * @param[out] tid - Pointer to the terminus id 441 * @return pldm_completion_codes 442 */ 443 int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length, 444 uint8_t *completion_code, uint8_t *tid); 445 446 /* Responder */ 447 448 /* GetPLDMTypes */ 449 450 /** @brief Create a PLDM response message for GetPLDMTypes 451 * 452 * @param[in] instance_id - Message's instance id 453 * @param[in] completion_code - PLDM completion code 454 * @param[in] types - pointer to array bitfield8_t[8] containing supported 455 * types (MAX_TYPES/8) = 8), as per DSP0240 456 * @param[in,out] msg - Message will be written to this 457 * @return pldm_completion_codes 458 * @note Caller is responsible for memory alloc and dealloc of param 459 * 'msg.payload' 460 */ 461 int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code, 462 const bitfield8_t *types, struct pldm_msg *msg); 463 464 /* GetPLDMCommands */ 465 466 /** @brief Decode GetPLDMCommands' request data 467 * 468 * @param[in] msg - Request message 469 * @param[in] payload_length - Length of request message payload 470 * @param[out] type - PLDM Type 471 * @param[out] version - Version for PLDM Type 472 * @return pldm_completion_codes 473 */ 474 int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length, 475 uint8_t *type, ver32_t *version); 476 477 /** @brief Create a PLDM response message for GetPLDMCommands 478 * 479 * @param[in] instance_id - Message's instance id 480 * @param[in] completion_code - PLDM completion code 481 * @param[in] commands - pointer to array bitfield8_t[32] containing supported 482 * commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240 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_commands_resp(uint8_t instance_id, uint8_t completion_code, 489 const bitfield8_t *commands, struct pldm_msg *msg); 490 491 /* GetPLDMVersion */ 492 493 /** @brief Create a PLDM response for GetPLDMVersion 494 * 495 * @param[in] instance_id - Message's instance id 496 * @param[in] completion_code - PLDM completion code 497 * @param[in] next_transfer_handle - Handle to identify next portion of 498 * data transfer 499 * @param[in] transfer_flag - Represents the part of transfer 500 * @param[in] version_data - the version data 501 * @param[in] version_size - size of version data 502 * @param[in,out] msg - Message will be written to this 503 * @return pldm_completion_codes 504 * @note Caller is responsible for memory alloc and dealloc of param 505 * 'msg.payload' 506 */ 507 int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code, 508 uint32_t next_transfer_handle, 509 uint8_t transfer_flag, const ver32_t *version_data, 510 size_t version_size, struct pldm_msg *msg); 511 512 /** @brief Decode a GetPLDMVersion request message 513 * 514 * @param[in] msg - Request message 515 * @param[in] payload_length - length of request message payload 516 * @param[out] transfer_handle - the handle of data 517 * @param[out] transfer_opflag - Transfer Flag 518 * @param[out] type - PLDM type for which version is requested 519 * @return pldm_completion_codes 520 */ 521 int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length, 522 uint32_t *transfer_handle, uint8_t *transfer_opflag, 523 uint8_t *type); 524 525 /* Requester */ 526 527 /* GetTID */ 528 529 /** @brief Create a PLDM request message for GetTID 530 * 531 * @param[in] instance_id - Message's instance id 532 * @param[in,out] msg - Message will be written to this 533 * @return pldm_completion_codes 534 * @note Caller is responsible for memory alloc and dealloc of param 535 * 'msg.payload' 536 */ 537 int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg); 538 539 /** @brief Create a PLDM response message for GetTID 540 * 541 * @param[in] instance_id - Message's instance id 542 * @param[in] completion_code - PLDM completion code 543 * @param[in] tid - Terminus ID 544 * @param[in,out] msg - Message will be written to this 545 * @return pldm_completion_codes 546 * @note Caller is responsible for memory alloc and dealloc of param 547 * 'msg.payload' 548 */ 549 int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code, 550 uint8_t tid, struct pldm_msg *msg); 551 552 /** @brief Create a PLDM request message for SetTID 553 * 554 * @param[in] instance_id - Message's instance id 555 * @param[in] tid - Terminus ID 556 * @param[in,out] msg - Message will be written to this 557 * @return pldm_completion_codes 558 * @note Caller is responsible for memory alloc and dealloc of param 559 * 'msg.payload' 560 */ 561 int encode_set_tid_req(uint8_t instance_id, uint8_t tid, struct pldm_msg *msg); 562 563 /* Responder */ 564 565 /* MultipartRecieve */ 566 567 /** @brief Decode a PLDM MultipartReceive request message 568 * 569 * @param[in] msg - Request message 570 * @param[in] payload_length - length of request message payload 571 * @param[out] pldm_type - PLDM type for which version is requested 572 * @param[out] transfer_opflag - Transfer Flag 573 * @param[out] transfer_ctx - The context of the packet 574 * @param[out] transfer_handle - The handle of data 575 * @param[out] section_offset - The start of the requested section 576 * @param[out] section_length - The length of the requested section 577 * @return pldm_completion_codes 578 */ 579 int decode_multipart_receive_req(const struct pldm_msg *msg, 580 size_t payload_length, uint8_t *pldm_type, 581 uint8_t *transfer_opflag, 582 uint32_t *transfer_ctx, 583 uint32_t *transfer_handle, 584 uint32_t *section_offset, 585 uint32_t *section_length); 586 587 /** @brief Create a PLDM response message containing only cc 588 * 589 * @param[in] instance_id - Message's instance id 590 * @param[in] type - PLDM Type 591 * @param[in] command - PLDM Command 592 * @param[in] cc - PLDM Completion Code 593 * @param[out] msg - Message will be written to this 594 * @return pldm_completion_codes 595 */ 596 int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command, 597 uint8_t cc, struct pldm_msg *msg); 598 599 /** @brief Create a PLDM message only with the header 600 * 601 * @param[in] msg_type - PLDM message type 602 * @param[in] instance_id - Message's instance id 603 * @param[in] pldm_type - PLDM Type 604 * @param[in] command - PLDM Command 605 * @param[out] msg - Message will be written to this 606 * 607 * @return pldm_completion_codes 608 */ 609 int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id, 610 uint8_t pldm_type, uint8_t command, 611 struct pldm_msg *msg); 612 613 #ifdef __cplusplus 614 } 615 #endif 616 617 #endif /* BASE_H */ 618