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