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 18 #include "manager_serialize.hpp" 19 #include "xyz/openbmc_project/BIOSConfig/Common/error.hpp" 20 #include "xyz/openbmc_project/Common/error.hpp" 21 22 #include <boost/asio.hpp> 23 #include <phosphor-logging/elog-errors.hpp> 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({}); 98 auto baseTable = Base::baseBIOSTable(value, false); 99 serialize(*this, biosFile); 100 Base::resetBIOSSettings(Base::ResetFlag::NoAction); 101 return baseTable; 102 } 103 104 Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value) 105 { 106 // Clear the pending attributes 107 if (value.empty()) 108 { 109 auto pendingAttrs = Base::pendingAttributes({}, false); 110 serialize(*this, biosFile); 111 return pendingAttrs; 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 { 122 phosphor::logging::log<phosphor::logging::level::ERR>( 123 "BIOS attribute not found in the BaseBIOSTable"); 124 throw AttributeNotFound(); 125 } 126 127 auto attributeType = 128 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); 129 if (attributeType != std::get<0>(pair.second)) 130 { 131 phosphor::logging::log<phosphor::logging::level::ERR>( 132 "attributeType is not same with bios base table"); 133 throw InvalidArgument(); 134 } 135 136 // Validate enumeration BIOS attributes 137 if (attributeType == AttributeType::Enumeration) 138 { 139 // For enumeration the expected variant types is Enumeration 140 if (std::get<1>(pair.second).index() == 0) 141 { 142 phosphor::logging::log<phosphor::logging::level::ERR>( 143 "Enumeration property value is not enum"); 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 { 166 phosphor::logging::log<phosphor::logging::level::ERR>( 167 "No valid attribute"); 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 { 177 phosphor::logging::log<phosphor::logging::level::ERR>( 178 "String property value is not string"); 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); 186 187 auto optionsIterator = options.begin(); 188 189 for (; optionsIterator != options.end(); ++optionsIterator) 190 { 191 if (std::get<1>(std::get<1>(*optionsIterator)) == attrValue) 192 { 193 break; 194 } 195 } 196 197 if (optionsIterator == options.end()) 198 { 199 std::string error = 200 attrValue + " is not a valid value for " + pair.first; 201 phosphor::logging::log<phosphor::logging::level::ERR>( 202 error.c_str()); 203 throw InvalidArgument(); 204 } 205 } 206 207 if (attributeType == AttributeType::Integer) 208 { 209 // For enumeration the expected variant types is Integer 210 if (std::get<1>(pair.second).index() == 1) 211 { 212 phosphor::logging::log<phosphor::logging::level::ERR>( 213 "Enumeration property value is not int"); 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 { 244 phosphor::logging::log<phosphor::logging::level::ERR>( 245 "Integer, bound is invalid"); 246 throw InvalidArgument(); 247 } 248 249 if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0) 250 { 251 phosphor::logging::log<phosphor::logging::level::ERR>( 252 "((std::abs(attrValue - lowerBound)) % scalarIncrement) != " 253 "0"); 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 272 auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false); 273 serialize(*this, biosFile); 274 275 return pendingAttrs; 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) 283 { 284 fs::path biosDir(BIOS_PERSIST_PATH); 285 fs::create_directories(biosDir); 286 biosFile = biosDir / biosPersistFile; 287 deserialize(biosFile, *this); 288 } 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 } 304