xref: /openbmc/pldm/common/utils.hpp (revision 579a34a3)
1 #pragma once
2 
3 #include "libpldm/base.h"
4 #include "libpldm/bios.h"
5 #include "libpldm/platform.h"
6 
7 #include <stdint.h>
8 #include <systemd/sd-bus.h>
9 #include <unistd.h>
10 
11 #include <nlohmann/json.hpp>
12 #include <sdbusplus/server.hpp>
13 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
14 
15 #include <exception>
16 #include <filesystem>
17 #include <iostream>
18 #include <string>
19 #include <variant>
20 #include <vector>
21 
22 namespace pldm
23 {
24 namespace utils
25 {
26 
27 namespace fs = std::filesystem;
28 using Json = nlohmann::json;
29 
30 /** @struct CustomFD
31  *
32  *  RAII wrapper for file descriptor.
33  */
34 struct CustomFD
35 {
36     CustomFD(const CustomFD&) = delete;
37     CustomFD& operator=(const CustomFD&) = delete;
38     CustomFD(CustomFD&&) = delete;
39     CustomFD& operator=(CustomFD&&) = delete;
40 
41     CustomFD(int fd) : fd(fd)
42     {}
43 
44     ~CustomFD()
45     {
46         if (fd >= 0)
47         {
48             close(fd);
49         }
50     }
51 
52     int operator()() const
53     {
54         return fd;
55     }
56 
57   private:
58     int fd = -1;
59 };
60 
61 /** @brief Calculate the pad for PLDM data
62  *
63  *  @param[in] data - Length of the data
64  *  @return - uint8_t - number of pad bytes
65  */
66 uint8_t getNumPadBytes(uint32_t data);
67 
68 /** @brief Convert uint64 to date
69  *
70  *  @param[in] data - time date of uint64
71  *  @param[out] year - year number in dec
72  *  @param[out] month - month number in dec
73  *  @param[out] day - day of the month in dec
74  *  @param[out] hour - number of hours in dec
75  *  @param[out] min - number of minutes in dec
76  *  @param[out] sec - number of seconds in dec
77  *  @return true if decode success, false if decode faild
78  */
79 bool uintToDate(uint64_t data, uint16_t* year, uint8_t* month, uint8_t* day,
80                 uint8_t* hour, uint8_t* min, uint8_t* sec);
81 
82 /** @brief Convert effecter data to structure of set_effecter_state_field
83  *
84  *  @param[in] effecterData - the date of effecter
85  *  @param[in] effecterCount - the number of individual sets of effecter
86  *                              information
87  *  @return[out] parse success and get a valid set_effecter_state_field
88  *               structure, return nullopt means parse failed
89  */
90 std::optional<std::vector<set_effecter_state_field>>
91     parseEffecterData(const std::vector<uint8_t>& effecterData,
92                       uint8_t effecterCount);
93 
94 /**
95  *  @brief creates an error log
96  *  @param[in] errorMsg - the error message
97  */
98 void reportError(const char* errorMsg);
99 
100 /** @brief Convert any Decimal number to BCD
101  *
102  *  @tparam[in] decimal - Decimal number
103  *  @return Corresponding BCD number
104  */
105 template <typename T>
106 T decimalToBcd(T decimal)
107 {
108     T bcd = 0;
109     T rem = 0;
110     auto cnt = 0;
111 
112     while (decimal)
113     {
114         rem = decimal % 10;
115         bcd = bcd + (rem << cnt);
116         decimal = decimal / 10;
117         cnt += 4;
118     }
119 
120     return bcd;
121 }
122 
123 constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
124 
125 struct DBusMapping
126 {
127     std::string objectPath;   //!< D-Bus object path
128     std::string interface;    //!< D-Bus interface
129     std::string propertyName; //!< D-Bus property name
130     std::string propertyType; //!< D-Bus property type
131 };
132 
133 using PropertyValue =
134     std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
135                  uint64_t, double, std::string>;
136 using DbusProp = std::string;
137 using DbusChangedProps = std::map<DbusProp, PropertyValue>;
138 
139 /**
140  * @brief The interface for DBusHandler
141  */
142 class DBusHandlerInterface
143 {
144   public:
145     virtual ~DBusHandlerInterface() = default;
146 
147     virtual void setDbusProperty(const DBusMapping& dBusMap,
148                                  const PropertyValue& value) const = 0;
149 
150     virtual PropertyValue
151         getDbusPropertyVariant(const char* objPath, const char* dbusProp,
152                                const char* dbusInterface) const = 0;
153 };
154 
155 /**
156  *  @class DBusHandler
157  *
158  *  Wrapper class to handle the D-Bus calls
159  *
160  *  This class contains the APIs to handle the D-Bus calls
161  *  to cater the request from pldm requester.
162  *  A class is created to mock the apis in the test cases
163  */
164 class DBusHandler : public DBusHandlerInterface
165 {
166   public:
167     /** @brief Get the bus connection. */
168     static auto& getBus()
169     {
170         static auto bus = sdbusplus::bus::new_default();
171         return bus;
172     }
173 
174     /**
175      *  @brief Get the DBUS Service name for the input dbus path
176      *
177      *  @param[in] path - DBUS object path
178      *  @param[in] interface - DBUS Interface
179      *
180      *  @return std::string - the dbus service name
181      *
182      *  @throw sdbusplus::exception::SdBusError when it fails
183      */
184     std::string getService(const char* path, const char* interface) const;
185 
186     /** @brief Get property(type: variant) from the requested dbus
187      *
188      *  @param[in] objPath - The Dbus object path
189      *  @param[in] dbusProp - The property name to get
190      *  @param[in] dbusInterface - The Dbus interface
191      *
192      *  @return The value of the property(type: variant)
193      *
194      *  @throw sdbusplus::exception::SdBusError when it fails
195      */
196     PropertyValue
197         getDbusPropertyVariant(const char* objPath, const char* dbusProp,
198                                const char* dbusInterface) const override;
199 
200     /** @brief The template function to get property from the requested dbus
201      *         path
202      *
203      *  @tparam Property - Excepted type of the property on dbus
204      *
205      *  @param[in] objPath - The Dbus object path
206      *  @param[in] dbusProp - The property name to get
207      *  @param[in] dbusInterface - The Dbus interface
208      *
209      *  @return The value of the property
210      *
211      *  @throw sdbusplus::exception::SdBusError when dbus request fails
212      *         std::bad_variant_access when \p Property and property on dbus do
213      *         not match
214      */
215     template <typename Property>
216     auto getDbusProperty(const char* objPath, const char* dbusProp,
217                          const char* dbusInterface)
218     {
219         auto VariantValue =
220             getDbusPropertyVariant(objPath, dbusProp, dbusInterface);
221         return std::get<Property>(VariantValue);
222     }
223 
224     /** @brief Set Dbus property
225      *
226      *  @param[in] dBusMap - Object path, property name, interface and property
227      *                       type for the D-Bus object
228      *  @param[in] value - The value to be set
229      *
230      *  @throw sdbusplus::exception::SdBusError when it fails
231      */
232     void setDbusProperty(const DBusMapping& dBusMap,
233                          const PropertyValue& value) const override;
234 };
235 
236 /** @brief Fetch parent D-Bus object based on pathname
237  *
238  *  @param[in] dbusObj - child D-Bus object
239  *
240  *  @return std::string - the parent D-Bus object path
241  */
242 inline std::string findParent(const std::string& dbusObj)
243 {
244     fs::path p(dbusObj);
245     return p.parent_path().string();
246 }
247 
248 /** @brief Read (static) MCTP EID of host firmware from a file
249  *
250  *  @return uint8_t - MCTP EID
251  */
252 uint8_t readHostEID();
253 
254 /** @brief Convert a value in the JSON to a D-Bus property value
255  *
256  *  @param[in] type - type of the D-Bus property
257  *  @param[in] value - value in the JSON file
258  *
259  *  @return PropertyValue - the D-Bus property value
260  */
261 PropertyValue jsonEntryToDbusVal(std::string_view type,
262                                  const nlohmann::json& value);
263 
264 /** @brief Find State Effecter PDR
265  *  @param[in] tid - PLDM terminus ID.
266  *  @param[in] entityID - entity that can be associated with PLDM State set.
267  *  @param[in] stateSetId - value that identifies PLDM State set.
268  *  @param[in] repo - pointer to BMC's primary PDR repo.
269  *  @return array[array[uint8_t]] - StateEffecterPDRs
270  */
271 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t tid,
272                                                        uint16_t entityID,
273                                                        uint16_t stateSetId,
274                                                        const pldm_pdr* repo);
275 /** @brief Find State Sensor PDR
276  *  @param[in] tid - PLDM terminus ID.
277  *  @param[in] entityID - entity that can be associated with PLDM State set.
278  *  @param[in] stateSetId - value that identifies PLDM State set.
279  *  @param[in] repo - pointer to BMC's primary PDR repo.
280  *  @return array[array[uint8_t]] - StateSensorPDRs
281  */
282 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t tid,
283                                                      uint16_t entityID,
284                                                      uint16_t stateSetId,
285                                                      const pldm_pdr* repo);
286 
287 /** @brief Find effecter id from a state effecter pdr
288  *  @param[in] pdrRepo - PDR repository
289  *  @param[in] entityType - entity type
290  *  @param[in] entityInstance - entity instance number
291  *  @param[in] containerId - container id
292  *  @param[in] stateSetId - state set id
293  *
294  *  @return uint16_t - the effecter id
295  */
296 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType,
297                              uint16_t entityInstance, uint16_t containerId,
298                              uint16_t stateSetId);
299 
300 } // namespace utils
301 } // namespace pldm
302