blob: 14654be2919a8e5540b4da26a314d92537de6679 [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>
Kuiying Wang642f4372020-08-12 15:35:46 +080024#include <sdbusplus/asio/connection.hpp>
25#include <sdbusplus/asio/object_server.hpp>
26
27namespace bios_config
28{
29
30using namespace sdbusplus::xyz::openbmc_project::Common::Error;
31using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error;
32
33void Manager::setAttribute(AttributeName attribute, AttributeValue value)
34{
35 auto pendingAttrs = Base::pendingAttributes();
36 auto iter = pendingAttrs.find(attribute);
37
38 if (iter != pendingAttrs.end())
39 {
40 std::get<1>(iter->second) = value;
41 }
42 else
43 {
44 Manager::PendingAttribute attributeValue;
45
46 if (std::get_if<int64_t>(&value))
47 {
48 std::get<0>(attributeValue) = AttributeType::Integer;
49 }
50 else
51 {
52 std::get<0>(attributeValue) = AttributeType::String;
53 }
54
55 std::get<1>(attributeValue) = value;
56 pendingAttrs.emplace(attribute, attributeValue);
57 }
58
59 pendingAttributes(pendingAttrs);
60}
61
62Manager::AttributeDetails Manager::getAttribute(AttributeName attribute)
63{
64 Manager::AttributeDetails value;
65
66 auto table = Base::baseBIOSTable();
67 auto iter = table.find(attribute);
68
69 if (iter != table.end())
70 {
71 std::get<0>(value) =
72 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
73 std::get<1>(value) =
74 std::get<static_cast<uint8_t>(Index::currentValue)>(iter->second);
75
76 auto pending = Base::pendingAttributes();
77 auto pendingIter = pending.find(attribute);
78 if (pendingIter != pending.end())
79 {
80 std::get<2>(value) = std::get<1>(pendingIter->second);
81 }
82 else if (std::get_if<std::string>(&std::get<1>(value)))
83 {
84 std::get<2>(value) = std::string();
85 }
86 }
87 else
88 {
89 throw AttributeNotFound();
90 }
91
92 return value;
93}
94
95Manager::BaseTable Manager::baseBIOSTable(BaseTable value)
96{
97 pendingAttributes({});
Tom Josephf1101df2020-11-06 08:23:34 +053098 auto baseTable = Base::baseBIOSTable(value, false);
99 serialize(*this, biosFile);
Snehalatha Venkatesh5e2cb722021-05-26 10:42:58 +0000100 Base::resetBIOSSettings(Base::ResetFlag::NoAction);
Tom Josephf1101df2020-11-06 08:23:34 +0530101 return baseTable;
Kuiying Wang642f4372020-08-12 15:35:46 +0800102}
103
104Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value)
105{
106 // Clear the pending attributes
107 if (value.empty())
108 {
Tom Josephf1101df2020-11-06 08:23:34 +0530109 auto pendingAttrs = Base::pendingAttributes({}, false);
110 serialize(*this, biosFile);
111 return pendingAttrs;
Kuiying Wang642f4372020-08-12 15:35:46 +0800112 }
113
114 // Validate all the BIOS attributes before setting PendingAttributes
115 BaseTable biosTable = Base::baseBIOSTable();
116 for (const auto& pair : value)
117 {
118 auto iter = biosTable.find(pair.first);
119 // BIOS attribute not found in the BaseBIOSTable
120 if (iter == biosTable.end())
121 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800122 phosphor::logging::log<phosphor::logging::level::ERR>(
123 "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 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800131 phosphor::logging::log<phosphor::logging::level::ERR>(
132 "attributeType is not same with bios base table");
Kuiying Wang642f4372020-08-12 15:35:46 +0800133 throw InvalidArgument();
134 }
135
136 // Validate enumeration BIOS attributes
137 if (attributeType == AttributeType::Enumeration)
138 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800139 // For enumeration the expected variant types is Enumeration
Kuiying Wang642f4372020-08-12 15:35:46 +0800140 if (std::get<1>(pair.second).index() == 0)
141 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800142 phosphor::logging::log<phosphor::logging::level::ERR>(
143 "Enumeration property value is not enum");
Kuiying Wang642f4372020-08-12 15:35:46 +0800144 throw InvalidArgument();
145 }
146
147 const auto& attrValue =
148 std::get<std::string>(std::get<1>(pair.second));
149 const auto& options =
150 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
151
152 bool found = false;
153 for (const auto& enumOptions : options)
154 {
155 if ((BoundType::OneOf == std::get<0>(enumOptions)) &&
156 (attrValue ==
157 std::get<std::string>(std::get<1>(enumOptions))))
158 {
159 found = true;
160 break;
161 }
162 }
163
164 if (!found)
165 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800166 phosphor::logging::log<phosphor::logging::level::ERR>(
167 "No valid attribute");
Kuiying Wang642f4372020-08-12 15:35:46 +0800168 throw InvalidArgument();
169 }
170 }
171
172 if (attributeType == AttributeType::String)
173 {
174 // For enumeration the expected variant types is std::string
175 if (std::get<1>(pair.second).index() == 0)
176 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800177 phosphor::logging::log<phosphor::logging::level::ERR>(
178 "String property value is not string");
Kuiying Wang642f4372020-08-12 15:35:46 +0800179 throw InvalidArgument();
180 }
181
182 const auto& attrValue =
183 std::get<std::string>(std::get<1>(pair.second));
184 const auto& options =
185 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
Kuiying Wang642f4372020-08-12 15:35:46 +0800186
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000187 auto optionsIterator = options.begin();
188
189 for (; optionsIterator != options.end(); ++optionsIterator)
Kuiying Wang642f4372020-08-12 15:35:46 +0800190 {
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000191 if (std::get<1>(std::get<1>(*optionsIterator)) == attrValue)
Kuiying Wang642f4372020-08-12 15:35:46 +0800192 {
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000193 break;
Kuiying Wang642f4372020-08-12 15:35:46 +0800194 }
195 }
196
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000197 if (optionsIterator == options.end())
Kuiying Wang642f4372020-08-12 15:35:46 +0800198 {
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000199 std::string error =
200 attrValue + " is not a valid value for " + pair.first;
Kuiying Wang8f706212020-12-16 18:59:24 +0800201 phosphor::logging::log<phosphor::logging::level::ERR>(
Arun Lal K Mb5984b82021-08-16 18:18:31 +0000202 error.c_str());
Kuiying Wang642f4372020-08-12 15:35:46 +0800203 throw InvalidArgument();
204 }
205 }
206
207 if (attributeType == AttributeType::Integer)
208 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800209 // For enumeration the expected variant types is Integer
Kuiying Wang642f4372020-08-12 15:35:46 +0800210 if (std::get<1>(pair.second).index() == 1)
211 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800212 phosphor::logging::log<phosphor::logging::level::ERR>(
213 "Enumeration property value is not int");
Kuiying Wang642f4372020-08-12 15:35:46 +0800214 throw InvalidArgument();
215 }
216
217 const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second));
218 const auto& options =
219 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
220 int64_t lowerBound = 0;
221 int64_t upperBound = 0;
222 int64_t scalarIncrement = 0;
223
224 for (const auto& integerOptions : options)
225 {
226 if (BoundType::LowerBound == std::get<0>(integerOptions))
227 {
228 lowerBound = std::get<int64_t>(std::get<1>(integerOptions));
229 }
230 else if (BoundType::UpperBound == std::get<0>(integerOptions))
231 {
232 upperBound = std::get<int64_t>(std::get<1>(integerOptions));
233 }
234 else if (BoundType::ScalarIncrement ==
235 std::get<0>(integerOptions))
236 {
237 scalarIncrement =
238 std::get<int64_t>(std::get<1>(integerOptions));
239 }
240 }
241
242 if ((attrValue < lowerBound) || (attrValue > upperBound))
243 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800244 phosphor::logging::log<phosphor::logging::level::ERR>(
245 "Integer, bound is invalid");
Kuiying Wang642f4372020-08-12 15:35:46 +0800246 throw InvalidArgument();
247 }
248
249 if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
250 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800251 phosphor::logging::log<phosphor::logging::level::ERR>(
252 "((std::abs(attrValue - lowerBound)) % scalarIncrement) != "
253 "0");
Kuiying Wang642f4372020-08-12 15:35:46 +0800254 throw InvalidArgument();
255 }
256 }
257 }
258
259 PendingAttributes pendingAttribute = Base::pendingAttributes();
260
261 for (const auto& pair : value)
262 {
263 auto iter = pendingAttribute.find(pair.first);
264 if (iter != pendingAttribute.end())
265 {
266 iter = pendingAttribute.erase(iter);
267 }
268
269 pendingAttribute.emplace(std::make_pair(pair.first, pair.second));
270 }
271
Tom Josephf1101df2020-11-06 08:23:34 +0530272 auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false);
273 serialize(*this, biosFile);
274
275 return pendingAttrs;
Kuiying Wang642f4372020-08-12 15:35:46 +0800276}
277
278Manager::Manager(sdbusplus::asio::object_server& objectServer,
279 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
280 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus,
281 objectPath),
282 objServer(objectServer), systemBus(systemBus)
Tom Josephf1101df2020-11-06 08:23:34 +0530283{
284 fs::path biosDir(BIOS_PERSIST_PATH);
285 fs::create_directories(biosDir);
286 biosFile = biosDir / biosPersistFile;
287 deserialize(biosFile, *this);
288}
Kuiying Wang642f4372020-08-12 15:35:46 +0800289
290} // namespace bios_config
291
292int main()
293{
294 boost::asio::io_service io;
295 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
296
297 systemBus->request_name(bios_config::service);
298 sdbusplus::asio::object_server objectServer(systemBus);
299 bios_config::Manager manager(objectServer, systemBus);
300
301 io.run();
302 return 0;
303}