xref: /openbmc/libpldm/src/dsp/bios_table.c (revision 92967bedd0a469ac2b84faf0ce4b3560aaa17d5a)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include "array.h"
3 
4 #include <libpldm/base.h>
5 #include <libpldm/bios.h>
6 #include <libpldm/bios_table.h>
7 #include <libpldm/utils.h>
8 
9 #include <assert.h>
10 #include <endian.h>
11 #include <limits.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #define POINTER_CHECK(pointer)                                                 \
18 	do {                                                                   \
19 		if ((pointer) == NULL)                                         \
20 			return PLDM_ERROR_INVALID_DATA;                        \
21 	} while (0)
22 
23 #define ATTR_TYPE_EXPECT(type, expected)                                       \
24 	do {                                                                   \
25 		if ((type) != (expected) && (type) != ((expected) | 0x80))     \
26 			return PLDM_ERROR_INVALID_DATA;                        \
27 	} while (0)
28 
29 #define BUFFER_SIZE_EXPECT(current_size, expected_size)                        \
30 	do {                                                                   \
31 		if ((current_size) < (expected_size))                          \
32 			return PLDM_ERROR_INVALID_LENGTH;                      \
33 	} while (0)
34 
35 #define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
36 
37 static void set_errmsg(const char **errmsg, const char *msg)
38 {
39 	if (errmsg != NULL) {
40 		*errmsg = msg;
41 	}
42 }
43 
44 static int get_bios_string_handle(uint16_t *val)
45 {
46 	static uint16_t handle = 0;
47 	assert(handle != UINT16_MAX);
48 	if (handle == UINT16_MAX) {
49 		return PLDM_ERROR_INVALID_DATA;
50 	}
51 
52 	*val = handle++;
53 	return PLDM_SUCCESS;
54 }
55 
56 LIBPLDM_ABI_STABLE
57 size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
58 {
59 	return sizeof(struct pldm_bios_string_table_entry) -
60 	       MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
61 }
62 
63 LIBPLDM_ABI_STABLE
64 int pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
65 					const char *str, uint16_t str_length)
66 {
67 	if (str_length == 0) {
68 		return PLDM_ERROR_INVALID_DATA;
69 	}
70 	POINTER_CHECK(entry);
71 	POINTER_CHECK(str);
72 	size_t length = pldm_bios_table_string_entry_encode_length(str_length);
73 	BUFFER_SIZE_EXPECT(entry_length, length);
74 	struct pldm_bios_string_table_entry *string_entry = entry;
75 	uint16_t handle;
76 	int rc = get_bios_string_handle(&handle);
77 	if (rc != PLDM_SUCCESS) {
78 		return rc;
79 	}
80 	string_entry->string_handle = htole16(handle);
81 	string_entry->string_length = htole16(str_length);
82 	memcpy(string_entry->name, str, str_length);
83 	return PLDM_SUCCESS;
84 }
85 
86 LIBPLDM_ABI_STABLE
87 uint16_t pldm_bios_table_string_entry_decode_handle(
88 	const struct pldm_bios_string_table_entry *entry)
89 {
90 	return le16toh(entry->string_handle);
91 }
92 
93 LIBPLDM_ABI_STABLE
94 uint16_t pldm_bios_table_string_entry_decode_string_length(
95 	const struct pldm_bios_string_table_entry *entry)
96 {
97 	return le16toh(entry->string_length);
98 }
99 
100 LIBPLDM_ABI_STABLE
101 int pldm_bios_table_string_entry_decode_string(
102 	const struct pldm_bios_string_table_entry *entry, char *buffer,
103 	size_t size)
104 {
105 	POINTER_CHECK(entry);
106 	POINTER_CHECK(buffer);
107 	if (size == 0) {
108 		return PLDM_ERROR_INVALID_LENGTH;
109 	}
110 	size_t length =
111 		pldm_bios_table_string_entry_decode_string_length(entry);
112 	length = length < (size - 1) ? length : (size - 1);
113 	memcpy(buffer, entry->name, length);
114 	buffer[length] = 0;
115 	return PLDM_SUCCESS;
116 }
117 
118 static ssize_t string_table_entry_length(const void *table_entry)
119 {
120 	const struct pldm_bios_string_table_entry *entry = table_entry;
121 	size_t len = sizeof(*entry) - sizeof(entry->name) +
122 		     pldm_bios_table_string_entry_decode_string_length(entry);
123 	if (len > SSIZE_MAX) {
124 		return -1;
125 	}
126 	return (ssize_t)len;
127 }
128 
129 static int get_bios_attr_handle(uint16_t *val)
130 {
131 	static uint16_t handle = 0;
132 	assert(handle != UINT16_MAX);
133 	if (handle == UINT16_MAX) {
134 		return PLDM_ERROR_INVALID_DATA;
135 	}
136 
137 	*val = handle++;
138 	return PLDM_SUCCESS;
139 }
140 
141 static int attr_table_entry_encode_header(void *entry, size_t length,
142 					  uint8_t attr_type,
143 					  uint16_t string_handle)
144 {
145 	struct pldm_bios_attr_table_entry *attr_entry = entry;
146 
147 	assert(sizeof(*attr_entry) <= length);
148 	if (sizeof(*attr_entry) > length) {
149 		return PLDM_ERROR_INVALID_LENGTH;
150 	}
151 
152 	uint16_t handle;
153 	int rc = get_bios_attr_handle(&handle);
154 	if (rc != PLDM_SUCCESS) {
155 		return rc;
156 	}
157 
158 	attr_entry->attr_handle = htole16(handle);
159 	attr_entry->attr_type = attr_type;
160 	attr_entry->string_handle = htole16(string_handle);
161 
162 	return PLDM_SUCCESS;
163 }
164 
165 LIBPLDM_ABI_STABLE
166 uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
167 	const struct pldm_bios_attr_table_entry *entry)
168 {
169 	return le16toh(entry->attr_handle);
170 }
171 
172 LIBPLDM_ABI_STABLE
173 uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
174 	const struct pldm_bios_attr_table_entry *entry)
175 {
176 	return entry->attr_type;
177 }
178 
179 LIBPLDM_ABI_STABLE
180 uint16_t pldm_bios_table_attr_entry_decode_string_handle(
181 	const struct pldm_bios_attr_table_entry *entry)
182 {
183 	return le16toh(entry->string_handle);
184 }
185 
186 LIBPLDM_ABI_STABLE
187 size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
188 						     uint8_t def_num)
189 {
190 	return sizeof(struct pldm_bios_attr_table_entry) -
191 	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
192 	       sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
193 	       def_num;
194 }
195 
196 LIBPLDM_ABI_STABLE
197 int pldm_bios_table_attr_entry_enum_encode(
198 	void *entry, size_t entry_length,
199 	const struct pldm_bios_table_attr_entry_enum_info *info)
200 {
201 	POINTER_CHECK(entry);
202 	POINTER_CHECK(info);
203 	size_t length = pldm_bios_table_attr_entry_enum_encode_length(
204 		info->pv_num, info->def_num);
205 	BUFFER_SIZE_EXPECT(entry_length, length);
206 	uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
207 					      PLDM_BIOS_ENUMERATION;
208 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
209 						info->name_handle);
210 	if (rc != PLDM_SUCCESS) {
211 		return rc;
212 	}
213 	struct pldm_bios_attr_table_entry *attr_entry = entry;
214 	attr_entry->metadata[0] = info->pv_num;
215 	uint16_t *pv_hdls =
216 		(uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
217 	size_t i;
218 	for (i = 0; i < info->pv_num; i++) {
219 		pv_hdls[i] = htole16(info->pv_handle[i]);
220 	}
221 	attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
222 		info->def_num;
223 	memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
224 		       info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
225 	       info->def_index, info->def_num);
226 	return PLDM_SUCCESS;
227 }
228 
229 #define ATTR_TYPE_EXPECT(type, expected)                                       \
230 	do {                                                                   \
231 		if ((type) != (expected) && (type) != ((expected) | 0x80))     \
232 			return PLDM_ERROR_INVALID_DATA;                        \
233 	} while (0)
234 
235 LIBPLDM_ABI_STABLE
236 int pldm_bios_table_attr_entry_enum_decode_pv_num(
237 	const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
238 {
239 	POINTER_CHECK(entry);
240 	POINTER_CHECK(pv_num);
241 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
242 	*pv_num = entry->metadata[0];
243 	return PLDM_SUCCESS;
244 }
245 
246 LIBPLDM_ABI_STABLE
247 int pldm_bios_table_attr_entry_enum_decode_def_num(
248 	const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
249 {
250 	uint8_t pv_num;
251 
252 	POINTER_CHECK(entry);
253 	POINTER_CHECK(def_num);
254 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
255 	pv_num = entry->metadata[0];
256 	*def_num = entry->metadata[sizeof(uint8_t) + sizeof(uint16_t) * pv_num];
257 	return PLDM_SUCCESS;
258 }
259 
260 LIBPLDM_ABI_STABLE
261 int pldm_bios_table_attr_entry_enum_decode_pv_hdls(
262 	const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
263 	uint8_t pv_num)
264 {
265 	POINTER_CHECK(entry);
266 	POINTER_CHECK(pv_hdls);
267 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
268 	uint8_t num = entry->metadata[0];
269 	num = num < pv_num ? num : pv_num;
270 	size_t i;
271 	for (i = 0; i < num; i++) {
272 		uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
273 					     i * sizeof(uint16_t));
274 		pv_hdls[i] = le16toh(*hdl);
275 	}
276 	return PLDM_SUCCESS;
277 }
278 
279 LIBPLDM_ABI_STABLE
280 uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
281 	const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
282 	uint8_t def_num)
283 {
284 	uint8_t num = 0;
285 
286 	/* TODO: Fix the API to propagate errors */
287 	pldm_bios_table_attr_entry_enum_decode_def_num(entry, &num);
288 	num = num < def_num ? num : def_num;
289 	uint8_t pv_num = entry->metadata[0];
290 	const uint8_t *p = entry->metadata +
291 			   sizeof(uint8_t) /* number of possible values*/
292 			   + pv_num * sizeof(uint16_t) /* possible values */
293 			   + sizeof(uint8_t); /* number of default values */
294 	memcpy(def_indices, p, num);
295 	return num;
296 }
297 
298 /** @brief Get length of an enum attribute entry
299  */
300 static ssize_t attr_table_entry_length_enum(const void *arg)
301 {
302 	const struct pldm_bios_attr_table_entry *entry = arg;
303 	uint8_t pv_num = entry->metadata[0];
304 	uint8_t def_num = 0;
305 
306 	/* TODO: Fix the API to propagate errors */
307 	pldm_bios_table_attr_entry_enum_decode_def_num(entry, &def_num);
308 	size_t len =
309 		pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
310 	if (len > SSIZE_MAX) {
311 		return -1;
312 	}
313 	return (ssize_t)len;
314 }
315 
316 struct attr_table_string_entry_fields {
317 	uint8_t string_type;
318 	uint16_t min_length;
319 	uint16_t max_length;
320 	uint16_t def_length;
321 	uint8_t def_string[1];
322 } __attribute__((packed));
323 
324 LIBPLDM_ABI_STABLE
325 size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
326 {
327 	return sizeof(struct pldm_bios_attr_table_entry) -
328 	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
329 	       sizeof(struct attr_table_string_entry_fields) -
330 	       MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
331 	       def_str_len;
332 }
333 
334 #define PLDM_STRING_TYPE_MAX	5
335 #define PLDM_STRING_TYPE_VENDOR 0xff
336 
337 LIBPLDM_ABI_STABLE
338 int pldm_bios_table_attr_entry_string_info_check(
339 	const struct pldm_bios_table_attr_entry_string_info *info,
340 	const char **errmsg)
341 {
342 	if (info->min_length > info->max_length) {
343 		set_errmsg(errmsg, "MinimumStingLength should not be greater "
344 				   "than MaximumStringLength");
345 		return PLDM_ERROR_INVALID_DATA;
346 	}
347 	if (info->min_length == info->max_length &&
348 	    info->def_length != info->min_length) {
349 		set_errmsg(errmsg, "Wrong DefaultStringLength");
350 		return PLDM_ERROR_INVALID_DATA;
351 	}
352 	if (info->def_length > info->max_length ||
353 	    info->def_length < info->min_length) {
354 		set_errmsg(errmsg, "Wrong DefaultStringLength");
355 		return PLDM_ERROR_INVALID_DATA;
356 	}
357 	if (info->string_type > PLDM_STRING_TYPE_MAX &&
358 	    info->string_type != PLDM_STRING_TYPE_VENDOR) {
359 		set_errmsg(errmsg, "Wrong StringType");
360 		return PLDM_ERROR_INVALID_DATA;
361 	}
362 	if (info->def_string && info->def_length != strlen(info->def_string)) {
363 		set_errmsg(errmsg, "Length of DefaultString should be equal to "
364 				   "DefaultStringLength");
365 		return PLDM_ERROR_INVALID_DATA;
366 	}
367 
368 	return PLDM_SUCCESS;
369 }
370 
371 LIBPLDM_ABI_STABLE
372 int pldm_bios_table_attr_entry_string_encode(
373 	void *entry, size_t entry_length,
374 	const struct pldm_bios_table_attr_entry_string_info *info)
375 {
376 	POINTER_CHECK(entry);
377 	POINTER_CHECK(info);
378 	size_t length = pldm_bios_table_attr_entry_string_encode_length(
379 		info->def_length);
380 	BUFFER_SIZE_EXPECT(entry_length, length);
381 	if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
382 	    PLDM_SUCCESS) {
383 		return PLDM_ERROR_INVALID_DATA;
384 	}
385 	uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
386 					      PLDM_BIOS_STRING;
387 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
388 						info->name_handle);
389 	if (rc != PLDM_SUCCESS) {
390 		return rc;
391 	}
392 	struct pldm_bios_attr_table_entry *attr_entry = entry;
393 	struct attr_table_string_entry_fields *attr_fields =
394 		(struct attr_table_string_entry_fields *)attr_entry->metadata;
395 	attr_fields->string_type = info->string_type;
396 	attr_fields->min_length = htole16(info->min_length);
397 	attr_fields->max_length = htole16(info->max_length);
398 	attr_fields->def_length = htole16(info->def_length);
399 	if (info->def_length != 0 && info->def_string != NULL) {
400 		memcpy(attr_fields->def_string, info->def_string,
401 		       info->def_length);
402 	}
403 	return PLDM_SUCCESS;
404 }
405 
406 LIBPLDM_ABI_STABLE
407 int pldm_bios_table_attr_entry_string_decode_def_string_length(
408 	const struct pldm_bios_attr_table_entry *entry,
409 	uint16_t *def_string_length)
410 {
411 	POINTER_CHECK(entry);
412 	POINTER_CHECK(def_string_length);
413 	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
414 	struct attr_table_string_entry_fields *fields =
415 		(struct attr_table_string_entry_fields *)entry->metadata;
416 	*def_string_length = le16toh(fields->def_length);
417 	return PLDM_SUCCESS;
418 }
419 
420 LIBPLDM_ABI_STABLE
421 uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
422 	const struct pldm_bios_attr_table_entry *entry)
423 {
424 	struct attr_table_string_entry_fields *fields =
425 		(struct attr_table_string_entry_fields *)entry->metadata;
426 	return fields->string_type;
427 }
428 
429 LIBPLDM_ABI_STABLE
430 uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
431 	const struct pldm_bios_attr_table_entry *entry)
432 {
433 	struct attr_table_string_entry_fields *fields =
434 		(struct attr_table_string_entry_fields *)entry->metadata;
435 	return le16toh(fields->max_length);
436 }
437 
438 LIBPLDM_ABI_STABLE
439 uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
440 	const struct pldm_bios_attr_table_entry *entry)
441 {
442 	struct attr_table_string_entry_fields *fields =
443 		(struct attr_table_string_entry_fields *)entry->metadata;
444 	return le16toh(fields->min_length);
445 }
446 
447 LIBPLDM_ABI_STABLE
448 uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
449 	const struct pldm_bios_attr_table_entry *entry, char *buffer,
450 	size_t size)
451 {
452 	uint16_t length = 0;
453 	int rc;
454 
455 	if (!entry || !buffer || size == 0) {
456 		return 0;
457 	}
458 
459 	/* TODO: Rework the API to propagate the error */
460 	rc = pldm_bios_table_attr_entry_string_decode_def_string_length(
461 		entry, &length);
462 	if (rc != PLDM_SUCCESS) {
463 		return 0;
464 	}
465 
466 	length = length < (size - 1) ? length : (size - 1);
467 	struct attr_table_string_entry_fields *fields =
468 		(struct attr_table_string_entry_fields *)entry->metadata;
469 	memcpy(buffer, fields->def_string, length);
470 	buffer[length] = 0;
471 	return length;
472 }
473 
474 /** @brief Get length of a string attribute entry
475  */
476 static ssize_t attr_table_entry_length_string(const void *entry)
477 {
478 	uint16_t def_str_len = 0;
479 
480 	/* TODO: Rework the API to propagate the error */
481 	pldm_bios_table_attr_entry_string_decode_def_string_length(
482 		entry, &def_str_len);
483 	size_t len =
484 		pldm_bios_table_attr_entry_string_encode_length(def_str_len);
485 	if (len > SSIZE_MAX) {
486 		return -1;
487 	}
488 	return (ssize_t)len;
489 }
490 
491 struct attr_table_integer_entry_fields {
492 	uint64_t lower_bound;
493 	uint64_t upper_bound;
494 	uint32_t scalar_increment;
495 	uint64_t default_value;
496 } __attribute__((packed));
497 
498 LIBPLDM_ABI_STABLE
499 size_t pldm_bios_table_attr_entry_integer_encode_length(void)
500 {
501 	return sizeof(struct pldm_bios_attr_table_entry) - 1 +
502 	       sizeof(struct attr_table_integer_entry_fields);
503 }
504 
505 LIBPLDM_ABI_STABLE
506 int pldm_bios_table_attr_entry_integer_info_check(
507 	const struct pldm_bios_table_attr_entry_integer_info *info,
508 	const char **errmsg)
509 {
510 	if (info->lower_bound == info->upper_bound) {
511 		if (info->default_value != info->lower_bound) {
512 			set_errmsg(errmsg, "Wrong DefaultValue");
513 			return PLDM_ERROR_INVALID_DATA;
514 		}
515 		if (info->scalar_increment != 0) {
516 			set_errmsg(errmsg, "Wrong ScalarIncrement");
517 			return PLDM_ERROR_INVALID_DATA;
518 		}
519 		return PLDM_SUCCESS;
520 	}
521 	if (info->lower_bound > info->upper_bound) {
522 		set_errmsg(errmsg,
523 			   "LowerBound should not be greater than UpperBound");
524 		return PLDM_ERROR_INVALID_DATA;
525 	}
526 	if (info->default_value > info->upper_bound ||
527 	    info->default_value < info->lower_bound) {
528 		set_errmsg(errmsg, "Wrong DefaultValue");
529 		return PLDM_ERROR_INVALID_DATA;
530 	}
531 	if (info->scalar_increment == 0) {
532 		set_errmsg(errmsg, "ScalarIncrement should not be zero when "
533 				   "lower_bound != upper_bound");
534 		return PLDM_ERROR_INVALID_DATA;
535 	}
536 	if ((info->default_value - info->lower_bound) %
537 		    info->scalar_increment !=
538 	    0) {
539 		set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
540 		return PLDM_ERROR_INVALID_DATA;
541 	}
542 	return PLDM_SUCCESS;
543 }
544 
545 LIBPLDM_ABI_STABLE
546 int pldm_bios_table_attr_entry_integer_encode(
547 	void *entry, size_t entry_length,
548 	const struct pldm_bios_table_attr_entry_integer_info *info)
549 {
550 	POINTER_CHECK(entry);
551 	POINTER_CHECK(info);
552 	size_t length = pldm_bios_table_attr_entry_integer_encode_length();
553 	BUFFER_SIZE_EXPECT(entry_length, length);
554 	if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
555 	    PLDM_SUCCESS) {
556 		return PLDM_ERROR_INVALID_DATA;
557 	}
558 	uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
559 					      PLDM_BIOS_INTEGER;
560 	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
561 						info->name_handle);
562 	if (rc != PLDM_SUCCESS) {
563 		return rc;
564 	}
565 	struct pldm_bios_attr_table_entry *attr_entry = entry;
566 	struct attr_table_integer_entry_fields *attr_fields =
567 		(struct attr_table_integer_entry_fields *)attr_entry->metadata;
568 	attr_fields->lower_bound = htole64(info->lower_bound);
569 	attr_fields->upper_bound = htole64(info->upper_bound);
570 	attr_fields->scalar_increment = htole32(info->scalar_increment);
571 	attr_fields->default_value = htole64(info->default_value);
572 	return PLDM_SUCCESS;
573 }
574 
575 LIBPLDM_ABI_STABLE
576 void pldm_bios_table_attr_entry_integer_decode(
577 	const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
578 	uint64_t *upper, uint32_t *scalar, uint64_t *def)
579 {
580 	struct attr_table_integer_entry_fields *fields =
581 		(struct attr_table_integer_entry_fields *)entry->metadata;
582 	*lower = le64toh(fields->lower_bound);
583 	*upper = le64toh(fields->upper_bound);
584 	*scalar = le32toh(fields->scalar_increment);
585 	*def = le64toh(fields->default_value);
586 }
587 
588 static ssize_t attr_table_entry_length_integer(const void *entry)
589 {
590 	(void)entry;
591 	size_t len = pldm_bios_table_attr_entry_integer_encode_length();
592 	if (len > SSIZE_MAX) {
593 		return -1;
594 	}
595 	return (ssize_t)len;
596 }
597 
598 struct table_entry_length {
599 	uint8_t attr_type;
600 	ssize_t (*entry_length_handler)(const void *);
601 };
602 
603 static const struct table_entry_length *
604 find_table_entry_length_by_type(uint8_t attr_type,
605 				const struct table_entry_length *handlers,
606 				size_t count)
607 {
608 	size_t i;
609 	for (i = 0; i < count; i++) {
610 		if (attr_type == handlers[i].attr_type) {
611 			return &handlers[i];
612 		}
613 	}
614 	return NULL;
615 }
616 
617 static const struct table_entry_length attr_table_entries[] = {
618 	{ .attr_type = PLDM_BIOS_ENUMERATION,
619 	  .entry_length_handler = attr_table_entry_length_enum },
620 	{ .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
621 	  .entry_length_handler = attr_table_entry_length_enum },
622 	{ .attr_type = PLDM_BIOS_STRING,
623 	  .entry_length_handler = attr_table_entry_length_string },
624 	{ .attr_type = PLDM_BIOS_STRING_READ_ONLY,
625 	  .entry_length_handler = attr_table_entry_length_string },
626 	{ .attr_type = PLDM_BIOS_INTEGER,
627 	  .entry_length_handler = attr_table_entry_length_integer },
628 	{ .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
629 	  .entry_length_handler = attr_table_entry_length_integer },
630 };
631 
632 static ssize_t attr_table_entry_length(const void *table_entry)
633 {
634 	const struct pldm_bios_attr_table_entry *entry = table_entry;
635 	const struct table_entry_length *attr_table_entry =
636 		find_table_entry_length_by_type(entry->attr_type,
637 						attr_table_entries,
638 						ARRAY_SIZE(attr_table_entries));
639 	assert(attr_table_entry != NULL);
640 	if (!attr_table_entry) {
641 		return -1;
642 	}
643 	assert(attr_table_entry->entry_length_handler != NULL);
644 	if (!attr_table_entry->entry_length_handler) {
645 		return -1;
646 	}
647 
648 	return attr_table_entry->entry_length_handler(entry);
649 }
650 
651 LIBPLDM_ABI_STABLE
652 uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
653 	const struct pldm_bios_attr_val_table_entry *entry)
654 {
655 	return le16toh(entry->attr_handle);
656 }
657 
658 LIBPLDM_ABI_STABLE
659 uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
660 	const struct pldm_bios_attr_val_table_entry *entry)
661 {
662 	return entry->attr_type;
663 }
664 
665 LIBPLDM_ABI_STABLE
666 size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
667 {
668 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
669 	       sizeof(count) + count;
670 }
671 
672 LIBPLDM_ABI_STABLE
673 uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
674 	const struct pldm_bios_attr_val_table_entry *entry)
675 {
676 	return entry->value[0];
677 }
678 
679 LIBPLDM_ABI_STABLE
680 uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
681 	const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
682 	uint8_t number)
683 {
684 	uint8_t curr_num =
685 		pldm_bios_table_attr_value_entry_enum_decode_number(entry);
686 	curr_num = number < curr_num ? number : curr_num;
687 	memcpy(handles, &entry->value[1], curr_num);
688 
689 	return curr_num;
690 }
691 
692 LIBPLDM_ABI_STABLE
693 int pldm_bios_table_attr_value_entry_encode_enum(
694 	void *entry, size_t entry_length, uint16_t attr_handle,
695 	uint8_t attr_type, uint8_t count, const uint8_t *handles)
696 {
697 	struct pldm_bios_attr_val_table_entry *table_entry;
698 
699 	POINTER_CHECK(entry);
700 	POINTER_CHECK(handles);
701 	if (count != 0 && handles == NULL) {
702 		return PLDM_ERROR_INVALID_DATA;
703 	}
704 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
705 	BUFFER_SIZE_EXPECT(entry_length, sizeof(*table_entry));
706 	table_entry = entry;
707 	table_entry->attr_handle = htole16(attr_handle);
708 	table_entry->attr_type = attr_type;
709 	table_entry->value[0] = count;
710 	if (entry_length - sizeof(*table_entry) < count) {
711 		return PLDM_ERROR_INVALID_LENGTH;
712 	}
713 	memcpy(&table_entry->value[1], handles, count);
714 	return PLDM_SUCCESS;
715 }
716 
717 static ssize_t attr_value_table_entry_length_enum(const void *entry)
718 {
719 	uint8_t number =
720 		pldm_bios_table_attr_value_entry_enum_decode_number(entry);
721 	size_t len =
722 		pldm_bios_table_attr_value_entry_encode_enum_length(number);
723 	if (len > SSIZE_MAX) {
724 		return -1;
725 	}
726 	return (ssize_t)len;
727 }
728 
729 LIBPLDM_ABI_STABLE
730 size_t
731 pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
732 {
733 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
734 	       sizeof(string_length) + string_length;
735 }
736 
737 LIBPLDM_ABI_STABLE
738 uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
739 	const struct pldm_bios_attr_val_table_entry *entry)
740 {
741 	uint16_t str_length = 0;
742 	memcpy(&str_length, entry->value, sizeof(str_length));
743 	return le16toh(str_length);
744 }
745 
746 LIBPLDM_ABI_STABLE
747 void pldm_bios_table_attr_value_entry_string_decode_string(
748 	const struct pldm_bios_attr_val_table_entry *entry,
749 	struct variable_field *current_string)
750 {
751 	current_string->length =
752 		pldm_bios_table_attr_value_entry_string_decode_length(entry);
753 	current_string->ptr =
754 		entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
755 }
756 
757 LIBPLDM_ABI_STABLE
758 int pldm_bios_table_attr_value_entry_encode_string(
759 	void *entry, size_t entry_length, uint16_t attr_handle,
760 	uint8_t attr_type, uint16_t str_length, const char *str)
761 {
762 	struct pldm_bios_attr_val_table_entry *table_entry;
763 
764 	POINTER_CHECK(entry);
765 	if (str_length != 0 && str == NULL) {
766 		return PLDM_ERROR_INVALID_DATA;
767 	}
768 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
769 	BUFFER_SIZE_EXPECT(entry_length,
770 			   (sizeof(*table_entry) - 1 + sizeof(str_length)));
771 	table_entry = entry;
772 	table_entry->attr_handle = htole16(attr_handle);
773 	table_entry->attr_type = attr_type;
774 	if (entry_length - (sizeof(*table_entry) - 1 + sizeof(str_length)) <
775 	    str_length) {
776 		return PLDM_ERROR_INVALID_LENGTH;
777 	}
778 	memcpy(table_entry->value + sizeof(str_length), str, str_length);
779 	str_length = htole16(str_length);
780 	memcpy(table_entry->value, &str_length, sizeof(str_length));
781 	return PLDM_SUCCESS;
782 }
783 
784 static ssize_t attr_value_table_entry_length_string(const void *entry)
785 {
786 	uint16_t str_length =
787 		pldm_bios_table_attr_value_entry_string_decode_length(entry);
788 	size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
789 		str_length);
790 	if (len > SSIZE_MAX) {
791 		return -1;
792 	}
793 	return (ssize_t)len;
794 }
795 
796 LIBPLDM_ABI_STABLE
797 size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
798 {
799 	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
800 	       sizeof(uint64_t);
801 }
802 
803 LIBPLDM_ABI_STABLE
804 int pldm_bios_table_attr_value_entry_encode_integer(void *entry,
805 						    size_t entry_length,
806 						    uint16_t attr_handle,
807 						    uint8_t attr_type,
808 						    uint64_t cv)
809 {
810 	POINTER_CHECK(entry);
811 	size_t length =
812 		pldm_bios_table_attr_value_entry_encode_integer_length();
813 	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
814 	BUFFER_SIZE_EXPECT(entry_length, length);
815 	struct pldm_bios_attr_val_table_entry *table_entry = entry;
816 	table_entry->attr_handle = htole16(attr_handle);
817 	table_entry->attr_type = attr_type;
818 	cv = htole64(cv);
819 	memcpy(table_entry->value, &cv, sizeof(uint64_t));
820 	return PLDM_SUCCESS;
821 }
822 
823 LIBPLDM_ABI_STABLE
824 uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
825 	const struct pldm_bios_attr_val_table_entry *entry)
826 {
827 	uint64_t cv = 0;
828 	memcpy(&cv, entry->value, sizeof(cv));
829 	cv = le64toh(cv);
830 	return cv;
831 }
832 
833 static ssize_t attr_value_table_entry_length_integer(const void *entry)
834 {
835 	(void)entry;
836 	size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
837 	if (len > SSIZE_MAX) {
838 		return -1;
839 	}
840 	return (ssize_t)len;
841 }
842 
843 static const struct table_entry_length attr_value_table_entries[] = {
844 	{ .attr_type = PLDM_BIOS_ENUMERATION,
845 	  .entry_length_handler = attr_value_table_entry_length_enum },
846 	{ .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
847 	  .entry_length_handler = attr_value_table_entry_length_enum },
848 	{ .attr_type = PLDM_BIOS_STRING,
849 	  .entry_length_handler = attr_value_table_entry_length_string },
850 	{ .attr_type = PLDM_BIOS_STRING_READ_ONLY,
851 	  .entry_length_handler = attr_value_table_entry_length_string },
852 	{ .attr_type = PLDM_BIOS_INTEGER,
853 	  .entry_length_handler = attr_value_table_entry_length_integer },
854 	{ .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
855 	  .entry_length_handler = attr_value_table_entry_length_integer },
856 };
857 
858 static ssize_t attr_value_table_entry_length(const void *table_entry)
859 {
860 	const struct pldm_bios_attr_val_table_entry *entry = table_entry;
861 	const struct table_entry_length *entry_length =
862 		find_table_entry_length_by_type(
863 			entry->attr_type, attr_value_table_entries,
864 			ARRAY_SIZE(attr_value_table_entries));
865 	assert(entry_length != NULL);
866 	if (!entry_length) {
867 		return -1;
868 	}
869 	assert(entry_length->entry_length_handler != NULL);
870 	if (!entry_length->entry_length_handler) {
871 		return -1;
872 	}
873 
874 	return entry_length->entry_length_handler(entry);
875 }
876 
877 LIBPLDM_ABI_STABLE
878 size_t pldm_bios_table_attr_value_entry_length(
879 	const struct pldm_bios_attr_val_table_entry *entry)
880 {
881 	return attr_value_table_entry_length(entry);
882 }
883 
884 LIBPLDM_ABI_STABLE
885 uint16_t pldm_bios_table_attr_value_entry_decode_handle(
886 	const struct pldm_bios_attr_val_table_entry *entry)
887 {
888 	return le16toh(entry->attr_handle);
889 }
890 
891 static size_t pad_size_get(size_t size_without_pad)
892 {
893 	return (4 - (size_without_pad % 4)) % 4;
894 }
895 
896 static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
897 {
898 	while (pad_size--) {
899 		*table_end++ = 0;
900 	}
901 
902 	return table_end;
903 }
904 
905 static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
906 {
907 	checksum = htole32(checksum);
908 	memcpy(table_end, &checksum, sizeof(checksum));
909 
910 	return table_end + sizeof(checksum);
911 }
912 
913 LIBPLDM_ABI_STABLE
914 size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
915 {
916 	return pad_size_get(size_without_pad) + sizeof(uint32_t);
917 }
918 
919 LIBPLDM_ABI_STABLE
920 int pldm_bios_table_append_pad_checksum(void *table, size_t capacity,
921 					size_t *size)
922 {
923 	if (!table || !size) {
924 		return PLDM_ERROR_INVALID_DATA;
925 	}
926 
927 	size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
928 
929 	if (SIZE_MAX - pad_checksum_size < *size) {
930 		return PLDM_ERROR_INVALID_LENGTH;
931 	}
932 
933 	size_t total_length = *size + pad_checksum_size;
934 	if (capacity < total_length) {
935 		return PLDM_ERROR_INVALID_LENGTH;
936 	}
937 
938 	if (UINTPTR_MAX - *size < (uintptr_t)table) {
939 		return PLDM_ERROR_INVALID_LENGTH;
940 	}
941 	uint8_t *table_end = (uint8_t *)table + *size;
942 	size_t pad_size = pad_size_get(*size);
943 	table_end = pad_append(table_end, pad_size);
944 
945 	uint32_t checksum = crc32(table, *size + pad_size);
946 	checksum_append(table_end, checksum);
947 	*size = total_length;
948 
949 	return PLDM_SUCCESS;
950 }
951 
952 struct pldm_bios_table_iter {
953 	const uint8_t *table_data;
954 	size_t table_len;
955 	size_t current_pos;
956 	ssize_t (*entry_length_handler)(const void *table_entry);
957 };
958 
959 LIBPLDM_ABI_STABLE
960 struct pldm_bios_table_iter *
961 pldm_bios_table_iter_create(const void *table, size_t length,
962 			    enum pldm_bios_table_types type)
963 {
964 	struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
965 	assert(iter != NULL);
966 	if (!iter) {
967 		return NULL;
968 	}
969 	iter->table_data = table;
970 	iter->table_len = length;
971 	iter->current_pos = 0;
972 	iter->entry_length_handler = NULL;
973 	switch (type) {
974 	case PLDM_BIOS_STRING_TABLE:
975 		iter->entry_length_handler = string_table_entry_length;
976 		break;
977 	case PLDM_BIOS_ATTR_TABLE:
978 		iter->entry_length_handler = attr_table_entry_length;
979 		break;
980 	case PLDM_BIOS_ATTR_VAL_TABLE:
981 		iter->entry_length_handler = attr_value_table_entry_length;
982 		break;
983 	}
984 
985 	return iter;
986 }
987 
988 LIBPLDM_ABI_STABLE
989 void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
990 {
991 	free(iter);
992 }
993 
994 #define pad_and_check_max 7
995 LIBPLDM_ABI_STABLE
996 bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
997 {
998 	ssize_t len;
999 
1000 	if (!iter) {
1001 		return true;
1002 	}
1003 
1004 	if (iter->table_len - iter->current_pos <= pad_and_check_max) {
1005 		return true;
1006 	}
1007 
1008 	len = iter->entry_length_handler(iter->table_data + iter->current_pos);
1009 
1010 	return len < 0;
1011 }
1012 
1013 LIBPLDM_ABI_STABLE
1014 void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
1015 {
1016 	if (pldm_bios_table_iter_is_end(iter)) {
1017 		return;
1018 	}
1019 	const void *entry = iter->table_data + iter->current_pos;
1020 	ssize_t rc = iter->entry_length_handler(entry);
1021 	/* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1022 	if (rc < 0) {
1023 		return;
1024 	}
1025 	iter->current_pos += rc;
1026 }
1027 
1028 LIBPLDM_ABI_STABLE
1029 const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1030 {
1031 	return iter->table_data + iter->current_pos;
1032 }
1033 
1034 typedef bool (*equal_handler)(const void *entry, const void *key);
1035 
1036 static const void *
1037 pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1038 				   const void *key, equal_handler equal)
1039 {
1040 	const void *entry;
1041 	while (!pldm_bios_table_iter_is_end(iter)) {
1042 		entry = pldm_bios_table_iter_value(iter);
1043 		if (equal(entry, key)) {
1044 			return entry;
1045 		}
1046 		pldm_bios_table_iter_next(iter);
1047 	}
1048 	return NULL;
1049 }
1050 
1051 static const void *
1052 pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1053 				      enum pldm_bios_table_types type,
1054 				      equal_handler equal, const void *key)
1055 {
1056 	struct pldm_bios_table_iter *iter =
1057 		pldm_bios_table_iter_create(table, length, type);
1058 	const void *entry =
1059 		pldm_bios_table_entry_find_by_iter(iter, key, equal);
1060 	pldm_bios_table_iter_free(iter);
1061 	return entry;
1062 }
1063 
1064 static bool string_table_handle_equal(const void *entry, const void *key)
1065 {
1066 	const struct pldm_bios_string_table_entry *string_entry = entry;
1067 	uint16_t handle = *(uint16_t *)key;
1068 	if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1069 	    handle) {
1070 		return true;
1071 	}
1072 	return false;
1073 }
1074 
1075 LIBPLDM_ABI_STABLE
1076 const struct pldm_bios_string_table_entry *
1077 pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1078 				      uint16_t handle)
1079 {
1080 	return pldm_bios_table_entry_find_from_table(table, length,
1081 						     PLDM_BIOS_STRING_TABLE,
1082 						     string_table_handle_equal,
1083 						     &handle);
1084 }
1085 
1086 struct string_equal_arg {
1087 	uint16_t str_length;
1088 	const char *str;
1089 };
1090 
1091 static bool string_table_string_equal(const void *entry, const void *key)
1092 {
1093 	const struct pldm_bios_string_table_entry *string_entry = entry;
1094 	const struct string_equal_arg *arg = key;
1095 	if (arg->str_length !=
1096 	    pldm_bios_table_string_entry_decode_string_length(string_entry)) {
1097 		return false;
1098 	}
1099 	if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
1100 		return false;
1101 	}
1102 	return true;
1103 }
1104 
1105 LIBPLDM_ABI_STABLE
1106 const struct pldm_bios_string_table_entry *
1107 pldm_bios_table_string_find_by_string(const void *table, size_t length,
1108 				      const char *str)
1109 {
1110 	uint16_t str_length = strlen(str);
1111 	struct string_equal_arg arg = { str_length, str };
1112 	return pldm_bios_table_entry_find_from_table(table, length,
1113 						     PLDM_BIOS_STRING_TABLE,
1114 						     string_table_string_equal,
1115 						     &arg);
1116 }
1117 
1118 static bool attr_table_handle_equal(const void *entry, const void *key)
1119 {
1120 	uint16_t handle = *(uint16_t *)key;
1121 	return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1122 	       handle;
1123 }
1124 
1125 LIBPLDM_ABI_STABLE
1126 const struct pldm_bios_attr_table_entry *
1127 pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1128 				    uint16_t handle)
1129 {
1130 	return pldm_bios_table_entry_find_from_table(table, length,
1131 						     PLDM_BIOS_ATTR_TABLE,
1132 						     attr_table_handle_equal,
1133 						     &handle);
1134 }
1135 
1136 static bool attr_table_string_handle_equal(const void *entry, const void *key)
1137 {
1138 	uint16_t handle = *(uint16_t *)key;
1139 	return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1140 }
1141 
1142 LIBPLDM_ABI_STABLE
1143 const struct pldm_bios_attr_table_entry *
1144 pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1145 					   uint16_t handle)
1146 {
1147 	return pldm_bios_table_entry_find_from_table(
1148 		table, length, PLDM_BIOS_ATTR_TABLE,
1149 		attr_table_string_handle_equal, &handle);
1150 }
1151 
1152 static bool attr_value_table_handle_equal(const void *entry, const void *key)
1153 {
1154 	uint16_t handle = *(uint16_t *)key;
1155 	return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1156 }
1157 
1158 LIBPLDM_ABI_STABLE
1159 const struct pldm_bios_attr_val_table_entry *
1160 pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1161 					  uint16_t handle)
1162 {
1163 	return pldm_bios_table_entry_find_from_table(
1164 		table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1165 		attr_value_table_handle_equal, &handle);
1166 }
1167 
1168 LIBPLDM_ABI_STABLE
1169 int pldm_bios_table_attr_value_copy_and_update(
1170 	const void *src_table, size_t src_length, void *dest_table,
1171 	size_t *dest_length, const void *entry, size_t entry_length)
1172 {
1173 	struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
1174 		src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
1175 
1176 	int rc = PLDM_SUCCESS;
1177 	const struct pldm_bios_attr_val_table_entry *tmp;
1178 	const struct pldm_bios_attr_val_table_entry *to_update = entry;
1179 	size_t buffer_length = *dest_length;
1180 	size_t copied_length = 0;
1181 	size_t length = 0;
1182 	while (!pldm_bios_table_iter_is_end(iter)) {
1183 		tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1184 		length = attr_value_table_entry_length(tmp);
1185 
1186 		/* we need the tmp's entry_length here, iter_next will calculate
1187 		 * it too, use current_pos directly to avoid calculating it
1188 		 * twice */
1189 		iter->current_pos += length;
1190 		if (tmp->attr_handle == to_update->attr_handle) {
1191 			if (tmp->attr_type != to_update->attr_type) {
1192 				rc = PLDM_ERROR_INVALID_DATA;
1193 				goto out;
1194 			}
1195 			length = entry_length;
1196 			tmp = entry;
1197 		}
1198 		if (copied_length + length > buffer_length) {
1199 			rc = PLDM_ERROR_INVALID_LENGTH;
1200 			goto out;
1201 		}
1202 		memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1203 		copied_length += length;
1204 	}
1205 
1206 	size_t pad_checksum_size =
1207 		pldm_bios_table_pad_checksum_size(copied_length);
1208 	if ((pad_checksum_size + copied_length) > buffer_length) {
1209 		rc = PLDM_ERROR_INVALID_LENGTH;
1210 		goto out;
1211 	}
1212 
1213 	rc = pldm_bios_table_append_pad_checksum(dest_table, buffer_length,
1214 						 &copied_length);
1215 	if (rc == PLDM_SUCCESS) {
1216 		*dest_length = copied_length;
1217 	}
1218 out:
1219 	pldm_bios_table_iter_free(iter);
1220 	return rc;
1221 }
1222 
1223 LIBPLDM_ABI_STABLE
1224 bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1225 {
1226 	if (table == NULL) {
1227 		return false;
1228 	}
1229 
1230 	// 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1231 	//     Variable(4) + checksum(uint32)
1232 	if (size < 12) {
1233 		return false;
1234 	}
1235 
1236 	uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1237 	uint32_t dst_crc = crc32(table, size - 4);
1238 
1239 	return src_crc == dst_crc;
1240 }
1241