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