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
Manager(sdbusplus::asio::object_server & objectServer,std::shared_ptr<sdbusplus::asio::connection> & systemBus,std::string persistPath)314 Manager::Manager(sdbusplus::asio::object_server& objectServer,
315 std::shared_ptr<sdbusplus::asio::connection>& systemBus,
316 std::string persistPath) :
317 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(
318 *systemBus, objectPath),
319 objServer(objectServer), systemBus(systemBus)
320 {
321 fs::path biosDir(persistPath);
322 fs::create_directories(biosDir);
323 biosFile = biosDir / biosPersistFile;
324 deserialize(biosFile, *this);
325 }
326
327 } // namespace bios_config
328