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