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