xref: /openbmc/libpldm/src/dsp/bios_table.c (revision 36324f6bea8c5de1e380659bb56aca5e0b8724b4)
148761c62SAndrew Jeffery /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
248761c62SAndrew Jeffery #include "array.h"
348761c62SAndrew Jeffery 
448761c62SAndrew Jeffery #include <libpldm/base.h>
548761c62SAndrew Jeffery #include <libpldm/bios.h>
648761c62SAndrew Jeffery #include <libpldm/bios_table.h>
748761c62SAndrew Jeffery #include <libpldm/utils.h>
848761c62SAndrew Jeffery 
948761c62SAndrew Jeffery #include <assert.h>
1048761c62SAndrew Jeffery #include <endian.h>
1148761c62SAndrew Jeffery #include <limits.h>
1248761c62SAndrew Jeffery #include <stdbool.h>
1348761c62SAndrew Jeffery #include <stdint.h>
1448761c62SAndrew Jeffery #include <stdlib.h>
1548761c62SAndrew Jeffery #include <string.h>
1648761c62SAndrew Jeffery 
1748761c62SAndrew Jeffery #define POINTER_CHECK(pointer)                                                 \
1848761c62SAndrew Jeffery 	do {                                                                   \
1948761c62SAndrew Jeffery 		if ((pointer) == NULL)                                         \
2048761c62SAndrew Jeffery 			return PLDM_ERROR_INVALID_DATA;                        \
2148761c62SAndrew Jeffery 	} while (0)
2248761c62SAndrew Jeffery 
2348761c62SAndrew Jeffery #define ATTR_TYPE_EXPECT(type, expected)                                       \
2448761c62SAndrew Jeffery 	do {                                                                   \
2548761c62SAndrew Jeffery 		if ((type) != (expected) && (type) != ((expected) | 0x80))     \
2648761c62SAndrew Jeffery 			return PLDM_ERROR_INVALID_DATA;                        \
2748761c62SAndrew Jeffery 	} while (0)
2848761c62SAndrew Jeffery 
2948761c62SAndrew Jeffery #define BUFFER_SIZE_EXPECT(current_size, expected_size)                        \
3048761c62SAndrew Jeffery 	do {                                                                   \
3148761c62SAndrew Jeffery 		if ((current_size) < (expected_size))                          \
3248761c62SAndrew Jeffery 			return PLDM_ERROR_INVALID_LENGTH;                      \
3348761c62SAndrew Jeffery 	} while (0)
3448761c62SAndrew Jeffery 
3548761c62SAndrew Jeffery #define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
3648761c62SAndrew Jeffery 
set_errmsg(const char ** errmsg,const char * msg)3748761c62SAndrew Jeffery static void set_errmsg(const char **errmsg, const char *msg)
3848761c62SAndrew Jeffery {
3948761c62SAndrew Jeffery 	if (errmsg != NULL) {
4048761c62SAndrew Jeffery 		*errmsg = msg;
4148761c62SAndrew Jeffery 	}
4248761c62SAndrew Jeffery }
4348761c62SAndrew Jeffery 
get_bios_string_handle(uint16_t * val)4448761c62SAndrew Jeffery static int get_bios_string_handle(uint16_t *val)
4548761c62SAndrew Jeffery {
4648761c62SAndrew Jeffery 	static uint16_t handle = 0;
4748761c62SAndrew Jeffery 	assert(handle != UINT16_MAX);
4848761c62SAndrew Jeffery 	if (handle == UINT16_MAX) {
4948761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
5048761c62SAndrew Jeffery 	}
5148761c62SAndrew Jeffery 
5248761c62SAndrew Jeffery 	*val = handle++;
5348761c62SAndrew Jeffery 	return PLDM_SUCCESS;
5448761c62SAndrew Jeffery }
5548761c62SAndrew Jeffery 
5648761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_string_entry_encode_length(uint16_t string_length)5748761c62SAndrew Jeffery size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
5848761c62SAndrew Jeffery {
5948761c62SAndrew Jeffery 	return sizeof(struct pldm_bios_string_table_entry) -
6048761c62SAndrew Jeffery 	       MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
6148761c62SAndrew Jeffery }
6248761c62SAndrew Jeffery 
6348761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_string_entry_encode(void * entry,size_t entry_length,const char * str,uint16_t str_length)64e48fdd6eSAndrew Jeffery int pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
65e48fdd6eSAndrew Jeffery 					const char *str, uint16_t str_length)
6648761c62SAndrew Jeffery {
6748761c62SAndrew Jeffery 	if (str_length == 0) {
6848761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
6948761c62SAndrew Jeffery 	}
7048761c62SAndrew Jeffery 	POINTER_CHECK(entry);
7148761c62SAndrew Jeffery 	POINTER_CHECK(str);
7248761c62SAndrew Jeffery 	size_t length = pldm_bios_table_string_entry_encode_length(str_length);
7348761c62SAndrew Jeffery 	BUFFER_SIZE_EXPECT(entry_length, length);
7421cb052bSAndrew Jeffery 	if (entry_length - (sizeof(struct pldm_bios_string_table_entry) -
7521cb052bSAndrew Jeffery 			    MEMBER_SIZE(pldm_bios_string_table_entry, name)) <
7621cb052bSAndrew Jeffery 	    str_length) {
7721cb052bSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
7821cb052bSAndrew Jeffery 	}
7948761c62SAndrew Jeffery 	struct pldm_bios_string_table_entry *string_entry = entry;
8048761c62SAndrew Jeffery 	uint16_t handle;
8148761c62SAndrew Jeffery 	int rc = get_bios_string_handle(&handle);
8248761c62SAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
8348761c62SAndrew Jeffery 		return rc;
8448761c62SAndrew Jeffery 	}
8548761c62SAndrew Jeffery 	string_entry->string_handle = htole16(handle);
8648761c62SAndrew Jeffery 	string_entry->string_length = htole16(str_length);
8748761c62SAndrew Jeffery 	memcpy(string_entry->name, str, str_length);
8848761c62SAndrew Jeffery 	return PLDM_SUCCESS;
8948761c62SAndrew Jeffery }
9048761c62SAndrew Jeffery 
9148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_string_entry_decode_handle(const struct pldm_bios_string_table_entry * entry)9248761c62SAndrew Jeffery uint16_t pldm_bios_table_string_entry_decode_handle(
9348761c62SAndrew Jeffery 	const struct pldm_bios_string_table_entry *entry)
9448761c62SAndrew Jeffery {
9548761c62SAndrew Jeffery 	return le16toh(entry->string_handle);
9648761c62SAndrew Jeffery }
9748761c62SAndrew Jeffery 
9848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_string_entry_decode_string_length(const struct pldm_bios_string_table_entry * entry)9948761c62SAndrew Jeffery uint16_t pldm_bios_table_string_entry_decode_string_length(
10048761c62SAndrew Jeffery 	const struct pldm_bios_string_table_entry *entry)
10148761c62SAndrew Jeffery {
10248761c62SAndrew Jeffery 	return le16toh(entry->string_length);
10348761c62SAndrew Jeffery }
10448761c62SAndrew Jeffery 
10548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_string_entry_decode_string(const struct pldm_bios_string_table_entry * entry,char * buffer,size_t size)1068c37ab36SAndrew Jeffery int pldm_bios_table_string_entry_decode_string(
10748761c62SAndrew Jeffery 	const struct pldm_bios_string_table_entry *entry, char *buffer,
10848761c62SAndrew Jeffery 	size_t size)
10948761c62SAndrew Jeffery {
11048761c62SAndrew Jeffery 	POINTER_CHECK(entry);
11148761c62SAndrew Jeffery 	POINTER_CHECK(buffer);
11248761c62SAndrew Jeffery 	if (size == 0) {
11348761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
11448761c62SAndrew Jeffery 	}
11548761c62SAndrew Jeffery 	size_t length =
11648761c62SAndrew Jeffery 		pldm_bios_table_string_entry_decode_string_length(entry);
11748761c62SAndrew Jeffery 	length = length < (size - 1) ? length : (size - 1);
11848761c62SAndrew Jeffery 	memcpy(buffer, entry->name, length);
11948761c62SAndrew Jeffery 	buffer[length] = 0;
12048761c62SAndrew Jeffery 	return PLDM_SUCCESS;
12148761c62SAndrew Jeffery }
12248761c62SAndrew Jeffery 
string_table_entry_length(const void * table_entry)12348761c62SAndrew Jeffery static ssize_t string_table_entry_length(const void *table_entry)
12448761c62SAndrew Jeffery {
12548761c62SAndrew Jeffery 	const struct pldm_bios_string_table_entry *entry = table_entry;
12648761c62SAndrew Jeffery 	size_t len = sizeof(*entry) - sizeof(entry->name) +
12748761c62SAndrew Jeffery 		     pldm_bios_table_string_entry_decode_string_length(entry);
12848761c62SAndrew Jeffery 	if (len > SSIZE_MAX) {
12948761c62SAndrew Jeffery 		return -1;
13048761c62SAndrew Jeffery 	}
13148761c62SAndrew Jeffery 	return (ssize_t)len;
13248761c62SAndrew Jeffery }
13348761c62SAndrew Jeffery 
get_bios_attr_handle(uint16_t * val)13448761c62SAndrew Jeffery static int get_bios_attr_handle(uint16_t *val)
13548761c62SAndrew Jeffery {
13648761c62SAndrew Jeffery 	static uint16_t handle = 0;
13748761c62SAndrew Jeffery 	assert(handle != UINT16_MAX);
13848761c62SAndrew Jeffery 	if (handle == UINT16_MAX) {
13948761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
14048761c62SAndrew Jeffery 	}
14148761c62SAndrew Jeffery 
14248761c62SAndrew Jeffery 	*val = handle++;
14348761c62SAndrew Jeffery 	return PLDM_SUCCESS;
14448761c62SAndrew Jeffery }
14548761c62SAndrew Jeffery 
attr_table_entry_encode_header(void * entry,size_t length,uint8_t attr_type,uint16_t string_handle)14648761c62SAndrew Jeffery static int attr_table_entry_encode_header(void *entry, size_t length,
14748761c62SAndrew Jeffery 					  uint8_t attr_type,
14848761c62SAndrew Jeffery 					  uint16_t string_handle)
14948761c62SAndrew Jeffery {
15048761c62SAndrew Jeffery 	struct pldm_bios_attr_table_entry *attr_entry = entry;
15148761c62SAndrew Jeffery 
15248761c62SAndrew Jeffery 	assert(sizeof(*attr_entry) <= length);
15348761c62SAndrew Jeffery 	if (sizeof(*attr_entry) > length) {
15448761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
15548761c62SAndrew Jeffery 	}
15648761c62SAndrew Jeffery 
15748761c62SAndrew Jeffery 	uint16_t handle;
15848761c62SAndrew Jeffery 	int rc = get_bios_attr_handle(&handle);
15948761c62SAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
16048761c62SAndrew Jeffery 		return rc;
16148761c62SAndrew Jeffery 	}
16248761c62SAndrew Jeffery 
16348761c62SAndrew Jeffery 	attr_entry->attr_handle = htole16(handle);
16448761c62SAndrew Jeffery 	attr_entry->attr_type = attr_type;
16548761c62SAndrew Jeffery 	attr_entry->string_handle = htole16(string_handle);
16648761c62SAndrew Jeffery 
16748761c62SAndrew Jeffery 	return PLDM_SUCCESS;
16848761c62SAndrew Jeffery }
16948761c62SAndrew Jeffery 
17048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_decode_attribute_handle(const struct pldm_bios_attr_table_entry * entry)17148761c62SAndrew Jeffery uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
17248761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry)
17348761c62SAndrew Jeffery {
17448761c62SAndrew Jeffery 	return le16toh(entry->attr_handle);
17548761c62SAndrew Jeffery }
17648761c62SAndrew Jeffery 
17748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_decode_attribute_type(const struct pldm_bios_attr_table_entry * entry)17848761c62SAndrew Jeffery uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
17948761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry)
18048761c62SAndrew Jeffery {
18148761c62SAndrew Jeffery 	return entry->attr_type;
18248761c62SAndrew Jeffery }
18348761c62SAndrew Jeffery 
18448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_decode_string_handle(const struct pldm_bios_attr_table_entry * entry)18548761c62SAndrew Jeffery uint16_t pldm_bios_table_attr_entry_decode_string_handle(
18648761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry)
18748761c62SAndrew Jeffery {
18848761c62SAndrew Jeffery 	return le16toh(entry->string_handle);
18948761c62SAndrew Jeffery }
19048761c62SAndrew Jeffery 
19148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,uint8_t def_num)19248761c62SAndrew Jeffery size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
19348761c62SAndrew Jeffery 						     uint8_t def_num)
19448761c62SAndrew Jeffery {
19548761c62SAndrew Jeffery 	return sizeof(struct pldm_bios_attr_table_entry) -
19648761c62SAndrew Jeffery 	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
19748761c62SAndrew Jeffery 	       sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
19848761c62SAndrew Jeffery 	       def_num;
19948761c62SAndrew Jeffery }
20048761c62SAndrew Jeffery 
201*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
pldm_bios_table_attr_entry_enum_encode(void * entry,size_t entry_length,const struct pldm_bios_table_attr_entry_enum_info * info)2027126b1d2SAndrew Jeffery int pldm_bios_table_attr_entry_enum_encode(
20348761c62SAndrew Jeffery 	void *entry, size_t entry_length,
20448761c62SAndrew Jeffery 	const struct pldm_bios_table_attr_entry_enum_info *info)
20548761c62SAndrew Jeffery {
20648761c62SAndrew Jeffery 	POINTER_CHECK(entry);
20748761c62SAndrew Jeffery 	POINTER_CHECK(info);
20848761c62SAndrew Jeffery 	size_t length = pldm_bios_table_attr_entry_enum_encode_length(
20948761c62SAndrew Jeffery 		info->pv_num, info->def_num);
21048761c62SAndrew Jeffery 	BUFFER_SIZE_EXPECT(entry_length, length);
21148761c62SAndrew Jeffery 	uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
21248761c62SAndrew Jeffery 					      PLDM_BIOS_ENUMERATION;
21348761c62SAndrew Jeffery 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
21448761c62SAndrew Jeffery 						info->name_handle);
21548761c62SAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
21648761c62SAndrew Jeffery 		return rc;
21748761c62SAndrew Jeffery 	}
21848761c62SAndrew Jeffery 	struct pldm_bios_attr_table_entry *attr_entry = entry;
21948761c62SAndrew Jeffery 	attr_entry->metadata[0] = info->pv_num;
22048761c62SAndrew Jeffery 	uint16_t *pv_hdls =
22148761c62SAndrew Jeffery 		(uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
22248761c62SAndrew Jeffery 	size_t i;
22348761c62SAndrew Jeffery 	for (i = 0; i < info->pv_num; i++) {
22448761c62SAndrew Jeffery 		pv_hdls[i] = htole16(info->pv_handle[i]);
22548761c62SAndrew Jeffery 	}
22648761c62SAndrew Jeffery 	attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
22748761c62SAndrew Jeffery 		info->def_num;
22848761c62SAndrew Jeffery 	memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
22948761c62SAndrew Jeffery 		       info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
23048761c62SAndrew Jeffery 	       info->def_index, info->def_num);
23148761c62SAndrew Jeffery 	return PLDM_SUCCESS;
23248761c62SAndrew Jeffery }
23348761c62SAndrew Jeffery 
23448761c62SAndrew Jeffery #define ATTR_TYPE_EXPECT(type, expected)                                       \
23548761c62SAndrew Jeffery 	do {                                                                   \
23648761c62SAndrew Jeffery 		if ((type) != (expected) && (type) != ((expected) | 0x80))     \
23748761c62SAndrew Jeffery 			return PLDM_ERROR_INVALID_DATA;                        \
23848761c62SAndrew Jeffery 	} while (0)
23948761c62SAndrew Jeffery 
24048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_enum_decode_pv_num(const struct pldm_bios_attr_table_entry * entry,uint8_t * pv_num)241b06882f1SAndrew Jeffery int pldm_bios_table_attr_entry_enum_decode_pv_num(
24248761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
24348761c62SAndrew Jeffery {
24448761c62SAndrew Jeffery 	POINTER_CHECK(entry);
24548761c62SAndrew Jeffery 	POINTER_CHECK(pv_num);
24648761c62SAndrew Jeffery 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
24748761c62SAndrew Jeffery 	*pv_num = entry->metadata[0];
24848761c62SAndrew Jeffery 	return PLDM_SUCCESS;
24948761c62SAndrew Jeffery }
25048761c62SAndrew Jeffery 
251*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
pldm_bios_table_attr_entry_enum_decode_def_num(const struct pldm_bios_attr_table_entry * entry,uint8_t * def_num)25246673f4aSAndrew Jeffery int pldm_bios_table_attr_entry_enum_decode_def_num(
25348761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
25448761c62SAndrew Jeffery {
25546673f4aSAndrew Jeffery 	uint8_t pv_num;
25646673f4aSAndrew Jeffery 
25748761c62SAndrew Jeffery 	POINTER_CHECK(entry);
25848761c62SAndrew Jeffery 	POINTER_CHECK(def_num);
25948761c62SAndrew Jeffery 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
26046673f4aSAndrew Jeffery 	pv_num = entry->metadata[0];
26146673f4aSAndrew Jeffery 	*def_num = entry->metadata[sizeof(uint8_t) + sizeof(uint16_t) * pv_num];
26248761c62SAndrew Jeffery 	return PLDM_SUCCESS;
26348761c62SAndrew Jeffery }
26448761c62SAndrew Jeffery 
26548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)26682b4d3b4SAndrew Jeffery int pldm_bios_table_attr_entry_enum_decode_pv_hdls(
26748761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
26848761c62SAndrew Jeffery 	uint8_t pv_num)
26948761c62SAndrew Jeffery {
27048761c62SAndrew Jeffery 	POINTER_CHECK(entry);
27148761c62SAndrew Jeffery 	POINTER_CHECK(pv_hdls);
27248761c62SAndrew Jeffery 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
27348761c62SAndrew Jeffery 	uint8_t num = entry->metadata[0];
27448761c62SAndrew Jeffery 	num = num < pv_num ? num : pv_num;
27548761c62SAndrew Jeffery 	size_t i;
27648761c62SAndrew Jeffery 	for (i = 0; i < num; i++) {
27748761c62SAndrew Jeffery 		uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
27848761c62SAndrew Jeffery 					     i * sizeof(uint16_t));
27948761c62SAndrew Jeffery 		pv_hdls[i] = le16toh(*hdl);
28048761c62SAndrew Jeffery 	}
28148761c62SAndrew Jeffery 	return PLDM_SUCCESS;
28248761c62SAndrew Jeffery }
28348761c62SAndrew Jeffery 
284*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
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)28548761c62SAndrew Jeffery uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
28648761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
28748761c62SAndrew Jeffery 	uint8_t def_num)
28848761c62SAndrew Jeffery {
28946673f4aSAndrew Jeffery 	uint8_t num = 0;
29046673f4aSAndrew Jeffery 
29146673f4aSAndrew Jeffery 	/* TODO: Fix the API to propagate errors */
29246673f4aSAndrew Jeffery 	pldm_bios_table_attr_entry_enum_decode_def_num(entry, &num);
29348761c62SAndrew Jeffery 	num = num < def_num ? num : def_num;
29448761c62SAndrew Jeffery 	uint8_t pv_num = entry->metadata[0];
29548761c62SAndrew Jeffery 	const uint8_t *p = entry->metadata +
29648761c62SAndrew Jeffery 			   sizeof(uint8_t) /* number of possible values*/
29748761c62SAndrew Jeffery 			   + pv_num * sizeof(uint16_t) /* possible values */
29848761c62SAndrew Jeffery 			   + sizeof(uint8_t); /* number of default values */
29948761c62SAndrew Jeffery 	memcpy(def_indices, p, num);
30048761c62SAndrew Jeffery 	return num;
30148761c62SAndrew Jeffery }
30248761c62SAndrew Jeffery 
30348761c62SAndrew Jeffery /** @brief Get length of an enum attribute entry
30448761c62SAndrew Jeffery  */
attr_table_entry_length_enum(const void * arg)30548761c62SAndrew Jeffery static ssize_t attr_table_entry_length_enum(const void *arg)
30648761c62SAndrew Jeffery {
30748761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry = arg;
30848761c62SAndrew Jeffery 	uint8_t pv_num = entry->metadata[0];
30946673f4aSAndrew Jeffery 	uint8_t def_num = 0;
31046673f4aSAndrew Jeffery 
31146673f4aSAndrew Jeffery 	/* TODO: Fix the API to propagate errors */
31246673f4aSAndrew Jeffery 	pldm_bios_table_attr_entry_enum_decode_def_num(entry, &def_num);
31348761c62SAndrew Jeffery 	size_t len =
31448761c62SAndrew Jeffery 		pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
31548761c62SAndrew Jeffery 	if (len > SSIZE_MAX) {
31648761c62SAndrew Jeffery 		return -1;
31748761c62SAndrew Jeffery 	}
31848761c62SAndrew Jeffery 	return (ssize_t)len;
31948761c62SAndrew Jeffery }
32048761c62SAndrew Jeffery 
32148761c62SAndrew Jeffery struct attr_table_string_entry_fields {
32248761c62SAndrew Jeffery 	uint8_t string_type;
32348761c62SAndrew Jeffery 	uint16_t min_length;
32448761c62SAndrew Jeffery 	uint16_t max_length;
32548761c62SAndrew Jeffery 	uint16_t def_length;
32648761c62SAndrew Jeffery 	uint8_t def_string[1];
32748761c62SAndrew Jeffery } __attribute__((packed));
32848761c62SAndrew Jeffery 
32948761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)33048761c62SAndrew Jeffery size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
33148761c62SAndrew Jeffery {
33248761c62SAndrew Jeffery 	return sizeof(struct pldm_bios_attr_table_entry) -
33348761c62SAndrew Jeffery 	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
33448761c62SAndrew Jeffery 	       sizeof(struct attr_table_string_entry_fields) -
33548761c62SAndrew Jeffery 	       MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
33648761c62SAndrew Jeffery 	       def_str_len;
33748761c62SAndrew Jeffery }
33848761c62SAndrew Jeffery 
33948761c62SAndrew Jeffery #define PLDM_STRING_TYPE_MAX	5
34048761c62SAndrew Jeffery #define PLDM_STRING_TYPE_VENDOR 0xff
34148761c62SAndrew Jeffery 
34248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_string_info_check(const struct pldm_bios_table_attr_entry_string_info * info,const char ** errmsg)34348761c62SAndrew Jeffery int pldm_bios_table_attr_entry_string_info_check(
34448761c62SAndrew Jeffery 	const struct pldm_bios_table_attr_entry_string_info *info,
34548761c62SAndrew Jeffery 	const char **errmsg)
34648761c62SAndrew Jeffery {
34748761c62SAndrew Jeffery 	if (info->min_length > info->max_length) {
34848761c62SAndrew Jeffery 		set_errmsg(errmsg, "MinimumStingLength should not be greater "
34948761c62SAndrew Jeffery 				   "than MaximumStringLength");
35048761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
35148761c62SAndrew Jeffery 	}
35248761c62SAndrew Jeffery 	if (info->min_length == info->max_length &&
35348761c62SAndrew Jeffery 	    info->def_length != info->min_length) {
35448761c62SAndrew Jeffery 		set_errmsg(errmsg, "Wrong DefaultStringLength");
35548761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
35648761c62SAndrew Jeffery 	}
35748761c62SAndrew Jeffery 	if (info->def_length > info->max_length ||
35848761c62SAndrew Jeffery 	    info->def_length < info->min_length) {
35948761c62SAndrew Jeffery 		set_errmsg(errmsg, "Wrong DefaultStringLength");
36048761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
36148761c62SAndrew Jeffery 	}
36248761c62SAndrew Jeffery 	if (info->string_type > PLDM_STRING_TYPE_MAX &&
36348761c62SAndrew Jeffery 	    info->string_type != PLDM_STRING_TYPE_VENDOR) {
36448761c62SAndrew Jeffery 		set_errmsg(errmsg, "Wrong StringType");
36548761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
36648761c62SAndrew Jeffery 	}
36748761c62SAndrew Jeffery 	if (info->def_string && info->def_length != strlen(info->def_string)) {
36848761c62SAndrew Jeffery 		set_errmsg(errmsg, "Length of DefaultString should be equal to "
36948761c62SAndrew Jeffery 				   "DefaultStringLength");
37048761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
37148761c62SAndrew Jeffery 	}
37248761c62SAndrew Jeffery 
37348761c62SAndrew Jeffery 	return PLDM_SUCCESS;
37448761c62SAndrew Jeffery }
37548761c62SAndrew Jeffery 
37648761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_string_encode(void * entry,size_t entry_length,const struct pldm_bios_table_attr_entry_string_info * info)377f6be4933SAndrew Jeffery int pldm_bios_table_attr_entry_string_encode(
37848761c62SAndrew Jeffery 	void *entry, size_t entry_length,
37948761c62SAndrew Jeffery 	const struct pldm_bios_table_attr_entry_string_info *info)
38048761c62SAndrew Jeffery {
38148761c62SAndrew Jeffery 	POINTER_CHECK(entry);
38248761c62SAndrew Jeffery 	POINTER_CHECK(info);
38348761c62SAndrew Jeffery 	size_t length = pldm_bios_table_attr_entry_string_encode_length(
38448761c62SAndrew Jeffery 		info->def_length);
38548761c62SAndrew Jeffery 	BUFFER_SIZE_EXPECT(entry_length, length);
38648761c62SAndrew Jeffery 	if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
38748761c62SAndrew Jeffery 	    PLDM_SUCCESS) {
38848761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
38948761c62SAndrew Jeffery 	}
39048761c62SAndrew Jeffery 	uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
39148761c62SAndrew Jeffery 					      PLDM_BIOS_STRING;
39248761c62SAndrew Jeffery 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
39348761c62SAndrew Jeffery 						info->name_handle);
39448761c62SAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
39548761c62SAndrew Jeffery 		return rc;
39648761c62SAndrew Jeffery 	}
39748761c62SAndrew Jeffery 	struct pldm_bios_attr_table_entry *attr_entry = entry;
39848761c62SAndrew Jeffery 	struct attr_table_string_entry_fields *attr_fields =
39948761c62SAndrew Jeffery 		(struct attr_table_string_entry_fields *)attr_entry->metadata;
40048761c62SAndrew Jeffery 	attr_fields->string_type = info->string_type;
40148761c62SAndrew Jeffery 	attr_fields->min_length = htole16(info->min_length);
40248761c62SAndrew Jeffery 	attr_fields->max_length = htole16(info->max_length);
40348761c62SAndrew Jeffery 	attr_fields->def_length = htole16(info->def_length);
40448761c62SAndrew Jeffery 	if (info->def_length != 0 && info->def_string != NULL) {
40548761c62SAndrew Jeffery 		memcpy(attr_fields->def_string, info->def_string,
40648761c62SAndrew Jeffery 		       info->def_length);
40748761c62SAndrew Jeffery 	}
40848761c62SAndrew Jeffery 	return PLDM_SUCCESS;
40948761c62SAndrew Jeffery }
41048761c62SAndrew Jeffery 
41148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_string_decode_def_string_length(const struct pldm_bios_attr_table_entry * entry,uint16_t * def_string_length)412c668ffceSAndrew Jeffery int pldm_bios_table_attr_entry_string_decode_def_string_length(
41348761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry,
41448761c62SAndrew Jeffery 	uint16_t *def_string_length)
41548761c62SAndrew Jeffery {
41648761c62SAndrew Jeffery 	POINTER_CHECK(entry);
41748761c62SAndrew Jeffery 	POINTER_CHECK(def_string_length);
41848761c62SAndrew Jeffery 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
419c668ffceSAndrew Jeffery 	struct attr_table_string_entry_fields *fields =
420c668ffceSAndrew Jeffery 		(struct attr_table_string_entry_fields *)entry->metadata;
421c668ffceSAndrew Jeffery 	*def_string_length = le16toh(fields->def_length);
42248761c62SAndrew Jeffery 	return PLDM_SUCCESS;
42348761c62SAndrew Jeffery }
42448761c62SAndrew Jeffery 
42548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_string_decode_string_type(const struct pldm_bios_attr_table_entry * entry)42648761c62SAndrew Jeffery uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
42748761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry)
42848761c62SAndrew Jeffery {
42948761c62SAndrew Jeffery 	struct attr_table_string_entry_fields *fields =
43048761c62SAndrew Jeffery 		(struct attr_table_string_entry_fields *)entry->metadata;
43148761c62SAndrew Jeffery 	return fields->string_type;
43248761c62SAndrew Jeffery }
43348761c62SAndrew Jeffery 
43448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_string_decode_max_length(const struct pldm_bios_attr_table_entry * entry)43548761c62SAndrew Jeffery uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
43648761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry)
43748761c62SAndrew Jeffery {
43848761c62SAndrew Jeffery 	struct attr_table_string_entry_fields *fields =
43948761c62SAndrew Jeffery 		(struct attr_table_string_entry_fields *)entry->metadata;
44048761c62SAndrew Jeffery 	return le16toh(fields->max_length);
44148761c62SAndrew Jeffery }
44248761c62SAndrew Jeffery 
44348761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_string_decode_min_length(const struct pldm_bios_attr_table_entry * entry)44448761c62SAndrew Jeffery uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
44548761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry)
44648761c62SAndrew Jeffery {
44748761c62SAndrew Jeffery 	struct attr_table_string_entry_fields *fields =
44848761c62SAndrew Jeffery 		(struct attr_table_string_entry_fields *)entry->metadata;
44948761c62SAndrew Jeffery 	return le16toh(fields->min_length);
45048761c62SAndrew Jeffery }
45148761c62SAndrew Jeffery 
45248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_string_decode_def_string(const struct pldm_bios_attr_table_entry * entry,char * buffer,size_t size)45348761c62SAndrew Jeffery uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
45448761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry, char *buffer,
45548761c62SAndrew Jeffery 	size_t size)
45648761c62SAndrew Jeffery {
457c668ffceSAndrew Jeffery 	uint16_t length = 0;
458c668ffceSAndrew Jeffery 	int rc;
459c668ffceSAndrew Jeffery 
460c668ffceSAndrew Jeffery 	if (!entry || !buffer || size == 0) {
461c668ffceSAndrew Jeffery 		return 0;
462c668ffceSAndrew Jeffery 	}
463c668ffceSAndrew Jeffery 
464c668ffceSAndrew Jeffery 	/* TODO: Rework the API to propagate the error */
465c668ffceSAndrew Jeffery 	rc = pldm_bios_table_attr_entry_string_decode_def_string_length(
466c668ffceSAndrew Jeffery 		entry, &length);
467c668ffceSAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
468c668ffceSAndrew Jeffery 		return 0;
469c668ffceSAndrew Jeffery 	}
470c668ffceSAndrew Jeffery 
47148761c62SAndrew Jeffery 	length = length < (size - 1) ? length : (size - 1);
47248761c62SAndrew Jeffery 	struct attr_table_string_entry_fields *fields =
47348761c62SAndrew Jeffery 		(struct attr_table_string_entry_fields *)entry->metadata;
47448761c62SAndrew Jeffery 	memcpy(buffer, fields->def_string, length);
47548761c62SAndrew Jeffery 	buffer[length] = 0;
47648761c62SAndrew Jeffery 	return length;
47748761c62SAndrew Jeffery }
47848761c62SAndrew Jeffery 
47948761c62SAndrew Jeffery /** @brief Get length of a string attribute entry
48048761c62SAndrew Jeffery  */
attr_table_entry_length_string(const void * entry)48148761c62SAndrew Jeffery static ssize_t attr_table_entry_length_string(const void *entry)
48248761c62SAndrew Jeffery {
483c668ffceSAndrew Jeffery 	uint16_t def_str_len = 0;
484c668ffceSAndrew Jeffery 
485c668ffceSAndrew Jeffery 	/* TODO: Rework the API to propagate the error */
48648761c62SAndrew Jeffery 	pldm_bios_table_attr_entry_string_decode_def_string_length(
487c668ffceSAndrew Jeffery 		entry, &def_str_len);
48848761c62SAndrew Jeffery 	size_t len =
48948761c62SAndrew Jeffery 		pldm_bios_table_attr_entry_string_encode_length(def_str_len);
49048761c62SAndrew Jeffery 	if (len > SSIZE_MAX) {
49148761c62SAndrew Jeffery 		return -1;
49248761c62SAndrew Jeffery 	}
49348761c62SAndrew Jeffery 	return (ssize_t)len;
49448761c62SAndrew Jeffery }
49548761c62SAndrew Jeffery 
49648761c62SAndrew Jeffery struct attr_table_integer_entry_fields {
49748761c62SAndrew Jeffery 	uint64_t lower_bound;
49848761c62SAndrew Jeffery 	uint64_t upper_bound;
49948761c62SAndrew Jeffery 	uint32_t scalar_increment;
50048761c62SAndrew Jeffery 	uint64_t default_value;
50148761c62SAndrew Jeffery } __attribute__((packed));
50248761c62SAndrew Jeffery 
50348761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_integer_encode_length(void)50448761c62SAndrew Jeffery size_t pldm_bios_table_attr_entry_integer_encode_length(void)
50548761c62SAndrew Jeffery {
50648761c62SAndrew Jeffery 	return sizeof(struct pldm_bios_attr_table_entry) - 1 +
50748761c62SAndrew Jeffery 	       sizeof(struct attr_table_integer_entry_fields);
50848761c62SAndrew Jeffery }
50948761c62SAndrew Jeffery 
51048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_integer_info_check(const struct pldm_bios_table_attr_entry_integer_info * info,const char ** errmsg)51148761c62SAndrew Jeffery int pldm_bios_table_attr_entry_integer_info_check(
51248761c62SAndrew Jeffery 	const struct pldm_bios_table_attr_entry_integer_info *info,
51348761c62SAndrew Jeffery 	const char **errmsg)
51448761c62SAndrew Jeffery {
51548761c62SAndrew Jeffery 	if (info->lower_bound == info->upper_bound) {
51648761c62SAndrew Jeffery 		if (info->default_value != info->lower_bound) {
51748761c62SAndrew Jeffery 			set_errmsg(errmsg, "Wrong DefaultValue");
51848761c62SAndrew Jeffery 			return PLDM_ERROR_INVALID_DATA;
51948761c62SAndrew Jeffery 		}
52048761c62SAndrew Jeffery 		if (info->scalar_increment != 0) {
52148761c62SAndrew Jeffery 			set_errmsg(errmsg, "Wrong ScalarIncrement");
52248761c62SAndrew Jeffery 			return PLDM_ERROR_INVALID_DATA;
52348761c62SAndrew Jeffery 		}
52448761c62SAndrew Jeffery 		return PLDM_SUCCESS;
52548761c62SAndrew Jeffery 	}
52648761c62SAndrew Jeffery 	if (info->lower_bound > info->upper_bound) {
52748761c62SAndrew Jeffery 		set_errmsg(errmsg,
52848761c62SAndrew Jeffery 			   "LowerBound should not be greater than UpperBound");
52948761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
53048761c62SAndrew Jeffery 	}
53148761c62SAndrew Jeffery 	if (info->default_value > info->upper_bound ||
53248761c62SAndrew Jeffery 	    info->default_value < info->lower_bound) {
53348761c62SAndrew Jeffery 		set_errmsg(errmsg, "Wrong DefaultValue");
53448761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
53548761c62SAndrew Jeffery 	}
53648761c62SAndrew Jeffery 	if (info->scalar_increment == 0) {
53748761c62SAndrew Jeffery 		set_errmsg(errmsg, "ScalarIncrement should not be zero when "
53848761c62SAndrew Jeffery 				   "lower_bound != upper_bound");
53948761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
54048761c62SAndrew Jeffery 	}
54148761c62SAndrew Jeffery 	if ((info->default_value - info->lower_bound) %
54248761c62SAndrew Jeffery 		    info->scalar_increment !=
54348761c62SAndrew Jeffery 	    0) {
54448761c62SAndrew Jeffery 		set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
54548761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
54648761c62SAndrew Jeffery 	}
54748761c62SAndrew Jeffery 	return PLDM_SUCCESS;
54848761c62SAndrew Jeffery }
54948761c62SAndrew Jeffery 
55048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_entry_integer_encode(void * entry,size_t entry_length,const struct pldm_bios_table_attr_entry_integer_info * info)5515347e279SAndrew Jeffery int pldm_bios_table_attr_entry_integer_encode(
55248761c62SAndrew Jeffery 	void *entry, size_t entry_length,
55348761c62SAndrew Jeffery 	const struct pldm_bios_table_attr_entry_integer_info *info)
55448761c62SAndrew Jeffery {
55548761c62SAndrew Jeffery 	POINTER_CHECK(entry);
55648761c62SAndrew Jeffery 	POINTER_CHECK(info);
55748761c62SAndrew Jeffery 	size_t length = pldm_bios_table_attr_entry_integer_encode_length();
55848761c62SAndrew Jeffery 	BUFFER_SIZE_EXPECT(entry_length, length);
55948761c62SAndrew Jeffery 	if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
56048761c62SAndrew Jeffery 	    PLDM_SUCCESS) {
56148761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
56248761c62SAndrew Jeffery 	}
56348761c62SAndrew Jeffery 	uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
56448761c62SAndrew Jeffery 					      PLDM_BIOS_INTEGER;
56548761c62SAndrew Jeffery 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
56648761c62SAndrew Jeffery 						info->name_handle);
56748761c62SAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
56848761c62SAndrew Jeffery 		return rc;
56948761c62SAndrew Jeffery 	}
57048761c62SAndrew Jeffery 	struct pldm_bios_attr_table_entry *attr_entry = entry;
57148761c62SAndrew Jeffery 	struct attr_table_integer_entry_fields *attr_fields =
57248761c62SAndrew Jeffery 		(struct attr_table_integer_entry_fields *)attr_entry->metadata;
57348761c62SAndrew Jeffery 	attr_fields->lower_bound = htole64(info->lower_bound);
57448761c62SAndrew Jeffery 	attr_fields->upper_bound = htole64(info->upper_bound);
57548761c62SAndrew Jeffery 	attr_fields->scalar_increment = htole32(info->scalar_increment);
57648761c62SAndrew Jeffery 	attr_fields->default_value = htole64(info->default_value);
57748761c62SAndrew Jeffery 	return PLDM_SUCCESS;
57848761c62SAndrew Jeffery }
57948761c62SAndrew Jeffery 
58048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)58148761c62SAndrew Jeffery void pldm_bios_table_attr_entry_integer_decode(
58248761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
58348761c62SAndrew Jeffery 	uint64_t *upper, uint32_t *scalar, uint64_t *def)
58448761c62SAndrew Jeffery {
58548761c62SAndrew Jeffery 	struct attr_table_integer_entry_fields *fields =
58648761c62SAndrew Jeffery 		(struct attr_table_integer_entry_fields *)entry->metadata;
58748761c62SAndrew Jeffery 	*lower = le64toh(fields->lower_bound);
58848761c62SAndrew Jeffery 	*upper = le64toh(fields->upper_bound);
58948761c62SAndrew Jeffery 	*scalar = le32toh(fields->scalar_increment);
59048761c62SAndrew Jeffery 	*def = le64toh(fields->default_value);
59148761c62SAndrew Jeffery }
59248761c62SAndrew Jeffery 
attr_table_entry_length_integer(const void * entry)59348761c62SAndrew Jeffery static ssize_t attr_table_entry_length_integer(const void *entry)
59448761c62SAndrew Jeffery {
59548761c62SAndrew Jeffery 	(void)entry;
59648761c62SAndrew Jeffery 	size_t len = pldm_bios_table_attr_entry_integer_encode_length();
59748761c62SAndrew Jeffery 	if (len > SSIZE_MAX) {
59848761c62SAndrew Jeffery 		return -1;
59948761c62SAndrew Jeffery 	}
60048761c62SAndrew Jeffery 	return (ssize_t)len;
60148761c62SAndrew Jeffery }
60248761c62SAndrew Jeffery 
60348761c62SAndrew Jeffery struct table_entry_length {
60448761c62SAndrew Jeffery 	uint8_t attr_type;
60548761c62SAndrew Jeffery 	ssize_t (*entry_length_handler)(const void *);
60648761c62SAndrew Jeffery };
60748761c62SAndrew Jeffery 
60848761c62SAndrew Jeffery 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)60948761c62SAndrew Jeffery find_table_entry_length_by_type(uint8_t attr_type,
61048761c62SAndrew Jeffery 				const struct table_entry_length *handlers,
61148761c62SAndrew Jeffery 				size_t count)
61248761c62SAndrew Jeffery {
61348761c62SAndrew Jeffery 	size_t i;
61448761c62SAndrew Jeffery 	for (i = 0; i < count; i++) {
61548761c62SAndrew Jeffery 		if (attr_type == handlers[i].attr_type) {
61648761c62SAndrew Jeffery 			return &handlers[i];
61748761c62SAndrew Jeffery 		}
61848761c62SAndrew Jeffery 	}
61948761c62SAndrew Jeffery 	return NULL;
62048761c62SAndrew Jeffery }
62148761c62SAndrew Jeffery 
62248761c62SAndrew Jeffery static const struct table_entry_length attr_table_entries[] = {
62348761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_ENUMERATION,
62448761c62SAndrew Jeffery 	  .entry_length_handler = attr_table_entry_length_enum },
62548761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
62648761c62SAndrew Jeffery 	  .entry_length_handler = attr_table_entry_length_enum },
62748761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_STRING,
62848761c62SAndrew Jeffery 	  .entry_length_handler = attr_table_entry_length_string },
62948761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_STRING_READ_ONLY,
63048761c62SAndrew Jeffery 	  .entry_length_handler = attr_table_entry_length_string },
63148761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_INTEGER,
63248761c62SAndrew Jeffery 	  .entry_length_handler = attr_table_entry_length_integer },
63348761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
63448761c62SAndrew Jeffery 	  .entry_length_handler = attr_table_entry_length_integer },
63548761c62SAndrew Jeffery };
63648761c62SAndrew Jeffery 
attr_table_entry_length(const void * table_entry)63748761c62SAndrew Jeffery static ssize_t attr_table_entry_length(const void *table_entry)
63848761c62SAndrew Jeffery {
63948761c62SAndrew Jeffery 	const struct pldm_bios_attr_table_entry *entry = table_entry;
64048761c62SAndrew Jeffery 	const struct table_entry_length *attr_table_entry =
64148761c62SAndrew Jeffery 		find_table_entry_length_by_type(entry->attr_type,
64248761c62SAndrew Jeffery 						attr_table_entries,
64348761c62SAndrew Jeffery 						ARRAY_SIZE(attr_table_entries));
64448761c62SAndrew Jeffery 	assert(attr_table_entry != NULL);
64548761c62SAndrew Jeffery 	if (!attr_table_entry) {
64648761c62SAndrew Jeffery 		return -1;
64748761c62SAndrew Jeffery 	}
64848761c62SAndrew Jeffery 	assert(attr_table_entry->entry_length_handler != NULL);
64948761c62SAndrew Jeffery 	if (!attr_table_entry->entry_length_handler) {
65048761c62SAndrew Jeffery 		return -1;
65148761c62SAndrew Jeffery 	}
65248761c62SAndrew Jeffery 
65348761c62SAndrew Jeffery 	return attr_table_entry->entry_length_handler(entry);
65448761c62SAndrew Jeffery }
65548761c62SAndrew Jeffery 
65648761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_decode_attribute_handle(const struct pldm_bios_attr_val_table_entry * entry)65748761c62SAndrew Jeffery uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
65848761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry)
65948761c62SAndrew Jeffery {
66048761c62SAndrew Jeffery 	return le16toh(entry->attr_handle);
66148761c62SAndrew Jeffery }
66248761c62SAndrew Jeffery 
66348761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_decode_attribute_type(const struct pldm_bios_attr_val_table_entry * entry)66448761c62SAndrew Jeffery uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
66548761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry)
66648761c62SAndrew Jeffery {
66748761c62SAndrew Jeffery 	return entry->attr_type;
66848761c62SAndrew Jeffery }
66948761c62SAndrew Jeffery 
67048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)67148761c62SAndrew Jeffery size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
67248761c62SAndrew Jeffery {
67348761c62SAndrew Jeffery 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
67448761c62SAndrew Jeffery 	       sizeof(count) + count;
67548761c62SAndrew Jeffery }
67648761c62SAndrew Jeffery 
67748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_enum_decode_number(const struct pldm_bios_attr_val_table_entry * entry)67848761c62SAndrew Jeffery uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
67948761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry)
68048761c62SAndrew Jeffery {
68148761c62SAndrew Jeffery 	return entry->value[0];
68248761c62SAndrew Jeffery }
68348761c62SAndrew Jeffery 
68448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_enum_decode_handles(const struct pldm_bios_attr_val_table_entry * entry,uint8_t * handles,uint8_t number)68548761c62SAndrew Jeffery uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
68648761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
68748761c62SAndrew Jeffery 	uint8_t number)
68848761c62SAndrew Jeffery {
68948761c62SAndrew Jeffery 	uint8_t curr_num =
69048761c62SAndrew Jeffery 		pldm_bios_table_attr_value_entry_enum_decode_number(entry);
69148761c62SAndrew Jeffery 	curr_num = number < curr_num ? number : curr_num;
69248761c62SAndrew Jeffery 	memcpy(handles, &entry->value[1], curr_num);
69348761c62SAndrew Jeffery 
69448761c62SAndrew Jeffery 	return curr_num;
69548761c62SAndrew Jeffery }
69648761c62SAndrew Jeffery 
69748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)69809004d6aSAndrew Jeffery int pldm_bios_table_attr_value_entry_encode_enum(
69948761c62SAndrew Jeffery 	void *entry, size_t entry_length, uint16_t attr_handle,
70048761c62SAndrew Jeffery 	uint8_t attr_type, uint8_t count, const uint8_t *handles)
70148761c62SAndrew Jeffery {
70292967bedSAndrew Jeffery 	struct pldm_bios_attr_val_table_entry *table_entry;
70392967bedSAndrew Jeffery 
70448761c62SAndrew Jeffery 	POINTER_CHECK(entry);
70548761c62SAndrew Jeffery 	POINTER_CHECK(handles);
70648761c62SAndrew Jeffery 	if (count != 0 && handles == NULL) {
70748761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
70848761c62SAndrew Jeffery 	}
70948761c62SAndrew Jeffery 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
71092967bedSAndrew Jeffery 	BUFFER_SIZE_EXPECT(entry_length, sizeof(*table_entry));
71192967bedSAndrew Jeffery 	table_entry = entry;
71248761c62SAndrew Jeffery 	table_entry->attr_handle = htole16(attr_handle);
71348761c62SAndrew Jeffery 	table_entry->attr_type = attr_type;
71448761c62SAndrew Jeffery 	table_entry->value[0] = count;
71592967bedSAndrew Jeffery 	if (entry_length - sizeof(*table_entry) < count) {
71692967bedSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
71748761c62SAndrew Jeffery 	}
71892967bedSAndrew Jeffery 	memcpy(&table_entry->value[1], handles, count);
71948761c62SAndrew Jeffery 	return PLDM_SUCCESS;
72048761c62SAndrew Jeffery }
72148761c62SAndrew Jeffery 
attr_value_table_entry_length_enum(const void * entry)72248761c62SAndrew Jeffery static ssize_t attr_value_table_entry_length_enum(const void *entry)
72348761c62SAndrew Jeffery {
72448761c62SAndrew Jeffery 	uint8_t number =
72548761c62SAndrew Jeffery 		pldm_bios_table_attr_value_entry_enum_decode_number(entry);
72648761c62SAndrew Jeffery 	size_t len =
72748761c62SAndrew Jeffery 		pldm_bios_table_attr_value_entry_encode_enum_length(number);
72848761c62SAndrew Jeffery 	if (len > SSIZE_MAX) {
72948761c62SAndrew Jeffery 		return -1;
73048761c62SAndrew Jeffery 	}
73148761c62SAndrew Jeffery 	return (ssize_t)len;
73248761c62SAndrew Jeffery }
73348761c62SAndrew Jeffery 
73448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
73548761c62SAndrew Jeffery size_t
pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)73648761c62SAndrew Jeffery pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
73748761c62SAndrew Jeffery {
73848761c62SAndrew Jeffery 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
73948761c62SAndrew Jeffery 	       sizeof(string_length) + string_length;
74048761c62SAndrew Jeffery }
74148761c62SAndrew Jeffery 
74248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_string_decode_length(const struct pldm_bios_attr_val_table_entry * entry)74348761c62SAndrew Jeffery uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
74448761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry)
74548761c62SAndrew Jeffery {
74648761c62SAndrew Jeffery 	uint16_t str_length = 0;
74748761c62SAndrew Jeffery 	memcpy(&str_length, entry->value, sizeof(str_length));
74848761c62SAndrew Jeffery 	return le16toh(str_length);
74948761c62SAndrew Jeffery }
75048761c62SAndrew Jeffery 
75148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_string_decode_string(const struct pldm_bios_attr_val_table_entry * entry,struct variable_field * current_string)75248761c62SAndrew Jeffery void pldm_bios_table_attr_value_entry_string_decode_string(
75348761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry,
75448761c62SAndrew Jeffery 	struct variable_field *current_string)
75548761c62SAndrew Jeffery {
75648761c62SAndrew Jeffery 	current_string->length =
75748761c62SAndrew Jeffery 		pldm_bios_table_attr_value_entry_string_decode_length(entry);
75848761c62SAndrew Jeffery 	current_string->ptr =
75948761c62SAndrew Jeffery 		entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
76048761c62SAndrew Jeffery }
76148761c62SAndrew Jeffery 
76248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)7631a3983ceSAndrew Jeffery int pldm_bios_table_attr_value_entry_encode_string(
76448761c62SAndrew Jeffery 	void *entry, size_t entry_length, uint16_t attr_handle,
76548761c62SAndrew Jeffery 	uint8_t attr_type, uint16_t str_length, const char *str)
76648761c62SAndrew Jeffery {
767d96d21f4SAndrew Jeffery 	struct pldm_bios_attr_val_table_entry *table_entry;
768d96d21f4SAndrew Jeffery 
76948761c62SAndrew Jeffery 	POINTER_CHECK(entry);
77048761c62SAndrew Jeffery 	if (str_length != 0 && str == NULL) {
77148761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
77248761c62SAndrew Jeffery 	}
77348761c62SAndrew Jeffery 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
774d96d21f4SAndrew Jeffery 	BUFFER_SIZE_EXPECT(entry_length,
775d96d21f4SAndrew Jeffery 			   (sizeof(*table_entry) - 1 + sizeof(str_length)));
776d96d21f4SAndrew Jeffery 	table_entry = entry;
77748761c62SAndrew Jeffery 	table_entry->attr_handle = htole16(attr_handle);
77848761c62SAndrew Jeffery 	table_entry->attr_type = attr_type;
779d96d21f4SAndrew Jeffery 	if (entry_length - (sizeof(*table_entry) - 1 + sizeof(str_length)) <
780d96d21f4SAndrew Jeffery 	    str_length) {
781d96d21f4SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
78248761c62SAndrew Jeffery 	}
783d96d21f4SAndrew Jeffery 	memcpy(table_entry->value + sizeof(str_length), str, str_length);
78448761c62SAndrew Jeffery 	str_length = htole16(str_length);
78548761c62SAndrew Jeffery 	memcpy(table_entry->value, &str_length, sizeof(str_length));
78648761c62SAndrew Jeffery 	return PLDM_SUCCESS;
78748761c62SAndrew Jeffery }
78848761c62SAndrew Jeffery 
attr_value_table_entry_length_string(const void * entry)78948761c62SAndrew Jeffery static ssize_t attr_value_table_entry_length_string(const void *entry)
79048761c62SAndrew Jeffery {
79148761c62SAndrew Jeffery 	uint16_t str_length =
79248761c62SAndrew Jeffery 		pldm_bios_table_attr_value_entry_string_decode_length(entry);
79348761c62SAndrew Jeffery 	size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
79448761c62SAndrew Jeffery 		str_length);
79548761c62SAndrew Jeffery 	if (len > SSIZE_MAX) {
79648761c62SAndrew Jeffery 		return -1;
79748761c62SAndrew Jeffery 	}
79848761c62SAndrew Jeffery 	return (ssize_t)len;
79948761c62SAndrew Jeffery }
80048761c62SAndrew Jeffery 
80148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_encode_integer_length(void)80248761c62SAndrew Jeffery size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
80348761c62SAndrew Jeffery {
80448761c62SAndrew Jeffery 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
80548761c62SAndrew Jeffery 	       sizeof(uint64_t);
80648761c62SAndrew Jeffery }
80748761c62SAndrew Jeffery 
80848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)809504dd17fSAndrew Jeffery int pldm_bios_table_attr_value_entry_encode_integer(void *entry,
81048761c62SAndrew Jeffery 						    size_t entry_length,
81148761c62SAndrew Jeffery 						    uint16_t attr_handle,
81248761c62SAndrew Jeffery 						    uint8_t attr_type,
81348761c62SAndrew Jeffery 						    uint64_t cv)
81448761c62SAndrew Jeffery {
81548761c62SAndrew Jeffery 	POINTER_CHECK(entry);
81648761c62SAndrew Jeffery 	size_t length =
81748761c62SAndrew Jeffery 		pldm_bios_table_attr_value_entry_encode_integer_length();
81848761c62SAndrew Jeffery 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
81948761c62SAndrew Jeffery 	BUFFER_SIZE_EXPECT(entry_length, length);
82048761c62SAndrew Jeffery 	struct pldm_bios_attr_val_table_entry *table_entry = entry;
82148761c62SAndrew Jeffery 	table_entry->attr_handle = htole16(attr_handle);
82248761c62SAndrew Jeffery 	table_entry->attr_type = attr_type;
82348761c62SAndrew Jeffery 	cv = htole64(cv);
82448761c62SAndrew Jeffery 	memcpy(table_entry->value, &cv, sizeof(uint64_t));
82548761c62SAndrew Jeffery 	return PLDM_SUCCESS;
82648761c62SAndrew Jeffery }
82748761c62SAndrew Jeffery 
82848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_integer_decode_cv(const struct pldm_bios_attr_val_table_entry * entry)82948761c62SAndrew Jeffery uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
83048761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry)
83148761c62SAndrew Jeffery {
83248761c62SAndrew Jeffery 	uint64_t cv = 0;
83348761c62SAndrew Jeffery 	memcpy(&cv, entry->value, sizeof(cv));
83448761c62SAndrew Jeffery 	cv = le64toh(cv);
83548761c62SAndrew Jeffery 	return cv;
83648761c62SAndrew Jeffery }
83748761c62SAndrew Jeffery 
attr_value_table_entry_length_integer(const void * entry)83848761c62SAndrew Jeffery static ssize_t attr_value_table_entry_length_integer(const void *entry)
83948761c62SAndrew Jeffery {
84048761c62SAndrew Jeffery 	(void)entry;
84148761c62SAndrew Jeffery 	size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
84248761c62SAndrew Jeffery 	if (len > SSIZE_MAX) {
84348761c62SAndrew Jeffery 		return -1;
84448761c62SAndrew Jeffery 	}
84548761c62SAndrew Jeffery 	return (ssize_t)len;
84648761c62SAndrew Jeffery }
84748761c62SAndrew Jeffery 
84848761c62SAndrew Jeffery static const struct table_entry_length attr_value_table_entries[] = {
84948761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_ENUMERATION,
85048761c62SAndrew Jeffery 	  .entry_length_handler = attr_value_table_entry_length_enum },
85148761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
85248761c62SAndrew Jeffery 	  .entry_length_handler = attr_value_table_entry_length_enum },
85348761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_STRING,
85448761c62SAndrew Jeffery 	  .entry_length_handler = attr_value_table_entry_length_string },
85548761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_STRING_READ_ONLY,
85648761c62SAndrew Jeffery 	  .entry_length_handler = attr_value_table_entry_length_string },
85748761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_INTEGER,
85848761c62SAndrew Jeffery 	  .entry_length_handler = attr_value_table_entry_length_integer },
85948761c62SAndrew Jeffery 	{ .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
86048761c62SAndrew Jeffery 	  .entry_length_handler = attr_value_table_entry_length_integer },
86148761c62SAndrew Jeffery };
86248761c62SAndrew Jeffery 
attr_value_table_entry_length(const void * table_entry)86348761c62SAndrew Jeffery static ssize_t attr_value_table_entry_length(const void *table_entry)
86448761c62SAndrew Jeffery {
86548761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry = table_entry;
86648761c62SAndrew Jeffery 	const struct table_entry_length *entry_length =
86748761c62SAndrew Jeffery 		find_table_entry_length_by_type(
86848761c62SAndrew Jeffery 			entry->attr_type, attr_value_table_entries,
86948761c62SAndrew Jeffery 			ARRAY_SIZE(attr_value_table_entries));
87048761c62SAndrew Jeffery 	assert(entry_length != NULL);
87148761c62SAndrew Jeffery 	if (!entry_length) {
87248761c62SAndrew Jeffery 		return -1;
87348761c62SAndrew Jeffery 	}
87448761c62SAndrew Jeffery 	assert(entry_length->entry_length_handler != NULL);
87548761c62SAndrew Jeffery 	if (!entry_length->entry_length_handler) {
87648761c62SAndrew Jeffery 		return -1;
87748761c62SAndrew Jeffery 	}
87848761c62SAndrew Jeffery 
87948761c62SAndrew Jeffery 	return entry_length->entry_length_handler(entry);
88048761c62SAndrew Jeffery }
88148761c62SAndrew Jeffery 
88248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_length(const struct pldm_bios_attr_val_table_entry * entry)88348761c62SAndrew Jeffery size_t pldm_bios_table_attr_value_entry_length(
88448761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry)
88548761c62SAndrew Jeffery {
88648761c62SAndrew Jeffery 	return attr_value_table_entry_length(entry);
88748761c62SAndrew Jeffery }
88848761c62SAndrew Jeffery 
88948761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_attr_value_entry_decode_handle(const struct pldm_bios_attr_val_table_entry * entry)89048761c62SAndrew Jeffery uint16_t pldm_bios_table_attr_value_entry_decode_handle(
89148761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *entry)
89248761c62SAndrew Jeffery {
89348761c62SAndrew Jeffery 	return le16toh(entry->attr_handle);
89448761c62SAndrew Jeffery }
89548761c62SAndrew Jeffery 
pad_size_get(size_t size_without_pad)89648761c62SAndrew Jeffery static size_t pad_size_get(size_t size_without_pad)
89748761c62SAndrew Jeffery {
89872dd2ddaSAndrew Jeffery 	return (4 - (size_without_pad % 4)) % 4;
89948761c62SAndrew Jeffery }
90048761c62SAndrew Jeffery 
pad_append(uint8_t * table_end,size_t pad_size)90148761c62SAndrew Jeffery static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
90248761c62SAndrew Jeffery {
90348761c62SAndrew Jeffery 	while (pad_size--) {
90448761c62SAndrew Jeffery 		*table_end++ = 0;
90548761c62SAndrew Jeffery 	}
90648761c62SAndrew Jeffery 
90748761c62SAndrew Jeffery 	return table_end;
90848761c62SAndrew Jeffery }
90948761c62SAndrew Jeffery 
checksum_append(uint8_t * table_end,uint32_t checksum)91048761c62SAndrew Jeffery static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
91148761c62SAndrew Jeffery {
91248761c62SAndrew Jeffery 	checksum = htole32(checksum);
91348761c62SAndrew Jeffery 	memcpy(table_end, &checksum, sizeof(checksum));
91448761c62SAndrew Jeffery 
91548761c62SAndrew Jeffery 	return table_end + sizeof(checksum);
91648761c62SAndrew Jeffery }
91748761c62SAndrew Jeffery 
91848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_pad_checksum_size(size_t size_without_pad)91948761c62SAndrew Jeffery size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
92048761c62SAndrew Jeffery {
921a16f70c5SAndrew Jeffery 	return pad_size_get(size_without_pad) + sizeof(uint32_t);
92248761c62SAndrew Jeffery }
92348761c62SAndrew Jeffery 
92448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_append_pad_checksum(void * table,size_t capacity,size_t * size)925d8bb75cbSAndrew Jeffery int pldm_bios_table_append_pad_checksum(void *table, size_t capacity,
92648761c62SAndrew Jeffery 					size_t *size)
92748761c62SAndrew Jeffery {
92848761c62SAndrew Jeffery 	if (!table || !size) {
92948761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
93048761c62SAndrew Jeffery 	}
93148761c62SAndrew Jeffery 
93248761c62SAndrew Jeffery 	size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
933d610b00eSAndrew Jeffery 
934d610b00eSAndrew Jeffery 	if (SIZE_MAX - pad_checksum_size < *size) {
935d610b00eSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
936d610b00eSAndrew Jeffery 	}
937d610b00eSAndrew Jeffery 
93848761c62SAndrew Jeffery 	size_t total_length = *size + pad_checksum_size;
93948761c62SAndrew Jeffery 	if (capacity < total_length) {
94048761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
94148761c62SAndrew Jeffery 	}
94248761c62SAndrew Jeffery 
943d610b00eSAndrew Jeffery 	if (UINTPTR_MAX - *size < (uintptr_t)table) {
944d610b00eSAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
945d610b00eSAndrew Jeffery 	}
94648761c62SAndrew Jeffery 	uint8_t *table_end = (uint8_t *)table + *size;
94748761c62SAndrew Jeffery 	size_t pad_size = pad_size_get(*size);
94848761c62SAndrew Jeffery 	table_end = pad_append(table_end, pad_size);
94948761c62SAndrew Jeffery 
95048761c62SAndrew Jeffery 	uint32_t checksum = crc32(table, *size + pad_size);
95148761c62SAndrew Jeffery 	checksum_append(table_end, checksum);
95248761c62SAndrew Jeffery 	*size = total_length;
95348761c62SAndrew Jeffery 
95448761c62SAndrew Jeffery 	return PLDM_SUCCESS;
95548761c62SAndrew Jeffery }
95648761c62SAndrew Jeffery 
95748761c62SAndrew Jeffery struct pldm_bios_table_iter {
95848761c62SAndrew Jeffery 	const uint8_t *table_data;
95948761c62SAndrew Jeffery 	size_t table_len;
96048761c62SAndrew Jeffery 	size_t current_pos;
96148761c62SAndrew Jeffery 	ssize_t (*entry_length_handler)(const void *table_entry);
96248761c62SAndrew Jeffery };
96348761c62SAndrew Jeffery 
964*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
96548761c62SAndrew Jeffery struct pldm_bios_table_iter *
pldm_bios_table_iter_create(const void * table,size_t length,enum pldm_bios_table_types type)96648761c62SAndrew Jeffery pldm_bios_table_iter_create(const void *table, size_t length,
96748761c62SAndrew Jeffery 			    enum pldm_bios_table_types type)
96848761c62SAndrew Jeffery {
96948761c62SAndrew Jeffery 	struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
97048761c62SAndrew Jeffery 	assert(iter != NULL);
97148761c62SAndrew Jeffery 	if (!iter) {
97248761c62SAndrew Jeffery 		return NULL;
97348761c62SAndrew Jeffery 	}
97448761c62SAndrew Jeffery 	iter->table_data = table;
97548761c62SAndrew Jeffery 	iter->table_len = length;
97648761c62SAndrew Jeffery 	iter->current_pos = 0;
97748761c62SAndrew Jeffery 	iter->entry_length_handler = NULL;
97848761c62SAndrew Jeffery 	switch (type) {
97948761c62SAndrew Jeffery 	case PLDM_BIOS_STRING_TABLE:
98048761c62SAndrew Jeffery 		iter->entry_length_handler = string_table_entry_length;
98148761c62SAndrew Jeffery 		break;
98248761c62SAndrew Jeffery 	case PLDM_BIOS_ATTR_TABLE:
98348761c62SAndrew Jeffery 		iter->entry_length_handler = attr_table_entry_length;
98448761c62SAndrew Jeffery 		break;
98548761c62SAndrew Jeffery 	case PLDM_BIOS_ATTR_VAL_TABLE:
98648761c62SAndrew Jeffery 		iter->entry_length_handler = attr_value_table_entry_length;
98748761c62SAndrew Jeffery 		break;
98848761c62SAndrew Jeffery 	}
98948761c62SAndrew Jeffery 
99048761c62SAndrew Jeffery 	return iter;
99148761c62SAndrew Jeffery }
99248761c62SAndrew Jeffery 
99348761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_iter_free(struct pldm_bios_table_iter * iter)99448761c62SAndrew Jeffery void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
99548761c62SAndrew Jeffery {
99648761c62SAndrew Jeffery 	free(iter);
99748761c62SAndrew Jeffery }
99848761c62SAndrew Jeffery 
99948761c62SAndrew Jeffery #define pad_and_check_max 7
1000*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter * iter)100148761c62SAndrew Jeffery bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
100248761c62SAndrew Jeffery {
100348761c62SAndrew Jeffery 	ssize_t len;
100448761c62SAndrew Jeffery 
10053b5ab929SAndrew Jeffery 	if (!iter) {
10063b5ab929SAndrew Jeffery 		return true;
10073b5ab929SAndrew Jeffery 	}
10083b5ab929SAndrew Jeffery 
1009*36324f6bSAndrew Jeffery 	if (iter->current_pos > iter->table_len) {
1010*36324f6bSAndrew Jeffery 		return true;
1011*36324f6bSAndrew Jeffery 	}
1012*36324f6bSAndrew Jeffery 
101348761c62SAndrew Jeffery 	if (iter->table_len - iter->current_pos <= pad_and_check_max) {
101448761c62SAndrew Jeffery 		return true;
101548761c62SAndrew Jeffery 	}
101648761c62SAndrew Jeffery 
101748761c62SAndrew Jeffery 	len = iter->entry_length_handler(iter->table_data + iter->current_pos);
101848761c62SAndrew Jeffery 
101948761c62SAndrew Jeffery 	return len < 0;
102048761c62SAndrew Jeffery }
102148761c62SAndrew Jeffery 
102248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_iter_next(struct pldm_bios_table_iter * iter)102348761c62SAndrew Jeffery void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
102448761c62SAndrew Jeffery {
102548761c62SAndrew Jeffery 	if (pldm_bios_table_iter_is_end(iter)) {
102648761c62SAndrew Jeffery 		return;
102748761c62SAndrew Jeffery 	}
102848761c62SAndrew Jeffery 	const void *entry = iter->table_data + iter->current_pos;
102948761c62SAndrew Jeffery 	ssize_t rc = iter->entry_length_handler(entry);
103048761c62SAndrew Jeffery 	/* Prevent bad behaviour by acting as if we've hit the end of the iterator */
103148761c62SAndrew Jeffery 	if (rc < 0) {
103248761c62SAndrew Jeffery 		return;
103348761c62SAndrew Jeffery 	}
103448761c62SAndrew Jeffery 	iter->current_pos += rc;
103548761c62SAndrew Jeffery }
103648761c62SAndrew Jeffery 
103748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_iter_value(struct pldm_bios_table_iter * iter)103848761c62SAndrew Jeffery const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
103948761c62SAndrew Jeffery {
104048761c62SAndrew Jeffery 	return iter->table_data + iter->current_pos;
104148761c62SAndrew Jeffery }
104248761c62SAndrew Jeffery 
104348761c62SAndrew Jeffery typedef bool (*equal_handler)(const void *entry, const void *key);
104448761c62SAndrew Jeffery 
104548761c62SAndrew Jeffery static const void *
pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter * iter,const void * key,equal_handler equal)104648761c62SAndrew Jeffery pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
104748761c62SAndrew Jeffery 				   const void *key, equal_handler equal)
104848761c62SAndrew Jeffery {
104948761c62SAndrew Jeffery 	const void *entry;
105048761c62SAndrew Jeffery 	while (!pldm_bios_table_iter_is_end(iter)) {
105148761c62SAndrew Jeffery 		entry = pldm_bios_table_iter_value(iter);
105248761c62SAndrew Jeffery 		if (equal(entry, key)) {
105348761c62SAndrew Jeffery 			return entry;
105448761c62SAndrew Jeffery 		}
105548761c62SAndrew Jeffery 		pldm_bios_table_iter_next(iter);
105648761c62SAndrew Jeffery 	}
105748761c62SAndrew Jeffery 	return NULL;
105848761c62SAndrew Jeffery }
105948761c62SAndrew Jeffery 
106048761c62SAndrew Jeffery 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)106148761c62SAndrew Jeffery pldm_bios_table_entry_find_from_table(const void *table, size_t length,
106248761c62SAndrew Jeffery 				      enum pldm_bios_table_types type,
106348761c62SAndrew Jeffery 				      equal_handler equal, const void *key)
106448761c62SAndrew Jeffery {
106548761c62SAndrew Jeffery 	struct pldm_bios_table_iter *iter =
106648761c62SAndrew Jeffery 		pldm_bios_table_iter_create(table, length, type);
106748761c62SAndrew Jeffery 	const void *entry =
106848761c62SAndrew Jeffery 		pldm_bios_table_entry_find_by_iter(iter, key, equal);
106948761c62SAndrew Jeffery 	pldm_bios_table_iter_free(iter);
107048761c62SAndrew Jeffery 	return entry;
107148761c62SAndrew Jeffery }
107248761c62SAndrew Jeffery 
string_table_handle_equal(const void * entry,const void * key)107348761c62SAndrew Jeffery static bool string_table_handle_equal(const void *entry, const void *key)
107448761c62SAndrew Jeffery {
107548761c62SAndrew Jeffery 	const struct pldm_bios_string_table_entry *string_entry = entry;
107648761c62SAndrew Jeffery 	uint16_t handle = *(uint16_t *)key;
107748761c62SAndrew Jeffery 	if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
107848761c62SAndrew Jeffery 	    handle) {
107948761c62SAndrew Jeffery 		return true;
108048761c62SAndrew Jeffery 	}
108148761c62SAndrew Jeffery 	return false;
108248761c62SAndrew Jeffery }
108348761c62SAndrew Jeffery 
1084*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
108548761c62SAndrew Jeffery const struct pldm_bios_string_table_entry *
pldm_bios_table_string_find_by_handle(const void * table,size_t length,uint16_t handle)108648761c62SAndrew Jeffery pldm_bios_table_string_find_by_handle(const void *table, size_t length,
108748761c62SAndrew Jeffery 				      uint16_t handle)
108848761c62SAndrew Jeffery {
108948761c62SAndrew Jeffery 	return pldm_bios_table_entry_find_from_table(table, length,
109048761c62SAndrew Jeffery 						     PLDM_BIOS_STRING_TABLE,
109148761c62SAndrew Jeffery 						     string_table_handle_equal,
109248761c62SAndrew Jeffery 						     &handle);
109348761c62SAndrew Jeffery }
109448761c62SAndrew Jeffery 
109548761c62SAndrew Jeffery struct string_equal_arg {
109648761c62SAndrew Jeffery 	uint16_t str_length;
109748761c62SAndrew Jeffery 	const char *str;
109848761c62SAndrew Jeffery };
109948761c62SAndrew Jeffery 
string_table_string_equal(const void * entry,const void * key)110048761c62SAndrew Jeffery static bool string_table_string_equal(const void *entry, const void *key)
110148761c62SAndrew Jeffery {
110248761c62SAndrew Jeffery 	const struct pldm_bios_string_table_entry *string_entry = entry;
110348761c62SAndrew Jeffery 	const struct string_equal_arg *arg = key;
110448761c62SAndrew Jeffery 	if (arg->str_length !=
110548761c62SAndrew Jeffery 	    pldm_bios_table_string_entry_decode_string_length(string_entry)) {
110648761c62SAndrew Jeffery 		return false;
110748761c62SAndrew Jeffery 	}
110848761c62SAndrew Jeffery 	if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
110948761c62SAndrew Jeffery 		return false;
111048761c62SAndrew Jeffery 	}
111148761c62SAndrew Jeffery 	return true;
111248761c62SAndrew Jeffery }
111348761c62SAndrew Jeffery 
1114*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
111548761c62SAndrew Jeffery const struct pldm_bios_string_table_entry *
pldm_bios_table_string_find_by_string(const void * table,size_t length,const char * str)111648761c62SAndrew Jeffery pldm_bios_table_string_find_by_string(const void *table, size_t length,
111748761c62SAndrew Jeffery 				      const char *str)
111848761c62SAndrew Jeffery {
111948761c62SAndrew Jeffery 	uint16_t str_length = strlen(str);
112048761c62SAndrew Jeffery 	struct string_equal_arg arg = { str_length, str };
112148761c62SAndrew Jeffery 	return pldm_bios_table_entry_find_from_table(table, length,
112248761c62SAndrew Jeffery 						     PLDM_BIOS_STRING_TABLE,
112348761c62SAndrew Jeffery 						     string_table_string_equal,
112448761c62SAndrew Jeffery 						     &arg);
112548761c62SAndrew Jeffery }
112648761c62SAndrew Jeffery 
attr_table_handle_equal(const void * entry,const void * key)112748761c62SAndrew Jeffery static bool attr_table_handle_equal(const void *entry, const void *key)
112848761c62SAndrew Jeffery {
112948761c62SAndrew Jeffery 	uint16_t handle = *(uint16_t *)key;
113048761c62SAndrew Jeffery 	return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
113148761c62SAndrew Jeffery 	       handle;
113248761c62SAndrew Jeffery }
113348761c62SAndrew Jeffery 
1134*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
113548761c62SAndrew Jeffery const struct pldm_bios_attr_table_entry *
pldm_bios_table_attr_find_by_handle(const void * table,size_t length,uint16_t handle)113648761c62SAndrew Jeffery pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
113748761c62SAndrew Jeffery 				    uint16_t handle)
113848761c62SAndrew Jeffery {
113948761c62SAndrew Jeffery 	return pldm_bios_table_entry_find_from_table(table, length,
114048761c62SAndrew Jeffery 						     PLDM_BIOS_ATTR_TABLE,
114148761c62SAndrew Jeffery 						     attr_table_handle_equal,
114248761c62SAndrew Jeffery 						     &handle);
114348761c62SAndrew Jeffery }
114448761c62SAndrew Jeffery 
attr_table_string_handle_equal(const void * entry,const void * key)114548761c62SAndrew Jeffery static bool attr_table_string_handle_equal(const void *entry, const void *key)
114648761c62SAndrew Jeffery {
114748761c62SAndrew Jeffery 	uint16_t handle = *(uint16_t *)key;
114848761c62SAndrew Jeffery 	return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
114948761c62SAndrew Jeffery }
115048761c62SAndrew Jeffery 
1151*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
115248761c62SAndrew Jeffery const struct pldm_bios_attr_table_entry *
pldm_bios_table_attr_find_by_string_handle(const void * table,size_t length,uint16_t handle)115348761c62SAndrew Jeffery pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
115448761c62SAndrew Jeffery 					   uint16_t handle)
115548761c62SAndrew Jeffery {
115648761c62SAndrew Jeffery 	return pldm_bios_table_entry_find_from_table(
115748761c62SAndrew Jeffery 		table, length, PLDM_BIOS_ATTR_TABLE,
115848761c62SAndrew Jeffery 		attr_table_string_handle_equal, &handle);
115948761c62SAndrew Jeffery }
116048761c62SAndrew Jeffery 
attr_value_table_handle_equal(const void * entry,const void * key)116148761c62SAndrew Jeffery static bool attr_value_table_handle_equal(const void *entry, const void *key)
116248761c62SAndrew Jeffery {
116348761c62SAndrew Jeffery 	uint16_t handle = *(uint16_t *)key;
116448761c62SAndrew Jeffery 	return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
116548761c62SAndrew Jeffery }
116648761c62SAndrew Jeffery 
1167*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
116848761c62SAndrew Jeffery 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)116948761c62SAndrew Jeffery pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
117048761c62SAndrew Jeffery 					  uint16_t handle)
117148761c62SAndrew Jeffery {
117248761c62SAndrew Jeffery 	return pldm_bios_table_entry_find_from_table(
117348761c62SAndrew Jeffery 		table, length, PLDM_BIOS_ATTR_VAL_TABLE,
117448761c62SAndrew Jeffery 		attr_value_table_handle_equal, &handle);
117548761c62SAndrew Jeffery }
117648761c62SAndrew Jeffery 
117748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)117848761c62SAndrew Jeffery int pldm_bios_table_attr_value_copy_and_update(
117948761c62SAndrew Jeffery 	const void *src_table, size_t src_length, void *dest_table,
118048761c62SAndrew Jeffery 	size_t *dest_length, const void *entry, size_t entry_length)
118148761c62SAndrew Jeffery {
118248761c62SAndrew Jeffery 	struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
118348761c62SAndrew Jeffery 		src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
118448761c62SAndrew Jeffery 
118548761c62SAndrew Jeffery 	int rc = PLDM_SUCCESS;
118648761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *tmp;
118748761c62SAndrew Jeffery 	const struct pldm_bios_attr_val_table_entry *to_update = entry;
118848761c62SAndrew Jeffery 	size_t buffer_length = *dest_length;
118948761c62SAndrew Jeffery 	size_t copied_length = 0;
119048761c62SAndrew Jeffery 	size_t length = 0;
119148761c62SAndrew Jeffery 	while (!pldm_bios_table_iter_is_end(iter)) {
119248761c62SAndrew Jeffery 		tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
119348761c62SAndrew Jeffery 		length = attr_value_table_entry_length(tmp);
119448761c62SAndrew Jeffery 
119548761c62SAndrew Jeffery 		/* we need the tmp's entry_length here, iter_next will calculate
119648761c62SAndrew Jeffery 		 * it too, use current_pos directly to avoid calculating it
119748761c62SAndrew Jeffery 		 * twice */
119848761c62SAndrew Jeffery 		iter->current_pos += length;
119948761c62SAndrew Jeffery 		if (tmp->attr_handle == to_update->attr_handle) {
120048761c62SAndrew Jeffery 			if (tmp->attr_type != to_update->attr_type) {
120148761c62SAndrew Jeffery 				rc = PLDM_ERROR_INVALID_DATA;
120248761c62SAndrew Jeffery 				goto out;
120348761c62SAndrew Jeffery 			}
120448761c62SAndrew Jeffery 			length = entry_length;
120548761c62SAndrew Jeffery 			tmp = entry;
120648761c62SAndrew Jeffery 		}
120748761c62SAndrew Jeffery 		if (copied_length + length > buffer_length) {
120848761c62SAndrew Jeffery 			rc = PLDM_ERROR_INVALID_LENGTH;
120948761c62SAndrew Jeffery 			goto out;
121048761c62SAndrew Jeffery 		}
121148761c62SAndrew Jeffery 		memcpy((uint8_t *)dest_table + copied_length, tmp, length);
121248761c62SAndrew Jeffery 		copied_length += length;
121348761c62SAndrew Jeffery 	}
121448761c62SAndrew Jeffery 
121548761c62SAndrew Jeffery 	size_t pad_checksum_size =
121648761c62SAndrew Jeffery 		pldm_bios_table_pad_checksum_size(copied_length);
121748761c62SAndrew Jeffery 	if ((pad_checksum_size + copied_length) > buffer_length) {
121848761c62SAndrew Jeffery 		rc = PLDM_ERROR_INVALID_LENGTH;
121948761c62SAndrew Jeffery 		goto out;
122048761c62SAndrew Jeffery 	}
122148761c62SAndrew Jeffery 
1222d8bb75cbSAndrew Jeffery 	rc = pldm_bios_table_append_pad_checksum(dest_table, buffer_length,
1223d8bb75cbSAndrew Jeffery 						 &copied_length);
122448761c62SAndrew Jeffery 	if (rc == PLDM_SUCCESS) {
122548761c62SAndrew Jeffery 		*dest_length = copied_length;
122648761c62SAndrew Jeffery 	}
122748761c62SAndrew Jeffery out:
122848761c62SAndrew Jeffery 	pldm_bios_table_iter_free(iter);
122948761c62SAndrew Jeffery 	return rc;
123048761c62SAndrew Jeffery }
123148761c62SAndrew Jeffery 
123248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_bios_table_checksum(const uint8_t * table,size_t size)123348761c62SAndrew Jeffery bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
123448761c62SAndrew Jeffery {
123548761c62SAndrew Jeffery 	if (table == NULL) {
123648761c62SAndrew Jeffery 		return false;
123748761c62SAndrew Jeffery 	}
123848761c62SAndrew Jeffery 
123948761c62SAndrew Jeffery 	// 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
124048761c62SAndrew Jeffery 	//     Variable(4) + checksum(uint32)
124148761c62SAndrew Jeffery 	if (size < 12) {
124248761c62SAndrew Jeffery 		return false;
124348761c62SAndrew Jeffery 	}
124448761c62SAndrew Jeffery 
124548761c62SAndrew Jeffery 	uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
124648761c62SAndrew Jeffery 	uint32_t dst_crc = crc32(table, size - 4);
124748761c62SAndrew Jeffery 
124848761c62SAndrew Jeffery 	return src_crc == dst_crc;
124948761c62SAndrew Jeffery }
1250