xref: /openbmc/pldm/common/utils.hpp (revision efacb6f7)
1 #pragma once
2 
3 #include "types.hpp"
4 
5 #include <libpldm/base.h>
6 #include <libpldm/bios.h>
7 #include <libpldm/entity.h>
8 #include <libpldm/pdr.h>
9 #include <libpldm/platform.h>
10 #include <libpldm/utils.h>
11 #include <stdint.h>
12 #include <systemd/sd-bus.h>
13 #include <unistd.h>
14 
15 #include <nlohmann/json.hpp>
16 #include <sdbusplus/server.hpp>
17 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
18 
19 #include <deque>
20 #include <exception>
21 #include <filesystem>
22 #include <iostream>
23 #include <map>
24 #include <string>
25 #include <variant>
26 #include <vector>
27 
28 constexpr uint64_t dbusTimeout =
29     std::chrono::duration_cast<std::chrono::microseconds>(
30         std::chrono::seconds(DBUS_TIMEOUT))
31         .count();
32 
33 namespace pldm
34 {
35 using Severity = pldm::PelSeverity;
36 
37 // mapping of severity enum to severity interface
38 static std::unordered_map<Severity, std::string> sevMap = {
39     {Severity::Informational,
40      "xyz.openbmc_project.Logging.Entry.Level.Informational"},
41     {Severity::Debug, "xyz.openbmc_project.Logging.Entry.Level.Debug"},
42     {Severity::Notice, "xyz.openbmc_project.Logging.Entry.Level.Notice"},
43     {Severity::Warning, "xyz.openbmc_project.Logging.Entry.Level.Warning"},
44     {Severity::Critical, "xyz.openbmc_project.Logging.Entry.Level.Critical"},
45     {Severity::Emergency, "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
46     {Severity::Error, "xyz.openbmc_project.Logging.Entry.Level.Error"},
47     {Severity::Alert, "xyz.openbmc_project.Logging.Entry.Level.Alert"}};
48 
49 namespace utils
50 {
51 namespace fs = std::filesystem;
52 using Json = nlohmann::json;
53 constexpr bool Tx = true;
54 constexpr bool Rx = false;
55 
56 using EntityName = std::string;
57 using EntityType = uint16_t;
58 
59 using Entities = std::vector<pldm_entity_node*>;
60 using EntityAssociations = std::vector<Entities>;
61 using ObjectPathMaps = std::map<fs::path, pldm_entity_node*>;
62 
63 const std::map<EntityType, EntityName> entityMaps = {
64     {PLDM_ENTITY_SYSTEM_CHASSIS, "chassis"},
65     {PLDM_ENTITY_BOARD, "io_board"},
66     {PLDM_ENTITY_SYS_BOARD, "motherboard"},
67     {PLDM_ENTITY_POWER_SUPPLY, "powersupply"},
68     {PLDM_ENTITY_PROC, "cpu"},
69     {PLDM_ENTITY_SYSTEM_CHASSIS | 0x8000, "system"},
70     {PLDM_ENTITY_PROC_MODULE, "dcm"},
71     {PLDM_ENTITY_PROC | 0x8000, "core"},
72     {PLDM_ENTITY_IO_MODULE, "io_module"},
73     {PLDM_ENTITY_FAN, "fan"},
74     {PLDM_ENTITY_SYS_MGMT_MODULE, "system_management_module"},
75     {PLDM_ENTITY_POWER_CONVERTER, "power_converter"},
76     {PLDM_ENTITY_SLOT, "slot"},
77     {PLDM_ENTITY_CONNECTOR, "connector"}};
78 
79 /** @brief Vector a entity name to pldm_entity from entity association tree
80  *  @param[in]  entityAssoc    - Vector of associated pldm entities
81  *  @param[in]  entityTree     - entity association tree
82  *  @param[out] objPathMap     - maps an object path to pldm_entity from the
83  *                               BMC's entity association tree
84  *  @return
85  */
86 void updateEntityAssociation(const EntityAssociations& entityAssoc,
87                              pldm_entity_association_tree* entityTree,
88                              ObjectPathMaps& objPathMap);
89 
90 /** @struct CustomFD
91  *
92  *  RAII wrapper for file descriptor.
93  */
94 struct CustomFD
95 {
96     CustomFD(const CustomFD&) = delete;
97     CustomFD& operator=(const CustomFD&) = delete;
98     CustomFD(CustomFD&&) = delete;
99     CustomFD& operator=(CustomFD&&) = delete;
100 
101     CustomFD(int fd) : fd(fd) {}
102 
103     ~CustomFD()
104     {
105         if (fd >= 0)
106         {
107             close(fd);
108         }
109     }
110 
111     int operator()() const
112     {
113         return fd;
114     }
115 
116   private:
117     int fd = -1;
118 };
119 
120 /** @brief Calculate the pad for PLDM data
121  *
122  *  @param[in] data - Length of the data
123  *  @return - uint8_t - number of pad bytes
124  */
125 uint8_t getNumPadBytes(uint32_t data);
126 
127 /** @brief Convert uint64 to date
128  *
129  *  @param[in] data - time date of uint64
130  *  @param[out] year - year number in dec
131  *  @param[out] month - month number in dec
132  *  @param[out] day - day of the month in dec
133  *  @param[out] hour - number of hours in dec
134  *  @param[out] min - number of minutes in dec
135  *  @param[out] sec - number of seconds in dec
136  *  @return true if decode success, false if decode faild
137  */
138 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day,
139                 uint8_t* hour, uint8_t* min, uint8_t* sec);
140 
141 /** @brief Convert effecter data to structure of set_effecter_state_field
142  *
143  *  @param[in] effecterData - the date of effecter
144  *  @param[in] effecterCount - the number of individual sets of effecter
145  *                              information
146  *  @return[out] parse success and get a valid set_effecter_state_field
147  *               structure, return nullopt means parse failed
148  */
149 std::optional<std::vector<set_effecter_state_field>>
150     parseEffecterData(const std::vector<uint8_t>& effecterData,
151                       uint8_t effecterCount);
152 
153 /**
154  *  @brief creates an error log
155  *  @param[in] errorMsg - the error message
156  *  @param[in] sev - severity of the log
157  *
158  */
159 void reportError(const char* errorMsg,
160                  const PelSeverity& sev = pldm::PelSeverity::Error);
161 
162 /** @brief Convert any Decimal number to BCD
163  *
164  *  @tparam[in] decimal - Decimal number
165  *  @return Corresponding BCD number
166  */
167 template <typename T>
168 T decimalToBcd(T decimal)
169 {
170     T bcd = 0;
171     T rem = 0;
172     auto cnt = 0;
173 
174     while (decimal)
175     {
176         rem = decimal % 10;
177         bcd = bcd + (rem << cnt);
178         decimal = decimal / 10;
179         cnt += 4;
180     }
181 
182     return bcd;
183 }
184 
185 constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
186 constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
187 
188 struct DBusMapping
189 {
190     std::string objectPath;   //!< D-Bus object path
191     std::string interface;    //!< D-Bus interface
192     std::string propertyName; //!< D-Bus property name
193     std::string propertyType; //!< D-Bus property type
194 };
195 
196 using PropertyValue =
197     std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
198                  uint64_t, double, std::string, std::vector<std::string>>;
199 using DbusProp = std::string;
200 using DbusChangedProps = std::map<DbusProp, PropertyValue>;
201 using DBusInterfaceAdded = std::vector<
202     std::pair<pldm::dbus::Interface,
203               std::vector<std::pair<pldm::dbus::Property,
204                                     std::variant<pldm::dbus::Property>>>>>;
205 using ObjectPath = std::string;
206 using ServiceName = std::string;
207 using Interfaces = std::vector<std::string>;
208 using MapperServiceMap = std::vector<std::pair<ServiceName, Interfaces>>;
209 using GetSubTreeResponse = std::vector<std::pair<ObjectPath, MapperServiceMap>>;
210 using PropertyMap = std::map<std::string, PropertyValue>;
211 using InterfaceMap = std::map<std::string, PropertyMap>;
212 
213 /**
214  * @brief The interface for DBusHandler
215  */
216 class DBusHandlerInterface
217 {
218   public:
219     virtual ~DBusHandlerInterface() = default;
220 
221     virtual std::string getService(const char* path,
222                                    const char* interface) const = 0;
223     virtual GetSubTreeResponse
224         getSubtree(const std::string& path, int depth,
225                    const std::vector<std::string>& ifaceList) const = 0;
226 
227     virtual void setDbusProperty(const DBusMapping& dBusMap,
228                                  const PropertyValue& value) const = 0;
229 
230     virtual PropertyValue
231         getDbusPropertyVariant(const char* objPath, const char* dbusProp,
232                                const char* dbusInterface) const = 0;
233 };
234 
235 /**
236  *  @class DBusHandler
237  *
238  *  Wrapper class to handle the D-Bus calls
239  *
240  *  This class contains the APIs to handle the D-Bus calls
241  *  to cater the request from pldm requester.
242  *  A class is created to mock the apis in the test cases
243  */
244 class DBusHandler : public DBusHandlerInterface
245 {
246   public:
247     /** @brief Get the bus connection. */
248     static auto& getBus()
249     {
250         static auto bus = sdbusplus::bus::new_default();
251         return bus;
252     }
253 
254     /**
255      *  @brief Get the DBUS Service name for the input dbus path
256      *
257      *  @param[in] path - DBUS object path
258      *  @param[in] interface - DBUS Interface
259      *
260      *  @return std::string - the dbus service name
261      *
262      *  @throw sdbusplus::exception_t when it fails
263      */
264     std::string getService(const char* path,
265                            const char* interface) const override;
266 
267     /**
268      *  @brief Get the Subtree response from the mapper
269      *
270      *  @param[in] path - DBUS object path
271      *  @param[in] depth - Search depth
272      *  @param[in] ifaceList - list of the interface that are being
273      *                         queried from the mapper
274      *
275      *  @return GetSubTreeResponse - the mapper subtree response
276      *
277      *  @throw sdbusplus::exception_t when it fails
278      */
279     GetSubTreeResponse
280         getSubtree(const std::string& path, int depth,
281                    const std::vector<std::string>& ifaceList) const override;
282 
283     /** @brief Get property(type: variant) from the requested dbus
284      *
285      *  @param[in] objPath - The Dbus object path
286      *  @param[in] dbusProp - The property name to get
287      *  @param[in] dbusInterface - The Dbus interface
288      *
289      *  @return The value of the property(type: variant)
290      *
291      *  @throw sdbusplus::exception_t when it fails
292      */
293     PropertyValue
294         getDbusPropertyVariant(const char* objPath, const char* dbusProp,
295                                const char* dbusInterface) const override;
296 
297     /** @brief The template function to get property from the requested dbus
298      *         path
299      *
300      *  @tparam Property - Excepted type of the property on dbus
301      *
302      *  @param[in] objPath - The Dbus object path
303      *  @param[in] dbusProp - The property name to get
304      *  @param[in] dbusInterface - The Dbus interface
305      *
306      *  @return The value of the property
307      *
308      *  @throw sdbusplus::exception_t when dbus request fails
309      *         std::bad_variant_access when \p Property and property on dbus do
310      *         not match
311      */
312     template <typename Property>
313     auto getDbusProperty(const char* objPath, const char* dbusProp,
314                          const char* dbusInterface)
315     {
316         auto VariantValue = getDbusPropertyVariant(objPath, dbusProp,
317                                                    dbusInterface);
318         return std::get<Property>(VariantValue);
319     }
320 
321     /** @brief Set Dbus property
322      *
323      *  @param[in] dBusMap - Object path, property name, interface and property
324      *                       type for the D-Bus object
325      *  @param[in] value - The value to be set
326      *
327      *  @throw sdbusplus::exception_t when it fails
328      */
329     void setDbusProperty(const DBusMapping& dBusMap,
330                          const PropertyValue& value) const override;
331 };
332 
333 /** @brief Fetch parent D-Bus object based on pathname
334  *
335  *  @param[in] dbusObj - child D-Bus object
336  *
337  *  @return std::string - the parent D-Bus object path
338  */
339 inline std::string findParent(const std::string& dbusObj)
340 {
341     fs::path p(dbusObj);
342     return p.parent_path().string();
343 }
344 
345 /** @brief Read (static) MCTP EID of host firmware from a file
346  *
347  *  @return uint8_t - MCTP EID
348  */
349 uint8_t readHostEID();
350 
351 /** @brief Convert a value in the JSON to a D-Bus property value
352  *
353  *  @param[in] type - type of the D-Bus property
354  *  @param[in] value - value in the JSON file
355  *
356  *  @return PropertyValue - the D-Bus property value
357  */
358 PropertyValue jsonEntryToDbusVal(std::string_view type,
359                                  const nlohmann::json& value);
360 
361 /** @brief Find State Effecter PDR
362  *  @param[in] tid - PLDM terminus ID.
363  *  @param[in] entityID - entity that can be associated with PLDM State set.
364  *  @param[in] stateSetId - value that identifies PLDM State set.
365  *  @param[in] repo - pointer to BMC's primary PDR repo.
366  *  @return array[array[uint8_t]] - StateEffecterPDRs
367  */
368 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t tid,
369                                                        uint16_t entityID,
370                                                        uint16_t stateSetId,
371                                                        const pldm_pdr* repo);
372 /** @brief Find State Sensor PDR
373  *  @param[in] tid - PLDM terminus ID.
374  *  @param[in] entityID - entity that can be associated with PLDM State set.
375  *  @param[in] stateSetId - value that identifies PLDM State set.
376  *  @param[in] repo - pointer to BMC's primary PDR repo.
377  *  @return array[array[uint8_t]] - StateSensorPDRs
378  */
379 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t tid,
380                                                      uint16_t entityID,
381                                                      uint16_t stateSetId,
382                                                      const pldm_pdr* repo);
383 
384 /** @brief Find sensor id from a state sensor PDR
385  *
386  *  @param[in] pdrRepo - PDR repository
387  *  @param[in] tid - terminus id
388  *  @param[in] entityType - entity type
389  *  @param[in] entityInstance - entity instance number
390  *  @param[in] containerId - container id
391  *  @param[in] stateSetId - state set id
392  *
393  *  @return uint16_t - the sensor id
394  */
395 uint16_t findStateSensorId(const pldm_pdr* pdrRepo, uint8_t tid,
396                            uint16_t entityType, uint16_t entityInstance,
397                            uint16_t containerId, uint16_t stateSetId);
398 
399 /** @brief Find effecter id from a state effecter pdr
400  *  @param[in] pdrRepo - PDR repository
401  *  @param[in] entityType - entity type
402  *  @param[in] entityInstance - entity instance number
403  *  @param[in] containerId - container id
404  *  @param[in] stateSetId - state set id
405  *  @param[in] localOrRemote - true for checking local repo and false for remote
406  *                             repo
407  *
408  *  @return uint16_t - the effecter id
409  */
410 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType,
411                              uint16_t entityInstance, uint16_t containerId,
412                              uint16_t stateSetId, bool localOrRemote);
413 
414 /** @brief Emit the sensor event signal
415  *
416  *	@param[in] tid - the terminus id
417  *  @param[in] sensorId - sensorID value of the sensor
418  *  @param[in] sensorOffset - Identifies which state sensor within a
419  * composite state sensor the event is being returned for
420  *  @param[in] eventState - The event state value from the state change that
421  * triggered the event message
422  *  @param[in] previousEventState - The event state value for the state from
423  * which the present event state was entered.
424  *  @return PLDM completion code
425  */
426 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId,
427                                uint8_t sensorOffset, uint8_t eventState,
428                                uint8_t previousEventState);
429 
430 /** @brief Print the buffer
431  *
432  *  @param[in]  isTx - True if the buffer is an outgoing PLDM message, false if
433                        the buffer is an incoming PLDM message
434  *  @param[in]  buffer - Buffer to print
435  *
436  *  @return - None
437  */
438 void printBuffer(bool isTx, const std::vector<uint8_t>& buffer);
439 
440 /** @brief Convert the buffer to std::string
441  *
442  *  If there are characters that are not printable characters, it is replaced
443  *  with space(0x20).
444  *
445  *  @param[in] var - pointer to data and length of the data
446  *
447  *  @return std::string equivalent of variable field
448  */
449 std::string toString(const struct variable_field& var);
450 
451 /** @brief Split strings according to special identifiers
452  *
453  *  We can split the string according to the custom identifier(';', ',', '&' or
454  *  others) and store it to vector.
455  *
456  *  @param[in] srcStr       - The string to be split
457  *  @param[in] delim        - The custom identifier
458  *  @param[in] trimStr      - The first and last string to be trimmed
459  *
460  *  @return std::vector<std::string> Vectors are used to store strings
461  */
462 std::vector<std::string> split(std::string_view srcStr, std::string_view delim,
463                                std::string_view trimStr = "");
464 /** @brief Get the current system time in readable format
465  *
466  *  @return - std::string equivalent of the system time
467  */
468 std::string getCurrentSystemTime();
469 
470 /** @brief checks if the FRU is actually present.
471  *  @param[in] objPath - FRU object path.
472  *
473  *  @return bool to indicate presence or absence of FRU.
474  */
475 bool checkForFruPresence(const std::string& objPath);
476 
477 /** @brief Method to check if the logical bit is set
478  *
479  *  @param[containerId] - container id of the entity
480  *
481  *  @return true or false based on the logic bit set
482  */
483 bool checkIfLogicalBitSet(const uint16_t& containerId);
484 
485 /** @brief setting the present property
486  *
487  *  @param[in] objPath - the object path of the fru
488  *  @param[in] present - status to set either true/false
489  */
490 void setFruPresence(const std::string& fruObjPath, bool present);
491 } // namespace utils
492 } // namespace pldm
493