blob: e9e1f3f395c5e26fb14cda6e1cb598d77a047ef9 [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(
81 const struct pldm_bios_string_table_entry *entry)
82{
83 return le16toh(entry->string_handle);
84}
85
86uint16_t pldm_bios_table_string_entry_decode_string_length(
87 const struct pldm_bios_string_table_entry *entry)
88{
89 return le16toh(entry->string_length);
90}
91
92uint16_t pldm_bios_table_string_entry_decode_string(
93 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
94{
95 uint16_t length =
96 pldm_bios_table_string_entry_decode_string_length(entry);
97 length = length < (size - 1) ? length : (size - 1);
98 memcpy(buffer, entry->name, length);
99 buffer[length] = 0;
100 return length;
101}
102
103int pldm_bios_table_string_entry_decode_string_check(
104 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
105{
106 POINTER_CHECK(entry);
107 POINTER_CHECK(buffer);
108 size_t length =
109 pldm_bios_table_string_entry_decode_string_length(entry);
110 BUFFER_SIZE_EXPECT(size, length + 1);
111 pldm_bios_table_string_entry_decode_string(entry, buffer, size);
112 return PLDM_SUCCESS;
113}
114
115static size_t string_table_entry_length(const void *table_entry)
116{
117 const struct pldm_bios_string_table_entry *entry = table_entry;
118 return sizeof(*entry) - sizeof(entry->name) +
119 pldm_bios_table_string_entry_decode_string_length(entry);
120}
121
Andrew Jeffery319304f2023-04-05 13:53:18 +0930122static uint16_t get_bios_attr_handle(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930123{
124 static uint16_t handle = 0;
125 assert(handle != UINT16_MAX);
126
127 return handle++;
128}
129
130static void attr_table_entry_encode_header(void *entry, size_t length,
131 uint8_t attr_type,
132 uint16_t string_handle)
133{
134 struct pldm_bios_attr_table_entry *attr_entry = entry;
135 assert(sizeof(*attr_entry) <= length);
136 attr_entry->attr_handle = htole16(get_bios_attr_handle());
137 attr_entry->attr_type = attr_type;
138 attr_entry->string_handle = htole16(string_handle);
139}
140
141uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
142 const struct pldm_bios_attr_table_entry *entry)
143{
144 return le16toh(entry->attr_handle);
145}
146
147uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
148 const struct pldm_bios_attr_table_entry *entry)
149{
150 return entry->attr_type;
151}
152
153uint16_t pldm_bios_table_attr_entry_decode_string_handle(
154 const struct pldm_bios_attr_table_entry *entry)
155{
156 return le16toh(entry->string_handle);
157}
158
159size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
160 uint8_t def_num)
161{
162 return sizeof(struct pldm_bios_attr_table_entry) -
163 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
164 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
165 def_num;
166}
167
168void pldm_bios_table_attr_entry_enum_encode(
169 void *entry, size_t entry_length,
170 const struct pldm_bios_table_attr_entry_enum_info *info)
171{
172 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
173 info->pv_num, info->def_num);
174 assert(length <= entry_length);
175 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY
176 : PLDM_BIOS_ENUMERATION;
177 attr_table_entry_encode_header(entry, entry_length, attr_type,
178 info->name_handle);
179 struct pldm_bios_attr_table_entry *attr_entry = entry;
180 attr_entry->metadata[0] = info->pv_num;
181 uint16_t *pv_hdls =
182 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
183 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930184 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930186 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
188 info->def_num;
189 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
190 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
191 info->def_index, info->def_num);
192}
193
194int pldm_bios_table_attr_entry_enum_encode_check(
195 void *entry, size_t entry_length,
196 const struct pldm_bios_table_attr_entry_enum_info *info)
197{
198 POINTER_CHECK(entry);
199 POINTER_CHECK(info);
200 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
201 info->pv_num, info->def_num);
202 BUFFER_SIZE_EXPECT(entry_length, length);
203 pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
204 return PLDM_SUCCESS;
205}
206
207#define ATTR_TYPE_EXPECT(type, expected) \
208 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930209 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930210 return PLDM_ERROR_INVALID_DATA; \
211 } while (0)
212
213uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
214 const struct pldm_bios_attr_table_entry *entry)
215{
216 return entry->metadata[0];
217}
218
219int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
220 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
221{
222 POINTER_CHECK(entry);
223 POINTER_CHECK(pv_num);
224 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
225 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
226 return PLDM_SUCCESS;
227}
228
229uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
230 const struct pldm_bios_attr_table_entry *entry)
231{
232 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
233 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
234 sizeof(uint16_t) * pv_num];
235}
236
237int pldm_bios_table_attr_entry_enum_decode_def_num_check(
238 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
239{
240 POINTER_CHECK(entry);
241 POINTER_CHECK(def_num);
242 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
243 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
244 return PLDM_SUCCESS;
245}
246
247uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
248 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
249 uint8_t pv_num)
250{
251 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
252 num = num < pv_num ? num : pv_num;
253 size_t i;
254 for (i = 0; i < num; i++) {
255 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
256 i * sizeof(uint16_t));
257 pv_hdls[i] = le16toh(*hdl);
258 }
259 return num;
260}
261
262int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
263 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
264 uint8_t pv_num)
265{
266 POINTER_CHECK(entry);
267 POINTER_CHECK(pv_hdls);
268 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
269 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930270 if (num != pv_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930271 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930272 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930273 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
274 return PLDM_SUCCESS;
275}
276
277uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
278 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
279 uint8_t def_num)
280{
281 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
282 num = num < def_num ? num : def_num;
283 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
284 const uint8_t *p = entry->metadata +
285 sizeof(uint8_t) /* number of possible values*/
286 + pv_num * sizeof(uint16_t) /* possible values */
287 + sizeof(uint8_t); /* number of default values */
288 memcpy(def_indices, p, num);
289 return num;
290}
291
292/** @brief Get length of an enum attribute entry
293 */
294static size_t attr_table_entry_length_enum(const void *entry)
295{
296 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
297 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
298 return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
299}
300
301struct attr_table_string_entry_fields {
302 uint8_t string_type;
303 uint16_t min_length;
304 uint16_t max_length;
305 uint16_t def_length;
306 uint8_t def_string[1];
307} __attribute__((packed));
308
309size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
310{
311 return sizeof(struct pldm_bios_attr_table_entry) -
312 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
313 sizeof(struct attr_table_string_entry_fields) -
314 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
315 def_str_len;
316}
317
318void pldm_bios_table_attr_entry_string_encode(
319 void *entry, size_t entry_length,
320 const struct pldm_bios_table_attr_entry_string_info *info)
321{
322 size_t length =
323 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
324 assert(length <= entry_length);
325 uint8_t attr_type =
326 info->read_only ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
327 attr_table_entry_encode_header(entry, entry_length, attr_type,
328 info->name_handle);
329 struct pldm_bios_attr_table_entry *attr_entry = entry;
330 struct attr_table_string_entry_fields *attr_fields =
331 (struct attr_table_string_entry_fields *)attr_entry->metadata;
332 attr_fields->string_type = info->string_type;
333 attr_fields->min_length = htole16(info->min_length);
334 attr_fields->max_length = htole16(info->max_length);
335 attr_fields->def_length = htole16(info->def_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930336 if (info->def_length != 0 && info->def_string != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337 memcpy(attr_fields->def_string, info->def_string,
338 info->def_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930339 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930340}
341
342#define PLDM_STRING_TYPE_MAX 5
343#define PLDM_STRING_TYPE_VENDOR 0xff
344
345int pldm_bios_table_attr_entry_string_info_check(
346 const struct pldm_bios_table_attr_entry_string_info *info,
347 const char **errmsg)
348{
349 if (info->min_length > info->max_length) {
350 set_errmsg(errmsg, "MinimumStingLength should not be greater "
351 "than MaximumStringLength");
352 return PLDM_ERROR_INVALID_DATA;
353 }
354 if (info->min_length == info->max_length &&
355 info->def_length != info->min_length) {
356 set_errmsg(errmsg, "Wrong DefaultStringLength");
357 return PLDM_ERROR_INVALID_DATA;
358 }
359 if (info->def_length > info->max_length ||
360 info->def_length < info->min_length) {
361 set_errmsg(errmsg, "Wrong DefaultStringLength");
362 return PLDM_ERROR_INVALID_DATA;
363 }
364 if (info->string_type > PLDM_STRING_TYPE_MAX &&
365 info->string_type != PLDM_STRING_TYPE_VENDOR) {
366 set_errmsg(errmsg, "Wrong StringType");
367 return PLDM_ERROR_INVALID_DATA;
368 }
369 if (info->def_length != strlen(info->def_string)) {
370 set_errmsg(errmsg, "Length of DefaultString should be equal to "
371 "DefaultStringLength");
372 return PLDM_ERROR_INVALID_DATA;
373 }
374
375 return PLDM_SUCCESS;
376}
377
378int pldm_bios_table_attr_entry_string_encode_check(
379 void *entry, size_t entry_length,
380 const struct pldm_bios_table_attr_entry_string_info *info)
381{
382 POINTER_CHECK(entry);
383 POINTER_CHECK(info);
384 size_t length =
385 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
386 BUFFER_SIZE_EXPECT(entry_length, length);
387 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930388 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930389 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930390 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930391 pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
392 return PLDM_SUCCESS;
393}
394
395uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
396 const struct pldm_bios_attr_table_entry *entry)
397{
398 struct attr_table_string_entry_fields *fields =
399 (struct attr_table_string_entry_fields *)entry->metadata;
400 return le16toh(fields->def_length);
401}
402
403int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
404 const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
405{
406 POINTER_CHECK(entry);
407 POINTER_CHECK(def_string_length);
408 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
409 *def_string_length =
410 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
411 return PLDM_SUCCESS;
412}
413
414uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
415 const struct pldm_bios_attr_table_entry *entry)
416{
417 struct attr_table_string_entry_fields *fields =
418 (struct attr_table_string_entry_fields *)entry->metadata;
419 return fields->string_type;
420}
421
422uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
423 const struct pldm_bios_attr_table_entry *entry)
424{
425 struct attr_table_string_entry_fields *fields =
426 (struct attr_table_string_entry_fields *)entry->metadata;
427 return le16toh(fields->max_length);
428}
429
430uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
431 const struct pldm_bios_attr_table_entry *entry)
432{
433 struct attr_table_string_entry_fields *fields =
434 (struct attr_table_string_entry_fields *)entry->metadata;
435 return le16toh(fields->min_length);
436}
437
438uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
439 const struct pldm_bios_attr_table_entry *entry, char *buffer, size_t size)
440{
441 uint16_t length =
442 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
443 length = length < (size - 1) ? length : (size - 1);
444 struct attr_table_string_entry_fields *fields =
445 (struct attr_table_string_entry_fields *)entry->metadata;
446 memcpy(buffer, fields->def_string, length);
447 buffer[length] = 0;
448 return length;
449}
450
451/** @brief Get length of a string attribute entry
452 */
453static size_t attr_table_entry_length_string(const void *entry)
454{
455 uint16_t def_str_len =
456 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
457 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
458}
459
460struct attr_table_integer_entry_fields {
461 uint64_t lower_bound;
462 uint64_t upper_bound;
463 uint32_t scalar_increment;
464 uint64_t default_value;
465} __attribute__((packed));
466
Andrew Jeffery319304f2023-04-05 13:53:18 +0930467size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930468{
469 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
470 sizeof(struct attr_table_integer_entry_fields);
471}
472
473void pldm_bios_table_attr_entry_integer_encode(
474 void *entry, size_t entry_length,
475 const struct pldm_bios_table_attr_entry_integer_info *info)
476{
477 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
478 assert(length <= entry_length);
479 uint8_t attr_type =
480 info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY : PLDM_BIOS_INTEGER;
481 attr_table_entry_encode_header(entry, entry_length, attr_type,
482 info->name_handle);
483 struct pldm_bios_attr_table_entry *attr_entry = entry;
484 struct attr_table_integer_entry_fields *attr_fields =
485 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
486 attr_fields->lower_bound = htole64(info->lower_bound);
487 attr_fields->upper_bound = htole64(info->upper_bound);
488 attr_fields->scalar_increment = htole32(info->scalar_increment);
489 attr_fields->default_value = htole64(info->default_value);
490}
491
492int pldm_bios_table_attr_entry_integer_info_check(
493 const struct pldm_bios_table_attr_entry_integer_info *info,
494 const char **errmsg)
495{
496 if (info->lower_bound == info->upper_bound) {
497 if (info->default_value != info->lower_bound) {
498 set_errmsg(errmsg, "Wrong DefaultValue");
499 return PLDM_ERROR_INVALID_DATA;
500 }
501 if (info->scalar_increment != 0) {
502 set_errmsg(errmsg, "Wrong ScalarIncrement");
503 return PLDM_ERROR_INVALID_DATA;
504 }
505 return PLDM_SUCCESS;
506 }
507 if (info->lower_bound > info->upper_bound) {
508 set_errmsg(errmsg,
509 "LowerBound should not be greater than UpperBound");
510 return PLDM_ERROR_INVALID_DATA;
511 }
512 if (info->default_value > info->upper_bound ||
513 info->default_value < info->lower_bound) {
514 set_errmsg(errmsg, "Wrong DefaultValue");
515 return PLDM_ERROR_INVALID_DATA;
516 }
517 if (info->scalar_increment == 0) {
518 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
519 "lower_bound != upper_bound");
520 return PLDM_ERROR_INVALID_DATA;
521 }
522 if ((info->default_value - info->lower_bound) %
523 info->scalar_increment !=
524 0) {
525 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
526 return PLDM_ERROR_INVALID_DATA;
527 }
528 return PLDM_SUCCESS;
529}
530
531int pldm_bios_table_attr_entry_integer_encode_check(
532 void *entry, size_t entry_length,
533 const struct pldm_bios_table_attr_entry_integer_info *info)
534{
535 POINTER_CHECK(entry);
536 POINTER_CHECK(info);
537 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
538 BUFFER_SIZE_EXPECT(entry_length, length);
539 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930540 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930541 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930542 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930543 pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
544 return PLDM_SUCCESS;
545}
546
547void pldm_bios_table_attr_entry_integer_decode(
548 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
549 uint64_t *upper, uint32_t *scalar, uint64_t *def)
550{
551 struct attr_table_integer_entry_fields *fields =
552 (struct attr_table_integer_entry_fields *)entry->metadata;
553 *lower = le64toh(fields->lower_bound);
554 *upper = le64toh(fields->upper_bound);
555 *scalar = le32toh(fields->scalar_increment);
556 *def = le64toh(fields->default_value);
557}
558
559static size_t attr_table_entry_length_integer(const void *entry)
560{
561 (void)entry;
562 return pldm_bios_table_attr_entry_integer_encode_length();
563}
564
565struct table_entry_length {
566 uint8_t attr_type;
567 size_t (*entry_length_handler)(const void *);
568};
569
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930570#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571
572static const struct table_entry_length *find_table_entry_length_by_type(
573 uint8_t attr_type, const struct table_entry_length *handlers, size_t count)
574{
575 size_t i;
576 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930577 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930578 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930579 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580 }
581 return NULL;
582}
583
584static const struct table_entry_length attr_table_entries[] = {
585 {.attr_type = PLDM_BIOS_ENUMERATION,
586 .entry_length_handler = attr_table_entry_length_enum},
587 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
588 .entry_length_handler = attr_table_entry_length_enum},
589 {.attr_type = PLDM_BIOS_STRING,
590 .entry_length_handler = attr_table_entry_length_string},
591 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
592 .entry_length_handler = attr_table_entry_length_string},
593 {.attr_type = PLDM_BIOS_INTEGER,
594 .entry_length_handler = attr_table_entry_length_integer},
595 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
596 .entry_length_handler = attr_table_entry_length_integer},
597};
598
599static size_t attr_table_entry_length(const void *table_entry)
600{
601 const struct pldm_bios_attr_table_entry *entry = table_entry;
602 const struct table_entry_length *attr_table_entry =
603 find_table_entry_length_by_type(entry->attr_type,
604 attr_table_entries,
605 ARRAY_SIZE(attr_table_entries));
606 assert(attr_table_entry != NULL);
607 assert(attr_table_entry->entry_length_handler != NULL);
608
609 return attr_table_entry->entry_length_handler(entry);
610}
611
612uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
613 const struct pldm_bios_attr_val_table_entry *entry)
614{
615 return le16toh(entry->attr_handle);
616}
617
618uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
619 const struct pldm_bios_attr_val_table_entry *entry)
620{
621 return entry->attr_type;
622}
623
624size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
625{
626 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
627 sizeof(count) + count;
628}
629
630void pldm_bios_table_attr_value_entry_encode_enum(
631 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
632 uint8_t count, const uint8_t *handles)
633{
634 size_t length =
635 pldm_bios_table_attr_value_entry_encode_enum_length(count);
636 assert(length <= entry_length);
637
638 struct pldm_bios_attr_val_table_entry *table_entry = entry;
639 table_entry->attr_handle = htole16(attr_handle);
640 table_entry->attr_type = attr_type;
641 table_entry->value[0] = count;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930642 if (count != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930643 memcpy(&table_entry->value[1], handles, count);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930644 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930645}
646
647uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
648 const struct pldm_bios_attr_val_table_entry *entry)
649{
650 return entry->value[0];
651}
652
653uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
654 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
655 uint8_t number)
656{
657 uint8_t curr_num =
658 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
659 number = number < curr_num ? number : curr_num;
660 memcpy(handles, &entry->value[1], number);
661
662 return number;
663}
664
665int pldm_bios_table_attr_value_entry_encode_enum_check(
666 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
667 uint8_t count, uint8_t *handles)
668{
669 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930670 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930671 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930672 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930673 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
674 size_t length =
675 pldm_bios_table_attr_value_entry_encode_enum_length(count);
676 BUFFER_SIZE_EXPECT(entry_length, length);
677 pldm_bios_table_attr_value_entry_encode_enum(
678 entry, entry_length, attr_handle, attr_type, count, handles);
679 return PLDM_SUCCESS;
680}
681
682static size_t attr_value_table_entry_length_enum(const void *entry)
683{
684 uint8_t number =
685 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
686 return pldm_bios_table_attr_value_entry_encode_enum_length(number);
687}
688
689size_t
690pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
691{
692 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
693 sizeof(string_length) + string_length;
694}
695
696void pldm_bios_table_attr_value_entry_encode_string(
697 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
698 uint16_t str_length, const char *str)
699{
700 size_t length =
701 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
702 assert(length <= entry_length);
703
704 struct pldm_bios_attr_val_table_entry *table_entry = entry;
705 table_entry->attr_handle = htole16(attr_handle);
706 table_entry->attr_type = attr_type;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930707 if (str_length != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930708 memcpy(table_entry->value + sizeof(str_length), str,
709 str_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930710 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930711 str_length = htole16(str_length);
712 memcpy(table_entry->value, &str_length, sizeof(str_length));
713}
714
715uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
716 const struct pldm_bios_attr_val_table_entry *entry)
717{
718 uint16_t str_length = 0;
719 memcpy(&str_length, entry->value, sizeof(str_length));
720 return le16toh(str_length);
721}
722
723void pldm_bios_table_attr_value_entry_string_decode_string(
724 const struct pldm_bios_attr_val_table_entry *entry,
725 struct variable_field *current_string)
726{
727 current_string->length =
728 pldm_bios_table_attr_value_entry_string_decode_length(entry);
729 current_string->ptr =
730 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
731}
732
733int pldm_bios_table_attr_value_entry_encode_string_check(
734 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
735 uint16_t str_length, const char *str)
736{
737 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930738 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930739 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930740 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930741 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
742 size_t length =
743 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
744 BUFFER_SIZE_EXPECT(entry_length, length);
745 pldm_bios_table_attr_value_entry_encode_string(
746 entry, entry_length, attr_handle, attr_type, str_length, str);
747 return PLDM_SUCCESS;
748}
749
750static size_t attr_value_table_entry_length_string(const void *entry)
751{
752 uint16_t str_length =
753 pldm_bios_table_attr_value_entry_string_decode_length(entry);
754 return pldm_bios_table_attr_value_entry_encode_string_length(
755 str_length);
756}
757
Andrew Jeffery319304f2023-04-05 13:53:18 +0930758size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930759{
760 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
761 sizeof(uint64_t);
762}
763void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
764 size_t entry_length,
765 uint16_t attr_handle,
766 uint8_t attr_type,
767 uint64_t cv)
768{
769 size_t length =
770 pldm_bios_table_attr_value_entry_encode_integer_length();
771 assert(length <= entry_length);
772
773 struct pldm_bios_attr_val_table_entry *table_entry = entry;
774 table_entry->attr_handle = htole16(attr_handle);
775 table_entry->attr_type = attr_type;
776 cv = htole64(cv);
777 memcpy(table_entry->value, &cv, sizeof(uint64_t));
778}
779
780int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
781 size_t entry_length,
782 uint16_t attr_handle,
783 uint8_t attr_type,
784 uint64_t cv)
785{
786 POINTER_CHECK(entry);
787 size_t length =
788 pldm_bios_table_attr_value_entry_encode_integer_length();
789 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
790 BUFFER_SIZE_EXPECT(entry_length, length);
791 pldm_bios_table_attr_value_entry_encode_integer(
792 entry, entry_length, attr_handle, attr_type, cv);
793 return PLDM_SUCCESS;
794}
795
796uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
797 const struct pldm_bios_attr_val_table_entry *entry)
798{
799 uint64_t cv = 0;
800 memcpy(&cv, entry->value, sizeof(cv));
801 cv = le64toh(cv);
802 return cv;
803}
804
805static size_t attr_value_table_entry_length_integer(const void *entry)
806{
807 (void)entry;
808 return pldm_bios_table_attr_value_entry_encode_integer_length();
809}
810
811static const struct table_entry_length attr_value_table_entries[] = {
812 {.attr_type = PLDM_BIOS_ENUMERATION,
813 .entry_length_handler = attr_value_table_entry_length_enum},
814 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
815 .entry_length_handler = attr_value_table_entry_length_enum},
816 {.attr_type = PLDM_BIOS_STRING,
817 .entry_length_handler = attr_value_table_entry_length_string},
818 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
819 .entry_length_handler = attr_value_table_entry_length_string},
820 {.attr_type = PLDM_BIOS_INTEGER,
821 .entry_length_handler = attr_value_table_entry_length_integer},
822 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
823 .entry_length_handler = attr_value_table_entry_length_integer},
824};
825
826static size_t attr_value_table_entry_length(const void *table_entry)
827{
828 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
829 const struct table_entry_length *entry_length =
830 find_table_entry_length_by_type(
831 entry->attr_type, attr_value_table_entries,
832 ARRAY_SIZE(attr_value_table_entries));
833 assert(entry_length != NULL);
834 assert(entry_length->entry_length_handler != NULL);
835
836 return entry_length->entry_length_handler(entry);
837}
838
839size_t pldm_bios_table_attr_value_entry_length(
840 const struct pldm_bios_attr_val_table_entry *entry)
841{
842 return attr_value_table_entry_length(entry);
843}
844
845uint16_t pldm_bios_table_attr_value_entry_decode_handle(
846 const struct pldm_bios_attr_val_table_entry *entry)
847{
848 return le16toh(entry->attr_handle);
849}
850
851static size_t pad_size_get(size_t size_without_pad)
852{
853 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
854}
855
856static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
857{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930858 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930859 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930860 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930861
862 return table_end;
863}
864
865static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
866{
867 checksum = htole32(checksum);
868 memcpy(table_end, &checksum, sizeof(checksum));
869
870 return table_end + sizeof(checksum);
871}
872
873size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
874{
875 size_t size = pad_size_get(size_without_pad) +
876 sizeof(uint32_t) /*sizeof(checksum)*/;
877 return size;
878}
879
880size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
881 size_t size_without_pad)
882{
883
884 size_t pad_checksum_size =
885 pldm_bios_table_pad_checksum_size(size_without_pad);
886 size_t total_length = size_without_pad + pad_checksum_size;
887 assert(size >= total_length);
888
889 uint8_t *table_end = (uint8_t *)table + size_without_pad;
890 size_t pad_size = pad_size_get(size_without_pad);
891 table_end = pad_append(table_end, pad_size);
892
893 uint32_t checksum = crc32(table, size_without_pad + pad_size);
894 checksum_append(table_end, checksum);
895
896 return total_length;
897}
898
899struct pldm_bios_table_iter {
900 const uint8_t *table_data;
901 size_t table_len;
902 size_t current_pos;
903 size_t (*entry_length_handler)(const void *table_entry);
904};
905
906struct pldm_bios_table_iter *
907pldm_bios_table_iter_create(const void *table, size_t length,
908 enum pldm_bios_table_types type)
909{
910 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
911 assert(iter != NULL);
912 iter->table_data = table;
913 iter->table_len = length;
914 iter->current_pos = 0;
915 iter->entry_length_handler = NULL;
916 switch (type) {
917 case PLDM_BIOS_STRING_TABLE:
918 iter->entry_length_handler = string_table_entry_length;
919 break;
920 case PLDM_BIOS_ATTR_TABLE:
921 iter->entry_length_handler = attr_table_entry_length;
922 break;
923 case PLDM_BIOS_ATTR_VAL_TABLE:
924 iter->entry_length_handler = attr_value_table_entry_length;
925 break;
926 }
927
928 return iter;
929}
930
931void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
932{
933 free(iter);
934}
935
936#define pad_and_check_max 7
937bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
938{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930939 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930940 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930941 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930942 return false;
943}
944
945void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
946{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930947 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930949 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 const void *entry = iter->table_data + iter->current_pos;
951 iter->current_pos += iter->entry_length_handler(entry);
952}
953
954const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
955{
956 return iter->table_data + iter->current_pos;
957}
958
959typedef bool (*equal_handler)(const void *entry, const void *key);
960
961static const void *
962pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
963 const void *key, equal_handler equal)
964{
965 const void *entry;
966 while (!pldm_bios_table_iter_is_end(iter)) {
967 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930968 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930969 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930970 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930971 pldm_bios_table_iter_next(iter);
972 }
973 return NULL;
974}
975
976static const void *
977pldm_bios_table_entry_find_from_table(const void *table, size_t length,
978 enum pldm_bios_table_types type,
979 equal_handler equal, const void *key)
980{
981 struct pldm_bios_table_iter *iter =
982 pldm_bios_table_iter_create(table, length, type);
983 const void *entry =
984 pldm_bios_table_entry_find_by_iter(iter, key, equal);
985 pldm_bios_table_iter_free(iter);
986 return entry;
987}
988
989static bool string_table_handle_equal(const void *entry, const void *key)
990{
991 const struct pldm_bios_string_table_entry *string_entry = entry;
992 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930993 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
994 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930995 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930996 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930997 return false;
998}
999
1000const struct pldm_bios_string_table_entry *
1001pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1002 uint16_t handle)
1003{
1004 return pldm_bios_table_entry_find_from_table(
1005 table, length, PLDM_BIOS_STRING_TABLE, string_table_handle_equal,
1006 &handle);
1007}
1008
1009struct string_equal_arg {
1010 uint16_t str_length;
1011 const char *str;
1012};
1013
1014static bool string_table_string_equal(const void *entry, const void *key)
1015{
1016 const struct pldm_bios_string_table_entry *string_entry = entry;
1017 const struct string_equal_arg *arg = key;
1018 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301019 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301020 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301021 }
1022 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301023 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301024 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301025 return true;
1026}
1027
1028const struct pldm_bios_string_table_entry *
1029pldm_bios_table_string_find_by_string(const void *table, size_t length,
1030 const char *str)
1031{
1032 uint16_t str_length = strlen(str);
1033 struct string_equal_arg arg = {str_length, str};
1034 return pldm_bios_table_entry_find_from_table(
1035 table, length, PLDM_BIOS_STRING_TABLE, string_table_string_equal,
1036 &arg);
1037}
1038
1039static bool attr_table_handle_equal(const void *entry, const void *key)
1040{
1041 uint16_t handle = *(uint16_t *)key;
1042 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1043 handle;
1044}
1045
1046const struct pldm_bios_attr_table_entry *
1047pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1048 uint16_t handle)
1049{
1050 return pldm_bios_table_entry_find_from_table(
1051 table, length, PLDM_BIOS_ATTR_TABLE, attr_table_handle_equal,
1052 &handle);
1053}
1054
1055static bool attr_table_string_handle_equal(const void *entry, const void *key)
1056{
1057 uint16_t handle = *(uint16_t *)key;
1058 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1059}
1060
1061const struct pldm_bios_attr_table_entry *
1062pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1063 uint16_t handle)
1064{
1065 return pldm_bios_table_entry_find_from_table(
1066 table, length, PLDM_BIOS_ATTR_TABLE, attr_table_string_handle_equal,
1067 &handle);
1068}
1069
1070static bool attr_value_table_handle_equal(const void *entry, const void *key)
1071{
1072 uint16_t handle = *(uint16_t *)key;
1073 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1074}
1075
1076const struct pldm_bios_attr_val_table_entry *
1077pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1078 uint16_t handle)
1079{
1080 return pldm_bios_table_entry_find_from_table(
1081 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1082 attr_value_table_handle_equal, &handle);
1083}
1084
1085int pldm_bios_table_attr_value_copy_and_update(
1086 const void *src_table, size_t src_length, void *dest_table,
1087 size_t *dest_length, const void *entry, size_t entry_length)
1088{
1089 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
1090 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
1091
1092 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301093 const struct pldm_bios_attr_val_table_entry *tmp;
1094 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1095 size_t buffer_length = *dest_length;
1096 size_t copied_length = 0;
1097 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301098 while (!pldm_bios_table_iter_is_end(iter)) {
1099 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1100 length = attr_value_table_entry_length(tmp);
1101
1102 /* we need the tmp's entry_length here, iter_next will calculate
1103 * it too, use current_pos directly to avoid calculating it
1104 * twice */
1105 iter->current_pos += length;
1106 if (tmp->attr_handle == to_update->attr_handle) {
1107 if (tmp->attr_type != to_update->attr_type) {
1108 rc = PLDM_ERROR_INVALID_DATA;
1109 goto out;
1110 }
1111 length = entry_length;
1112 tmp = entry;
1113 }
1114 if (copied_length + length > buffer_length) {
1115 rc = PLDM_ERROR_INVALID_LENGTH;
1116 goto out;
1117 }
1118 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1119 copied_length += length;
1120 }
1121
1122 size_t pad_checksum_size =
1123 pldm_bios_table_pad_checksum_size(copied_length);
1124 if ((pad_checksum_size + copied_length) > buffer_length) {
1125 rc = PLDM_ERROR_INVALID_LENGTH;
1126 goto out;
1127 }
1128
1129 *dest_length = pldm_bios_table_append_pad_checksum(
1130 dest_table, buffer_length, copied_length);
1131out:
1132 pldm_bios_table_iter_free(iter);
1133 return rc;
1134}
1135
1136bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1137{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301138 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301139 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301140 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301141
1142 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1143 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301144 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301145 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301146 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301147
1148 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1149 uint32_t dst_crc = crc32(table, size - 4);
1150
1151 return src_crc == dst_crc;
1152}