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