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