| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 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 | #include "manager.hpp" | 
|  | 17 |  | 
| Tom Joseph | f1101df | 2020-11-06 08:23:34 +0530 | [diff] [blame] | 18 | #include "manager_serialize.hpp" | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 19 | #include "xyz/openbmc_project/BIOSConfig/Common/error.hpp" | 
|  | 20 | #include "xyz/openbmc_project/Common/error.hpp" | 
|  | 21 |  | 
|  | 22 | #include <boost/asio.hpp> | 
| Kuiying Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 23 | #include <phosphor-logging/elog-errors.hpp> | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 24 | #include <sdbusplus/asio/connection.hpp> | 
|  | 25 | #include <sdbusplus/asio/object_server.hpp> | 
|  | 26 |  | 
|  | 27 | namespace bios_config | 
|  | 28 | { | 
|  | 29 |  | 
|  | 30 | using namespace sdbusplus::xyz::openbmc_project::Common::Error; | 
|  | 31 | using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error; | 
|  | 32 |  | 
|  | 33 | void 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 |  | 
|  | 62 | Manager::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 |  | 
|  | 95 | Manager::BaseTable Manager::baseBIOSTable(BaseTable value) | 
|  | 96 | { | 
|  | 97 | pendingAttributes({}); | 
| Tom Joseph | f1101df | 2020-11-06 08:23:34 +0530 | [diff] [blame] | 98 | auto baseTable = Base::baseBIOSTable(value, false); | 
|  | 99 | serialize(*this, biosFile); | 
| Snehalatha Venkatesh | 5e2cb72 | 2021-05-26 10:42:58 +0000 | [diff] [blame] | 100 | Base::resetBIOSSettings(Base::ResetFlag::NoAction); | 
| Tom Joseph | f1101df | 2020-11-06 08:23:34 +0530 | [diff] [blame] | 101 | return baseTable; | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 102 | } | 
|  | 103 |  | 
|  | 104 | Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value) | 
|  | 105 | { | 
|  | 106 | // Clear the pending attributes | 
|  | 107 | if (value.empty()) | 
|  | 108 | { | 
| Tom Joseph | f1101df | 2020-11-06 08:23:34 +0530 | [diff] [blame] | 109 | auto pendingAttrs = Base::pendingAttributes({}, false); | 
|  | 110 | serialize(*this, biosFile); | 
|  | 111 | return pendingAttrs; | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 112 | } | 
|  | 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 Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 122 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 123 | "BIOS attribute not found in the BaseBIOSTable"); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 124 | throw AttributeNotFound(); | 
|  | 125 | } | 
|  | 126 |  | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 127 | auto attributeType = | 
|  | 128 | std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); | 
|  | 129 | if (attributeType != std::get<0>(pair.second)) | 
|  | 130 | { | 
| Kuiying Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 131 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 132 | "attributeType is not same with bios base table"); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 133 | throw InvalidArgument(); | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | // Validate enumeration BIOS attributes | 
|  | 137 | if (attributeType == AttributeType::Enumeration) | 
|  | 138 | { | 
| Kuiying Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 139 | // For enumeration the expected variant types is Enumeration | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 140 | if (std::get<1>(pair.second).index() == 0) | 
|  | 141 | { | 
| Kuiying Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 142 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 143 | "Enumeration property value is not enum"); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 144 | 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 Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 166 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 167 | "No valid attribute"); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 168 | 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 Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 177 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 178 | "String property value is not string"); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 179 | 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 Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 186 |  | 
| Arun Lal K M | b5984b8 | 2021-08-16 18:18:31 +0000 | [diff] [blame^] | 187 | auto optionsIterator = options.begin(); | 
|  | 188 |  | 
|  | 189 | for (; optionsIterator != options.end(); ++optionsIterator) | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 190 | { | 
| Arun Lal K M | b5984b8 | 2021-08-16 18:18:31 +0000 | [diff] [blame^] | 191 | if (std::get<1>(std::get<1>(*optionsIterator)) == attrValue) | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 192 | { | 
| Arun Lal K M | b5984b8 | 2021-08-16 18:18:31 +0000 | [diff] [blame^] | 193 | break; | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 194 | } | 
|  | 195 | } | 
|  | 196 |  | 
| Arun Lal K M | b5984b8 | 2021-08-16 18:18:31 +0000 | [diff] [blame^] | 197 | if (optionsIterator == options.end()) | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 198 | { | 
| Arun Lal K M | b5984b8 | 2021-08-16 18:18:31 +0000 | [diff] [blame^] | 199 | std::string error = | 
|  | 200 | attrValue + " is not a valid value for " + pair.first; | 
| Kuiying Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 201 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
| Arun Lal K M | b5984b8 | 2021-08-16 18:18:31 +0000 | [diff] [blame^] | 202 | error.c_str()); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 203 | throw InvalidArgument(); | 
|  | 204 | } | 
|  | 205 | } | 
|  | 206 |  | 
|  | 207 | if (attributeType == AttributeType::Integer) | 
|  | 208 | { | 
| Kuiying Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 209 | // For enumeration the expected variant types is Integer | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 210 | if (std::get<1>(pair.second).index() == 1) | 
|  | 211 | { | 
| Kuiying Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 212 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 213 | "Enumeration property value is not int"); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 214 | 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 Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 244 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 245 | "Integer, bound is invalid"); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 246 | throw InvalidArgument(); | 
|  | 247 | } | 
|  | 248 |  | 
|  | 249 | if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0) | 
|  | 250 | { | 
| Kuiying Wang | 8f70621 | 2020-12-16 18:59:24 +0800 | [diff] [blame] | 251 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 252 | "((std::abs(attrValue - lowerBound)) % scalarIncrement) != " | 
|  | 253 | "0"); | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 254 | 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 Joseph | f1101df | 2020-11-06 08:23:34 +0530 | [diff] [blame] | 272 | auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false); | 
|  | 273 | serialize(*this, biosFile); | 
|  | 274 |  | 
|  | 275 | return pendingAttrs; | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 276 | } | 
|  | 277 |  | 
|  | 278 | Manager::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 Joseph | f1101df | 2020-11-06 08:23:34 +0530 | [diff] [blame] | 283 | { | 
|  | 284 | fs::path biosDir(BIOS_PERSIST_PATH); | 
|  | 285 | fs::create_directories(biosDir); | 
|  | 286 | biosFile = biosDir / biosPersistFile; | 
|  | 287 | deserialize(biosFile, *this); | 
|  | 288 | } | 
| Kuiying Wang | 642f437 | 2020-08-12 15:35:46 +0800 | [diff] [blame] | 289 |  | 
|  | 290 | } // namespace bios_config | 
|  | 291 |  | 
|  | 292 | int 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 | } |