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