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