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