blob: 2512f5e90fed303f140333eb12e1e910caf866a1 [file] [log] [blame]
John Wang02700402019-10-06 16:34:29 +08001#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
John Wang3ad21752019-10-06 16:42:21 +080023#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
John Wangdd9a6282019-10-11 18:52:46 +080029#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
30
John Wang827c5de2019-11-07 18:27:27 +080031static void set_errmsg(const char **errmsg, const char *msg)
32{
33 if (errmsg != NULL)
34 *errmsg = msg;
35}
36
John Wangdd9a6282019-10-11 18:52:46 +080037static 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 ? length : size;
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
John Wangccc04552019-10-14 14:28:25 +0800119static 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
138size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
139 uint8_t def_num)
140{
141 return sizeof(struct pldm_bios_attr_table_entry) -
142 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
143 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
144 def_num;
145}
146
147void pldm_bios_table_attr_entry_enum_encode(
148 void *entry, size_t entry_length,
149 const struct pldm_bios_table_attr_entry_enum_info *info)
150{
151 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
152 info->pv_num, info->def_num);
153 assert(length <= entry_length);
154 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY
155 : PLDM_BIOS_ENUMERATION;
156 attr_table_entry_encode_header(entry, entry_length, attr_type,
157 info->name_handle);
158 struct pldm_bios_attr_table_entry *attr_entry = entry;
159 attr_entry->metadata[0] = info->pv_num;
160 uint16_t *pv_hdls =
161 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
162 size_t i;
163 for (i = 0; i < info->pv_num; i++)
164 pv_hdls[i] = htole16(info->pv_handle[i]);
165 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
166 info->def_num;
167 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
168 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
169 info->def_index, info->def_num);
170}
171
172int pldm_bios_table_attr_entry_enum_encode_check(
173 void *entry, size_t entry_length,
174 const struct pldm_bios_table_attr_entry_enum_info *info)
175{
176 POINTER_CHECK(entry);
177 POINTER_CHECK(info);
178 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
179 info->pv_num, info->def_num);
180 BUFFER_SIZE_EXPECT(entry_length, length);
181 pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
182 return PLDM_SUCCESS;
183}
184
John Wangdd9a6282019-10-11 18:52:46 +0800185#define ATTR_TYPE_EXPECT(type, expected) \
186 do { \
187 if (type != expected && type != (expected | 0x80)) \
188 return PLDM_ERROR_INVALID_DATA; \
189 } while (0)
190
John Wang02700402019-10-06 16:34:29 +0800191uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
192 const struct pldm_bios_attr_table_entry *entry)
193{
194 return entry->metadata[0];
195}
196
197int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
198 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
199{
200 POINTER_CHECK(entry);
201 POINTER_CHECK(pv_num);
202 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
203 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
204 return PLDM_SUCCESS;
205}
206
207uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
208 const struct pldm_bios_attr_table_entry *entry)
209{
210 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
211 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
212 sizeof(uint16_t) * pv_num];
213}
214
215int pldm_bios_table_attr_entry_enum_decode_def_num_check(
216 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
217{
218 POINTER_CHECK(entry);
219 POINTER_CHECK(def_num);
220 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
221 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
222 return PLDM_SUCCESS;
223}
224
John Wang3ad21752019-10-06 16:42:21 +0800225uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
226 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
227 uint8_t pv_num)
228{
229 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
230 num = num < pv_num ? num : pv_num;
231 size_t i;
232 for (i = 0; i < num; i++) {
233 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
234 i * sizeof(uint16_t));
235 pv_hdls[i] = le16toh(*hdl);
236 }
237 return num;
238}
239
240int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
241 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
242 uint8_t pv_num)
243{
244 POINTER_CHECK(entry);
245 POINTER_CHECK(pv_hdls);
246 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
247 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
248 if (num != pv_num)
249 return PLDM_ERROR_INVALID_DATA;
250 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
251 return PLDM_SUCCESS;
252}
253
John Wang02700402019-10-06 16:34:29 +0800254/** @brief Get length of an enum attribute entry
255 */
256static size_t
257attr_table_entry_length_enum(const struct pldm_bios_attr_table_entry *entry)
258{
259 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
260 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
John Wangccc04552019-10-14 14:28:25 +0800261 return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
John Wang02700402019-10-06 16:34:29 +0800262}
263
John Wangccc04552019-10-14 14:28:25 +0800264struct attr_table_string_entry_fields {
265 uint8_t string_type;
266 uint16_t min_length;
267 uint16_t max_length;
268 uint16_t def_length;
269 uint8_t def_string[1];
270} __attribute__((packed));
271
272size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
273{
274 return sizeof(struct pldm_bios_attr_table_entry) -
275 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
276 sizeof(struct attr_table_string_entry_fields) -
277 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
278 def_str_len;
279}
280
281void pldm_bios_table_attr_entry_string_encode(
282 void *entry, size_t entry_length,
283 const struct pldm_bios_table_attr_entry_string_info *info)
284{
285 size_t length =
286 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
287 assert(length <= entry_length);
288 uint8_t attr_type =
289 info->read_only ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
290 attr_table_entry_encode_header(entry, entry_length, attr_type,
291 info->name_handle);
292 struct pldm_bios_attr_table_entry *attr_entry = entry;
293 struct attr_table_string_entry_fields *attr_fields =
294 (struct attr_table_string_entry_fields *)attr_entry->metadata;
295 attr_fields->string_type = info->string_type;
296 attr_fields->min_length = htole16(info->min_length);
297 attr_fields->max_length = htole16(info->max_length);
298 attr_fields->def_length = htole16(info->def_length);
299 if (info->def_length != 0 && info->def_string != NULL)
300 memcpy(attr_fields->def_string, info->def_string,
301 info->def_length);
302}
303
John Wang827c5de2019-11-07 18:27:27 +0800304#define PLDM_STRING_TYPE_MAX 5
305#define PLDM_STRING_TYPE_VENDOR 0xff
306
307int pldm_bios_table_attr_entry_string_info_check(
308 const struct pldm_bios_table_attr_entry_string_info *info,
309 const char **errmsg)
310{
311 if (info->min_length > info->max_length) {
312 set_errmsg(errmsg, "MinimumStingLength should not be greater "
313 "than MaximumStringLength");
314 return PLDM_ERROR_INVALID_DATA;
315 }
316 if (info->min_length == info->max_length &&
317 info->def_length != info->min_length) {
318 set_errmsg(errmsg, "Wrong DefaultStringLength");
319 return PLDM_ERROR_INVALID_DATA;
320 }
321 if (info->def_length > info->max_length ||
322 info->def_length < info->min_length) {
323 set_errmsg(errmsg, "Wrong DefaultStringLength");
324 return PLDM_ERROR_INVALID_DATA;
325 }
326 if (info->string_type > PLDM_STRING_TYPE_MAX &&
327 info->string_type != PLDM_STRING_TYPE_VENDOR) {
328 set_errmsg(errmsg, "Wrong StringType");
329 return PLDM_ERROR_INVALID_DATA;
330 }
331 if (info->def_length != strlen(info->def_string)) {
332 set_errmsg(errmsg, "Length of DefaultString should be equal to "
333 "DefaultStringLength");
334 return PLDM_ERROR_INVALID_DATA;
335 }
336
337 return PLDM_SUCCESS;
338}
339
John Wangccc04552019-10-14 14:28:25 +0800340int pldm_bios_table_attr_entry_string_encode_check(
341 void *entry, size_t entry_length,
342 const struct pldm_bios_table_attr_entry_string_info *info)
343{
344 POINTER_CHECK(entry);
345 POINTER_CHECK(info);
346 size_t length =
347 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
348 BUFFER_SIZE_EXPECT(entry_length, length);
John Wang827c5de2019-11-07 18:27:27 +0800349 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
350 PLDM_SUCCESS)
John Wangccc04552019-10-14 14:28:25 +0800351 return PLDM_ERROR_INVALID_DATA;
352 pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
353 return PLDM_SUCCESS;
354}
John Wang02700402019-10-06 16:34:29 +0800355
356uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
357 const struct pldm_bios_attr_table_entry *entry)
358{
John Wangccc04552019-10-14 14:28:25 +0800359 struct attr_table_string_entry_fields *fields =
360 (struct attr_table_string_entry_fields *)entry->metadata;
361 return le16toh(fields->def_length);
John Wang02700402019-10-06 16:34:29 +0800362}
363
364int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
365 const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
366{
367 POINTER_CHECK(entry);
368 POINTER_CHECK(def_string_length);
369 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
370 *def_string_length =
371 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
372 return PLDM_SUCCESS;
373}
374
375/** @brief Get length of a string attribute entry
376 */
377static size_t
378attr_table_entry_length_string(const struct pldm_bios_attr_table_entry *entry)
379{
John Wangccc04552019-10-14 14:28:25 +0800380 uint16_t def_str_len =
John Wang02700402019-10-06 16:34:29 +0800381 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
John Wangccc04552019-10-14 14:28:25 +0800382 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
John Wang02700402019-10-06 16:34:29 +0800383}
384
John Wangca230822019-10-16 11:39:27 +0800385struct attr_table_integer_entry_fields {
386 uint64_t lower_bound;
387 uint64_t upper_bound;
388 uint32_t scalar_increment;
389 uint64_t default_value;
390} __attribute__((packed));
391
392size_t pldm_bios_table_attr_entry_integer_encode_length()
393{
394 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
395 sizeof(struct attr_table_integer_entry_fields);
396}
397
398void pldm_bios_table_attr_entry_integer_encode(
399 void *entry, size_t entry_length,
400 const struct pldm_bios_table_attr_entry_integer_info *info)
401{
402 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
403 assert(length <= entry_length);
404 uint8_t attr_type =
405 info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY : PLDM_BIOS_INTEGER;
406 attr_table_entry_encode_header(entry, entry_length, attr_type,
407 info->name_handle);
408 struct pldm_bios_attr_table_entry *attr_entry = entry;
409 struct attr_table_integer_entry_fields *attr_fields =
410 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
411 attr_fields->lower_bound = htole64(info->lower_bound);
412 attr_fields->upper_bound = htole64(info->upper_bound);
413 attr_fields->scalar_increment = htole32(info->scalar_increment);
414 attr_fields->default_value = htole64(info->default_value);
415}
416
John Wang827c5de2019-11-07 18:27:27 +0800417int pldm_bios_table_attr_entry_integer_info_check(
418 const struct pldm_bios_table_attr_entry_integer_info *info,
419 const char **errmsg)
420{
421 if (info->lower_bound == info->upper_bound) {
422 if (info->default_value != info->lower_bound) {
423 set_errmsg(errmsg, "Wrong DefaultValue");
424 return PLDM_ERROR_INVALID_DATA;
425 }
426 if (info->scalar_increment != 0) {
427 set_errmsg(errmsg, "Wrong ScalarIncrement");
428 return PLDM_ERROR_INVALID_DATA;
429 }
430 return PLDM_SUCCESS;
431 }
432 if (info->lower_bound > info->upper_bound) {
433 set_errmsg(errmsg,
434 "LowerBound should not be greater than UpperBound");
435 return PLDM_ERROR_INVALID_DATA;
436 }
437 if (info->default_value > info->upper_bound ||
438 info->default_value < info->lower_bound) {
439 set_errmsg(errmsg, "Wrong DefaultValue");
440 return PLDM_ERROR_INVALID_DATA;
441 }
442 if (info->scalar_increment == 0) {
443 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
444 "lower_bound != upper_bound");
445 return PLDM_ERROR_INVALID_DATA;
446 }
447 if ((info->default_value - info->lower_bound) %
448 info->scalar_increment !=
449 0) {
450 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
451 return PLDM_ERROR_INVALID_DATA;
452 }
453 return PLDM_SUCCESS;
454}
455
John Wangca230822019-10-16 11:39:27 +0800456int pldm_bios_table_attr_entry_integer_encode_check(
457 void *entry, size_t entry_length,
458 const struct pldm_bios_table_attr_entry_integer_info *info)
459{
460 POINTER_CHECK(entry);
461 POINTER_CHECK(info);
462 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
463 BUFFER_SIZE_EXPECT(entry_length, length);
John Wang827c5de2019-11-07 18:27:27 +0800464 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
465 PLDM_SUCCESS)
John Wangca230822019-10-16 11:39:27 +0800466 return PLDM_ERROR_INVALID_DATA;
467 pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
468 return PLDM_SUCCESS;
469}
470
471static size_t
472attr_table_entry_length_integer(const struct pldm_bios_attr_table_entry *entry)
473{
474 (void)entry;
475 return pldm_bios_table_attr_entry_integer_encode_length();
476}
477
John Wang02700402019-10-06 16:34:29 +0800478struct attr_table_entry {
479 uint8_t attr_type;
480 size_t (*entry_length_handler)(
481 const struct pldm_bios_attr_table_entry *);
482};
483
484static struct attr_table_entry attr_table_entrys[] = {
485 {.attr_type = PLDM_BIOS_ENUMERATION,
486 .entry_length_handler = attr_table_entry_length_enum},
487 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
488 .entry_length_handler = attr_table_entry_length_enum},
489 {.attr_type = PLDM_BIOS_STRING,
490 .entry_length_handler = attr_table_entry_length_string},
491 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
492 .entry_length_handler = attr_table_entry_length_string},
John Wangca230822019-10-16 11:39:27 +0800493 {.attr_type = PLDM_BIOS_INTEGER,
494 .entry_length_handler = attr_table_entry_length_integer},
495 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
496 .entry_length_handler = attr_table_entry_length_integer},
John Wang02700402019-10-06 16:34:29 +0800497};
498
499#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
500
501static struct attr_table_entry *find_attr_table_entry_by_type(uint8_t attr_type)
502{
503 size_t i;
504 for (i = 0; i < ARRAY_SIZE(attr_table_entrys); i++) {
505 if (attr_type == attr_table_entrys[i].attr_type)
506 return &attr_table_entrys[i];
507 }
508 return NULL;
509}
510
511static size_t attr_table_entry_length(const void *table_entry)
512{
513 const struct pldm_bios_attr_table_entry *entry = table_entry;
514 struct attr_table_entry *attr_table_entry =
515 find_attr_table_entry_by_type(entry->attr_type);
516 assert(attr_table_entry != NULL);
517 assert(attr_table_entry->entry_length_handler != NULL);
518
519 return attr_table_entry->entry_length_handler(entry);
520}
521
John Wang3ad21752019-10-06 16:42:21 +0800522size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
523{
524 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
525 sizeof(count) + count;
526}
527
528void pldm_bios_table_attr_value_entry_encode_enum(
529 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
530 uint8_t count, uint8_t *handles)
531{
532 size_t length =
533 pldm_bios_table_attr_value_entry_encode_enum_length(count);
534 assert(length <= entry_length);
535
536 struct pldm_bios_attr_val_table_entry *table_entry = entry;
537 table_entry->attr_handle = htole16(attr_handle);
538 table_entry->attr_type = attr_type;
539 table_entry->value[0] = count;
540 if (count != 0)
541 memcpy(&table_entry->value[1], handles, count);
542}
543
544int pldm_bios_table_attr_value_entry_encode_enum_check(
545 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
546 uint8_t count, uint8_t *handles)
547{
548 POINTER_CHECK(entry);
549 if (count != 0 && handles == NULL)
550 return PLDM_ERROR_INVALID_DATA;
551 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
552 size_t length =
553 pldm_bios_table_attr_value_entry_encode_enum_length(count);
554 BUFFER_SIZE_EXPECT(entry_length, length);
555 pldm_bios_table_attr_value_entry_encode_enum(
556 entry, entry_length, attr_handle, attr_type, count, handles);
557 return PLDM_SUCCESS;
558}
559
560size_t
561pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
562{
563 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
564 sizeof(string_length) + string_length;
565}
566
567void pldm_bios_table_attr_value_entry_encode_string(
568 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
569 uint16_t str_length, const char *str)
570{
571 size_t length =
572 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
573 assert(length <= entry_length);
574
575 struct pldm_bios_attr_val_table_entry *table_entry = entry;
576 table_entry->attr_handle = htole16(attr_handle);
577 table_entry->attr_type = attr_type;
578 if (str_length != 0)
579 memcpy(table_entry->value + sizeof(str_length), str,
580 str_length);
581 str_length = htole16(str_length);
582 memcpy(table_entry->value, &str_length, sizeof(str_length));
583}
584
585int pldm_bios_table_attr_value_entry_encode_string_check(
586 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
587 uint16_t str_length, const char *str)
588{
589 POINTER_CHECK(entry);
590 if (str_length != 0 && str == NULL)
591 return PLDM_ERROR_INVALID_DATA;
592 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
593 size_t length =
594 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
595 BUFFER_SIZE_EXPECT(entry_length, length);
596 pldm_bios_table_attr_value_entry_encode_string(
597 entry, entry_length, attr_handle, attr_type, str_length, str);
598 return PLDM_SUCCESS;
599}
600
John Wangca230822019-10-16 11:39:27 +0800601size_t pldm_bios_table_attr_value_entry_encode_integer_length()
602{
603 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
604 sizeof(uint64_t);
605}
606void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
607 size_t entry_length,
608 uint16_t attr_handle,
609 uint8_t attr_type,
610 uint64_t cv)
611{
612 size_t length =
613 pldm_bios_table_attr_value_entry_encode_integer_length();
614 assert(length <= entry_length);
615
616 struct pldm_bios_attr_val_table_entry *table_entry = entry;
617 table_entry->attr_handle = htole16(attr_handle);
618 table_entry->attr_type = attr_type;
619 cv = htole64(cv);
620 memcpy(table_entry->value, &cv, sizeof(uint64_t));
621}
622
623int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
624 size_t entry_length,
625 uint16_t attr_handle,
626 uint8_t attr_type,
627 uint64_t cv)
628{
629 POINTER_CHECK(entry);
630 size_t length =
631 pldm_bios_table_attr_value_entry_encode_integer_length();
632 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
633 BUFFER_SIZE_EXPECT(entry_length, length);
634 pldm_bios_table_attr_value_entry_encode_integer(
635 entry, entry_length, attr_handle, attr_type, cv);
636 return PLDM_SUCCESS;
637}
638
John Wang02700402019-10-06 16:34:29 +0800639struct pldm_bios_table_iter {
640 const uint8_t *table_data;
641 size_t table_len;
642 size_t current_pos;
643 size_t (*entry_length_handler)(const void *table_entry);
644};
645
646struct pldm_bios_table_iter *
647pldm_bios_table_iter_create(const void *table, size_t length,
648 enum pldm_bios_table_types type)
649{
650 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
651 assert(iter != NULL);
652 iter->table_data = table;
653 iter->table_len = length;
654 iter->current_pos = 0;
655 iter->entry_length_handler = NULL;
656 switch (type) {
657 case PLDM_BIOS_STRING_TABLE:
John Wangdd9a6282019-10-11 18:52:46 +0800658 iter->entry_length_handler = string_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800659 break;
660 case PLDM_BIOS_ATTR_TABLE:
661 iter->entry_length_handler = attr_table_entry_length;
662 break;
663 case PLDM_BIOS_ATTR_VAL_TABLE:
664 break;
665 }
666
667 return iter;
668}
669
670void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
671{
672 free(iter);
673}
674
675#define pad_and_check_max 7
676bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
677{
678 if (iter->table_len - iter->current_pos <= pad_and_check_max)
679 return true;
680 return false;
681}
682
683void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
684{
685 if (pldm_bios_table_iter_is_end(iter))
686 return;
687 const void *entry = iter->table_data + iter->current_pos;
688 iter->current_pos += iter->entry_length_handler(entry);
689}
690
691const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
692{
693 return iter->table_data + iter->current_pos;
John Wang3ad21752019-10-06 16:42:21 +0800694}
John Wangdd9a6282019-10-11 18:52:46 +0800695
696static const void *
697pldm_bios_table_entry_find(struct pldm_bios_table_iter *iter, const void *key,
698 int (*equal)(const void *entry, const void *key))
699{
700 const void *entry;
701 while (!pldm_bios_table_iter_is_end(iter)) {
702 entry = pldm_bios_table_iter_value(iter);
703 if (equal(entry, key))
704 return entry;
705 pldm_bios_table_iter_next(iter);
706 }
707 return NULL;
708}
709
710static int string_table_handle_equal(const void *entry, const void *key)
711{
712 const struct pldm_bios_string_table_entry *string_entry = entry;
713 uint16_t handle = *(uint16_t *)key;
714 if (pldm_bios_table_string_entry_decode_handle(string_entry) == handle)
715 return true;
716 return false;
717}
718
719struct string_equal_arg {
720 uint16_t str_length;
721 const char *str;
722};
723
724static int string_table_string_equal(const void *entry, const void *key)
725{
726 const struct pldm_bios_string_table_entry *string_entry = entry;
727 const struct string_equal_arg *arg = key;
728 if (arg->str_length !=
729 pldm_bios_table_string_entry_decode_string_length(string_entry))
730 return false;
731 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0)
732 return false;
733 return true;
734}
735
736const struct pldm_bios_string_table_entry *
737pldm_bios_table_string_find_by_string(const void *table, size_t length,
738 const char *str)
739{
740 uint16_t str_length = strlen(str);
741 struct string_equal_arg arg = {str_length, str};
742 struct pldm_bios_table_iter *iter =
743 pldm_bios_table_iter_create(table, length, PLDM_BIOS_STRING_TABLE);
744 const void *entry =
745 pldm_bios_table_entry_find(iter, &arg, string_table_string_equal);
746 pldm_bios_table_iter_free(iter);
747 return entry;
748}
749
750const struct pldm_bios_string_table_entry *
751pldm_bios_table_string_find_by_handle(const void *table, size_t length,
752 uint16_t handle)
753{
754 struct pldm_bios_table_iter *iter =
755 pldm_bios_table_iter_create(table, length, PLDM_BIOS_STRING_TABLE);
756 const void *entry = pldm_bios_table_entry_find(
757 iter, &handle, string_table_handle_equal);
758 pldm_bios_table_iter_free(iter);
759 return entry;
760}