1 2 #include "platform.hpp" 3 4 #include "common/types.hpp" 5 #include "common/utils.hpp" 6 #include "event_parser.hpp" 7 #include "pdr.hpp" 8 #include "pdr_numeric_effecter.hpp" 9 #include "pdr_state_effecter.hpp" 10 #include "pdr_state_sensor.hpp" 11 #include "pdr_utils.hpp" 12 #include "platform_numeric_effecter.hpp" 13 #include "platform_state_effecter.hpp" 14 #include "platform_state_sensor.hpp" 15 16 namespace pldm 17 { 18 namespace responder 19 { 20 namespace platform 21 { 22 23 using InternalFailure = 24 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 25 26 static const Json empty{}; 27 28 void Handler::addDbusObjMaps( 29 uint16_t id, 30 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj, 31 TypeId typeId) 32 { 33 if (typeId == TypeId::PLDM_SENSOR_ID) 34 { 35 sensorDbusObjMaps.emplace(id, dbusObj); 36 } 37 else 38 { 39 effecterDbusObjMaps.emplace(id, dbusObj); 40 } 41 } 42 43 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>& 44 Handler::getDbusObjMaps(uint16_t id, TypeId typeId) const 45 { 46 if (typeId == TypeId::PLDM_SENSOR_ID) 47 { 48 return sensorDbusObjMaps.at(id); 49 } 50 else 51 { 52 return effecterDbusObjMaps.at(id); 53 } 54 } 55 56 void Handler::generate(const pldm::utils::DBusHandler& dBusIntf, 57 const std::string& dir, Repo& repo) 58 { 59 if (!fs::exists(dir)) 60 { 61 return; 62 } 63 64 // A map of PDR type to a lambda that handles creation of that PDR type. 65 // The lambda essentially would parse the platform specific PDR JSONs to 66 // generate the PDR structures. This function iterates through the map to 67 // invoke all lambdas, so that all PDR types can be created. 68 69 const std::map<Type, generatePDR> generateHandlers = { 70 {PLDM_STATE_EFFECTER_PDR, 71 [this](const DBusHandler& dBusIntf, const auto& json, 72 RepoInterface& repo) { 73 pdr_state_effecter::generateStateEffecterPDR< 74 pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, 75 repo); 76 }}, 77 {PLDM_NUMERIC_EFFECTER_PDR, 78 [this](const DBusHandler& dBusIntf, const auto& json, 79 RepoInterface& repo) { 80 pdr_numeric_effecter::generateNumericEffecterPDR< 81 pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, 82 repo); 83 }}, 84 {PLDM_STATE_SENSOR_PDR, [this](const DBusHandler& dBusIntf, 85 const auto& json, RepoInterface& repo) { 86 pdr_state_sensor::generateStateSensorPDR<pldm::utils::DBusHandler, 87 Handler>(dBusIntf, json, 88 *this, repo); 89 }}}; 90 91 Type pdrType{}; 92 for (const auto& dirEntry : fs::directory_iterator(dir)) 93 { 94 try 95 { 96 auto json = readJson(dirEntry.path().string()); 97 if (!json.empty()) 98 { 99 auto effecterPDRs = json.value("effecterPDRs", empty); 100 for (const auto& effecter : effecterPDRs) 101 { 102 pdrType = effecter.value("pdrType", 0); 103 generateHandlers.at(pdrType)(dBusIntf, effecter, repo); 104 } 105 106 auto sensorPDRs = json.value("sensorPDRs", empty); 107 for (const auto& sensor : sensorPDRs) 108 { 109 pdrType = sensor.value("pdrType", 0); 110 generateHandlers.at(pdrType)(dBusIntf, sensor, repo); 111 } 112 } 113 } 114 catch (const InternalFailure& e) 115 { 116 std::cerr << "PDR config directory does not exist or empty, TYPE= " 117 << pdrType << "PATH= " << dirEntry 118 << " ERROR=" << e.what() << "\n"; 119 } 120 catch (const Json::exception& e) 121 { 122 std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType 123 << " ERROR=" << e.what() << "\n"; 124 pldm::utils::reportError( 125 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 126 } 127 catch (const std::exception& e) 128 { 129 std::cerr << "Failed parsing PDR JSON file, TYPE= " << pdrType 130 << " ERROR=" << e.what() << "\n"; 131 pldm::utils::reportError( 132 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 133 } 134 } 135 } 136 137 Response Handler::getPDR(const pldm_msg* request, size_t payloadLength) 138 { 139 // Build FRU table if not built, since entity association PDR's are built 140 // when the FRU table is constructed. 141 if (fruHandler) 142 { 143 fruHandler->buildFRUTable(); 144 } 145 146 if (!pdrCreated) 147 { 148 generateTerminusLocatorPDR(pdrRepo); 149 generate(*dBusIntf, pdrJsonsDir, pdrRepo); 150 pdrCreated = true; 151 } 152 153 Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0); 154 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 155 156 if (payloadLength != PLDM_GET_PDR_REQ_BYTES) 157 { 158 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 159 } 160 161 uint32_t recordHandle{}; 162 uint32_t dataTransferHandle{}; 163 uint8_t transferOpFlag{}; 164 uint16_t reqSizeBytes{}; 165 uint16_t recordChangeNum{}; 166 167 auto rc = decode_get_pdr_req(request, payloadLength, &recordHandle, 168 &dataTransferHandle, &transferOpFlag, 169 &reqSizeBytes, &recordChangeNum); 170 if (rc != PLDM_SUCCESS) 171 { 172 return CmdHandler::ccOnlyResponse(request, rc); 173 } 174 175 uint16_t respSizeBytes{}; 176 uint8_t* recordData = nullptr; 177 try 178 { 179 pdr_utils::PdrEntry e; 180 auto record = pdr::getRecordByHandle(pdrRepo, recordHandle, e); 181 if (record == NULL) 182 { 183 return CmdHandler::ccOnlyResponse( 184 request, PLDM_PLATFORM_INVALID_RECORD_HANDLE); 185 } 186 187 if (reqSizeBytes) 188 { 189 respSizeBytes = e.size; 190 if (respSizeBytes > reqSizeBytes) 191 { 192 respSizeBytes = reqSizeBytes; 193 } 194 recordData = e.data; 195 } 196 response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES + 197 respSizeBytes, 198 0); 199 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 200 rc = encode_get_pdr_resp( 201 request->hdr.instance_id, PLDM_SUCCESS, e.handle.nextRecordHandle, 202 0, PLDM_START_AND_END, respSizeBytes, recordData, 0, responsePtr); 203 if (rc != PLDM_SUCCESS) 204 { 205 return ccOnlyResponse(request, rc); 206 } 207 } 208 catch (const std::exception& e) 209 { 210 std::cerr << "Error accessing PDR, HANDLE=" << recordHandle 211 << " ERROR=" << e.what() << "\n"; 212 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR); 213 } 214 return response; 215 } 216 217 Response Handler::setStateEffecterStates(const pldm_msg* request, 218 size_t payloadLength) 219 { 220 Response response( 221 sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0); 222 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 223 uint16_t effecterId; 224 uint8_t compEffecterCnt; 225 constexpr auto maxCompositeEffecterCnt = 8; 226 std::vector<set_effecter_state_field> stateField(maxCompositeEffecterCnt, 227 {0, 0}); 228 229 if ((payloadLength > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) || 230 (payloadLength < sizeof(effecterId) + sizeof(compEffecterCnt) + 231 sizeof(set_effecter_state_field))) 232 { 233 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 234 } 235 236 int rc = decode_set_state_effecter_states_req(request, payloadLength, 237 &effecterId, &compEffecterCnt, 238 stateField.data()); 239 240 if (rc != PLDM_SUCCESS) 241 { 242 return CmdHandler::ccOnlyResponse(request, rc); 243 } 244 245 stateField.resize(compEffecterCnt); 246 const pldm::utils::DBusHandler dBusIntf; 247 rc = platform_state_effecter::setStateEffecterStatesHandler< 248 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 249 stateField); 250 if (rc != PLDM_SUCCESS) 251 { 252 return CmdHandler::ccOnlyResponse(request, rc); 253 } 254 255 rc = encode_set_state_effecter_states_resp(request->hdr.instance_id, rc, 256 responsePtr); 257 if (rc != PLDM_SUCCESS) 258 { 259 return ccOnlyResponse(request, rc); 260 } 261 262 return response; 263 } 264 265 Response Handler::platformEventMessage(const pldm_msg* request, 266 size_t payloadLength) 267 { 268 uint8_t formatVersion{}; 269 uint8_t tid{}; 270 uint8_t eventClass{}; 271 size_t offset{}; 272 273 auto rc = decode_platform_event_message_req( 274 request, payloadLength, &formatVersion, &tid, &eventClass, &offset); 275 if (rc != PLDM_SUCCESS) 276 { 277 return CmdHandler::ccOnlyResponse(request, rc); 278 } 279 280 try 281 { 282 const auto& handlers = eventHandlers.at(eventClass); 283 for (const auto& handler : handlers) 284 { 285 auto rc = 286 handler(request, payloadLength, formatVersion, tid, offset); 287 if (rc != PLDM_SUCCESS) 288 { 289 return CmdHandler::ccOnlyResponse(request, rc); 290 } 291 } 292 } 293 catch (const std::out_of_range& e) 294 { 295 return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA); 296 } 297 298 Response response( 299 sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES, 0); 300 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 301 302 rc = encode_platform_event_message_resp(request->hdr.instance_id, rc, 303 PLDM_EVENT_NO_LOGGING, responsePtr); 304 if (rc != PLDM_SUCCESS) 305 { 306 return ccOnlyResponse(request, rc); 307 } 308 309 return response; 310 } 311 312 int Handler::sensorEvent(const pldm_msg* request, size_t payloadLength, 313 uint8_t /*formatVersion*/, uint8_t tid, 314 size_t eventDataOffset) 315 { 316 uint16_t sensorId{}; 317 uint8_t eventClass{}; 318 size_t eventClassDataOffset{}; 319 auto eventData = 320 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 321 auto eventDataSize = payloadLength - eventDataOffset; 322 323 auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId, 324 &eventClass, &eventClassDataOffset); 325 if (rc != PLDM_SUCCESS) 326 { 327 return rc; 328 } 329 330 auto eventClassData = reinterpret_cast<const uint8_t*>(request->payload) + 331 eventDataOffset + eventClassDataOffset; 332 auto eventClassDataSize = 333 payloadLength - eventDataOffset - eventClassDataOffset; 334 335 if (eventClass == PLDM_STATE_SENSOR_STATE) 336 { 337 uint8_t sensorOffset{}; 338 uint8_t eventState{}; 339 uint8_t previousEventState{}; 340 341 rc = decode_state_sensor_data(eventClassData, eventClassDataSize, 342 &sensorOffset, &eventState, 343 &previousEventState); 344 if (rc != PLDM_SUCCESS) 345 { 346 return PLDM_ERROR; 347 } 348 349 // Emitting state sensor event signal 350 emitStateSensorEventSignal(tid, sensorId, sensorOffset, eventState, 351 previousEventState); 352 353 // If there are no HOST PDR's, there is no further action 354 if (hostPDRHandler == NULL) 355 { 356 return PLDM_SUCCESS; 357 } 358 359 // Handle PLDM events for which PDR is available 360 SensorEntry sensorEntry{tid, sensorId}; 361 362 pldm::pdr::EntityInfo entityInfo{}; 363 pldm::pdr::CompositeSensorStates compositeSensorStates{}; 364 365 try 366 { 367 std::tie(entityInfo, compositeSensorStates) = 368 hostPDRHandler->lookupSensorInfo(sensorEntry); 369 } 370 catch (const std::out_of_range& e) 371 { 372 // If there is no mapping for tid, sensorId combination, try 373 // PLDM_TID_RESERVED, sensorId for terminus that is yet to 374 // implement TL PDR. 375 try 376 { 377 sensorEntry.terminusID = PLDM_TID_RESERVED; 378 std::tie(entityInfo, compositeSensorStates) = 379 hostPDRHandler->lookupSensorInfo(sensorEntry); 380 } 381 // If there is no mapping for events return PLDM_SUCCESS 382 catch (const std::out_of_range& e) 383 { 384 return PLDM_SUCCESS; 385 } 386 } 387 388 if (sensorOffset >= compositeSensorStates.size()) 389 { 390 return PLDM_ERROR_INVALID_DATA; 391 } 392 393 const auto& possibleStates = compositeSensorStates[sensorOffset]; 394 if (possibleStates.find(eventState) == possibleStates.end()) 395 { 396 return PLDM_ERROR_INVALID_DATA; 397 } 398 399 const auto& [containerId, entityType, entityInstance] = entityInfo; 400 events::StateSensorEntry stateSensorEntry{containerId, entityType, 401 entityInstance, sensorOffset}; 402 return hostPDRHandler->handleStateSensorEvent(stateSensorEntry, 403 eventState); 404 } 405 else 406 { 407 return PLDM_ERROR_INVALID_DATA; 408 } 409 410 return PLDM_SUCCESS; 411 } 412 413 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request, 414 size_t payloadLength, 415 uint8_t /*formatVersion*/, 416 uint8_t /*tid*/, size_t eventDataOffset) 417 { 418 uint8_t eventDataFormat{}; 419 uint8_t numberOfChangeRecords{}; 420 size_t dataOffset{}; 421 422 auto eventData = 423 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 424 auto eventDataSize = payloadLength - eventDataOffset; 425 426 auto rc = decode_pldm_pdr_repository_chg_event_data( 427 eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords, 428 &dataOffset); 429 if (rc != PLDM_SUCCESS) 430 { 431 return rc; 432 } 433 434 PDRRecordHandles pdrRecordHandles; 435 436 if (eventDataFormat == FORMAT_IS_PDR_TYPES) 437 { 438 return PLDM_ERROR_INVALID_DATA; 439 } 440 441 if (eventDataFormat == FORMAT_IS_PDR_HANDLES) 442 { 443 uint8_t eventDataOperation{}; 444 uint8_t numberOfChangeEntries{}; 445 446 auto changeRecordData = eventData + dataOffset; 447 auto changeRecordDataSize = eventDataSize - dataOffset; 448 449 while (changeRecordDataSize) 450 { 451 rc = decode_pldm_pdr_repository_change_record_data( 452 changeRecordData, changeRecordDataSize, &eventDataOperation, 453 &numberOfChangeEntries, &dataOffset); 454 455 if (rc != PLDM_SUCCESS) 456 { 457 return rc; 458 } 459 460 if (eventDataOperation == PLDM_RECORDS_ADDED) 461 { 462 rc = getPDRRecordHandles( 463 reinterpret_cast<const ChangeEntry*>(changeRecordData + 464 dataOffset), 465 changeRecordDataSize - dataOffset, 466 static_cast<size_t>(numberOfChangeEntries), 467 pdrRecordHandles); 468 469 if (rc != PLDM_SUCCESS) 470 { 471 return rc; 472 } 473 } 474 475 changeRecordData += 476 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 477 changeRecordDataSize -= 478 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 479 } 480 } 481 if (hostPDRHandler) 482 { 483 hostPDRHandler->fetchPDR(std::move(pdrRecordHandles)); 484 } 485 486 return PLDM_SUCCESS; 487 } 488 489 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData, 490 size_t changeEntryDataSize, 491 size_t numberOfChangeEntries, 492 PDRRecordHandles& pdrRecordHandles) 493 { 494 if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry))) 495 { 496 return PLDM_ERROR_INVALID_DATA; 497 } 498 for (size_t i = 0; i < numberOfChangeEntries; i++) 499 { 500 pdrRecordHandles.push_back(changeEntryData[i]); 501 } 502 return PLDM_SUCCESS; 503 } 504 505 Response Handler::setNumericEffecterValue(const pldm_msg* request, 506 size_t payloadLength) 507 { 508 Response response(sizeof(pldm_msg_hdr) + 509 PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES); 510 uint16_t effecterId{}; 511 uint8_t effecterDataSize{}; 512 uint8_t effecterValue[4] = {}; 513 514 if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) + 515 sizeof(union_effecter_data_size)) || 516 (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1)) 517 { 518 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 519 } 520 521 int rc = decode_set_numeric_effecter_value_req( 522 request, payloadLength, &effecterId, &effecterDataSize, 523 reinterpret_cast<uint8_t*>(&effecterValue)); 524 525 if (rc == PLDM_SUCCESS) 526 { 527 const pldm::utils::DBusHandler dBusIntf; 528 rc = platform_numeric_effecter::setNumericEffecterValueHandler< 529 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 530 effecterDataSize, effecterValue, 531 sizeof(effecterValue)); 532 } 533 534 return ccOnlyResponse(request, rc); 535 } 536 537 void Handler::generateTerminusLocatorPDR(Repo& repo) 538 { 539 std::vector<uint8_t> pdrBuffer(sizeof(pldm_terminus_locator_pdr)); 540 541 auto pdr = reinterpret_cast<pldm_terminus_locator_pdr*>(pdrBuffer.data()); 542 543 pdr->hdr.record_handle = 0; 544 pdr->hdr.version = 1; 545 pdr->hdr.type = PLDM_TERMINUS_LOCATOR_PDR; 546 pdr->hdr.record_change_num = 0; 547 pdr->hdr.length = sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr); 548 pdr->terminus_handle = BmcPldmTerminusHandle; 549 pdr->validity = PLDM_TL_PDR_VALID; 550 pdr->tid = BmcTerminusId; 551 pdr->container_id = 0x0; 552 pdr->terminus_locator_type = PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID; 553 pdr->terminus_locator_value_size = 554 sizeof(pldm_terminus_locator_type_mctp_eid); 555 auto locatorValue = reinterpret_cast<pldm_terminus_locator_type_mctp_eid*>( 556 pdr->terminus_locator_value); 557 locatorValue->eid = BmcMctpEid; 558 559 PdrEntry pdrEntry{}; 560 pdrEntry.data = pdrBuffer.data(); 561 pdrEntry.size = pdrBuffer.size(); 562 repo.addRecord(pdrEntry); 563 } 564 565 Response Handler::getStateSensorReadings(const pldm_msg* request, 566 size_t payloadLength) 567 { 568 uint16_t sensorId{}; 569 bitfield8_t sensorRearm{}; 570 uint8_t reserved{}; 571 572 if (payloadLength != PLDM_GET_SENSOR_READING_REQ_BYTES) 573 { 574 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 575 } 576 577 int rc = decode_get_state_sensor_readings_req( 578 request, payloadLength, &sensorId, &sensorRearm, &reserved); 579 580 if (rc != PLDM_SUCCESS) 581 { 582 return ccOnlyResponse(request, rc); 583 } 584 585 // 0x01 to 0x08 586 uint8_t sensorRearmCout = getBitfieldCount(sensorRearm); 587 std::vector<get_sensor_state_field> stateField(sensorRearmCout); 588 uint8_t comSensorCnt{}; 589 const pldm::utils::DBusHandler dBusIntf; 590 rc = platform_state_sensor::getStateSensorReadingsHandler< 591 pldm::utils::DBusHandler, Handler>( 592 dBusIntf, *this, sensorId, sensorRearmCout, comSensorCnt, stateField); 593 594 if (rc != PLDM_SUCCESS) 595 { 596 return ccOnlyResponse(request, rc); 597 } 598 599 Response response(sizeof(pldm_msg_hdr) + 600 PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES + 601 sizeof(get_sensor_state_field) * comSensorCnt); 602 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 603 rc = encode_get_state_sensor_readings_resp(request->hdr.instance_id, rc, 604 comSensorCnt, stateField.data(), 605 responsePtr); 606 if (rc != PLDM_SUCCESS) 607 { 608 return ccOnlyResponse(request, rc); 609 } 610 611 return response; 612 } 613 614 } // namespace platform 615 } // namespace responder 616 } // namespace pldm 617