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 <array> 9 #include <ctime> 10 #include <fstream> 11 #include <iostream> 12 #include <map> 13 #include <stdexcept> 14 #include <string> 15 #include <vector> 16 17 namespace pldm 18 { 19 namespace utils 20 { 21 22 constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper"; 23 constexpr auto mapperPath = "/xyz/openbmc_project/object_mapper"; 24 constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper"; 25 constexpr auto eidPath = "/usr/share/pldm/host_eid"; 26 27 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t /*tid*/, 28 uint16_t entityID, 29 uint16_t stateSetId, 30 const pldm_pdr* repo) 31 { 32 uint8_t* outData = nullptr; 33 uint32_t size{}; 34 const pldm_pdr_record* record{}; 35 std::vector<std::vector<uint8_t>> pdrs; 36 try 37 { 38 do 39 { 40 record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_EFFECTER_PDR, 41 record, &outData, &size); 42 if (record) 43 { 44 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(outData); 45 auto compositeEffecterCount = pdr->composite_effecter_count; 46 auto possible_states_start = pdr->possible_states; 47 48 for (auto effecters = 0x00; effecters < compositeEffecterCount; 49 effecters++) 50 { 51 auto possibleStates = 52 reinterpret_cast<state_effecter_possible_states*>( 53 possible_states_start); 54 auto setId = possibleStates->state_set_id; 55 auto possibleStateSize = 56 possibleStates->possible_states_size; 57 58 if (pdr->entity_type == entityID && setId == stateSetId) 59 { 60 std::vector<uint8_t> effecter_pdr(&outData[0], 61 &outData[size]); 62 pdrs.emplace_back(std::move(effecter_pdr)); 63 break; 64 } 65 possible_states_start += possibleStateSize + sizeof(setId) + 66 sizeof(possibleStateSize); 67 } 68 } 69 70 } while (record); 71 } 72 catch (const std::exception& e) 73 { 74 std::cerr << " Failed to obtain a record. ERROR =" << e.what() 75 << std::endl; 76 } 77 78 return pdrs; 79 } 80 81 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t /*tid*/, 82 uint16_t entityID, 83 uint16_t stateSetId, 84 const pldm_pdr* repo) 85 { 86 uint8_t* outData = nullptr; 87 uint32_t size{}; 88 const pldm_pdr_record* record{}; 89 std::vector<std::vector<uint8_t>> pdrs; 90 try 91 { 92 do 93 { 94 record = pldm_pdr_find_record_by_type(repo, PLDM_STATE_SENSOR_PDR, 95 record, &outData, &size); 96 if (record) 97 { 98 auto pdr = reinterpret_cast<pldm_state_sensor_pdr*>(outData); 99 auto compositeSensorCount = pdr->composite_sensor_count; 100 auto possible_states_start = pdr->possible_states; 101 102 for (auto sensors = 0x00; sensors < compositeSensorCount; 103 sensors++) 104 { 105 auto possibleStates = 106 reinterpret_cast<state_sensor_possible_states*>( 107 possible_states_start); 108 auto setId = possibleStates->state_set_id; 109 auto possibleStateSize = 110 possibleStates->possible_states_size; 111 112 if (pdr->entity_type == entityID && setId == stateSetId) 113 { 114 std::vector<uint8_t> sensor_pdr(&outData[0], 115 &outData[size]); 116 pdrs.emplace_back(std::move(sensor_pdr)); 117 break; 118 } 119 possible_states_start += possibleStateSize + sizeof(setId) + 120 sizeof(possibleStateSize); 121 } 122 } 123 124 } while (record); 125 } 126 catch (const std::exception& e) 127 { 128 std::cerr << " Failed to obtain a record. ERROR =" << e.what() 129 << std::endl; 130 } 131 132 return pdrs; 133 } 134 135 uint8_t readHostEID() 136 { 137 uint8_t eid{}; 138 std::ifstream eidFile{eidPath}; 139 if (!eidFile.good()) 140 { 141 std::cerr << "Could not open host EID file" 142 << "\n"; 143 } 144 else 145 { 146 std::string eidStr; 147 eidFile >> eidStr; 148 if (!eidStr.empty()) 149 { 150 eid = atoi(eidStr.c_str()); 151 } 152 else 153 { 154 std::cerr << "Host EID file was empty" 155 << "\n"; 156 } 157 } 158 159 return eid; 160 } 161 162 uint8_t getNumPadBytes(uint32_t data) 163 { 164 uint8_t pad; 165 pad = ((data % 4) ? (4 - data % 4) : 0); 166 return pad; 167 } // end getNumPadBytes 168 169 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day, 170 uint8_t* hour, uint8_t* min, uint8_t* sec) 171 { 172 constexpr uint64_t max_data = 29991231115959; 173 constexpr uint64_t min_data = 19700101000000; 174 if (data < min_data || data > max_data) 175 { 176 return false; 177 } 178 179 *year = data / 10000000000; 180 data = data % 10000000000; 181 *month = data / 100000000; 182 data = data % 100000000; 183 *day = data / 1000000; 184 data = data % 1000000; 185 *hour = data / 10000; 186 data = data % 10000; 187 *min = data / 100; 188 *sec = data % 100; 189 190 return true; 191 } 192 193 std::optional<std::vector<set_effecter_state_field>> 194 parseEffecterData(const std::vector<uint8_t>& effecterData, 195 uint8_t effecterCount) 196 { 197 std::vector<set_effecter_state_field> stateField; 198 199 if (effecterData.size() != effecterCount * 2) 200 { 201 return std::nullopt; 202 } 203 204 for (uint8_t i = 0; i < effecterCount; ++i) 205 { 206 uint8_t set_request = effecterData[i * 2] == PLDM_REQUEST_SET 207 ? PLDM_REQUEST_SET 208 : PLDM_NO_CHANGE; 209 set_effecter_state_field filed{set_request, effecterData[i * 2 + 1]}; 210 stateField.emplace_back(std::move(filed)); 211 } 212 213 return std::make_optional(std::move(stateField)); 214 } 215 216 std::string DBusHandler::getService(const char* path, 217 const char* interface) const 218 { 219 using DbusInterfaceList = std::vector<std::string>; 220 std::map<std::string, std::vector<std::string>> mapperResponse; 221 auto& bus = DBusHandler::getBus(); 222 223 auto mapper = bus.new_method_call(mapperBusName, mapperPath, 224 mapperInterface, "GetObject"); 225 mapper.append(path, DbusInterfaceList({interface})); 226 227 auto mapperResponseMsg = bus.call(mapper); 228 mapperResponseMsg.read(mapperResponse); 229 return mapperResponse.begin()->first; 230 } 231 232 void reportError(const char* errorMsg) 233 { 234 static constexpr auto logObjPath = "/xyz/openbmc_project/logging"; 235 static constexpr auto logInterface = "xyz.openbmc_project.Logging.Create"; 236 237 auto& bus = pldm::utils::DBusHandler::getBus(); 238 239 try 240 { 241 auto service = DBusHandler().getService(logObjPath, logInterface); 242 using namespace sdbusplus::xyz::openbmc_project::Logging::server; 243 auto severity = 244 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage( 245 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level:: 246 Error); 247 auto method = bus.new_method_call(service.c_str(), logObjPath, 248 logInterface, "Create"); 249 std::map<std::string, std::string> addlData{}; 250 method.append(errorMsg, severity, addlData); 251 bus.call_noreply(method); 252 } 253 catch (const std::exception& e) 254 { 255 std::cerr << "failed to make a d-bus call to create error log, ERROR=" 256 << e.what() << "\n"; 257 } 258 } 259 260 void DBusHandler::setDbusProperty(const DBusMapping& dBusMap, 261 const PropertyValue& value) const 262 { 263 auto setDbusValue = [&dBusMap, this](const auto& variant) { 264 auto& bus = getBus(); 265 auto service = 266 getService(dBusMap.objectPath.c_str(), dBusMap.interface.c_str()); 267 auto method = bus.new_method_call( 268 service.c_str(), dBusMap.objectPath.c_str(), dbusProperties, "Set"); 269 method.append(dBusMap.interface.c_str(), dBusMap.propertyName.c_str(), 270 variant); 271 bus.call_noreply(method); 272 }; 273 274 if (dBusMap.propertyType == "uint8_t") 275 { 276 std::variant<uint8_t> v = std::get<uint8_t>(value); 277 setDbusValue(v); 278 } 279 else if (dBusMap.propertyType == "bool") 280 { 281 std::variant<bool> v = std::get<bool>(value); 282 setDbusValue(v); 283 } 284 else if (dBusMap.propertyType == "int16_t") 285 { 286 std::variant<int16_t> v = std::get<int16_t>(value); 287 setDbusValue(v); 288 } 289 else if (dBusMap.propertyType == "uint16_t") 290 { 291 std::variant<uint16_t> v = std::get<uint16_t>(value); 292 setDbusValue(v); 293 } 294 else if (dBusMap.propertyType == "int32_t") 295 { 296 std::variant<int32_t> v = std::get<int32_t>(value); 297 setDbusValue(v); 298 } 299 else if (dBusMap.propertyType == "uint32_t") 300 { 301 std::variant<uint32_t> v = std::get<uint32_t>(value); 302 setDbusValue(v); 303 } 304 else if (dBusMap.propertyType == "int64_t") 305 { 306 std::variant<int64_t> v = std::get<int64_t>(value); 307 setDbusValue(v); 308 } 309 else if (dBusMap.propertyType == "uint64_t") 310 { 311 std::variant<uint64_t> v = std::get<uint64_t>(value); 312 setDbusValue(v); 313 } 314 else if (dBusMap.propertyType == "double") 315 { 316 std::variant<double> v = std::get<double>(value); 317 setDbusValue(v); 318 } 319 else if (dBusMap.propertyType == "string") 320 { 321 std::variant<std::string> v = std::get<std::string>(value); 322 setDbusValue(v); 323 } 324 else 325 { 326 throw std::invalid_argument("UnSpported Dbus Type"); 327 } 328 } 329 330 PropertyValue DBusHandler::getDbusPropertyVariant( 331 const char* objPath, const char* dbusProp, const char* dbusInterface) const 332 { 333 auto& bus = DBusHandler::getBus(); 334 auto service = getService(objPath, dbusInterface); 335 auto method = 336 bus.new_method_call(service.c_str(), objPath, dbusProperties, "Get"); 337 method.append(dbusInterface, dbusProp); 338 PropertyValue value{}; 339 auto reply = bus.call(method); 340 reply.read(value); 341 return value; 342 } 343 344 PropertyValue jsonEntryToDbusVal(std::string_view type, 345 const nlohmann::json& value) 346 { 347 PropertyValue propValue{}; 348 if (type == "uint8_t") 349 { 350 propValue = static_cast<uint8_t>(value); 351 } 352 else if (type == "uint16_t") 353 { 354 propValue = static_cast<uint16_t>(value); 355 } 356 else if (type == "uint32_t") 357 { 358 propValue = static_cast<uint32_t>(value); 359 } 360 else if (type == "uint64_t") 361 { 362 propValue = static_cast<uint64_t>(value); 363 } 364 else if (type == "int16_t") 365 { 366 propValue = static_cast<int16_t>(value); 367 } 368 else if (type == "int32_t") 369 { 370 propValue = static_cast<int32_t>(value); 371 } 372 else if (type == "int64_t") 373 { 374 propValue = static_cast<int64_t>(value); 375 } 376 else if (type == "bool") 377 { 378 propValue = static_cast<bool>(value); 379 } 380 else if (type == "double") 381 { 382 propValue = static_cast<double>(value); 383 } 384 else if (type == "string") 385 { 386 propValue = static_cast<std::string>(value); 387 } 388 else 389 { 390 std::cerr << "Unknown D-Bus property type, TYPE=" << type << "\n"; 391 } 392 393 return propValue; 394 } 395 396 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType, 397 uint16_t entityInstance, uint16_t containerId, 398 uint16_t stateSetId) 399 { 400 uint8_t* pdrData = nullptr; 401 uint32_t pdrSize{}; 402 const pldm_pdr_record* record{}; 403 do 404 { 405 record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR, 406 record, &pdrData, &pdrSize); 407 if (record) 408 { 409 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrData); 410 auto compositeEffecterCount = pdr->composite_effecter_count; 411 auto possible_states_start = pdr->possible_states; 412 413 for (auto effecters = 0x00; effecters < compositeEffecterCount; 414 effecters++) 415 { 416 auto possibleStates = 417 reinterpret_cast<state_effecter_possible_states*>( 418 possible_states_start); 419 auto setId = possibleStates->state_set_id; 420 auto possibleStateSize = possibleStates->possible_states_size; 421 422 if (entityType == pdr->entity_type && 423 entityInstance == pdr->entity_instance && 424 containerId == pdr->container_id && stateSetId == setId) 425 { 426 return pdr->effecter_id; 427 } 428 possible_states_start += possibleStateSize + sizeof(setId) + 429 sizeof(possibleStateSize); 430 } 431 } 432 } while (record); 433 434 return PLDM_INVALID_EFFECTER_ID; 435 } 436 437 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId, 438 uint8_t sensorOffset, uint8_t eventState, 439 uint8_t previousEventState) 440 { 441 try 442 { 443 auto& bus = DBusHandler::getBus(); 444 auto msg = bus.new_signal("/xyz/openbmc_project/pldm", 445 "xyz.openbmc_project.PLDM.Event", 446 "StateSensorEvent"); 447 msg.append(tid, sensorId, sensorOffset, eventState, previousEventState); 448 449 msg.signal_send(); 450 } 451 catch (std::exception& e) 452 { 453 std::cerr << "Error emitting pldm event signal:" 454 << "ERROR=" << e.what() << "\n"; 455 return PLDM_ERROR; 456 } 457 458 return PLDM_SUCCESS; 459 } 460 461 } // namespace utils 462 } // namespace pldm 463