blob: 0cb425930611a7adb7966e2cd4f0f7abc06851c5 [file] [log] [blame]
Kuiying Wang642f4372020-08-12 15:35:46 +08001/*
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
Tom Josephf1101df2020-11-06 08:23:34 +053018#include "manager_serialize.hpp"
Kuiying Wang642f4372020-08-12 15:35:46 +080019#include "xyz/openbmc_project/BIOSConfig/Common/error.hpp"
20#include "xyz/openbmc_project/Common/error.hpp"
21
22#include <boost/asio.hpp>
Kuiying Wang8f706212020-12-16 18:59:24 +080023#include <phosphor-logging/elog-errors.hpp>
George Liu567a3cf2021-12-08 10:36:03 +080024#include <phosphor-logging/lg2.hpp>
Kuiying Wang642f4372020-08-12 15:35:46 +080025#include <sdbusplus/asio/connection.hpp>
26#include <sdbusplus/asio/object_server.hpp>
27
28namespace bios_config
29{
30
31using namespace sdbusplus::xyz::openbmc_project::Common::Error;
32using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
33
34void 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
63Manager::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
96Manager::BaseTable Manager::baseBIOSTable(BaseTable value)
97{
98 pendingAttributes({});
Tom Josephf1101df2020-11-06 08:23:34 +053099 auto baseTable = Base::baseBIOSTable(value, false);
100 serialize(*this, biosFile);
Snehalatha Venkatesh5e2cb722021-05-26 10:42:58 +0000101 Base::resetBIOSSettings(Base::ResetFlag::NoAction);
Tom Josephf1101df2020-11-06 08:23:34 +0530102 return baseTable;
Kuiying Wang642f4372020-08-12 15:35:46 +0800103}
104
105Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value)
106{
107 // Clear the pending attributes
108 if (value.empty())
109 {
Tom Josephf1101df2020-11-06 08:23:34 +0530110 auto pendingAttrs = Base::pendingAttributes({}, false);
111 serialize(*this, biosFile);
112 return pendingAttrs;
Kuiying Wang642f4372020-08-12 15:35:46 +0800113 }
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 {
George Liu567a3cf2021-12-08 10:36:03 +0800123 lg2::error("BIOS attribute not found in the BaseBIOSTable");
Kuiying Wang642f4372020-08-12 15:35:46 +0800124 throw AttributeNotFound();
125 }
126
Kuiying Wang642f4372020-08-12 15:35:46 +0800127 auto attributeType =
128 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
129 if (attributeType != std::get<0>(pair.second))
130 {
George Liu567a3cf2021-12-08 10:36:03 +0800131 lg2::error("attributeType is not same with bios base table");
Kuiying Wang642f4372020-08-12 15:35:46 +0800132 throw InvalidArgument();
133 }
134
135 // Validate enumeration BIOS attributes
136 if (attributeType == AttributeType::Enumeration)
137 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800138 // For enumeration the expected variant types is Enumeration
Kuiying Wang642f4372020-08-12 15:35:46 +0800139 if (std::get<1>(pair.second).index() == 0)
140 {
George Liu567a3cf2021-12-08 10:36:03 +0800141 lg2::error("Enumeration property value is not enum");
Kuiying Wang642f4372020-08-12 15:35:46 +0800142 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 {
George Liu567a3cf2021-12-08 10:36:03 +0800164 lg2::error("No valid attribute");
Kuiying Wang642f4372020-08-12 15:35:46 +0800165 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 {
George Liu567a3cf2021-12-08 10:36:03 +0800174 lg2::error("String property value is not string");
Kuiying Wang642f4372020-08-12 15:35:46 +0800175 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);
Kuiying Wang642f4372020-08-12 15:35:46 +0800182
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000183 auto optionsIterator = options.begin();
184
185 for (; optionsIterator != options.end(); ++optionsIterator)
Kuiying Wang642f4372020-08-12 15:35:46 +0800186 {
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000187 if (std::get<1>(std::get<1>(*optionsIterator)) == attrValue)
Kuiying Wang642f4372020-08-12 15:35:46 +0800188 {
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000189 break;
Kuiying Wang642f4372020-08-12 15:35:46 +0800190 }
191 }
192
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000193 if (optionsIterator == options.end())
Kuiying Wang642f4372020-08-12 15:35:46 +0800194 {
George Liu567a3cf2021-12-08 10:36:03 +0800195 lg2::error("{ATTRVALUE} is not a valid value for {NAME}",
196 "ATTRVALUE", attrValue, "NAME", pair.first);
Kuiying Wang642f4372020-08-12 15:35:46 +0800197 throw InvalidArgument();
198 }
199 }
200
201 if (attributeType == AttributeType::Integer)
202 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800203 // For enumeration the expected variant types is Integer
Kuiying Wang642f4372020-08-12 15:35:46 +0800204 if (std::get<1>(pair.second).index() == 1)
205 {
George Liu567a3cf2021-12-08 10:36:03 +0800206 lg2::error("Enumeration property value is not int");
Kuiying Wang642f4372020-08-12 15:35:46 +0800207 throw InvalidArgument();
208 }
209
210 const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second));
211 const auto& options =
212 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
213 int64_t lowerBound = 0;
214 int64_t upperBound = 0;
215 int64_t scalarIncrement = 0;
216
217 for (const auto& integerOptions : options)
218 {
219 if (BoundType::LowerBound == std::get<0>(integerOptions))
220 {
221 lowerBound = std::get<int64_t>(std::get<1>(integerOptions));
222 }
223 else if (BoundType::UpperBound == std::get<0>(integerOptions))
224 {
225 upperBound = std::get<int64_t>(std::get<1>(integerOptions));
226 }
227 else if (BoundType::ScalarIncrement ==
228 std::get<0>(integerOptions))
229 {
230 scalarIncrement =
231 std::get<int64_t>(std::get<1>(integerOptions));
232 }
233 }
234
235 if ((attrValue < lowerBound) || (attrValue > upperBound))
236 {
George Liu567a3cf2021-12-08 10:36:03 +0800237 lg2::error("Integer, bound is invalid");
Kuiying Wang642f4372020-08-12 15:35:46 +0800238 throw InvalidArgument();
239 }
240
241 if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
242 {
George Liu567a3cf2021-12-08 10:36:03 +0800243 lg2::error(
244 "((std::abs({ATTR_VALUE} - {LOWER_BOUND})) % {SCALAR_INCREMENT}) != 0",
245 "ATTR_VALUE", attrValue, "LOWER_BOUND", lowerBound,
246 "SCALAR_INCREMENT", scalarIncrement);
Kuiying Wang642f4372020-08-12 15:35:46 +0800247 throw InvalidArgument();
248 }
249 }
250 }
251
252 PendingAttributes pendingAttribute = Base::pendingAttributes();
253
254 for (const auto& pair : value)
255 {
256 auto iter = pendingAttribute.find(pair.first);
257 if (iter != pendingAttribute.end())
258 {
259 iter = pendingAttribute.erase(iter);
260 }
261
262 pendingAttribute.emplace(std::make_pair(pair.first, pair.second));
263 }
264
Tom Josephf1101df2020-11-06 08:23:34 +0530265 auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false);
266 serialize(*this, biosFile);
267
268 return pendingAttrs;
Kuiying Wang642f4372020-08-12 15:35:46 +0800269}
270
271Manager::Manager(sdbusplus::asio::object_server& objectServer,
272 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
273 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus,
274 objectPath),
275 objServer(objectServer), systemBus(systemBus)
Tom Josephf1101df2020-11-06 08:23:34 +0530276{
277 fs::path biosDir(BIOS_PERSIST_PATH);
278 fs::create_directories(biosDir);
279 biosFile = biosDir / biosPersistFile;
280 deserialize(biosFile, *this);
281}
Kuiying Wang642f4372020-08-12 15:35:46 +0800282
283} // namespace bios_config
284
285int main()
286{
287 boost::asio::io_service io;
288 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
289
290 systemBus->request_name(bios_config::service);
291 sdbusplus::asio::object_server objectServer(systemBus);
292 bios_config::Manager manager(objectServer, systemBus);
293
294 io.run();
295 return 0;
296}