blob: 8782a1618d3a0221f5c8d1b4b1d3b5b23c09f8de [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
31static uint16_t get_bios_string_handle()
32{
33 static uint16_t handle = 0;
34 assert(handle != UINT16_MAX);
35
36 return handle++;
37}
38
39size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
40{
41 return sizeof(struct pldm_bios_string_table_entry) -
42 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
43}
44
45void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
46 const char *str, uint16_t str_length)
47{
48 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
49 assert(length <= entry_length);
50 struct pldm_bios_string_table_entry *string_entry = entry;
51 string_entry->string_handle = htole16(get_bios_string_handle());
52 string_entry->string_length = htole16(str_length);
53 memcpy(string_entry->name, str, str_length);
54}
55
56int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
57 const char *str,
58 uint16_t str_length)
59{
60 if (str_length == 0)
61 return PLDM_ERROR_INVALID_DATA;
62 POINTER_CHECK(entry);
63 POINTER_CHECK(str);
64 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
65 BUFFER_SIZE_EXPECT(entry_length, length);
66 pldm_bios_table_string_entry_encode(entry, entry_length, str,
67 str_length);
68 return PLDM_SUCCESS;
69}
70
71uint16_t pldm_bios_table_string_entry_decode_handle(
72 const struct pldm_bios_string_table_entry *entry)
73{
74 return le16toh(entry->string_handle);
75}
76
77uint16_t pldm_bios_table_string_entry_decode_string_length(
78 const struct pldm_bios_string_table_entry *entry)
79{
80 return le16toh(entry->string_length);
81}
82
83uint16_t pldm_bios_table_string_entry_decode_string(
84 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
85{
86 uint16_t length =
87 pldm_bios_table_string_entry_decode_string_length(entry);
88 length = length < size ? length : size;
89 memcpy(buffer, entry->name, length);
90 buffer[length] = 0;
91 return length;
92}
93
94int pldm_bios_table_string_entry_decode_string_check(
95 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
96{
97 POINTER_CHECK(entry);
98 POINTER_CHECK(buffer);
99 size_t length =
100 pldm_bios_table_string_entry_decode_string_length(entry);
101 BUFFER_SIZE_EXPECT(size, length + 1);
102 pldm_bios_table_string_entry_decode_string(entry, buffer, size);
103 return PLDM_SUCCESS;
104}
105
106static size_t string_table_entry_length(const void *table_entry)
107{
108 const struct pldm_bios_string_table_entry *entry = table_entry;
109 return sizeof(*entry) - sizeof(entry->name) +
110 pldm_bios_table_string_entry_decode_string_length(entry);
111}
112
John Wangccc04552019-10-14 14:28:25 +0800113static uint16_t get_bios_attr_handle()
114{
115 static uint16_t handle = 0;
116 assert(handle != UINT16_MAX);
117
118 return handle++;
119}
120
121static void attr_table_entry_encode_header(void *entry, size_t length,
122 uint8_t attr_type,
123 uint16_t string_handle)
124{
125 struct pldm_bios_attr_table_entry *attr_entry = entry;
126 assert(sizeof(*attr_entry) <= length);
127 attr_entry->attr_handle = htole16(get_bios_attr_handle());
128 attr_entry->attr_type = attr_type;
129 attr_entry->string_handle = htole16(string_handle);
130}
131
132size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
133 uint8_t def_num)
134{
135 return sizeof(struct pldm_bios_attr_table_entry) -
136 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
137 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
138 def_num;
139}
140
141void pldm_bios_table_attr_entry_enum_encode(
142 void *entry, size_t entry_length,
143 const struct pldm_bios_table_attr_entry_enum_info *info)
144{
145 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
146 info->pv_num, info->def_num);
147 assert(length <= entry_length);
148 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY
149 : PLDM_BIOS_ENUMERATION;
150 attr_table_entry_encode_header(entry, entry_length, attr_type,
151 info->name_handle);
152 struct pldm_bios_attr_table_entry *attr_entry = entry;
153 attr_entry->metadata[0] = info->pv_num;
154 uint16_t *pv_hdls =
155 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
156 size_t i;
157 for (i = 0; i < info->pv_num; i++)
158 pv_hdls[i] = htole16(info->pv_handle[i]);
159 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
160 info->def_num;
161 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
162 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
163 info->def_index, info->def_num);
164}
165
166int pldm_bios_table_attr_entry_enum_encode_check(
167 void *entry, size_t entry_length,
168 const struct pldm_bios_table_attr_entry_enum_info *info)
169{
170 POINTER_CHECK(entry);
171 POINTER_CHECK(info);
172 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
173 info->pv_num, info->def_num);
174 BUFFER_SIZE_EXPECT(entry_length, length);
175 pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
176 return PLDM_SUCCESS;
177}
178
John Wangdd9a6282019-10-11 18:52:46 +0800179#define ATTR_TYPE_EXPECT(type, expected) \
180 do { \
181 if (type != expected && type != (expected | 0x80)) \
182 return PLDM_ERROR_INVALID_DATA; \
183 } while (0)
184
John Wang02700402019-10-06 16:34:29 +0800185uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
186 const struct pldm_bios_attr_table_entry *entry)
187{
188 return entry->metadata[0];
189}
190
191int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
192 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
193{
194 POINTER_CHECK(entry);
195 POINTER_CHECK(pv_num);
196 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
197 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
198 return PLDM_SUCCESS;
199}
200
201uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
202 const struct pldm_bios_attr_table_entry *entry)
203{
204 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
205 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
206 sizeof(uint16_t) * pv_num];
207}
208
209int pldm_bios_table_attr_entry_enum_decode_def_num_check(
210 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
211{
212 POINTER_CHECK(entry);
213 POINTER_CHECK(def_num);
214 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
215 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
216 return PLDM_SUCCESS;
217}
218
John Wang3ad21752019-10-06 16:42:21 +0800219uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
220 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
221 uint8_t pv_num)
222{
223 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
224 num = num < pv_num ? num : pv_num;
225 size_t i;
226 for (i = 0; i < num; i++) {
227 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
228 i * sizeof(uint16_t));
229 pv_hdls[i] = le16toh(*hdl);
230 }
231 return num;
232}
233
234int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
235 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
236 uint8_t pv_num)
237{
238 POINTER_CHECK(entry);
239 POINTER_CHECK(pv_hdls);
240 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
241 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
242 if (num != pv_num)
243 return PLDM_ERROR_INVALID_DATA;
244 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
245 return PLDM_SUCCESS;
246}
247
John Wang02700402019-10-06 16:34:29 +0800248/** @brief Get length of an enum attribute entry
249 */
250static size_t
251attr_table_entry_length_enum(const struct pldm_bios_attr_table_entry *entry)
252{
253 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
254 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
John Wangccc04552019-10-14 14:28:25 +0800255 return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
John Wang02700402019-10-06 16:34:29 +0800256}
257
John Wangccc04552019-10-14 14:28:25 +0800258struct attr_table_string_entry_fields {
259 uint8_t string_type;
260 uint16_t min_length;
261 uint16_t max_length;
262 uint16_t def_length;
263 uint8_t def_string[1];
264} __attribute__((packed));
265
266size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
267{
268 return sizeof(struct pldm_bios_attr_table_entry) -
269 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
270 sizeof(struct attr_table_string_entry_fields) -
271 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
272 def_str_len;
273}
274
275void pldm_bios_table_attr_entry_string_encode(
276 void *entry, size_t entry_length,
277 const struct pldm_bios_table_attr_entry_string_info *info)
278{
279 size_t length =
280 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
281 assert(length <= entry_length);
282 uint8_t attr_type =
283 info->read_only ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
284 attr_table_entry_encode_header(entry, entry_length, attr_type,
285 info->name_handle);
286 struct pldm_bios_attr_table_entry *attr_entry = entry;
287 struct attr_table_string_entry_fields *attr_fields =
288 (struct attr_table_string_entry_fields *)attr_entry->metadata;
289 attr_fields->string_type = info->string_type;
290 attr_fields->min_length = htole16(info->min_length);
291 attr_fields->max_length = htole16(info->max_length);
292 attr_fields->def_length = htole16(info->def_length);
293 if (info->def_length != 0 && info->def_string != NULL)
294 memcpy(attr_fields->def_string, info->def_string,
295 info->def_length);
296}
297
298int pldm_bios_table_attr_entry_string_encode_check(
299 void *entry, size_t entry_length,
300 const struct pldm_bios_table_attr_entry_string_info *info)
301{
302 POINTER_CHECK(entry);
303 POINTER_CHECK(info);
304 size_t length =
305 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
306 BUFFER_SIZE_EXPECT(entry_length, length);
307 if (info->def_length > info->max_length ||
308 info->def_length < info->min_length ||
309 info->min_length > info->max_length)
310 return PLDM_ERROR_INVALID_DATA;
311 if (info->string_type > 5 && info->string_type != 0xFF)
312 return PLDM_ERROR_INVALID_DATA;
313 pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
314 return PLDM_SUCCESS;
315}
John Wang02700402019-10-06 16:34:29 +0800316
317uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
318 const struct pldm_bios_attr_table_entry *entry)
319{
John Wangccc04552019-10-14 14:28:25 +0800320 struct attr_table_string_entry_fields *fields =
321 (struct attr_table_string_entry_fields *)entry->metadata;
322 return le16toh(fields->def_length);
John Wang02700402019-10-06 16:34:29 +0800323}
324
325int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
326 const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
327{
328 POINTER_CHECK(entry);
329 POINTER_CHECK(def_string_length);
330 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
331 *def_string_length =
332 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
333 return PLDM_SUCCESS;
334}
335
336/** @brief Get length of a string attribute entry
337 */
338static size_t
339attr_table_entry_length_string(const struct pldm_bios_attr_table_entry *entry)
340{
John Wangccc04552019-10-14 14:28:25 +0800341 uint16_t def_str_len =
John Wang02700402019-10-06 16:34:29 +0800342 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
John Wangccc04552019-10-14 14:28:25 +0800343 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
John Wang02700402019-10-06 16:34:29 +0800344}
345
346struct attr_table_entry {
347 uint8_t attr_type;
348 size_t (*entry_length_handler)(
349 const struct pldm_bios_attr_table_entry *);
350};
351
352static struct attr_table_entry attr_table_entrys[] = {
353 {.attr_type = PLDM_BIOS_ENUMERATION,
354 .entry_length_handler = attr_table_entry_length_enum},
355 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
356 .entry_length_handler = attr_table_entry_length_enum},
357 {.attr_type = PLDM_BIOS_STRING,
358 .entry_length_handler = attr_table_entry_length_string},
359 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
360 .entry_length_handler = attr_table_entry_length_string},
361};
362
363#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
364
365static struct attr_table_entry *find_attr_table_entry_by_type(uint8_t attr_type)
366{
367 size_t i;
368 for (i = 0; i < ARRAY_SIZE(attr_table_entrys); i++) {
369 if (attr_type == attr_table_entrys[i].attr_type)
370 return &attr_table_entrys[i];
371 }
372 return NULL;
373}
374
375static size_t attr_table_entry_length(const void *table_entry)
376{
377 const struct pldm_bios_attr_table_entry *entry = table_entry;
378 struct attr_table_entry *attr_table_entry =
379 find_attr_table_entry_by_type(entry->attr_type);
380 assert(attr_table_entry != NULL);
381 assert(attr_table_entry->entry_length_handler != NULL);
382
383 return attr_table_entry->entry_length_handler(entry);
384}
385
John Wang3ad21752019-10-06 16:42:21 +0800386size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
387{
388 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
389 sizeof(count) + count;
390}
391
392void pldm_bios_table_attr_value_entry_encode_enum(
393 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
394 uint8_t count, uint8_t *handles)
395{
396 size_t length =
397 pldm_bios_table_attr_value_entry_encode_enum_length(count);
398 assert(length <= entry_length);
399
400 struct pldm_bios_attr_val_table_entry *table_entry = entry;
401 table_entry->attr_handle = htole16(attr_handle);
402 table_entry->attr_type = attr_type;
403 table_entry->value[0] = count;
404 if (count != 0)
405 memcpy(&table_entry->value[1], handles, count);
406}
407
408int pldm_bios_table_attr_value_entry_encode_enum_check(
409 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
410 uint8_t count, uint8_t *handles)
411{
412 POINTER_CHECK(entry);
413 if (count != 0 && handles == NULL)
414 return PLDM_ERROR_INVALID_DATA;
415 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
416 size_t length =
417 pldm_bios_table_attr_value_entry_encode_enum_length(count);
418 BUFFER_SIZE_EXPECT(entry_length, length);
419 pldm_bios_table_attr_value_entry_encode_enum(
420 entry, entry_length, attr_handle, attr_type, count, handles);
421 return PLDM_SUCCESS;
422}
423
424size_t
425pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
426{
427 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
428 sizeof(string_length) + string_length;
429}
430
431void pldm_bios_table_attr_value_entry_encode_string(
432 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
433 uint16_t str_length, const char *str)
434{
435 size_t length =
436 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
437 assert(length <= entry_length);
438
439 struct pldm_bios_attr_val_table_entry *table_entry = entry;
440 table_entry->attr_handle = htole16(attr_handle);
441 table_entry->attr_type = attr_type;
442 if (str_length != 0)
443 memcpy(table_entry->value + sizeof(str_length), str,
444 str_length);
445 str_length = htole16(str_length);
446 memcpy(table_entry->value, &str_length, sizeof(str_length));
447}
448
449int pldm_bios_table_attr_value_entry_encode_string_check(
450 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
451 uint16_t str_length, const char *str)
452{
453 POINTER_CHECK(entry);
454 if (str_length != 0 && str == NULL)
455 return PLDM_ERROR_INVALID_DATA;
456 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
457 size_t length =
458 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
459 BUFFER_SIZE_EXPECT(entry_length, length);
460 pldm_bios_table_attr_value_entry_encode_string(
461 entry, entry_length, attr_handle, attr_type, str_length, str);
462 return PLDM_SUCCESS;
463}
464
John Wang02700402019-10-06 16:34:29 +0800465struct pldm_bios_table_iter {
466 const uint8_t *table_data;
467 size_t table_len;
468 size_t current_pos;
469 size_t (*entry_length_handler)(const void *table_entry);
470};
471
472struct pldm_bios_table_iter *
473pldm_bios_table_iter_create(const void *table, size_t length,
474 enum pldm_bios_table_types type)
475{
476 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
477 assert(iter != NULL);
478 iter->table_data = table;
479 iter->table_len = length;
480 iter->current_pos = 0;
481 iter->entry_length_handler = NULL;
482 switch (type) {
483 case PLDM_BIOS_STRING_TABLE:
John Wangdd9a6282019-10-11 18:52:46 +0800484 iter->entry_length_handler = string_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800485 break;
486 case PLDM_BIOS_ATTR_TABLE:
487 iter->entry_length_handler = attr_table_entry_length;
488 break;
489 case PLDM_BIOS_ATTR_VAL_TABLE:
490 break;
491 }
492
493 return iter;
494}
495
496void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
497{
498 free(iter);
499}
500
501#define pad_and_check_max 7
502bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
503{
504 if (iter->table_len - iter->current_pos <= pad_and_check_max)
505 return true;
506 return false;
507}
508
509void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
510{
511 if (pldm_bios_table_iter_is_end(iter))
512 return;
513 const void *entry = iter->table_data + iter->current_pos;
514 iter->current_pos += iter->entry_length_handler(entry);
515}
516
517const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
518{
519 return iter->table_data + iter->current_pos;
John Wang3ad21752019-10-06 16:42:21 +0800520}
John Wangdd9a6282019-10-11 18:52:46 +0800521
522static const void *
523pldm_bios_table_entry_find(struct pldm_bios_table_iter *iter, const void *key,
524 int (*equal)(const void *entry, const void *key))
525{
526 const void *entry;
527 while (!pldm_bios_table_iter_is_end(iter)) {
528 entry = pldm_bios_table_iter_value(iter);
529 if (equal(entry, key))
530 return entry;
531 pldm_bios_table_iter_next(iter);
532 }
533 return NULL;
534}
535
536static int string_table_handle_equal(const void *entry, const void *key)
537{
538 const struct pldm_bios_string_table_entry *string_entry = entry;
539 uint16_t handle = *(uint16_t *)key;
540 if (pldm_bios_table_string_entry_decode_handle(string_entry) == handle)
541 return true;
542 return false;
543}
544
545struct string_equal_arg {
546 uint16_t str_length;
547 const char *str;
548};
549
550static int string_table_string_equal(const void *entry, const void *key)
551{
552 const struct pldm_bios_string_table_entry *string_entry = entry;
553 const struct string_equal_arg *arg = key;
554 if (arg->str_length !=
555 pldm_bios_table_string_entry_decode_string_length(string_entry))
556 return false;
557 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0)
558 return false;
559 return true;
560}
561
562const struct pldm_bios_string_table_entry *
563pldm_bios_table_string_find_by_string(const void *table, size_t length,
564 const char *str)
565{
566 uint16_t str_length = strlen(str);
567 struct string_equal_arg arg = {str_length, str};
568 struct pldm_bios_table_iter *iter =
569 pldm_bios_table_iter_create(table, length, PLDM_BIOS_STRING_TABLE);
570 const void *entry =
571 pldm_bios_table_entry_find(iter, &arg, string_table_string_equal);
572 pldm_bios_table_iter_free(iter);
573 return entry;
574}
575
576const struct pldm_bios_string_table_entry *
577pldm_bios_table_string_find_by_handle(const void *table, size_t length,
578 uint16_t handle)
579{
580 struct pldm_bios_table_iter *iter =
581 pldm_bios_table_iter_create(table, length, PLDM_BIOS_STRING_TABLE);
582 const void *entry = pldm_bios_table_entry_find(
583 iter, &handle, string_table_handle_equal);
584 pldm_bios_table_iter_free(iter);
585 return entry;
586}