blob: 89f724184beb98bae6dfff392f8e24077fde95b3 [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 Wang02700402019-10-06 16:34:29 +080029uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
30 const struct pldm_bios_attr_table_entry *entry)
31{
32 return entry->metadata[0];
33}
34
35int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
36 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
37{
38 POINTER_CHECK(entry);
39 POINTER_CHECK(pv_num);
40 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
41 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
42 return PLDM_SUCCESS;
43}
44
45uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
46 const struct pldm_bios_attr_table_entry *entry)
47{
48 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
49 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
50 sizeof(uint16_t) * pv_num];
51}
52
53int pldm_bios_table_attr_entry_enum_decode_def_num_check(
54 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
55{
56 POINTER_CHECK(entry);
57 POINTER_CHECK(def_num);
58 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
59 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
60 return PLDM_SUCCESS;
61}
62
John Wang3ad21752019-10-06 16:42:21 +080063uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
64 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
65 uint8_t pv_num)
66{
67 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
68 num = num < pv_num ? num : pv_num;
69 size_t i;
70 for (i = 0; i < num; i++) {
71 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
72 i * sizeof(uint16_t));
73 pv_hdls[i] = le16toh(*hdl);
74 }
75 return num;
76}
77
78int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
79 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
80 uint8_t pv_num)
81{
82 POINTER_CHECK(entry);
83 POINTER_CHECK(pv_hdls);
84 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
85 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
86 if (num != pv_num)
87 return PLDM_ERROR_INVALID_DATA;
88 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
89 return PLDM_SUCCESS;
90}
91
John Wang02700402019-10-06 16:34:29 +080092/** @brief Get length of an enum attribute entry
93 */
94static size_t
95attr_table_entry_length_enum(const struct pldm_bios_attr_table_entry *entry)
96{
97 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
98 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
99 return sizeof(*entry) - 1 + sizeof(pv_num) + pv_num * sizeof(uint16_t) +
100 sizeof(def_num) + def_num;
101}
102
103#define ATTR_ENTRY_STRING_LENGTH_MIN \
104 sizeof(uint8_t) /* string type */ + \
105 sizeof(uint16_t) /* minimum string length */ + \
106 sizeof(uint16_t) /* maximum string length */ + \
107 sizeof(uint16_t) /* default string length */
108
109uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
110 const struct pldm_bios_attr_table_entry *entry)
111{
112 int def_string_pos = ATTR_ENTRY_STRING_LENGTH_MIN - sizeof(uint16_t);
113 uint16_t def_string_length =
114 *(uint16_t *)(entry->metadata + def_string_pos);
115 return le16toh(def_string_length);
116}
117
118int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
119 const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
120{
121 POINTER_CHECK(entry);
122 POINTER_CHECK(def_string_length);
123 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
124 *def_string_length =
125 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
126 return PLDM_SUCCESS;
127}
128
129/** @brief Get length of a string attribute entry
130 */
131static size_t
132attr_table_entry_length_string(const struct pldm_bios_attr_table_entry *entry)
133{
134 uint16_t def_string_len =
135 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
136 return sizeof(*entry) - 1 + ATTR_ENTRY_STRING_LENGTH_MIN +
137 def_string_len;
138}
139
140struct attr_table_entry {
141 uint8_t attr_type;
142 size_t (*entry_length_handler)(
143 const struct pldm_bios_attr_table_entry *);
144};
145
146static struct attr_table_entry attr_table_entrys[] = {
147 {.attr_type = PLDM_BIOS_ENUMERATION,
148 .entry_length_handler = attr_table_entry_length_enum},
149 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
150 .entry_length_handler = attr_table_entry_length_enum},
151 {.attr_type = PLDM_BIOS_STRING,
152 .entry_length_handler = attr_table_entry_length_string},
153 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
154 .entry_length_handler = attr_table_entry_length_string},
155};
156
157#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
158
159static struct attr_table_entry *find_attr_table_entry_by_type(uint8_t attr_type)
160{
161 size_t i;
162 for (i = 0; i < ARRAY_SIZE(attr_table_entrys); i++) {
163 if (attr_type == attr_table_entrys[i].attr_type)
164 return &attr_table_entrys[i];
165 }
166 return NULL;
167}
168
169static size_t attr_table_entry_length(const void *table_entry)
170{
171 const struct pldm_bios_attr_table_entry *entry = table_entry;
172 struct attr_table_entry *attr_table_entry =
173 find_attr_table_entry_by_type(entry->attr_type);
174 assert(attr_table_entry != NULL);
175 assert(attr_table_entry->entry_length_handler != NULL);
176
177 return attr_table_entry->entry_length_handler(entry);
178}
179
John Wang3ad21752019-10-06 16:42:21 +0800180size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
181{
182 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
183 sizeof(count) + count;
184}
185
186void pldm_bios_table_attr_value_entry_encode_enum(
187 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
188 uint8_t count, uint8_t *handles)
189{
190 size_t length =
191 pldm_bios_table_attr_value_entry_encode_enum_length(count);
192 assert(length <= entry_length);
193
194 struct pldm_bios_attr_val_table_entry *table_entry = entry;
195 table_entry->attr_handle = htole16(attr_handle);
196 table_entry->attr_type = attr_type;
197 table_entry->value[0] = count;
198 if (count != 0)
199 memcpy(&table_entry->value[1], handles, count);
200}
201
202int pldm_bios_table_attr_value_entry_encode_enum_check(
203 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
204 uint8_t count, uint8_t *handles)
205{
206 POINTER_CHECK(entry);
207 if (count != 0 && handles == NULL)
208 return PLDM_ERROR_INVALID_DATA;
209 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
210 size_t length =
211 pldm_bios_table_attr_value_entry_encode_enum_length(count);
212 BUFFER_SIZE_EXPECT(entry_length, length);
213 pldm_bios_table_attr_value_entry_encode_enum(
214 entry, entry_length, attr_handle, attr_type, count, handles);
215 return PLDM_SUCCESS;
216}
217
218size_t
219pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
220{
221 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
222 sizeof(string_length) + string_length;
223}
224
225void pldm_bios_table_attr_value_entry_encode_string(
226 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
227 uint16_t str_length, const char *str)
228{
229 size_t length =
230 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
231 assert(length <= entry_length);
232
233 struct pldm_bios_attr_val_table_entry *table_entry = entry;
234 table_entry->attr_handle = htole16(attr_handle);
235 table_entry->attr_type = attr_type;
236 if (str_length != 0)
237 memcpy(table_entry->value + sizeof(str_length), str,
238 str_length);
239 str_length = htole16(str_length);
240 memcpy(table_entry->value, &str_length, sizeof(str_length));
241}
242
243int pldm_bios_table_attr_value_entry_encode_string_check(
244 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
245 uint16_t str_length, const char *str)
246{
247 POINTER_CHECK(entry);
248 if (str_length != 0 && str == NULL)
249 return PLDM_ERROR_INVALID_DATA;
250 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
251 size_t length =
252 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
253 BUFFER_SIZE_EXPECT(entry_length, length);
254 pldm_bios_table_attr_value_entry_encode_string(
255 entry, entry_length, attr_handle, attr_type, str_length, str);
256 return PLDM_SUCCESS;
257}
258
John Wang02700402019-10-06 16:34:29 +0800259struct pldm_bios_table_iter {
260 const uint8_t *table_data;
261 size_t table_len;
262 size_t current_pos;
263 size_t (*entry_length_handler)(const void *table_entry);
264};
265
266struct pldm_bios_table_iter *
267pldm_bios_table_iter_create(const void *table, size_t length,
268 enum pldm_bios_table_types type)
269{
270 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
271 assert(iter != NULL);
272 iter->table_data = table;
273 iter->table_len = length;
274 iter->current_pos = 0;
275 iter->entry_length_handler = NULL;
276 switch (type) {
277 case PLDM_BIOS_STRING_TABLE:
278 break;
279 case PLDM_BIOS_ATTR_TABLE:
280 iter->entry_length_handler = attr_table_entry_length;
281 break;
282 case PLDM_BIOS_ATTR_VAL_TABLE:
283 break;
284 }
285
286 return iter;
287}
288
289void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
290{
291 free(iter);
292}
293
294#define pad_and_check_max 7
295bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
296{
297 if (iter->table_len - iter->current_pos <= pad_and_check_max)
298 return true;
299 return false;
300}
301
302void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
303{
304 if (pldm_bios_table_iter_is_end(iter))
305 return;
306 const void *entry = iter->table_data + iter->current_pos;
307 iter->current_pos += iter->entry_length_handler(entry);
308}
309
310const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
311{
312 return iter->table_data + iter->current_pos;
John Wang3ad21752019-10-06 16:42:21 +0800313}