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 <phosphor-logging/lg2.hpp> 25 #include <sdbusplus/asio/connection.hpp> 26 #include <sdbusplus/asio/object_server.hpp> 27 28 namespace bios_config 29 { 30 31 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 32 using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error; 33 34 void Manager::setAttribute(AttributeName attribute, AttributeValue value) 35 { 36 auto pendingAttrs = Base::pendingAttributes(); 37 auto iter = pendingAttrs.find(attribute); 38 39 if (iter != pendingAttrs.end()) 40 { 41 std::get<1>(iter->second) = value; 42 } 43 else 44 { 45 Manager::PendingAttribute attributeValue; 46 47 if (std::get_if<int64_t>(&value)) 48 { 49 std::get<0>(attributeValue) = AttributeType::Integer; 50 } 51 else 52 { 53 std::get<0>(attributeValue) = AttributeType::String; 54 } 55 56 std::get<1>(attributeValue) = value; 57 pendingAttrs.emplace(attribute, attributeValue); 58 } 59 60 pendingAttributes(pendingAttrs); 61 } 62 63 Manager::AttributeDetails Manager::getAttribute(AttributeName attribute) 64 { 65 Manager::AttributeDetails value; 66 67 auto table = Base::baseBIOSTable(); 68 auto iter = table.find(attribute); 69 70 if (iter != table.end()) 71 { 72 std::get<0>(value) = 73 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); 74 std::get<1>(value) = 75 std::get<static_cast<uint8_t>(Index::currentValue)>(iter->second); 76 77 auto pending = Base::pendingAttributes(); 78 auto pendingIter = pending.find(attribute); 79 if (pendingIter != pending.end()) 80 { 81 std::get<2>(value) = std::get<1>(pendingIter->second); 82 } 83 else if (std::get_if<std::string>(&std::get<1>(value))) 84 { 85 std::get<2>(value) = std::string(); 86 } 87 } 88 else 89 { 90 throw AttributeNotFound(); 91 } 92 93 return value; 94 } 95 96 Manager::BaseTable Manager::baseBIOSTable(BaseTable value) 97 { 98 pendingAttributes({}); 99 auto baseTable = Base::baseBIOSTable(value, false); 100 serialize(*this, biosFile); 101 Base::resetBIOSSettings(Base::ResetFlag::NoAction); 102 return baseTable; 103 } 104 105 bool Manager::validateEnumOption( 106 const std::string& attrValue, 107 const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>, 108 std::string>>& options) 109 { 110 for (const auto& enumOptions : options) 111 { 112 if ((BoundType::OneOf == std::get<0>(enumOptions)) && 113 (attrValue == std::get<std::string>(std::get<1>(enumOptions)))) 114 { 115 return true; 116 } 117 } 118 119 lg2::error("No valid attribute"); 120 return false; 121 } 122 123 bool Manager::validateStringOption( 124 const std::string& attrValue, 125 const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>, 126 std::string>>& options) 127 { 128 size_t minStringLength = 0; 129 size_t maxStringLength = 0; 130 for (const auto& stringOptions : options) 131 { 132 if (BoundType::MinStringLength == std::get<0>(stringOptions)) 133 { 134 minStringLength = std::get<int64_t>(std::get<1>(stringOptions)); 135 } 136 else if (BoundType::MaxStringLength == std::get<0>(stringOptions)) 137 { 138 maxStringLength = std::get<int64_t>(std::get<1>(stringOptions)); 139 } 140 else 141 { 142 continue; 143 } 144 } 145 146 if (attrValue.length() < minStringLength || 147 attrValue.length() > maxStringLength) 148 { 149 lg2::error( 150 "{ATTRVALUE} Length is out of range, bound is invalid, maxStringLength = {MAXLEN}, minStringLength = {MINLEN}", 151 "ATTRVALUE", attrValue, "MAXLEN", maxStringLength, "MINLEN", 152 minStringLength); 153 return false; 154 } 155 156 return true; 157 } 158 159 bool Manager::validateIntegerOption( 160 const int64_t& attrValue, 161 const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>, 162 std::string>>& options) 163 { 164 int64_t lowerBound = 0; 165 int64_t upperBound = 0; 166 int64_t scalarIncrement = 0; 167 168 for (const auto& integerOptions : options) 169 { 170 if (BoundType::LowerBound == std::get<0>(integerOptions)) 171 { 172 lowerBound = std::get<int64_t>(std::get<1>(integerOptions)); 173 } 174 else if (BoundType::UpperBound == std::get<0>(integerOptions)) 175 { 176 upperBound = std::get<int64_t>(std::get<1>(integerOptions)); 177 } 178 else if (BoundType::ScalarIncrement == std::get<0>(integerOptions)) 179 { 180 scalarIncrement = std::get<int64_t>(std::get<1>(integerOptions)); 181 } 182 } 183 184 if ((attrValue < lowerBound) || (attrValue > upperBound)) 185 { 186 lg2::error("Integer, bound is invalid"); 187 return false; 188 } 189 190 if (scalarIncrement == 0 || 191 ((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0) 192 { 193 lg2::error( 194 "((std::abs({ATTR_VALUE} - {LOWER_BOUND})) % {SCALAR_INCREMENT}) != 0", 195 "ATTR_VALUE", attrValue, "LOWER_BOUND", lowerBound, 196 "SCALAR_INCREMENT", scalarIncrement); 197 return false; 198 } 199 200 return true; 201 } 202 203 Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value) 204 { 205 // Clear the pending attributes 206 if (value.empty()) 207 { 208 auto pendingAttrs = Base::pendingAttributes({}, false); 209 serialize(*this, biosFile); 210 return pendingAttrs; 211 } 212 213 // Validate all the BIOS attributes before setting PendingAttributes 214 BaseTable biosTable = Base::baseBIOSTable(); 215 for (const auto& pair : value) 216 { 217 auto iter = biosTable.find(pair.first); 218 // BIOS attribute not found in the BaseBIOSTable 219 if (iter == biosTable.end()) 220 { 221 lg2::error("BIOS attribute not found in the BaseBIOSTable"); 222 throw AttributeNotFound(); 223 } 224 225 auto attributeType = 226 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); 227 if (attributeType != std::get<0>(pair.second)) 228 { 229 lg2::error("attributeType is not same with bios base table"); 230 throw InvalidArgument(); 231 } 232 233 // Validate enumeration BIOS attributes 234 if (attributeType == AttributeType::Enumeration) 235 { 236 // For enumeration the expected variant types is Enumeration 237 if (std::get<1>(pair.second).index() == 0) 238 { 239 lg2::error("Enumeration property value is not enum"); 240 throw InvalidArgument(); 241 } 242 243 const auto& attrValue = 244 std::get<std::string>(std::get<1>(pair.second)); 245 const auto& options = 246 std::get<static_cast<uint8_t>(Index::options)>(iter->second); 247 248 if (!validateEnumOption(attrValue, options)) 249 { 250 throw InvalidArgument(); 251 } 252 } 253 254 if (attributeType == AttributeType::String) 255 { 256 // For enumeration the expected variant types is std::string 257 if (std::get<1>(pair.second).index() == 0) 258 { 259 lg2::error("String property value is not string"); 260 throw InvalidArgument(); 261 } 262 263 const auto& attrValue = 264 std::get<std::string>(std::get<1>(pair.second)); 265 const auto& options = 266 std::get<static_cast<uint8_t>(Index::options)>(iter->second); 267 268 if (!validateStringOption(attrValue, options)) 269 { 270 throw InvalidArgument(); 271 } 272 } 273 274 if (attributeType == AttributeType::Integer) 275 { 276 // For enumeration the expected variant types is Integer 277 if (std::get<1>(pair.second).index() == 1) 278 { 279 lg2::error("Enumeration property value is not int"); 280 throw InvalidArgument(); 281 } 282 283 const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second)); 284 const auto& options = 285 std::get<static_cast<uint8_t>(Index::options)>(iter->second); 286 287 if (!validateIntegerOption(attrValue, options)) 288 { 289 throw InvalidArgument(); 290 } 291 } 292 } 293 294 PendingAttributes pendingAttribute = Base::pendingAttributes(); 295 296 for (const auto& pair : value) 297 { 298 auto iter = pendingAttribute.find(pair.first); 299 if (iter != pendingAttribute.end()) 300 { 301 iter = pendingAttribute.erase(iter); 302 } 303 304 pendingAttribute.emplace(std::make_pair(pair.first, pair.second)); 305 } 306 307 auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false); 308 serialize(*this, biosFile); 309 310 return pendingAttrs; 311 } 312 313 Manager::Manager(sdbusplus::asio::object_server& objectServer, 314 std::shared_ptr<sdbusplus::asio::connection>& systemBus) : 315 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus, 316 objectPath), 317 objServer(objectServer), systemBus(systemBus) 318 { 319 fs::path biosDir(BIOS_PERSIST_PATH); 320 fs::create_directories(biosDir); 321 biosFile = biosDir / biosPersistFile; 322 deserialize(biosFile, *this); 323 } 324 325 } // namespace bios_config 326