blob: 42a3721dd9824251151faaca479c83e47913ff3d [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);
186 int64_t minStringLength = 0;
187 int64_t maxStringLength = 0;
188
189 for (const auto& stringOptions : options)
190 {
191 if (BoundType::MinStringLength == std::get<0>(stringOptions))
192 {
193 minStringLength =
194 std::get<int64_t>(std::get<1>(stringOptions));
195 }
196 else if (BoundType::MaxStringLength ==
197 std::get<0>(stringOptions))
198 {
199 maxStringLength =
200 std::get<int64_t>(std::get<1>(stringOptions));
201 }
202 }
203
204 if ((attrValue.length() < static_cast<size_t>(minStringLength)) ||
205 (attrValue.length() > static_cast<size_t>(maxStringLength)))
206 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800207 phosphor::logging::log<phosphor::logging::level::ERR>(
208 "std::string, length is invalid");
Kuiying Wang642f4372020-08-12 15:35:46 +0800209 throw InvalidArgument();
210 }
211 }
212
213 if (attributeType == AttributeType::Integer)
214 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800215 // For enumeration the expected variant types is Integer
Kuiying Wang642f4372020-08-12 15:35:46 +0800216 if (std::get<1>(pair.second).index() == 1)
217 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800218 phosphor::logging::log<phosphor::logging::level::ERR>(
219 "Enumeration property value is not int");
Kuiying Wang642f4372020-08-12 15:35:46 +0800220 throw InvalidArgument();
221 }
222
223 const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second));
224 const auto& options =
225 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
226 int64_t lowerBound = 0;
227 int64_t upperBound = 0;
228 int64_t scalarIncrement = 0;
229
230 for (const auto& integerOptions : options)
231 {
232 if (BoundType::LowerBound == std::get<0>(integerOptions))
233 {
234 lowerBound = std::get<int64_t>(std::get<1>(integerOptions));
235 }
236 else if (BoundType::UpperBound == std::get<0>(integerOptions))
237 {
238 upperBound = std::get<int64_t>(std::get<1>(integerOptions));
239 }
240 else if (BoundType::ScalarIncrement ==
241 std::get<0>(integerOptions))
242 {
243 scalarIncrement =
244 std::get<int64_t>(std::get<1>(integerOptions));
245 }
246 }
247
248 if ((attrValue < lowerBound) || (attrValue > upperBound))
249 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800250 phosphor::logging::log<phosphor::logging::level::ERR>(
251 "Integer, bound is invalid");
Kuiying Wang642f4372020-08-12 15:35:46 +0800252 throw InvalidArgument();
253 }
254
255 if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
256 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800257 phosphor::logging::log<phosphor::logging::level::ERR>(
258 "((std::abs(attrValue - lowerBound)) % scalarIncrement) != "
259 "0");
Kuiying Wang642f4372020-08-12 15:35:46 +0800260 throw InvalidArgument();
261 }
262 }
263 }
264
265 PendingAttributes pendingAttribute = Base::pendingAttributes();
266
267 for (const auto& pair : value)
268 {
269 auto iter = pendingAttribute.find(pair.first);
270 if (iter != pendingAttribute.end())
271 {
272 iter = pendingAttribute.erase(iter);
273 }
274
275 pendingAttribute.emplace(std::make_pair(pair.first, pair.second));
276 }
277
Tom Josephf1101df2020-11-06 08:23:34 +0530278 auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false);
279 serialize(*this, biosFile);
280
281 return pendingAttrs;
Kuiying Wang642f4372020-08-12 15:35:46 +0800282}
283
284Manager::Manager(sdbusplus::asio::object_server& objectServer,
285 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
286 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus,
287 objectPath),
288 objServer(objectServer), systemBus(systemBus)
Tom Josephf1101df2020-11-06 08:23:34 +0530289{
290 fs::path biosDir(BIOS_PERSIST_PATH);
291 fs::create_directories(biosDir);
292 biosFile = biosDir / biosPersistFile;
293 deserialize(biosFile, *this);
294}
Kuiying Wang642f4372020-08-12 15:35:46 +0800295
296} // namespace bios_config
297
298int main()
299{
300 boost::asio::io_service io;
301 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
302
303 systemBus->request_name(bios_config::service);
304 sdbusplus::asio::object_server objectServer(systemBus);
305 bios_config::Manager manager(objectServer, systemBus);
306
307 io.run();
308 return 0;
309}