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