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