support runtime update of BIOS attributes
Register the BIOSConfig/PendingAttributes signal and when the out of band
redfish user updates the BIOS attributes, the pldm daemon should process and
check the PendingAttributes porperty, and then update the
BIOSConfig/BaseBIOSTable property and the BIOS table.
Tested: test JSON with
https://gist.github.com/lxwinspur/2afffff2e445fddf90dfed6eceef4014
Type.Enumeration:
~#: busctl set-property xyz.openbmc_project.BIOSConfigManager
/xyz/openbmc_project/bios_config/manager
xyz.openbmc_project.BIOSConfig.Manager PendingAttributes a\{s\(sv\)\} 1
"Led" "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Enumeration" s
"xyz.openbmc_project.Led.Physical.Action.On"
~#: pldmtool bios getbiostable -t 2
PLDM AttributeValueTable:
... ...
AttributeHandle: 3
AttributeType: BIOSEnumeration
NumberOfCurrentValues: 1
CurrentValueStringHandleIndex[0] = 0, StringHandle = On
... ...
Type.String
~#: busctl set-property xyz.openbmc_project.BIOSConfigManager
/xyz/openbmc_project/bios_config/manager
xyz.openbmc_project.BIOSConfig.Manager PendingAttributes a\{s\(sv\)\} 1
"Model" "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String" s
"testModel"
~#: pldmtool bios getbiostable -t 2
PLDM AttributeValueTable:
AttributeHandle: 0
AttributeType: BIOSString
CurrentStringLength: 10
CurrentString: testModel
... ...
Type.Integer
~#: busctl set-property xyz.openbmc_project.BIOSConfigManager
/xyz/openbmc_project/bios_config/manager
xyz.openbmc_project.BIOSConfig.Manager PendingAttributes a\{s\(sv\)\} 1
"OUTLET" "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer" x
1000
~#: pldmtool bios getbiostable -t 2
... ...
AttributeHandle: 2
AttributeType: BIOSInteger
CurrentValue: 1000
... ...
Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I4d4d2941e6c9bfa7f6fccb664db1580f2ffc9c9f
diff --git a/libpldmresponder/bios_attribute.hpp b/libpldmresponder/bios_attribute.hpp
index 7b4116a..7a15c09 100644
--- a/libpldmresponder/bios_attribute.hpp
+++ b/libpldmresponder/bios_attribute.hpp
@@ -73,6 +73,15 @@
uint8_t attrType,
const PropertyValue& newPropVal) = 0;
+ /** @brief Generate attribute entry by the spec DSP0247_1.0.0 Table 14
+ * @param[in] attributevalue - attribute value(Enumeration, String and
+ * Integer)
+ * @param[in,out] attrValueEntry - attribute entry
+ */
+ virtual void generateAttributeEntry(
+ const std::variant<int64_t, std::string>& attributevalue,
+ Table& attrValueEntry) = 0;
+
/** @brief Method to return the D-Bus map */
std::optional<DBusMapping> getDBusMap();
diff --git a/libpldmresponder/bios_config.cpp b/libpldmresponder/bios_config.cpp
index ee634c9..e3d89a6 100644
--- a/libpldmresponder/bios_config.cpp
+++ b/libpldmresponder/bios_config.cpp
@@ -6,6 +6,8 @@
#include "bios_table.hpp"
#include "common/bios_utils.hpp"
+#include <xyz/openbmc_project/BIOSConfig/Manager/server.hpp>
+
#include <fstream>
#include <iostream>
@@ -18,6 +20,9 @@
namespace
{
+using BIOSConfigManager =
+ sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager;
+
constexpr auto enumJsonFile = "enum_attrs.json";
constexpr auto stringJsonFile = "string_attrs.json";
constexpr auto integerJsonFile = "integer_attrs.json";
@@ -35,6 +40,7 @@
{
fs::create_directories(tableDir);
constructAttributes();
+ listenPendingAttributes();
}
void BIOSConfig::buildTables()
@@ -782,6 +788,107 @@
}
}
+uint16_t BIOSConfig::findAttrHandle(const std::string& attrName)
+{
+ auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+ auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+ BIOSStringTable biosStringTable(*stringTable);
+ pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(
+ attrTable->data(), attrTable->size());
+ auto stringHandle = biosStringTable.findHandle(attrName);
+
+ for (auto entry : pldm::bios::utils::BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(
+ attrTable->data(), attrTable->size()))
+ {
+ auto header = table::attribute::decodeHeader(entry);
+ if (header.stringHandle == stringHandle)
+ {
+ return header.attrHandle;
+ }
+ }
+
+ throw std::invalid_argument("Unknow attribute Name");
+}
+
+void BIOSConfig::constructPendingAttribute(
+ const PendingAttributes& pendingAttributes)
+{
+ for (auto& attribute : pendingAttributes)
+ {
+ std::string attributeName = attribute.first;
+ auto& [attributeType, attributevalue] = attribute.second;
+
+ auto iter = std::find_if(biosAttributes.begin(), biosAttributes.end(),
+ [&attributeName](const auto& attr) {
+ return attr->name == attributeName;
+ });
+
+ if (iter == biosAttributes.end())
+ {
+ std::cerr << "Wrong attribute name, attributeName = "
+ << attributeName << std::endl;
+ continue;
+ }
+
+ Table attrValueEntry(sizeof(pldm_bios_attr_val_table_entry), 0);
+ auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
+ attrValueEntry.data());
+
+ auto handler = findAttrHandle(attributeName);
+ auto type =
+ BIOSConfigManager::convertAttributeTypeFromString(attributeType);
+
+ if (type != BIOSConfigManager::AttributeType::Enumeration &&
+ type != BIOSConfigManager::AttributeType::String &&
+ type != BIOSConfigManager::AttributeType::Integer)
+ {
+ std::cerr << "Attribute type not supported, attributeType = "
+ << attributeType << std::endl;
+ continue;
+ }
+
+ entry->attr_handle = htole16(handler);
+ (*iter)->generateAttributeEntry(attributevalue, attrValueEntry);
+
+ setAttrValue(attrValueEntry.data(), attrValueEntry.size());
+ }
+}
+
+void BIOSConfig::listenPendingAttributes()
+{
+ constexpr auto objPath = "/xyz/openbmc_project/bios_config/manager";
+ constexpr auto objInterface = "xyz.openbmc_project.BIOSConfig.Manager";
+
+ using namespace sdbusplus::bus::match::rules;
+ auto updateBIOSMatch = std::make_unique<sdbusplus::bus::match::match>(
+ pldm::utils::DBusHandler::getBus(),
+ propertiesChanged(objPath, objInterface),
+ [this](sdbusplus::message::message& msg) {
+ constexpr auto propertyName = "PendingAttributes";
+
+ using Value =
+ std::variant<std::string, PendingAttributes, BaseBIOSTable>;
+ using Properties = std::map<DbusProp, Value>;
+
+ Properties props{};
+ std::string intf;
+ msg.read(intf, props);
+
+ auto valPropMap = props.find(propertyName);
+ if (valPropMap == props.end())
+ {
+ return;
+ }
+
+ PendingAttributes pendingAttributes =
+ std::get<PendingAttributes>(valPropMap->second);
+ this->constructPendingAttribute(pendingAttributes);
+ });
+
+ biosAttrMatch.emplace_back(std::move(updateBIOSMatch));
+}
+
} // namespace bios
} // namespace responder
} // namespace pldm
diff --git a/libpldmresponder/bios_config.hpp b/libpldmresponder/bios_config.hpp
index 8782640..b10ca78 100644
--- a/libpldmresponder/bios_config.hpp
+++ b/libpldmresponder/bios_config.hpp
@@ -48,6 +48,9 @@
MenuPath, CurrentValue, DefaultValue, Option>;
using BaseBIOSTable = std::map<AttributeName, BIOSTableObj>;
+using PendingObj = std::tuple<AttributeType, CurrentValue>;
+using PendingAttributes = std::map<AttributeName, PendingObj>;
+
/** @class BIOSConfig
* @brief Manager BIOS Attributes
*/
@@ -220,6 +223,23 @@
/** @brief Update the BaseBIOSTable property of the D-Bus interface
*/
void updateBaseBIOSTableProperty();
+
+ /** @brief Listen the PendingAttributes property of the D-Bus interface and
+ * update BaseBIOSTable
+ */
+ void listenPendingAttributes();
+
+ /** @brief Find attribute handle from bios attribute table
+ * @param[in] attrName - attribute name
+ * @return attribute handle
+ */
+ uint16_t findAttrHandle(const std::string& attrName);
+
+ /** @brief Listen the PendingAttributes property of the D-Bus interface
+ * and update BaseBIOSTable
+ * @param[in] msg - Data associated with subscribed signal
+ */
+ void constructPendingAttribute(const PendingAttributes& pendingAttributes);
};
} // namespace bios
diff --git a/libpldmresponder/bios_enum_attribute.cpp b/libpldmresponder/bios_enum_attribute.cpp
index ecbb8f5..e799cee 100644
--- a/libpldmresponder/bios_enum_attribute.cpp
+++ b/libpldmresponder/bios_enum_attribute.cpp
@@ -147,6 +147,30 @@
}
}
+uint8_t BIOSEnumAttribute::getAttrValueIndex(const PropertyValue& propValue)
+{
+ auto defaultValueIndex = getValueIndex(defaultValue, possibleValues);
+ if (readOnly)
+ {
+ return defaultValueIndex;
+ }
+
+ try
+ {
+ auto iter = valMap.find(propValue);
+ if (iter == valMap.end())
+ {
+ return defaultValueIndex;
+ }
+ auto currentValue = iter->second;
+ return getValueIndex(currentValue, possibleValues);
+ }
+ catch (const std::exception& e)
+ {
+ return defaultValueIndex;
+ }
+}
+
void BIOSEnumAttribute::setAttrValueOnDbus(
const pldm_bios_attr_val_table_entry* attrValueEntry,
const pldm_bios_attr_table_entry* attrEntry,
@@ -220,6 +244,21 @@
return PLDM_SUCCESS;
}
+void BIOSEnumAttribute::generateAttributeEntry(
+ const std::variant<int64_t, std::string>& attributevalue,
+ Table& attrValueEntry)
+{
+ attrValueEntry.resize(sizeof(pldm_bios_attr_val_table_entry) + 1);
+
+ auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
+ attrValueEntry.data());
+
+ std::string value = std::get<std::string>(attributevalue);
+ entry->attr_type = 0;
+ entry->value[0] = 1; // number of current values, default 1
+ entry->value[1] = getAttrValueIndex(value);
+}
+
} // namespace bios
} // namespace responder
} // namespace pldm
diff --git a/libpldmresponder/bios_enum_attribute.hpp b/libpldmresponder/bios_enum_attribute.hpp
index c86d9d7..e69d76d 100644
--- a/libpldmresponder/bios_enum_attribute.hpp
+++ b/libpldmresponder/bios_enum_attribute.hpp
@@ -51,6 +51,15 @@
void constructEntry(const BIOSStringTable& stringTable, Table& attrTable,
Table& attrValueTable) override;
+ /** @brief Generate attribute entry by the spec DSP0247_1.0.0 Table 14
+ * @param[in] attributevalue - attribute value(Enumeration, String and
+ * Integer)
+ * @param[in,out] attrValueEntry - attribute entry
+ */
+ void generateAttributeEntry(
+ const std::variant<int64_t, std::string>& attributevalue,
+ Table& attrValueEntry) override;
+
int updateAttrVal(Table& newValue, uint16_t attrHdl, uint8_t attrType,
const PropertyValue& newPropVal);
@@ -89,6 +98,13 @@
* @return The index of the current value in possible values
*/
uint8_t getAttrValueIndex();
+
+ /** @brief Get index of the property value in possible values
+ * @param[in] propValue - property values
+ *
+ * @return The index of the property value in possible values
+ */
+ uint8_t getAttrValueIndex(const PropertyValue& propValue);
};
} // namespace bios
diff --git a/libpldmresponder/bios_integer_attribute.cpp b/libpldmresponder/bios_integer_attribute.cpp
index d6d1214..a4bc14b 100644
--- a/libpldmresponder/bios_integer_attribute.cpp
+++ b/libpldmresponder/bios_integer_attribute.cpp
@@ -191,6 +191,21 @@
return PLDM_SUCCESS;
}
+void BIOSIntegerAttribute::generateAttributeEntry(
+ const std::variant<int64_t, std::string>& attributevalue,
+ Table& attrValueEntry)
+{
+ attrValueEntry.resize(sizeof(pldm_bios_attr_val_table_entry) +
+ sizeof(int64_t) - 1);
+
+ auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
+ attrValueEntry.data());
+
+ int64_t value = std::get<int64_t>(attributevalue);
+ entry->attr_type = 3;
+ memcpy(entry->value, &value, sizeof(int64_t));
+}
+
} // namespace bios
} // namespace responder
} // namespace pldm
diff --git a/libpldmresponder/bios_integer_attribute.hpp b/libpldmresponder/bios_integer_attribute.hpp
index e180066..5f2773a 100644
--- a/libpldmresponder/bios_integer_attribute.hpp
+++ b/libpldmresponder/bios_integer_attribute.hpp
@@ -47,6 +47,15 @@
void constructEntry(const BIOSStringTable& stringTable, Table& attrTable,
Table& attrValueTable) override;
+ /** @brief Generate attribute entry by the spec DSP0247_1.0.0 Table 14
+ * @param[in] attributevalue - attribute value(Enumeration, String and
+ * Integer)
+ * @param[in,out] attrValueEntry - attribute entry
+ */
+ void generateAttributeEntry(
+ const std::variant<int64_t, std::string>& attributevalue,
+ Table& attrValueEntry) override;
+
int updateAttrVal(Table& newValue, uint16_t attrHdl, uint8_t attrType,
const PropertyValue& newPropVal);
diff --git a/libpldmresponder/bios_string_attribute.cpp b/libpldmresponder/bios_string_attribute.cpp
index 1453644..19819c9 100644
--- a/libpldmresponder/bios_string_attribute.cpp
+++ b/libpldmresponder/bios_string_attribute.cpp
@@ -129,6 +129,24 @@
return PLDM_SUCCESS;
}
+void BIOSStringAttribute::generateAttributeEntry(
+ const std::variant<int64_t, std::string>& attributevalue,
+ Table& attrValueEntry)
+{
+ std::string value = std::get<std::string>(attributevalue);
+ uint16_t len = value.size();
+
+ attrValueEntry.resize(sizeof(pldm_bios_attr_val_table_entry) +
+ sizeof(uint16_t) + len - 1);
+
+ auto entry = reinterpret_cast<pldm_bios_attr_val_table_entry*>(
+ attrValueEntry.data());
+
+ entry->attr_type = 1;
+ memcpy(entry->value, &len, sizeof(uint16_t));
+ memcpy(entry->value + sizeof(uint16_t), value.c_str(), value.size());
+}
+
} // namespace bios
} // namespace responder
} // namespace pldm
diff --git a/libpldmresponder/bios_string_attribute.hpp b/libpldmresponder/bios_string_attribute.hpp
index 3b29dc1..b079401 100644
--- a/libpldmresponder/bios_string_attribute.hpp
+++ b/libpldmresponder/bios_string_attribute.hpp
@@ -70,6 +70,15 @@
void constructEntry(const BIOSStringTable& stringTable, Table& attrTable,
Table& attrValueTable) override;
+ /** @brief Generate attribute entry by the spec DSP0247_1.0.0 Table 14
+ * @param[in] attributevalue - attribute value(Enumeration, String and
+ * Integer)
+ * @param[in,out] attrValueEntry - attribute entry
+ */
+ void generateAttributeEntry(
+ const std::variant<int64_t, std::string>& attributevalue,
+ Table& attrValueEntry) override;
+
int updateAttrVal(Table& newValue, uint16_t attrHdl, uint8_t attrType,
const PropertyValue& newPropVal);
diff --git a/test/libpldmresponder_bios_attribute_test.cpp b/test/libpldmresponder_bios_attribute_test.cpp
index b4200d3..8abaac7 100644
--- a/test/libpldmresponder_bios_attribute_test.cpp
+++ b/test/libpldmresponder_bios_attribute_test.cpp
@@ -32,6 +32,11 @@
{
return PLDM_SUCCESS;
}
+
+ void generateAttributeEntry(
+ const std::variant<int64_t, std::string>& /*attributevalue*/,
+ Table& /*attrValueEntry*/)
+ {}
};
TEST(BIOSAttribute, CtorTest)