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