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