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