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