libpldm: Migrate to subproject

Organize files in libpldm to make it a subproject

In the current state, libpldm is not readily consumable
as a subproject.This commit does all the necessary re-organisation
of the source code to make it work as a subproject.

There are no .c/.h files changes in this commit, only meson
changes and re-organising the code structure.

Signed-off-by: Manojkiran Eda <manojkiran.eda@gmail.com>
Change-Id: I20a71c0c972b1fd81fb359d604433618799102c6
diff --git a/src/bios_table.c b/src/bios_table.c
new file mode 100644
index 0000000..ea9f669
--- /dev/null
+++ b/src/bios_table.c
@@ -0,0 +1,1126 @@
+#include <assert.h>
+#include <endian.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bios.h"
+#include "bios_table.h"
+
+#define POINTER_CHECK(pointer)                                                 \
+	do {                                                                   \
+		if (pointer == NULL)                                           \
+			return PLDM_ERROR_INVALID_DATA;                        \
+	} while (0)
+
+#define ATTR_TYPE_EXPECT(type, expected)                                       \
+	do {                                                                   \
+		if (type != expected && type != (expected | 0x80))             \
+			return PLDM_ERROR_INVALID_DATA;                        \
+	} while (0)
+
+#define BUFFER_SIZE_EXPECT(current_size, expected_size)                        \
+	do {                                                                   \
+		if (current_size < expected_size)                              \
+			return PLDM_ERROR_INVALID_LENGTH;                      \
+	} while (0)
+
+#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
+
+static void set_errmsg(const char **errmsg, const char *msg)
+{
+	if (errmsg != NULL)
+		*errmsg = msg;
+}
+
+static uint16_t get_bios_string_handle()
+{
+	static uint16_t handle = 0;
+	assert(handle != UINT16_MAX);
+
+	return handle++;
+}
+
+size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
+{
+	return sizeof(struct pldm_bios_string_table_entry) -
+	       MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
+}
+
+void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
+					 const char *str, uint16_t str_length)
+{
+	size_t length = pldm_bios_table_string_entry_encode_length(str_length);
+	assert(length <= entry_length);
+	struct pldm_bios_string_table_entry *string_entry = entry;
+	string_entry->string_handle = htole16(get_bios_string_handle());
+	string_entry->string_length = htole16(str_length);
+	memcpy(string_entry->name, str, str_length);
+}
+
+int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
+					      const char *str,
+					      uint16_t str_length)
+{
+	if (str_length == 0)
+		return PLDM_ERROR_INVALID_DATA;
+	POINTER_CHECK(entry);
+	POINTER_CHECK(str);
+	size_t length = pldm_bios_table_string_entry_encode_length(str_length);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	pldm_bios_table_string_entry_encode(entry, entry_length, str,
+					    str_length);
+	return PLDM_SUCCESS;
+}
+
+uint16_t pldm_bios_table_string_entry_decode_handle(
+    const struct pldm_bios_string_table_entry *entry)
+{
+	return le16toh(entry->string_handle);
+}
+
+uint16_t pldm_bios_table_string_entry_decode_string_length(
+    const struct pldm_bios_string_table_entry *entry)
+{
+	return le16toh(entry->string_length);
+}
+
+uint16_t pldm_bios_table_string_entry_decode_string(
+    const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
+{
+	uint16_t length =
+	    pldm_bios_table_string_entry_decode_string_length(entry);
+	length = length < (size - 1) ? length : (size - 1);
+	memcpy(buffer, entry->name, length);
+	buffer[length] = 0;
+	return length;
+}
+
+int pldm_bios_table_string_entry_decode_string_check(
+    const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(buffer);
+	size_t length =
+	    pldm_bios_table_string_entry_decode_string_length(entry);
+	BUFFER_SIZE_EXPECT(size, length + 1);
+	pldm_bios_table_string_entry_decode_string(entry, buffer, size);
+	return PLDM_SUCCESS;
+}
+
+static size_t string_table_entry_length(const void *table_entry)
+{
+	const struct pldm_bios_string_table_entry *entry = table_entry;
+	return sizeof(*entry) - sizeof(entry->name) +
+	       pldm_bios_table_string_entry_decode_string_length(entry);
+}
+
+static uint16_t get_bios_attr_handle()
+{
+	static uint16_t handle = 0;
+	assert(handle != UINT16_MAX);
+
+	return handle++;
+}
+
+static void attr_table_entry_encode_header(void *entry, size_t length,
+					   uint8_t attr_type,
+					   uint16_t string_handle)
+{
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	assert(sizeof(*attr_entry) <= length);
+	attr_entry->attr_handle = htole16(get_bios_attr_handle());
+	attr_entry->attr_type = attr_type;
+	attr_entry->string_handle = htole16(string_handle);
+}
+
+uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	return le16toh(entry->attr_handle);
+}
+
+uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	return entry->attr_type;
+}
+
+uint16_t pldm_bios_table_attr_entry_decode_string_handle(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	return le16toh(entry->string_handle);
+}
+
+size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
+						     uint8_t def_num)
+{
+	return sizeof(struct pldm_bios_attr_table_entry) -
+	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
+	       sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
+	       def_num;
+}
+
+void pldm_bios_table_attr_entry_enum_encode(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_enum_info *info)
+{
+	size_t length = pldm_bios_table_attr_entry_enum_encode_length(
+	    info->pv_num, info->def_num);
+	assert(length <= entry_length);
+	uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY
+					    : PLDM_BIOS_ENUMERATION;
+	attr_table_entry_encode_header(entry, entry_length, attr_type,
+				       info->name_handle);
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	attr_entry->metadata[0] = info->pv_num;
+	uint16_t *pv_hdls =
+	    (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
+	size_t i;
+	for (i = 0; i < info->pv_num; i++)
+		pv_hdls[i] = htole16(info->pv_handle[i]);
+	attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
+	    info->def_num;
+	memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
+		   info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
+	       info->def_index, info->def_num);
+}
+
+int pldm_bios_table_attr_entry_enum_encode_check(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_enum_info *info)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(info);
+	size_t length = pldm_bios_table_attr_entry_enum_encode_length(
+	    info->pv_num, info->def_num);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
+	return PLDM_SUCCESS;
+}
+
+#define ATTR_TYPE_EXPECT(type, expected)                                       \
+	do {                                                                   \
+		if (type != expected && type != (expected | 0x80))             \
+			return PLDM_ERROR_INVALID_DATA;                        \
+	} while (0)
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	return entry->metadata[0];
+}
+
+int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
+    const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(pv_num);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
+	*pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+	return PLDM_SUCCESS;
+}
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+	return entry->metadata[sizeof(uint8_t) /* pv_num */ +
+			       sizeof(uint16_t) * pv_num];
+}
+
+int pldm_bios_table_attr_entry_enum_decode_def_num_check(
+    const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(def_num);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
+	*def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+	return PLDM_SUCCESS;
+}
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+    const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
+    uint8_t pv_num)
+{
+	uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+	num = num < pv_num ? num : pv_num;
+	size_t i;
+	for (i = 0; i < num; i++) {
+		uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
+					     i * sizeof(uint16_t));
+		pv_hdls[i] = le16toh(*hdl);
+	}
+	return num;
+}
+
+int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
+    const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
+    uint8_t pv_num)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(pv_hdls);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
+	uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+	if (num != pv_num)
+		return PLDM_ERROR_INVALID_DATA;
+	pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
+	return PLDM_SUCCESS;
+}
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
+    const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
+    uint8_t def_num)
+{
+	uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+	num = num < def_num ? num : def_num;
+	uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+	const uint8_t *p = entry->metadata +
+			   sizeof(uint8_t) /* number of possible values*/
+			   + pv_num * sizeof(uint16_t) /* possible values */
+			   + sizeof(uint8_t); /* number of default values */
+	memcpy(def_indices, p, num);
+	return num;
+}
+
+/** @brief Get length of an enum attribute 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);
+	return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
+}
+
+struct attr_table_string_entry_fields {
+	uint8_t string_type;
+	uint16_t min_length;
+	uint16_t max_length;
+	uint16_t def_length;
+	uint8_t def_string[1];
+} __attribute__((packed));
+
+size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
+{
+	return sizeof(struct pldm_bios_attr_table_entry) -
+	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
+	       sizeof(struct attr_table_string_entry_fields) -
+	       MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
+	       def_str_len;
+}
+
+void pldm_bios_table_attr_entry_string_encode(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_string_info *info)
+{
+	size_t length =
+	    pldm_bios_table_attr_entry_string_encode_length(info->def_length);
+	assert(length <= entry_length);
+	uint8_t attr_type =
+	    info->read_only ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
+	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_string_entry_fields *attr_fields =
+	    (struct attr_table_string_entry_fields *)attr_entry->metadata;
+	attr_fields->string_type = info->string_type;
+	attr_fields->min_length = htole16(info->min_length);
+	attr_fields->max_length = htole16(info->max_length);
+	attr_fields->def_length = htole16(info->def_length);
+	if (info->def_length != 0 && info->def_string != NULL)
+		memcpy(attr_fields->def_string, info->def_string,
+		       info->def_length);
+}
+
+#define PLDM_STRING_TYPE_MAX 5
+#define PLDM_STRING_TYPE_VENDOR 0xff
+
+int pldm_bios_table_attr_entry_string_info_check(
+    const struct pldm_bios_table_attr_entry_string_info *info,
+    const char **errmsg)
+{
+	if (info->min_length > info->max_length) {
+		set_errmsg(errmsg, "MinimumStingLength should not be greater "
+				   "than MaximumStringLength");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->min_length == info->max_length &&
+	    info->def_length != info->min_length) {
+		set_errmsg(errmsg, "Wrong DefaultStringLength");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->def_length > info->max_length ||
+	    info->def_length < info->min_length) {
+		set_errmsg(errmsg, "Wrong DefaultStringLength");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->string_type > PLDM_STRING_TYPE_MAX &&
+	    info->string_type != PLDM_STRING_TYPE_VENDOR) {
+		set_errmsg(errmsg, "Wrong StringType");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->def_length != strlen(info->def_string)) {
+		set_errmsg(errmsg, "Length of DefaultString should be equal to "
+				   "DefaultStringLength");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+int pldm_bios_table_attr_entry_string_encode_check(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_string_info *info)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(info);
+	size_t length =
+	    pldm_bios_table_attr_entry_string_encode_length(info->def_length);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
+	    PLDM_SUCCESS)
+		return PLDM_ERROR_INVALID_DATA;
+	pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
+	return PLDM_SUCCESS;
+}
+
+uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	struct attr_table_string_entry_fields *fields =
+	    (struct attr_table_string_entry_fields *)entry->metadata;
+	return le16toh(fields->def_length);
+}
+
+int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+    const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(def_string_length);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
+	*def_string_length =
+	    pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
+	return PLDM_SUCCESS;
+}
+
+uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	struct attr_table_string_entry_fields *fields =
+	    (struct attr_table_string_entry_fields *)entry->metadata;
+	return fields->string_type;
+}
+
+uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	struct attr_table_string_entry_fields *fields =
+	    (struct attr_table_string_entry_fields *)entry->metadata;
+	return le16toh(fields->max_length);
+}
+
+uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	struct attr_table_string_entry_fields *fields =
+	    (struct attr_table_string_entry_fields *)entry->metadata;
+	return le16toh(fields->min_length);
+}
+
+uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
+    const struct pldm_bios_attr_table_entry *entry, char *buffer, size_t size)
+{
+	uint16_t length =
+	    pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
+	length = length < (size - 1) ? length : (size - 1);
+	struct attr_table_string_entry_fields *fields =
+	    (struct attr_table_string_entry_fields *)entry->metadata;
+	memcpy(buffer, fields->def_string, length);
+	buffer[length] = 0;
+	return length;
+}
+
+/** @brief Get length of a string attribute 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);
+	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_info_check(
+    const struct pldm_bios_table_attr_entry_integer_info *info,
+    const char **errmsg)
+{
+	if (info->lower_bound == info->upper_bound) {
+		if (info->default_value != info->lower_bound) {
+			set_errmsg(errmsg, "Wrong DefaultValue");
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		if (info->scalar_increment != 0) {
+			set_errmsg(errmsg, "Wrong ScalarIncrement");
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		return PLDM_SUCCESS;
+	}
+	if (info->lower_bound > info->upper_bound) {
+		set_errmsg(errmsg,
+			   "LowerBound should not be greater than UpperBound");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->default_value > info->upper_bound ||
+	    info->default_value < info->lower_bound) {
+		set_errmsg(errmsg, "Wrong DefaultValue");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->scalar_increment == 0) {
+		set_errmsg(errmsg, "ScalarIncrement should not be zero when "
+				   "lower_bound != upper_bound");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if ((info->default_value - info->lower_bound) %
+		info->scalar_increment !=
+	    0) {
+		set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	return PLDM_SUCCESS;
+}
+
+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 (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
+	    PLDM_SUCCESS)
+		return PLDM_ERROR_INVALID_DATA;
+	pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
+	return PLDM_SUCCESS;
+}
+
+void pldm_bios_table_attr_entry_integer_decode(
+    const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
+    uint64_t *upper, uint32_t *scalar, uint64_t *def)
+{
+	struct attr_table_integer_entry_fields *fields =
+	    (struct attr_table_integer_entry_fields *)entry->metadata;
+	*lower = le64toh(fields->lower_bound);
+	*upper = le64toh(fields->upper_bound);
+	*scalar = le32toh(fields->scalar_increment);
+	*def = le64toh(fields->default_value);
+}
+
+static size_t attr_table_entry_length_integer(const void *entry)
+{
+	(void)entry;
+	return pldm_bios_table_attr_entry_integer_encode_length();
+}
+
+struct table_entry_length {
+	uint8_t attr_type;
+	size_t (*entry_length_handler)(const void *);
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static const struct table_entry_length *find_table_entry_length_by_type(
+    uint8_t attr_type, const 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 const 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,
+     .entry_length_handler = attr_table_entry_length_enum},
+    {.attr_type = PLDM_BIOS_STRING,
+     .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},
+};
+
+static size_t attr_table_entry_length(const void *table_entry)
+{
+	const struct pldm_bios_attr_table_entry *entry = table_entry;
+	const 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);
+
+	return attr_table_entry->entry_length_handler(entry);
+}
+
+uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
+    const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return le16toh(entry->attr_handle);
+}
+
+uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
+    const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return entry->attr_type;
+}
+
+size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
+{
+	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
+	       sizeof(count) + count;
+}
+
+void pldm_bios_table_attr_value_entry_encode_enum(
+    void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
+    uint8_t count, const uint8_t *handles)
+{
+	size_t length =
+	    pldm_bios_table_attr_value_entry_encode_enum_length(count);
+	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;
+	table_entry->value[0] = count;
+	if (count != 0)
+		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];
+}
+
+uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
+    const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
+    uint8_t number)
+{
+	uint8_t curr_num =
+	    pldm_bios_table_attr_value_entry_enum_decode_number(entry);
+	number = number < curr_num ? number : curr_num;
+	memcpy(handles, &entry->value[1], number);
+
+	return number;
+}
+
+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)
+{
+	POINTER_CHECK(entry);
+	if (count != 0 && handles == NULL)
+		return PLDM_ERROR_INVALID_DATA;
+	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
+	size_t length =
+	    pldm_bios_table_attr_value_entry_encode_enum_length(count);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	pldm_bios_table_attr_value_entry_encode_enum(
+	    entry, entry_length, attr_handle, attr_type, count, handles);
+	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)
+{
+	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
+	       sizeof(string_length) + string_length;
+}
+
+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 str_length, const char *str)
+{
+	size_t length =
+	    pldm_bios_table_attr_value_entry_encode_string_length(str_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;
+	if (str_length != 0)
+		memcpy(table_entry->value + sizeof(str_length), str,
+		       str_length);
+	str_length = htole16(str_length);
+	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);
+}
+
+void pldm_bios_table_attr_value_entry_string_decode_string(
+    const struct pldm_bios_attr_val_table_entry *entry,
+    struct variable_field *current_string)
+{
+	current_string->length =
+	    pldm_bios_table_attr_value_entry_string_decode_length(entry);
+	current_string->ptr =
+	    entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
+}
+
+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)
+{
+	POINTER_CHECK(entry);
+	if (str_length != 0 && str == NULL)
+		return PLDM_ERROR_INVALID_DATA;
+	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
+	size_t length =
+	    pldm_bios_table_attr_value_entry_encode_string_length(str_length);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	pldm_bios_table_attr_value_entry_encode_string(
+	    entry, entry_length, attr_handle, attr_type, str_length, str);
+	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 +
+	       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;
+}
+
+uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
+    const struct pldm_bios_attr_val_table_entry *entry)
+{
+	uint64_t cv = 0;
+	memcpy(&cv, entry->value, sizeof(cv));
+	cv = le64toh(cv);
+	return cv;
+}
+
+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 const 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;
+	const 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);
+}
+
+size_t pldm_bios_table_attr_value_entry_length(
+    const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return attr_value_table_entry_length(entry);
+}
+
+uint16_t pldm_bios_table_attr_value_entry_decode_handle(
+    const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return le16toh(entry->attr_handle);
+}
+
+static size_t pad_size_get(size_t size_without_pad)
+{
+	return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
+}
+
+static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
+{
+	while (pad_size--)
+		*table_end++ = 0;
+
+	return table_end;
+}
+
+static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
+{
+	checksum = htole32(checksum);
+	memcpy(table_end, &checksum, sizeof(checksum));
+
+	return table_end + sizeof(checksum);
+}
+
+size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
+{
+	size_t size = pad_size_get(size_without_pad) +
+		      sizeof(uint32_t) /*sizeof(checksum)*/;
+	return size;
+}
+
+size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
+					   size_t size_without_pad)
+{
+
+	size_t pad_checksum_size =
+	    pldm_bios_table_pad_checksum_size(size_without_pad);
+	size_t total_length = size_without_pad + pad_checksum_size;
+	assert(size >= total_length);
+
+	uint8_t *table_end = (uint8_t *)table + size_without_pad;
+	size_t pad_size = pad_size_get(size_without_pad);
+	table_end = pad_append(table_end, pad_size);
+
+	uint32_t checksum = crc32(table, size_without_pad + pad_size);
+	checksum_append(table_end, checksum);
+
+	return total_length;
+}
+
+struct pldm_bios_table_iter {
+	const uint8_t *table_data;
+	size_t table_len;
+	size_t current_pos;
+	size_t (*entry_length_handler)(const void *table_entry);
+};
+
+struct pldm_bios_table_iter *
+pldm_bios_table_iter_create(const void *table, size_t length,
+			    enum pldm_bios_table_types type)
+{
+	struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
+	assert(iter != NULL);
+	iter->table_data = table;
+	iter->table_len = length;
+	iter->current_pos = 0;
+	iter->entry_length_handler = NULL;
+	switch (type) {
+	case PLDM_BIOS_STRING_TABLE:
+		iter->entry_length_handler = string_table_entry_length;
+		break;
+	case PLDM_BIOS_ATTR_TABLE:
+		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;
+	}
+
+	return iter;
+}
+
+void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
+{
+	free(iter);
+}
+
+#define pad_and_check_max 7
+bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
+{
+	if (iter->table_len - iter->current_pos <= pad_and_check_max)
+		return true;
+	return false;
+}
+
+void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
+{
+	if (pldm_bios_table_iter_is_end(iter))
+		return;
+	const void *entry = iter->table_data + iter->current_pos;
+	iter->current_pos += iter->entry_length_handler(entry);
+}
+
+const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
+{
+	return iter->table_data + iter->current_pos;
+}
+
+typedef bool (*equal_handler)(const void *entry, const void *key);
+
+static const void *
+pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
+				   const void *key, equal_handler equal)
+{
+	const void *entry;
+	while (!pldm_bios_table_iter_is_end(iter)) {
+		entry = pldm_bios_table_iter_value(iter);
+		if (equal(entry, key))
+			return entry;
+		pldm_bios_table_iter_next(iter);
+	}
+	return NULL;
+}
+
+static const void *
+pldm_bios_table_entry_find_from_table(const void *table, size_t length,
+				      enum pldm_bios_table_types type,
+				      equal_handler equal, const void *key)
+{
+	struct pldm_bios_table_iter *iter =
+	    pldm_bios_table_iter_create(table, length, type);
+	const void *entry =
+	    pldm_bios_table_entry_find_by_iter(iter, key, equal);
+	pldm_bios_table_iter_free(iter);
+	return entry;
+}
+
+static bool string_table_handle_equal(const void *entry, const void *key)
+{
+	const struct pldm_bios_string_table_entry *string_entry = entry;
+	uint16_t handle = *(uint16_t *)key;
+	if (pldm_bios_table_string_entry_decode_handle(string_entry) == handle)
+		return true;
+	return false;
+}
+
+const struct pldm_bios_string_table_entry *
+pldm_bios_table_string_find_by_handle(const void *table, size_t length,
+				      uint16_t handle)
+{
+	return pldm_bios_table_entry_find_from_table(
+	    table, length, PLDM_BIOS_STRING_TABLE, string_table_handle_equal,
+	    &handle);
+}
+
+struct string_equal_arg {
+	uint16_t str_length;
+	const char *str;
+};
+
+static bool string_table_string_equal(const void *entry, const void *key)
+{
+	const struct pldm_bios_string_table_entry *string_entry = entry;
+	const struct string_equal_arg *arg = key;
+	if (arg->str_length !=
+	    pldm_bios_table_string_entry_decode_string_length(string_entry))
+		return false;
+	if (memcmp(string_entry->name, arg->str, arg->str_length) != 0)
+		return false;
+	return true;
+}
+
+const struct pldm_bios_string_table_entry *
+pldm_bios_table_string_find_by_string(const void *table, size_t length,
+				      const char *str)
+{
+	uint16_t str_length = strlen(str);
+	struct string_equal_arg arg = {str_length, str};
+	return pldm_bios_table_entry_find_from_table(
+	    table, length, PLDM_BIOS_STRING_TABLE, string_table_string_equal,
+	    &arg);
+}
+
+static bool attr_table_handle_equal(const void *entry, const void *key)
+{
+	uint16_t handle = *(uint16_t *)key;
+	return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
+	       handle;
+}
+
+const struct pldm_bios_attr_table_entry *
+pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
+				    uint16_t handle)
+{
+	return pldm_bios_table_entry_find_from_table(
+	    table, length, PLDM_BIOS_ATTR_TABLE, attr_table_handle_equal,
+	    &handle);
+}
+
+static bool attr_table_string_handle_equal(const void *entry, const void *key)
+{
+	uint16_t handle = *(uint16_t *)key;
+	return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
+}
+
+const struct pldm_bios_attr_table_entry *
+pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
+					   uint16_t handle)
+{
+	return pldm_bios_table_entry_find_from_table(
+	    table, length, PLDM_BIOS_ATTR_TABLE, attr_table_string_handle_equal,
+	    &handle);
+}
+
+static bool attr_value_table_handle_equal(const void *entry, const void *key)
+{
+	uint16_t handle = *(uint16_t *)key;
+	return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
+}
+
+const struct pldm_bios_attr_val_table_entry *
+pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
+					  uint16_t handle)
+{
+	return pldm_bios_table_entry_find_from_table(
+	    table, length, PLDM_BIOS_ATTR_VAL_TABLE,
+	    attr_value_table_handle_equal, &handle);
+}
+
+int pldm_bios_table_attr_value_copy_and_update(
+    const void *src_table, size_t src_length, void *dest_table,
+    size_t *dest_length, const void *entry, size_t entry_length)
+{
+	struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
+	    src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
+
+	int rc = PLDM_SUCCESS;
+	const struct pldm_bios_attr_val_table_entry *tmp, *to_update = entry;
+	size_t buffer_length = *dest_length, copied_length = 0, length = 0;
+	while (!pldm_bios_table_iter_is_end(iter)) {
+		tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
+		length = attr_value_table_entry_length(tmp);
+
+		/* we need the tmp's entry_length here, iter_next will calculate
+		 * it too, use current_pos directly to avoid calculating it
+		 * twice */
+		iter->current_pos += length;
+		if (tmp->attr_handle == to_update->attr_handle) {
+			if (tmp->attr_type != to_update->attr_type) {
+				rc = PLDM_ERROR_INVALID_DATA;
+				goto out;
+			}
+			length = entry_length;
+			tmp = entry;
+		}
+		if (copied_length + length > buffer_length) {
+			rc = PLDM_ERROR_INVALID_LENGTH;
+			goto out;
+		}
+		memcpy((uint8_t *)dest_table + copied_length, tmp, length);
+		copied_length += length;
+	}
+
+	size_t pad_checksum_size =
+	    pldm_bios_table_pad_checksum_size(copied_length);
+	if ((pad_checksum_size + copied_length) > buffer_length) {
+		rc = PLDM_ERROR_INVALID_LENGTH;
+		goto out;
+	}
+
+	*dest_length = pldm_bios_table_append_pad_checksum(
+	    dest_table, buffer_length, copied_length);
+out:
+	pldm_bios_table_iter_free(iter);
+	return rc;
+}
+
+bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
+{
+	if (table == NULL)
+		return false;
+
+	// 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
+	//     Variable(4) + checksum(uint32)
+	if (size < 12)
+		return false;
+
+	uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
+	uint32_t dst_crc = crc32(table, size - 4);
+
+	return src_crc == dst_crc;
+}