blob: d9c25056db3e33a472e95cae2a285b0089adf1a9 [file] [log] [blame]
John Wang02700402019-10-06 16:34:29 +08001#include <assert.h>
2#include <endian.h>
3#include <stdbool.h>
4#include <stdint.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "bios.h"
9#include "bios_table.h"
10
11#define POINTER_CHECK(pointer) \
12 do { \
13 if (pointer == NULL) \
14 return PLDM_ERROR_INVALID_DATA; \
15 } while (0)
16
17#define ATTR_TYPE_EXPECT(type, expected) \
18 do { \
19 if (type != expected && type != (expected | 0x80)) \
20 return PLDM_ERROR_INVALID_DATA; \
21 } while (0)
22
John Wang3ad21752019-10-06 16:42:21 +080023#define BUFFER_SIZE_EXPECT(current_size, expected_size) \
24 do { \
25 if (current_size < expected_size) \
26 return PLDM_ERROR_INVALID_LENGTH; \
27 } while (0)
28
John Wangdd9a6282019-10-11 18:52:46 +080029#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
30
31static uint16_t get_bios_string_handle()
32{
33 static uint16_t handle = 0;
34 assert(handle != UINT16_MAX);
35
36 return handle++;
37}
38
39size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
40{
41 return sizeof(struct pldm_bios_string_table_entry) -
42 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
43}
44
45void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
46 const char *str, uint16_t str_length)
47{
48 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
49 assert(length <= entry_length);
50 struct pldm_bios_string_table_entry *string_entry = entry;
51 string_entry->string_handle = htole16(get_bios_string_handle());
52 string_entry->string_length = htole16(str_length);
53 memcpy(string_entry->name, str, str_length);
54}
55
56int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
57 const char *str,
58 uint16_t str_length)
59{
60 if (str_length == 0)
61 return PLDM_ERROR_INVALID_DATA;
62 POINTER_CHECK(entry);
63 POINTER_CHECK(str);
64 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
65 BUFFER_SIZE_EXPECT(entry_length, length);
66 pldm_bios_table_string_entry_encode(entry, entry_length, str,
67 str_length);
68 return PLDM_SUCCESS;
69}
70
71uint16_t pldm_bios_table_string_entry_decode_handle(
72 const struct pldm_bios_string_table_entry *entry)
73{
74 return le16toh(entry->string_handle);
75}
76
77uint16_t pldm_bios_table_string_entry_decode_string_length(
78 const struct pldm_bios_string_table_entry *entry)
79{
80 return le16toh(entry->string_length);
81}
82
83uint16_t pldm_bios_table_string_entry_decode_string(
84 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
85{
86 uint16_t length =
87 pldm_bios_table_string_entry_decode_string_length(entry);
88 length = length < size ? length : size;
89 memcpy(buffer, entry->name, length);
90 buffer[length] = 0;
91 return length;
92}
93
94int pldm_bios_table_string_entry_decode_string_check(
95 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
96{
97 POINTER_CHECK(entry);
98 POINTER_CHECK(buffer);
99 size_t length =
100 pldm_bios_table_string_entry_decode_string_length(entry);
101 BUFFER_SIZE_EXPECT(size, length + 1);
102 pldm_bios_table_string_entry_decode_string(entry, buffer, size);
103 return PLDM_SUCCESS;
104}
105
106static size_t string_table_entry_length(const void *table_entry)
107{
108 const struct pldm_bios_string_table_entry *entry = table_entry;
109 return sizeof(*entry) - sizeof(entry->name) +
110 pldm_bios_table_string_entry_decode_string_length(entry);
111}
112
113#define ATTR_TYPE_EXPECT(type, expected) \
114 do { \
115 if (type != expected && type != (expected | 0x80)) \
116 return PLDM_ERROR_INVALID_DATA; \
117 } while (0)
118
John Wang02700402019-10-06 16:34:29 +0800119uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
120 const struct pldm_bios_attr_table_entry *entry)
121{
122 return entry->metadata[0];
123}
124
125int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
126 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
127{
128 POINTER_CHECK(entry);
129 POINTER_CHECK(pv_num);
130 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
131 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
132 return PLDM_SUCCESS;
133}
134
135uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
136 const struct pldm_bios_attr_table_entry *entry)
137{
138 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
139 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
140 sizeof(uint16_t) * pv_num];
141}
142
143int pldm_bios_table_attr_entry_enum_decode_def_num_check(
144 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
145{
146 POINTER_CHECK(entry);
147 POINTER_CHECK(def_num);
148 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
149 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
150 return PLDM_SUCCESS;
151}
152
John Wang3ad21752019-10-06 16:42:21 +0800153uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
154 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
155 uint8_t pv_num)
156{
157 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
158 num = num < pv_num ? num : pv_num;
159 size_t i;
160 for (i = 0; i < num; i++) {
161 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
162 i * sizeof(uint16_t));
163 pv_hdls[i] = le16toh(*hdl);
164 }
165 return num;
166}
167
168int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
169 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
170 uint8_t pv_num)
171{
172 POINTER_CHECK(entry);
173 POINTER_CHECK(pv_hdls);
174 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
175 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
176 if (num != pv_num)
177 return PLDM_ERROR_INVALID_DATA;
178 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
179 return PLDM_SUCCESS;
180}
181
John Wang02700402019-10-06 16:34:29 +0800182/** @brief Get length of an enum attribute entry
183 */
184static size_t
185attr_table_entry_length_enum(const struct pldm_bios_attr_table_entry *entry)
186{
187 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
188 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
189 return sizeof(*entry) - 1 + sizeof(pv_num) + pv_num * sizeof(uint16_t) +
190 sizeof(def_num) + def_num;
191}
192
193#define ATTR_ENTRY_STRING_LENGTH_MIN \
194 sizeof(uint8_t) /* string type */ + \
195 sizeof(uint16_t) /* minimum string length */ + \
196 sizeof(uint16_t) /* maximum string length */ + \
197 sizeof(uint16_t) /* default string length */
198
199uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
200 const struct pldm_bios_attr_table_entry *entry)
201{
202 int def_string_pos = ATTR_ENTRY_STRING_LENGTH_MIN - sizeof(uint16_t);
203 uint16_t def_string_length =
204 *(uint16_t *)(entry->metadata + def_string_pos);
205 return le16toh(def_string_length);
206}
207
208int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
209 const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
210{
211 POINTER_CHECK(entry);
212 POINTER_CHECK(def_string_length);
213 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
214 *def_string_length =
215 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
216 return PLDM_SUCCESS;
217}
218
219/** @brief Get length of a string attribute entry
220 */
221static size_t
222attr_table_entry_length_string(const struct pldm_bios_attr_table_entry *entry)
223{
224 uint16_t def_string_len =
225 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
226 return sizeof(*entry) - 1 + ATTR_ENTRY_STRING_LENGTH_MIN +
227 def_string_len;
228}
229
230struct attr_table_entry {
231 uint8_t attr_type;
232 size_t (*entry_length_handler)(
233 const struct pldm_bios_attr_table_entry *);
234};
235
236static struct attr_table_entry attr_table_entrys[] = {
237 {.attr_type = PLDM_BIOS_ENUMERATION,
238 .entry_length_handler = attr_table_entry_length_enum},
239 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
240 .entry_length_handler = attr_table_entry_length_enum},
241 {.attr_type = PLDM_BIOS_STRING,
242 .entry_length_handler = attr_table_entry_length_string},
243 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
244 .entry_length_handler = attr_table_entry_length_string},
245};
246
247#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
248
249static struct attr_table_entry *find_attr_table_entry_by_type(uint8_t attr_type)
250{
251 size_t i;
252 for (i = 0; i < ARRAY_SIZE(attr_table_entrys); i++) {
253 if (attr_type == attr_table_entrys[i].attr_type)
254 return &attr_table_entrys[i];
255 }
256 return NULL;
257}
258
259static size_t attr_table_entry_length(const void *table_entry)
260{
261 const struct pldm_bios_attr_table_entry *entry = table_entry;
262 struct attr_table_entry *attr_table_entry =
263 find_attr_table_entry_by_type(entry->attr_type);
264 assert(attr_table_entry != NULL);
265 assert(attr_table_entry->entry_length_handler != NULL);
266
267 return attr_table_entry->entry_length_handler(entry);
268}
269
John Wang3ad21752019-10-06 16:42:21 +0800270size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
271{
272 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
273 sizeof(count) + count;
274}
275
276void pldm_bios_table_attr_value_entry_encode_enum(
277 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
278 uint8_t count, uint8_t *handles)
279{
280 size_t length =
281 pldm_bios_table_attr_value_entry_encode_enum_length(count);
282 assert(length <= entry_length);
283
284 struct pldm_bios_attr_val_table_entry *table_entry = entry;
285 table_entry->attr_handle = htole16(attr_handle);
286 table_entry->attr_type = attr_type;
287 table_entry->value[0] = count;
288 if (count != 0)
289 memcpy(&table_entry->value[1], handles, count);
290}
291
292int pldm_bios_table_attr_value_entry_encode_enum_check(
293 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
294 uint8_t count, uint8_t *handles)
295{
296 POINTER_CHECK(entry);
297 if (count != 0 && handles == NULL)
298 return PLDM_ERROR_INVALID_DATA;
299 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
300 size_t length =
301 pldm_bios_table_attr_value_entry_encode_enum_length(count);
302 BUFFER_SIZE_EXPECT(entry_length, length);
303 pldm_bios_table_attr_value_entry_encode_enum(
304 entry, entry_length, attr_handle, attr_type, count, handles);
305 return PLDM_SUCCESS;
306}
307
308size_t
309pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
310{
311 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
312 sizeof(string_length) + string_length;
313}
314
315void pldm_bios_table_attr_value_entry_encode_string(
316 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
317 uint16_t str_length, const char *str)
318{
319 size_t length =
320 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
321 assert(length <= entry_length);
322
323 struct pldm_bios_attr_val_table_entry *table_entry = entry;
324 table_entry->attr_handle = htole16(attr_handle);
325 table_entry->attr_type = attr_type;
326 if (str_length != 0)
327 memcpy(table_entry->value + sizeof(str_length), str,
328 str_length);
329 str_length = htole16(str_length);
330 memcpy(table_entry->value, &str_length, sizeof(str_length));
331}
332
333int pldm_bios_table_attr_value_entry_encode_string_check(
334 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
335 uint16_t str_length, const char *str)
336{
337 POINTER_CHECK(entry);
338 if (str_length != 0 && str == NULL)
339 return PLDM_ERROR_INVALID_DATA;
340 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
341 size_t length =
342 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
343 BUFFER_SIZE_EXPECT(entry_length, length);
344 pldm_bios_table_attr_value_entry_encode_string(
345 entry, entry_length, attr_handle, attr_type, str_length, str);
346 return PLDM_SUCCESS;
347}
348
John Wang02700402019-10-06 16:34:29 +0800349struct pldm_bios_table_iter {
350 const uint8_t *table_data;
351 size_t table_len;
352 size_t current_pos;
353 size_t (*entry_length_handler)(const void *table_entry);
354};
355
356struct pldm_bios_table_iter *
357pldm_bios_table_iter_create(const void *table, size_t length,
358 enum pldm_bios_table_types type)
359{
360 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
361 assert(iter != NULL);
362 iter->table_data = table;
363 iter->table_len = length;
364 iter->current_pos = 0;
365 iter->entry_length_handler = NULL;
366 switch (type) {
367 case PLDM_BIOS_STRING_TABLE:
John Wangdd9a6282019-10-11 18:52:46 +0800368 iter->entry_length_handler = string_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800369 break;
370 case PLDM_BIOS_ATTR_TABLE:
371 iter->entry_length_handler = attr_table_entry_length;
372 break;
373 case PLDM_BIOS_ATTR_VAL_TABLE:
374 break;
375 }
376
377 return iter;
378}
379
380void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
381{
382 free(iter);
383}
384
385#define pad_and_check_max 7
386bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
387{
388 if (iter->table_len - iter->current_pos <= pad_and_check_max)
389 return true;
390 return false;
391}
392
393void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
394{
395 if (pldm_bios_table_iter_is_end(iter))
396 return;
397 const void *entry = iter->table_data + iter->current_pos;
398 iter->current_pos += iter->entry_length_handler(entry);
399}
400
401const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
402{
403 return iter->table_data + iter->current_pos;
John Wang3ad21752019-10-06 16:42:21 +0800404}
John Wangdd9a6282019-10-11 18:52:46 +0800405
406static const void *
407pldm_bios_table_entry_find(struct pldm_bios_table_iter *iter, const void *key,
408 int (*equal)(const void *entry, const void *key))
409{
410 const void *entry;
411 while (!pldm_bios_table_iter_is_end(iter)) {
412 entry = pldm_bios_table_iter_value(iter);
413 if (equal(entry, key))
414 return entry;
415 pldm_bios_table_iter_next(iter);
416 }
417 return NULL;
418}
419
420static int string_table_handle_equal(const void *entry, const void *key)
421{
422 const struct pldm_bios_string_table_entry *string_entry = entry;
423 uint16_t handle = *(uint16_t *)key;
424 if (pldm_bios_table_string_entry_decode_handle(string_entry) == handle)
425 return true;
426 return false;
427}
428
429struct string_equal_arg {
430 uint16_t str_length;
431 const char *str;
432};
433
434static int string_table_string_equal(const void *entry, const void *key)
435{
436 const struct pldm_bios_string_table_entry *string_entry = entry;
437 const struct string_equal_arg *arg = key;
438 if (arg->str_length !=
439 pldm_bios_table_string_entry_decode_string_length(string_entry))
440 return false;
441 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0)
442 return false;
443 return true;
444}
445
446const struct pldm_bios_string_table_entry *
447pldm_bios_table_string_find_by_string(const void *table, size_t length,
448 const char *str)
449{
450 uint16_t str_length = strlen(str);
451 struct string_equal_arg arg = {str_length, str};
452 struct pldm_bios_table_iter *iter =
453 pldm_bios_table_iter_create(table, length, PLDM_BIOS_STRING_TABLE);
454 const void *entry =
455 pldm_bios_table_entry_find(iter, &arg, string_table_string_equal);
456 pldm_bios_table_iter_free(iter);
457 return entry;
458}
459
460const struct pldm_bios_string_table_entry *
461pldm_bios_table_string_find_by_handle(const void *table, size_t length,
462 uint16_t handle)
463{
464 struct pldm_bios_table_iter *iter =
465 pldm_bios_table_iter_create(table, length, PLDM_BIOS_STRING_TABLE);
466 const void *entry = pldm_bios_table_entry_find(
467 iter, &handle, string_table_handle_equal);
468 pldm_bios_table_iter_free(iter);
469 return entry;
470}