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