BIOS: Implement attribute table with type string
Construct attribute table with type string based on string table.
Tested:
Following are the tables constructed from the sample json file present at
"test/bios_jsons/
$ hexdump -C stringTable
00000000 00 00 07 00 41 6c 6c 6f 77 65 64 01 00 10 00 43 |....Allowed....C|
00000010 6f 64 65 55 70 64 61 74 65 50 6f 6c 69 63 79 02 |odeUpdatePolicy.|
00000020 00 0a 00 43 6f 6e 63 75 72 72 65 6e 74 03 00 0a |...Concurrent...|
00000030 00 44 69 73 72 75 70 74 69 76 65 04 00 0a 00 46 |.Disruptive....F|
00000040 57 42 6f 6f 74 53 69 64 65 05 00 0f 00 48 4d 43 |WBootSide....HMC|
00000050 4d 61 6e 61 67 65 64 53 74 61 74 65 06 00 10 00 |ManagedState....|
00000060 49 6e 62 61 6e 64 43 6f 64 65 55 70 64 61 74 65 |InbandCodeUpdate|
00000070 07 00 0a 00 4e 6f 74 41 6c 6c 6f 77 65 64 08 00 |....NotAllowed..|
00000080 03 00 4f 66 66 09 00 02 00 4f 6e 0a 00 04 00 50 |..Off....On....P|
00000090 65 72 6d 0b 00 04 00 54 65 6d 70 0c 00 0c 00 73 |erm....Temp....s|
000000a0 74 72 5f 65 78 61 6d 70 6c 65 31 0d 00 0c 00 73 |tr_example1....s|
000000b0 74 72 5f 65 78 61 6d 70 6c 65 32 0e 00 0c 00 73 |tr_example2....s|
000000c0 74 72 5f 65 78 61 6d 70 6c 65 33 00 6c 11 89 d4 |tr_example3.l...|
$ hexdump -C attributeTable
00000000 00 00 00 01 00 02 02 00 03 00 01 00 01 00 00 04 |................|
00000010 00 02 0a 00 0b 00 01 00 02 00 00 05 00 02 08 00 |................|
00000020 09 00 01 01 03 00 00 06 00 02 00 00 07 00 01 00 |................|
00000030 04 00 01 0c 00 01 01 00 64 00 03 00 61 62 63 05 |........d...abc.|
00000040 00 01 0d 00 02 00 00 64 00 00 00 06 00 01 0e 00 |.......d........|
00000050 00 01 00 64 00 02 00 65 66 00 00 00 72 ef 0c 2a |...d...ef...r..*|
Change-Id: I272c59b96b5aa14571d01eeeaccd504ca7ac168b
Signed-off-by: Carol Wang <wangkair@cn.ibm.com>
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 6669688..90d86c8 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -591,6 +591,9 @@
namespace bios_type_string
{
+
+using namespace bios_parser::bios_string;
+
/** @brief Construct the attibute table for BIOS type String and
* String ReadOnly
* @param[in] BIOSStringTable - the string table
@@ -598,10 +601,63 @@
* @param[in,out] attributeTable - the attribute table
*
*/
-void constructAttrTable(const BIOSTable& /*BIOSStringTable*/,
- const char* /*biosJsonDir*/, Table& /*attributeTable*/)
+void constructAttrTable(const BIOSTable& BIOSStringTable,
+ const char* biosJsonDir, Table& attributeTable)
{
- // TODO
+ auto rc = setupValueLookup(biosJsonDir);
+ if (rc == -1)
+ {
+ log<level::ERR>("Failed to parse entries in Json file");
+ return;
+ }
+ const auto& attributeMap = getValues();
+ StringHandle strHandle;
+
+ for (const auto& [key, value] : attributeMap)
+ {
+ try
+ {
+ strHandle = findStringHandle(key, BIOSStringTable);
+ }
+ catch (InternalFailure& e)
+ {
+ log<level::ERR>("Could not find handle for BIOS string",
+ entry("ATTRIBUTE=%s", key.c_str()));
+ continue;
+ }
+
+ const auto& [type, strType, minStrLen, maxStrLen, defaultStrLen,
+ defaultStr] = value;
+ uint8_t typeOfAttr =
+ type ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
+
+ BIOSTableRow stringAttrTable(bios_parser::bios_string::attrTableSize +
+ defaultStr.size());
+ BIOSTableRow::iterator it = stringAttrTable.begin();
+ auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
+ stringAttrTable.data());
+ attrPtr->attr_handle = nextAttributeHandle();
+ attrPtr->attr_type = typeOfAttr;
+ attrPtr->string_handle = strHandle;
+
+ std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
+ std::copy_n(&strType, sizeof(uint8_t), it);
+ std::advance(it, sizeof(uint8_t));
+ std::copy_n(reinterpret_cast<const uint8_t*>(&minStrLen),
+ sizeof(uint16_t), it);
+ std::advance(it, sizeof(uint16_t));
+ std::copy_n(reinterpret_cast<const uint8_t*>(&maxStrLen),
+ sizeof(uint16_t), it);
+ std::advance(it, sizeof(uint16_t));
+ std::copy_n(reinterpret_cast<const uint8_t*>(&defaultStrLen),
+ sizeof(uint16_t), it);
+ std::advance(it, sizeof(uint16_t));
+ std::copy_n(defaultStr.data(), defaultStr.size(), it);
+ std::advance(it, defaultStr.size());
+
+ attributeTable.insert(attributeTable.end(), stringAttrTable.begin(),
+ stringAttrTable.end());
+ }
}
} // end namespace bios_type_string
diff --git a/libpldmresponder/bios_parser.cpp b/libpldmresponder/bios_parser.cpp
index 3933ad4..a6f07d8 100644
--- a/libpldmresponder/bios_parser.cpp
+++ b/libpldmresponder/bios_parser.cpp
@@ -15,6 +15,43 @@
namespace fs = std::filesystem;
using namespace phosphor::logging;
+namespace
+{
+
+const std::vector<Json> emptyJsonList{};
+const Json emptyJson{};
+
+} // namespace
+
+int parseBiosJsonFile(const char* dirPath, const std::string& fileName,
+ Json& fileData)
+{
+ int rc = 0;
+
+ fs::path filePath(dirPath);
+ filePath /= fileName;
+
+ std::ifstream jsonFile(filePath);
+ if (!jsonFile.is_open())
+ {
+ log<level::ERR>("BIOS config file does not exist",
+ entry("FILE=%s", filePath.c_str()));
+ rc = -1;
+ }
+ else
+ {
+ fileData = Json::parse(jsonFile, nullptr, false);
+ if (fileData.is_discarded())
+ {
+ log<level::ERR>("Parsing config file failed",
+ entry("FILE=%s", filePath.c_str()));
+ rc = -1;
+ }
+ }
+
+ return rc;
+}
+
namespace bios_enum
{
@@ -165,8 +202,7 @@
return rc;
}
- static const std::vector<Json> emptyList{};
- auto entries = fileData.value("entries", emptyList);
+ auto entries = fileData.value("entries", emptyJsonList);
// Iterate through each JSON object in the config file
for (const auto& entry : entries)
{
@@ -187,10 +223,10 @@
}
std::optional<internal::DBusMapping> dBusMap = std::nullopt;
- static const Json empty{};
+
if (entry.count("dbus") != 0)
{
- auto dBusEntry = entry.value("dbus", empty);
+ auto dBusEntry = entry.value("dbus", emptyJson);
dBusMap = std::make_optional<internal::DBusMapping>();
dBusMap.value().objectPath = dBusEntry.value("object_path", "");
dBusMap.value().interface = dBusEntry.value("interface", "");
@@ -251,6 +287,154 @@
} // namespace bios_enum
+namespace bios_string
+{
+
+/** @brief BIOS string types
+ */
+enum BiosStringEncoding
+{
+ UNKNOWN = 0x00,
+ ASCII = 0x01,
+ HEX = 0x02,
+ UTF_8 = 0x03,
+ UTF_16LE = 0x04,
+ UTF_16BE = 0x05,
+ VENDOR_SPECIFIC = 0xFF
+};
+
+const std::map<std::string, uint8_t> strTypeMap{
+ {"Unknown", UNKNOWN},
+ {"ASCII", ASCII},
+ {"Hex", HEX},
+ {"UTF-8", UTF_8},
+ {"UTF-16LE", UTF_16LE},
+ {"UTF-16LE", UTF_16LE},
+ {"Vendor Specific", VENDOR_SPECIFIC}};
+
+namespace internal
+{
+
+/** @struct DBusMapping
+ *
+ * Data structure for storing information regarding BIOS string attribute
+ * and the D-Bus object for the attribute.
+ */
+struct DBusMapping
+{
+ std::string objectPath; //!< D-Bus object path
+ std::string interface; //!< D-Bus interface
+ std::string propertyName; //!< D-Bus property name
+};
+
+/** @brief Map containing the possible and the default values for the BIOS
+ * string type attributes.
+ */
+AttrValuesMap valueMap;
+
+/** @brief Map containing the optional D-Bus property information about the
+ * BIOS string type attributes.
+ */
+std::map<AttrName, std::optional<DBusMapping>> attrLookup;
+
+} // namespace internal
+
+int setupValueLookup(const char* dirPath)
+{
+ int rc = 0;
+
+ if (!internal::valueMap.empty() && !internal::attrLookup.empty())
+ {
+ return rc;
+ }
+
+ Json fileData;
+ rc = parseBiosJsonFile(dirPath, bIOSStrJson, fileData);
+ if (rc != 0)
+ {
+ return rc;
+ }
+
+ auto entries = fileData.value("entries", emptyJsonList);
+ // Iterate through each JSON object in the config file
+ for (const auto& entry : entries)
+ {
+ std::string attr = entry.value("attribute_name", "");
+ // Transfer string type from string to enum
+ std::string strTypeTmp = entry.value("string_type", "Unknown");
+ auto iter = strTypeMap.find(strTypeTmp);
+ if (iter == strTypeMap.end())
+ {
+ log<level::ERR>(
+ "Wrong string type",
+ phosphor::logging::entry("STRING_TYPE=%s", strTypeTmp.c_str()),
+ phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
+ return -1;
+ }
+ uint8_t strType = iter->second;
+
+ uint16_t minStrLen = entry.value("minimum_string_length", 0);
+ uint16_t maxStrLen = entry.value("maximum_string_length", 0);
+ if (maxStrLen - minStrLen < 0)
+ {
+ log<level::ERR>(
+ "Maximum string length is smaller than minimum string length",
+ phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
+ return -1;
+ }
+ uint16_t defaultStrLen = entry.value("default_string_length", 0);
+ std::string defaultStr = entry.value("default_string", "");
+ if ((defaultStrLen == 0) && (defaultStr.size() > 0))
+ {
+ log<level::ERR>(
+ "Default string length is 0, but default string is existing",
+ phosphor::logging::entry("ATTRIBUTE_NAME=%s", attr.c_str()));
+ return -1;
+ }
+
+ // dbus handling
+ std::optional<internal::DBusMapping> dBusMap;
+
+ if (entry.count("dbus") != 0)
+ {
+ auto dBusEntry = entry.value("dbus", emptyJson);
+ dBusMap = std::make_optional<internal::DBusMapping>();
+ dBusMap->objectPath = dBusEntry.value("object_path", "");
+ dBusMap->interface = dBusEntry.value("interface", "");
+ dBusMap->propertyName = dBusEntry.value("property_name", "");
+ if (dBusMap->objectPath.empty() || dBusMap->interface.empty() ||
+ dBusMap->propertyName.empty())
+ {
+ log<level::ERR>(
+ "Invalid dbus config",
+ phosphor::logging::entry("OBJPATH=%s",
+ dBusMap->objectPath.c_str()),
+ phosphor::logging::entry("INTERFACE=%s",
+ dBusMap->interface.c_str()),
+ phosphor::logging::entry("PROPERTY_NAME=%s",
+ dBusMap->propertyName.c_str()));
+ return -1;
+ }
+ }
+
+ internal::attrLookup.emplace(attr, std::move(dBusMap));
+
+ // Defaulting all the types of attributes to BIOSString
+ internal::valueMap.emplace(
+ std::move(attr),
+ std::make_tuple(entry.count("dbus") == 0, strType, minStrLen,
+ maxStrLen, defaultStrLen, std::move(defaultStr)));
+ }
+
+ return rc;
+}
+
+const AttrValuesMap& getValues()
+{
+ return internal::valueMap;
+}
+} // namespace bios_string
+
Strings getStrings(const char* dirPath)
{
Strings biosStrings{};
@@ -279,8 +463,7 @@
continue;
}
- static const std::vector<Json> emptyList{};
- auto entries = fileData.value("entries", emptyList);
+ auto entries = fileData.value("entries", emptyJsonList);
// Iterate through each entry in the config file
for (auto& entry : entries)
diff --git a/libpldmresponder/bios_parser.hpp b/libpldmresponder/bios_parser.hpp
index 1f13f94..2edbc95 100644
--- a/libpldmresponder/bios_parser.hpp
+++ b/libpldmresponder/bios_parser.hpp
@@ -89,4 +89,50 @@
} // namespace bios_enum
+namespace bios_string
+{
+
+/** @brief Parse the JSON file specific to BIOSString and
+ * BIOSStringReadOnly types and populate the data structure for
+ * the corresponding possible values and the default value. Setup the
+ * data structure to lookup the current value of the BIOS string
+ * attribute. JSON is parsed once and the information is cached.
+ *
+ * @param[in] dirPath - directory path where all the BIOS configuration JSON
+ * exist
+ *
+ * @return 0 for success and negative return code for failure
+ */
+int setupValueLookup(const char* dirPath);
+
+using AttrName = std::string;
+using IsReadOnly = bool;
+using StrType = uint8_t;
+using MinStrLen = uint16_t;
+using MaxStrLen = uint16_t;
+using DefaultStrLen = uint16_t;
+using DefaultStr = std::string;
+using AttrValuesMap =
+ std::map<AttrName, std::tuple<IsReadOnly, StrType, MinStrLen, MaxStrLen,
+ DefaultStrLen, DefaultStr>>;
+/* attrTableSize is the sum of fixed length of members which construct a string
+ * attribute table, including attr_handle(uint16_t), attr_type(uint8_t),
+ * string_handle(uint16_t), strType(uint8_t), minStrLen(uint16_t),
+ * MaxStrLen(uint16_t), DefaultStrLen(uint16_t) */
+constexpr auto attrTableSize = 12;
+static_assert(attrTableSize == sizeof(uint16_t) + sizeof(uint8_t) +
+ sizeof(uint16_t) + sizeof(uint8_t) +
+ sizeof(uint16_t) + sizeof(uint16_t) +
+ sizeof(uint16_t));
+
+/** @brief Get the string related values and the default values for the
+ * BIOSString and BIOSStringReadOnly types
+ *
+ * @return information needed to build the BIOS attribute table specific to
+ * BIOSString and BIOSStringReadOnly types
+ */
+const AttrValuesMap& getValues();
+
+} // namespace bios_string
+
} // namespace bios_parser
diff --git a/test/bios_jsons/string_attrs.json b/test/bios_jsons/string_attrs.json
new file mode 100644
index 0000000..6133412
--- /dev/null
+++ b/test/bios_jsons/string_attrs.json
@@ -0,0 +1,40 @@
+{
+ "entries" : [
+ {
+ "attribute_name" : "str_example1",
+ "string_type" : "ASCII",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 3,
+ "default_string" : "abc",
+ "dbus" : {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc_project.str_example1.value",
+ "property_name" : "Str_example1",
+ "property_type" : "string"
+ }
+ },
+ {
+ "attribute_name" : "str_example2",
+ "string_type" : "Hex",
+ "minimum_string_length" : 0,
+ "maximum_string_length" : 100,
+ "default_string_length" : 0,
+ "default_string" : "",
+ "dbus" : {
+ "object_path" : "/xyz/abc/def",
+ "interface" : "xyz.openbmc_project.str_example2.value",
+ "property_name" : "Str_example2",
+ "property_type" : "string"
+ }
+ },
+ {
+ "attribute_name" : "str_example3",
+ "string_type" : "Unknown",
+ "minimum_string_length" : 1,
+ "maximum_string_length" : 100,
+ "default_string_length" : 2,
+ "default_string" : "ef"
+ }
+ ]
+}
diff --git a/test/libpldmresponder_bios_test.cpp b/test/libpldmresponder_bios_test.cpp
index b5b207b..d54ef2c 100644
--- a/test/libpldmresponder_bios_test.cpp
+++ b/test/libpldmresponder_bios_test.cpp
@@ -55,10 +55,11 @@
{
using namespace bios_parser;
// All the BIOS Strings in the BIOS JSON config files.
- Strings vec{"HMCManagedState", "On", "Off",
- "FWBootSide", "Perm", "Temp",
- "InbandCodeUpdate", "Allowed", "NotAllowed",
- "CodeUpdatePolicy", "Concurrent", "Disruptive"};
+ Strings vec{"HMCManagedState", "On", "Off",
+ "FWBootSide", "Perm", "Temp",
+ "InbandCodeUpdate", "Allowed", "NotAllowed",
+ "CodeUpdatePolicy", "Concurrent", "Disruptive",
+ "str_example1", "str_example2", "str_example3"};
Strings nullVec{};
@@ -67,6 +68,8 @@
ASSERT_EQ(strings == nullVec, true);
strings = bios_parser::getStrings("./bios_jsons");
+ std::sort(strings.begin(), strings.end());
+ std::sort(vec.begin(), vec.end());
ASSERT_EQ(strings == vec, true);
}