xref: /openbmc/pldm/common/utils.cpp (revision 772403b9)
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, bool localOrRemote)
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 && (localOrRemote ^ pldm_pdr_record_is_remote(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 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid,
462                            uint16_t entityType, uint16_t entityInstance,
463                            uint16_t containerId, uint16_t stateSetId)
464 {
465     auto pdrs = findStateSensorPDR(tid, entityType, stateSetId, pdrRepo);
466     for (auto pdr : pdrs)
467     {
468         auto sensorPdr = reinterpret_cast<pldm_state_sensor_pdr*>(pdr.data());
469         auto compositeSensorCount = sensorPdr->composite_sensor_count;
470         auto possible_states_start = sensorPdr->possible_states;
471 
472         for (auto sensors = 0x00; sensors < compositeSensorCount; sensors++)
473         {
474             auto possibleStates =
475                 reinterpret_cast<state_sensor_possible_states*>(
476                     possible_states_start);
477             auto setId = possibleStates->state_set_id;
478             auto possibleStateSize = possibleStates->possible_states_size;
479             if (entityType == sensorPdr->entity_type &&
480                 entityInstance == sensorPdr->entity_instance &&
481                 stateSetId == setId && containerId == sensorPdr->container_id)
482             {
483                 return sensorPdr->sensor_id;
484             }
485             possible_states_start +=
486                 possibleStateSize + sizeof(setId) + sizeof(possibleStateSize);
487         }
488     }
489     return PLDM_INVALID_EFFECTER_ID;
490 }
491 
492 void printBuffer(const std::vector<uint8_t>& buffer, bool pldmVerbose)
493 {
494     if (pldmVerbose && !buffer.empty())
495     {
496         std::ostringstream tempStream;
497         for (int byte : buffer)
498         {
499             tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
500                        << " ";
501         }
502         std::cout << tempStream.str() << std::endl;
503     }
504 }
505 
506 } // namespace utils
507 } // namespace pldm
508