blob: a1db7eb01123340e85f99b0ce49bedab1fe7be8a [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 Wang871c9272019-12-09 18:02:15 +080024static bool attribute_is_readonly(uint8_t attr_type)
25{
26 return (attr_type & 0x80);
27}
28
John Wang3ad21752019-10-06 16:42:21 +080029#define BUFFER_SIZE_EXPECT(current_size, expected_size) \
30 do { \
31 if (current_size < expected_size) \
32 return PLDM_ERROR_INVALID_LENGTH; \
33 } while (0)
34
John Wangdd9a6282019-10-11 18:52:46 +080035#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
36
John Wang827c5de2019-11-07 18:27:27 +080037static void set_errmsg(const char **errmsg, const char *msg)
38{
39 if (errmsg != NULL)
40 *errmsg = msg;
41}
42
John Wangdd9a6282019-10-11 18:52:46 +080043static uint16_t get_bios_string_handle()
44{
45 static uint16_t handle = 0;
46 assert(handle != UINT16_MAX);
47
48 return handle++;
49}
50
51size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
52{
53 return sizeof(struct pldm_bios_string_table_entry) -
54 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
55}
56
57void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
58 const char *str, uint16_t str_length)
59{
60 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
61 assert(length <= entry_length);
62 struct pldm_bios_string_table_entry *string_entry = entry;
63 string_entry->string_handle = htole16(get_bios_string_handle());
64 string_entry->string_length = htole16(str_length);
65 memcpy(string_entry->name, str, str_length);
66}
67
68int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
69 const char *str,
70 uint16_t str_length)
71{
72 if (str_length == 0)
73 return PLDM_ERROR_INVALID_DATA;
74 POINTER_CHECK(entry);
75 POINTER_CHECK(str);
76 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
77 BUFFER_SIZE_EXPECT(entry_length, length);
78 pldm_bios_table_string_entry_encode(entry, entry_length, str,
79 str_length);
80 return PLDM_SUCCESS;
81}
82
83uint16_t pldm_bios_table_string_entry_decode_handle(
84 const struct pldm_bios_string_table_entry *entry)
85{
86 return le16toh(entry->string_handle);
87}
88
89uint16_t pldm_bios_table_string_entry_decode_string_length(
90 const struct pldm_bios_string_table_entry *entry)
91{
92 return le16toh(entry->string_length);
93}
94
95uint16_t pldm_bios_table_string_entry_decode_string(
96 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
97{
98 uint16_t length =
99 pldm_bios_table_string_entry_decode_string_length(entry);
100 length = length < size ? length : size;
101 memcpy(buffer, entry->name, length);
102 buffer[length] = 0;
103 return length;
104}
105
106int pldm_bios_table_string_entry_decode_string_check(
107 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
108{
109 POINTER_CHECK(entry);
110 POINTER_CHECK(buffer);
111 size_t length =
112 pldm_bios_table_string_entry_decode_string_length(entry);
113 BUFFER_SIZE_EXPECT(size, length + 1);
114 pldm_bios_table_string_entry_decode_string(entry, buffer, size);
115 return PLDM_SUCCESS;
116}
117
118static size_t string_table_entry_length(const void *table_entry)
119{
120 const struct pldm_bios_string_table_entry *entry = table_entry;
121 return sizeof(*entry) - sizeof(entry->name) +
122 pldm_bios_table_string_entry_decode_string_length(entry);
123}
124
John Wangccc04552019-10-14 14:28:25 +0800125static uint16_t get_bios_attr_handle()
126{
127 static uint16_t handle = 0;
128 assert(handle != UINT16_MAX);
129
130 return handle++;
131}
132
133static void attr_table_entry_encode_header(void *entry, size_t length,
134 uint8_t attr_type,
135 uint16_t string_handle)
136{
137 struct pldm_bios_attr_table_entry *attr_entry = entry;
138 assert(sizeof(*attr_entry) <= length);
139 attr_entry->attr_handle = htole16(get_bios_attr_handle());
140 attr_entry->attr_type = attr_type;
141 attr_entry->string_handle = htole16(string_handle);
142}
143
144size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
145 uint8_t def_num)
146{
147 return sizeof(struct pldm_bios_attr_table_entry) -
148 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
149 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
150 def_num;
151}
152
153void pldm_bios_table_attr_entry_enum_encode(
154 void *entry, size_t entry_length,
155 const struct pldm_bios_table_attr_entry_enum_info *info)
156{
157 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
158 info->pv_num, info->def_num);
159 assert(length <= entry_length);
160 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY
161 : PLDM_BIOS_ENUMERATION;
162 attr_table_entry_encode_header(entry, entry_length, attr_type,
163 info->name_handle);
164 struct pldm_bios_attr_table_entry *attr_entry = entry;
165 attr_entry->metadata[0] = info->pv_num;
166 uint16_t *pv_hdls =
167 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
168 size_t i;
169 for (i = 0; i < info->pv_num; i++)
170 pv_hdls[i] = htole16(info->pv_handle[i]);
171 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
172 info->def_num;
173 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
174 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
175 info->def_index, info->def_num);
176}
177
178int pldm_bios_table_attr_entry_enum_encode_check(
179 void *entry, size_t entry_length,
180 const struct pldm_bios_table_attr_entry_enum_info *info)
181{
182 POINTER_CHECK(entry);
183 POINTER_CHECK(info);
184 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
185 info->pv_num, info->def_num);
186 BUFFER_SIZE_EXPECT(entry_length, length);
187 pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
188 return PLDM_SUCCESS;
189}
190
John Wangdd9a6282019-10-11 18:52:46 +0800191#define ATTR_TYPE_EXPECT(type, expected) \
192 do { \
193 if (type != expected && type != (expected | 0x80)) \
194 return PLDM_ERROR_INVALID_DATA; \
195 } while (0)
196
John Wang02700402019-10-06 16:34:29 +0800197uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
198 const struct pldm_bios_attr_table_entry *entry)
199{
200 return entry->metadata[0];
201}
202
203int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
204 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
205{
206 POINTER_CHECK(entry);
207 POINTER_CHECK(pv_num);
208 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
209 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
210 return PLDM_SUCCESS;
211}
212
213uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
214 const struct pldm_bios_attr_table_entry *entry)
215{
216 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
217 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
218 sizeof(uint16_t) * pv_num];
219}
220
221int pldm_bios_table_attr_entry_enum_decode_def_num_check(
222 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
223{
224 POINTER_CHECK(entry);
225 POINTER_CHECK(def_num);
226 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
227 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
228 return PLDM_SUCCESS;
229}
230
John Wang3ad21752019-10-06 16:42:21 +0800231uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
232 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
233 uint8_t pv_num)
234{
235 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
236 num = num < pv_num ? num : pv_num;
237 size_t i;
238 for (i = 0; i < num; i++) {
239 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
240 i * sizeof(uint16_t));
241 pv_hdls[i] = le16toh(*hdl);
242 }
243 return num;
244}
245
246int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
247 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
248 uint8_t pv_num)
249{
250 POINTER_CHECK(entry);
251 POINTER_CHECK(pv_hdls);
252 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
253 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
254 if (num != pv_num)
255 return PLDM_ERROR_INVALID_DATA;
256 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
257 return PLDM_SUCCESS;
258}
259
John Wang02700402019-10-06 16:34:29 +0800260/** @brief Get length of an enum attribute entry
261 */
John Wang49484a12019-12-02 14:21:53 +0800262static size_t attr_table_entry_length_enum(const void *entry)
John Wang02700402019-10-06 16:34:29 +0800263{
264 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
265 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
John Wangccc04552019-10-14 14:28:25 +0800266 return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
John Wang02700402019-10-06 16:34:29 +0800267}
268
John Wangccc04552019-10-14 14:28:25 +0800269struct attr_table_string_entry_fields {
270 uint8_t string_type;
271 uint16_t min_length;
272 uint16_t max_length;
273 uint16_t def_length;
274 uint8_t def_string[1];
275} __attribute__((packed));
276
277size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
278{
279 return sizeof(struct pldm_bios_attr_table_entry) -
280 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
281 sizeof(struct attr_table_string_entry_fields) -
282 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
283 def_str_len;
284}
285
286void pldm_bios_table_attr_entry_string_encode(
287 void *entry, size_t entry_length,
288 const struct pldm_bios_table_attr_entry_string_info *info)
289{
290 size_t length =
291 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
292 assert(length <= entry_length);
293 uint8_t attr_type =
294 info->read_only ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
295 attr_table_entry_encode_header(entry, entry_length, attr_type,
296 info->name_handle);
297 struct pldm_bios_attr_table_entry *attr_entry = entry;
298 struct attr_table_string_entry_fields *attr_fields =
299 (struct attr_table_string_entry_fields *)attr_entry->metadata;
300 attr_fields->string_type = info->string_type;
301 attr_fields->min_length = htole16(info->min_length);
302 attr_fields->max_length = htole16(info->max_length);
303 attr_fields->def_length = htole16(info->def_length);
304 if (info->def_length != 0 && info->def_string != NULL)
305 memcpy(attr_fields->def_string, info->def_string,
306 info->def_length);
307}
308
John Wang827c5de2019-11-07 18:27:27 +0800309#define PLDM_STRING_TYPE_MAX 5
310#define PLDM_STRING_TYPE_VENDOR 0xff
311
312int pldm_bios_table_attr_entry_string_info_check(
313 const struct pldm_bios_table_attr_entry_string_info *info,
314 const char **errmsg)
315{
316 if (info->min_length > info->max_length) {
317 set_errmsg(errmsg, "MinimumStingLength should not be greater "
318 "than MaximumStringLength");
319 return PLDM_ERROR_INVALID_DATA;
320 }
321 if (info->min_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->def_length > info->max_length ||
327 info->def_length < info->min_length) {
328 set_errmsg(errmsg, "Wrong DefaultStringLength");
329 return PLDM_ERROR_INVALID_DATA;
330 }
331 if (info->string_type > PLDM_STRING_TYPE_MAX &&
332 info->string_type != PLDM_STRING_TYPE_VENDOR) {
333 set_errmsg(errmsg, "Wrong StringType");
334 return PLDM_ERROR_INVALID_DATA;
335 }
336 if (info->def_length != strlen(info->def_string)) {
337 set_errmsg(errmsg, "Length of DefaultString should be equal to "
338 "DefaultStringLength");
339 return PLDM_ERROR_INVALID_DATA;
340 }
341
342 return PLDM_SUCCESS;
343}
344
John Wangccc04552019-10-14 14:28:25 +0800345int pldm_bios_table_attr_entry_string_encode_check(
346 void *entry, size_t entry_length,
347 const struct pldm_bios_table_attr_entry_string_info *info)
348{
349 POINTER_CHECK(entry);
350 POINTER_CHECK(info);
351 size_t length =
352 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
353 BUFFER_SIZE_EXPECT(entry_length, length);
John Wang827c5de2019-11-07 18:27:27 +0800354 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
355 PLDM_SUCCESS)
John Wangccc04552019-10-14 14:28:25 +0800356 return PLDM_ERROR_INVALID_DATA;
357 pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
358 return PLDM_SUCCESS;
359}
John Wang02700402019-10-06 16:34:29 +0800360
361uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
362 const struct pldm_bios_attr_table_entry *entry)
363{
John Wangccc04552019-10-14 14:28:25 +0800364 struct attr_table_string_entry_fields *fields =
365 (struct attr_table_string_entry_fields *)entry->metadata;
366 return le16toh(fields->def_length);
John Wang02700402019-10-06 16:34:29 +0800367}
368
369int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
370 const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
371{
372 POINTER_CHECK(entry);
373 POINTER_CHECK(def_string_length);
374 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
375 *def_string_length =
376 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
377 return PLDM_SUCCESS;
378}
379
380/** @brief Get length of a string attribute entry
381 */
John Wang49484a12019-12-02 14:21:53 +0800382static size_t attr_table_entry_length_string(const void *entry)
John Wang02700402019-10-06 16:34:29 +0800383{
John Wangccc04552019-10-14 14:28:25 +0800384 uint16_t def_str_len =
John Wang02700402019-10-06 16:34:29 +0800385 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
John Wangccc04552019-10-14 14:28:25 +0800386 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
John Wang02700402019-10-06 16:34:29 +0800387}
388
John Wangca230822019-10-16 11:39:27 +0800389struct attr_table_integer_entry_fields {
390 uint64_t lower_bound;
391 uint64_t upper_bound;
392 uint32_t scalar_increment;
393 uint64_t default_value;
394} __attribute__((packed));
395
396size_t pldm_bios_table_attr_entry_integer_encode_length()
397{
398 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
399 sizeof(struct attr_table_integer_entry_fields);
400}
401
402void pldm_bios_table_attr_entry_integer_encode(
403 void *entry, size_t entry_length,
404 const struct pldm_bios_table_attr_entry_integer_info *info)
405{
406 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
407 assert(length <= entry_length);
408 uint8_t attr_type =
409 info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY : PLDM_BIOS_INTEGER;
410 attr_table_entry_encode_header(entry, entry_length, attr_type,
411 info->name_handle);
412 struct pldm_bios_attr_table_entry *attr_entry = entry;
413 struct attr_table_integer_entry_fields *attr_fields =
414 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
415 attr_fields->lower_bound = htole64(info->lower_bound);
416 attr_fields->upper_bound = htole64(info->upper_bound);
417 attr_fields->scalar_increment = htole32(info->scalar_increment);
418 attr_fields->default_value = htole64(info->default_value);
419}
420
John Wang827c5de2019-11-07 18:27:27 +0800421int pldm_bios_table_attr_entry_integer_info_check(
422 const struct pldm_bios_table_attr_entry_integer_info *info,
423 const char **errmsg)
424{
425 if (info->lower_bound == info->upper_bound) {
426 if (info->default_value != info->lower_bound) {
427 set_errmsg(errmsg, "Wrong DefaultValue");
428 return PLDM_ERROR_INVALID_DATA;
429 }
430 if (info->scalar_increment != 0) {
431 set_errmsg(errmsg, "Wrong ScalarIncrement");
432 return PLDM_ERROR_INVALID_DATA;
433 }
434 return PLDM_SUCCESS;
435 }
436 if (info->lower_bound > info->upper_bound) {
437 set_errmsg(errmsg,
438 "LowerBound should not be greater than UpperBound");
439 return PLDM_ERROR_INVALID_DATA;
440 }
441 if (info->default_value > info->upper_bound ||
442 info->default_value < info->lower_bound) {
443 set_errmsg(errmsg, "Wrong DefaultValue");
444 return PLDM_ERROR_INVALID_DATA;
445 }
446 if (info->scalar_increment == 0) {
447 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
448 "lower_bound != upper_bound");
449 return PLDM_ERROR_INVALID_DATA;
450 }
451 if ((info->default_value - info->lower_bound) %
452 info->scalar_increment !=
453 0) {
454 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
455 return PLDM_ERROR_INVALID_DATA;
456 }
457 return PLDM_SUCCESS;
458}
459
John Wangca230822019-10-16 11:39:27 +0800460int pldm_bios_table_attr_entry_integer_encode_check(
461 void *entry, size_t entry_length,
462 const struct pldm_bios_table_attr_entry_integer_info *info)
463{
464 POINTER_CHECK(entry);
465 POINTER_CHECK(info);
466 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
467 BUFFER_SIZE_EXPECT(entry_length, length);
John Wang827c5de2019-11-07 18:27:27 +0800468 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
469 PLDM_SUCCESS)
John Wangca230822019-10-16 11:39:27 +0800470 return PLDM_ERROR_INVALID_DATA;
471 pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
472 return PLDM_SUCCESS;
473}
474
John Wang49484a12019-12-02 14:21:53 +0800475static size_t attr_table_entry_length_integer(const void *entry)
John Wangca230822019-10-16 11:39:27 +0800476{
477 (void)entry;
478 return pldm_bios_table_attr_entry_integer_encode_length();
479}
480
John Wang49484a12019-12-02 14:21:53 +0800481struct table_entry_length {
John Wang02700402019-10-06 16:34:29 +0800482 uint8_t attr_type;
John Wang49484a12019-12-02 14:21:53 +0800483 size_t (*entry_length_handler)(const void *);
John Wang02700402019-10-06 16:34:29 +0800484};
485
John Wang49484a12019-12-02 14:21:53 +0800486#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
487
John Wangb6333cb2019-12-10 09:43:42 +0800488static const struct table_entry_length *find_table_entry_length_by_type(
489 uint8_t attr_type, const struct table_entry_length *handlers, size_t count)
John Wang49484a12019-12-02 14:21:53 +0800490{
491 size_t i;
492 for (i = 0; i < count; i++) {
493 if (attr_type == handlers[i].attr_type)
494 return &handlers[i];
495 }
496 return NULL;
497}
498
John Wangb6333cb2019-12-10 09:43:42 +0800499static const struct table_entry_length attr_table_entries[] = {
John Wang02700402019-10-06 16:34:29 +0800500 {.attr_type = PLDM_BIOS_ENUMERATION,
501 .entry_length_handler = attr_table_entry_length_enum},
502 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
503 .entry_length_handler = attr_table_entry_length_enum},
504 {.attr_type = PLDM_BIOS_STRING,
505 .entry_length_handler = attr_table_entry_length_string},
506 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
507 .entry_length_handler = attr_table_entry_length_string},
John Wangca230822019-10-16 11:39:27 +0800508 {.attr_type = PLDM_BIOS_INTEGER,
509 .entry_length_handler = attr_table_entry_length_integer},
510 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
511 .entry_length_handler = attr_table_entry_length_integer},
John Wang02700402019-10-06 16:34:29 +0800512};
513
John Wang02700402019-10-06 16:34:29 +0800514static size_t attr_table_entry_length(const void *table_entry)
515{
516 const struct pldm_bios_attr_table_entry *entry = table_entry;
John Wangb6333cb2019-12-10 09:43:42 +0800517 const struct table_entry_length *attr_table_entry =
John Wang49484a12019-12-02 14:21:53 +0800518 find_table_entry_length_by_type(entry->attr_type,
519 attr_table_entries,
520 ARRAY_SIZE(attr_table_entries));
John Wang02700402019-10-06 16:34:29 +0800521 assert(attr_table_entry != NULL);
522 assert(attr_table_entry->entry_length_handler != NULL);
523
524 return attr_table_entry->entry_length_handler(entry);
525}
526
John Wang3ad21752019-10-06 16:42:21 +0800527size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
528{
529 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
530 sizeof(count) + count;
531}
532
533void pldm_bios_table_attr_value_entry_encode_enum(
534 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
535 uint8_t count, uint8_t *handles)
536{
537 size_t length =
538 pldm_bios_table_attr_value_entry_encode_enum_length(count);
539 assert(length <= entry_length);
540
541 struct pldm_bios_attr_val_table_entry *table_entry = entry;
542 table_entry->attr_handle = htole16(attr_handle);
543 table_entry->attr_type = attr_type;
544 table_entry->value[0] = count;
545 if (count != 0)
546 memcpy(&table_entry->value[1], handles, count);
547}
548
John Wang49484a12019-12-02 14:21:53 +0800549uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
550 const struct pldm_bios_attr_val_table_entry *entry)
551{
552 return entry->value[0];
553}
554
John Wang3ad21752019-10-06 16:42:21 +0800555int pldm_bios_table_attr_value_entry_encode_enum_check(
556 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
557 uint8_t count, uint8_t *handles)
558{
559 POINTER_CHECK(entry);
560 if (count != 0 && handles == NULL)
561 return PLDM_ERROR_INVALID_DATA;
562 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
563 size_t length =
564 pldm_bios_table_attr_value_entry_encode_enum_length(count);
565 BUFFER_SIZE_EXPECT(entry_length, length);
566 pldm_bios_table_attr_value_entry_encode_enum(
567 entry, entry_length, attr_handle, attr_type, count, handles);
568 return PLDM_SUCCESS;
569}
570
John Wang49484a12019-12-02 14:21:53 +0800571static size_t attr_value_table_entry_length_enum(const void *entry)
572{
573 uint8_t number =
574 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
575 return pldm_bios_table_attr_value_entry_encode_enum_length(number);
576}
577
John Wang3ad21752019-10-06 16:42:21 +0800578size_t
579pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
580{
581 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
582 sizeof(string_length) + string_length;
583}
584
585void pldm_bios_table_attr_value_entry_encode_string(
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 size_t length =
590 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
591 assert(length <= entry_length);
592
593 struct pldm_bios_attr_val_table_entry *table_entry = entry;
594 table_entry->attr_handle = htole16(attr_handle);
595 table_entry->attr_type = attr_type;
596 if (str_length != 0)
597 memcpy(table_entry->value + sizeof(str_length), str,
598 str_length);
599 str_length = htole16(str_length);
600 memcpy(table_entry->value, &str_length, sizeof(str_length));
601}
602
John Wang49484a12019-12-02 14:21:53 +0800603uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
604 const struct pldm_bios_attr_val_table_entry *entry)
605{
606 uint16_t str_length = 0;
607 memcpy(&str_length, entry->value, sizeof(str_length));
608 return le16toh(str_length);
609}
610
John Wang3ad21752019-10-06 16:42:21 +0800611int pldm_bios_table_attr_value_entry_encode_string_check(
612 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
613 uint16_t str_length, const char *str)
614{
615 POINTER_CHECK(entry);
616 if (str_length != 0 && str == NULL)
617 return PLDM_ERROR_INVALID_DATA;
618 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
619 size_t length =
620 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
621 BUFFER_SIZE_EXPECT(entry_length, length);
622 pldm_bios_table_attr_value_entry_encode_string(
623 entry, entry_length, attr_handle, attr_type, str_length, str);
624 return PLDM_SUCCESS;
625}
626
John Wang49484a12019-12-02 14:21:53 +0800627static size_t attr_value_table_entry_length_string(const void *entry)
628{
629 uint16_t str_length =
630 pldm_bios_table_attr_value_entry_string_decode_length(entry);
631 return pldm_bios_table_attr_value_entry_encode_string_length(
632 str_length);
633}
634
John Wangca230822019-10-16 11:39:27 +0800635size_t pldm_bios_table_attr_value_entry_encode_integer_length()
636{
637 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
638 sizeof(uint64_t);
639}
640void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
641 size_t entry_length,
642 uint16_t attr_handle,
643 uint8_t attr_type,
644 uint64_t cv)
645{
646 size_t length =
647 pldm_bios_table_attr_value_entry_encode_integer_length();
648 assert(length <= entry_length);
649
650 struct pldm_bios_attr_val_table_entry *table_entry = entry;
651 table_entry->attr_handle = htole16(attr_handle);
652 table_entry->attr_type = attr_type;
653 cv = htole64(cv);
654 memcpy(table_entry->value, &cv, sizeof(uint64_t));
655}
656
657int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
658 size_t entry_length,
659 uint16_t attr_handle,
660 uint8_t attr_type,
661 uint64_t cv)
662{
663 POINTER_CHECK(entry);
664 size_t length =
665 pldm_bios_table_attr_value_entry_encode_integer_length();
666 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
667 BUFFER_SIZE_EXPECT(entry_length, length);
668 pldm_bios_table_attr_value_entry_encode_integer(
669 entry, entry_length, attr_handle, attr_type, cv);
670 return PLDM_SUCCESS;
671}
672
John Wang49484a12019-12-02 14:21:53 +0800673static size_t attr_value_table_entry_length_integer(const void *entry)
674{
675 (void)entry;
676 return pldm_bios_table_attr_value_entry_encode_integer_length();
677}
678
John Wangb6333cb2019-12-10 09:43:42 +0800679static const struct table_entry_length attr_value_table_entries[] = {
John Wang49484a12019-12-02 14:21:53 +0800680 {.attr_type = PLDM_BIOS_ENUMERATION,
681 .entry_length_handler = attr_value_table_entry_length_enum},
682 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
683 .entry_length_handler = attr_value_table_entry_length_enum},
684 {.attr_type = PLDM_BIOS_STRING,
685 .entry_length_handler = attr_value_table_entry_length_string},
686 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
687 .entry_length_handler = attr_value_table_entry_length_string},
688 {.attr_type = PLDM_BIOS_INTEGER,
689 .entry_length_handler = attr_value_table_entry_length_integer},
690 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
691 .entry_length_handler = attr_value_table_entry_length_integer},
692};
693
694static size_t attr_value_table_entry_length(const void *table_entry)
695{
696 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
John Wangb6333cb2019-12-10 09:43:42 +0800697 const struct table_entry_length *entry_length =
John Wang49484a12019-12-02 14:21:53 +0800698 find_table_entry_length_by_type(
699 entry->attr_type, attr_value_table_entries,
700 ARRAY_SIZE(attr_value_table_entries));
701 assert(entry_length != NULL);
702 assert(entry_length->entry_length_handler != NULL);
703
704 return entry_length->entry_length_handler(entry);
705}
706
John Wang8e877e02020-02-03 16:06:55 +0800707size_t pldm_bios_table_attr_value_entry_length(
708 const struct pldm_bios_attr_val_table_entry *entry)
709{
710 return attr_value_table_entry_length(entry);
711}
712
John Wang3342adb2019-11-29 16:03:58 +0800713uint16_t pldm_bios_table_attr_value_entry_decode_handle(
714 const struct pldm_bios_attr_val_table_entry *entry)
715{
716 return le16toh(entry->attr_handle);
717}
718
John Wang79c37f12019-10-31 15:46:31 +0800719static size_t pad_size_get(size_t size_without_pad)
720{
721 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
722}
723
724static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
725{
726 while (pad_size--)
727 *table_end++ = 0;
728
729 return table_end;
730}
731
732static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
733{
734 checksum = htole32(checksum);
735 memcpy(table_end, &checksum, sizeof(checksum));
736
737 return table_end + sizeof(checksum);
738}
739
740size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
741{
742 size_t size = pad_size_get(size_without_pad) +
743 sizeof(uint32_t) /*sizeof(checksum)*/;
744 return size;
745}
746
John Wang871c9272019-12-09 18:02:15 +0800747size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
748 size_t size_without_pad)
John Wang79c37f12019-10-31 15:46:31 +0800749{
750
751 size_t pad_checksum_size =
752 pldm_bios_table_pad_checksum_size(size_without_pad);
John Wang871c9272019-12-09 18:02:15 +0800753 size_t total_length = size_without_pad + pad_checksum_size;
754 assert(size >= total_length);
John Wang79c37f12019-10-31 15:46:31 +0800755
756 uint8_t *table_end = (uint8_t *)table + size_without_pad;
757 size_t pad_size = pad_size_get(size_without_pad);
758 table_end = pad_append(table_end, pad_size);
759
760 uint32_t checksum = crc32(table, size_without_pad + pad_size);
761 checksum_append(table_end, checksum);
John Wang871c9272019-12-09 18:02:15 +0800762
763 return total_length;
John Wang79c37f12019-10-31 15:46:31 +0800764}
765
John Wang02700402019-10-06 16:34:29 +0800766struct pldm_bios_table_iter {
767 const uint8_t *table_data;
768 size_t table_len;
769 size_t current_pos;
770 size_t (*entry_length_handler)(const void *table_entry);
771};
772
773struct pldm_bios_table_iter *
774pldm_bios_table_iter_create(const void *table, size_t length,
775 enum pldm_bios_table_types type)
776{
777 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
778 assert(iter != NULL);
779 iter->table_data = table;
780 iter->table_len = length;
781 iter->current_pos = 0;
782 iter->entry_length_handler = NULL;
783 switch (type) {
784 case PLDM_BIOS_STRING_TABLE:
John Wangdd9a6282019-10-11 18:52:46 +0800785 iter->entry_length_handler = string_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800786 break;
787 case PLDM_BIOS_ATTR_TABLE:
788 iter->entry_length_handler = attr_table_entry_length;
789 break;
790 case PLDM_BIOS_ATTR_VAL_TABLE:
John Wang49484a12019-12-02 14:21:53 +0800791 iter->entry_length_handler = attr_value_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800792 break;
793 }
794
795 return iter;
796}
797
798void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
799{
800 free(iter);
801}
802
803#define pad_and_check_max 7
804bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
805{
806 if (iter->table_len - iter->current_pos <= pad_and_check_max)
807 return true;
808 return false;
809}
810
811void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
812{
813 if (pldm_bios_table_iter_is_end(iter))
814 return;
815 const void *entry = iter->table_data + iter->current_pos;
816 iter->current_pos += iter->entry_length_handler(entry);
817}
818
819const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
820{
821 return iter->table_data + iter->current_pos;
John Wang3ad21752019-10-06 16:42:21 +0800822}
John Wangdd9a6282019-10-11 18:52:46 +0800823
John Wang3342adb2019-11-29 16:03:58 +0800824typedef bool (*equal_handler)(const void *entry, const void *key);
825
John Wangdd9a6282019-10-11 18:52:46 +0800826static const void *
John Wang3342adb2019-11-29 16:03:58 +0800827pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
828 const void *key, equal_handler equal)
John Wangdd9a6282019-10-11 18:52:46 +0800829{
830 const void *entry;
831 while (!pldm_bios_table_iter_is_end(iter)) {
832 entry = pldm_bios_table_iter_value(iter);
833 if (equal(entry, key))
834 return entry;
835 pldm_bios_table_iter_next(iter);
836 }
837 return NULL;
838}
839
John Wang3342adb2019-11-29 16:03:58 +0800840static const void *
841pldm_bios_table_entry_find_from_table(const void *table, size_t length,
842 enum pldm_bios_table_types type,
843 equal_handler equal, const void *key)
844{
845 struct pldm_bios_table_iter *iter =
846 pldm_bios_table_iter_create(table, length, type);
847 const void *entry =
848 pldm_bios_table_entry_find_by_iter(iter, key, equal);
849 pldm_bios_table_iter_free(iter);
850 return entry;
851}
852
853static bool string_table_handle_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +0800854{
855 const struct pldm_bios_string_table_entry *string_entry = entry;
856 uint16_t handle = *(uint16_t *)key;
857 if (pldm_bios_table_string_entry_decode_handle(string_entry) == handle)
858 return true;
859 return false;
860}
861
John Wang3342adb2019-11-29 16:03:58 +0800862const struct pldm_bios_string_table_entry *
863pldm_bios_table_string_find_by_handle(const void *table, size_t length,
864 uint16_t handle)
865{
866 return pldm_bios_table_entry_find_from_table(
867 table, length, PLDM_BIOS_STRING_TABLE, string_table_handle_equal,
868 &handle);
869}
870
John Wangdd9a6282019-10-11 18:52:46 +0800871struct string_equal_arg {
872 uint16_t str_length;
873 const char *str;
874};
875
John Wang3342adb2019-11-29 16:03:58 +0800876static bool string_table_string_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +0800877{
878 const struct pldm_bios_string_table_entry *string_entry = entry;
879 const struct string_equal_arg *arg = key;
880 if (arg->str_length !=
881 pldm_bios_table_string_entry_decode_string_length(string_entry))
882 return false;
883 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0)
884 return false;
885 return true;
886}
887
888const struct pldm_bios_string_table_entry *
889pldm_bios_table_string_find_by_string(const void *table, size_t length,
890 const char *str)
891{
892 uint16_t str_length = strlen(str);
893 struct string_equal_arg arg = {str_length, str};
John Wang3342adb2019-11-29 16:03:58 +0800894 return pldm_bios_table_entry_find_from_table(
895 table, length, PLDM_BIOS_STRING_TABLE, string_table_string_equal,
896 &arg);
John Wangdd9a6282019-10-11 18:52:46 +0800897}
898
John Wang3342adb2019-11-29 16:03:58 +0800899static bool attr_value_table_handle_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +0800900{
John Wang3342adb2019-11-29 16:03:58 +0800901 uint16_t handle = *(uint16_t *)key;
902 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
903}
904
905const struct pldm_bios_attr_val_table_entry *
906pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
907 uint16_t handle)
908{
909 return pldm_bios_table_entry_find_from_table(
910 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
911 attr_value_table_handle_equal, &handle);
John Wangdd9a6282019-10-11 18:52:46 +0800912}
John Wang871c9272019-12-09 18:02:15 +0800913
914int pldm_bios_table_attr_value_copy_and_update(
915 const void *src_table, size_t src_length, void *dest_table,
916 size_t *dest_length, const void *entry, size_t entry_length)
917{
918 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
919 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
920
921 int rc = PLDM_SUCCESS;
922 const struct pldm_bios_attr_val_table_entry *tmp;
923 size_t buffer_length = *dest_length, copied_length = 0, length = 0;
924 while (!pldm_bios_table_iter_is_end(iter)) {
925 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
926 length = attr_value_table_entry_length(tmp);
927
928 /* we need the tmp's entry_length here, iter_next will calculate
929 * it too, use current_pos directly to avoid calculating it
930 * twice */
931 iter->current_pos += length;
932 if (tmp->attr_handle ==
933 ((const struct pldm_bios_attr_val_table_entry *)entry)
934 ->attr_handle) {
935 if (attribute_is_readonly(tmp->attr_type)) {
936 rc = PLDM_ERROR_INVALID_DATA;
937 goto out;
938 }
939 length = entry_length;
940 tmp = entry;
941 }
942 if (copied_length + length > buffer_length) {
943 rc = PLDM_ERROR_INVALID_LENGTH;
944 goto out;
945 }
946 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
947 copied_length += length;
948 }
949
950 size_t pad_checksum_size =
951 pldm_bios_table_pad_checksum_size(copied_length);
952 if ((pad_checksum_size + copied_length) > buffer_length) {
953 rc = PLDM_ERROR_INVALID_LENGTH;
954 goto out;
955 }
956
957 *dest_length = pldm_bios_table_append_pad_checksum(
958 dest_table, buffer_length, copied_length);
959out:
960 pldm_bios_table_iter_free(iter);
961 return rc;
962}