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 stateSensorHandler.eventAction(stateSensorEntry, eventState); 403 } 404 else 405 { 406 return PLDM_ERROR_INVALID_DATA; 407 } 408 409 return PLDM_SUCCESS; 410 } 411 412 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request, 413 size_t payloadLength, 414 uint8_t /*formatVersion*/, 415 uint8_t /*tid*/, size_t eventDataOffset) 416 { 417 uint8_t eventDataFormat{}; 418 uint8_t numberOfChangeRecords{}; 419 size_t dataOffset{}; 420 421 auto eventData = 422 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 423 auto eventDataSize = payloadLength - eventDataOffset; 424 425 auto rc = decode_pldm_pdr_repository_chg_event_data( 426 eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords, 427 &dataOffset); 428 if (rc != PLDM_SUCCESS) 429 { 430 return rc; 431 } 432 433 PDRRecordHandles pdrRecordHandles; 434 435 if (eventDataFormat == FORMAT_IS_PDR_TYPES) 436 { 437 return PLDM_ERROR_INVALID_DATA; 438 } 439 440 if (eventDataFormat == FORMAT_IS_PDR_HANDLES) 441 { 442 uint8_t eventDataOperation{}; 443 uint8_t numberOfChangeEntries{}; 444 445 auto changeRecordData = eventData + dataOffset; 446 auto changeRecordDataSize = eventDataSize - dataOffset; 447 448 while (changeRecordDataSize) 449 { 450 rc = decode_pldm_pdr_repository_change_record_data( 451 changeRecordData, changeRecordDataSize, &eventDataOperation, 452 &numberOfChangeEntries, &dataOffset); 453 454 if (rc != PLDM_SUCCESS) 455 { 456 return rc; 457 } 458 459 if (eventDataOperation == PLDM_RECORDS_ADDED) 460 { 461 rc = getPDRRecordHandles( 462 reinterpret_cast<const ChangeEntry*>(changeRecordData + 463 dataOffset), 464 changeRecordDataSize - dataOffset, 465 static_cast<size_t>(numberOfChangeEntries), 466 pdrRecordHandles); 467 468 if (rc != PLDM_SUCCESS) 469 { 470 return rc; 471 } 472 } 473 474 changeRecordData += 475 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 476 changeRecordDataSize -= 477 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 478 } 479 } 480 if (hostPDRHandler) 481 { 482 hostPDRHandler->fetchPDR(std::move(pdrRecordHandles)); 483 } 484 485 return PLDM_SUCCESS; 486 } 487 488 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData, 489 size_t changeEntryDataSize, 490 size_t numberOfChangeEntries, 491 PDRRecordHandles& pdrRecordHandles) 492 { 493 if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry))) 494 { 495 return PLDM_ERROR_INVALID_DATA; 496 } 497 for (size_t i = 0; i < numberOfChangeEntries; i++) 498 { 499 pdrRecordHandles.push_back(changeEntryData[i]); 500 } 501 return PLDM_SUCCESS; 502 } 503 504 Response Handler::setNumericEffecterValue(const pldm_msg* request, 505 size_t payloadLength) 506 { 507 Response response(sizeof(pldm_msg_hdr) + 508 PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES); 509 uint16_t effecterId{}; 510 uint8_t effecterDataSize{}; 511 uint8_t effecterValue[4] = {}; 512 513 if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) + 514 sizeof(union_effecter_data_size)) || 515 (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1)) 516 { 517 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 518 } 519 520 int rc = decode_set_numeric_effecter_value_req( 521 request, payloadLength, &effecterId, &effecterDataSize, 522 reinterpret_cast<uint8_t*>(&effecterValue)); 523 524 if (rc == PLDM_SUCCESS) 525 { 526 const pldm::utils::DBusHandler dBusIntf; 527 rc = platform_numeric_effecter::setNumericEffecterValueHandler< 528 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 529 effecterDataSize, effecterValue, 530 sizeof(effecterValue)); 531 } 532 533 return ccOnlyResponse(request, rc); 534 } 535 536 void Handler::generateTerminusLocatorPDR(Repo& repo) 537 { 538 std::vector<uint8_t> pdrBuffer(sizeof(pldm_terminus_locator_pdr)); 539 540 auto pdr = reinterpret_cast<pldm_terminus_locator_pdr*>(pdrBuffer.data()); 541 542 pdr->hdr.record_handle = 0; 543 pdr->hdr.version = 1; 544 pdr->hdr.type = PLDM_TERMINUS_LOCATOR_PDR; 545 pdr->hdr.record_change_num = 0; 546 pdr->hdr.length = sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr); 547 pdr->terminus_handle = BmcPldmTerminusHandle; 548 pdr->validity = PLDM_TL_PDR_VALID; 549 pdr->tid = BmcTerminusId; 550 pdr->container_id = 0x0; 551 pdr->terminus_locator_type = PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID; 552 pdr->terminus_locator_value_size = 553 sizeof(pldm_terminus_locator_type_mctp_eid); 554 auto locatorValue = reinterpret_cast<pldm_terminus_locator_type_mctp_eid*>( 555 pdr->terminus_locator_value); 556 locatorValue->eid = BmcMctpEid; 557 558 PdrEntry pdrEntry{}; 559 pdrEntry.data = pdrBuffer.data(); 560 pdrEntry.size = pdrBuffer.size(); 561 repo.addRecord(pdrEntry); 562 } 563 564 Response Handler::getStateSensorReadings(const pldm_msg* request, 565 size_t payloadLength) 566 { 567 uint16_t sensorId{}; 568 bitfield8_t sensorRearm{}; 569 uint8_t reserved{}; 570 571 if (payloadLength != PLDM_GET_SENSOR_READING_REQ_BYTES) 572 { 573 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 574 } 575 576 int rc = decode_get_state_sensor_readings_req( 577 request, payloadLength, &sensorId, &sensorRearm, &reserved); 578 579 if (rc != PLDM_SUCCESS) 580 { 581 return ccOnlyResponse(request, rc); 582 } 583 584 // 0x01 to 0x08 585 uint8_t sensorRearmCout = getBitfieldCount(sensorRearm); 586 std::vector<get_sensor_state_field> stateField(sensorRearmCout); 587 uint8_t comSensorCnt{}; 588 const pldm::utils::DBusHandler dBusIntf; 589 rc = platform_state_sensor::getStateSensorReadingsHandler< 590 pldm::utils::DBusHandler, Handler>( 591 dBusIntf, *this, sensorId, sensorRearmCout, comSensorCnt, stateField); 592 593 if (rc != PLDM_SUCCESS) 594 { 595 return ccOnlyResponse(request, rc); 596 } 597 598 Response response(sizeof(pldm_msg_hdr) + 599 PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES + 600 sizeof(get_sensor_state_field) * comSensorCnt); 601 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 602 rc = encode_get_state_sensor_readings_resp(request->hdr.instance_id, rc, 603 comSensorCnt, stateField.data(), 604 responsePtr); 605 if (rc != PLDM_SUCCESS) 606 { 607 return ccOnlyResponse(request, rc); 608 } 609 610 return response; 611 } 612 613 } // namespace platform 614 } // namespace responder 615 } // namespace pldm 616