bios: Add en/decodes for integer attribute

Add encode/decode functions for integer attribute to
construct attribute table and attribute value table

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: I1b61e33c169ea9f78864f9919af0f09fb5ffe5e0
diff --git a/libpldm/bios_table.c b/libpldm/bios_table.c
index 8782a16..271d179 100644
--- a/libpldm/bios_table.c
+++ b/libpldm/bios_table.c
@@ -343,6 +343,64 @@
 	return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
 }
 
+struct attr_table_integer_entry_fields {
+	uint64_t lower_bound;
+	uint64_t upper_bound;
+	uint32_t scalar_increment;
+	uint64_t default_value;
+} __attribute__((packed));
+
+size_t pldm_bios_table_attr_entry_integer_encode_length()
+{
+	return sizeof(struct pldm_bios_attr_table_entry) - 1 +
+	       sizeof(struct attr_table_integer_entry_fields);
+}
+
+void pldm_bios_table_attr_entry_integer_encode(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_integer_info *info)
+{
+	size_t length = pldm_bios_table_attr_entry_integer_encode_length();
+	assert(length <= entry_length);
+	uint8_t attr_type =
+	    info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY : PLDM_BIOS_INTEGER;
+	attr_table_entry_encode_header(entry, entry_length, attr_type,
+				       info->name_handle);
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	struct attr_table_integer_entry_fields *attr_fields =
+	    (struct attr_table_integer_entry_fields *)attr_entry->metadata;
+	attr_fields->lower_bound = htole64(info->lower_bound);
+	attr_fields->upper_bound = htole64(info->upper_bound);
+	attr_fields->scalar_increment = htole32(info->scalar_increment);
+	attr_fields->default_value = htole64(info->default_value);
+}
+
+int pldm_bios_table_attr_entry_integer_encode_check(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_integer_info *info)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(info);
+	size_t length = pldm_bios_table_attr_entry_integer_encode_length();
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	if (info->lower_bound > info->upper_bound ||
+	    info->default_value > info->upper_bound ||
+	    info->default_value < info->lower_bound ||
+	    (info->default_value - info->lower_bound) %
+		    info->scalar_increment !=
+		0)
+		return PLDM_ERROR_INVALID_DATA;
+	pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
+	return PLDM_SUCCESS;
+}
+
+static size_t
+attr_table_entry_length_integer(const struct pldm_bios_attr_table_entry *entry)
+{
+	(void)entry;
+	return pldm_bios_table_attr_entry_integer_encode_length();
+}
+
 struct attr_table_entry {
 	uint8_t attr_type;
 	size_t (*entry_length_handler)(
@@ -358,6 +416,10 @@
      .entry_length_handler = attr_table_entry_length_string},
     {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
      .entry_length_handler = attr_table_entry_length_string},
+    {.attr_type = PLDM_BIOS_INTEGER,
+     .entry_length_handler = attr_table_entry_length_integer},
+    {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
+     .entry_length_handler = attr_table_entry_length_integer},
 };
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@@ -462,6 +524,44 @@
 	return PLDM_SUCCESS;
 }
 
+size_t pldm_bios_table_attr_value_entry_encode_integer_length()
+{
+	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
+	       sizeof(uint64_t);
+}
+void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
+						     size_t entry_length,
+						     uint16_t attr_handle,
+						     uint8_t attr_type,
+						     uint64_t cv)
+{
+	size_t length =
+	    pldm_bios_table_attr_value_entry_encode_integer_length();
+	assert(length <= entry_length);
+
+	struct pldm_bios_attr_val_table_entry *table_entry = entry;
+	table_entry->attr_handle = htole16(attr_handle);
+	table_entry->attr_type = attr_type;
+	cv = htole64(cv);
+	memcpy(table_entry->value, &cv, sizeof(uint64_t));
+}
+
+int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
+							  size_t entry_length,
+							  uint16_t attr_handle,
+							  uint8_t attr_type,
+							  uint64_t cv)
+{
+	POINTER_CHECK(entry);
+	size_t length =
+	    pldm_bios_table_attr_value_entry_encode_integer_length();
+	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	pldm_bios_table_attr_value_entry_encode_integer(
+	    entry, entry_length, attr_handle, attr_type, cv);
+	return PLDM_SUCCESS;
+}
+
 struct pldm_bios_table_iter {
 	const uint8_t *table_data;
 	size_t table_len;
diff --git a/libpldm/bios_table.h b/libpldm/bios_table.h
index 97c64ce..0a4fcd6 100644
--- a/libpldm/bios_table.h
+++ b/libpldm/bios_table.h
@@ -314,6 +314,49 @@
     const struct pldm_bios_attr_table_entry *entry,
     uint16_t *def_string_length);
 
+/** @struct pldm_bios_table_attr_entry_integer_info
+ *
+ *  An auxiliary structure for passing parameters to @ref
+ * pldm_bios_table_attr_entry_integer_encode
+ *
+ */
+struct pldm_bios_table_attr_entry_integer_info {
+	uint16_t name_handle; //!< attribute name handle
+	bool read_only;       //!< indicate whether the attribute is read-only
+	uint64_t lower_bound; //!< The lower bound on the integer value
+	uint64_t upper_bound; //!< The upper bound on the integer value
+	uint32_t scalar_increment; //!< The scalar value that is used for the
+				   //!< increments to this integer
+	uint64_t default_value;    //!< The default value of the integer
+};
+
+/** @brief Get length that an attribute entry(type: integer) will take
+ *  @return The length that an entry(type: integer) will take
+ */
+size_t pldm_bios_table_attr_entry_integer_encode_length();
+
+/** @brief Create an entry of BIOS Attribute Table (type: integer)
+ *  @param[out] entry - Pointer to a buffer to create an entry
+ *  @param[in] entry_length - Length of the buffer to create an entry
+ *  @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_integer_info
+ */
+void pldm_bios_table_attr_entry_integer_encode(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_integer_info *info);
+
+/** @brief Create an entry of BIOS Attribute Table (type: integer) and check the
+ * validity of the parameters
+ *  @param[out] entry - Pointer to a buffer to create an entry
+ *  @param[in] entry_length - Length of the buffer to create an entry
+ *  @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_integer_info
+ *  @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_integer_encode_check(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_integer_info *info);
+
 /** @brief Get length that an attribute value entry(type: enum) will take
  *  @param[in] count - Total number of current values for this enumeration
  *  @return The length that an entry(type: enum) will take
@@ -391,6 +434,42 @@
     void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
     uint16_t string_length, const char *string);
 
+/** @brief Get length that an attribute value entry(type: integer) will take
+ *  @return The length that an entry(type: integer) will take
+ */
+size_t pldm_bios_table_attr_value_entry_encode_integer_length();
+
+/** @brief Create an attribute value entry(type: integer)
+ *  @param[out] entry - Pointer to bios attribute value entry
+ *  @param[in] entry_length - Length of attribute value entry
+ *  @param[in] attr_handle - This handle points to an attribute in the
+ *  BIOS Attribute Vlaue Table.
+ *  @param[in] attr_type - Type of this attribute in the BIOS Attribute Value
+ * Table
+ *  @param[in] cv - Current Value
+ */
+void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
+						     size_t entry_length,
+						     uint16_t attr_handle,
+						     uint8_t attr_type,
+						     uint64_t cv);
+
+/** @brief Create an attribute value entry(type: integer) and check the validity
+ * of the parameters
+ *  @param[out] entry - Pointer to bios attribute value entry
+ *  @param[in] entry_length - Length of attribute value entry
+ *  @param[in] attr_handle - This handle points to an attribute in the
+ *  BIOS Attribute Vlaue Table.
+ *  @param[in] attr_type - Type of this attribute in the BIOS Attribute Value
+ * Table
+ *  @param[in] cv - Current Value
+ *  @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
+							  size_t entry_length,
+							  uint16_t attr_handle,
+							  uint8_t attr_type,
+							  uint64_t cv);
 #ifdef __cplusplus
 }
 #endif
diff --git a/test/libpldm_bios_table_test.cpp b/test/libpldm_bios_table_test.cpp
index a07036a..d22f61c 100644
--- a/test/libpldm_bios_table_test.cpp
+++ b/test/libpldm_bios_table_test.cpp
@@ -269,6 +269,65 @@
     EXPECT_EQ(stringEntryLength0, encodeEntry);
 }
 
+TEST(AttrTable, integerEntryEncodeTest)
+{
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        1,  0,                   /* attr name handle */
+        1,  0, 0, 0, 0, 0, 0, 0, /* lower bound */
+        10, 0, 0, 0, 0, 0, 0, 0, /* upper bound */
+        2,  0, 0, 0,             /* scalar increment */
+        3,  0, 0, 0, 0, 0, 0, 0, /* defaut value */
+    };
+
+    std::vector<uint16_t> pv_hdls{2, 3};
+    std::vector<uint8_t> defs{0};
+
+    struct pldm_bios_table_attr_entry_integer_info info = {
+        1,     /* name handle */
+        false, /* read only */
+        1,     /* lower bound */
+        10,    /* upper bound */
+        2,     /* sacalar increment */
+        3      /* default value */
+    };
+    auto encodeLength = pldm_bios_table_attr_entry_integer_encode_length();
+    EXPECT_EQ(encodeLength, integerEntry.size());
+
+    std::vector<uint8_t> encodeEntry(encodeLength, 0);
+    pldm_bios_table_attr_entry_integer_encode(encodeEntry.data(),
+                                              encodeEntry.size(), &info);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(integerEntry, encodeEntry);
+
+    EXPECT_DEATH(pldm_bios_table_attr_entry_integer_encode(
+                     encodeEntry.data(), encodeEntry.size() - 1, &info),
+                 "length <= entry_length");
+
+    auto rc = pldm_bios_table_attr_entry_integer_encode_check(
+        encodeEntry.data(), encodeEntry.size(), &info);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(integerEntry, encodeEntry);
+
+    rc = pldm_bios_table_attr_entry_integer_encode_check(
+        encodeEntry.data(), encodeEntry.size() - 1, &info);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+    info.lower_bound = 100;
+    info.upper_bound = 50;
+    rc = pldm_bios_table_attr_entry_integer_encode_check(
+        encodeEntry.data(), encodeEntry.size(), &info);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
 TEST(AttrTable, ItearatorTest)
 {
     std::vector<uint8_t> enumEntry{
@@ -291,9 +350,18 @@
         3,   0,       /* length of default string in length */
         'a', 'b', 'c' /* default string  */
     };
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        1,  0,                   /* attr name handle */
+        1,  0, 0, 0, 0, 0, 0, 0, /* lower bound */
+        10, 0, 0, 0, 0, 0, 0, 0, /* upper bound */
+        2,  0, 0, 0,             /* scalar increment */
+        3,  0, 0, 0, 0, 0, 0, 0, /* defaut value */
+    };
 
     Table table;
-    buildTable(table, enumEntry, stringEntry, enumEntry);
+    buildTable(table, enumEntry, stringEntry, integerEntry, enumEntry);
     auto iter = pldm_bios_table_iter_create(table.data(), table.size(),
                                             PLDM_BIOS_ATTR_TABLE);
     auto entry = pldm_bios_table_iter_attr_entry_value(iter);
@@ -307,6 +375,11 @@
 
     pldm_bios_table_iter_next(iter);
     entry = pldm_bios_table_iter_attr_entry_value(iter);
+    rc = std::memcmp(entry, integerEntry.data(), integerEntry.size());
+    EXPECT_EQ(rc, 0);
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_entry_value(iter);
     rc = std::memcmp(entry, enumEntry.data(), enumEntry.size());
     EXPECT_EQ(rc, 0);
 
@@ -404,6 +477,48 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(AttrValTable, integerEntryEncodeTest)
+{
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        10, 0, 0, 0, 0, 0, 0, 0, /* current value */
+    };
+
+    auto length = pldm_bios_table_attr_value_entry_encode_integer_length();
+    EXPECT_EQ(length, integerEntry.size());
+    std::vector<uint8_t> encodeEntry(length, 0);
+    pldm_bios_table_attr_value_entry_encode_integer(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_INTEGER, 10);
+    EXPECT_EQ(encodeEntry, integerEntry);
+
+    EXPECT_DEATH(pldm_bios_table_attr_value_entry_encode_integer(
+                     encodeEntry.data(), encodeEntry.size() - 1, 0,
+                     PLDM_BIOS_INTEGER, 10),
+                 "length <= entry_length");
+
+    auto rc = pldm_bios_table_attr_value_entry_encode_integer_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_INTEGER, 10);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(encodeEntry, integerEntry);
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        integerEntry.data());
+    entry->attr_type = PLDM_BIOS_INTEGER_READ_ONLY;
+    rc = pldm_bios_table_attr_value_entry_encode_integer_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_INTEGER_READ_ONLY,
+        10);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(encodeEntry, integerEntry);
+
+    rc = pldm_bios_table_attr_value_entry_encode_integer_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_PASSWORD, 10);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = pldm_bios_table_attr_value_entry_encode_integer_check(
+        encodeEntry.data(), encodeEntry.size() - 1, 0,
+        PLDM_BIOS_INTEGER_READ_ONLY, 10);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(StringTable, EntryEncodeTest)
 {
     std::vector<uint8_t> stringEntry{
@@ -558,7 +673,5 @@
                                             PLDM_BIOS_ATTR_TABLE);
     attr_entry->attr_type = PLDM_BIOS_PASSWORD;
     EXPECT_DEATH(pldm_bios_table_iter_next(iter), "attr_table_entry != NULL");
-    attr_entry->attr_type = PLDM_BIOS_INTEGER;
-    EXPECT_DEATH(pldm_bios_table_iter_next(iter), "attr_table_entry != NULL");
     pldm_bios_table_iter_free(iter);
 }