xref: /openbmc/bios-settings-mgr/src/manager.cpp (revision 1a448ad8)
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 #include "manager.hpp"
17 
18 #include "manager_serialize.hpp"
19 #include "xyz/openbmc_project/BIOSConfig/Common/error.hpp"
20 #include "xyz/openbmc_project/Common/error.hpp"
21 
22 #include <boost/asio.hpp>
23 #include <phosphor-logging/elog-errors.hpp>
24 #include <phosphor-logging/lg2.hpp>
25 #include <sdbusplus/asio/connection.hpp>
26 #include <sdbusplus/asio/object_server.hpp>
27 
28 namespace bios_config
29 {
30 
31 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
32 using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
33 
setAttribute(AttributeName attribute,AttributeValue value)34 void Manager::setAttribute(AttributeName attribute, AttributeValue value)
35 {
36     auto pendingAttrs = Base::pendingAttributes();
37     auto iter = pendingAttrs.find(attribute);
38 
39     if (iter != pendingAttrs.end())
40     {
41         std::get<1>(iter->second) = value;
42     }
43     else
44     {
45         Manager::PendingAttribute attributeValue;
46 
47         if (std::get_if<int64_t>(&value))
48         {
49             std::get<0>(attributeValue) = AttributeType::Integer;
50         }
51         else
52         {
53             std::get<0>(attributeValue) = AttributeType::String;
54         }
55 
56         std::get<1>(attributeValue) = value;
57         pendingAttrs.emplace(attribute, attributeValue);
58     }
59 
60     pendingAttributes(pendingAttrs);
61 }
62 
getAttribute(AttributeName attribute)63 Manager::AttributeDetails Manager::getAttribute(AttributeName attribute)
64 {
65     Manager::AttributeDetails value;
66 
67     auto table = Base::baseBIOSTable();
68     auto iter = table.find(attribute);
69 
70     if (iter != table.end())
71     {
72         std::get<0>(value) =
73             std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
74         std::get<1>(value) =
75             std::get<static_cast<uint8_t>(Index::currentValue)>(iter->second);
76 
77         auto pending = Base::pendingAttributes();
78         auto pendingIter = pending.find(attribute);
79         if (pendingIter != pending.end())
80         {
81             std::get<2>(value) = std::get<1>(pendingIter->second);
82         }
83         else if (std::get_if<std::string>(&std::get<1>(value)))
84         {
85             std::get<2>(value) = std::string();
86         }
87     }
88     else
89     {
90         throw AttributeNotFound();
91     }
92 
93     return value;
94 }
95 
baseBIOSTable(BaseTable value)96 Manager::BaseTable Manager::baseBIOSTable(BaseTable value)
97 {
98     pendingAttributes({});
99     auto baseTable = Base::baseBIOSTable(value, false);
100     serialize(*this, biosFile);
101     Base::resetBIOSSettings(Base::ResetFlag::NoAction);
102     return baseTable;
103 }
104 
validateEnumOption(const std::string & attrValue,const std::vector<std::tuple<BoundType,std::variant<int64_t,std::string>,std::string>> & options)105 bool Manager::validateEnumOption(
106     const std::string& attrValue,
107     const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>,
108                                  std::string>>& options)
109 {
110     for (const auto& enumOptions : options)
111     {
112         if ((BoundType::OneOf == std::get<0>(enumOptions)) &&
113             (attrValue == std::get<std::string>(std::get<1>(enumOptions))))
114         {
115             return true;
116         }
117     }
118 
119     lg2::error("No valid attribute");
120     return false;
121 }
122 
validateStringOption(const std::string & attrValue,const std::vector<std::tuple<BoundType,std::variant<int64_t,std::string>,std::string>> & options)123 bool Manager::validateStringOption(
124     const std::string& attrValue,
125     const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>,
126                                  std::string>>& options)
127 {
128     size_t minStringLength = 0;
129     size_t maxStringLength = 0;
130     for (const auto& stringOptions : options)
131     {
132         if (BoundType::MinStringLength == std::get<0>(stringOptions))
133         {
134             minStringLength = std::get<int64_t>(std::get<1>(stringOptions));
135         }
136         else if (BoundType::MaxStringLength == std::get<0>(stringOptions))
137         {
138             maxStringLength = std::get<int64_t>(std::get<1>(stringOptions));
139         }
140         else
141         {
142             continue;
143         }
144     }
145 
146     if (attrValue.length() < minStringLength ||
147         attrValue.length() > maxStringLength)
148     {
149         lg2::error(
150             "{ATTRVALUE} Length is out of range, bound is invalid, maxStringLength = {MAXLEN}, minStringLength = {MINLEN}",
151             "ATTRVALUE", attrValue, "MAXLEN", maxStringLength, "MINLEN",
152             minStringLength);
153         return false;
154     }
155 
156     return true;
157 }
158 
validateIntegerOption(const int64_t & attrValue,const std::vector<std::tuple<BoundType,std::variant<int64_t,std::string>,std::string>> & options)159 bool Manager::validateIntegerOption(
160     const int64_t& attrValue,
161     const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>,
162                                  std::string>>& options)
163 {
164     int64_t lowerBound = 0;
165     int64_t upperBound = 0;
166     int64_t scalarIncrement = 0;
167 
168     for (const auto& integerOptions : options)
169     {
170         if (BoundType::LowerBound == std::get<0>(integerOptions))
171         {
172             lowerBound = std::get<int64_t>(std::get<1>(integerOptions));
173         }
174         else if (BoundType::UpperBound == std::get<0>(integerOptions))
175         {
176             upperBound = std::get<int64_t>(std::get<1>(integerOptions));
177         }
178         else if (BoundType::ScalarIncrement == std::get<0>(integerOptions))
179         {
180             scalarIncrement = std::get<int64_t>(std::get<1>(integerOptions));
181         }
182     }
183 
184     if ((attrValue < lowerBound) || (attrValue > upperBound))
185     {
186         lg2::error("Integer, bound is invalid");
187         return false;
188     }
189 
190     if (scalarIncrement == 0 ||
191         ((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
192     {
193         lg2::error(
194             "((std::abs({ATTR_VALUE} - {LOWER_BOUND})) % {SCALAR_INCREMENT}) != 0",
195             "ATTR_VALUE", attrValue, "LOWER_BOUND", lowerBound,
196             "SCALAR_INCREMENT", scalarIncrement);
197         return false;
198     }
199 
200     return true;
201 }
202 
pendingAttributes(PendingAttributes value)203 Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value)
204 {
205     // Clear the pending attributes
206     if (value.empty())
207     {
208         auto pendingAttrs = Base::pendingAttributes({}, false);
209         serialize(*this, biosFile);
210         return pendingAttrs;
211     }
212 
213     // Validate all the BIOS attributes before setting PendingAttributes
214     BaseTable biosTable = Base::baseBIOSTable();
215     for (const auto& pair : value)
216     {
217         auto iter = biosTable.find(pair.first);
218         // BIOS attribute not found in the BaseBIOSTable
219         if (iter == biosTable.end())
220         {
221             lg2::error("BIOS attribute not found in the BaseBIOSTable");
222             throw AttributeNotFound();
223         }
224 
225         auto attributeType =
226             std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
227         if (attributeType != std::get<0>(pair.second))
228         {
229             lg2::error("attributeType is not same with bios base table");
230             throw InvalidArgument();
231         }
232 
233         // Validate enumeration BIOS attributes
234         if (attributeType == AttributeType::Enumeration)
235         {
236             // For enumeration the expected variant types is Enumeration
237             if (std::get<1>(pair.second).index() == 0)
238             {
239                 lg2::error("Enumeration property value is not enum");
240                 throw InvalidArgument();
241             }
242 
243             const auto& attrValue =
244                 std::get<std::string>(std::get<1>(pair.second));
245             const auto& options =
246                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
247 
248             if (!validateEnumOption(attrValue, options))
249             {
250                 throw InvalidArgument();
251             }
252         }
253 
254         if (attributeType == AttributeType::String)
255         {
256             // For enumeration the expected variant types is std::string
257             if (std::get<1>(pair.second).index() == 0)
258             {
259                 lg2::error("String property value is not string");
260                 throw InvalidArgument();
261             }
262 
263             const auto& attrValue =
264                 std::get<std::string>(std::get<1>(pair.second));
265             const auto& options =
266                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
267 
268             if (!validateStringOption(attrValue, options))
269             {
270                 throw InvalidArgument();
271             }
272         }
273 
274         if (attributeType == AttributeType::Integer)
275         {
276             // For enumeration the expected variant types is Integer
277             if (std::get<1>(pair.second).index() == 1)
278             {
279                 lg2::error("Enumeration property value is not int");
280                 throw InvalidArgument();
281             }
282 
283             const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second));
284             const auto& options =
285                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
286 
287             if (!validateIntegerOption(attrValue, options))
288             {
289                 throw InvalidArgument();
290             }
291         }
292     }
293 
294     PendingAttributes pendingAttribute = Base::pendingAttributes();
295 
296     for (const auto& pair : value)
297     {
298         auto iter = pendingAttribute.find(pair.first);
299         if (iter != pendingAttribute.end())
300         {
301             iter = pendingAttribute.erase(iter);
302         }
303 
304         pendingAttribute.emplace(std::make_pair(pair.first, pair.second));
305     }
306 
307     auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false);
308     serialize(*this, biosFile);
309 
310     return pendingAttrs;
311 }
312 
Manager(sdbusplus::asio::object_server & objectServer,std::shared_ptr<sdbusplus::asio::connection> & systemBus)313 Manager::Manager(sdbusplus::asio::object_server& objectServer,
314                  std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
315     sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus,
316                                                                  objectPath),
317     objServer(objectServer), systemBus(systemBus)
318 {
319     fs::path biosDir(BIOS_PERSIST_PATH);
320     fs::create_directories(biosDir);
321     biosFile = biosDir / biosPersistFile;
322     deserialize(biosFile, *this);
323 }
324 
325 } // namespace bios_config
326