xref: /openbmc/bios-settings-mgr/src/manager.cpp (revision 4e29f80bf85c3a8197bb6c3183f25face059f29c)
1 /*
2  Copyright (c) 2020 Intel Corporation
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8       http:www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 #include "manager.hpp"
18 
19 #include "manager_serialize.hpp"
20 #include "xyz/openbmc_project/BIOSConfig/Common/error.hpp"
21 #include "xyz/openbmc_project/Common/error.hpp"
22 
23 #include <boost/asio.hpp>
24 #include <phosphor-logging/elog-errors.hpp>
25 #include <phosphor-logging/lg2.hpp>
26 #include <sdbusplus/asio/connection.hpp>
27 #include <sdbusplus/asio/object_server.hpp>
28 
29 namespace bios_config
30 {
31 
32 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
33 using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
34 
setAttribute(AttributeName attribute,AttributeValue value)35 void Manager::setAttribute(AttributeName attribute, AttributeValue value)
36 {
37     auto pendingAttrs = Base::pendingAttributes();
38     auto iter = pendingAttrs.find(attribute);
39 
40     if (iter != pendingAttrs.end())
41     {
42         std::get<1>(iter->second) = value;
43     }
44     else
45     {
46         Manager::PendingAttribute attributeValue;
47 
48         if (std::get_if<int64_t>(&value))
49         {
50             std::get<0>(attributeValue) = AttributeType::Integer;
51         }
52         else
53         {
54             std::get<0>(attributeValue) = AttributeType::String;
55         }
56 
57         std::get<1>(attributeValue) = value;
58         pendingAttrs.emplace(attribute, attributeValue);
59     }
60 
61     pendingAttributes(pendingAttrs);
62 }
63 
getAttribute(AttributeName attribute)64 Manager::AttributeDetails Manager::getAttribute(AttributeName attribute)
65 {
66     Manager::AttributeDetails value;
67 
68     auto table = Base::baseBIOSTable();
69     auto iter = table.find(attribute);
70 
71     if (iter != table.end())
72     {
73         std::get<0>(value) =
74             std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
75         std::get<1>(value) =
76             std::get<static_cast<uint8_t>(Index::currentValue)>(iter->second);
77 
78         auto pending = Base::pendingAttributes();
79         auto pendingIter = pending.find(attribute);
80         if (pendingIter != pending.end())
81         {
82             std::get<2>(value) = std::get<1>(pendingIter->second);
83         }
84         else if (std::get_if<std::string>(&std::get<1>(value)))
85         {
86             std::get<2>(value) = std::string();
87         }
88     }
89     else
90     {
91         throw AttributeNotFound();
92     }
93 
94     return value;
95 }
96 
baseBIOSTable(BaseTable value)97 Manager::BaseTable Manager::baseBIOSTable(BaseTable value)
98 {
99     pendingAttributes({});
100     auto baseTable = Base::baseBIOSTable(value, false);
101     serialize(*this, biosFile);
102     Base::resetBIOSSettings(Base::ResetFlag::NoAction);
103     return baseTable;
104 }
105 
validateEnumOption(const std::string & attrValue,const std::vector<std::tuple<BoundType,std::variant<int64_t,std::string>,std::string>> & options)106 bool Manager::validateEnumOption(
107     const std::string& attrValue,
108     const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>,
109                                  std::string>>& options)
110 {
111     for (const auto& enumOptions : options)
112     {
113         if ((BoundType::OneOf == std::get<0>(enumOptions)) &&
114             (attrValue == std::get<std::string>(std::get<1>(enumOptions))))
115         {
116             return true;
117         }
118     }
119 
120     lg2::error("No valid attribute");
121     return false;
122 }
123 
validateStringOption(const std::string & attrValue,const std::vector<std::tuple<BoundType,std::variant<int64_t,std::string>,std::string>> & options)124 bool Manager::validateStringOption(
125     const std::string& attrValue,
126     const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>,
127                                  std::string>>& options)
128 {
129     size_t minStringLength = 0;
130     size_t maxStringLength = 0;
131     for (const auto& stringOptions : options)
132     {
133         if (BoundType::MinStringLength == std::get<0>(stringOptions))
134         {
135             minStringLength = std::get<int64_t>(std::get<1>(stringOptions));
136         }
137         else if (BoundType::MaxStringLength == std::get<0>(stringOptions))
138         {
139             maxStringLength = std::get<int64_t>(std::get<1>(stringOptions));
140         }
141         else
142         {
143             continue;
144         }
145     }
146 
147     if (attrValue.length() < minStringLength ||
148         attrValue.length() > maxStringLength)
149     {
150         lg2::error(
151             "{ATTRVALUE} Length is out of range, bound is invalid, maxStringLength = {MAXLEN}, minStringLength = {MINLEN}",
152             "ATTRVALUE", attrValue, "MAXLEN", maxStringLength, "MINLEN",
153             minStringLength);
154         return false;
155     }
156 
157     return true;
158 }
159 
validateIntegerOption(const int64_t & attrValue,const std::vector<std::tuple<BoundType,std::variant<int64_t,std::string>,std::string>> & options)160 bool Manager::validateIntegerOption(
161     const int64_t& attrValue,
162     const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>,
163                                  std::string>>& options)
164 {
165     int64_t lowerBound = 0;
166     int64_t upperBound = 0;
167     int64_t scalarIncrement = 0;
168 
169     for (const auto& integerOptions : options)
170     {
171         if (BoundType::LowerBound == std::get<0>(integerOptions))
172         {
173             lowerBound = std::get<int64_t>(std::get<1>(integerOptions));
174         }
175         else if (BoundType::UpperBound == std::get<0>(integerOptions))
176         {
177             upperBound = std::get<int64_t>(std::get<1>(integerOptions));
178         }
179         else if (BoundType::ScalarIncrement == std::get<0>(integerOptions))
180         {
181             scalarIncrement = std::get<int64_t>(std::get<1>(integerOptions));
182         }
183     }
184 
185     if ((attrValue < lowerBound) || (attrValue > upperBound))
186     {
187         lg2::error("Integer, bound is invalid");
188         return false;
189     }
190 
191     if (scalarIncrement == 0 ||
192         ((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
193     {
194         lg2::error(
195             "((std::abs({ATTR_VALUE} - {LOWER_BOUND})) % {SCALAR_INCREMENT}) != 0",
196             "ATTR_VALUE", attrValue, "LOWER_BOUND", lowerBound,
197             "SCALAR_INCREMENT", scalarIncrement);
198         return false;
199     }
200 
201     return true;
202 }
203 
pendingAttributes(PendingAttributes value)204 Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value)
205 {
206     // Clear the pending attributes
207     if (value.empty())
208     {
209         auto pendingAttrs = Base::pendingAttributes({}, false);
210         serialize(*this, biosFile);
211         return pendingAttrs;
212     }
213 
214     // Validate all the BIOS attributes before setting PendingAttributes
215     BaseTable biosTable = Base::baseBIOSTable();
216     for (const auto& pair : value)
217     {
218         auto iter = biosTable.find(pair.first);
219         // BIOS attribute not found in the BaseBIOSTable
220         if (iter == biosTable.end())
221         {
222             lg2::error("BIOS attribute not found in the BaseBIOSTable");
223             throw AttributeNotFound();
224         }
225 
226         auto attributeType =
227             std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
228         if (attributeType != std::get<0>(pair.second))
229         {
230             lg2::error("attributeType is not same with bios base table");
231             throw InvalidArgument();
232         }
233 
234         // Validate enumeration BIOS attributes
235         if (attributeType == AttributeType::Enumeration)
236         {
237             // For enumeration the expected variant types is Enumeration
238             if (std::get<1>(pair.second).index() == 0)
239             {
240                 lg2::error("Enumeration property value is not enum");
241                 throw InvalidArgument();
242             }
243 
244             const auto& attrValue =
245                 std::get<std::string>(std::get<1>(pair.second));
246             const auto& options =
247                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
248 
249             if (!validateEnumOption(attrValue, options))
250             {
251                 throw InvalidArgument();
252             }
253         }
254 
255         if (attributeType == AttributeType::String)
256         {
257             // For enumeration the expected variant types is std::string
258             if (std::get<1>(pair.second).index() == 0)
259             {
260                 lg2::error("String property value is not string");
261                 throw InvalidArgument();
262             }
263 
264             const auto& attrValue =
265                 std::get<std::string>(std::get<1>(pair.second));
266             const auto& options =
267                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
268 
269             if (!validateStringOption(attrValue, options))
270             {
271                 throw InvalidArgument();
272             }
273         }
274 
275         if (attributeType == AttributeType::Integer)
276         {
277             // For enumeration the expected variant types is Integer
278             if (std::get<1>(pair.second).index() == 1)
279             {
280                 lg2::error("Integer property value is not int");
281                 throw InvalidArgument();
282             }
283 
284             const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second));
285             const auto& options =
286                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
287 
288             if (!validateIntegerOption(attrValue, options))
289             {
290                 throw InvalidArgument();
291             }
292         }
293     }
294 
295     PendingAttributes pendingAttribute = Base::pendingAttributes();
296 
297     for (const auto& pair : value)
298     {
299         auto iter = pendingAttribute.find(pair.first);
300         if (iter != pendingAttribute.end())
301         {
302             iter = pendingAttribute.erase(iter);
303         }
304 
305         pendingAttribute.emplace(std::make_pair(pair.first, pair.second));
306     }
307 
308     auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false);
309     serialize(*this, biosFile);
310 
311     return pendingAttrs;
312 }
313 
convertBiosDataToVersion1(Manager::oldBaseTable biosTbl,Manager::BaseTable & baseTable)314 void Manager::convertBiosDataToVersion1(Manager::oldBaseTable biosTbl,
315                                         Manager::BaseTable& baseTable)
316 {
317     lg2::error("convertBiosDataToVersion1");
318     for (const auto& [key, baseTuple] : biosTbl)
319     {
320         const auto& vec = std::get<7>(baseTuple);
321         std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>,
322                                std::string>>
323             dataVec;
324 
325         for (const auto& [value, variantVal] : vec)
326         {
327             dataVec.emplace_back(value, variantVal,
328                                  ""); // Copy VDN as empty string
329         }
330 
331         if (std::get<0>(baseTuple) == AttributeType::Integer)
332         {
333             baseTable[key] = std::make_tuple(
334                 std::get<0>(baseTuple), std::get<1>(baseTuple),
335                 std::get<2>(baseTuple), std::get<3>(baseTuple),
336                 std::get<4>(baseTuple),
337                 std::get<int64_t>(std::get<5>(baseTuple)),
338                 std::get<int64_t>(std::get<6>(baseTuple)), dataVec);
339         }
340         else
341         {
342             baseTable[key] = std::make_tuple(
343                 std::get<0>(baseTuple), std::get<1>(baseTuple),
344                 std::get<2>(baseTuple), std::get<3>(baseTuple),
345                 std::get<4>(baseTuple),
346                 std::get<std::string>(std::get<5>(baseTuple)),
347                 std::get<std::string>(std::get<6>(baseTuple)), dataVec);
348         }
349     }
350 }
351 
convertBiosDataToVersion0(Manager::oldBaseTable & baseTable,Manager::BaseTable & biosTbl)352 void Manager::convertBiosDataToVersion0(Manager::oldBaseTable& baseTable,
353                                         Manager::BaseTable& biosTbl)
354 {
355     lg2::error("convertBiosDataToVersion0");
356     for (const auto& [key, baseTuple] : biosTbl)
357     {
358         const auto& vec = std::get<7>(baseTuple);
359         std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>>>
360             dataVec;
361 
362         for (const auto& [value, variantVal, vDisplayName] : vec)
363         {
364             dataVec.emplace_back(value, variantVal); // Remove VDN
365         }
366 
367         if (std::get<0>(baseTuple) == AttributeType::Integer)
368         {
369             baseTable[key] = std::make_tuple(
370                 std::get<0>(baseTuple), std::get<1>(baseTuple),
371                 std::get<2>(baseTuple), std::get<3>(baseTuple),
372                 std::get<4>(baseTuple),
373                 std::get<int64_t>(std::get<5>(baseTuple)),
374                 std::get<int64_t>(std::get<6>(baseTuple)), dataVec);
375         }
376         else
377         {
378             baseTable[key] = std::make_tuple(
379                 std::get<0>(baseTuple), std::get<1>(baseTuple),
380                 std::get<2>(baseTuple), std::get<3>(baseTuple),
381                 std::get<4>(baseTuple),
382                 std::get<std::string>(std::get<5>(baseTuple)),
383                 std::get<std::string>(std::get<6>(baseTuple)), dataVec);
384         }
385     }
386 }
387 
Manager(sdbusplus::asio::object_server & objectServer,std::shared_ptr<sdbusplus::asio::connection> & systemBus,std::string persistPath)388 Manager::Manager(sdbusplus::asio::object_server& objectServer,
389                  std::shared_ptr<sdbusplus::asio::connection>& systemBus,
390                  std::string persistPath) :
391     sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(
392         *systemBus, objectPath),
393     objServer(objectServer), systemBus(systemBus)
394 {
395     fs::path biosDir(persistPath);
396     fs::create_directories(biosDir);
397     biosFile = biosDir / biosPersistFile;
398     deserialize(biosFile, *this);
399 }
400 
401 } // namespace bios_config
402