1 #pragma once 2 3 #include "config.h" 4 5 #include "libpldm/platform.h" 6 #include "libpldm/states.h" 7 8 #include "common/utils.hpp" 9 #include "event_parser.hpp" 10 #include "fru.hpp" 11 #include "host-bmc/host_pdr_handler.hpp" 12 #include "libpldmresponder/pdr.hpp" 13 #include "libpldmresponder/pdr_utils.hpp" 14 #include "pldmd/handler.hpp" 15 16 #include <stdint.h> 17 18 #include <map> 19 20 namespace pldm 21 { 22 namespace responder 23 { 24 namespace platform 25 { 26 27 using namespace pldm::utils; 28 using namespace pldm::responder::pdr_utils; 29 30 using generatePDR = 31 std::function<void(const pldm::utils::DBusHandler& dBusIntf, 32 const Json& json, pdr_utils::RepoInterface& repo)>; 33 34 using EffecterId = uint16_t; 35 using DbusObjMaps = 36 std::map<EffecterId, 37 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>>; 38 using DbusPath = std::string; 39 using EffecterObjs = std::vector<DbusPath>; 40 using EventType = uint8_t; 41 using EventHandler = std::function<int( 42 const pldm_msg* request, size_t payloadLength, uint8_t formatVersion, 43 uint8_t tid, size_t eventDataOffset)>; 44 using EventHandlers = std::vector<EventHandler>; 45 using EventMap = std::map<EventType, EventHandlers>; 46 47 // EventEntry = <uint8_t> - EventState <uint8_t> - SensorOffset <uint16_t> - 48 // SensorID 49 using EventEntry = uint32_t; 50 struct DBusInfo 51 { 52 pldm::utils::DBusMapping dBusValues; 53 pldm::utils::PropertyValue dBusPropertyValue; 54 }; 55 56 class Handler : public CmdHandler 57 { 58 public: 59 Handler(const pldm::utils::DBusHandler* dBusIntf, 60 const std::string& pdrJsonsDir, const std::string& eventsJsonsDir, 61 pldm_pdr* repo, HostPDRHandler* hostPDRHandler, 62 fru::Handler* fruHandler, bool buildPDRLazily = false, 63 const std::optional<EventMap>& addOnHandlersMap = std::nullopt) : 64 pdrRepo(repo), 65 hostPDRHandler(hostPDRHandler), stateSensorHandler(eventsJsonsDir), 66 fruHandler(fruHandler), dBusIntf(dBusIntf), pdrJsonsDir(pdrJsonsDir), 67 pdrCreated(false) 68 { 69 if (!buildPDRLazily) 70 { 71 generateTerminusLocatorPDR(pdrRepo); 72 generate(*dBusIntf, pdrJsonsDir, pdrRepo); 73 pdrCreated = true; 74 } 75 76 handlers.emplace(PLDM_GET_PDR, 77 [this](const pldm_msg* request, size_t payloadLength) { 78 return this->getPDR(request, payloadLength); 79 }); 80 handlers.emplace(PLDM_SET_NUMERIC_EFFECTER_VALUE, 81 [this](const pldm_msg* request, size_t payloadLength) { 82 return this->setNumericEffecterValue( 83 request, payloadLength); 84 }); 85 handlers.emplace(PLDM_SET_STATE_EFFECTER_STATES, 86 [this](const pldm_msg* request, size_t payloadLength) { 87 return this->setStateEffecterStates(request, 88 payloadLength); 89 }); 90 handlers.emplace(PLDM_PLATFORM_EVENT_MESSAGE, 91 [this](const pldm_msg* request, size_t payloadLength) { 92 return this->platformEventMessage(request, 93 payloadLength); 94 }); 95 96 // Default handler for PLDM Events 97 eventHandlers[PLDM_SENSOR_EVENT].emplace_back( 98 [this](const pldm_msg* request, size_t payloadLength, 99 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) { 100 return this->sensorEvent(request, payloadLength, formatVersion, 101 tid, eventDataOffset); 102 }); 103 eventHandlers[PLDM_PDR_REPOSITORY_CHG_EVENT].emplace_back( 104 [this](const pldm_msg* request, size_t payloadLength, 105 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset) { 106 return this->pldmPDRRepositoryChgEvent(request, payloadLength, 107 formatVersion, tid, 108 eventDataOffset); 109 }); 110 111 // Additional OEM event handlers for PLDM events, append it to the 112 // standard handlers 113 if (addOnHandlersMap) 114 { 115 auto addOnHandlers = addOnHandlersMap.value(); 116 for (EventMap::iterator iter = addOnHandlers.begin(); 117 iter != addOnHandlers.end(); ++iter) 118 { 119 auto search = eventHandlers.find(iter->first); 120 if (search != eventHandlers.end()) 121 { 122 search->second.insert(std::end(search->second), 123 std::begin(iter->second), 124 std::end(iter->second)); 125 } 126 else 127 { 128 eventHandlers.emplace(iter->first, iter->second); 129 } 130 } 131 } 132 } 133 134 pdr_utils::Repo& getRepo() 135 { 136 return this->pdrRepo; 137 } 138 139 /** @brief Add D-Bus mapping and value mapping(stateId to D-Bus) for the 140 * effecterId. If the same id is added, the previous dbusObjs will 141 * be "over-written". 142 * 143 * @param[in] effecterId - effecter id 144 * @param[in] dbusObj - list of D-Bus object structure and list of D-Bus 145 * property value to attribute value 146 */ 147 void addDbusObjMaps( 148 uint16_t effecterId, 149 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj); 150 151 /** @brief Retrieve an effecter id -> D-Bus objects mapping 152 * 153 * @param[in] effecterId - effecter id 154 * 155 * @return std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> - 156 * list of D-Bus object structure and list of D-Bus property value 157 * to attribute value 158 */ 159 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>& 160 getDbusObjMaps(uint16_t effecterId) const; 161 162 uint16_t getNextEffecterId() 163 { 164 return ++nextEffecterId; 165 } 166 167 /** @brief Parse PDR JSONs and build PDR repository 168 * 169 * @param[in] dBusIntf - The interface object 170 * @param[in] dir - directory housing platform specific PDR JSON files 171 * @param[in] repo - instance of concrete implementation of Repo 172 */ 173 void generate(const pldm::utils::DBusHandler& dBusIntf, 174 const std::string& dir, Repo& repo); 175 176 /** @brief Parse PDR JSONs and build state effecter PDR repository 177 * 178 * @param[in] json - platform specific PDR JSON files 179 * @param[in] repo - instance of state effecter implementation of Repo 180 */ 181 void generateStateEffecterRepo(const Json& json, Repo& repo); 182 183 /** @brief map of PLDM event type to EventHandlers 184 * 185 */ 186 EventMap eventHandlers; 187 188 /** @brief Handler for GetPDR 189 * 190 * @param[in] request - Request message payload 191 * @param[in] payloadLength - Request payload length 192 * @param[out] Response - Response message written here 193 */ 194 Response getPDR(const pldm_msg* request, size_t payloadLength); 195 196 /** @brief Handler for setNumericEffecterValue 197 * 198 * @param[in] request - Request message 199 * @param[in] payloadLength - Request payload length 200 * @return Response - PLDM Response message 201 */ 202 Response setNumericEffecterValue(const pldm_msg* request, 203 size_t payloadLength); 204 205 /** @brief Handler for setStateEffecterStates 206 * 207 * @param[in] request - Request message 208 * @param[in] payloadLength - Request payload length 209 * @return Response - PLDM Response message 210 */ 211 Response setStateEffecterStates(const pldm_msg* request, 212 size_t payloadLength); 213 214 /** @brief Handler for PlatformEventMessage 215 * 216 * @param[in] request - Request message 217 * @param[in] payloadLength - Request payload length 218 * @return Response - PLDM Response message 219 */ 220 Response platformEventMessage(const pldm_msg* request, 221 size_t payloadLength); 222 223 /** @brief Handler for event class Sensor event 224 * 225 * @param[in] request - Request message 226 * @param[in] payloadLength - Request payload length 227 * @param[in] formatVersion - Version of the event format 228 * @param[in] tid - Terminus ID of the event's originator 229 * @param[in] eventDataOffset - Offset of the event data in the request 230 * message 231 * @return PLDM completion code 232 */ 233 int sensorEvent(const pldm_msg* request, size_t payloadLength, 234 uint8_t formatVersion, uint8_t tid, size_t eventDataOffset); 235 236 /** @brief Handler for pldmPDRRepositoryChgEvent 237 * 238 * @param[in] request - Request message 239 * @param[in] payloadLength - Request payload length 240 * @param[in] formatVersion - Version of the event format 241 * @param[in] tid - Terminus ID of the event's originator 242 * @param[in] eventDataOffset - Offset of the event data in the request 243 * message 244 * @return PLDM completion code 245 */ 246 int pldmPDRRepositoryChgEvent(const pldm_msg* request, size_t payloadLength, 247 uint8_t formatVersion, uint8_t tid, 248 size_t eventDataOffset); 249 250 /** @brief Handler for extracting the PDR handles from changeEntries 251 * 252 * @param[in] changeEntryData - ChangeEntry data from changeRecord 253 * @param[in] changeEntryDataSize - total size of changeEntryData 254 * @param[in] numberOfChangeEntries - total number of changeEntries to 255 * extract 256 * @param[out] pdrRecordHandles - std::vector where the extracted PDR 257 * handles are placed 258 * @return PLDM completion code 259 */ 260 int getPDRRecordHandles(const ChangeEntry* changeEntryData, 261 size_t changeEntryDataSize, 262 size_t numberOfChangeEntries, 263 PDRRecordHandles& pdrRecordHandles); 264 265 /** @brief Handler for setting Sensor event data 266 * 267 * @param[in] sensorId - sensorID value of the sensor 268 * @param[in] sensorOffset - Identifies which state sensor within a 269 * composite state sensor the event is being returned for 270 * @param[in] eventState - The event state value from the state change that 271 * triggered the event message 272 * @return PLDM completion code 273 */ 274 int setSensorEventData(uint16_t sensorId, uint8_t sensorOffset, 275 uint8_t eventState); 276 277 /** @brief Function to set the effecter requested by pldm requester 278 * @param[in] dBusIntf - The interface object 279 * @param[in] effecterId - Effecter ID sent by the requester to act on 280 * @param[in] stateField - The state field data for each of the states, 281 * equal to composite effecter count in number 282 * @return - Success or failure in setting the states. Returns failure in 283 * terms of PLDM completion codes if atleast one state fails to be set 284 */ 285 template <class DBusInterface> 286 int setStateEffecterStatesHandler( 287 const DBusInterface& dBusIntf, uint16_t effecterId, 288 const std::vector<set_effecter_state_field>& stateField) 289 { 290 using namespace pldm::responder::pdr; 291 using namespace pldm::utils; 292 using StateSetNum = uint8_t; 293 294 state_effecter_possible_states* states = nullptr; 295 pldm_state_effecter_pdr* pdr = nullptr; 296 uint8_t compEffecterCnt = stateField.size(); 297 298 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> 299 stateEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); 300 Repo stateEffecterPDRs(stateEffecterPdrRepo.get()); 301 getRepoByType(pdrRepo, stateEffecterPDRs, PLDM_STATE_EFFECTER_PDR); 302 if (stateEffecterPDRs.empty()) 303 { 304 std::cerr << "Failed to get record by PDR type\n"; 305 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 306 } 307 308 PdrEntry pdrEntry{}; 309 auto pdrRecord = stateEffecterPDRs.getFirstRecord(pdrEntry); 310 while (pdrRecord) 311 { 312 pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data); 313 if (pdr->effecter_id != effecterId) 314 { 315 pdr = nullptr; 316 pdrRecord = 317 stateEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 318 continue; 319 } 320 321 states = reinterpret_cast<state_effecter_possible_states*>( 322 pdr->possible_states); 323 if (compEffecterCnt > pdr->composite_effecter_count) 324 { 325 std::cerr << "The requester sent wrong composite effecter" 326 << " count for the effecter, EFFECTER_ID=" 327 << effecterId << "COMP_EFF_CNT=" << compEffecterCnt 328 << "\n"; 329 return PLDM_ERROR_INVALID_DATA; 330 } 331 break; 332 } 333 334 if (!pdr) 335 { 336 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 337 } 338 339 int rc = PLDM_SUCCESS; 340 try 341 { 342 const auto& [dbusMappings, dbusValMaps] = 343 dbusObjMaps.at(effecterId); 344 for (uint8_t currState = 0; currState < compEffecterCnt; 345 ++currState) 346 { 347 std::vector<StateSetNum> allowed{}; 348 // computation is based on table 79 from DSP0248 v1.1.1 349 uint8_t bitfieldIndex = 350 stateField[currState].effecter_state / 8; 351 uint8_t bit = 352 stateField[currState].effecter_state - (8 * bitfieldIndex); 353 if (states->possible_states_size < bitfieldIndex || 354 !(states->states[bitfieldIndex].byte & (1 << bit))) 355 { 356 std::cerr 357 << "Invalid state set value, EFFECTER_ID=" << effecterId 358 << " VALUE=" << stateField[currState].effecter_state 359 << " COMPOSITE_EFFECTER_ID=" << currState 360 << " DBUS_PATH=" << dbusMappings[currState].objectPath 361 << "\n"; 362 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE; 363 break; 364 } 365 const DBusMapping& dbusMapping = dbusMappings[currState]; 366 const StatestoDbusVal& dbusValToMap = dbusValMaps[currState]; 367 368 if (stateField[currState].set_request == PLDM_REQUEST_SET) 369 { 370 try 371 { 372 dBusIntf.setDbusProperty( 373 dbusMapping, 374 dbusValToMap.at( 375 stateField[currState].effecter_state)); 376 } 377 catch (const std::exception& e) 378 { 379 std::cerr 380 << "Error setting property, ERROR=" << e.what() 381 << " PROPERTY=" << dbusMapping.propertyName 382 << " INTERFACE=" 383 << dbusMapping.interface << " PATH=" 384 << dbusMapping.objectPath << "\n"; 385 return PLDM_ERROR; 386 } 387 } 388 uint8_t* nextState = 389 reinterpret_cast<uint8_t*>(states) + 390 sizeof(state_effecter_possible_states) - 391 sizeof(states->states) + 392 (states->possible_states_size * sizeof(states->states)); 393 states = reinterpret_cast<state_effecter_possible_states*>( 394 nextState); 395 } 396 } 397 catch (const std::out_of_range& e) 398 { 399 std::cerr << "the effecterId does not exist. effecter id: " 400 << effecterId << e.what() << '\n'; 401 } 402 403 return rc; 404 } 405 406 /** @brief Build BMC Terminus Locator PDR 407 * 408 * @param[in] repo - instance of concrete implementation of Repo 409 */ 410 void generateTerminusLocatorPDR(Repo& repo); 411 412 private: 413 pdr_utils::Repo pdrRepo; 414 uint16_t nextEffecterId{}; 415 DbusObjMaps dbusObjMaps{}; 416 HostPDRHandler* hostPDRHandler; 417 events::StateSensorHandler stateSensorHandler; 418 fru::Handler* fruHandler; 419 const pldm::utils::DBusHandler* dBusIntf; 420 std::string pdrJsonsDir; 421 bool pdrCreated; 422 }; 423 424 } // namespace platform 425 } // namespace responder 426 } // namespace pldm 427