1 #pragma once
2 
3 #include "bios_table.h"
4 
5 #include "bios_attribute.hpp"
6 #include "bios_table.hpp"
7 #include "pldmd/dbus_impl_requester.hpp"
8 
9 #include <nlohmann/json.hpp>
10 
11 #include <functional>
12 #include <iostream>
13 #include <memory>
14 #include <optional>
15 #include <set>
16 #include <string>
17 #include <vector>
18 
19 namespace pldm
20 {
21 namespace responder
22 {
23 namespace bios
24 {
25 
26 enum class BoundType
27 {
28     LowerBound,
29     UpperBound,
30     ScalarIncrement,
31     MinStringLength,
32     MaxStringLength,
33     OneOf
34 };
35 
36 using AttributeName = std::string;
37 using AttributeType = std::string;
38 using ReadonlyStatus = bool;
39 using DisplayName = std::string;
40 using Description = std::string;
41 using MenuPath = std::string;
42 using CurrentValue = std::variant<int64_t, std::string>;
43 using DefaultValue = std::variant<int64_t, std::string>;
44 using OptionString = std::string;
45 using OptionValue = std::variant<int64_t, std::string>;
46 using Option = std::vector<std::tuple<OptionString, OptionValue>>;
47 using BIOSTableObj =
48     std::tuple<AttributeType, ReadonlyStatus, DisplayName, Description,
49                MenuPath, CurrentValue, DefaultValue, Option>;
50 using BaseBIOSTable = std::map<AttributeName, BIOSTableObj>;
51 
52 using PendingObj = std::tuple<AttributeType, CurrentValue>;
53 using PendingAttributes = std::map<AttributeName, PendingObj>;
54 
55 /** @class BIOSConfig
56  *  @brief Manager BIOS Attributes
57  */
58 class BIOSConfig
59 {
60   public:
61     BIOSConfig() = delete;
62     BIOSConfig(const BIOSConfig&) = delete;
63     BIOSConfig(BIOSConfig&&) = delete;
64     BIOSConfig& operator=(const BIOSConfig&) = delete;
65     BIOSConfig& operator=(BIOSConfig&&) = delete;
66     ~BIOSConfig() = default;
67 
68     /** @brief Construct BIOSConfig
69      *  @param[in] jsonDir - The directory where json file exists
70      *  @param[in] tableDir - The directory where the persistent table is placed
71      *  @param[in] dbusHandler - Dbus Handler
72      *  @param[in] fd - socket descriptor to communicate to host
73      *  @param[in] eid - MCTP EID of host firmware
74      *  @param[in] requester - pointer to Requester object
75      */
76     explicit BIOSConfig(const char* jsonDir, const char* tableDir,
77                         DBusHandler* const dbusHandler, int fd, uint8_t eid,
78                         dbus_api::Requester* requester);
79 
80     /** @brief Set attribute value on dbus and attribute value table
81      *  @param[in] entry - attribute value entry
82      *  @param[in] size - size of the attribute value entry
83      *  @param[in] updateBaseBIOSTable - update BaseBIOSTable D-Bus property
84      *                                   if this is set to true
85      *  @return pldm_completion_codes
86      */
87     int setAttrValue(const void* entry, size_t size,
88                      bool updateBaseBIOSTable = true);
89 
90     /** @brief Remove the persistent tables */
91     void removeTables();
92 
93     /** @brief Build bios tables(string,attribute,attribute value table)*/
94     void buildTables();
95 
96     /** @brief Get BIOS table of specified type
97      *  @param[in] tableType - The table type
98      *  @return The bios table, std::nullopt if the table is unaviliable
99      */
100     std::optional<Table> getBIOSTable(pldm_bios_table_types tableType);
101 
102     /** @brief set BIOS table
103      *  @param[in] tableType - Indicates what table is being transferred
104      *             {BIOSStringTable=0x0, BIOSAttributeTable=0x1,
105      *              BIOSAttributeValueTable=0x2}
106      *  @param[in] table - table data
107      *  @param[in] updateBaseBIOSTable - update BaseBIOSTable D-Bus property
108      *                                   if this is set to true
109      *  @return pldm_completion_codes
110      */
111     int setBIOSTable(uint8_t tableType, const Table& table,
112                      bool updateBaseBIOSTable = true);
113 
114   private:
115     /** @enum Index into the fields in the BaseBIOSTable
116      */
117     enum class Index : uint8_t
118     {
119         attributeType = 0,
120         readOnly,
121         displayName,
122         description,
123         menuPath,
124         currentValue,
125         defaultValue,
126         options,
127     };
128 
129     const fs::path jsonDir;
130     const fs::path tableDir;
131     DBusHandler* const dbusHandler;
132     BaseBIOSTable baseBIOSTableMaps;
133 
134     /** @brief socket descriptor to communicate to host */
135     int fd;
136 
137     /** @brief MCTP EID of host firmware */
138     uint8_t eid;
139 
140     /** @brief pointer to Requester object, primarily used to access API to
141      *  obtain PLDM instance id.
142      */
143     dbus_api::Requester* requester;
144 
145     // vector persists all attributes
146     using BIOSAttributes = std::vector<std::unique_ptr<BIOSAttribute>>;
147     BIOSAttributes biosAttributes;
148 
149     using propName = std::string;
150     using DbusChObjProperties = std::map<propName, PropertyValue>;
151 
152     // vector to catch the D-Bus property change signals for BIOS attributes
153     std::vector<std::unique_ptr<sdbusplus::bus::match::match>> biosAttrMatch;
154 
155     /** @brief Method to update a BIOS attribute when the corresponding Dbus
156      *  property is changed
157      *  @param[in] chProperties - list of properties which have changed
158      *  @param[in] biosAttrIndex - Index of BIOSAttribute pointer in
159      * biosAttributes
160      *  @return - none
161      */
162     void processBiosAttrChangeNotification(
163         const DbusChObjProperties& chProperties, uint32_t biosAttrIndex);
164 
165     /** @brief Construct an attribute and persist it
166      *  @tparam T - attribute type
167      *  @param[in] entry - json entry
168      */
169     template <typename T>
170     void constructAttribute(const Json& entry)
171     {
172         try
173         {
174             biosAttributes.push_back(std::make_unique<T>(entry, dbusHandler));
175             auto biosAttrIndex = biosAttributes.size() - 1;
176             auto dBusMap = biosAttributes[biosAttrIndex]->getDBusMap();
177 
178             if (dBusMap.has_value())
179             {
180                 using namespace sdbusplus::bus::match::rules;
181                 biosAttrMatch.push_back(
182                     std::make_unique<sdbusplus::bus::match::match>(
183                         pldm::utils::DBusHandler::getBus(),
184                         propertiesChanged(dBusMap->objectPath,
185                                           dBusMap->interface),
186                         [this,
187                          biosAttrIndex](sdbusplus::message::message& msg) {
188                             DbusChObjProperties props;
189                             std::string iface;
190                             msg.read(iface, props);
191                             processBiosAttrChangeNotification(props,
192                                                               biosAttrIndex);
193                         }));
194             }
195         }
196         catch (const std::exception& e)
197         {
198             std::cerr << "Constructs Attribute Error, " << e.what()
199                       << std::endl;
200         }
201     }
202 
203     /** Construct attributes and persist them */
204     void constructAttributes();
205 
206     using ParseHandler = std::function<void(const Json& entry)>;
207 
208     /** @brief Helper function to parse json
209      *  @param[in] filePath - Path of json file
210      *  @param[in] handler - Handler to process each entry in the json
211      */
212     void load(const fs::path& filePath, ParseHandler handler);
213 
214     /** @brief Build String Table and persist it
215      *  @return The built string table, std::nullopt if it fails.
216      */
217     std::optional<Table> buildAndStoreStringTable();
218 
219     /** @brief Build attribute table and attribute value table and persist them
220      *         Read the BaseBIOSTable from the bios-settings-manager and update
221      *         attribute table and attribute value table.
222      *
223      *  @param[in] stringTable - The string Table
224      */
225     void buildAndStoreAttrTables(const Table& stringTable);
226 
227     /** @brief Persist the table
228      *  @param[in] path - Path to persist the table
229      *  @param[in] table - The table
230      */
231     void storeTable(const fs::path& path, const Table& table);
232 
233     /** @brief Load bios table to ram
234      *  @param[in] path - Path of the table
235      *  @return The table, std::nullopt if loading fails
236      */
237     std::optional<Table> loadTable(const fs::path& path);
238 
239     /** @brief Check the attribute value to update
240      *  @param[in] attrValueEntry - The attribute value entry to update
241      *  @param[in] attrEntry - The attribute table entry
242      *  @param[in] stringTable - The string  table
243      *  @return pldm_completion_codes
244      */
245     int checkAttrValueToUpdate(
246         const pldm_bios_attr_val_table_entry* attrValueEntry,
247         const pldm_bios_attr_table_entry* attrEntry, Table& stringTable);
248 
249     /** @brief Check the attribute table
250      *  @param[in] table - The table
251      *  @return pldm_completion_codes
252      */
253     int checkAttributeTable(const Table& table);
254 
255     /** @brief Check the attribute value table
256      *  @param[in] table - The table
257      *  @return pldm_completion_codes
258      */
259     int checkAttributeValueTable(const Table& table);
260 
261     /** @brief Update the BaseBIOSTable property of the D-Bus interface
262      */
263     void updateBaseBIOSTableProperty();
264 
265     /** @brief Listen the PendingAttributes property of the D-Bus interface and
266      *         update BaseBIOSTable
267      */
268     void listenPendingAttributes();
269 
270     /** @brief Find attribute handle from bios attribute table
271      *  @param[in] attrName - attribute name
272      *  @return attribute handle
273      */
274     uint16_t findAttrHandle(const std::string& attrName);
275 
276     /** @brief Listen the PendingAttributes property of the D-Bus interface
277      * and update BaseBIOSTable
278      *  @param[in] msg - Data associated with subscribed signal
279      */
280     void constructPendingAttribute(const PendingAttributes& pendingAttributes);
281 };
282 
283 } // namespace bios
284 } // namespace responder
285 } // namespace pldm
286