xref: /openbmc/pldm/common/utils.hpp (revision a792b216)
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 std::string getService(const char* path,
148                                    const char* interface) const = 0;
149 
150     virtual void setDbusProperty(const DBusMapping& dBusMap,
151                                  const PropertyValue& value) const = 0;
152 
153     virtual PropertyValue
154         getDbusPropertyVariant(const char* objPath, const char* dbusProp,
155                                const char* dbusInterface) const = 0;
156 };
157 
158 /**
159  *  @class DBusHandler
160  *
161  *  Wrapper class to handle the D-Bus calls
162  *
163  *  This class contains the APIs to handle the D-Bus calls
164  *  to cater the request from pldm requester.
165  *  A class is created to mock the apis in the test cases
166  */
167 class DBusHandler : public DBusHandlerInterface
168 {
169   public:
170     /** @brief Get the bus connection. */
171     static auto& getBus()
172     {
173         static auto bus = sdbusplus::bus::new_default();
174         return bus;
175     }
176 
177     /**
178      *  @brief Get the DBUS Service name for the input dbus path
179      *
180      *  @param[in] path - DBUS object path
181      *  @param[in] interface - DBUS Interface
182      *
183      *  @return std::string - the dbus service name
184      *
185      *  @throw sdbusplus::exception::SdBusError when it fails
186      */
187     std::string getService(const char* path,
188                            const char* interface) const override;
189 
190     /** @brief Get property(type: variant) from the requested dbus
191      *
192      *  @param[in] objPath - The Dbus object path
193      *  @param[in] dbusProp - The property name to get
194      *  @param[in] dbusInterface - The Dbus interface
195      *
196      *  @return The value of the property(type: variant)
197      *
198      *  @throw sdbusplus::exception::SdBusError when it fails
199      */
200     PropertyValue
201         getDbusPropertyVariant(const char* objPath, const char* dbusProp,
202                                const char* dbusInterface) const override;
203 
204     /** @brief The template function to get property from the requested dbus
205      *         path
206      *
207      *  @tparam Property - Excepted type of the property on dbus
208      *
209      *  @param[in] objPath - The Dbus object path
210      *  @param[in] dbusProp - The property name to get
211      *  @param[in] dbusInterface - The Dbus interface
212      *
213      *  @return The value of the property
214      *
215      *  @throw sdbusplus::exception::SdBusError when dbus request fails
216      *         std::bad_variant_access when \p Property and property on dbus do
217      *         not match
218      */
219     template <typename Property>
220     auto getDbusProperty(const char* objPath, const char* dbusProp,
221                          const char* dbusInterface)
222     {
223         auto VariantValue =
224             getDbusPropertyVariant(objPath, dbusProp, dbusInterface);
225         return std::get<Property>(VariantValue);
226     }
227 
228     /** @brief Set Dbus property
229      *
230      *  @param[in] dBusMap - Object path, property name, interface and property
231      *                       type for the D-Bus object
232      *  @param[in] value - The value to be set
233      *
234      *  @throw sdbusplus::exception::SdBusError when it fails
235      */
236     void setDbusProperty(const DBusMapping& dBusMap,
237                          const PropertyValue& value) const override;
238 };
239 
240 /** @brief Fetch parent D-Bus object based on pathname
241  *
242  *  @param[in] dbusObj - child D-Bus object
243  *
244  *  @return std::string - the parent D-Bus object path
245  */
246 inline std::string findParent(const std::string& dbusObj)
247 {
248     fs::path p(dbusObj);
249     return p.parent_path().string();
250 }
251 
252 /** @brief Read (static) MCTP EID of host firmware from a file
253  *
254  *  @return uint8_t - MCTP EID
255  */
256 uint8_t readHostEID();
257 
258 /** @brief Convert a value in the JSON to a D-Bus property value
259  *
260  *  @param[in] type - type of the D-Bus property
261  *  @param[in] value - value in the JSON file
262  *
263  *  @return PropertyValue - the D-Bus property value
264  */
265 PropertyValue jsonEntryToDbusVal(std::string_view type,
266                                  const nlohmann::json& value);
267 
268 /** @brief Find State Effecter PDR
269  *  @param[in] tid - PLDM terminus ID.
270  *  @param[in] entityID - entity that can be associated with PLDM State set.
271  *  @param[in] stateSetId - value that identifies PLDM State set.
272  *  @param[in] repo - pointer to BMC's primary PDR repo.
273  *  @return array[array[uint8_t]] - StateEffecterPDRs
274  */
275 std::vector<std::vector<uint8_t>> findStateEffecterPDR(uint8_t tid,
276                                                        uint16_t entityID,
277                                                        uint16_t stateSetId,
278                                                        const pldm_pdr* repo);
279 /** @brief Find State Sensor PDR
280  *  @param[in] tid - PLDM terminus ID.
281  *  @param[in] entityID - entity that can be associated with PLDM State set.
282  *  @param[in] stateSetId - value that identifies PLDM State set.
283  *  @param[in] repo - pointer to BMC's primary PDR repo.
284  *  @return array[array[uint8_t]] - StateSensorPDRs
285  */
286 std::vector<std::vector<uint8_t>> findStateSensorPDR(uint8_t tid,
287                                                      uint16_t entityID,
288                                                      uint16_t stateSetId,
289                                                      const pldm_pdr* repo);
290 
291 /** @brief Find effecter id from a state effecter pdr
292  *  @param[in] pdrRepo - PDR repository
293  *  @param[in] entityType - entity type
294  *  @param[in] entityInstance - entity instance number
295  *  @param[in] containerId - container id
296  *  @param[in] stateSetId - state set id
297  *  @param[in] localOrRemote - true for checking local repo and false for remote
298  *                             repo
299  *
300  *  @return uint16_t - the effecter id
301  */
302 uint16_t findStateEffecterId(const pldm_pdr* pdrRepo, uint16_t entityType,
303                              uint16_t entityInstance, uint16_t containerId,
304                              uint16_t stateSetId, bool localOrRemote);
305 
306 /** @brief Emit the sensor event signal
307  *
308  *	@param[in] tid - the terminus id
309  *  @param[in] sensorId - sensorID value of the sensor
310  *  @param[in] sensorOffset - Identifies which state sensor within a
311  * composite state sensor the event is being returned for
312  *  @param[in] eventState - The event state value from the state change that
313  * triggered the event message
314  *  @param[in] previousEventState - The event state value for the state from
315  * which the present event state was entered.
316  *  @return PLDM completion code
317  */
318 int emitStateSensorEventSignal(uint8_t tid, uint16_t sensorId,
319                                uint8_t sensorOffset, uint8_t eventState,
320                                uint8_t previousEventState);
321 
322 } // namespace utils
323 } // namespace pldm
324