blob: cfb7a4e0e984621fe654a74174edb4a9a67261fb [file] [log] [blame]
/*
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