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(mapper); 232 mapperResponseMsg.read(mapperResponse); 233 return mapperResponse.begin()->first; 234 } 235 236 GetSubTreeResponse 237 DBusHandler::getSubtree(const std::string& searchPath, int depth, 238 const std::vector<std::string>& ifaceList) const 239 { 240 auto& bus = pldm::utils::DBusHandler::getBus(); 241 auto method = bus.new_method_call(mapperBusName, mapperPath, 242 mapperInterface, "GetSubTree"); 243 method.append(searchPath, depth, ifaceList); 244 auto reply = bus.call(method); 245 GetSubTreeResponse response; 246 reply.read(response); 247 return response; 248 } 249 250 void reportError(const char* errorMsg) 251 { 252 static constexpr auto logObjPath = "/xyz/openbmc_project/logging"; 253 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create"; 254 255 auto& bus = pldm::utils::DBusHandler::getBus(); 256 257 try 258 { 259 auto service = DBusHandler().getService(logObjPath, logInterface); 260 using namespace sdbusplus::xyz::openbmc_project::Logging::server; 261 auto severity = 262 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 263 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 264 Error); 265 auto method = bus.new_method_call(service.c_str(), logObjPath, 266 logInterface, "Create"); 267 std::map<std::string, std::string> addlData{}; 268 method.append(errorMsg, severity, addlData); 269 bus.call_noreply(method); 270 } 271 catch (const std::exception& e) 272 { 273 error( 274 "failed to make a d-bus call to create error log, ERROR={ERR_EXCEP}", 275 "ERR_EXCEP", e.what()); 276 } 277 } 278 279 void DBusHandler::setDbusProperty(const DBusMapping& dBusMap, 280 const PropertyValue& value) const 281 { 282 auto setDbusValue = [&dBusMap, this](const auto& variant) { 283 auto& bus = getBus(); 284 auto service = getService(dBusMap.objectPath.c_str(), 285 dBusMap.interface.c_str()); 286 auto method = bus.new_method_call( 287 service.c_str(), dBusMap.objectPath.c_str(), dbusProperties, "Set"); 288 method.append(dBusMap.interface.c_str(), dBusMap.propertyName.c_str(), 289 variant); 290 bus.call_noreply(method); 291 }; 292 293 if (dBusMap.propertyType == "uint8_t") 294 { 295 std::variant<uint8_t> v = std::get<uint8_t>(value); 296 setDbusValue(v); 297 } 298 else if (dBusMap.propertyType == "bool") 299 { 300 std::variant<bool> v = std::get<bool>(value); 301 setDbusValue(v); 302 } 303 else if (dBusMap.propertyType == "int16_t") 304 { 305 std::variant<int16_t> v = std::get<int16_t>(value); 306 setDbusValue(v); 307 } 308 else if (dBusMap.propertyType == "uint16_t") 309 { 310 std::variant<uint16_t> v = std::get<uint16_t>(value); 311 setDbusValue(v); 312 } 313 else if (dBusMap.propertyType == "int32_t") 314 { 315 std::variant<int32_t> v = std::get<int32_t>(value); 316 setDbusValue(v); 317 } 318 else if (dBusMap.propertyType == "uint32_t") 319 { 320 std::variant<uint32_t> v = std::get<uint32_t>(value); 321 setDbusValue(v); 322 } 323 else if (dBusMap.propertyType == "int64_t") 324 { 325 std::variant<int64_t> v = std::get<int64_t>(value); 326 setDbusValue(v); 327 } 328 else if (dBusMap.propertyType == "uint64_t") 329 { 330 std::variant<uint64_t> v = std::get<uint64_t>(value); 331 setDbusValue(v); 332 } 333 else if (dBusMap.propertyType == "double") 334 { 335 std::variant<double> v = std::get<double>(value); 336 setDbusValue(v); 337 } 338 else if (dBusMap.propertyType == "string") 339 { 340 std::variant<std::string> v = std::get<std::string>(value); 341 setDbusValue(v); 342 } 343 else 344 { 345 throw std::invalid_argument("UnSpported Dbus Type"); 346 } 347 } 348 349 PropertyValue DBusHandler::getDbusPropertyVariant( 350 const char* objPath, const char* dbusProp, const char* dbusInterface) const 351 { 352 auto& bus = DBusHandler::getBus(); 353 auto service = getService(objPath, dbusInterface); 354 auto method = bus.new_method_call(service.c_str(), objPath, dbusProperties, 355 "Get"); 356 method.append(dbusInterface, dbusProp); 357 PropertyValue value{}; 358 auto reply = bus.call(method); 359 reply.read(value); 360 return value; 361 } 362 363 PropertyValue jsonEntryToDbusVal(std::string_view type, 364 const nlohmann::json& value) 365 { 366 PropertyValue propValue{}; 367 if (type == "uint8_t") 368 { 369 propValue = static_cast<uint8_t>(value); 370 } 371 else if (type == "uint16_t") 372 { 373 propValue = static_cast<uint16_t>(value); 374 } 375 else if (type == "uint32_t") 376 { 377 propValue = static_cast<uint32_t>(value); 378 } 379 else if (type == "uint64_t") 380 { 381 propValue = static_cast<uint64_t>(value); 382 } 383 else if (type == "int16_t") 384 { 385 propValue = static_cast<int16_t>(value); 386 } 387 else if (type == "int32_t") 388 { 389 propValue = static_cast<int32_t>(value); 390 } 391 else if (type == "int64_t") 392 { 393 propValue = static_cast<int64_t>(value); 394 } 395 else if (type == "bool") 396 { 397 propValue = static_cast<bool>(value); 398 } 399 else if (type == "double") 400 { 401 propValue = static_cast<double>(value); 402 } 403 else if (type == "string") 404 { 405 propValue = static_cast<std::string>(value); 406 } 407 else 408 { 409 error("Unknown D-Bus property type, TYPE={OTHER_TYPE}", "OTHER_TYPE", 410 type); 411 } 412 413 return propValue; 414 } 415 416 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType, 417 uint16_t entityInstance, uint16_t containerId, 418 uint16_t stateSetId, bool localOrRemote) 419 { 420 uint8_t* pdrData = nullptr; 421 uint32_t pdrSize{}; 422 const pldm_pdr_record* record{}; 423 do 424 { 425 record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR, 426 record, &pdrData, &pdrSize); 427 if (record && (localOrRemote ^ pldm_pdr_record_is_remote(record))) 428 { 429 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrData); 430 auto compositeEffecterCount = pdr->composite_effecter_count; 431 auto possible_states_start = pdr->possible_states; 432 433 for (auto effecters = 0x00; effecters < compositeEffecterCount; 434 effecters++) 435 { 436 auto possibleStates = 437 reinterpret_cast<state_effecter_possible_states*>( 438 possible_states_start); 439 auto setId = possibleStates->state_set_id; 440 auto possibleStateSize = possibleStates->possible_states_size; 441 442 if (entityType == pdr->entity_type && 443 entityInstance == pdr->entity_instance && 444 containerId == pdr->container_id && stateSetId == setId) 445 { 446 return pdr->effecter_id; 447 } 448 possible_states_start += possibleStateSize + sizeof(setId) + 449 sizeof(possibleStateSize); 450 } 451 } 452 } while (record); 453 454 return PLDM_INVALID_EFFECTER_ID; 455 } 456 457 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId, 458 uint8_t sensorOffset, uint8_t eventState, 459 uint8_t previousEventState) 460 { 461 try 462 { 463 auto& bus = DBusHandler::getBus(); 464 auto msg = bus.new_signal("/xyz/openbmc_project/pldm", 465 "xyz.openbmc_project.PLDM.Event", 466 "StateSensorEvent"); 467 msg.append(tid, sensorId, sensorOffset, eventState, previousEventState); 468 469 msg.signal_send(); 470 } 471 catch (const std::exception& e) 472 { 473 error("Error emitting pldm event signal:ERROR={ERR_EXCEP}", "ERR_EXCEP", 474 e.what()); 475 return PLDM_ERROR; 476 } 477 478 return PLDM_SUCCESS; 479 } 480 481 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid, 482 uint16_t entityType, uint16_t entityInstance, 483 uint16_t containerId, uint16_t stateSetId) 484 { 485 auto pdrs = findStateSensorPDR(tid, entityType, stateSetId, pdrRepo); 486 for (auto pdr : pdrs) 487 { 488 auto sensorPdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data()); 489 auto compositeSensorCount = sensorPdr->composite_sensor_count; 490 auto possible_states_start = sensorPdr->possible_states; 491 492 for (auto sensors = 0x00; sensors < compositeSensorCount; sensors++) 493 { 494 auto possibleStates = 495 reinterpret_cast<state_sensor_possible_states*>( 496 possible_states_start); 497 auto setId = possibleStates->state_set_id; 498 auto possibleStateSize = possibleStates->possible_states_size; 499 if (entityType == sensorPdr->entity_type && 500 entityInstance == sensorPdr->entity_instance && 501 stateSetId == setId && containerId == sensorPdr->container_id) 502 { 503 return sensorPdr->sensor_id; 504 } 505 possible_states_start += possibleStateSize + sizeof(setId) + 506 sizeof(possibleStateSize); 507 } 508 } 509 return PLDM_INVALID_EFFECTER_ID; 510 } 511 512 void printBuffer(bool isTx, const std::vector<uint8_t>& buffer) 513 { 514 if (!buffer.empty()) 515 { 516 if (isTx) 517 { 518 std::cout << "Tx: "; 519 } 520 else 521 { 522 std::cout << "Rx: "; 523 } 524 std::ostringstream tempStream; 525 for (int byte : buffer) 526 { 527 tempStream << std::setfill('0') << std::setw(2) << std::hex << byte 528 << " "; 529 } 530 std::cout << tempStream.str() << std::endl; 531 } 532 } 533 534 std::string toString(const struct variable_field& var) 535 { 536 if (var.ptr == nullptr || !var.length) 537 { 538 return ""; 539 } 540 541 std::string str(reinterpret_cast<const char*>(var.ptr), var.length); 542 std::replace_if( 543 str.begin(), str.end(), [](const char& c) { return !isprint(c); }, ' '); 544 return str; 545 } 546 547 std::vector<std::string> split(std::string_view srcStr, std::string_view delim, 548 std::string_view trimStr) 549 { 550 std::vector<std::string> out; 551 size_t start; 552 size_t end = 0; 553 554 while ((start = srcStr.find_first_not_of(delim, end)) != std::string::npos) 555 { 556 end = srcStr.find(delim, start); 557 std::string_view dstStr = srcStr.substr(start, end - start); 558 if (!trimStr.empty()) 559 { 560 dstStr.remove_prefix(dstStr.find_first_not_of(trimStr)); 561 dstStr.remove_suffix(dstStr.size() - 1 - 562 dstStr.find_last_not_of(trimStr)); 563 } 564 565 if (!dstStr.empty()) 566 { 567 out.push_back(std::string(dstStr)); 568 } 569 } 570 571 return out; 572 } 573 574 std::string getCurrentSystemTime() 575 { 576 using namespace std::chrono; 577 const time_point<system_clock> tp = system_clock::now(); 578 std::time_t tt = system_clock::to_time_t(tp); 579 auto ms = duration_cast<microseconds>(tp.time_since_epoch()) - 580 duration_cast<seconds>(tp.time_since_epoch()); 581 582 std::stringstream ss; 583 ss << std::put_time(std::localtime(&tt), "%F %Z %T.") 584 << std::to_string(ms.count()); 585 return ss.str(); 586 } 587 588 bool checkForFruPresence(const std::string& objPath) 589 { 590 bool isPresent = false; 591 static constexpr auto presentInterface = 592 "xyz.openbmc_project.Inventory.Item"; 593 static constexpr auto presentProperty = "Present"; 594 try 595 { 596 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant( 597 objPath.c_str(), presentProperty, presentInterface); 598 isPresent = std::get<bool>(propVal); 599 } 600 catch (const sdbusplus::exception::SdBusError& e) 601 { 602 error( 603 "Failed to check for FRU presence for {OBJ_PATH} ERROR = {ERR_EXCEP}", 604 "OBJ_PATH", objPath.c_str(), "ERR_EXCEP", e.what()); 605 } 606 return isPresent; 607 } 608 609 } // namespace utils 610 } // namespace pldm 611