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" 145 << "\n"; 146 } 147 else 148 { 149 std::string eidStr; 150 eidFile >> eidStr; 151 if (!eidStr.empty()) 152 { 153 eid = atoi(eidStr.c_str()); 154 } 155 else 156 { 157 std::cerr << "Host EID file was empty" 158 << "\n"; 159 } 160 } 161 162 return eid; 163 } 164 165 uint8_t getNumPadBytes(uint32_t data) 166 { 167 uint8_t pad; 168 pad = ((data % 4) ? (4 - data % 4) : 0); 169 return pad; 170 } // end getNumPadBytes 171 172 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day, 173 uint8_t* hour, uint8_t* min, uint8_t* sec) 174 { 175 constexpr uint64_t max_data = 29991231115959; 176 constexpr uint64_t min_data = 19700101000000; 177 if (data < min_data || data > max_data) 178 { 179 return false; 180 } 181 182 *year = data / 10000000000; 183 data = data % 10000000000; 184 *month = data / 100000000; 185 data = data % 100000000; 186 *day = data / 1000000; 187 data = data % 1000000; 188 *hour = data / 10000; 189 data = data % 10000; 190 *min = data / 100; 191 *sec = data % 100; 192 193 return true; 194 } 195 196 std::optional<std::vector<set_effecter_state_field>> 197 parseEffecterData(const std::vector<uint8_t>& effecterData, 198 uint8_t effecterCount) 199 { 200 std::vector<set_effecter_state_field> stateField; 201 202 if (effecterData.size() != effecterCount * 2) 203 { 204 return std::nullopt; 205 } 206 207 for (uint8_t i = 0; i < effecterCount; ++i) 208 { 209 uint8_t set_request = effecterData[i * 2] == PLDM_REQUEST_SET 210 ? PLDM_REQUEST_SET 211 : PLDM_NO_CHANGE; 212 set_effecter_state_field filed{set_request, effecterData[i * 2 + 1]}; 213 stateField.emplace_back(std::move(filed)); 214 } 215 216 return std::make_optional(std::move(stateField)); 217 } 218 219 std::string DBusHandler::getService(const char* path, 220 const char* interface) const 221 { 222 using DbusInterfaceList = std::vector<std::string>; 223 std::map<std::string, std::vector<std::string>> mapperResponse; 224 auto& bus = DBusHandler::getBus(); 225 226 auto mapper = bus.new_method_call(mapperBusName, mapperPath, 227 mapperInterface, "GetObject"); 228 mapper.append(path, DbusInterfaceList({interface})); 229 230 auto mapperResponseMsg = bus.call(mapper); 231 mapperResponseMsg.read(mapperResponse); 232 return mapperResponse.begin()->first; 233 } 234 235 void reportError(const char* errorMsg) 236 { 237 static constexpr auto logObjPath = "/xyz/openbmc_project/logging"; 238 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create"; 239 240 auto& bus = pldm::utils::DBusHandler::getBus(); 241 242 try 243 { 244 auto service = DBusHandler().getService(logObjPath, logInterface); 245 using namespace sdbusplus::xyz::openbmc_project::Logging::server; 246 auto severity = 247 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 248 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 249 Error); 250 auto method = bus.new_method_call(service.c_str(), logObjPath, 251 logInterface, "Create"); 252 std::map<std::string, std::string> addlData{}; 253 method.append(errorMsg, severity, addlData); 254 bus.call_noreply(method); 255 } 256 catch (const std::exception& e) 257 { 258 std::cerr << "failed to make a d-bus call to create error log, ERROR=" 259 << e.what() << "\n"; 260 } 261 } 262 263 void DBusHandler::setDbusProperty(const DBusMapping& dBusMap, 264 const PropertyValue& value) const 265 { 266 auto setDbusValue = [&dBusMap, this](const auto& variant) { 267 auto& bus = getBus(); 268 auto service = 269 getService(dBusMap.objectPath.c_str(), dBusMap.interface.c_str()); 270 auto method = bus.new_method_call( 271 service.c_str(), dBusMap.objectPath.c_str(), dbusProperties, "Set"); 272 method.append(dBusMap.interface.c_str(), dBusMap.propertyName.c_str(), 273 variant); 274 bus.call_noreply(method); 275 }; 276 277 if (dBusMap.propertyType == "uint8_t") 278 { 279 std::variant<uint8_t> v = std::get<uint8_t>(value); 280 setDbusValue(v); 281 } 282 else if (dBusMap.propertyType == "bool") 283 { 284 std::variant<bool> v = std::get<bool>(value); 285 setDbusValue(v); 286 } 287 else if (dBusMap.propertyType == "int16_t") 288 { 289 std::variant<int16_t> v = std::get<int16_t>(value); 290 setDbusValue(v); 291 } 292 else if (dBusMap.propertyType == "uint16_t") 293 { 294 std::variant<uint16_t> v = std::get<uint16_t>(value); 295 setDbusValue(v); 296 } 297 else if (dBusMap.propertyType == "int32_t") 298 { 299 std::variant<int32_t> v = std::get<int32_t>(value); 300 setDbusValue(v); 301 } 302 else if (dBusMap.propertyType == "uint32_t") 303 { 304 std::variant<uint32_t> v = std::get<uint32_t>(value); 305 setDbusValue(v); 306 } 307 else if (dBusMap.propertyType == "int64_t") 308 { 309 std::variant<int64_t> v = std::get<int64_t>(value); 310 setDbusValue(v); 311 } 312 else if (dBusMap.propertyType == "uint64_t") 313 { 314 std::variant<uint64_t> v = std::get<uint64_t>(value); 315 setDbusValue(v); 316 } 317 else if (dBusMap.propertyType == "double") 318 { 319 std::variant<double> v = std::get<double>(value); 320 setDbusValue(v); 321 } 322 else if (dBusMap.propertyType == "string") 323 { 324 std::variant<std::string> v = std::get<std::string>(value); 325 setDbusValue(v); 326 } 327 else 328 { 329 throw std::invalid_argument("UnSpported Dbus Type"); 330 } 331 } 332 333 PropertyValue DBusHandler::getDbusPropertyVariant( 334 const char* objPath, const char* dbusProp, const char* dbusInterface) const 335 { 336 auto& bus = DBusHandler::getBus(); 337 auto service = getService(objPath, dbusInterface); 338 auto method = 339 bus.new_method_call(service.c_str(), objPath, dbusProperties, "Get"); 340 method.append(dbusInterface, dbusProp); 341 PropertyValue value{}; 342 auto reply = bus.call(method); 343 reply.read(value); 344 return value; 345 } 346 347 PropertyValue jsonEntryToDbusVal(std::string_view type, 348 const nlohmann::json& value) 349 { 350 PropertyValue propValue{}; 351 if (type == "uint8_t") 352 { 353 propValue = static_cast<uint8_t>(value); 354 } 355 else if (type == "uint16_t") 356 { 357 propValue = static_cast<uint16_t>(value); 358 } 359 else if (type == "uint32_t") 360 { 361 propValue = static_cast<uint32_t>(value); 362 } 363 else if (type == "uint64_t") 364 { 365 propValue = static_cast<uint64_t>(value); 366 } 367 else if (type == "int16_t") 368 { 369 propValue = static_cast<int16_t>(value); 370 } 371 else if (type == "int32_t") 372 { 373 propValue = static_cast<int32_t>(value); 374 } 375 else if (type == "int64_t") 376 { 377 propValue = static_cast<int64_t>(value); 378 } 379 else if (type == "bool") 380 { 381 propValue = static_cast<bool>(value); 382 } 383 else if (type == "double") 384 { 385 propValue = static_cast<double>(value); 386 } 387 else if (type == "string") 388 { 389 propValue = static_cast<std::string>(value); 390 } 391 else 392 { 393 std::cerr << "Unknown D-Bus property type, TYPE=" << type << "\n"; 394 } 395 396 return propValue; 397 } 398 399 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType, 400 uint16_t entityInstance, uint16_t containerId, 401 uint16_t stateSetId, bool localOrRemote) 402 { 403 uint8_t* pdrData = nullptr; 404 uint32_t pdrSize{}; 405 const pldm_pdr_record* record{}; 406 do 407 { 408 record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR, 409 record, &pdrData, &pdrSize); 410 if (record && (localOrRemote ^ pldm_pdr_record_is_remote(record))) 411 { 412 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrData); 413 auto compositeEffecterCount = pdr->composite_effecter_count; 414 auto possible_states_start = pdr->possible_states; 415 416 for (auto effecters = 0x00; effecters < compositeEffecterCount; 417 effecters++) 418 { 419 auto possibleStates = 420 reinterpret_cast<state_effecter_possible_states*>( 421 possible_states_start); 422 auto setId = possibleStates->state_set_id; 423 auto possibleStateSize = possibleStates->possible_states_size; 424 425 if (entityType == pdr->entity_type && 426 entityInstance == pdr->entity_instance && 427 containerId == pdr->container_id && stateSetId == setId) 428 { 429 return pdr->effecter_id; 430 } 431 possible_states_start += possibleStateSize + sizeof(setId) + 432 sizeof(possibleStateSize); 433 } 434 } 435 } while (record); 436 437 return PLDM_INVALID_EFFECTER_ID; 438 } 439 440 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId, 441 uint8_t sensorOffset, uint8_t eventState, 442 uint8_t previousEventState) 443 { 444 try 445 { 446 auto& bus = DBusHandler::getBus(); 447 auto msg = bus.new_signal("/xyz/openbmc_project/pldm", 448 "xyz.openbmc_project.PLDM.Event", 449 "StateSensorEvent"); 450 msg.append(tid, sensorId, sensorOffset, eventState, previousEventState); 451 452 msg.signal_send(); 453 } 454 catch (std::exception& e) 455 { 456 std::cerr << "Error emitting pldm event signal:" 457 << "ERROR=" << e.what() << "\n"; 458 return PLDM_ERROR; 459 } 460 461 return PLDM_SUCCESS; 462 } 463 464 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid, 465 uint16_t entityType, uint16_t entityInstance, 466 uint16_t containerId, uint16_t stateSetId) 467 { 468 auto pdrs = findStateSensorPDR(tid, entityType, stateSetId, pdrRepo); 469 for (auto pdr : pdrs) 470 { 471 auto sensorPdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data()); 472 auto compositeSensorCount = sensorPdr->composite_sensor_count; 473 auto possible_states_start = sensorPdr->possible_states; 474 475 for (auto sensors = 0x00; sensors < compositeSensorCount; sensors++) 476 { 477 auto possibleStates = 478 reinterpret_cast<state_sensor_possible_states*>( 479 possible_states_start); 480 auto setId = possibleStates->state_set_id; 481 auto possibleStateSize = possibleStates->possible_states_size; 482 if (entityType == sensorPdr->entity_type && 483 entityInstance == sensorPdr->entity_instance && 484 stateSetId == setId && containerId == sensorPdr->container_id) 485 { 486 return sensorPdr->sensor_id; 487 } 488 possible_states_start += 489 possibleStateSize + sizeof(setId) + sizeof(possibleStateSize); 490 } 491 } 492 return PLDM_INVALID_EFFECTER_ID; 493 } 494 495 void printBuffer(bool isTx, const std::vector<uint8_t>& buffer) 496 { 497 if (!buffer.empty()) 498 { 499 if (isTx) 500 { 501 std::cout << "Tx: "; 502 } 503 else 504 { 505 std::cout << "Rx: "; 506 } 507 std::ostringstream tempStream; 508 for (int byte : buffer) 509 { 510 tempStream << std::setfill('0') << std::setw(2) << std::hex << byte 511 << " "; 512 } 513 std::cout << tempStream.str() << std::endl; 514 } 515 } 516 517 std::string toString(const struct variable_field& var) 518 { 519 if (var.ptr == nullptr || !var.length) 520 { 521 return ""; 522 } 523 524 std::string str(reinterpret_cast<const char*>(var.ptr), var.length); 525 std::replace_if( 526 str.begin(), str.end(), [](const char& c) { return !isprint(c); }, ' '); 527 return str; 528 } 529 530 } // namespace utils 531 } // namespace pldm 532