blob: e8b660799588a473e5858eb641f06d4e4a30ac81 [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 */
John Wang49484a12019-12-02 14:21:53 +0800257static size_t attr_table_entry_length_enum(const void *entry)
John Wang02700402019-10-06 16:34:29 +0800258{
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 */
John Wang49484a12019-12-02 14:21:53 +0800377static size_t attr_table_entry_length_string(const void *entry)
John Wang02700402019-10-06 16:34:29 +0800378{
John Wangccc04552019-10-14 14:28:25 +0800379 uint16_t def_str_len =
John Wang02700402019-10-06 16:34:29 +0800380 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
John Wangccc04552019-10-14 14:28:25 +0800381 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
John Wang02700402019-10-06 16:34:29 +0800382}
383
John Wangca230822019-10-16 11:39:27 +0800384struct attr_table_integer_entry_fields {
385 uint64_t lower_bound;
386 uint64_t upper_bound;
387 uint32_t scalar_increment;
388 uint64_t default_value;
389} __attribute__((packed));
390
391size_t pldm_bios_table_attr_entry_integer_encode_length()
392{
393 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
394 sizeof(struct attr_table_integer_entry_fields);
395}
396
397void pldm_bios_table_attr_entry_integer_encode(
398 void *entry, size_t entry_length,
399 const struct pldm_bios_table_attr_entry_integer_info *info)
400{
401 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
402 assert(length <= entry_length);
403 uint8_t attr_type =
404 info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY : PLDM_BIOS_INTEGER;
405 attr_table_entry_encode_header(entry, entry_length, attr_type,
406 info->name_handle);
407 struct pldm_bios_attr_table_entry *attr_entry = entry;
408 struct attr_table_integer_entry_fields *attr_fields =
409 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
410 attr_fields->lower_bound = htole64(info->lower_bound);
411 attr_fields->upper_bound = htole64(info->upper_bound);
412 attr_fields->scalar_increment = htole32(info->scalar_increment);
413 attr_fields->default_value = htole64(info->default_value);
414}
415
John Wang827c5de2019-11-07 18:27:27 +0800416int pldm_bios_table_attr_entry_integer_info_check(
417 const struct pldm_bios_table_attr_entry_integer_info *info,
418 const char **errmsg)
419{
420 if (info->lower_bound == info->upper_bound) {
421 if (info->default_value != info->lower_bound) {
422 set_errmsg(errmsg, "Wrong DefaultValue");
423 return PLDM_ERROR_INVALID_DATA;
424 }
425 if (info->scalar_increment != 0) {
426 set_errmsg(errmsg, "Wrong ScalarIncrement");
427 return PLDM_ERROR_INVALID_DATA;
428 }
429 return PLDM_SUCCESS;
430 }
431 if (info->lower_bound > info->upper_bound) {
432 set_errmsg(errmsg,
433 "LowerBound should not be greater than UpperBound");
434 return PLDM_ERROR_INVALID_DATA;
435 }
436 if (info->default_value > info->upper_bound ||
437 info->default_value < info->lower_bound) {
438 set_errmsg(errmsg, "Wrong DefaultValue");
439 return PLDM_ERROR_INVALID_DATA;
440 }
441 if (info->scalar_increment == 0) {
442 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
443 "lower_bound != upper_bound");
444 return PLDM_ERROR_INVALID_DATA;
445 }
446 if ((info->default_value - info->lower_bound) %
447 info->scalar_increment !=
448 0) {
449 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
450 return PLDM_ERROR_INVALID_DATA;
451 }
452 return PLDM_SUCCESS;
453}
454
John Wangca230822019-10-16 11:39:27 +0800455int pldm_bios_table_attr_entry_integer_encode_check(
456 void *entry, size_t entry_length,
457 const struct pldm_bios_table_attr_entry_integer_info *info)
458{
459 POINTER_CHECK(entry);
460 POINTER_CHECK(info);
461 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
462 BUFFER_SIZE_EXPECT(entry_length, length);
John Wang827c5de2019-11-07 18:27:27 +0800463 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
464 PLDM_SUCCESS)
John Wangca230822019-10-16 11:39:27 +0800465 return PLDM_ERROR_INVALID_DATA;
466 pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
467 return PLDM_SUCCESS;
468}
469
John Wang49484a12019-12-02 14:21:53 +0800470static size_t attr_table_entry_length_integer(const void *entry)
John Wangca230822019-10-16 11:39:27 +0800471{
472 (void)entry;
473 return pldm_bios_table_attr_entry_integer_encode_length();
474}
475
John Wang49484a12019-12-02 14:21:53 +0800476struct table_entry_length {
John Wang02700402019-10-06 16:34:29 +0800477 uint8_t attr_type;
John Wang49484a12019-12-02 14:21:53 +0800478 size_t (*entry_length_handler)(const void *);
John Wang02700402019-10-06 16:34:29 +0800479};
480
John Wang49484a12019-12-02 14:21:53 +0800481#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
482
John Wangb6333cb2019-12-10 09:43:42 +0800483static const struct table_entry_length *find_table_entry_length_by_type(
484 uint8_t attr_type, const struct table_entry_length *handlers, size_t count)
John Wang49484a12019-12-02 14:21:53 +0800485{
486 size_t i;
487 for (i = 0; i < count; i++) {
488 if (attr_type == handlers[i].attr_type)
489 return &handlers[i];
490 }
491 return NULL;
492}
493
John Wangb6333cb2019-12-10 09:43:42 +0800494static const struct table_entry_length attr_table_entries[] = {
John Wang02700402019-10-06 16:34:29 +0800495 {.attr_type = PLDM_BIOS_ENUMERATION,
496 .entry_length_handler = attr_table_entry_length_enum},
497 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
498 .entry_length_handler = attr_table_entry_length_enum},
499 {.attr_type = PLDM_BIOS_STRING,
500 .entry_length_handler = attr_table_entry_length_string},
501 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
502 .entry_length_handler = attr_table_entry_length_string},
John Wangca230822019-10-16 11:39:27 +0800503 {.attr_type = PLDM_BIOS_INTEGER,
504 .entry_length_handler = attr_table_entry_length_integer},
505 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
506 .entry_length_handler = attr_table_entry_length_integer},
John Wang02700402019-10-06 16:34:29 +0800507};
508
John Wang02700402019-10-06 16:34:29 +0800509static size_t attr_table_entry_length(const void *table_entry)
510{
511 const struct pldm_bios_attr_table_entry *entry = table_entry;
John Wangb6333cb2019-12-10 09:43:42 +0800512 const struct table_entry_length *attr_table_entry =
John Wang49484a12019-12-02 14:21:53 +0800513 find_table_entry_length_by_type(entry->attr_type,
514 attr_table_entries,
515 ARRAY_SIZE(attr_table_entries));
John Wang02700402019-10-06 16:34:29 +0800516 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
John Wang49484a12019-12-02 14:21:53 +0800544uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
545 const struct pldm_bios_attr_val_table_entry *entry)
546{
547 return entry->value[0];
548}
549
John Wang3ad21752019-10-06 16:42:21 +0800550int pldm_bios_table_attr_value_entry_encode_enum_check(
551 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
552 uint8_t count, uint8_t *handles)
553{
554 POINTER_CHECK(entry);
555 if (count != 0 && handles == NULL)
556 return PLDM_ERROR_INVALID_DATA;
557 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
558 size_t length =
559 pldm_bios_table_attr_value_entry_encode_enum_length(count);
560 BUFFER_SIZE_EXPECT(entry_length, length);
561 pldm_bios_table_attr_value_entry_encode_enum(
562 entry, entry_length, attr_handle, attr_type, count, handles);
563 return PLDM_SUCCESS;
564}
565
John Wang49484a12019-12-02 14:21:53 +0800566static size_t attr_value_table_entry_length_enum(const void *entry)
567{
568 uint8_t number =
569 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
570 return pldm_bios_table_attr_value_entry_encode_enum_length(number);
571}
572
John Wang3ad21752019-10-06 16:42:21 +0800573size_t
574pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
575{
576 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
577 sizeof(string_length) + string_length;
578}
579
580void pldm_bios_table_attr_value_entry_encode_string(
581 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
582 uint16_t str_length, const char *str)
583{
584 size_t length =
585 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
586 assert(length <= entry_length);
587
588 struct pldm_bios_attr_val_table_entry *table_entry = entry;
589 table_entry->attr_handle = htole16(attr_handle);
590 table_entry->attr_type = attr_type;
591 if (str_length != 0)
592 memcpy(table_entry->value + sizeof(str_length), str,
593 str_length);
594 str_length = htole16(str_length);
595 memcpy(table_entry->value, &str_length, sizeof(str_length));
596}
597
John Wang49484a12019-12-02 14:21:53 +0800598uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
599 const struct pldm_bios_attr_val_table_entry *entry)
600{
601 uint16_t str_length = 0;
602 memcpy(&str_length, entry->value, sizeof(str_length));
603 return le16toh(str_length);
604}
605
John Wang3ad21752019-10-06 16:42:21 +0800606int pldm_bios_table_attr_value_entry_encode_string_check(
607 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
608 uint16_t str_length, const char *str)
609{
610 POINTER_CHECK(entry);
611 if (str_length != 0 && str == NULL)
612 return PLDM_ERROR_INVALID_DATA;
613 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
614 size_t length =
615 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
616 BUFFER_SIZE_EXPECT(entry_length, length);
617 pldm_bios_table_attr_value_entry_encode_string(
618 entry, entry_length, attr_handle, attr_type, str_length, str);
619 return PLDM_SUCCESS;
620}
621
John Wang49484a12019-12-02 14:21:53 +0800622static size_t attr_value_table_entry_length_string(const void *entry)
623{
624 uint16_t str_length =
625 pldm_bios_table_attr_value_entry_string_decode_length(entry);
626 return pldm_bios_table_attr_value_entry_encode_string_length(
627 str_length);
628}
629
John Wangca230822019-10-16 11:39:27 +0800630size_t pldm_bios_table_attr_value_entry_encode_integer_length()
631{
632 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
633 sizeof(uint64_t);
634}
635void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
636 size_t entry_length,
637 uint16_t attr_handle,
638 uint8_t attr_type,
639 uint64_t cv)
640{
641 size_t length =
642 pldm_bios_table_attr_value_entry_encode_integer_length();
643 assert(length <= entry_length);
644
645 struct pldm_bios_attr_val_table_entry *table_entry = entry;
646 table_entry->attr_handle = htole16(attr_handle);
647 table_entry->attr_type = attr_type;
648 cv = htole64(cv);
649 memcpy(table_entry->value, &cv, sizeof(uint64_t));
650}
651
652int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
653 size_t entry_length,
654 uint16_t attr_handle,
655 uint8_t attr_type,
656 uint64_t cv)
657{
658 POINTER_CHECK(entry);
659 size_t length =
660 pldm_bios_table_attr_value_entry_encode_integer_length();
661 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
662 BUFFER_SIZE_EXPECT(entry_length, length);
663 pldm_bios_table_attr_value_entry_encode_integer(
664 entry, entry_length, attr_handle, attr_type, cv);
665 return PLDM_SUCCESS;
666}
667
John Wang49484a12019-12-02 14:21:53 +0800668static size_t attr_value_table_entry_length_integer(const void *entry)
669{
670 (void)entry;
671 return pldm_bios_table_attr_value_entry_encode_integer_length();
672}
673
John Wangb6333cb2019-12-10 09:43:42 +0800674static const struct table_entry_length attr_value_table_entries[] = {
John Wang49484a12019-12-02 14:21:53 +0800675 {.attr_type = PLDM_BIOS_ENUMERATION,
676 .entry_length_handler = attr_value_table_entry_length_enum},
677 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
678 .entry_length_handler = attr_value_table_entry_length_enum},
679 {.attr_type = PLDM_BIOS_STRING,
680 .entry_length_handler = attr_value_table_entry_length_string},
681 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
682 .entry_length_handler = attr_value_table_entry_length_string},
683 {.attr_type = PLDM_BIOS_INTEGER,
684 .entry_length_handler = attr_value_table_entry_length_integer},
685 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
686 .entry_length_handler = attr_value_table_entry_length_integer},
687};
688
689static size_t attr_value_table_entry_length(const void *table_entry)
690{
691 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
John Wangb6333cb2019-12-10 09:43:42 +0800692 const struct table_entry_length *entry_length =
John Wang49484a12019-12-02 14:21:53 +0800693 find_table_entry_length_by_type(
694 entry->attr_type, attr_value_table_entries,
695 ARRAY_SIZE(attr_value_table_entries));
696 assert(entry_length != NULL);
697 assert(entry_length->entry_length_handler != NULL);
698
699 return entry_length->entry_length_handler(entry);
700}
701
John Wang8e877e02020-02-03 16:06:55 +0800702size_t pldm_bios_table_attr_value_entry_length(
703 const struct pldm_bios_attr_val_table_entry *entry)
704{
705 return attr_value_table_entry_length(entry);
706}
707
John Wang3342adb2019-11-29 16:03:58 +0800708uint16_t pldm_bios_table_attr_value_entry_decode_handle(
709 const struct pldm_bios_attr_val_table_entry *entry)
710{
711 return le16toh(entry->attr_handle);
712}
713
John Wang79c37f12019-10-31 15:46:31 +0800714static size_t pad_size_get(size_t size_without_pad)
715{
716 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
717}
718
719static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
720{
721 while (pad_size--)
722 *table_end++ = 0;
723
724 return table_end;
725}
726
727static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
728{
729 checksum = htole32(checksum);
730 memcpy(table_end, &checksum, sizeof(checksum));
731
732 return table_end + sizeof(checksum);
733}
734
735size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
736{
737 size_t size = pad_size_get(size_without_pad) +
738 sizeof(uint32_t) /*sizeof(checksum)*/;
739 return size;
740}
741
742void pldm_bios_table_append_pad_checksum(void *table, size_t size,
743 size_t size_without_pad)
744{
745
746 size_t pad_checksum_size =
747 pldm_bios_table_pad_checksum_size(size_without_pad);
748 assert(size >= (size_without_pad + pad_checksum_size));
749
750 uint8_t *table_end = (uint8_t *)table + size_without_pad;
751 size_t pad_size = pad_size_get(size_without_pad);
752 table_end = pad_append(table_end, pad_size);
753
754 uint32_t checksum = crc32(table, size_without_pad + pad_size);
755 checksum_append(table_end, checksum);
756}
757
John Wang02700402019-10-06 16:34:29 +0800758struct pldm_bios_table_iter {
759 const uint8_t *table_data;
760 size_t table_len;
761 size_t current_pos;
762 size_t (*entry_length_handler)(const void *table_entry);
763};
764
765struct pldm_bios_table_iter *
766pldm_bios_table_iter_create(const void *table, size_t length,
767 enum pldm_bios_table_types type)
768{
769 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
770 assert(iter != NULL);
771 iter->table_data = table;
772 iter->table_len = length;
773 iter->current_pos = 0;
774 iter->entry_length_handler = NULL;
775 switch (type) {
776 case PLDM_BIOS_STRING_TABLE:
John Wangdd9a6282019-10-11 18:52:46 +0800777 iter->entry_length_handler = string_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800778 break;
779 case PLDM_BIOS_ATTR_TABLE:
780 iter->entry_length_handler = attr_table_entry_length;
781 break;
782 case PLDM_BIOS_ATTR_VAL_TABLE:
John Wang49484a12019-12-02 14:21:53 +0800783 iter->entry_length_handler = attr_value_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800784 break;
785 }
786
787 return iter;
788}
789
790void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
791{
792 free(iter);
793}
794
795#define pad_and_check_max 7
796bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
797{
798 if (iter->table_len - iter->current_pos <= pad_and_check_max)
799 return true;
800 return false;
801}
802
803void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
804{
805 if (pldm_bios_table_iter_is_end(iter))
806 return;
807 const void *entry = iter->table_data + iter->current_pos;
808 iter->current_pos += iter->entry_length_handler(entry);
809}
810
811const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
812{
813 return iter->table_data + iter->current_pos;
John Wang3ad21752019-10-06 16:42:21 +0800814}
John Wangdd9a6282019-10-11 18:52:46 +0800815
John Wang3342adb2019-11-29 16:03:58 +0800816typedef bool (*equal_handler)(const void *entry, const void *key);
817
John Wangdd9a6282019-10-11 18:52:46 +0800818static const void *
John Wang3342adb2019-11-29 16:03:58 +0800819pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
820 const void *key, equal_handler equal)
John Wangdd9a6282019-10-11 18:52:46 +0800821{
822 const void *entry;
823 while (!pldm_bios_table_iter_is_end(iter)) {
824 entry = pldm_bios_table_iter_value(iter);
825 if (equal(entry, key))
826 return entry;
827 pldm_bios_table_iter_next(iter);
828 }
829 return NULL;
830}
831
John Wang3342adb2019-11-29 16:03:58 +0800832static const void *
833pldm_bios_table_entry_find_from_table(const void *table, size_t length,
834 enum pldm_bios_table_types type,
835 equal_handler equal, const void *key)
836{
837 struct pldm_bios_table_iter *iter =
838 pldm_bios_table_iter_create(table, length, type);
839 const void *entry =
840 pldm_bios_table_entry_find_by_iter(iter, key, equal);
841 pldm_bios_table_iter_free(iter);
842 return entry;
843}
844
845static bool string_table_handle_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +0800846{
847 const struct pldm_bios_string_table_entry *string_entry = entry;
848 uint16_t handle = *(uint16_t *)key;
849 if (pldm_bios_table_string_entry_decode_handle(string_entry) == handle)
850 return true;
851 return false;
852}
853
John Wang3342adb2019-11-29 16:03:58 +0800854const struct pldm_bios_string_table_entry *
855pldm_bios_table_string_find_by_handle(const void *table, size_t length,
856 uint16_t handle)
857{
858 return pldm_bios_table_entry_find_from_table(
859 table, length, PLDM_BIOS_STRING_TABLE, string_table_handle_equal,
860 &handle);
861}
862
John Wangdd9a6282019-10-11 18:52:46 +0800863struct string_equal_arg {
864 uint16_t str_length;
865 const char *str;
866};
867
John Wang3342adb2019-11-29 16:03:58 +0800868static bool string_table_string_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +0800869{
870 const struct pldm_bios_string_table_entry *string_entry = entry;
871 const struct string_equal_arg *arg = key;
872 if (arg->str_length !=
873 pldm_bios_table_string_entry_decode_string_length(string_entry))
874 return false;
875 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0)
876 return false;
877 return true;
878}
879
880const struct pldm_bios_string_table_entry *
881pldm_bios_table_string_find_by_string(const void *table, size_t length,
882 const char *str)
883{
884 uint16_t str_length = strlen(str);
885 struct string_equal_arg arg = {str_length, str};
John Wang3342adb2019-11-29 16:03:58 +0800886 return pldm_bios_table_entry_find_from_table(
887 table, length, PLDM_BIOS_STRING_TABLE, string_table_string_equal,
888 &arg);
John Wangdd9a6282019-10-11 18:52:46 +0800889}
890
John Wang3342adb2019-11-29 16:03:58 +0800891static bool attr_value_table_handle_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +0800892{
John Wang3342adb2019-11-29 16:03:58 +0800893 uint16_t handle = *(uint16_t *)key;
894 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
895}
896
897const struct pldm_bios_attr_val_table_entry *
898pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
899 uint16_t handle)
900{
901 return pldm_bios_table_entry_find_from_table(
902 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
903 attr_value_table_handle_equal, &handle);
John Wangdd9a6282019-10-11 18:52:46 +0800904}