blob: c92205f7c061042a1103f0c172ea3cfa66e337d0 [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);
100 return baseTable;
Kuiying Wang642f4372020-08-12 15:35:46 +0800101}
102
103Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value)
104{
105 // Clear the pending attributes
106 if (value.empty())
107 {
Tom Josephf1101df2020-11-06 08:23:34 +0530108 auto pendingAttrs = Base::pendingAttributes({}, false);
109 serialize(*this, biosFile);
110 return pendingAttrs;
Kuiying Wang642f4372020-08-12 15:35:46 +0800111 }
112
113 // Validate all the BIOS attributes before setting PendingAttributes
114 BaseTable biosTable = Base::baseBIOSTable();
115 for (const auto& pair : value)
116 {
117 auto iter = biosTable.find(pair.first);
118 // BIOS attribute not found in the BaseBIOSTable
119 if (iter == biosTable.end())
120 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800121 phosphor::logging::log<phosphor::logging::level::ERR>(
122 "BIOS attribute not found in the BaseBIOSTable");
Kuiying Wang642f4372020-08-12 15:35:46 +0800123 throw AttributeNotFound();
124 }
125
126 // BIOS attribute is read only
127 if (std::get<static_cast<uint8_t>(Index::readOnly)>(iter->second))
128 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800129 phosphor::logging::log<phosphor::logging::level::ERR>(
130 "BIOS attribute is read only");
Kuiying Wang642f4372020-08-12 15:35:46 +0800131 throw AttributeReadOnly();
132 }
133
134 auto attributeType =
135 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second);
136 if (attributeType != std::get<0>(pair.second))
137 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800138 phosphor::logging::log<phosphor::logging::level::ERR>(
139 "attributeType is not same with bios base table");
Kuiying Wang642f4372020-08-12 15:35:46 +0800140 throw InvalidArgument();
141 }
142
143 // Validate enumeration BIOS attributes
144 if (attributeType == AttributeType::Enumeration)
145 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800146 // For enumeration the expected variant types is Enumeration
Kuiying Wang642f4372020-08-12 15:35:46 +0800147 if (std::get<1>(pair.second).index() == 0)
148 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800149 phosphor::logging::log<phosphor::logging::level::ERR>(
150 "Enumeration property value is not enum");
Kuiying Wang642f4372020-08-12 15:35:46 +0800151 throw InvalidArgument();
152 }
153
154 const auto& attrValue =
155 std::get<std::string>(std::get<1>(pair.second));
156 const auto& options =
157 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
158
159 bool found = false;
160 for (const auto& enumOptions : options)
161 {
162 if ((BoundType::OneOf == std::get<0>(enumOptions)) &&
163 (attrValue ==
164 std::get<std::string>(std::get<1>(enumOptions))))
165 {
166 found = true;
167 break;
168 }
169 }
170
171 if (!found)
172 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800173 phosphor::logging::log<phosphor::logging::level::ERR>(
174 "No valid attribute");
Kuiying Wang642f4372020-08-12 15:35:46 +0800175 throw InvalidArgument();
176 }
177 }
178
179 if (attributeType == AttributeType::String)
180 {
181 // For enumeration the expected variant types is std::string
182 if (std::get<1>(pair.second).index() == 0)
183 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800184 phosphor::logging::log<phosphor::logging::level::ERR>(
185 "String property value is not string");
Kuiying Wang642f4372020-08-12 15:35:46 +0800186 throw InvalidArgument();
187 }
188
189 const auto& attrValue =
190 std::get<std::string>(std::get<1>(pair.second));
191 const auto& options =
192 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
193 int64_t minStringLength = 0;
194 int64_t maxStringLength = 0;
195
196 for (const auto& stringOptions : options)
197 {
198 if (BoundType::MinStringLength == std::get<0>(stringOptions))
199 {
200 minStringLength =
201 std::get<int64_t>(std::get<1>(stringOptions));
202 }
203 else if (BoundType::MaxStringLength ==
204 std::get<0>(stringOptions))
205 {
206 maxStringLength =
207 std::get<int64_t>(std::get<1>(stringOptions));
208 }
209 }
210
211 if ((attrValue.length() < static_cast<size_t>(minStringLength)) ||
212 (attrValue.length() > static_cast<size_t>(maxStringLength)))
213 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800214 phosphor::logging::log<phosphor::logging::level::ERR>(
215 "std::string, length is invalid");
Kuiying Wang642f4372020-08-12 15:35:46 +0800216 throw InvalidArgument();
217 }
218 }
219
220 if (attributeType == AttributeType::Integer)
221 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800222 // For enumeration the expected variant types is Integer
Kuiying Wang642f4372020-08-12 15:35:46 +0800223 if (std::get<1>(pair.second).index() == 1)
224 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800225 phosphor::logging::log<phosphor::logging::level::ERR>(
226 "Enumeration property value is not int");
Kuiying Wang642f4372020-08-12 15:35:46 +0800227 throw InvalidArgument();
228 }
229
230 const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second));
231 const auto& options =
232 std::get<static_cast<uint8_t>(Index::options)>(iter->second);
233 int64_t lowerBound = 0;
234 int64_t upperBound = 0;
235 int64_t scalarIncrement = 0;
236
237 for (const auto& integerOptions : options)
238 {
239 if (BoundType::LowerBound == std::get<0>(integerOptions))
240 {
241 lowerBound = std::get<int64_t>(std::get<1>(integerOptions));
242 }
243 else if (BoundType::UpperBound == std::get<0>(integerOptions))
244 {
245 upperBound = std::get<int64_t>(std::get<1>(integerOptions));
246 }
247 else if (BoundType::ScalarIncrement ==
248 std::get<0>(integerOptions))
249 {
250 scalarIncrement =
251 std::get<int64_t>(std::get<1>(integerOptions));
252 }
253 }
254
255 if ((attrValue < lowerBound) || (attrValue > upperBound))
256 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800257 phosphor::logging::log<phosphor::logging::level::ERR>(
258 "Integer, bound is invalid");
Kuiying Wang642f4372020-08-12 15:35:46 +0800259 throw InvalidArgument();
260 }
261
262 if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0)
263 {
Kuiying Wang8f706212020-12-16 18:59:24 +0800264 phosphor::logging::log<phosphor::logging::level::ERR>(
265 "((std::abs(attrValue - lowerBound)) % scalarIncrement) != "
266 "0");
Kuiying Wang642f4372020-08-12 15:35:46 +0800267 throw InvalidArgument();
268 }
269 }
270 }
271
272 PendingAttributes pendingAttribute = Base::pendingAttributes();
273
274 for (const auto& pair : value)
275 {
276 auto iter = pendingAttribute.find(pair.first);
277 if (iter != pendingAttribute.end())
278 {
279 iter = pendingAttribute.erase(iter);
280 }
281
282 pendingAttribute.emplace(std::make_pair(pair.first, pair.second));
283 }
284
Tom Josephf1101df2020-11-06 08:23:34 +0530285 auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false);
286 serialize(*this, biosFile);
287
288 return pendingAttrs;
Kuiying Wang642f4372020-08-12 15:35:46 +0800289}
290
291Manager::Manager(sdbusplus::asio::object_server& objectServer,
292 std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
293 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus,
294 objectPath),
295 objServer(objectServer), systemBus(systemBus)
Tom Josephf1101df2020-11-06 08:23:34 +0530296{
297 fs::path biosDir(BIOS_PERSIST_PATH);
298 fs::create_directories(biosDir);
299 biosFile = biosDir / biosPersistFile;
300 deserialize(biosFile, *this);
301}
Kuiying Wang642f4372020-08-12 15:35:46 +0800302
303} // namespace bios_config
304
305int main()
306{
307 boost::asio::io_service io;
308 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
309
310 systemBus->request_name(bios_config::service);
311 sdbusplus::asio::object_server objectServer(systemBus);
312 bios_config::Manager manager(objectServer, systemBus);
313
314 io.run();
315 return 0;
316}