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