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