1 #include "config.h" 2 3 #include "libpldm/base.h" 4 5 #include "libpldm/bios.h" 6 #include "libpldm/fru.h" 7 #include "libpldm/platform.h" 8 #include "libpldm/requester/pldm.h" 9 10 #include "base.hpp" 11 #include "common/utils.hpp" 12 #include "libpldmresponder/pdr.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 namespace pldm 27 { 28 29 using Type = uint8_t; 30 31 namespace responder 32 { 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, {0xF1, 0xF0, 0xF0, 0x00}}, 64 {PLDM_PLATFORM, {0xF1, 0xF2, 0xF0, 0x00}}, 65 {PLDM_BIOS, {0xF1, 0xF0, 0xF0, 0x00}}, 66 {PLDM_FRU, {0xF1, 0xF0, 0xF0, 0x00}}, 67 #ifdef OEM_IBM 68 {PLDM_OEM, {0xF1, 0xF0, 0xF0, 0x00}}, 69 #endif 70 }; 71 72 namespace base 73 { 74 75 Response Handler::getPLDMTypes(const pldm_msg* request, 76 size_t /*payloadLength*/) 77 { 78 // DSP0240 has this as a bitfield8[N], where N = 0 to 7 79 std::array<bitfield8_t, 8> types{}; 80 for (const auto& type : capabilities) 81 { 82 auto index = type.first / 8; 83 // <Type Number> = <Array Index> * 8 + <bit position> 84 auto bit = type.first - (index * 8); 85 types[index].byte |= 1 << bit; 86 } 87 88 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0); 89 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 90 auto rc = encode_get_types_resp(request->hdr.instance_id, PLDM_SUCCESS, 91 types.data(), responsePtr); 92 if (rc != PLDM_SUCCESS) 93 { 94 return CmdHandler::ccOnlyResponse(request, rc); 95 } 96 97 return response; 98 } 99 100 Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength) 101 { 102 ver32_t version{}; 103 Type type; 104 105 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0); 106 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 107 108 auto rc = decode_get_commands_req(request, payloadLength, &type, &version); 109 110 if (rc != PLDM_SUCCESS) 111 { 112 return CmdHandler::ccOnlyResponse(request, rc); 113 } 114 115 // DSP0240 has this as a bitfield8[N], where N = 0 to 31 116 std::array<bitfield8_t, 32> cmds{}; 117 if (capabilities.find(type) == capabilities.end()) 118 { 119 return CmdHandler::ccOnlyResponse(request, 120 PLDM_ERROR_INVALID_PLDM_TYPE); 121 } 122 123 for (const auto& cmd : capabilities.at(type)) 124 { 125 auto index = cmd / 8; 126 // <Type Number> = <Array Index> * 8 + <bit position> 127 auto bit = cmd - (index * 8); 128 cmds[index].byte |= 1 << bit; 129 } 130 131 rc = encode_get_commands_resp(request->hdr.instance_id, PLDM_SUCCESS, 132 cmds.data(), responsePtr); 133 if (rc != PLDM_SUCCESS) 134 { 135 return ccOnlyResponse(request, rc); 136 } 137 138 return response; 139 } 140 141 Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength) 142 { 143 uint32_t transferHandle; 144 Type type; 145 uint8_t transferFlag; 146 147 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0); 148 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 149 150 uint8_t rc = decode_get_version_req(request, payloadLength, &transferHandle, 151 &transferFlag, &type); 152 153 if (rc != PLDM_SUCCESS) 154 { 155 return CmdHandler::ccOnlyResponse(request, rc); 156 } 157 158 ver32_t version{}; 159 auto search = versions.find(type); 160 161 if (search == versions.end()) 162 { 163 return CmdHandler::ccOnlyResponse(request, 164 PLDM_ERROR_INVALID_PLDM_TYPE); 165 } 166 167 memcpy(&version, &(search->second), sizeof(version)); 168 rc = encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0, 169 PLDM_START_AND_END, &version, 170 sizeof(pldm_version), responsePtr); 171 if (rc != PLDM_SUCCESS) 172 { 173 return ccOnlyResponse(request, rc); 174 } 175 176 return response; 177 } 178 179 void Handler::processSetEventReceiver( 180 sdeventplus::source::EventBase& /*source */) 181 { 182 survEvent.reset(); 183 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 184 PLDM_SET_EVENT_RECEIVER_REQ_BYTES); 185 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 186 auto instanceId = requester.getInstanceId(eid); 187 uint8_t eventMessageGlobalEnable = 188 PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE; 189 uint8_t transportProtocolType = PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP; 190 uint8_t eventReceiverAddressInfo = pldm::responder::pdr::BmcMctpEid; 191 uint16_t heartbeatTimer = HEARTBEAT_TIMEOUT; 192 193 auto rc = encode_set_event_receiver_req( 194 instanceId, eventMessageGlobalEnable, transportProtocolType, 195 eventReceiverAddressInfo, heartbeatTimer, request); 196 if (rc != PLDM_SUCCESS) 197 { 198 requester.markFree(eid, instanceId); 199 std::cerr << "Failed to encode_set_event_receiver_req, rc = " 200 << std::hex << std::showbase << rc << std::endl; 201 return; 202 } 203 204 auto processSetEventReceiverResponse = [](mctp_eid_t /*eid*/, 205 const pldm_msg* response, 206 size_t respMsgLen) { 207 if (response == nullptr || !respMsgLen) 208 { 209 std::cerr << "Failed to receive response for " 210 "setEventReceiver command \n"; 211 return; 212 } 213 214 uint8_t completionCode{}; 215 auto rc = decode_set_event_receiver_resp(response, respMsgLen, 216 &completionCode); 217 if (rc || completionCode) 218 { 219 std::cerr << "Failed to decode setEventReceiver command response," 220 << " rc=" << rc << "cc=" << (uint8_t)completionCode 221 << "\n"; 222 pldm::utils::reportError( 223 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 224 } 225 }; 226 rc = handler->registerRequest( 227 eid, instanceId, PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER, 228 std::move(requestMsg), std::move(processSetEventReceiverResponse)); 229 230 if (rc != PLDM_SUCCESS) 231 { 232 std::cerr << "Failed to send the setEventReceiver request" 233 << "\n"; 234 } 235 236 if (oemPlatformHandler) 237 { 238 oemPlatformHandler->countSetEventReceiver(); 239 oemPlatformHandler->checkAndDisableWatchDog(); 240 } 241 } 242 243 Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/) 244 { 245 // assigned 1 to the bmc as the PLDM terminus 246 uint8_t tid = 1; 247 248 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0); 249 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 250 auto rc = encode_get_tid_resp(request->hdr.instance_id, PLDM_SUCCESS, tid, 251 responsePtr); 252 if (rc != PLDM_SUCCESS) 253 { 254 return ccOnlyResponse(request, rc); 255 } 256 257 survEvent = std::make_unique<sdeventplus::source::Defer>( 258 event, std::bind_front(&Handler::processSetEventReceiver, this)); 259 260 return response; 261 } 262 263 } // namespace base 264 } // namespace responder 265 } // namespace pldm 266