1 #include "config.h" 2 3 #include "utils.hpp" 4 5 #include <libpldm/pdr.h> 6 #include <libpldm/pldm_types.h> 7 8 #include <phosphor-logging/lg2.hpp> 9 #include <xyz/openbmc_project/Common/error.hpp> 10 11 #include <algorithm> 12 #include <array> 13 #include <cctype> 14 #include <ctime> 15 #include <fstream> 16 #include <iostream> 17 #include <map> 18 #include <stdexcept> 19 #include <string> 20 #include <vector> 21 22 PHOSPHOR_LOG2_USING; 23 24 namespace pldm 25 { 26 namespace utils 27 { 28 constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper"; 29 constexpr auto mapperPath = "/xyz/openbmc_project/object_mapper"; 30 constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper"; 31 32 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t /*tid*/, 33 uint16_t entityID, 34 uint16_t stateSetId, 35 const pldm_pdr* repo) 36 { 37 uint8_t* outData = nullptr; 38 uint32_t size{}; 39 const pldm_pdr_record* record{}; 40 std::vector<std::vector<uint8_t>> pdrs; 41 try 42 { 43 do 44 { 45 record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_EFFECTER_PDR, 46 record, &outData, &size); 47 if (record) 48 { 49 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(outData); 50 auto compositeEffecterCount = pdr->composite_effecter_count; 51 auto possible_states_start = pdr->possible_states; 52 53 for (auto effecters = 0x00; effecters < compositeEffecterCount; 54 effecters++) 55 { 56 auto possibleStates = 57 reinterpret_cast<state_effecter_possible_states*>( 58 possible_states_start); 59 auto setId = possibleStates->state_set_id; 60 auto possibleStateSize = 61 possibleStates->possible_states_size; 62 63 if (pdr->entity_type == entityID && setId == stateSetId) 64 { 65 std::vector<uint8_t> effecter_pdr(&outData[0], 66 &outData[size]); 67 pdrs.emplace_back(std::move(effecter_pdr)); 68 break; 69 } 70 possible_states_start += possibleStateSize + sizeof(setId) + 71 sizeof(possibleStateSize); 72 } 73 } 74 75 } while (record); 76 } 77 catch (const std::exception& e) 78 { 79 error(" Failed to obtain a record. ERROR = {ERR_EXCEP}", "ERR_EXCEP", 80 e.what()); 81 } 82 83 return pdrs; 84 } 85 86 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t /*tid*/, 87 uint16_t entityID, 88 uint16_t stateSetId, 89 const pldm_pdr* repo) 90 { 91 uint8_t* outData = nullptr; 92 uint32_t size{}; 93 const pldm_pdr_record* record{}; 94 std::vector<std::vector<uint8_t>> pdrs; 95 try 96 { 97 do 98 { 99 record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_SENSOR_PDR, 100 record, &outData, &size); 101 if (record) 102 { 103 auto pdr = reinterpret_cast<pldm_state_sensor_pdr*>(outData); 104 auto compositeSensorCount = pdr->composite_sensor_count; 105 auto possible_states_start = pdr->possible_states; 106 107 for (auto sensors = 0x00; sensors < compositeSensorCount; 108 sensors++) 109 { 110 auto possibleStates = 111 reinterpret_cast<state_sensor_possible_states*>( 112 possible_states_start); 113 auto setId = possibleStates->state_set_id; 114 auto possibleStateSize = 115 possibleStates->possible_states_size; 116 117 if (pdr->entity_type == entityID && setId == stateSetId) 118 { 119 std::vector<uint8_t> sensor_pdr(&outData[0], 120 &outData[size]); 121 pdrs.emplace_back(std::move(sensor_pdr)); 122 break; 123 } 124 possible_states_start += possibleStateSize + sizeof(setId) + 125 sizeof(possibleStateSize); 126 } 127 } 128 129 } while (record); 130 } 131 catch (const std::exception& e) 132 { 133 error(" Failed to obtain a record. ERROR = {ERR_EXCEP}", "ERR_EXCEP", 134 e.what()); 135 } 136 137 return pdrs; 138 } 139 140 uint8_t readHostEID() 141 { 142 uint8_t eid{}; 143 std::ifstream eidFile{HOST_EID_PATH}; 144 if (!eidFile.good()) 145 { 146 error("Could not open host EID file: {HOST_PATH}", "HOST_PATH", 147 static_cast<std::string>(HOST_EID_PATH)); 148 } 149 else 150 { 151 std::string eidStr; 152 eidFile >> eidStr; 153 if (!eidStr.empty()) 154 { 155 eid = atoi(eidStr.c_str()); 156 } 157 else 158 { 159 error("Host EID file was empty"); 160 } 161 } 162 163 return eid; 164 } 165 166 uint8_t getNumPadBytes(uint32_t data) 167 { 168 uint8_t pad; 169 pad = ((data % 4) ? (4 - data % 4) : 0); 170 return pad; 171 } // end getNumPadBytes 172 173 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day, 174 uint8_t* hour, uint8_t* min, uint8_t* sec) 175 { 176 constexpr uint64_t max_data = 29991231115959; 177 constexpr uint64_t min_data = 19700101000000; 178 if (data < min_data || data > max_data) 179 { 180 return false; 181 } 182 183 *year = data / 10000000000; 184 data = data % 10000000000; 185 *month = data / 100000000; 186 data = data % 100000000; 187 *day = data / 1000000; 188 data = data % 1000000; 189 *hour = data / 10000; 190 data = data % 10000; 191 *min = data / 100; 192 *sec = data % 100; 193 194 return true; 195 } 196 197 std::optional<std::vector<set_effecter_state_field>> 198 parseEffecterData(const std::vector<uint8_t>& effecterData, 199 uint8_t effecterCount) 200 { 201 std::vector<set_effecter_state_field> stateField; 202 203 if (effecterData.size() != effecterCount * 2) 204 { 205 return std::nullopt; 206 } 207 208 for (uint8_t i = 0; i < effecterCount; ++i) 209 { 210 uint8_t set_request = effecterData[i * 2] == PLDM_REQUEST_SET 211 ? PLDM_REQUEST_SET 212 : PLDM_NO_CHANGE; 213 set_effecter_state_field filed{set_request, effecterData[i * 2 + 1]}; 214 stateField.emplace_back(std::move(filed)); 215 } 216 217 return std::make_optional(std::move(stateField)); 218 } 219 220 std::string DBusHandler::getService(const char* path, 221 const char* interface) const 222 { 223 using DbusInterfaceList = std::vector<std::string>; 224 std::map<std::string, std::vector<std::string>> mapperResponse; 225 auto& bus = DBusHandler::getBus(); 226 227 auto mapper = bus.new_method_call(mapperBusName, mapperPath, 228 mapperInterface, "GetObject"); 229 mapper.append(path, DbusInterfaceList({interface})); 230 231 auto mapperResponseMsg = bus.call( 232 mapper, 233 std::chrono::duration_cast<microsec>(sec(DBUS_TIMEOUT)).count()); 234 mapperResponseMsg.read(mapperResponse); 235 return mapperResponse.begin()->first; 236 } 237 238 GetSubTreeResponse 239 DBusHandler::getSubtree(const std::string& searchPath, int depth, 240 const std::vector<std::string>& ifaceList) const 241 { 242 auto& bus = pldm::utils::DBusHandler::getBus(); 243 auto method = bus.new_method_call(mapperBusName, mapperPath, 244 mapperInterface, "GetSubTree"); 245 method.append(searchPath, depth, ifaceList); 246 auto reply = bus.call( 247 method, 248 std::chrono::duration_cast<microsec>(sec(DBUS_TIMEOUT)).count()); 249 GetSubTreeResponse response; 250 reply.read(response); 251 return response; 252 } 253 254 void reportError(const char* errorMsg) 255 { 256 static constexpr auto logObjPath = "/xyz/openbmc_project/logging"; 257 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create"; 258 259 auto& bus = pldm::utils::DBusHandler::getBus(); 260 261 try 262 { 263 auto service = DBusHandler().getService(logObjPath, logInterface); 264 using namespace sdbusplus::xyz::openbmc_project::Logging::server; 265 auto severity = 266 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 267 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 268 Error); 269 auto method = bus.new_method_call(service.c_str(), logObjPath, 270 logInterface, "Create"); 271 std::map<std::string, std::string> addlData{}; 272 method.append(errorMsg, severity, addlData); 273 bus.call_noreply(method); 274 } 275 catch (const std::exception& e) 276 { 277 error( 278 "failed to make a d-bus call to create error log, ERROR={ERR_EXCEP}", 279 "ERR_EXCEP", e.what()); 280 } 281 } 282 283 void DBusHandler::setDbusProperty(const DBusMapping& dBusMap, 284 const PropertyValue& value) const 285 { 286 auto setDbusValue = [&dBusMap, this](const auto& variant) { 287 auto& bus = getBus(); 288 auto service = getService(dBusMap.objectPath.c_str(), 289 dBusMap.interface.c_str()); 290 auto method = bus.new_method_call( 291 service.c_str(), dBusMap.objectPath.c_str(), dbusProperties, "Set"); 292 method.append(dBusMap.interface.c_str(), dBusMap.propertyName.c_str(), 293 variant); 294 bus.call_noreply(method); 295 }; 296 297 if (dBusMap.propertyType == "uint8_t") 298 { 299 std::variant<uint8_t> v = std::get<uint8_t>(value); 300 setDbusValue(v); 301 } 302 else if (dBusMap.propertyType == "bool") 303 { 304 std::variant<bool> v = std::get<bool>(value); 305 setDbusValue(v); 306 } 307 else if (dBusMap.propertyType == "int16_t") 308 { 309 std::variant<int16_t> v = std::get<int16_t>(value); 310 setDbusValue(v); 311 } 312 else if (dBusMap.propertyType == "uint16_t") 313 { 314 std::variant<uint16_t> v = std::get<uint16_t>(value); 315 setDbusValue(v); 316 } 317 else if (dBusMap.propertyType == "int32_t") 318 { 319 std::variant<int32_t> v = std::get<int32_t>(value); 320 setDbusValue(v); 321 } 322 else if (dBusMap.propertyType == "uint32_t") 323 { 324 std::variant<uint32_t> v = std::get<uint32_t>(value); 325 setDbusValue(v); 326 } 327 else if (dBusMap.propertyType == "int64_t") 328 { 329 std::variant<int64_t> v = std::get<int64_t>(value); 330 setDbusValue(v); 331 } 332 else if (dBusMap.propertyType == "uint64_t") 333 { 334 std::variant<uint64_t> v = std::get<uint64_t>(value); 335 setDbusValue(v); 336 } 337 else if (dBusMap.propertyType == "double") 338 { 339 std::variant<double> v = std::get<double>(value); 340 setDbusValue(v); 341 } 342 else if (dBusMap.propertyType == "string") 343 { 344 std::variant<std::string> v = std::get<std::string>(value); 345 setDbusValue(v); 346 } 347 else 348 { 349 throw std::invalid_argument("UnSpported Dbus Type"); 350 } 351 } 352 353 PropertyValue DBusHandler::getDbusPropertyVariant( 354 const char* objPath, const char* dbusProp, const char* dbusInterface) const 355 { 356 auto& bus = DBusHandler::getBus(); 357 auto service = getService(objPath, dbusInterface); 358 auto method = bus.new_method_call(service.c_str(), objPath, dbusProperties, 359 "Get"); 360 method.append(dbusInterface, dbusProp); 361 PropertyValue value{}; 362 auto reply = bus.call( 363 method, 364 std::chrono::duration_cast<microsec>(sec(DBUS_TIMEOUT)).count()); 365 reply.read(value); 366 return value; 367 } 368 369 PropertyValue jsonEntryToDbusVal(std::string_view type, 370 const nlohmann::json& value) 371 { 372 PropertyValue propValue{}; 373 if (type == "uint8_t") 374 { 375 propValue = static_cast<uint8_t>(value); 376 } 377 else if (type == "uint16_t") 378 { 379 propValue = static_cast<uint16_t>(value); 380 } 381 else if (type == "uint32_t") 382 { 383 propValue = static_cast<uint32_t>(value); 384 } 385 else if (type == "uint64_t") 386 { 387 propValue = static_cast<uint64_t>(value); 388 } 389 else if (type == "int16_t") 390 { 391 propValue = static_cast<int16_t>(value); 392 } 393 else if (type == "int32_t") 394 { 395 propValue = static_cast<int32_t>(value); 396 } 397 else if (type == "int64_t") 398 { 399 propValue = static_cast<int64_t>(value); 400 } 401 else if (type == "bool") 402 { 403 propValue = static_cast<bool>(value); 404 } 405 else if (type == "double") 406 { 407 propValue = static_cast<double>(value); 408 } 409 else if (type == "string") 410 { 411 propValue = static_cast<std::string>(value); 412 } 413 else 414 { 415 error("Unknown D-Bus property type, TYPE={OTHER_TYPE}", "OTHER_TYPE", 416 type); 417 } 418 419 return propValue; 420 } 421 422 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType, 423 uint16_t entityInstance, uint16_t containerId, 424 uint16_t stateSetId, bool localOrRemote) 425 { 426 uint8_t* pdrData = nullptr; 427 uint32_t pdrSize{}; 428 const pldm_pdr_record* record{}; 429 do 430 { 431 record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR, 432 record, &pdrData, &pdrSize); 433 if (record && (localOrRemote ^ pldm_pdr_record_is_remote(record))) 434 { 435 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrData); 436 auto compositeEffecterCount = pdr->composite_effecter_count; 437 auto possible_states_start = pdr->possible_states; 438 439 for (auto effecters = 0x00; effecters < compositeEffecterCount; 440 effecters++) 441 { 442 auto possibleStates = 443 reinterpret_cast<state_effecter_possible_states*>( 444 possible_states_start); 445 auto setId = possibleStates->state_set_id; 446 auto possibleStateSize = possibleStates->possible_states_size; 447 448 if (entityType == pdr->entity_type && 449 entityInstance == pdr->entity_instance && 450 containerId == pdr->container_id && stateSetId == setId) 451 { 452 return pdr->effecter_id; 453 } 454 possible_states_start += possibleStateSize + sizeof(setId) + 455 sizeof(possibleStateSize); 456 } 457 } 458 } while (record); 459 460 return PLDM_INVALID_EFFECTER_ID; 461 } 462 463 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId, 464 uint8_t sensorOffset, uint8_t eventState, 465 uint8_t previousEventState) 466 { 467 try 468 { 469 auto& bus = DBusHandler::getBus(); 470 auto msg = bus.new_signal("/xyz/openbmc_project/pldm", 471 "xyz.openbmc_project.PLDM.Event", 472 "StateSensorEvent"); 473 msg.append(tid, sensorId, sensorOffset, eventState, previousEventState); 474 475 msg.signal_send(); 476 } 477 catch (const std::exception& e) 478 { 479 error("Error emitting pldm event signal:ERROR={ERR_EXCEP}", "ERR_EXCEP", 480 e.what()); 481 return PLDM_ERROR; 482 } 483 484 return PLDM_SUCCESS; 485 } 486 487 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid, 488 uint16_t entityType, uint16_t entityInstance, 489 uint16_t containerId, uint16_t stateSetId) 490 { 491 auto pdrs = findStateSensorPDR(tid, entityType, stateSetId, pdrRepo); 492 for (auto pdr : pdrs) 493 { 494 auto sensorPdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data()); 495 auto compositeSensorCount = sensorPdr->composite_sensor_count; 496 auto possible_states_start = sensorPdr->possible_states; 497 498 for (auto sensors = 0x00; sensors < compositeSensorCount; sensors++) 499 { 500 auto possibleStates = 501 reinterpret_cast<state_sensor_possible_states*>( 502 possible_states_start); 503 auto setId = possibleStates->state_set_id; 504 auto possibleStateSize = possibleStates->possible_states_size; 505 if (entityType == sensorPdr->entity_type && 506 entityInstance == sensorPdr->entity_instance && 507 stateSetId == setId && containerId == sensorPdr->container_id) 508 { 509 return sensorPdr->sensor_id; 510 } 511 possible_states_start += possibleStateSize + sizeof(setId) + 512 sizeof(possibleStateSize); 513 } 514 } 515 return PLDM_INVALID_EFFECTER_ID; 516 } 517 518 void printBuffer(bool isTx, const std::vector<uint8_t>& buffer) 519 { 520 if (!buffer.empty()) 521 { 522 if (isTx) 523 { 524 std::cout << "Tx: "; 525 } 526 else 527 { 528 std::cout << "Rx: "; 529 } 530 std::ostringstream tempStream; 531 for (int byte : buffer) 532 { 533 tempStream << std::setfill('0') << std::setw(2) << std::hex << byte 534 << " "; 535 } 536 std::cout << tempStream.str() << std::endl; 537 } 538 } 539 540 std::string toString(const struct variable_field& var) 541 { 542 if (var.ptr == nullptr || !var.length) 543 { 544 return ""; 545 } 546 547 std::string str(reinterpret_cast<const char*>(var.ptr), var.length); 548 std::replace_if( 549 str.begin(), str.end(), [](const char& c) { return !isprint(c); }, ' '); 550 return str; 551 } 552 553 std::vector<std::string> split(std::string_view srcStr, std::string_view delim, 554 std::string_view trimStr) 555 { 556 std::vector<std::string> out; 557 size_t start; 558 size_t end = 0; 559 560 while ((start = srcStr.find_first_not_of(delim, end)) != std::string::npos) 561 { 562 end = srcStr.find(delim, start); 563 std::string_view dstStr = srcStr.substr(start, end - start); 564 if (!trimStr.empty()) 565 { 566 dstStr.remove_prefix(dstStr.find_first_not_of(trimStr)); 567 dstStr.remove_suffix(dstStr.size() - 1 - 568 dstStr.find_last_not_of(trimStr)); 569 } 570 571 if (!dstStr.empty()) 572 { 573 out.push_back(std::string(dstStr)); 574 } 575 } 576 577 return out; 578 } 579 580 std::string getCurrentSystemTime() 581 { 582 using namespace std::chrono; 583 const time_point<system_clock> tp = system_clock::now(); 584 std::time_t tt = system_clock::to_time_t(tp); 585 auto ms = duration_cast<microseconds>(tp.time_since_epoch()) - 586 duration_cast<seconds>(tp.time_since_epoch()); 587 588 std::stringstream ss; 589 ss << std::put_time(std::localtime(&tt), "%F %Z %T.") 590 << std::to_string(ms.count()); 591 return ss.str(); 592 } 593 594 bool checkForFruPresence(const std::string& objPath) 595 { 596 bool isPresent = false; 597 static constexpr auto presentInterface = 598 "xyz.openbmc_project.Inventory.Item"; 599 static constexpr auto presentProperty = "Present"; 600 try 601 { 602 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant( 603 objPath.c_str(), presentProperty, presentInterface); 604 isPresent = std::get<bool>(propVal); 605 } 606 catch (const sdbusplus::exception::SdBusError& e) 607 { 608 error( 609 "Failed to check for FRU presence for {OBJ_PATH} ERROR = {ERR_EXCEP}", 610 "OBJ_PATH", objPath.c_str(), "ERR_EXCEP", e.what()); 611 } 612 return isPresent; 613 } 614 615 } // namespace utils 616 } // namespace pldm 617