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