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