blob: ceb26b1ee6e30cfba72f1657872d7bd82376614f [file] [log] [blame]
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05301#include "bios_table.h"
2#include "base.h"
3#include "bios.h"
4#include "utils.h"
Andrew Jeffery9c766792022-08-10 23:12:49 +09305#include <assert.h>
6#include <endian.h>
7#include <stdbool.h>
8#include <stdint.h>
9#include <stdlib.h>
10#include <string.h>
11
Andrew Jeffery9c766792022-08-10 23:12:49 +093012#define POINTER_CHECK(pointer) \
13 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093014 if ((pointer) == NULL) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093015 return PLDM_ERROR_INVALID_DATA; \
16 } while (0)
17
18#define ATTR_TYPE_EXPECT(type, expected) \
19 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093020 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093021 return PLDM_ERROR_INVALID_DATA; \
22 } while (0)
23
24#define BUFFER_SIZE_EXPECT(current_size, expected_size) \
25 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093026 if ((current_size) < (expected_size)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093027 return PLDM_ERROR_INVALID_LENGTH; \
28 } while (0)
29
30#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
31
32static void set_errmsg(const char **errmsg, const char *msg)
33{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093034 if (errmsg != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093035 *errmsg = msg;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093036 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093037}
38
Andrew Jeffery319304f2023-04-05 13:53:18 +093039static uint16_t get_bios_string_handle(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +093040{
41 static uint16_t handle = 0;
42 assert(handle != UINT16_MAX);
43
44 return handle++;
45}
46
47size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
48{
49 return sizeof(struct pldm_bios_string_table_entry) -
50 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
51}
52
53void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
54 const char *str, uint16_t str_length)
55{
56 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
57 assert(length <= entry_length);
58 struct pldm_bios_string_table_entry *string_entry = entry;
59 string_entry->string_handle = htole16(get_bios_string_handle());
60 string_entry->string_length = htole16(str_length);
61 memcpy(string_entry->name, str, str_length);
62}
63
64int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
65 const char *str,
66 uint16_t str_length)
67{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093068 if (str_length == 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093069 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093070 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093071 POINTER_CHECK(entry);
72 POINTER_CHECK(str);
73 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
74 BUFFER_SIZE_EXPECT(entry_length, length);
75 pldm_bios_table_string_entry_encode(entry, entry_length, str,
76 str_length);
77 return PLDM_SUCCESS;
78}
79
80uint16_t pldm_bios_table_string_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093081 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093082{
83 return le16toh(entry->string_handle);
84}
85
86uint16_t pldm_bios_table_string_entry_decode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093087 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093088{
89 return le16toh(entry->string_length);
90}
91
92uint16_t pldm_bios_table_string_entry_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093093 const struct pldm_bios_string_table_entry *entry, char *buffer,
94 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +093095{
96 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093097 pldm_bios_table_string_entry_decode_string_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +093098 length = length < (size - 1) ? length : (size - 1);
99 memcpy(buffer, entry->name, length);
100 buffer[length] = 0;
101 return length;
102}
103
104int pldm_bios_table_string_entry_decode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930105 const struct pldm_bios_string_table_entry *entry, char *buffer,
106 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930107{
108 POINTER_CHECK(entry);
109 POINTER_CHECK(buffer);
110 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930111 pldm_bios_table_string_entry_decode_string_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930112 BUFFER_SIZE_EXPECT(size, length + 1);
113 pldm_bios_table_string_entry_decode_string(entry, buffer, size);
114 return PLDM_SUCCESS;
115}
116
117static size_t string_table_entry_length(const void *table_entry)
118{
119 const struct pldm_bios_string_table_entry *entry = table_entry;
120 return sizeof(*entry) - sizeof(entry->name) +
121 pldm_bios_table_string_entry_decode_string_length(entry);
122}
123
Andrew Jeffery319304f2023-04-05 13:53:18 +0930124static uint16_t get_bios_attr_handle(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930125{
126 static uint16_t handle = 0;
127 assert(handle != UINT16_MAX);
128
129 return handle++;
130}
131
132static void attr_table_entry_encode_header(void *entry, size_t length,
133 uint8_t attr_type,
134 uint16_t string_handle)
135{
136 struct pldm_bios_attr_table_entry *attr_entry = entry;
137 assert(sizeof(*attr_entry) <= length);
138 attr_entry->attr_handle = htole16(get_bios_attr_handle());
139 attr_entry->attr_type = attr_type;
140 attr_entry->string_handle = htole16(string_handle);
141}
142
143uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930144 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930145{
146 return le16toh(entry->attr_handle);
147}
148
149uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930150 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930151{
152 return entry->attr_type;
153}
154
155uint16_t pldm_bios_table_attr_entry_decode_string_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930156 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930157{
158 return le16toh(entry->string_handle);
159}
160
161size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
162 uint8_t def_num)
163{
164 return sizeof(struct pldm_bios_attr_table_entry) -
165 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
166 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
167 def_num;
168}
169
170void pldm_bios_table_attr_entry_enum_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930171 void *entry, size_t entry_length,
172 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930173{
174 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930175 info->pv_num, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930176 assert(length <= entry_length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930177 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
178 PLDM_BIOS_ENUMERATION;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930179 attr_table_entry_encode_header(entry, entry_length, attr_type,
180 info->name_handle);
181 struct pldm_bios_attr_table_entry *attr_entry = entry;
182 attr_entry->metadata[0] = info->pv_num;
183 uint16_t *pv_hdls =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930184 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930186 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930188 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930189 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930190 info->def_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930191 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930192 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930193 info->def_index, info->def_num);
194}
195
196int pldm_bios_table_attr_entry_enum_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930197 void *entry, size_t entry_length,
198 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930199{
200 POINTER_CHECK(entry);
201 POINTER_CHECK(info);
202 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930203 info->pv_num, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930204 BUFFER_SIZE_EXPECT(entry_length, length);
205 pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
206 return PLDM_SUCCESS;
207}
208
209#define ATTR_TYPE_EXPECT(type, expected) \
210 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930211 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930212 return PLDM_ERROR_INVALID_DATA; \
213 } while (0)
214
215uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930216 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930217{
218 return entry->metadata[0];
219}
220
221int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930222 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930223{
224 POINTER_CHECK(entry);
225 POINTER_CHECK(pv_num);
226 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
227 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
228 return PLDM_SUCCESS;
229}
230
231uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930232 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930233{
234 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
235 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
236 sizeof(uint16_t) * pv_num];
237}
238
239int pldm_bios_table_attr_entry_enum_decode_def_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930240 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930241{
242 POINTER_CHECK(entry);
243 POINTER_CHECK(def_num);
244 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
245 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
246 return PLDM_SUCCESS;
247}
248
249uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930250 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
251 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930252{
253 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
254 num = num < pv_num ? num : pv_num;
255 size_t i;
256 for (i = 0; i < num; i++) {
257 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
258 i * sizeof(uint16_t));
259 pv_hdls[i] = le16toh(*hdl);
260 }
261 return num;
262}
263
264int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930265 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
266 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930267{
268 POINTER_CHECK(entry);
269 POINTER_CHECK(pv_hdls);
270 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
271 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930272 if (num != pv_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930273 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930274 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930275 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
276 return PLDM_SUCCESS;
277}
278
279uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930280 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
281 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930282{
283 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
284 num = num < def_num ? num : def_num;
285 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
286 const uint8_t *p = entry->metadata +
287 sizeof(uint8_t) /* number of possible values*/
288 + pv_num * sizeof(uint16_t) /* possible values */
289 + sizeof(uint8_t); /* number of default values */
290 memcpy(def_indices, p, num);
291 return num;
292}
293
294/** @brief Get length of an enum attribute entry
295 */
296static size_t attr_table_entry_length_enum(const void *entry)
297{
298 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
299 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
300 return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
301}
302
303struct attr_table_string_entry_fields {
304 uint8_t string_type;
305 uint16_t min_length;
306 uint16_t max_length;
307 uint16_t def_length;
308 uint8_t def_string[1];
309} __attribute__((packed));
310
311size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
312{
313 return sizeof(struct pldm_bios_attr_table_entry) -
314 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
315 sizeof(struct attr_table_string_entry_fields) -
316 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
317 def_str_len;
318}
319
320void pldm_bios_table_attr_entry_string_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930321 void *entry, size_t entry_length,
322 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930323{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930324 size_t length = pldm_bios_table_attr_entry_string_encode_length(
325 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930326 assert(length <= entry_length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930327 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
328 PLDM_BIOS_STRING;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930329 attr_table_entry_encode_header(entry, entry_length, attr_type,
330 info->name_handle);
331 struct pldm_bios_attr_table_entry *attr_entry = entry;
332 struct attr_table_string_entry_fields *attr_fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930333 (struct attr_table_string_entry_fields *)attr_entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930334 attr_fields->string_type = info->string_type;
335 attr_fields->min_length = htole16(info->min_length);
336 attr_fields->max_length = htole16(info->max_length);
337 attr_fields->def_length = htole16(info->def_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930338 if (info->def_length != 0 && info->def_string != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930339 memcpy(attr_fields->def_string, info->def_string,
340 info->def_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930341 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342}
343
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930344#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930345#define PLDM_STRING_TYPE_VENDOR 0xff
346
347int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930348 const struct pldm_bios_table_attr_entry_string_info *info,
349 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930350{
351 if (info->min_length > info->max_length) {
352 set_errmsg(errmsg, "MinimumStingLength should not be greater "
353 "than MaximumStringLength");
354 return PLDM_ERROR_INVALID_DATA;
355 }
356 if (info->min_length == info->max_length &&
357 info->def_length != info->min_length) {
358 set_errmsg(errmsg, "Wrong DefaultStringLength");
359 return PLDM_ERROR_INVALID_DATA;
360 }
361 if (info->def_length > info->max_length ||
362 info->def_length < info->min_length) {
363 set_errmsg(errmsg, "Wrong DefaultStringLength");
364 return PLDM_ERROR_INVALID_DATA;
365 }
366 if (info->string_type > PLDM_STRING_TYPE_MAX &&
367 info->string_type != PLDM_STRING_TYPE_VENDOR) {
368 set_errmsg(errmsg, "Wrong StringType");
369 return PLDM_ERROR_INVALID_DATA;
370 }
371 if (info->def_length != strlen(info->def_string)) {
372 set_errmsg(errmsg, "Length of DefaultString should be equal to "
373 "DefaultStringLength");
374 return PLDM_ERROR_INVALID_DATA;
375 }
376
377 return PLDM_SUCCESS;
378}
379
380int pldm_bios_table_attr_entry_string_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930381 void *entry, size_t entry_length,
382 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930383{
384 POINTER_CHECK(entry);
385 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930386 size_t length = pldm_bios_table_attr_entry_string_encode_length(
387 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930388 BUFFER_SIZE_EXPECT(entry_length, length);
389 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930390 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930391 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930392 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930393 pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
394 return PLDM_SUCCESS;
395}
396
397uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930398 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930399{
400 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930401 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930402 return le16toh(fields->def_length);
403}
404
405int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930406 const struct pldm_bios_attr_table_entry *entry,
407 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930408{
409 POINTER_CHECK(entry);
410 POINTER_CHECK(def_string_length);
411 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
412 *def_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930413 pldm_bios_table_attr_entry_string_decode_def_string_length(
414 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930415 return PLDM_SUCCESS;
416}
417
418uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930419 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930420{
421 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930422 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930423 return fields->string_type;
424}
425
426uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930427 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930428{
429 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930430 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930431 return le16toh(fields->max_length);
432}
433
434uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930435 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930436{
437 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930438 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930439 return le16toh(fields->min_length);
440}
441
442uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930443 const struct pldm_bios_attr_table_entry *entry, char *buffer,
444 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930445{
446 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930447 pldm_bios_table_attr_entry_string_decode_def_string_length(
448 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930449 length = length < (size - 1) ? length : (size - 1);
450 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930451 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930452 memcpy(buffer, fields->def_string, length);
453 buffer[length] = 0;
454 return length;
455}
456
457/** @brief Get length of a string attribute entry
458 */
459static size_t attr_table_entry_length_string(const void *entry)
460{
461 uint16_t def_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930462 pldm_bios_table_attr_entry_string_decode_def_string_length(
463 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930464 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
465}
466
467struct attr_table_integer_entry_fields {
468 uint64_t lower_bound;
469 uint64_t upper_bound;
470 uint32_t scalar_increment;
471 uint64_t default_value;
472} __attribute__((packed));
473
Andrew Jeffery319304f2023-04-05 13:53:18 +0930474size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930475{
476 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
477 sizeof(struct attr_table_integer_entry_fields);
478}
479
480void pldm_bios_table_attr_entry_integer_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930481 void *entry, size_t entry_length,
482 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930483{
484 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
485 assert(length <= entry_length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930486 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
487 PLDM_BIOS_INTEGER;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930488 attr_table_entry_encode_header(entry, entry_length, attr_type,
489 info->name_handle);
490 struct pldm_bios_attr_table_entry *attr_entry = entry;
491 struct attr_table_integer_entry_fields *attr_fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930492 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930493 attr_fields->lower_bound = htole64(info->lower_bound);
494 attr_fields->upper_bound = htole64(info->upper_bound);
495 attr_fields->scalar_increment = htole32(info->scalar_increment);
496 attr_fields->default_value = htole64(info->default_value);
497}
498
499int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930500 const struct pldm_bios_table_attr_entry_integer_info *info,
501 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930502{
503 if (info->lower_bound == info->upper_bound) {
504 if (info->default_value != info->lower_bound) {
505 set_errmsg(errmsg, "Wrong DefaultValue");
506 return PLDM_ERROR_INVALID_DATA;
507 }
508 if (info->scalar_increment != 0) {
509 set_errmsg(errmsg, "Wrong ScalarIncrement");
510 return PLDM_ERROR_INVALID_DATA;
511 }
512 return PLDM_SUCCESS;
513 }
514 if (info->lower_bound > info->upper_bound) {
515 set_errmsg(errmsg,
516 "LowerBound should not be greater than UpperBound");
517 return PLDM_ERROR_INVALID_DATA;
518 }
519 if (info->default_value > info->upper_bound ||
520 info->default_value < info->lower_bound) {
521 set_errmsg(errmsg, "Wrong DefaultValue");
522 return PLDM_ERROR_INVALID_DATA;
523 }
524 if (info->scalar_increment == 0) {
525 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
526 "lower_bound != upper_bound");
527 return PLDM_ERROR_INVALID_DATA;
528 }
529 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930530 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930531 0) {
532 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
533 return PLDM_ERROR_INVALID_DATA;
534 }
535 return PLDM_SUCCESS;
536}
537
538int pldm_bios_table_attr_entry_integer_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930539 void *entry, size_t entry_length,
540 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930541{
542 POINTER_CHECK(entry);
543 POINTER_CHECK(info);
544 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
545 BUFFER_SIZE_EXPECT(entry_length, length);
546 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930547 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930549 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930550 pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
551 return PLDM_SUCCESS;
552}
553
554void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930555 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
556 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930557{
558 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930559 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930560 *lower = le64toh(fields->lower_bound);
561 *upper = le64toh(fields->upper_bound);
562 *scalar = le32toh(fields->scalar_increment);
563 *def = le64toh(fields->default_value);
564}
565
566static size_t attr_table_entry_length_integer(const void *entry)
567{
568 (void)entry;
569 return pldm_bios_table_attr_entry_integer_encode_length();
570}
571
572struct table_entry_length {
573 uint8_t attr_type;
574 size_t (*entry_length_handler)(const void *);
575};
576
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930577#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
Andrew Jeffery9c766792022-08-10 23:12:49 +0930578
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930579static const struct table_entry_length *
580find_table_entry_length_by_type(uint8_t attr_type,
581 const struct table_entry_length *handlers,
582 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930583{
584 size_t i;
585 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930586 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930587 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930588 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589 }
590 return NULL;
591}
592
593static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930594 { .attr_type = PLDM_BIOS_ENUMERATION,
595 .entry_length_handler = attr_table_entry_length_enum },
596 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
597 .entry_length_handler = attr_table_entry_length_enum },
598 { .attr_type = PLDM_BIOS_STRING,
599 .entry_length_handler = attr_table_entry_length_string },
600 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
601 .entry_length_handler = attr_table_entry_length_string },
602 { .attr_type = PLDM_BIOS_INTEGER,
603 .entry_length_handler = attr_table_entry_length_integer },
604 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
605 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606};
607
608static size_t attr_table_entry_length(const void *table_entry)
609{
610 const struct pldm_bios_attr_table_entry *entry = table_entry;
611 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930612 find_table_entry_length_by_type(entry->attr_type,
613 attr_table_entries,
614 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930615 assert(attr_table_entry != NULL);
616 assert(attr_table_entry->entry_length_handler != NULL);
617
618 return attr_table_entry->entry_length_handler(entry);
619}
620
621uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930622 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930623{
624 return le16toh(entry->attr_handle);
625}
626
627uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930628 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930629{
630 return entry->attr_type;
631}
632
633size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
634{
635 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
636 sizeof(count) + count;
637}
638
639void pldm_bios_table_attr_value_entry_encode_enum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930640 void *entry, size_t entry_length, uint16_t attr_handle,
641 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930642{
643 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930644 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930645 assert(length <= entry_length);
646
647 struct pldm_bios_attr_val_table_entry *table_entry = entry;
648 table_entry->attr_handle = htole16(attr_handle);
649 table_entry->attr_type = attr_type;
650 table_entry->value[0] = count;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930651 if (count != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930652 memcpy(&table_entry->value[1], handles, count);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930653 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930654}
655
656uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930657 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930658{
659 return entry->value[0];
660}
661
662uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930663 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
664 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930665{
666 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930667 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930668 number = number < curr_num ? number : curr_num;
669 memcpy(handles, &entry->value[1], number);
670
671 return number;
672}
673
674int pldm_bios_table_attr_value_entry_encode_enum_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930675 void *entry, size_t entry_length, uint16_t attr_handle,
676 uint8_t attr_type, uint8_t count, uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677{
678 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930679 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930681 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930682 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
683 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930684 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685 BUFFER_SIZE_EXPECT(entry_length, length);
686 pldm_bios_table_attr_value_entry_encode_enum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930687 entry, entry_length, attr_handle, attr_type, count, handles);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688 return PLDM_SUCCESS;
689}
690
691static size_t attr_value_table_entry_length_enum(const void *entry)
692{
693 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930694 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695 return pldm_bios_table_attr_value_entry_encode_enum_length(number);
696}
697
698size_t
699pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
700{
701 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
702 sizeof(string_length) + string_length;
703}
704
705void pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930706 void *entry, size_t entry_length, uint16_t attr_handle,
707 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930708{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930709 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
710 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930711 assert(length <= entry_length);
712
713 struct pldm_bios_attr_val_table_entry *table_entry = entry;
714 table_entry->attr_handle = htole16(attr_handle);
715 table_entry->attr_type = attr_type;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930716 if (str_length != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930717 memcpy(table_entry->value + sizeof(str_length), str,
718 str_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930719 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930720 str_length = htole16(str_length);
721 memcpy(table_entry->value, &str_length, sizeof(str_length));
722}
723
724uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930725 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930726{
727 uint16_t str_length = 0;
728 memcpy(&str_length, entry->value, sizeof(str_length));
729 return le16toh(str_length);
730}
731
732void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930733 const struct pldm_bios_attr_val_table_entry *entry,
734 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930735{
736 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930737 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930738 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930739 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930740}
741
742int pldm_bios_table_attr_value_entry_encode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930743 void *entry, size_t entry_length, uint16_t attr_handle,
744 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745{
746 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930747 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930749 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930750 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930751 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
752 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930753 BUFFER_SIZE_EXPECT(entry_length, length);
754 pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930755 entry, entry_length, attr_handle, attr_type, str_length, str);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930756 return PLDM_SUCCESS;
757}
758
759static size_t attr_value_table_entry_length_string(const void *entry)
760{
761 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930762 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930763 return pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930764 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930765}
766
Andrew Jeffery319304f2023-04-05 13:53:18 +0930767size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930768{
769 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
770 sizeof(uint64_t);
771}
772void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
773 size_t entry_length,
774 uint16_t attr_handle,
775 uint8_t attr_type,
776 uint64_t cv)
777{
778 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930779 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930780 assert(length <= entry_length);
781
782 struct pldm_bios_attr_val_table_entry *table_entry = entry;
783 table_entry->attr_handle = htole16(attr_handle);
784 table_entry->attr_type = attr_type;
785 cv = htole64(cv);
786 memcpy(table_entry->value, &cv, sizeof(uint64_t));
787}
788
789int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
790 size_t entry_length,
791 uint16_t attr_handle,
792 uint8_t attr_type,
793 uint64_t cv)
794{
795 POINTER_CHECK(entry);
796 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930797 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930798 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
799 BUFFER_SIZE_EXPECT(entry_length, length);
800 pldm_bios_table_attr_value_entry_encode_integer(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930801 entry, entry_length, attr_handle, attr_type, cv);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930802 return PLDM_SUCCESS;
803}
804
805uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930806 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930807{
808 uint64_t cv = 0;
809 memcpy(&cv, entry->value, sizeof(cv));
810 cv = le64toh(cv);
811 return cv;
812}
813
814static size_t attr_value_table_entry_length_integer(const void *entry)
815{
816 (void)entry;
817 return pldm_bios_table_attr_value_entry_encode_integer_length();
818}
819
820static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930821 { .attr_type = PLDM_BIOS_ENUMERATION,
822 .entry_length_handler = attr_value_table_entry_length_enum },
823 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
824 .entry_length_handler = attr_value_table_entry_length_enum },
825 { .attr_type = PLDM_BIOS_STRING,
826 .entry_length_handler = attr_value_table_entry_length_string },
827 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
828 .entry_length_handler = attr_value_table_entry_length_string },
829 { .attr_type = PLDM_BIOS_INTEGER,
830 .entry_length_handler = attr_value_table_entry_length_integer },
831 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
832 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930833};
834
835static size_t attr_value_table_entry_length(const void *table_entry)
836{
837 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
838 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930839 find_table_entry_length_by_type(
840 entry->attr_type, attr_value_table_entries,
841 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930842 assert(entry_length != NULL);
843 assert(entry_length->entry_length_handler != NULL);
844
845 return entry_length->entry_length_handler(entry);
846}
847
848size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930849 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930850{
851 return attr_value_table_entry_length(entry);
852}
853
854uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930855 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930856{
857 return le16toh(entry->attr_handle);
858}
859
860static size_t pad_size_get(size_t size_without_pad)
861{
862 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
863}
864
865static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
866{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930867 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930868 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930869 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870
871 return table_end;
872}
873
874static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
875{
876 checksum = htole32(checksum);
877 memcpy(table_end, &checksum, sizeof(checksum));
878
879 return table_end + sizeof(checksum);
880}
881
882size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
883{
884 size_t size = pad_size_get(size_without_pad) +
885 sizeof(uint32_t) /*sizeof(checksum)*/;
886 return size;
887}
888
889size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
890 size_t size_without_pad)
891{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930892 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930893 pldm_bios_table_pad_checksum_size(size_without_pad);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894 size_t total_length = size_without_pad + pad_checksum_size;
895 assert(size >= total_length);
896
897 uint8_t *table_end = (uint8_t *)table + size_without_pad;
898 size_t pad_size = pad_size_get(size_without_pad);
899 table_end = pad_append(table_end, pad_size);
900
901 uint32_t checksum = crc32(table, size_without_pad + pad_size);
902 checksum_append(table_end, checksum);
903
904 return total_length;
905}
906
907struct pldm_bios_table_iter {
908 const uint8_t *table_data;
909 size_t table_len;
910 size_t current_pos;
911 size_t (*entry_length_handler)(const void *table_entry);
912};
913
914struct pldm_bios_table_iter *
915pldm_bios_table_iter_create(const void *table, size_t length,
916 enum pldm_bios_table_types type)
917{
918 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
919 assert(iter != NULL);
920 iter->table_data = table;
921 iter->table_len = length;
922 iter->current_pos = 0;
923 iter->entry_length_handler = NULL;
924 switch (type) {
925 case PLDM_BIOS_STRING_TABLE:
926 iter->entry_length_handler = string_table_entry_length;
927 break;
928 case PLDM_BIOS_ATTR_TABLE:
929 iter->entry_length_handler = attr_table_entry_length;
930 break;
931 case PLDM_BIOS_ATTR_VAL_TABLE:
932 iter->entry_length_handler = attr_value_table_entry_length;
933 break;
934 }
935
936 return iter;
937}
938
939void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
940{
941 free(iter);
942}
943
944#define pad_and_check_max 7
945bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
946{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930947 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930949 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 return false;
951}
952
953void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
954{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930955 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930956 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930957 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930958 const void *entry = iter->table_data + iter->current_pos;
959 iter->current_pos += iter->entry_length_handler(entry);
960}
961
962const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
963{
964 return iter->table_data + iter->current_pos;
965}
966
967typedef bool (*equal_handler)(const void *entry, const void *key);
968
969static const void *
970pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
971 const void *key, equal_handler equal)
972{
973 const void *entry;
974 while (!pldm_bios_table_iter_is_end(iter)) {
975 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930976 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930977 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930978 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930979 pldm_bios_table_iter_next(iter);
980 }
981 return NULL;
982}
983
984static const void *
985pldm_bios_table_entry_find_from_table(const void *table, size_t length,
986 enum pldm_bios_table_types type,
987 equal_handler equal, const void *key)
988{
989 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930990 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930991 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930992 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930993 pldm_bios_table_iter_free(iter);
994 return entry;
995}
996
997static bool string_table_handle_equal(const void *entry, const void *key)
998{
999 const struct pldm_bios_string_table_entry *string_entry = entry;
1000 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301001 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1002 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301003 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301004 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301005 return false;
1006}
1007
1008const struct pldm_bios_string_table_entry *
1009pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1010 uint16_t handle)
1011{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301012 return pldm_bios_table_entry_find_from_table(table, length,
1013 PLDM_BIOS_STRING_TABLE,
1014 string_table_handle_equal,
1015 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301016}
1017
1018struct string_equal_arg {
1019 uint16_t str_length;
1020 const char *str;
1021};
1022
1023static bool string_table_string_equal(const void *entry, const void *key)
1024{
1025 const struct pldm_bios_string_table_entry *string_entry = entry;
1026 const struct string_equal_arg *arg = key;
1027 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301028 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301029 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301030 }
1031 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301032 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301033 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301034 return true;
1035}
1036
1037const struct pldm_bios_string_table_entry *
1038pldm_bios_table_string_find_by_string(const void *table, size_t length,
1039 const char *str)
1040{
1041 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301042 struct string_equal_arg arg = { str_length, str };
1043 return pldm_bios_table_entry_find_from_table(table, length,
1044 PLDM_BIOS_STRING_TABLE,
1045 string_table_string_equal,
1046 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301047}
1048
1049static bool attr_table_handle_equal(const void *entry, const void *key)
1050{
1051 uint16_t handle = *(uint16_t *)key;
1052 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1053 handle;
1054}
1055
1056const struct pldm_bios_attr_table_entry *
1057pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1058 uint16_t handle)
1059{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301060 return pldm_bios_table_entry_find_from_table(table, length,
1061 PLDM_BIOS_ATTR_TABLE,
1062 attr_table_handle_equal,
1063 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301064}
1065
1066static bool attr_table_string_handle_equal(const void *entry, const void *key)
1067{
1068 uint16_t handle = *(uint16_t *)key;
1069 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1070}
1071
1072const struct pldm_bios_attr_table_entry *
1073pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1074 uint16_t handle)
1075{
1076 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301077 table, length, PLDM_BIOS_ATTR_TABLE,
1078 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301079}
1080
1081static bool attr_value_table_handle_equal(const void *entry, const void *key)
1082{
1083 uint16_t handle = *(uint16_t *)key;
1084 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1085}
1086
1087const struct pldm_bios_attr_val_table_entry *
1088pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1089 uint16_t handle)
1090{
1091 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301092 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1093 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301094}
1095
1096int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301097 const void *src_table, size_t src_length, void *dest_table,
1098 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301099{
1100 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301101 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301102
1103 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301104 const struct pldm_bios_attr_val_table_entry *tmp;
1105 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1106 size_t buffer_length = *dest_length;
1107 size_t copied_length = 0;
1108 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301109 while (!pldm_bios_table_iter_is_end(iter)) {
1110 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1111 length = attr_value_table_entry_length(tmp);
1112
1113 /* we need the tmp's entry_length here, iter_next will calculate
1114 * it too, use current_pos directly to avoid calculating it
1115 * twice */
1116 iter->current_pos += length;
1117 if (tmp->attr_handle == to_update->attr_handle) {
1118 if (tmp->attr_type != to_update->attr_type) {
1119 rc = PLDM_ERROR_INVALID_DATA;
1120 goto out;
1121 }
1122 length = entry_length;
1123 tmp = entry;
1124 }
1125 if (copied_length + length > buffer_length) {
1126 rc = PLDM_ERROR_INVALID_LENGTH;
1127 goto out;
1128 }
1129 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1130 copied_length += length;
1131 }
1132
1133 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301134 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301135 if ((pad_checksum_size + copied_length) > buffer_length) {
1136 rc = PLDM_ERROR_INVALID_LENGTH;
1137 goto out;
1138 }
1139
1140 *dest_length = pldm_bios_table_append_pad_checksum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301141 dest_table, buffer_length, copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301142out:
1143 pldm_bios_table_iter_free(iter);
1144 return rc;
1145}
1146
1147bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1148{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301149 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301150 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301151 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301152
1153 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1154 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301155 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301156 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301157 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301158
1159 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1160 uint32_t dst_crc = crc32(table, size - 4);
1161
1162 return src_crc == dst_crc;
1163}