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