1 #include "utils.hpp" 2 3 #include "libpldm/pdr.h" 4 #include "libpldm/pldm_types.h" 5 6 #include <xyz/openbmc_project/Common/error.hpp> 7 8 #include <algorithm> 9 #include <array> 10 #include <cctype> 11 #include <ctime> 12 #include <fstream> 13 #include <iostream> 14 #include <map> 15 #include <stdexcept> 16 #include <string> 17 #include <vector> 18 19 namespace pldm 20 { 21 namespace utils 22 { 23 24 constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper"; 25 constexpr auto mapperPath = "/xyz/openbmc_project/object_mapper"; 26 constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper"; 27 constexpr auto eidPath = "/usr/share/pldm/host_eid"; 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{eidPath}; 141 if (!eidFile.good()) 142 { 143 std::cerr << "Could not open host EID file" 144 << "\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 void reportError(const char* errorMsg) 235 { 236 static constexpr auto logObjPath = "/xyz/openbmc_project/logging"; 237 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create"; 238 239 auto& bus = pldm::utils::DBusHandler::getBus(); 240 241 try 242 { 243 auto service = DBusHandler().getService(logObjPath, logInterface); 244 using namespace sdbusplus::xyz::openbmc_project::Logging::server; 245 auto severity = 246 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 247 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 248 Error); 249 auto method = bus.new_method_call(service.c_str(), logObjPath, 250 logInterface, "Create"); 251 std::map<std::string, std::string> addlData{}; 252 method.append(errorMsg, severity, addlData); 253 bus.call_noreply(method); 254 } 255 catch (const std::exception& e) 256 { 257 std::cerr << "failed to make a d-bus call to create error log, ERROR=" 258 << e.what() << "\n"; 259 } 260 } 261 262 void DBusHandler::setDbusProperty(const DBusMapping& dBusMap, 263 const PropertyValue& value) const 264 { 265 auto setDbusValue = [&dBusMap, this](const auto& variant) { 266 auto& bus = getBus(); 267 auto service = 268 getService(dBusMap.objectPath.c_str(), dBusMap.interface.c_str()); 269 auto method = bus.new_method_call( 270 service.c_str(), dBusMap.objectPath.c_str(), dbusProperties, "Set"); 271 method.append(dBusMap.interface.c_str(), dBusMap.propertyName.c_str(), 272 variant); 273 bus.call_noreply(method); 274 }; 275 276 if (dBusMap.propertyType == "uint8_t") 277 { 278 std::variant<uint8_t> v = std::get<uint8_t>(value); 279 setDbusValue(v); 280 } 281 else if (dBusMap.propertyType == "bool") 282 { 283 std::variant<bool> v = std::get<bool>(value); 284 setDbusValue(v); 285 } 286 else if (dBusMap.propertyType == "int16_t") 287 { 288 std::variant<int16_t> v = std::get<int16_t>(value); 289 setDbusValue(v); 290 } 291 else if (dBusMap.propertyType == "uint16_t") 292 { 293 std::variant<uint16_t> v = std::get<uint16_t>(value); 294 setDbusValue(v); 295 } 296 else if (dBusMap.propertyType == "int32_t") 297 { 298 std::variant<int32_t> v = std::get<int32_t>(value); 299 setDbusValue(v); 300 } 301 else if (dBusMap.propertyType == "uint32_t") 302 { 303 std::variant<uint32_t> v = std::get<uint32_t>(value); 304 setDbusValue(v); 305 } 306 else if (dBusMap.propertyType == "int64_t") 307 { 308 std::variant<int64_t> v = std::get<int64_t>(value); 309 setDbusValue(v); 310 } 311 else if (dBusMap.propertyType == "uint64_t") 312 { 313 std::variant<uint64_t> v = std::get<uint64_t>(value); 314 setDbusValue(v); 315 } 316 else if (dBusMap.propertyType == "double") 317 { 318 std::variant<double> v = std::get<double>(value); 319 setDbusValue(v); 320 } 321 else if (dBusMap.propertyType == "string") 322 { 323 std::variant<std::string> v = std::get<std::string>(value); 324 setDbusValue(v); 325 } 326 else 327 { 328 throw std::invalid_argument("UnSpported Dbus Type"); 329 } 330 } 331 332 PropertyValue DBusHandler::getDbusPropertyVariant( 333 const char* objPath, const char* dbusProp, const char* dbusInterface) const 334 { 335 auto& bus = DBusHandler::getBus(); 336 auto service = getService(objPath, dbusInterface); 337 auto method = 338 bus.new_method_call(service.c_str(), objPath, dbusProperties, "Get"); 339 method.append(dbusInterface, dbusProp); 340 PropertyValue value{}; 341 auto reply = bus.call(method); 342 reply.read(value); 343 return value; 344 } 345 346 PropertyValue jsonEntryToDbusVal(std::string_view type, 347 const nlohmann::json& value) 348 { 349 PropertyValue propValue{}; 350 if (type == "uint8_t") 351 { 352 propValue = static_cast<uint8_t>(value); 353 } 354 else if (type == "uint16_t") 355 { 356 propValue = static_cast<uint16_t>(value); 357 } 358 else if (type == "uint32_t") 359 { 360 propValue = static_cast<uint32_t>(value); 361 } 362 else if (type == "uint64_t") 363 { 364 propValue = static_cast<uint64_t>(value); 365 } 366 else if (type == "int16_t") 367 { 368 propValue = static_cast<int16_t>(value); 369 } 370 else if (type == "int32_t") 371 { 372 propValue = static_cast<int32_t>(value); 373 } 374 else if (type == "int64_t") 375 { 376 propValue = static_cast<int64_t>(value); 377 } 378 else if (type == "bool") 379 { 380 propValue = static_cast<bool>(value); 381 } 382 else if (type == "double") 383 { 384 propValue = static_cast<double>(value); 385 } 386 else if (type == "string") 387 { 388 propValue = static_cast<std::string>(value); 389 } 390 else 391 { 392 std::cerr << "Unknown D-Bus property type, TYPE=" << type << "\n"; 393 } 394 395 return propValue; 396 } 397 398 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType, 399 uint16_t entityInstance, uint16_t containerId, 400 uint16_t stateSetId, bool localOrRemote) 401 { 402 uint8_t* pdrData = nullptr; 403 uint32_t pdrSize{}; 404 const pldm_pdr_record* record{}; 405 do 406 { 407 record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR, 408 record, &pdrData, &pdrSize); 409 if (record && (localOrRemote ^ pldm_pdr_record_is_remote(record))) 410 { 411 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrData); 412 auto compositeEffecterCount = pdr->composite_effecter_count; 413 auto possible_states_start = pdr->possible_states; 414 415 for (auto effecters = 0x00; effecters < compositeEffecterCount; 416 effecters++) 417 { 418 auto possibleStates = 419 reinterpret_cast<state_effecter_possible_states*>( 420 possible_states_start); 421 auto setId = possibleStates->state_set_id; 422 auto possibleStateSize = possibleStates->possible_states_size; 423 424 if (entityType == pdr->entity_type && 425 entityInstance == pdr->entity_instance && 426 containerId == pdr->container_id && stateSetId == setId) 427 { 428 return pdr->effecter_id; 429 } 430 possible_states_start += possibleStateSize + sizeof(setId) + 431 sizeof(possibleStateSize); 432 } 433 } 434 } while (record); 435 436 return PLDM_INVALID_EFFECTER_ID; 437 } 438 439 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId, 440 uint8_t sensorOffset, uint8_t eventState, 441 uint8_t previousEventState) 442 { 443 try 444 { 445 auto& bus = DBusHandler::getBus(); 446 auto msg = bus.new_signal("/xyz/openbmc_project/pldm", 447 "xyz.openbmc_project.PLDM.Event", 448 "StateSensorEvent"); 449 msg.append(tid, sensorId, sensorOffset, eventState, previousEventState); 450 451 msg.signal_send(); 452 } 453 catch (std::exception& e) 454 { 455 std::cerr << "Error emitting pldm event signal:" 456 << "ERROR=" << e.what() << "\n"; 457 return PLDM_ERROR; 458 } 459 460 return PLDM_SUCCESS; 461 } 462 463 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid, 464 uint16_t entityType, uint16_t entityInstance, 465 uint16_t containerId, uint16_t stateSetId) 466 { 467 auto pdrs = findStateSensorPDR(tid, entityType, stateSetId, pdrRepo); 468 for (auto pdr : pdrs) 469 { 470 auto sensorPdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data()); 471 auto compositeSensorCount = sensorPdr->composite_sensor_count; 472 auto possible_states_start = sensorPdr->possible_states; 473 474 for (auto sensors = 0x00; sensors < compositeSensorCount; sensors++) 475 { 476 auto possibleStates = 477 reinterpret_cast<state_sensor_possible_states*>( 478 possible_states_start); 479 auto setId = possibleStates->state_set_id; 480 auto possibleStateSize = possibleStates->possible_states_size; 481 if (entityType == sensorPdr->entity_type && 482 entityInstance == sensorPdr->entity_instance && 483 stateSetId == setId && containerId == sensorPdr->container_id) 484 { 485 return sensorPdr->sensor_id; 486 } 487 possible_states_start += 488 possibleStateSize + sizeof(setId) + sizeof(possibleStateSize); 489 } 490 } 491 return PLDM_INVALID_EFFECTER_ID; 492 } 493 494 void printBuffer(const std::vector<uint8_t>& buffer, bool pldmVerbose) 495 { 496 if (pldmVerbose && !buffer.empty()) 497 { 498 std::ostringstream tempStream; 499 for (int byte : buffer) 500 { 501 tempStream << std::setfill('0') << std::setw(2) << std::hex << byte 502 << " "; 503 } 504 std::cout << tempStream.str() << std::endl; 505 } 506 } 507 508 std::string toString(const struct variable_field& var) 509 { 510 if (var.ptr == nullptr || !var.length) 511 { 512 return ""; 513 } 514 515 std::string str(reinterpret_cast<const char*>(var.ptr), var.length); 516 std::replace_if( 517 str.begin(), str.end(), [](const char& c) { return !isprint(c); }, ' '); 518 return str; 519 } 520 521 } // namespace utils 522 } // namespace pldm 523