libpldmresponder: Implement SetBIOSTable
Register the setBIOSTable method and set separately string table,
attribute table, and attribute value table.
When the attribute value table is set, the corresponding D-Bus
property value needs to updated.
Tested:
test with JSON:
https://gist.github.com/lxwinspur/2afffff2e445fddf90dfed6eceef4014
~# pldmtool raw -d 0x80 0x03 0x02 0x00 0x00 0x00 0x00 0x05 0x00 0x00 0x00 0x03 0x00 0x4c 0x65 0x64 0x01 0x00 0x03 0x00 0x4f 0x66 0x66 0x02 0x00 0x02 0x00 0x4f 0x6e 0x23 0x4d 0x50 0x09
Request Message:
08 01 80 03 02 00 00 00 00 05 00 00 00 03 00 4c 65 64 01 00 03 00 4f 66 66 02 00 02 00 4f 6e 23 4d 50 09
Response Message:
08 01 00 03 02 00 00 00 00 00
~# pldmtool raw -d 0x80 0x03 0x02 0x00 0x00 0x00 0x00 0x05 0x01 0x00 0x00 0x00 0x00 0x00 0x02 0x02 0x00 0x01 0x00 0x01 0x01 0xff 0x10 0x22 0x77
Request Message:
08 01 80 03 02 00 00 00 00 05 01 00 00 00 00 00 02 02 00 01 00 01 01 ff 10 22 77
Response Message:
08 01 00 03 02 00 00 00 00 00
~# pldmtool raw -d 0x80 0x03 0x02 0x00 0x00 0x00 0x00 0x05 0x02 0x00 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0xbc 0x91 0xfe 0xe0
Request Message:
08 01 80 03 02 00 00 00 00 05 02 00 00 00 01 01 00 00 00 bc 91 fe e0
Response Message:
08 01 00 03 02 00 00 00 00 00
~# pldmtool bios GetBIOSTable -t 0
PLDM StringTable:
BIOSStringHandle : BIOSString
0 : Led
1 : Off
2 : On
~# pldmtool bios GetBIOSTable -t 1
PLDM AttributeTable:
AttributeHandle: 0, AttributeNameHandle: 0(Led)
AttributeType: BIOSEnumeration
NumberOfPossibleValues: 2
PossibleValueStringHandle[0] = 2(On)
PossibleValueStringHandle[1] = 1(Off)
NumberOfDefaultValues: 1
DefaultValueStringHandleIndex[0] = 1, StringHandle = 1(Off)
~# pldmtool bios GetBIOSTable -t 2
PLDM AttributeValueTable:
AttributeHandle: 0
AttributeType: BIOSEnumeration
NumberOfCurrentValues: 1
CurrentValueStringHandleIndex[0] = 1, StringHandle = Off
Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I0ff88961afdfe0835c9fd0b56e37f7ed75f2fb45
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 4bfef06..a62d978 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -84,6 +84,10 @@
[this](const pldm_msg* request, size_t payloadLength) {
return this->getBIOSTable(request, payloadLength);
});
+ handlers.emplace(PLDM_SET_BIOS_TABLE,
+ [this](const pldm_msg* request, size_t payloadLength) {
+ return this->setBIOSTable(request, payloadLength);
+ });
handlers.emplace(PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE,
[this](const pldm_msg* request, size_t payloadLength) {
return this->getBIOSAttributeCurrentValueByHandle(
@@ -222,6 +226,40 @@
return response;
}
+Response Handler::setBIOSTable(const pldm_msg* request, size_t payloadLength)
+{
+ uint32_t transferHandle{};
+ uint8_t transferOpFlag{};
+ uint8_t tableType{};
+ struct variable_field field;
+
+ auto rc = decode_set_bios_table_req(request, payloadLength, &transferHandle,
+ &transferOpFlag, &tableType, &field);
+ if (rc != PLDM_SUCCESS)
+ {
+ return ccOnlyResponse(request, rc);
+ }
+
+ Table table(field.ptr, field.ptr + field.length);
+ rc = biosConfig.setBIOSTable(tableType, table);
+ if (rc != PLDM_SUCCESS)
+ {
+ return ccOnlyResponse(request, rc);
+ }
+
+ Response response(sizeof(pldm_msg_hdr) + PLDM_SET_BIOS_TABLE_RESP_BYTES);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+ rc = encode_set_bios_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
+ 0 /* nxtTransferHandle */, responsePtr);
+ if (rc != PLDM_SUCCESS)
+ {
+ return ccOnlyResponse(request, rc);
+ }
+
+ return response;
+}
+
Response Handler::getBIOSAttributeCurrentValueByHandle(const pldm_msg* request,
size_t payloadLength)
{
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
index f3cf5f9..9cfb22b 100644
--- a/libpldmresponder/bios.hpp
+++ b/libpldmresponder/bios.hpp
@@ -45,6 +45,14 @@
*/
Response getBIOSTable(const pldm_msg* request, size_t payloadLength);
+ /** @brief Handler for SetBIOSTable
+ *
+ * @param[in] request - Request message
+ * @param[in] payload_length - Request message payload length
+ * @return Response - PLDM Response message
+ */
+ Response setBIOSTable(const pldm_msg* request, size_t payloadLength);
+
/** @brief Handler for GetBIOSAttributeCurrentValueByHandle
*
* @param[in] request - Request message
diff --git a/libpldmresponder/bios_config.cpp b/libpldmresponder/bios_config.cpp
index c1810de..805b172 100644
--- a/libpldmresponder/bios_config.cpp
+++ b/libpldmresponder/bios_config.cpp
@@ -4,6 +4,7 @@
#include "bios_integer_attribute.hpp"
#include "bios_string_attribute.hpp"
#include "bios_table.hpp"
+#include "common/bios_utils.hpp"
#include <fstream>
#include <iostream>
@@ -30,7 +31,7 @@
BIOSConfig::BIOSConfig(const char* jsonDir, const char* tableDir,
DBusHandler* const dbusHandler) :
jsonDir(jsonDir),
- tableDir(tableDir), dbusHandler(dbusHandler)
+ tableDir(tableDir), dbusHandler(dbusHandler), isUpdateProperty(false)
{
fs::create_directories(tableDir);
constructAttributes();
@@ -63,6 +64,378 @@
return loadTable(tablePath);
}
+int BIOSConfig::setBIOSTable(uint8_t tableType, const Table& table)
+{
+ fs::path stringTablePath(tableDir / stringTableFile);
+ fs::path attrTablePath(tableDir / attrTableFile);
+ fs::path attrValueTablePath(tableDir / attrValueTableFile);
+
+ if (!pldm_bios_table_checksum(table.data(), table.size()))
+ {
+ return PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK;
+ }
+
+ if (tableType == PLDM_BIOS_STRING_TABLE)
+ {
+ storeTable(stringTablePath, table);
+ }
+ else if (tableType == PLDM_BIOS_ATTR_TABLE)
+ {
+ BIOSTable biosStringTable(stringTablePath.c_str());
+ if (biosStringTable.isEmpty())
+ {
+ return PLDM_INVALID_BIOS_TABLE_TYPE;
+ }
+
+ auto rc = checkAttributeTable(table);
+ if (rc != PLDM_SUCCESS)
+ {
+ return rc;
+ }
+
+ storeTable(attrTablePath, table);
+ }
+ else if (tableType == PLDM_BIOS_ATTR_VAL_TABLE)
+ {
+ BIOSTable biosStringTable(stringTablePath.c_str());
+ BIOSTable biosStringValueTable(attrTablePath.c_str());
+ if (biosStringTable.isEmpty() || biosStringValueTable.isEmpty())
+ {
+ return PLDM_INVALID_BIOS_TABLE_TYPE;
+ }
+
+ auto rc = checkAttributeValueTable(table);
+ if (rc != PLDM_SUCCESS)
+ {
+ return rc;
+ }
+
+ storeTable(attrValueTablePath, table);
+ isUpdateProperty = true;
+ }
+ else
+ {
+ return PLDM_INVALID_BIOS_TABLE_TYPE;
+ }
+
+ if (isUpdateProperty)
+ {
+ isUpdateProperty = false;
+ updateBaseBIOSTableProperty();
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int BIOSConfig::checkAttributeTable(const Table& table)
+{
+ using namespace pldm::bios::utils;
+ auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+ for (auto entry :
+ BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(table.data(), table.size()))
+ {
+ auto attrNameHandle =
+ pldm_bios_table_attr_entry_decode_string_handle(entry);
+
+ auto stringEnty = pldm_bios_table_string_find_by_handle(
+ stringTable->data(), stringTable->size(), attrNameHandle);
+ if (stringEnty == nullptr)
+ {
+ return PLDM_INVALID_BIOS_ATTR_HANDLE;
+ }
+
+ auto attrType = static_cast<pldm_bios_attribute_type>(
+ pldm_bios_table_attr_entry_decode_attribute_type(entry));
+
+ switch (attrType)
+ {
+ case PLDM_BIOS_ENUMERATION:
+ case PLDM_BIOS_ENUMERATION_READ_ONLY:
+ {
+ auto pvNum =
+ pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+ std::vector<uint16_t> pvHandls(pvNum);
+ pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+ entry, pvHandls.data(), pvHandls.size());
+ auto defNum =
+ pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+ std::vector<uint8_t> defIndices(defNum);
+ pldm_bios_table_attr_entry_enum_decode_def_indices(
+ entry, defIndices.data(), defIndices.size());
+
+ for (size_t i = 0; i < pvHandls.size(); i++)
+ {
+ auto stringEntry = pldm_bios_table_string_find_by_handle(
+ stringTable->data(), stringTable->size(), pvHandls[i]);
+ if (stringEntry == nullptr)
+ {
+ return PLDM_INVALID_BIOS_ATTR_HANDLE;
+ }
+ }
+
+ for (size_t i = 0; i < defIndices.size(); i++)
+ {
+ auto stringEntry = pldm_bios_table_string_find_by_handle(
+ stringTable->data(), stringTable->size(),
+ pvHandls[defIndices[i]]);
+ if (stringEntry == nullptr)
+ {
+ return PLDM_INVALID_BIOS_ATTR_HANDLE;
+ }
+ }
+ break;
+ }
+ case PLDM_BIOS_INTEGER:
+ case PLDM_BIOS_INTEGER_READ_ONLY:
+ case PLDM_BIOS_STRING:
+ case PLDM_BIOS_STRING_READ_ONLY:
+ case PLDM_BIOS_PASSWORD:
+ case PLDM_BIOS_PASSWORD_READ_ONLY:
+ break;
+ default:
+ return PLDM_INVALID_BIOS_ATTR_HANDLE;
+ }
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int BIOSConfig::checkAttributeValueTable(const Table& table)
+{
+ using namespace pldm::bios::utils;
+ auto stringTable = getBIOSTable(PLDM_BIOS_STRING_TABLE);
+ auto attrTable = getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+ baseBIOSTableMaps.clear();
+
+ for (auto tableEntry :
+ BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(table.data(), table.size()))
+ {
+ AttributeName attributeName{};
+ AttributeType attributeType{};
+ ReadonlyStatus readonlyStatus{};
+ DisplayName displayName{};
+ Description description{};
+ MenuPath menuPath{};
+ CurrentValue currentValue{};
+ DefaultValue defaultValue{};
+ Option options{};
+
+ auto attrValueHandle =
+ pldm_bios_table_attr_value_entry_decode_attribute_handle(
+ tableEntry);
+ auto attrType = static_cast<pldm_bios_attribute_type>(
+ pldm_bios_table_attr_value_entry_decode_attribute_type(tableEntry));
+
+ auto attrEntry = pldm_bios_table_attr_find_by_handle(
+ attrTable->data(), attrTable->size(), attrValueHandle);
+ if (attrEntry == nullptr)
+ {
+ return PLDM_INVALID_BIOS_ATTR_HANDLE;
+ }
+ auto attrHandle =
+ pldm_bios_table_attr_entry_decode_attribute_handle(attrEntry);
+ auto attrNameHandle =
+ pldm_bios_table_attr_entry_decode_string_handle(attrEntry);
+
+ auto stringEntry = pldm_bios_table_string_find_by_handle(
+ stringTable->data(), stringTable->size(), attrNameHandle);
+ if (stringEntry == nullptr)
+ {
+ return PLDM_INVALID_BIOS_ATTR_HANDLE;
+ }
+ auto strLength =
+ pldm_bios_table_string_entry_decode_string_length(stringEntry);
+ std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
+ pldm_bios_table_string_entry_decode_string(stringEntry, buffer.data(),
+ buffer.size());
+ attributeName = std::string(buffer.data(), buffer.data() + strLength);
+
+ if (!biosAttributes.empty())
+ {
+ readonlyStatus =
+ biosAttributes[attrHandle / biosAttributes.size()]->readOnly;
+ }
+
+ switch (attrType)
+ {
+ case PLDM_BIOS_ENUMERATION:
+ case PLDM_BIOS_ENUMERATION_READ_ONLY:
+ {
+ auto getValue = [](uint16_t handle,
+ const Table& table) -> std::string {
+ auto stringEntry = pldm_bios_table_string_find_by_handle(
+ table.data(), table.size(), handle);
+
+ auto strLength =
+ pldm_bios_table_string_entry_decode_string_length(
+ stringEntry);
+ std::vector<char> buffer(strLength + 1 /* sizeof '\0' */);
+ pldm_bios_table_string_entry_decode_string(
+ stringEntry, buffer.data(), buffer.size());
+
+ return std::string(buffer.data(),
+ buffer.data() + strLength);
+ };
+
+ attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
+ "AttributeType.Enumeration";
+
+ auto pvNum =
+ pldm_bios_table_attr_entry_enum_decode_pv_num(attrEntry);
+ std::vector<uint16_t> pvHandls(pvNum);
+ pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+ attrEntry, pvHandls.data(), pvHandls.size());
+
+ // get possible_value
+ for (size_t i = 0; i < pvHandls.size(); i++)
+ {
+ options.push_back(
+ std::make_tuple("xyz.openbmc_project.BIOSConfig."
+ "Manager.BoundType.OneOf",
+ getValue(pvHandls[i], *stringTable)));
+ }
+
+ auto count =
+ pldm_bios_table_attr_value_entry_enum_decode_number(
+ tableEntry);
+ std::vector<uint8_t> handles(count);
+ pldm_bios_table_attr_value_entry_enum_decode_handles(
+ tableEntry, handles.data(), handles.size());
+
+ // get current_value
+ for (size_t i = 0; i < handles.size(); i++)
+ {
+ currentValue = getValue(pvHandls[handles[i]], *stringTable);
+ }
+
+ auto defNum =
+ pldm_bios_table_attr_entry_enum_decode_def_num(attrEntry);
+ std::vector<uint8_t> defIndices(defNum);
+ pldm_bios_table_attr_entry_enum_decode_def_indices(
+ attrEntry, defIndices.data(), defIndices.size());
+
+ // get default_value
+ for (size_t i = 0; i < defIndices.size(); i++)
+ {
+ defaultValue =
+ getValue(pvHandls[defIndices[i]], *stringTable);
+ }
+
+ break;
+ }
+ case PLDM_BIOS_INTEGER:
+ case PLDM_BIOS_INTEGER_READ_ONLY:
+ {
+ attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
+ "AttributeType.Integer";
+ currentValue = static_cast<int64_t>(
+ pldm_bios_table_attr_value_entry_integer_decode_cv(
+ tableEntry));
+
+ uint64_t lower, upper, def;
+ uint32_t scalar;
+ pldm_bios_table_attr_entry_integer_decode(
+ attrEntry, &lower, &upper, &scalar, &def);
+ options.push_back(
+ std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
+ "BoundType.LowerBound",
+ static_cast<int64_t>(lower)));
+ options.push_back(
+ std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
+ "BoundType.UpperBound",
+ static_cast<int64_t>(upper)));
+ options.push_back(
+ std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
+ "BoundType.ScalarIncrement",
+ static_cast<int64_t>(scalar)));
+ defaultValue = static_cast<int64_t>(def);
+ break;
+ }
+ case PLDM_BIOS_STRING:
+ case PLDM_BIOS_STRING_READ_ONLY:
+ {
+ attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
+ "AttributeType.String";
+ variable_field currentString;
+ pldm_bios_table_attr_value_entry_string_decode_string(
+ tableEntry, ¤tString);
+ currentValue = std::string(
+ reinterpret_cast<const char*>(currentString.ptr),
+ currentString.length);
+ auto min = pldm_bios_table_attr_entry_string_decode_min_length(
+ attrEntry);
+ auto max = pldm_bios_table_attr_entry_string_decode_max_length(
+ attrEntry);
+ auto def =
+ pldm_bios_table_attr_entry_string_decode_def_string_length(
+ attrEntry);
+ std::vector<char> defString(def + 1);
+ pldm_bios_table_attr_entry_string_decode_def_string(
+ attrEntry, defString.data(), defString.size());
+ options.push_back(
+ std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
+ "BoundType.MinStringLength",
+ static_cast<int64_t>(min)));
+ options.push_back(
+ std::make_tuple("xyz.openbmc_project.BIOSConfig.Manager."
+ "BoundType.MaxStringLength",
+ static_cast<int64_t>(max)));
+ defaultValue = defString.data();
+ break;
+ }
+ case PLDM_BIOS_PASSWORD:
+ case PLDM_BIOS_PASSWORD_READ_ONLY:
+ {
+ attributeType = "xyz.openbmc_project.BIOSConfig.Manager."
+ "AttributeType.Password";
+ break;
+ }
+ default:
+ return PLDM_INVALID_BIOS_ATTR_HANDLE;
+ }
+ baseBIOSTableMaps.emplace(
+ std::move(attributeName),
+ std::make_tuple(attributeType, readonlyStatus, displayName,
+ description, menuPath, currentValue, defaultValue,
+ std::move(options)));
+ }
+
+ return PLDM_SUCCESS;
+}
+
+void BIOSConfig::updateBaseBIOSTableProperty()
+{
+ constexpr static auto biosConfigPath =
+ "/xyz/openbmc_project/bios_config/manager";
+ constexpr static auto biosConfigInterface =
+ "xyz.openbmc_project.BIOSConfig.Manager";
+ constexpr static auto biosConfigPropertyName = "BaseBIOSTable";
+ constexpr static auto dbusProperties = "org.freedesktop.DBus.Properties";
+
+ if (baseBIOSTableMaps.empty())
+ {
+ return;
+ }
+
+ try
+ {
+ auto& bus = dbusHandler->getBus();
+ auto service =
+ dbusHandler->getService(biosConfigPath, biosConfigInterface);
+ auto method = bus.new_method_call(service.c_str(), biosConfigPath,
+ dbusProperties, "Set");
+ std::variant<BaseBIOSTable> value = baseBIOSTableMaps;
+ method.append(biosConfigInterface, biosConfigPropertyName, value);
+ bus.call_noreply(method);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "failed to update BaseBIOSTable property, ERROR="
+ << e.what() << "\n";
+ }
+}
+
void BIOSConfig::constructAttributes()
{
load(jsonDir / stringJsonFile, [this](const Json& entry) {
@@ -102,9 +475,8 @@
table::appendPadAndChecksum(attrTable);
table::appendPadAndChecksum(attrValueTable);
-
- storeTable(tableDir / attrTableFile, attrTable);
- storeTable(tableDir / attrValueTableFile, attrValueTable);
+ setBIOSTable(PLDM_BIOS_ATTR_TABLE, attrTable);
+ setBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE, attrValueTable);
}
std::optional<Table> BIOSConfig::buildAndStoreStringTable()
@@ -137,7 +509,7 @@
}
table::appendPadAndChecksum(table);
- storeTable(tableDir / stringTableFile, table);
+ setBIOSTable(PLDM_BIOS_STRING_TABLE, table);
return table;
}
diff --git a/libpldmresponder/bios_config.hpp b/libpldmresponder/bios_config.hpp
index 430798f..8782640 100644
--- a/libpldmresponder/bios_config.hpp
+++ b/libpldmresponder/bios_config.hpp
@@ -22,6 +22,32 @@
namespace bios
{
+enum class BoundType
+{
+ LowerBound,
+ UpperBound,
+ ScalarIncrement,
+ MinStringLength,
+ MaxStringLength,
+ OneOf
+};
+
+using AttributeName = std::string;
+using AttributeType = std::string;
+using ReadonlyStatus = bool;
+using DisplayName = std::string;
+using Description = std::string;
+using MenuPath = std::string;
+using CurrentValue = std::variant<int64_t, std::string>;
+using DefaultValue = std::variant<int64_t, std::string>;
+using OptionString = std::string;
+using OptionValue = std::variant<int64_t, std::string>;
+using Option = std::vector<std::tuple<OptionString, OptionValue>>;
+using BIOSTableObj =
+ std::tuple<AttributeType, ReadonlyStatus, DisplayName, Description,
+ MenuPath, CurrentValue, DefaultValue, Option>;
+using BaseBIOSTable = std::map<AttributeName, BIOSTableObj>;
+
/** @class BIOSConfig
* @brief Manager BIOS Attributes
*/
@@ -62,10 +88,21 @@
*/
std::optional<Table> getBIOSTable(pldm_bios_table_types tableType);
+ /** @brief set BIOS table
+ * @param[in] tableType - Indicates what table is being transferred
+ * {BIOSStringTable=0x0, BIOSAttributeTable=0x1,
+ * BIOSAttributeValueTable=0x2}
+ * @param[in] table - table data
+ * @return pldm_completion_codes
+ */
+ int setBIOSTable(uint8_t tableType, const Table& table);
+
private:
const fs::path jsonDir;
const fs::path tableDir;
DBusHandler* const dbusHandler;
+ bool isUpdateProperty;
+ BaseBIOSTable baseBIOSTableMaps;
// vector persists all attributes
using BIOSAttributes = std::vector<std::unique_ptr<BIOSAttribute>>;
@@ -167,6 +204,22 @@
int checkAttrValueToUpdate(
const pldm_bios_attr_val_table_entry* attrValueEntry,
const pldm_bios_attr_table_entry* attrEntry, Table& stringTable);
+
+ /** @brief Check the attribute table
+ * @param[in] table - The table
+ * @return pldm_completion_codes
+ */
+ int checkAttributeTable(const Table& table);
+
+ /** @brief Check the attribute value table
+ * @param[in] table - The table
+ * @return pldm_completion_codes
+ */
+ int checkAttributeValueTable(const Table& table);
+
+ /** @brief Update the BaseBIOSTable property of the D-Bus interface
+ */
+ void updateBaseBIOSTableProperty();
};
} // namespace bios