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 "platform_numeric_effecter.hpp" 10 #include "platform_state_effecter.hpp" 11 12 namespace pldm 13 { 14 namespace responder 15 { 16 namespace platform 17 { 18 19 using InternalFailure = 20 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 21 22 static const Json empty{}; 23 24 using EventEntryMap = std::map<EventEntry, DBusInfo>; 25 26 const EventEntryMap eventEntryMap = { 27 { 28 0x01010007, // SensorID for VMI Port 0 ipv4 = 7, SensorOffset for the 29 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 1 30 // (Valid Configuration) 31 {"/xyz/openbmc_project/network/hypervisor/eth0/ipv4/addr0", 32 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", true}, 33 }, 34 { 35 0x02010007, // SensorID for VMI Port 0 ipv4 = 7, SensorOffset for the 36 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 2 37 // (Invalid Configuration) 38 {"/xyz/openbmc_project/network/hypervisor/eth0/ipv4/addr0", 39 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", false}, 40 }, 41 { 42 0x01010008, // SensorID for VMI Port 1 ipv4 = 8, SensorOffset for the 43 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 1 44 // (Valid Configuration) 45 {"/xyz/openbmc_project/network/hypervisor/eth1/ipv4/addr0", 46 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", true}, 47 }, 48 { 49 0x02010008, // SensorID for VMI Port 1 ipv4 = 8, SensorOffset for the 50 // State Set ID 15 = 1 & PLDM State Set Enumeration List = 2 51 // (Invalid Configuration) 52 {"/xyz/openbmc_project/network/hypervisor/eth1/ipv4/addr0", 53 "xyz.openbmc_project.Object.Enable", "Enabled", "bool", false}, 54 }}; 55 56 void Handler::addDbusObjMaps( 57 uint16_t effecterId, 58 std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps> dbusObj) 59 { 60 dbusObjMaps.emplace(effecterId, dbusObj); 61 } 62 63 const std::tuple<pdr_utils::DbusMappings, pdr_utils::DbusValMaps>& 64 Handler::getDbusObjMaps(uint16_t effecterId) const 65 { 66 return dbusObjMaps.at(effecterId); 67 } 68 69 void Handler::generate(const pldm::utils::DBusHandler& dBusIntf, 70 const std::string& dir, Repo& repo) 71 { 72 if (!fs::exists(dir)) 73 { 74 return; 75 } 76 77 // A map of PDR type to a lambda that handles creation of that PDR type. 78 // The lambda essentially would parse the platform specific PDR JSONs to 79 // generate the PDR structures. This function iterates through the map to 80 // invoke all lambdas, so that all PDR types can be created. 81 82 const std::map<Type, generatePDR> generateHandlers = { 83 {PLDM_STATE_EFFECTER_PDR, 84 [this](const DBusHandler& dBusIntf, const auto& json, 85 RepoInterface& repo) { 86 pdr_state_effecter::generateStateEffecterPDR< 87 pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, 88 repo); 89 }}, 90 {PLDM_NUMERIC_EFFECTER_PDR, 91 [this](const DBusHandler& dBusIntf, const auto& json, 92 RepoInterface& repo) { 93 pdr_numeric_effecter::generateNumericEffecterPDR< 94 pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, 95 repo); 96 }}}; 97 98 Type pdrType{}; 99 for (const auto& dirEntry : fs::directory_iterator(dir)) 100 { 101 try 102 { 103 auto json = readJson(dirEntry.path().string()); 104 if (!json.empty()) 105 { 106 auto effecterPDRs = json.value("effecterPDRs", empty); 107 for (const auto& effecter : effecterPDRs) 108 { 109 pdrType = effecter.value("pdrType", 0); 110 generateHandlers.at(pdrType)(dBusIntf, effecter, 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 if (!pdrCreated) 140 { 141 generateTerminusLocatorPDR(pdrRepo); 142 generate(*dBusIntf, pdrJsonsDir, pdrRepo); 143 pdrCreated = true; 144 } 145 146 // Build FRU table if not built, since entity association PDR's are built 147 // when the FRU table is constructed. 148 if (fruHandler) 149 { 150 fruHandler->buildFRUTable(); 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 // Handle PLDM events for which PDR is not available, setSensorEventData 354 // will return PLDM_ERROR_INVALID_DATA if the sensorID is not found in 355 // the hardcoded sensor list. 356 rc = setSensorEventData(sensorId, sensorOffset, eventState); 357 if (rc != PLDM_ERROR_INVALID_DATA) 358 { 359 return rc; 360 } 361 362 // If there are no HOST PDR's, there is no further action 363 if (hostPDRHandler == NULL) 364 { 365 return PLDM_SUCCESS; 366 } 367 368 // Handle PLDM events for which PDR is available 369 SensorEntry sensorEntry{tid, sensorId}; 370 try 371 { 372 const auto& [entityInfo, compositeSensorStates] = 373 hostPDRHandler->lookupSensorInfo(sensorEntry); 374 if (sensorOffset >= compositeSensorStates.size()) 375 { 376 return PLDM_ERROR_INVALID_DATA; 377 } 378 379 const auto& possibleStates = compositeSensorStates[sensorOffset]; 380 if (possibleStates.find(eventState) == possibleStates.end()) 381 { 382 return PLDM_ERROR_INVALID_DATA; 383 } 384 385 const auto& [containerId, entityType, entityInstance] = entityInfo; 386 events::StateSensorEntry stateSensorEntry{ 387 containerId, entityType, entityInstance, sensorOffset}; 388 return stateSensorHandler.eventAction(stateSensorEntry, eventState); 389 } 390 // If there is no mapping for events return PLDM_SUCCESS 391 catch (const std::out_of_range& e) 392 { 393 return PLDM_SUCCESS; 394 } 395 } 396 else 397 { 398 return PLDM_ERROR_INVALID_DATA; 399 } 400 401 return PLDM_SUCCESS; 402 } 403 404 int Handler::setSensorEventData(uint16_t sensorId, uint8_t sensorOffset, 405 uint8_t eventState) 406 { 407 EventEntry eventEntry = ((static_cast<uint32_t>(eventState)) << 24) + 408 ((static_cast<uint32_t>(sensorOffset)) << 16) + 409 sensorId; 410 auto iter = eventEntryMap.find(eventEntry); 411 if (iter == eventEntryMap.end()) 412 { 413 return PLDM_ERROR_INVALID_DATA; 414 } 415 416 const auto& dBusInfo = iter->second; 417 try 418 { 419 pldm::utils::DBusMapping dbusMapping{ 420 dBusInfo.dBusValues.objectPath, dBusInfo.dBusValues.interface, 421 dBusInfo.dBusValues.propertyName, dBusInfo.dBusValues.propertyType}; 422 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, 423 dBusInfo.dBusPropertyValue); 424 } 425 catch (std::exception& e) 426 { 427 std::cerr 428 << "Error Setting dbus property,SensorID=" << eventEntry 429 << "DBusInfo=" << dBusInfo.dBusValues.objectPath 430 << dBusInfo.dBusValues.interface << dBusInfo.dBusValues.propertyName 431 << "ERROR=" << e.what() << "\n"; 432 return PLDM_ERROR; 433 } 434 return PLDM_SUCCESS; 435 } 436 437 int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request, 438 size_t payloadLength, 439 uint8_t /*formatVersion*/, 440 uint8_t /*tid*/, size_t eventDataOffset) 441 { 442 uint8_t eventDataFormat{}; 443 uint8_t numberOfChangeRecords{}; 444 size_t dataOffset{}; 445 446 auto eventData = 447 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset; 448 auto eventDataSize = payloadLength - eventDataOffset; 449 450 auto rc = decode_pldm_pdr_repository_chg_event_data( 451 eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords, 452 &dataOffset); 453 if (rc != PLDM_SUCCESS) 454 { 455 return rc; 456 } 457 458 PDRRecordHandles pdrRecordHandles; 459 460 if (eventDataFormat == FORMAT_IS_PDR_TYPES) 461 { 462 return PLDM_ERROR_INVALID_DATA; 463 } 464 465 if (eventDataFormat == FORMAT_IS_PDR_HANDLES) 466 { 467 uint8_t eventDataOperation{}; 468 uint8_t numberOfChangeEntries{}; 469 470 auto changeRecordData = eventData + dataOffset; 471 auto changeRecordDataSize = eventDataSize - dataOffset; 472 473 while (changeRecordDataSize) 474 { 475 rc = decode_pldm_pdr_repository_change_record_data( 476 changeRecordData, changeRecordDataSize, &eventDataOperation, 477 &numberOfChangeEntries, &dataOffset); 478 479 if (rc != PLDM_SUCCESS) 480 { 481 return rc; 482 } 483 484 if (eventDataOperation == PLDM_RECORDS_ADDED) 485 { 486 rc = getPDRRecordHandles( 487 reinterpret_cast<const ChangeEntry*>(changeRecordData + 488 dataOffset), 489 changeRecordDataSize - dataOffset, 490 static_cast<size_t>(numberOfChangeEntries), 491 pdrRecordHandles); 492 493 if (rc != PLDM_SUCCESS) 494 { 495 return rc; 496 } 497 } 498 499 changeRecordData += 500 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 501 changeRecordDataSize -= 502 dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry)); 503 } 504 } 505 if (hostPDRHandler) 506 { 507 hostPDRHandler->fetchPDR(std::move(pdrRecordHandles)); 508 } 509 510 return PLDM_SUCCESS; 511 } 512 513 int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData, 514 size_t changeEntryDataSize, 515 size_t numberOfChangeEntries, 516 PDRRecordHandles& pdrRecordHandles) 517 { 518 if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry))) 519 { 520 return PLDM_ERROR_INVALID_DATA; 521 } 522 for (size_t i = 0; i < numberOfChangeEntries; i++) 523 { 524 pdrRecordHandles.push_back(changeEntryData[i]); 525 } 526 return PLDM_SUCCESS; 527 } 528 529 Response Handler::setNumericEffecterValue(const pldm_msg* request, 530 size_t payloadLength) 531 { 532 Response response(sizeof(pldm_msg_hdr) + 533 PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES); 534 uint16_t effecterId{}; 535 uint8_t effecterDataSize{}; 536 uint8_t effecterValue[4] = {}; 537 538 if ((payloadLength > sizeof(effecterId) + sizeof(effecterDataSize) + 539 sizeof(union_effecter_data_size)) || 540 (payloadLength < sizeof(effecterId) + sizeof(effecterDataSize) + 1)) 541 { 542 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); 543 } 544 545 int rc = decode_set_numeric_effecter_value_req( 546 request, payloadLength, &effecterId, &effecterDataSize, 547 reinterpret_cast<uint8_t*>(&effecterValue)); 548 549 if (rc == PLDM_SUCCESS) 550 { 551 const pldm::utils::DBusHandler dBusIntf; 552 rc = platform_numeric_effecter::setNumericEffecterValueHandler< 553 pldm::utils::DBusHandler, Handler>(dBusIntf, *this, effecterId, 554 effecterDataSize, effecterValue, 555 sizeof(effecterValue)); 556 } 557 558 return ccOnlyResponse(request, rc); 559 } 560 561 void Handler::generateTerminusLocatorPDR(Repo& repo) 562 { 563 std::vector<uint8_t> pdrBuffer(sizeof(pldm_terminus_locator_pdr)); 564 565 auto pdr = reinterpret_cast<pldm_terminus_locator_pdr*>(pdrBuffer.data()); 566 567 pdr->hdr.record_handle = 0; 568 pdr->hdr.version = 1; 569 pdr->hdr.type = PLDM_TERMINUS_LOCATOR_PDR; 570 pdr->hdr.record_change_num = 0; 571 pdr->hdr.length = sizeof(pldm_terminus_locator_pdr) - sizeof(pldm_pdr_hdr); 572 pdr->terminus_handle = BmcPldmTerminusHandle; 573 pdr->validity = PLDM_TL_PDR_VALID; 574 pdr->tid = BmcTerminusId; 575 pdr->container_id = 0x0; 576 pdr->terminus_locator_type = PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID; 577 pdr->terminus_locator_value_size = 578 sizeof(pldm_terminus_locator_type_mctp_eid); 579 auto locatorValue = reinterpret_cast<pldm_terminus_locator_type_mctp_eid*>( 580 pdr->terminus_locator_value); 581 locatorValue->eid = BmcMctpEid; 582 583 PdrEntry pdrEntry{}; 584 pdrEntry.data = pdrBuffer.data(); 585 pdrEntry.size = pdrBuffer.size(); 586 repo.addRecord(pdrEntry); 587 } 588 } // namespace platform 589 } // namespace responder 590 } // namespace pldm 591