| /* |
| Copyright (c) 2020 Intel Corporation |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http:www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #include "manager.hpp" |
| |
| #include "manager_serialize.hpp" |
| #include "xyz/openbmc_project/BIOSConfig/Common/error.hpp" |
| #include "xyz/openbmc_project/Common/error.hpp" |
| |
| #include <boost/asio.hpp> |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <phosphor-logging/lg2.hpp> |
| #include <sdbusplus/asio/connection.hpp> |
| #include <sdbusplus/asio/object_server.hpp> |
| |
| namespace bios_config |
| { |
| |
| using namespace sdbusplus::xyz::openbmc_project::Common::Error; |
| using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error; |
| |
| void Manager::setAttribute(AttributeName attribute, AttributeValue value) |
| { |
| auto pendingAttrs = Base::pendingAttributes(); |
| auto iter = pendingAttrs.find(attribute); |
| |
| if (iter != pendingAttrs.end()) |
| { |
| std::get<1>(iter->second) = value; |
| } |
| else |
| { |
| Manager::PendingAttribute attributeValue; |
| |
| if (std::get_if<int64_t>(&value)) |
| { |
| std::get<0>(attributeValue) = AttributeType::Integer; |
| } |
| else |
| { |
| std::get<0>(attributeValue) = AttributeType::String; |
| } |
| |
| std::get<1>(attributeValue) = value; |
| pendingAttrs.emplace(attribute, attributeValue); |
| } |
| |
| pendingAttributes(pendingAttrs); |
| } |
| |
| Manager::AttributeDetails Manager::getAttribute(AttributeName attribute) |
| { |
| Manager::AttributeDetails value; |
| |
| auto table = Base::baseBIOSTable(); |
| auto iter = table.find(attribute); |
| |
| if (iter != table.end()) |
| { |
| std::get<0>(value) = |
| std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); |
| std::get<1>(value) = |
| std::get<static_cast<uint8_t>(Index::currentValue)>(iter->second); |
| |
| auto pending = Base::pendingAttributes(); |
| auto pendingIter = pending.find(attribute); |
| if (pendingIter != pending.end()) |
| { |
| std::get<2>(value) = std::get<1>(pendingIter->second); |
| } |
| else if (std::get_if<std::string>(&std::get<1>(value))) |
| { |
| std::get<2>(value) = std::string(); |
| } |
| } |
| else |
| { |
| throw AttributeNotFound(); |
| } |
| |
| return value; |
| } |
| |
| Manager::BaseTable Manager::baseBIOSTable(BaseTable value) |
| { |
| pendingAttributes({}); |
| auto baseTable = Base::baseBIOSTable(value, false); |
| serialize(*this, biosFile); |
| Base::resetBIOSSettings(Base::ResetFlag::NoAction); |
| return baseTable; |
| } |
| |
| bool Manager::validateEnumOption( |
| const std::string& attrValue, |
| const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>, |
| std::string>>& options) |
| { |
| for (const auto& enumOptions : options) |
| { |
| if ((BoundType::OneOf == std::get<0>(enumOptions)) && |
| (attrValue == std::get<std::string>(std::get<1>(enumOptions)))) |
| { |
| return true; |
| } |
| } |
| |
| lg2::error("No valid attribute"); |
| return false; |
| } |
| |
| bool Manager::validateStringOption( |
| const std::string& attrValue, |
| const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>, |
| std::string>>& options) |
| { |
| size_t minStringLength = 0; |
| size_t maxStringLength = 0; |
| for (const auto& stringOptions : options) |
| { |
| if (BoundType::MinStringLength == std::get<0>(stringOptions)) |
| { |
| minStringLength = std::get<int64_t>(std::get<1>(stringOptions)); |
| } |
| else if (BoundType::MaxStringLength == std::get<0>(stringOptions)) |
| { |
| maxStringLength = std::get<int64_t>(std::get<1>(stringOptions)); |
| } |
| else |
| { |
| continue; |
| } |
| } |
| |
| if (attrValue.length() < minStringLength || |
| attrValue.length() > maxStringLength) |
| { |
| lg2::error( |
| "{ATTRVALUE} Length is out of range, bound is invalid, maxStringLength = {MAXLEN}, minStringLength = {MINLEN}", |
| "ATTRVALUE", attrValue, "MAXLEN", maxStringLength, "MINLEN", |
| minStringLength); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool Manager::validateIntegerOption( |
| const int64_t& attrValue, |
| const std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>, |
| std::string>>& options) |
| { |
| int64_t lowerBound = 0; |
| int64_t upperBound = 0; |
| int64_t scalarIncrement = 0; |
| |
| for (const auto& integerOptions : options) |
| { |
| if (BoundType::LowerBound == std::get<0>(integerOptions)) |
| { |
| lowerBound = std::get<int64_t>(std::get<1>(integerOptions)); |
| } |
| else if (BoundType::UpperBound == std::get<0>(integerOptions)) |
| { |
| upperBound = std::get<int64_t>(std::get<1>(integerOptions)); |
| } |
| else if (BoundType::ScalarIncrement == std::get<0>(integerOptions)) |
| { |
| scalarIncrement = std::get<int64_t>(std::get<1>(integerOptions)); |
| } |
| } |
| |
| if ((attrValue < lowerBound) || (attrValue > upperBound)) |
| { |
| lg2::error("Integer, bound is invalid"); |
| return false; |
| } |
| |
| if (scalarIncrement == 0 || |
| ((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0) |
| { |
| lg2::error( |
| "((std::abs({ATTR_VALUE} - {LOWER_BOUND})) % {SCALAR_INCREMENT}) != 0", |
| "ATTR_VALUE", attrValue, "LOWER_BOUND", lowerBound, |
| "SCALAR_INCREMENT", scalarIncrement); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value) |
| { |
| // Clear the pending attributes |
| if (value.empty()) |
| { |
| auto pendingAttrs = Base::pendingAttributes({}, false); |
| serialize(*this, biosFile); |
| return pendingAttrs; |
| } |
| |
| // Validate all the BIOS attributes before setting PendingAttributes |
| BaseTable biosTable = Base::baseBIOSTable(); |
| for (const auto& pair : value) |
| { |
| auto iter = biosTable.find(pair.first); |
| // BIOS attribute not found in the BaseBIOSTable |
| if (iter == biosTable.end()) |
| { |
| lg2::error("BIOS attribute not found in the BaseBIOSTable"); |
| throw AttributeNotFound(); |
| } |
| |
| auto attributeType = |
| std::get<static_cast<uint8_t>(Index::attributeType)>(iter->second); |
| if (attributeType != std::get<0>(pair.second)) |
| { |
| lg2::error("attributeType is not same with bios base table"); |
| throw InvalidArgument(); |
| } |
| |
| // Validate enumeration BIOS attributes |
| if (attributeType == AttributeType::Enumeration) |
| { |
| // For enumeration the expected variant types is Enumeration |
| if (std::get<1>(pair.second).index() == 0) |
| { |
| lg2::error("Enumeration property value is not enum"); |
| throw InvalidArgument(); |
| } |
| |
| const auto& attrValue = |
| std::get<std::string>(std::get<1>(pair.second)); |
| const auto& options = |
| std::get<static_cast<uint8_t>(Index::options)>(iter->second); |
| |
| if (!validateEnumOption(attrValue, options)) |
| { |
| throw InvalidArgument(); |
| } |
| } |
| |
| if (attributeType == AttributeType::String) |
| { |
| // For enumeration the expected variant types is std::string |
| if (std::get<1>(pair.second).index() == 0) |
| { |
| lg2::error("String property value is not string"); |
| throw InvalidArgument(); |
| } |
| |
| const auto& attrValue = |
| std::get<std::string>(std::get<1>(pair.second)); |
| const auto& options = |
| std::get<static_cast<uint8_t>(Index::options)>(iter->second); |
| |
| if (!validateStringOption(attrValue, options)) |
| { |
| throw InvalidArgument(); |
| } |
| } |
| |
| if (attributeType == AttributeType::Integer) |
| { |
| // For enumeration the expected variant types is Integer |
| if (std::get<1>(pair.second).index() == 1) |
| { |
| lg2::error("Integer property value is not int"); |
| throw InvalidArgument(); |
| } |
| |
| const auto& attrValue = std::get<int64_t>(std::get<1>(pair.second)); |
| const auto& options = |
| std::get<static_cast<uint8_t>(Index::options)>(iter->second); |
| |
| if (!validateIntegerOption(attrValue, options)) |
| { |
| throw InvalidArgument(); |
| } |
| } |
| } |
| |
| PendingAttributes pendingAttribute = Base::pendingAttributes(); |
| |
| for (const auto& pair : value) |
| { |
| auto iter = pendingAttribute.find(pair.first); |
| if (iter != pendingAttribute.end()) |
| { |
| iter = pendingAttribute.erase(iter); |
| } |
| |
| pendingAttribute.emplace(std::make_pair(pair.first, pair.second)); |
| } |
| |
| auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false); |
| serialize(*this, biosFile); |
| |
| return pendingAttrs; |
| } |
| |
| void Manager::convertBiosDataToVersion1(Manager::oldBaseTable biosTbl, |
| Manager::BaseTable& baseTable) |
| { |
| lg2::error("convertBiosDataToVersion1"); |
| for (const auto& [key, baseTuple] : biosTbl) |
| { |
| const auto& vec = std::get<7>(baseTuple); |
| std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>, |
| std::string>> |
| dataVec; |
| |
| for (const auto& [value, variantVal] : vec) |
| { |
| dataVec.emplace_back(value, variantVal, |
| ""); // Copy VDN as empty string |
| } |
| |
| if (std::get<0>(baseTuple) == AttributeType::Integer) |
| { |
| baseTable[key] = std::make_tuple( |
| std::get<0>(baseTuple), std::get<1>(baseTuple), |
| std::get<2>(baseTuple), std::get<3>(baseTuple), |
| std::get<4>(baseTuple), |
| std::get<int64_t>(std::get<5>(baseTuple)), |
| std::get<int64_t>(std::get<6>(baseTuple)), dataVec); |
| } |
| else |
| { |
| baseTable[key] = std::make_tuple( |
| std::get<0>(baseTuple), std::get<1>(baseTuple), |
| std::get<2>(baseTuple), std::get<3>(baseTuple), |
| std::get<4>(baseTuple), |
| std::get<std::string>(std::get<5>(baseTuple)), |
| std::get<std::string>(std::get<6>(baseTuple)), dataVec); |
| } |
| } |
| } |
| |
| void Manager::convertBiosDataToVersion0(Manager::oldBaseTable& baseTable, |
| Manager::BaseTable& biosTbl) |
| { |
| lg2::error("convertBiosDataToVersion0"); |
| for (const auto& [key, baseTuple] : biosTbl) |
| { |
| const auto& vec = std::get<7>(baseTuple); |
| std::vector<std::tuple<BoundType, std::variant<int64_t, std::string>>> |
| dataVec; |
| |
| for (const auto& [value, variantVal, vDisplayName] : vec) |
| { |
| dataVec.emplace_back(value, variantVal); // Remove VDN |
| } |
| |
| if (std::get<0>(baseTuple) == AttributeType::Integer) |
| { |
| baseTable[key] = std::make_tuple( |
| std::get<0>(baseTuple), std::get<1>(baseTuple), |
| std::get<2>(baseTuple), std::get<3>(baseTuple), |
| std::get<4>(baseTuple), |
| std::get<int64_t>(std::get<5>(baseTuple)), |
| std::get<int64_t>(std::get<6>(baseTuple)), dataVec); |
| } |
| else |
| { |
| baseTable[key] = std::make_tuple( |
| std::get<0>(baseTuple), std::get<1>(baseTuple), |
| std::get<2>(baseTuple), std::get<3>(baseTuple), |
| std::get<4>(baseTuple), |
| std::get<std::string>(std::get<5>(baseTuple)), |
| std::get<std::string>(std::get<6>(baseTuple)), dataVec); |
| } |
| } |
| } |
| |
| Manager::Manager(sdbusplus::asio::object_server& objectServer, |
| std::shared_ptr<sdbusplus::asio::connection>& systemBus, |
| std::string persistPath) : |
| sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager( |
| *systemBus, objectPath), |
| objServer(objectServer), systemBus(systemBus) |
| { |
| fs::path biosDir(persistPath); |
| fs::create_directories(biosDir); |
| biosFile = biosDir / biosPersistFile; |
| deserialize(biosFile, *this); |
| } |
| |
| } // namespace bios_config |