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 // BIOS attribute is read only 128 if (std::get<static_cast<uint8_t>(Index::readOnly)>(iter->second)) 129 { 130 phosphor::logging::log<phosphor::logging::level::ERR>( 131 "BIOS attribute is read only"); 132 throw AttributeReadOnly(); 133 } 134 135 auto attributeType = 136 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); 137 if (attributeType != std::get<0>(pair.second)) 138 { 139 phosphor::logging::log<phosphor::logging::level::ERR>( 140 "attributeType is not same with bios base table"); 141 throw InvalidArgument(); 142 } 143 144 // Validate enumeration BIOS attributes 145 if (attributeType == AttributeType::Enumeration) 146 { 147 // For enumeration the expected variant types is Enumeration 148 if (std::get<1>(pair.second).index() == 0) 149 { 150 phosphor::logging::log<phosphor::logging::level::ERR>( 151 "Enumeration property value is not enum"); 152 throw InvalidArgument(); 153 } 154 155 const auto& attrValue = 156 std::get<std::string>(std::get<1>(pair.second)); 157 const auto& options = 158 std::get<static_cast<uint8_t>(Index::options)>(iter->second); 159 160 bool found = false; 161 for (const auto& enumOptions : options) 162 { 163 if ((BoundType::OneOf == std::get<0>(enumOptions)) && 164 (attrValue == 165 std::get<std::string>(std::get<1>(enumOptions)))) 166 { 167 found = true; 168 break; 169 } 170 } 171 172 if (!found) 173 { 174 phosphor::logging::log<phosphor::logging::level::ERR>( 175 "No valid attribute"); 176 throw InvalidArgument(); 177 } 178 } 179 180 if (attributeType == AttributeType::String) 181 { 182 // For enumeration the expected variant types is std::string 183 if (std::get<1>(pair.second).index() == 0) 184 { 185 phosphor::logging::log<phosphor::logging::level::ERR>( 186 "String property value is not string"); 187 throw InvalidArgument(); 188 } 189 190 const auto& attrValue = 191 std::get<std::string>(std::get<1>(pair.second)); 192 const auto& options = 193 std::get<static_cast<uint8_t>(Index::options)>(iter->second); 194 int64_t minStringLength = 0; 195 int64_t maxStringLength = 0; 196 197 for (const auto& stringOptions : options) 198 { 199 if (BoundType::MinStringLength == std::get<0>(stringOptions)) 200 { 201 minStringLength = 202 std::get<int64_t>(std::get<1>(stringOptions)); 203 } 204 else if (BoundType::MaxStringLength == 205 std::get<0>(stringOptions)) 206 { 207 maxStringLength = 208 std::get<int64_t>(std::get<1>(stringOptions)); 209 } 210 } 211 212 if ((attrValue.length() < static_cast<size_t>(minStringLength)) || 213 (attrValue.length() > static_cast<size_t>(maxStringLength))) 214 { 215 phosphor::logging::log<phosphor::logging::level::ERR>( 216 "std::string, length is invalid"); 217 throw InvalidArgument(); 218 } 219 } 220 221 if (attributeType == AttributeType::Integer) 222 { 223 // For enumeration the expected variant types is Integer 224 if (std::get<1>(pair.second).index() == 1) 225 { 226 phosphor::logging::log<phosphor::logging::level::ERR>( 227 "Enumeration property value is not int"); 228 throw InvalidArgument(); 229 } 230 231 const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second)); 232 const auto& options = 233 std::get<static_cast<uint8_t>(Index::options)>(iter->second); 234 int64_t lowerBound = 0; 235 int64_t upperBound = 0; 236 int64_t scalarIncrement = 0; 237 238 for (const auto& integerOptions : options) 239 { 240 if (BoundType::LowerBound == std::get<0>(integerOptions)) 241 { 242 lowerBound = std::get<int64_t>(std::get<1>(integerOptions)); 243 } 244 else if (BoundType::UpperBound == std::get<0>(integerOptions)) 245 { 246 upperBound = std::get<int64_t>(std::get<1>(integerOptions)); 247 } 248 else if (BoundType::ScalarIncrement == 249 std::get<0>(integerOptions)) 250 { 251 scalarIncrement = 252 std::get<int64_t>(std::get<1>(integerOptions)); 253 } 254 } 255 256 if ((attrValue < lowerBound) || (attrValue > upperBound)) 257 { 258 phosphor::logging::log<phosphor::logging::level::ERR>( 259 "Integer, bound is invalid"); 260 throw InvalidArgument(); 261 } 262 263 if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0) 264 { 265 phosphor::logging::log<phosphor::logging::level::ERR>( 266 "((std::abs(attrValue - lowerBound)) % scalarIncrement) != " 267 "0"); 268 throw InvalidArgument(); 269 } 270 } 271 } 272 273 PendingAttributes pendingAttribute = Base::pendingAttributes(); 274 275 for (const auto& pair : value) 276 { 277 auto iter = pendingAttribute.find(pair.first); 278 if (iter != pendingAttribute.end()) 279 { 280 iter = pendingAttribute.erase(iter); 281 } 282 283 pendingAttribute.emplace(std::make_pair(pair.first, pair.second)); 284 } 285 286 auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false); 287 serialize(*this, biosFile); 288 289 return pendingAttrs; 290 } 291 292 Manager::Manager(sdbusplus::asio::object_server& objectServer, 293 std::shared_ptr<sdbusplus::asio::connection>& systemBus) : 294 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus, 295 objectPath), 296 objServer(objectServer), systemBus(systemBus) 297 { 298 fs::path biosDir(BIOS_PERSIST_PATH); 299 fs::create_directories(biosDir); 300 biosFile = biosDir / biosPersistFile; 301 deserialize(biosFile, *this); 302 } 303 304 } // namespace bios_config 305 306 int main() 307 { 308 boost::asio::io_service io; 309 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); 310 311 systemBus->request_name(bios_config::service); 312 sdbusplus::asio::object_server objectServer(systemBus); 313 bios_config::Manager manager(objectServer, systemBus); 314 315 io.run(); 316 return 0; 317 } 318