xref: /openbmc/bios-settings-mgr/src/manager.cpp (revision f1101df28a1b6fff742272e0ab347dc2c24d38b9)
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 <sdbusplus/asio/connection.hpp>
24 #include <sdbusplus/asio/object_server.hpp>
25 
26 namespace bios_config
27 {
28 
29 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
30 using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
31 
32 void Manager::setAttribute(AttributeName attribute, AttributeValue value)
33 {
34     auto pendingAttrs = Base::pendingAttributes();
35     auto iter = pendingAttrs.find(attribute);
36 
37     if (iter != pendingAttrs.end())
38     {
39         std::get<1>(iter->second) = value;
40     }
41     else
42     {
43         Manager::PendingAttribute attributeValue;
44 
45         if (std::get_if<int64_t>(&value))
46         {
47             std::get<0>(attributeValue) = AttributeType::Integer;
48         }
49         else
50         {
51             std::get<0>(attributeValue) = AttributeType::String;
52         }
53 
54         std::get<1>(attributeValue) = value;
55         pendingAttrs.emplace(attribute, attributeValue);
56     }
57 
58     pendingAttributes(pendingAttrs);
59 }
60 
61 Manager::AttributeDetails Manager::getAttribute(AttributeName attribute)
62 {
63     Manager::AttributeDetails value;
64 
65     auto table = Base::baseBIOSTable();
66     auto iter = table.find(attribute);
67 
68     if (iter != table.end())
69     {
70         std::get<0>(value) =
71             std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
72         std::get<1>(value) =
73             std::get<static_cast<uint8_t>(Index::currentValue)>(iter->second);
74 
75         auto pending = Base::pendingAttributes();
76         auto pendingIter = pending.find(attribute);
77         if (pendingIter != pending.end())
78         {
79             std::get<2>(value) = std::get<1>(pendingIter->second);
80         }
81         else if (std::get_if<std::string>(&std::get<1>(value)))
82         {
83             std::get<2>(value) = std::string();
84         }
85     }
86     else
87     {
88         throw AttributeNotFound();
89     }
90 
91     return value;
92 }
93 
94 Manager::BaseTable Manager::baseBIOSTable(BaseTable value)
95 {
96     pendingAttributes({});
97     auto baseTable = Base::baseBIOSTable(value, false);
98     serialize(*this, biosFile);
99     return baseTable;
100 }
101 
102 Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value)
103 {
104     // Clear the pending attributes
105     if (value.empty())
106     {
107         auto pendingAttrs = Base::pendingAttributes({}, false);
108         serialize(*this, biosFile);
109         return pendingAttrs;
110     }
111 
112     // Validate all the BIOS attributes before setting PendingAttributes
113     BaseTable biosTable = Base::baseBIOSTable();
114     for (const auto& pair : value)
115     {
116         auto iter = biosTable.find(pair.first);
117         // BIOS attribute not found in the BaseBIOSTable
118         if (iter == biosTable.end())
119         {
120             throw AttributeNotFound();
121         }
122 
123         // BIOS attribute is read only
124         if (std::get<static_cast<uint8_t>(Index::readOnly)>(iter->second))
125         {
126             throw AttributeReadOnly();
127         }
128 
129         auto attributeType =
130             std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
131         if (attributeType != std::get<0>(pair.second))
132         {
133             throw InvalidArgument();
134         }
135 
136         // Validate enumeration BIOS attributes
137         if (attributeType == AttributeType::Enumeration)
138         {
139             // For enumeration the expected variant types is std::string
140             if (std::get<1>(pair.second).index() == 0)
141             {
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                 throw InvalidArgument();
165             }
166         }
167 
168         if (attributeType == AttributeType::String)
169         {
170             // For enumeration the expected variant types is std::string
171             if (std::get<1>(pair.second).index() == 0)
172             {
173                 throw InvalidArgument();
174             }
175 
176             const auto& attrValue =
177                 std::get<std::string>(std::get<1>(pair.second));
178             const auto& options =
179                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
180             int64_t minStringLength = 0;
181             int64_t maxStringLength = 0;
182 
183             for (const auto& stringOptions : options)
184             {
185                 if (BoundType::MinStringLength == std::get<0>(stringOptions))
186                 {
187                     minStringLength =
188                         std::get<int64_t>(std::get<1>(stringOptions));
189                 }
190                 else if (BoundType::MaxStringLength ==
191                          std::get<0>(stringOptions))
192                 {
193                     maxStringLength =
194                         std::get<int64_t>(std::get<1>(stringOptions));
195                 }
196             }
197 
198             if ((attrValue.length() < static_cast<size_t>(minStringLength)) ||
199                 (attrValue.length() > static_cast<size_t>(maxStringLength)))
200             {
201                 throw InvalidArgument();
202             }
203         }
204 
205         if (attributeType == AttributeType::Integer)
206         {
207             // For enumeration the expected variant types is std::string
208             if (std::get<1>(pair.second).index() == 1)
209             {
210                 throw InvalidArgument();
211             }
212 
213             const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second));
214             const auto& options =
215                 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
216             int64_t lowerBound = 0;
217             int64_t upperBound = 0;
218             int64_t scalarIncrement = 0;
219 
220             for (const auto& integerOptions : options)
221             {
222                 if (BoundType::LowerBound == std::get<0>(integerOptions))
223                 {
224                     lowerBound = std::get<int64_t>(std::get<1>(integerOptions));
225                 }
226                 else if (BoundType::UpperBound == std::get<0>(integerOptions))
227                 {
228                     upperBound = std::get<int64_t>(std::get<1>(integerOptions));
229                 }
230                 else if (BoundType::ScalarIncrement ==
231                          std::get<0>(integerOptions))
232                 {
233                     scalarIncrement =
234                         std::get<int64_t>(std::get<1>(integerOptions));
235                 }
236             }
237 
238             if ((attrValue < lowerBound) || (attrValue > upperBound))
239             {
240                 throw InvalidArgument();
241             }
242 
243             if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
244             {
245                 throw InvalidArgument();
246             }
247         }
248     }
249 
250     PendingAttributes pendingAttribute = Base::pendingAttributes();
251 
252     for (const auto& pair : value)
253     {
254         auto iter = pendingAttribute.find(pair.first);
255         if (iter != pendingAttribute.end())
256         {
257             iter = pendingAttribute.erase(iter);
258         }
259 
260         pendingAttribute.emplace(std::make_pair(pair.first, pair.second));
261     }
262 
263     auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false);
264     serialize(*this, biosFile);
265 
266     return pendingAttrs;
267 }
268 
269 Manager::Manager(sdbusplus::asio::object_server& objectServer,
270                  std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
271     sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus,
272                                                                  objectPath),
273     objServer(objectServer), systemBus(systemBus)
274 {
275     fs::path biosDir(BIOS_PERSIST_PATH);
276     fs::create_directories(biosDir);
277     biosFile = biosDir / biosPersistFile;
278     deserialize(biosFile, *this);
279 }
280 
281 } // namespace bios_config
282 
283 int main()
284 {
285     boost::asio::io_service io;
286     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
287 
288     systemBus->request_name(bios_config::service);
289     sdbusplus::asio::object_server objectServer(systemBus);
290     bios_config::Manager manager(objectServer, systemBus);
291 
292     io.run();
293     return 0;
294 }
295