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