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