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