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