1 #include "libpldm/base.h" 2 3 #include "base.hpp" 4 5 #include <array> 6 #include <cstring> 7 #include <map> 8 #include <stdexcept> 9 #include <vector> 10 11 #include "libpldm/bios.h" 12 #include "libpldm/fru.h" 13 #include "libpldm/platform.h" 14 15 #ifdef OEM_IBM 16 #include "libpldm/file_io.h" 17 #include "libpldm/host.h" 18 #endif 19 20 namespace pldm 21 { 22 23 using Type = uint8_t; 24 25 namespace responder 26 { 27 28 using Cmd = std::vector<uint8_t>; 29 30 static const std::map<Type, Cmd> capabilities{ 31 {PLDM_BASE, 32 {PLDM_GET_TID, PLDM_GET_PLDM_VERSION, PLDM_GET_PLDM_TYPES, 33 PLDM_GET_PLDM_COMMANDS}}, 34 {PLDM_PLATFORM, {PLDM_GET_PDR, PLDM_SET_STATE_EFFECTER_STATES}}, 35 {PLDM_BIOS, 36 {PLDM_GET_DATE_TIME, PLDM_SET_DATE_TIME, PLDM_GET_BIOS_TABLE, 37 PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE, 38 PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE}}, 39 {PLDM_FRU, {PLDM_GET_FRU_RECORD_TABLE_METADATA, PLDM_GET_FRU_RECORD_TABLE}}, 40 #ifdef OEM_IBM 41 {PLDM_OEM, 42 {PLDM_HOST_GET_ALERT_STATUS, PLDM_GET_FILE_TABLE, PLDM_READ_FILE, 43 PLDM_WRITE_FILE, PLDM_READ_FILE_INTO_MEMORY, PLDM_WRITE_FILE_FROM_MEMORY, 44 PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, 45 PLDM_NEW_FILE_AVAILABLE, PLDM_READ_FILE_BY_TYPE, PLDM_WRITE_FILE_BY_TYPE, 46 PLDM_FILE_ACK}}, 47 #endif 48 }; 49 50 static const std::map<Type, ver32_t> versions{ 51 {PLDM_BASE, {0xF1, 0xF0, 0xF0, 0x00}}, 52 {PLDM_PLATFORM, {0xF1, 0xF2, 0xF0, 0x00}}, 53 {PLDM_BIOS, {0xF1, 0xF0, 0xF0, 0x00}}, 54 {PLDM_FRU, {0xF1, 0xF0, 0xF0, 0x00}}, 55 #ifdef OEM_IBM 56 {PLDM_OEM, {0xF1, 0xF0, 0xF0, 0x00}}, 57 #endif 58 }; 59 60 namespace base 61 { 62 63 Response Handler::getPLDMTypes(const pldm_msg* request, 64 size_t /*payloadLength*/) 65 { 66 // DSP0240 has this as a bitfield8[N], where N = 0 to 7 67 std::array<bitfield8_t, 8> types{}; 68 for (const auto& type : capabilities) 69 { 70 auto index = type.first / 8; 71 // <Type Number> = <Array Index> * 8 + <bit position> 72 auto bit = type.first - (index * 8); 73 types[index].byte |= 1 << bit; 74 } 75 76 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0); 77 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 78 auto rc = encode_get_types_resp(request->hdr.instance_id, PLDM_SUCCESS, 79 types.data(), responsePtr); 80 if (rc != PLDM_SUCCESS) 81 { 82 return CmdHandler::ccOnlyResponse(request, rc); 83 } 84 85 return response; 86 } 87 88 Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength) 89 { 90 ver32_t version{}; 91 Type type; 92 93 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0); 94 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 95 96 auto rc = decode_get_commands_req(request, payloadLength, &type, &version); 97 98 if (rc != PLDM_SUCCESS) 99 { 100 return CmdHandler::ccOnlyResponse(request, rc); 101 } 102 103 // DSP0240 has this as a bitfield8[N], where N = 0 to 31 104 std::array<bitfield8_t, 32> cmds{}; 105 if (capabilities.find(type) == capabilities.end()) 106 { 107 return CmdHandler::ccOnlyResponse(request, 108 PLDM_ERROR_INVALID_PLDM_TYPE); 109 } 110 111 for (const auto& cmd : capabilities.at(type)) 112 { 113 auto index = cmd / 8; 114 // <Type Number> = <Array Index> * 8 + <bit position> 115 auto bit = cmd - (index * 8); 116 cmds[index].byte |= 1 << bit; 117 } 118 119 rc = encode_get_commands_resp(request->hdr.instance_id, PLDM_SUCCESS, 120 cmds.data(), responsePtr); 121 if (rc != PLDM_SUCCESS) 122 { 123 return ccOnlyResponse(request, rc); 124 } 125 126 return response; 127 } 128 129 Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength) 130 { 131 uint32_t transferHandle; 132 Type type; 133 uint8_t transferFlag; 134 135 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0); 136 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 137 138 uint8_t rc = decode_get_version_req(request, payloadLength, &transferHandle, 139 &transferFlag, &type); 140 141 if (rc != PLDM_SUCCESS) 142 { 143 return CmdHandler::ccOnlyResponse(request, rc); 144 } 145 146 ver32_t version{}; 147 auto search = versions.find(type); 148 149 if (search == versions.end()) 150 { 151 return CmdHandler::ccOnlyResponse(request, 152 PLDM_ERROR_INVALID_PLDM_TYPE); 153 } 154 155 memcpy(&version, &(search->second), sizeof(version)); 156 rc = encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0, 157 PLDM_START_AND_END, &version, 158 sizeof(pldm_version), responsePtr); 159 if (rc != PLDM_SUCCESS) 160 { 161 return ccOnlyResponse(request, rc); 162 } 163 164 return response; 165 } 166 167 Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/) 168 { 169 // assigned 1 to the bmc as the PLDM terminus 170 uint8_t tid = 1; 171 172 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0); 173 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 174 auto rc = encode_get_tid_resp(request->hdr.instance_id, PLDM_SUCCESS, tid, 175 responsePtr); 176 if (rc != PLDM_SUCCESS) 177 { 178 return ccOnlyResponse(request, rc); 179 } 180 181 return response; 182 } 183 184 } // namespace base 185 } // namespace responder 186 } // namespace pldm 187