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