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 #include <libpldm/pldm.h> 11 12 #include <phosphor-logging/lg2.hpp> 13 14 #include <array> 15 #include <cstring> 16 #include <iostream> 17 #include <map> 18 #include <stdexcept> 19 #include <vector> 20 21 #ifdef OEM_IBM 22 #include <libpldm/file_io.h> 23 #include <libpldm/host.h> 24 #endif 25 26 PHOSPHOR_LOG2_USING; 27 28 namespace pldm 29 { 30 using Type = uint8_t; 31 32 namespace responder 33 { 34 using Cmd = std::vector<uint8_t>; 35 36 static const std::map<Type, Cmd> capabilities{ 37 {PLDM_BASE, 38 {PLDM_GET_TID, PLDM_GET_PLDM_VERSION, PLDM_GET_PLDM_TYPES, 39 PLDM_GET_PLDM_COMMANDS}}, 40 {PLDM_PLATFORM, 41 {PLDM_GET_PDR, PLDM_SET_STATE_EFFECTER_STATES, PLDM_SET_EVENT_RECEIVER, 42 PLDM_GET_SENSOR_READING, PLDM_GET_STATE_SENSOR_READINGS, 43 PLDM_SET_NUMERIC_EFFECTER_VALUE, PLDM_GET_NUMERIC_EFFECTER_VALUE, 44 PLDM_PLATFORM_EVENT_MESSAGE}}, 45 {PLDM_BIOS, 46 {PLDM_GET_DATE_TIME, PLDM_SET_DATE_TIME, PLDM_GET_BIOS_TABLE, 47 PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE, 48 PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE, PLDM_SET_BIOS_TABLE}}, 49 {PLDM_FRU, 50 {PLDM_GET_FRU_RECORD_TABLE_METADATA, PLDM_GET_FRU_RECORD_TABLE, 51 PLDM_GET_FRU_RECORD_BY_OPTION}}, 52 #ifdef OEM_IBM 53 {PLDM_OEM, 54 {PLDM_HOST_GET_ALERT_STATUS, PLDM_GET_FILE_TABLE, PLDM_READ_FILE, 55 PLDM_WRITE_FILE, PLDM_READ_FILE_INTO_MEMORY, PLDM_WRITE_FILE_FROM_MEMORY, 56 PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, 57 PLDM_NEW_FILE_AVAILABLE, PLDM_READ_FILE_BY_TYPE, PLDM_WRITE_FILE_BY_TYPE, 58 PLDM_FILE_ACK}}, 59 #endif 60 }; 61 62 static const std::map<Type, ver32_t> versions{ 63 {PLDM_BASE, {0x00, 0xf0, 0xf0, 0xf1}}, 64 {PLDM_PLATFORM, {0x00, 0xf0, 0xf2, 0xf1}}, 65 {PLDM_BIOS, {0x00, 0xf0, 0xf0, 0xf1}}, 66 {PLDM_FRU, {0x00, 0xf0, 0xf0, 0xf1}}, 67 #ifdef OEM_IBM 68 {PLDM_OEM, {0x00, 0xf0, 0xf0, 0xf1}}, 69 #endif 70 }; 71 72 namespace base 73 { 74 Response Handler::getPLDMTypes(const pldm_msg* request, 75 size_t /*payloadLength*/) 76 { 77 // DSP0240 has this as a bitfield8[N], where N = 0 to 7 78 std::array<bitfield8_t, 8> types{}; 79 for (const auto& type : capabilities) 80 { 81 auto index = type.first / 8; 82 // <Type Number> = <Array Index> * 8 + <bit position> 83 auto bit = type.first - (index * 8); 84 types[index].byte |= 1 << bit; 85 } 86 87 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0); 88 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 89 auto rc = encode_get_types_resp(request->hdr.instance_id, PLDM_SUCCESS, 90 types.data(), responsePtr); 91 if (rc != PLDM_SUCCESS) 92 { 93 return CmdHandler::ccOnlyResponse(request, rc); 94 } 95 96 return response; 97 } 98 99 Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength) 100 { 101 ver32_t version{}; 102 Type type; 103 104 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0); 105 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 106 107 auto rc = decode_get_commands_req(request, payloadLength, &type, &version); 108 109 if (rc != PLDM_SUCCESS) 110 { 111 return CmdHandler::ccOnlyResponse(request, rc); 112 } 113 114 // DSP0240 has this as a bitfield8[N], where N = 0 to 31 115 std::array<bitfield8_t, 32> cmds{}; 116 if (capabilities.find(type) == capabilities.end()) 117 { 118 return CmdHandler::ccOnlyResponse(request, 119 PLDM_ERROR_INVALID_PLDM_TYPE); 120 } 121 122 for (const auto& cmd : capabilities.at(type)) 123 { 124 auto index = cmd / 8; 125 // <Type Number> = <Array Index> * 8 + <bit position> 126 auto bit = cmd - (index * 8); 127 cmds[index].byte |= 1 << bit; 128 } 129 130 rc = encode_get_commands_resp(request->hdr.instance_id, PLDM_SUCCESS, 131 cmds.data(), responsePtr); 132 if (rc != PLDM_SUCCESS) 133 { 134 return ccOnlyResponse(request, rc); 135 } 136 137 return response; 138 } 139 140 Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength) 141 { 142 uint32_t transferHandle; 143 Type type; 144 uint8_t transferFlag; 145 146 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0); 147 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 148 149 uint8_t rc = decode_get_version_req(request, payloadLength, &transferHandle, 150 &transferFlag, &type); 151 152 if (rc != PLDM_SUCCESS) 153 { 154 return CmdHandler::ccOnlyResponse(request, rc); 155 } 156 157 ver32_t version{}; 158 auto search = versions.find(type); 159 160 if (search == versions.end()) 161 { 162 return CmdHandler::ccOnlyResponse(request, 163 PLDM_ERROR_INVALID_PLDM_TYPE); 164 } 165 166 memcpy(&version, &(search->second), sizeof(version)); 167 rc = encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0, 168 PLDM_START_AND_END, &version, 169 sizeof(pldm_version), responsePtr); 170 if (rc != PLDM_SUCCESS) 171 { 172 return ccOnlyResponse(request, rc); 173 } 174 175 return response; 176 } 177 178 void Handler::processSetEventReceiver( 179 sdeventplus::source::EventBase& /*source */) 180 { 181 survEvent.reset(); 182 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 183 PLDM_SET_EVENT_RECEIVER_REQ_BYTES); 184 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 185 auto instanceId = instanceIdDb.next(eid); 186 uint8_t eventMessageGlobalEnable = 187 PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE; 188 uint8_t transportProtocolType = PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP; 189 uint8_t eventReceiverAddressInfo = pldm::responder::pdr::BmcMctpEid; 190 uint16_t heartbeatTimer = HEARTBEAT_TIMEOUT; 191 192 auto rc = encode_set_event_receiver_req( 193 instanceId, eventMessageGlobalEnable, transportProtocolType, 194 eventReceiverAddressInfo, heartbeatTimer, request); 195 if (rc != PLDM_SUCCESS) 196 { 197 instanceIdDb.free(eid, instanceId); 198 error("Failed to encode_set_event_receiver_req, rc = {RC}", "RC", 199 lg2::hex, rc); 200 return; 201 } 202 203 auto processSetEventReceiverResponse = 204 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 205 if (response == nullptr || !respMsgLen) 206 { 207 error("Failed to receive response for setEventReceiver command"); 208 return; 209 } 210 211 uint8_t completionCode{}; 212 auto rc = decode_set_event_receiver_resp(response, respMsgLen, 213 &completionCode); 214 if (rc || completionCode) 215 { 216 error( 217 "Failed to decode setEventReceiver command response, rc = {RC}, cc = {CC}", 218 "RC", rc, "CC", (unsigned)completionCode); 219 pldm::utils::reportError( 220 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 221 } 222 }; 223 rc = handler->registerRequest( 224 eid, instanceId, PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER, 225 std::move(requestMsg), std::move(processSetEventReceiverResponse)); 226 227 if (rc != PLDM_SUCCESS) 228 { 229 error("Failed to send the setEventReceiver request"); 230 } 231 232 if (oemPlatformHandler) 233 { 234 oemPlatformHandler->countSetEventReceiver(); 235 oemPlatformHandler->checkAndDisableWatchDog(); 236 } 237 } 238 239 Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/) 240 { 241 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0); 242 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 243 auto rc = encode_get_tid_resp(request->hdr.instance_id, PLDM_SUCCESS, 244 TERMINUS_ID, responsePtr); 245 if (rc != PLDM_SUCCESS) 246 { 247 return ccOnlyResponse(request, rc); 248 } 249 250 survEvent = std::make_unique<sdeventplus::source::Defer>( 251 event, std::bind_front(&Handler::processSetEventReceiver, this)); 252 253 return response; 254 } 255 256 } // namespace base 257 } // namespace responder 258 } // namespace pldm 259