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 <sdbusplus/asio/connection.hpp> 24 #include <sdbusplus/asio/object_server.hpp> 25 26 namespace bios_config 27 { 28 29 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 30 using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error; 31 32 void Manager::setAttribute(AttributeName attribute, AttributeValue value) 33 { 34 auto pendingAttrs = Base::pendingAttributes(); 35 auto iter = pendingAttrs.find(attribute); 36 37 if (iter != pendingAttrs.end()) 38 { 39 std::get<1>(iter->second) = value; 40 } 41 else 42 { 43 Manager::PendingAttribute attributeValue; 44 45 if (std::get_if<int64_t>(&value)) 46 { 47 std::get<0>(attributeValue) = AttributeType::Integer; 48 } 49 else 50 { 51 std::get<0>(attributeValue) = AttributeType::String; 52 } 53 54 std::get<1>(attributeValue) = value; 55 pendingAttrs.emplace(attribute, attributeValue); 56 } 57 58 pendingAttributes(pendingAttrs); 59 } 60 61 Manager::AttributeDetails Manager::getAttribute(AttributeName attribute) 62 { 63 Manager::AttributeDetails value; 64 65 auto table = Base::baseBIOSTable(); 66 auto iter = table.find(attribute); 67 68 if (iter != table.end()) 69 { 70 std::get<0>(value) = 71 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); 72 std::get<1>(value) = 73 std::get<static_cast<uint8_t>(Index::currentValue)>(iter->second); 74 75 auto pending = Base::pendingAttributes(); 76 auto pendingIter = pending.find(attribute); 77 if (pendingIter != pending.end()) 78 { 79 std::get<2>(value) = std::get<1>(pendingIter->second); 80 } 81 else if (std::get_if<std::string>(&std::get<1>(value))) 82 { 83 std::get<2>(value) = std::string(); 84 } 85 } 86 else 87 { 88 throw AttributeNotFound(); 89 } 90 91 return value; 92 } 93 94 Manager::BaseTable Manager::baseBIOSTable(BaseTable value) 95 { 96 pendingAttributes({}); 97 auto baseTable = Base::baseBIOSTable(value, false); 98 serialize(*this, biosFile); 99 return baseTable; 100 } 101 102 Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value) 103 { 104 // Clear the pending attributes 105 if (value.empty()) 106 { 107 auto pendingAttrs = Base::pendingAttributes({}, false); 108 serialize(*this, biosFile); 109 return pendingAttrs; 110 } 111 112 // Validate all the BIOS attributes before setting PendingAttributes 113 BaseTable biosTable = Base::baseBIOSTable(); 114 for (const auto& pair : value) 115 { 116 auto iter = biosTable.find(pair.first); 117 // BIOS attribute not found in the BaseBIOSTable 118 if (iter == biosTable.end()) 119 { 120 throw AttributeNotFound(); 121 } 122 123 // BIOS attribute is read only 124 if (std::get<static_cast<uint8_t>(Index::readOnly)>(iter->second)) 125 { 126 throw AttributeReadOnly(); 127 } 128 129 auto attributeType = 130 std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); 131 if (attributeType != std::get<0>(pair.second)) 132 { 133 throw InvalidArgument(); 134 } 135 136 // Validate enumeration BIOS attributes 137 if (attributeType == AttributeType::Enumeration) 138 { 139 // For enumeration the expected variant types is std::string 140 if (std::get<1>(pair.second).index() == 0) 141 { 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 throw InvalidArgument(); 165 } 166 } 167 168 if (attributeType == AttributeType::String) 169 { 170 // For enumeration the expected variant types is std::string 171 if (std::get<1>(pair.second).index() == 0) 172 { 173 throw InvalidArgument(); 174 } 175 176 const auto& attrValue = 177 std::get<std::string>(std::get<1>(pair.second)); 178 const auto& options = 179 std::get<static_cast<uint8_t>(Index::options)>(iter->second); 180 int64_t minStringLength = 0; 181 int64_t maxStringLength = 0; 182 183 for (const auto& stringOptions : options) 184 { 185 if (BoundType::MinStringLength == std::get<0>(stringOptions)) 186 { 187 minStringLength = 188 std::get<int64_t>(std::get<1>(stringOptions)); 189 } 190 else if (BoundType::MaxStringLength == 191 std::get<0>(stringOptions)) 192 { 193 maxStringLength = 194 std::get<int64_t>(std::get<1>(stringOptions)); 195 } 196 } 197 198 if ((attrValue.length() < static_cast<size_t>(minStringLength)) || 199 (attrValue.length() > static_cast<size_t>(maxStringLength))) 200 { 201 throw InvalidArgument(); 202 } 203 } 204 205 if (attributeType == AttributeType::Integer) 206 { 207 // For enumeration the expected variant types is std::string 208 if (std::get<1>(pair.second).index() == 1) 209 { 210 throw InvalidArgument(); 211 } 212 213 const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second)); 214 const auto& options = 215 std::get<static_cast<uint8_t>(Index::options)>(iter->second); 216 int64_t lowerBound = 0; 217 int64_t upperBound = 0; 218 int64_t scalarIncrement = 0; 219 220 for (const auto& integerOptions : options) 221 { 222 if (BoundType::LowerBound == std::get<0>(integerOptions)) 223 { 224 lowerBound = std::get<int64_t>(std::get<1>(integerOptions)); 225 } 226 else if (BoundType::UpperBound == std::get<0>(integerOptions)) 227 { 228 upperBound = std::get<int64_t>(std::get<1>(integerOptions)); 229 } 230 else if (BoundType::ScalarIncrement == 231 std::get<0>(integerOptions)) 232 { 233 scalarIncrement = 234 std::get<int64_t>(std::get<1>(integerOptions)); 235 } 236 } 237 238 if ((attrValue < lowerBound) || (attrValue > upperBound)) 239 { 240 throw InvalidArgument(); 241 } 242 243 if (((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0) 244 { 245 throw InvalidArgument(); 246 } 247 } 248 } 249 250 PendingAttributes pendingAttribute = Base::pendingAttributes(); 251 252 for (const auto& pair : value) 253 { 254 auto iter = pendingAttribute.find(pair.first); 255 if (iter != pendingAttribute.end()) 256 { 257 iter = pendingAttribute.erase(iter); 258 } 259 260 pendingAttribute.emplace(std::make_pair(pair.first, pair.second)); 261 } 262 263 auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false); 264 serialize(*this, biosFile); 265 266 return pendingAttrs; 267 } 268 269 Manager::Manager(sdbusplus::asio::object_server& objectServer, 270 std::shared_ptr<sdbusplus::asio::connection>& systemBus) : 271 sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager(*systemBus, 272 objectPath), 273 objServer(objectServer), systemBus(systemBus) 274 { 275 fs::path biosDir(BIOS_PERSIST_PATH); 276 fs::create_directories(biosDir); 277 biosFile = biosDir / biosPersistFile; 278 deserialize(biosFile, *this); 279 } 280 281 } // namespace bios_config 282 283 int main() 284 { 285 boost::asio::io_service io; 286 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); 287 288 systemBus->request_name(bios_config::service); 289 sdbusplus::asio::object_server objectServer(systemBus); 290 bios_config::Manager manager(objectServer, systemBus); 291 292 io.run(); 293 return 0; 294 } 295