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