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