libpldm: bios: Implement iter for attr value table

Implement a handler to get the length of the attribute
value table entry, and then we can create iter for the attr
table

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: Iccaf1a55fa1c7a18fce990dd476703eb8b974c68
diff --git a/libpldm/bios_table.c b/libpldm/bios_table.c
index d59c48e..8a6e29a 100644
--- a/libpldm/bios_table.c
+++ b/libpldm/bios_table.c
@@ -254,8 +254,7 @@
 
 /** @brief Get length of an enum attribute entry
  */
-static size_t
-attr_table_entry_length_enum(const struct pldm_bios_attr_table_entry *entry)
+static size_t attr_table_entry_length_enum(const void *entry)
 {
 	uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
 	uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
@@ -375,8 +374,7 @@
 
 /** @brief Get length of a string attribute entry
  */
-static size_t
-attr_table_entry_length_string(const struct pldm_bios_attr_table_entry *entry)
+static size_t attr_table_entry_length_string(const void *entry)
 {
 	uint16_t def_str_len =
 	    pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
@@ -469,20 +467,31 @@
 	return PLDM_SUCCESS;
 }
 
-static size_t
-attr_table_entry_length_integer(const struct pldm_bios_attr_table_entry *entry)
+static size_t attr_table_entry_length_integer(const void *entry)
 {
 	(void)entry;
 	return pldm_bios_table_attr_entry_integer_encode_length();
 }
 
-struct attr_table_entry {
+struct table_entry_length {
 	uint8_t attr_type;
-	size_t (*entry_length_handler)(
-	    const struct pldm_bios_attr_table_entry *);
+	size_t (*entry_length_handler)(const void *);
 };
 
-static struct attr_table_entry attr_table_entrys[] = {
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static struct table_entry_length *find_table_entry_length_by_type(
+    uint8_t attr_type, struct table_entry_length *handlers, size_t count)
+{
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (attr_type == handlers[i].attr_type)
+			return &handlers[i];
+	}
+	return NULL;
+}
+
+static struct table_entry_length attr_table_entries[] = {
     {.attr_type = PLDM_BIOS_ENUMERATION,
      .entry_length_handler = attr_table_entry_length_enum},
     {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
@@ -497,23 +506,13 @@
      .entry_length_handler = attr_table_entry_length_integer},
 };
 
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
-static struct attr_table_entry *find_attr_table_entry_by_type(uint8_t attr_type)
-{
-	size_t i;
-	for (i = 0; i < ARRAY_SIZE(attr_table_entrys); i++) {
-		if (attr_type == attr_table_entrys[i].attr_type)
-			return &attr_table_entrys[i];
-	}
-	return NULL;
-}
-
 static size_t attr_table_entry_length(const void *table_entry)
 {
 	const struct pldm_bios_attr_table_entry *entry = table_entry;
-	struct attr_table_entry *attr_table_entry =
-	    find_attr_table_entry_by_type(entry->attr_type);
+	struct table_entry_length *attr_table_entry =
+	    find_table_entry_length_by_type(entry->attr_type,
+					    attr_table_entries,
+					    ARRAY_SIZE(attr_table_entries));
 	assert(attr_table_entry != NULL);
 	assert(attr_table_entry->entry_length_handler != NULL);
 
@@ -542,6 +541,12 @@
 		memcpy(&table_entry->value[1], handles, count);
 }
 
+uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
+    const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return entry->value[0];
+}
+
 int pldm_bios_table_attr_value_entry_encode_enum_check(
     void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
     uint8_t count, uint8_t *handles)
@@ -558,6 +563,13 @@
 	return PLDM_SUCCESS;
 }
 
+static size_t attr_value_table_entry_length_enum(const void *entry)
+{
+	uint8_t number =
+	    pldm_bios_table_attr_value_entry_enum_decode_number(entry);
+	return pldm_bios_table_attr_value_entry_encode_enum_length(number);
+}
+
 size_t
 pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
 {
@@ -583,6 +595,14 @@
 	memcpy(table_entry->value, &str_length, sizeof(str_length));
 }
 
+uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
+    const struct pldm_bios_attr_val_table_entry *entry)
+{
+	uint16_t str_length = 0;
+	memcpy(&str_length, entry->value, sizeof(str_length));
+	return le16toh(str_length);
+}
+
 int pldm_bios_table_attr_value_entry_encode_string_check(
     void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
     uint16_t str_length, const char *str)
@@ -599,6 +619,14 @@
 	return PLDM_SUCCESS;
 }
 
+static size_t attr_value_table_entry_length_string(const void *entry)
+{
+	uint16_t str_length =
+	    pldm_bios_table_attr_value_entry_string_decode_length(entry);
+	return pldm_bios_table_attr_value_entry_encode_string_length(
+	    str_length);
+}
+
 size_t pldm_bios_table_attr_value_entry_encode_integer_length()
 {
 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
@@ -637,6 +665,40 @@
 	return PLDM_SUCCESS;
 }
 
+static size_t attr_value_table_entry_length_integer(const void *entry)
+{
+	(void)entry;
+	return pldm_bios_table_attr_value_entry_encode_integer_length();
+}
+
+static struct table_entry_length attr_value_table_entries[] = {
+    {.attr_type = PLDM_BIOS_ENUMERATION,
+     .entry_length_handler = attr_value_table_entry_length_enum},
+    {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
+     .entry_length_handler = attr_value_table_entry_length_enum},
+    {.attr_type = PLDM_BIOS_STRING,
+     .entry_length_handler = attr_value_table_entry_length_string},
+    {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
+     .entry_length_handler = attr_value_table_entry_length_string},
+    {.attr_type = PLDM_BIOS_INTEGER,
+     .entry_length_handler = attr_value_table_entry_length_integer},
+    {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
+     .entry_length_handler = attr_value_table_entry_length_integer},
+};
+
+static size_t attr_value_table_entry_length(const void *table_entry)
+{
+	const struct pldm_bios_attr_val_table_entry *entry = table_entry;
+	struct table_entry_length *entry_length =
+	    find_table_entry_length_by_type(
+		entry->attr_type, attr_value_table_entries,
+		ARRAY_SIZE(attr_value_table_entries));
+	assert(entry_length != NULL);
+	assert(entry_length->entry_length_handler != NULL);
+
+	return entry_length->entry_length_handler(entry);
+}
+
 static size_t pad_size_get(size_t size_without_pad)
 {
 	return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
@@ -706,6 +768,7 @@
 		iter->entry_length_handler = attr_table_entry_length;
 		break;
 	case PLDM_BIOS_ATTR_VAL_TABLE:
+		iter->entry_length_handler = attr_value_table_entry_length;
 		break;
 	}
 
diff --git a/libpldm/bios_table.h b/libpldm/bios_table.h
index ad5891d..0327c59 100644
--- a/libpldm/bios_table.h
+++ b/libpldm/bios_table.h
@@ -70,6 +70,17 @@
 	    pldm_bios_table_iter_value(iter);
 }
 
+/** @brief Get the bios attribute value table entry that the iterator ponit to
+ *  @param[in] iter - Pointer the bios attribute value table iterator
+ *  @return Pointer to an entry in bios attribute value table
+ */
+static inline const struct pldm_bios_attr_val_table_entry *
+pldm_bios_table_iter_attr_value_entry_value(struct pldm_bios_table_iter *iter)
+{
+	return (const struct pldm_bios_attr_val_table_entry *)
+	    pldm_bios_table_iter_value(iter);
+}
+
 /** @brief Get the length of an entry in the BIOS String Table
  *  @param[in] string_length - Length of string
  *  @return Length of an entry in bytes
@@ -398,6 +409,13 @@
     void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
     uint8_t count, uint8_t *handle_indexes);
 
+/** @brief Get number of current values for the enum entry
+ *  @param[in] entry - Pointer to bios attribute value table entry
+ *  @return Total number of current values for this enumeration
+ */
+uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
+    const struct pldm_bios_attr_val_table_entry *entry);
+
 /** @brief Create an attribute value entry(type: enum) and check the validity of
  * the parameters
  *  @param[out] entry - Pointer to bios attribute value entry
@@ -437,6 +455,14 @@
 void pldm_bios_table_attr_value_entry_encode_string(
     void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
     uint16_t string_length, const char *string);
+
+/** @brief Get length of the current string in bytes
+ *  @param [in] entry - Pointer to bios attribute value table entry
+ *  @return The length of the current string in bytes
+ */
+uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
+    const struct pldm_bios_attr_val_table_entry *entry);
+
 /** @brief Create an attribute value entry(type: string) and check the validity
  * of the parameters
  *  @param[out] entry - Pointer to bios attribute value entry
diff --git a/test/libpldm_bios_table_test.cpp b/test/libpldm_bios_table_test.cpp
index cbed6d6..b5459c5 100644
--- a/test/libpldm_bios_table_test.cpp
+++ b/test/libpldm_bios_table_test.cpp
@@ -8,8 +8,10 @@
 #include "libpldm/bios.h"
 #include "libpldm/bios_table.h"
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+using testing::ElementsAreArray;
 using Table = std::vector<uint8_t>;
 
 void buildTable(Table& table)
@@ -444,6 +446,22 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(AttrValTable, EnumEntryDecodeTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        2,    /* number of current value */
+        0,    /* current value string handle index */
+        1,    /* current value string handle index */
+    };
+
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        enumEntry.data());
+    auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry);
+    EXPECT_EQ(2, number);
+}
+
 TEST(AttrValTable, stringEntryEncodeTest)
 {
     std::vector<uint8_t> stringEntry{
@@ -487,6 +505,21 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(AttrValTable, StringEntryDecodeTest)
+{
+    std::vector<uint8_t> stringEntry{
+        0,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* current string length */
+        'a', 'b', 'c', /* defaut value string handle index */
+    };
+
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        stringEntry.data());
+    auto length = pldm_bios_table_attr_value_entry_string_decode_length(entry);
+    EXPECT_EQ(3, length);
+}
+
 TEST(AttrValTable, integerEntryEncodeTest)
 {
     std::vector<uint8_t> integerEntry{
@@ -529,6 +562,62 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(AttrValTable, IteratorTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        2,    /* number of current value */
+        0,    /* current value string handle index */
+        1,    /* current value string handle index */
+    };
+    std::vector<uint8_t> stringEntry{
+        0,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* current string length */
+        'a', 'b', 'c', /* defaut value string handle index */
+    };
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        10, 0, 0, 0, 0, 0, 0, 0, /* current value */
+    };
+
+    Table table;
+    buildTable(table, enumEntry, stringEntry, integerEntry, enumEntry);
+
+    auto iter = pldm_bios_table_iter_create(table.data(), table.size(),
+                                            PLDM_BIOS_ATTR_VAL_TABLE);
+    auto entry = pldm_bios_table_iter_attr_value_entry_value(iter);
+
+    auto p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + enumEntry.size()),
+                ElementsAreArray(enumEntry));
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_value_entry_value(iter);
+    p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + stringEntry.size()),
+                ElementsAreArray(stringEntry));
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_value_entry_value(iter);
+    p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + integerEntry.size()),
+                ElementsAreArray(integerEntry));
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_value_entry_value(iter);
+    p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + enumEntry.size()),
+                ElementsAreArray(enumEntry));
+
+    pldm_bios_table_iter_next(iter);
+    EXPECT_TRUE(pldm_bios_table_iter_is_end(iter));
+
+    pldm_bios_table_iter_free(iter);
+}
+
 TEST(StringTable, EntryEncodeTest)
 {
     std::vector<uint8_t> stringEntry{