xref: /openbmc/bios-settings-mgr/src/manager.cpp (revision 616f9228daa5b94447c3c9d519b63f1686e751f5)
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 
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 
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 
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 
105 Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value)
106 {
107     // Clear the pending attributes
108     if (value.empty())
109     {
110         auto pendingAttrs = Base::pendingAttributes({}, false);
111         serialize(*this, biosFile);
112         return pendingAttrs;
113     }
114 
115     // Validate all the BIOS attributes before setting PendingAttributes
116     BaseTable biosTable = Base::baseBIOSTable();
117     for (const auto& pair : value)
118     {
119         auto iter = biosTable.find(pair.first);
120         // BIOS attribute not found in the BaseBIOSTable
121         if (iter == biosTable.end())
122         {
123             lg2::error("BIOS attribute not found in the BaseBIOSTable");
124             throw AttributeNotFound();
125         }
126 
127         auto attributeType =
128             std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
129         if (attributeType != std::get<0>(pair.second))
130         {
131             lg2::error("attributeType is not same with bios base table");
132             throw InvalidArgument();
133         }
134 
135         // Validate enumeration BIOS attributes
136         if (attributeType == AttributeType::Enumeration)
137         {
138             // For enumeration the expected variant types is Enumeration
139             if (std::get<1>(pair.second).index() == 0)
140             {
141                 lg2::error("Enumeration property value is not enum");
142                 throw InvalidArgument();
143             }
144 
145             const auto& attrValue =
146                 std::get<std::string>(std::get<1>(pair.second));
147             const auto& options =
148                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
149 
150             bool found = false;
151             for (const auto& enumOptions : options)
152             {
153                 if ((BoundType::OneOf == std::get<0>(enumOptions)) &&
154                     (attrValue ==
155                      std::get<std::string>(std::get<1>(enumOptions))))
156                 {
157                     found = true;
158                     break;
159                 }
160             }
161 
162             if (!found)
163             {
164                 lg2::error("No valid attribute");
165                 throw InvalidArgument();
166             }
167         }
168 
169         if (attributeType == AttributeType::String)
170         {
171             // For enumeration the expected variant types is std::string
172             if (std::get<1>(pair.second).index() == 0)
173             {
174                 lg2::error("String property value is not string");
175                 throw InvalidArgument();
176             }
177 
178             const auto& attrValue =
179                 std::get<std::string>(std::get<1>(pair.second));
180             const auto& options =
181                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
182 
183             size_t minStringLength = 0;
184             size_t maxStringLength = 0;
185             for (const auto& stringOptions : options)
186             {
187                 if (BoundType::MinStringLength == std::get<0>(stringOptions))
188                 {
189                     minStringLength =
190                         std::get<int64_t>(std::get<1>(stringOptions));
191                 }
192                 else if (BoundType::MaxStringLength ==
193                          std::get<0>(stringOptions))
194                 {
195                     maxStringLength =
196                         std::get<int64_t>(std::get<1>(stringOptions));
197                 }
198                 else
199                 {
200                     continue;
201                 }
202             }
203 
204             if (attrValue.length() < minStringLength ||
205                 attrValue.length() > maxStringLength)
206             {
207                 lg2::error(
208                     "{ATTRVALUE} Length is out of range, bound is invalid, maxStringLength = {MAXLEN}, minStringLength = {MINLEN}",
209                     "ATTRVALUE", attrValue, "MAXLEN", maxStringLength, "MINLEN",
210                     minStringLength);
211                 throw InvalidArgument();
212             }
213         }
214 
215         if (attributeType == AttributeType::Integer)
216         {
217             // For enumeration the expected variant types is Integer
218             if (std::get<1>(pair.second).index() == 1)
219             {
220                 lg2::error("Enumeration property value is not int");
221                 throw InvalidArgument();
222             }
223 
224             const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second));
225             const auto& options =
226                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
227             int64_t lowerBound = 0;
228             int64_t upperBound = 0;
229             int64_t scalarIncrement = 0;
230 
231             for (const auto& integerOptions : options)
232             {
233                 if (BoundType::LowerBound == std::get<0>(integerOptions))
234                 {
235                     lowerBound = std::get<int64_t>(std::get<1>(integerOptions));
236                 }
237                 else if (BoundType::UpperBound == std::get<0>(integerOptions))
238                 {
239                     upperBound = std::get<int64_t>(std::get<1>(integerOptions));
240                 }
241                 else if (BoundType::ScalarIncrement ==
242                          std::get<0>(integerOptions))
243                 {
244                     scalarIncrement =
245                         std::get<int64_t>(std::get<1>(integerOptions));
246                 }
247             }
248 
249             if ((attrValue < lowerBound) || (attrValue > upperBound))
250             {
251                 lg2::error("Integer, bound is invalid");
252                 throw InvalidArgument();
253             }
254 
255             if (scalarIncrement == 0 ||
256                 ((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
257             {
258                 lg2::error(
259                     "((std::abs({ATTR_VALUE} - {LOWER_BOUND})) % {SCALAR_INCREMENT}) != 0",
260                     "ATTR_VALUE", attrValue, "LOWER_BOUND", lowerBound,
261                     "SCALAR_INCREMENT", scalarIncrement);
262                 throw InvalidArgument();
263             }
264         }
265     }
266 
267     PendingAttributes pendingAttribute = Base::pendingAttributes();
268 
269     for (const auto& pair : value)
270     {
271         auto iter = pendingAttribute.find(pair.first);
272         if (iter != pendingAttribute.end())
273         {
274             iter = pendingAttribute.erase(iter);
275         }
276 
277         pendingAttribute.emplace(std::make_pair(pair.first, pair.second));
278     }
279 
280     auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false);
281     serialize(*this, biosFile);
282 
283     return pendingAttrs;
284 }
285 
286 Manager::Manager(sdbusplus::asio::object_server& objectServer,
287                  std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
288     sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus,
289                                                                  objectPath),
290     objServer(objectServer), systemBus(systemBus)
291 {
292     fs::path biosDir(BIOS_PERSIST_PATH);
293     fs::create_directories(biosDir);
294     biosFile = biosDir / biosPersistFile;
295     deserialize(biosFile, *this);
296 }
297 
298 } // namespace bios_config
299 
300 int main()
301 {
302     boost::asio::io_service io;
303     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
304 
305     systemBus->request_name(bios_config::service);
306     sdbusplus::asio::object_server objectServer(systemBus);
307     bios_config::Manager manager(objectServer, systemBus);
308 
309     io.run();
310     return 0;
311 }
312