blob: 8c04f36c060968f94ec666847a3cc8f61d81e0aa [file] [log] [blame]
John Wang02700402019-10-06 16:34:29 +08001#include <assert.h>
2#include <endian.h>
3#include <stdbool.h>
4#include <stdint.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "bios.h"
9#include "bios_table.h"
10
11#define POINTER_CHECK(pointer) \
12 do { \
13 if (pointer == NULL) \
14 return PLDM_ERROR_INVALID_DATA; \
15 } while (0)
16
17#define ATTR_TYPE_EXPECT(type, expected) \
18 do { \
19 if (type != expected && type != (expected | 0x80)) \
20 return PLDM_ERROR_INVALID_DATA; \
21 } while (0)
22
John Wang871c9272019-12-09 18:02:15 +080023static bool attribute_is_readonly(uint8_t attr_type)
24{
25 return (attr_type & 0x80);
26}
27
John Wang3ad21752019-10-06 16:42:21 +080028#define BUFFER_SIZE_EXPECT(current_size, expected_size) \
29 do { \
30 if (current_size < expected_size) \
31 return PLDM_ERROR_INVALID_LENGTH; \
32 } while (0)
33
John Wangdd9a6282019-10-11 18:52:46 +080034#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
35
John Wang827c5de2019-11-07 18:27:27 +080036static void set_errmsg(const char **errmsg, const char *msg)
37{
38 if (errmsg != NULL)
39 *errmsg = msg;
40}
41
John Wangdd9a6282019-10-11 18:52:46 +080042static uint16_t get_bios_string_handle()
43{
44 static uint16_t handle = 0;
45 assert(handle != UINT16_MAX);
46
47 return handle++;
48}
49
50size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
51{
52 return sizeof(struct pldm_bios_string_table_entry) -
53 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
54}
55
56void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
57 const char *str, uint16_t str_length)
58{
59 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
60 assert(length <= entry_length);
61 struct pldm_bios_string_table_entry *string_entry = entry;
62 string_entry->string_handle = htole16(get_bios_string_handle());
63 string_entry->string_length = htole16(str_length);
64 memcpy(string_entry->name, str, str_length);
65}
66
67int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
68 const char *str,
69 uint16_t str_length)
70{
71 if (str_length == 0)
72 return PLDM_ERROR_INVALID_DATA;
73 POINTER_CHECK(entry);
74 POINTER_CHECK(str);
75 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
76 BUFFER_SIZE_EXPECT(entry_length, length);
77 pldm_bios_table_string_entry_encode(entry, entry_length, str,
78 str_length);
79 return PLDM_SUCCESS;
80}
81
82uint16_t pldm_bios_table_string_entry_decode_handle(
83 const struct pldm_bios_string_table_entry *entry)
84{
85 return le16toh(entry->string_handle);
86}
87
88uint16_t pldm_bios_table_string_entry_decode_string_length(
89 const struct pldm_bios_string_table_entry *entry)
90{
91 return le16toh(entry->string_length);
92}
93
94uint16_t pldm_bios_table_string_entry_decode_string(
95 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
96{
97 uint16_t length =
98 pldm_bios_table_string_entry_decode_string_length(entry);
John Wang88a349c2020-01-20 14:19:49 +080099 length = length < (size - 1) ? length : (size - 1);
John Wangdd9a6282019-10-11 18:52:46 +0800100 memcpy(buffer, entry->name, length);
101 buffer[length] = 0;
102 return length;
103}
104
105int pldm_bios_table_string_entry_decode_string_check(
106 const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
107{
108 POINTER_CHECK(entry);
109 POINTER_CHECK(buffer);
110 size_t length =
111 pldm_bios_table_string_entry_decode_string_length(entry);
112 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
John Wangccc04552019-10-14 14:28:25 +0800124static uint16_t get_bios_attr_handle()
125{
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
John Wangb0da7a02020-01-07 16:55:00 +0800143uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
144 const struct pldm_bios_attr_table_entry *entry)
145{
146 return le16toh(entry->attr_handle);
147}
148
John Wang50218a62020-02-12 17:10:28 +0800149uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
150 const struct pldm_bios_attr_table_entry *entry)
151{
152 return entry->attr_type;
153}
154
John Wangb0da7a02020-01-07 16:55:00 +0800155uint16_t pldm_bios_table_attr_entry_decode_string_handle(
156 const struct pldm_bios_attr_table_entry *entry)
157{
158 return le16toh(entry->string_handle);
159}
160
John Wangccc04552019-10-14 14:28:25 +0800161size_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(
171 void *entry, size_t entry_length,
172 const struct pldm_bios_table_attr_entry_enum_info *info)
173{
174 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
175 info->pv_num, info->def_num);
176 assert(length <= entry_length);
177 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY
178 : PLDM_BIOS_ENUMERATION;
179 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 =
184 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
185 size_t i;
186 for (i = 0; i < info->pv_num; i++)
187 pv_hdls[i] = htole16(info->pv_handle[i]);
188 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
189 info->def_num;
190 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
191 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
192 info->def_index, info->def_num);
193}
194
195int pldm_bios_table_attr_entry_enum_encode_check(
196 void *entry, size_t entry_length,
197 const struct pldm_bios_table_attr_entry_enum_info *info)
198{
199 POINTER_CHECK(entry);
200 POINTER_CHECK(info);
201 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
202 info->pv_num, info->def_num);
203 BUFFER_SIZE_EXPECT(entry_length, length);
204 pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
205 return PLDM_SUCCESS;
206}
207
John Wangdd9a6282019-10-11 18:52:46 +0800208#define ATTR_TYPE_EXPECT(type, expected) \
209 do { \
210 if (type != expected && type != (expected | 0x80)) \
211 return PLDM_ERROR_INVALID_DATA; \
212 } while (0)
213
John Wang02700402019-10-06 16:34:29 +0800214uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
215 const struct pldm_bios_attr_table_entry *entry)
216{
217 return entry->metadata[0];
218}
219
220int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
221 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
222{
223 POINTER_CHECK(entry);
224 POINTER_CHECK(pv_num);
225 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
226 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
227 return PLDM_SUCCESS;
228}
229
230uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
231 const struct pldm_bios_attr_table_entry *entry)
232{
233 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
234 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
235 sizeof(uint16_t) * pv_num];
236}
237
238int pldm_bios_table_attr_entry_enum_decode_def_num_check(
239 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
240{
241 POINTER_CHECK(entry);
242 POINTER_CHECK(def_num);
243 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
244 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
245 return PLDM_SUCCESS;
246}
247
John Wang3ad21752019-10-06 16:42:21 +0800248uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
249 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
250 uint8_t pv_num)
251{
252 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
253 num = num < pv_num ? num : pv_num;
254 size_t i;
255 for (i = 0; i < num; i++) {
256 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
257 i * sizeof(uint16_t));
258 pv_hdls[i] = le16toh(*hdl);
259 }
260 return num;
261}
262
263int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
264 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
265 uint8_t pv_num)
266{
267 POINTER_CHECK(entry);
268 POINTER_CHECK(pv_hdls);
269 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
270 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
271 if (num != pv_num)
272 return PLDM_ERROR_INVALID_DATA;
273 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
274 return PLDM_SUCCESS;
275}
276
John Wang50218a62020-02-12 17:10:28 +0800277uint8_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
John Wang02700402019-10-06 16:34:29 +0800292/** @brief Get length of an enum attribute entry
293 */
John Wang49484a12019-12-02 14:21:53 +0800294static size_t attr_table_entry_length_enum(const void *entry)
John Wang02700402019-10-06 16:34:29 +0800295{
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);
John Wangccc04552019-10-14 14:28:25 +0800298 return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
John Wang02700402019-10-06 16:34:29 +0800299}
300
John Wangccc04552019-10-14 14:28:25 +0800301struct 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);
336 if (info->def_length != 0 && info->def_string != NULL)
337 memcpy(attr_fields->def_string, info->def_string,
338 info->def_length);
339}
340
John Wang827c5de2019-11-07 18:27:27 +0800341#define PLDM_STRING_TYPE_MAX 5
342#define PLDM_STRING_TYPE_VENDOR 0xff
343
344int pldm_bios_table_attr_entry_string_info_check(
345 const struct pldm_bios_table_attr_entry_string_info *info,
346 const char **errmsg)
347{
348 if (info->min_length > info->max_length) {
349 set_errmsg(errmsg, "MinimumStingLength should not be greater "
350 "than MaximumStringLength");
351 return PLDM_ERROR_INVALID_DATA;
352 }
353 if (info->min_length == info->max_length &&
354 info->def_length != info->min_length) {
355 set_errmsg(errmsg, "Wrong DefaultStringLength");
356 return PLDM_ERROR_INVALID_DATA;
357 }
358 if (info->def_length > info->max_length ||
359 info->def_length < info->min_length) {
360 set_errmsg(errmsg, "Wrong DefaultStringLength");
361 return PLDM_ERROR_INVALID_DATA;
362 }
363 if (info->string_type > PLDM_STRING_TYPE_MAX &&
364 info->string_type != PLDM_STRING_TYPE_VENDOR) {
365 set_errmsg(errmsg, "Wrong StringType");
366 return PLDM_ERROR_INVALID_DATA;
367 }
368 if (info->def_length != strlen(info->def_string)) {
369 set_errmsg(errmsg, "Length of DefaultString should be equal to "
370 "DefaultStringLength");
371 return PLDM_ERROR_INVALID_DATA;
372 }
373
374 return PLDM_SUCCESS;
375}
376
John Wangccc04552019-10-14 14:28:25 +0800377int pldm_bios_table_attr_entry_string_encode_check(
378 void *entry, size_t entry_length,
379 const struct pldm_bios_table_attr_entry_string_info *info)
380{
381 POINTER_CHECK(entry);
382 POINTER_CHECK(info);
383 size_t length =
384 pldm_bios_table_attr_entry_string_encode_length(info->def_length);
385 BUFFER_SIZE_EXPECT(entry_length, length);
John Wang827c5de2019-11-07 18:27:27 +0800386 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
387 PLDM_SUCCESS)
John Wangccc04552019-10-14 14:28:25 +0800388 return PLDM_ERROR_INVALID_DATA;
389 pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
390 return PLDM_SUCCESS;
391}
John Wang02700402019-10-06 16:34:29 +0800392
393uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
394 const struct pldm_bios_attr_table_entry *entry)
395{
John Wangccc04552019-10-14 14:28:25 +0800396 struct attr_table_string_entry_fields *fields =
397 (struct attr_table_string_entry_fields *)entry->metadata;
398 return le16toh(fields->def_length);
John Wang02700402019-10-06 16:34:29 +0800399}
400
401int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
402 const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
403{
404 POINTER_CHECK(entry);
405 POINTER_CHECK(def_string_length);
406 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
407 *def_string_length =
408 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
409 return PLDM_SUCCESS;
410}
411
John Wangb0da7a02020-01-07 16:55:00 +0800412uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
413 const struct pldm_bios_attr_table_entry *entry)
414{
415 struct attr_table_string_entry_fields *fields =
416 (struct attr_table_string_entry_fields *)entry->metadata;
417 return fields->string_type;
418}
419
John Wang50218a62020-02-12 17:10:28 +0800420uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
421 const struct pldm_bios_attr_table_entry *entry)
422{
423 struct attr_table_string_entry_fields *fields =
424 (struct attr_table_string_entry_fields *)entry->metadata;
425 return le16toh(fields->max_length);
426}
427
428uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
429 const struct pldm_bios_attr_table_entry *entry)
430{
431 struct attr_table_string_entry_fields *fields =
432 (struct attr_table_string_entry_fields *)entry->metadata;
433 return le16toh(fields->min_length);
434}
435
436uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
437 const struct pldm_bios_attr_table_entry *entry, char *buffer, size_t size)
438{
439 uint16_t length =
440 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
441 length = length < (size - 1) ? length : (size - 1);
442 struct attr_table_string_entry_fields *fields =
443 (struct attr_table_string_entry_fields *)entry->metadata;
444 memcpy(buffer, fields->def_string, length);
445 buffer[length] = 0;
446 return length;
447}
448
John Wang02700402019-10-06 16:34:29 +0800449/** @brief Get length of a string attribute entry
450 */
John Wang49484a12019-12-02 14:21:53 +0800451static size_t attr_table_entry_length_string(const void *entry)
John Wang02700402019-10-06 16:34:29 +0800452{
John Wangccc04552019-10-14 14:28:25 +0800453 uint16_t def_str_len =
John Wang02700402019-10-06 16:34:29 +0800454 pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
John Wangccc04552019-10-14 14:28:25 +0800455 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
John Wang02700402019-10-06 16:34:29 +0800456}
457
John Wangca230822019-10-16 11:39:27 +0800458struct attr_table_integer_entry_fields {
459 uint64_t lower_bound;
460 uint64_t upper_bound;
461 uint32_t scalar_increment;
462 uint64_t default_value;
463} __attribute__((packed));
464
465size_t pldm_bios_table_attr_entry_integer_encode_length()
466{
467 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
468 sizeof(struct attr_table_integer_entry_fields);
469}
470
471void pldm_bios_table_attr_entry_integer_encode(
472 void *entry, size_t entry_length,
473 const struct pldm_bios_table_attr_entry_integer_info *info)
474{
475 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
476 assert(length <= entry_length);
477 uint8_t attr_type =
478 info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY : PLDM_BIOS_INTEGER;
479 attr_table_entry_encode_header(entry, entry_length, attr_type,
480 info->name_handle);
481 struct pldm_bios_attr_table_entry *attr_entry = entry;
482 struct attr_table_integer_entry_fields *attr_fields =
483 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
484 attr_fields->lower_bound = htole64(info->lower_bound);
485 attr_fields->upper_bound = htole64(info->upper_bound);
486 attr_fields->scalar_increment = htole32(info->scalar_increment);
487 attr_fields->default_value = htole64(info->default_value);
488}
489
John Wang827c5de2019-11-07 18:27:27 +0800490int pldm_bios_table_attr_entry_integer_info_check(
491 const struct pldm_bios_table_attr_entry_integer_info *info,
492 const char **errmsg)
493{
494 if (info->lower_bound == info->upper_bound) {
495 if (info->default_value != info->lower_bound) {
496 set_errmsg(errmsg, "Wrong DefaultValue");
497 return PLDM_ERROR_INVALID_DATA;
498 }
499 if (info->scalar_increment != 0) {
500 set_errmsg(errmsg, "Wrong ScalarIncrement");
501 return PLDM_ERROR_INVALID_DATA;
502 }
503 return PLDM_SUCCESS;
504 }
505 if (info->lower_bound > info->upper_bound) {
506 set_errmsg(errmsg,
507 "LowerBound should not be greater than UpperBound");
508 return PLDM_ERROR_INVALID_DATA;
509 }
510 if (info->default_value > info->upper_bound ||
511 info->default_value < info->lower_bound) {
512 set_errmsg(errmsg, "Wrong DefaultValue");
513 return PLDM_ERROR_INVALID_DATA;
514 }
515 if (info->scalar_increment == 0) {
516 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
517 "lower_bound != upper_bound");
518 return PLDM_ERROR_INVALID_DATA;
519 }
520 if ((info->default_value - info->lower_bound) %
521 info->scalar_increment !=
522 0) {
523 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
524 return PLDM_ERROR_INVALID_DATA;
525 }
526 return PLDM_SUCCESS;
527}
528
John Wangca230822019-10-16 11:39:27 +0800529int pldm_bios_table_attr_entry_integer_encode_check(
530 void *entry, size_t entry_length,
531 const struct pldm_bios_table_attr_entry_integer_info *info)
532{
533 POINTER_CHECK(entry);
534 POINTER_CHECK(info);
535 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
536 BUFFER_SIZE_EXPECT(entry_length, length);
John Wang827c5de2019-11-07 18:27:27 +0800537 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
538 PLDM_SUCCESS)
John Wangca230822019-10-16 11:39:27 +0800539 return PLDM_ERROR_INVALID_DATA;
540 pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
541 return PLDM_SUCCESS;
542}
543
John Wang50218a62020-02-12 17:10:28 +0800544void pldm_bios_table_attr_entry_integer_decode(
545 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
546 uint64_t *upper, uint32_t *scalar, uint64_t *def)
547{
548 struct attr_table_integer_entry_fields *fields =
549 (struct attr_table_integer_entry_fields *)entry->metadata;
550 *lower = le64toh(fields->lower_bound);
551 *upper = le64toh(fields->upper_bound);
552 *scalar = le32toh(fields->scalar_increment);
553 *def = le64toh(fields->default_value);
554}
555
John Wang49484a12019-12-02 14:21:53 +0800556static size_t attr_table_entry_length_integer(const void *entry)
John Wangca230822019-10-16 11:39:27 +0800557{
558 (void)entry;
559 return pldm_bios_table_attr_entry_integer_encode_length();
560}
561
John Wang49484a12019-12-02 14:21:53 +0800562struct table_entry_length {
John Wang02700402019-10-06 16:34:29 +0800563 uint8_t attr_type;
John Wang49484a12019-12-02 14:21:53 +0800564 size_t (*entry_length_handler)(const void *);
John Wang02700402019-10-06 16:34:29 +0800565};
566
John Wang49484a12019-12-02 14:21:53 +0800567#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
568
John Wangb6333cb2019-12-10 09:43:42 +0800569static const struct table_entry_length *find_table_entry_length_by_type(
570 uint8_t attr_type, const struct table_entry_length *handlers, size_t count)
John Wang49484a12019-12-02 14:21:53 +0800571{
572 size_t i;
573 for (i = 0; i < count; i++) {
574 if (attr_type == handlers[i].attr_type)
575 return &handlers[i];
576 }
577 return NULL;
578}
579
John Wangb6333cb2019-12-10 09:43:42 +0800580static const struct table_entry_length attr_table_entries[] = {
John Wang02700402019-10-06 16:34:29 +0800581 {.attr_type = PLDM_BIOS_ENUMERATION,
582 .entry_length_handler = attr_table_entry_length_enum},
583 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
584 .entry_length_handler = attr_table_entry_length_enum},
585 {.attr_type = PLDM_BIOS_STRING,
586 .entry_length_handler = attr_table_entry_length_string},
587 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
588 .entry_length_handler = attr_table_entry_length_string},
John Wangca230822019-10-16 11:39:27 +0800589 {.attr_type = PLDM_BIOS_INTEGER,
590 .entry_length_handler = attr_table_entry_length_integer},
591 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
592 .entry_length_handler = attr_table_entry_length_integer},
John Wang02700402019-10-06 16:34:29 +0800593};
594
John Wang02700402019-10-06 16:34:29 +0800595static size_t attr_table_entry_length(const void *table_entry)
596{
597 const struct pldm_bios_attr_table_entry *entry = table_entry;
John Wangb6333cb2019-12-10 09:43:42 +0800598 const struct table_entry_length *attr_table_entry =
John Wang49484a12019-12-02 14:21:53 +0800599 find_table_entry_length_by_type(entry->attr_type,
600 attr_table_entries,
601 ARRAY_SIZE(attr_table_entries));
John Wang02700402019-10-06 16:34:29 +0800602 assert(attr_table_entry != NULL);
603 assert(attr_table_entry->entry_length_handler != NULL);
604
605 return attr_table_entry->entry_length_handler(entry);
606}
607
John Wangb0da7a02020-01-07 16:55:00 +0800608uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
609 const struct pldm_bios_attr_val_table_entry *entry)
610{
611 return le16toh(entry->attr_handle);
612}
613
614uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
615 const struct pldm_bios_attr_val_table_entry *entry)
616{
617 return entry->attr_type;
618}
619
John Wang3ad21752019-10-06 16:42:21 +0800620size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
621{
622 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
623 sizeof(count) + count;
624}
625
626void pldm_bios_table_attr_value_entry_encode_enum(
627 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
628 uint8_t count, uint8_t *handles)
629{
630 size_t length =
631 pldm_bios_table_attr_value_entry_encode_enum_length(count);
632 assert(length <= entry_length);
633
634 struct pldm_bios_attr_val_table_entry *table_entry = entry;
635 table_entry->attr_handle = htole16(attr_handle);
636 table_entry->attr_type = attr_type;
637 table_entry->value[0] = count;
638 if (count != 0)
639 memcpy(&table_entry->value[1], handles, count);
640}
641
John Wang49484a12019-12-02 14:21:53 +0800642uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
643 const struct pldm_bios_attr_val_table_entry *entry)
644{
645 return entry->value[0];
646}
647
John Wangb0da7a02020-01-07 16:55:00 +0800648uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
649 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
650 uint8_t number)
651{
652 uint8_t curr_num =
653 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
654 number = number < curr_num ? number : curr_num;
655 memcpy(handles, &entry->value[1], number);
656
657 return number;
658}
659
John Wang3ad21752019-10-06 16:42:21 +0800660int pldm_bios_table_attr_value_entry_encode_enum_check(
661 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
662 uint8_t count, uint8_t *handles)
663{
664 POINTER_CHECK(entry);
665 if (count != 0 && handles == NULL)
666 return PLDM_ERROR_INVALID_DATA;
667 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
668 size_t length =
669 pldm_bios_table_attr_value_entry_encode_enum_length(count);
670 BUFFER_SIZE_EXPECT(entry_length, length);
671 pldm_bios_table_attr_value_entry_encode_enum(
672 entry, entry_length, attr_handle, attr_type, count, handles);
673 return PLDM_SUCCESS;
674}
675
John Wang49484a12019-12-02 14:21:53 +0800676static size_t attr_value_table_entry_length_enum(const void *entry)
677{
678 uint8_t number =
679 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
680 return pldm_bios_table_attr_value_entry_encode_enum_length(number);
681}
682
John Wang3ad21752019-10-06 16:42:21 +0800683size_t
684pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
685{
686 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
687 sizeof(string_length) + string_length;
688}
689
690void pldm_bios_table_attr_value_entry_encode_string(
691 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
692 uint16_t str_length, const char *str)
693{
694 size_t length =
695 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
696 assert(length <= entry_length);
697
698 struct pldm_bios_attr_val_table_entry *table_entry = entry;
699 table_entry->attr_handle = htole16(attr_handle);
700 table_entry->attr_type = attr_type;
701 if (str_length != 0)
702 memcpy(table_entry->value + sizeof(str_length), str,
703 str_length);
704 str_length = htole16(str_length);
705 memcpy(table_entry->value, &str_length, sizeof(str_length));
706}
707
John Wang49484a12019-12-02 14:21:53 +0800708uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
709 const struct pldm_bios_attr_val_table_entry *entry)
710{
711 uint16_t str_length = 0;
712 memcpy(&str_length, entry->value, sizeof(str_length));
713 return le16toh(str_length);
714}
715
John Wangb0da7a02020-01-07 16:55:00 +0800716void pldm_bios_table_attr_value_entry_string_decode_string(
717 const struct pldm_bios_attr_val_table_entry *entry,
718 struct variable_field *current_string)
719{
720 current_string->length =
721 pldm_bios_table_attr_value_entry_string_decode_length(entry);
722 current_string->ptr =
723 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
724}
725
John Wang3ad21752019-10-06 16:42:21 +0800726int pldm_bios_table_attr_value_entry_encode_string_check(
727 void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
728 uint16_t str_length, const char *str)
729{
730 POINTER_CHECK(entry);
731 if (str_length != 0 && str == NULL)
732 return PLDM_ERROR_INVALID_DATA;
733 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
734 size_t length =
735 pldm_bios_table_attr_value_entry_encode_string_length(str_length);
736 BUFFER_SIZE_EXPECT(entry_length, length);
737 pldm_bios_table_attr_value_entry_encode_string(
738 entry, entry_length, attr_handle, attr_type, str_length, str);
739 return PLDM_SUCCESS;
740}
741
John Wang49484a12019-12-02 14:21:53 +0800742static size_t attr_value_table_entry_length_string(const void *entry)
743{
744 uint16_t str_length =
745 pldm_bios_table_attr_value_entry_string_decode_length(entry);
746 return pldm_bios_table_attr_value_entry_encode_string_length(
747 str_length);
748}
749
John Wangca230822019-10-16 11:39:27 +0800750size_t pldm_bios_table_attr_value_entry_encode_integer_length()
751{
752 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
753 sizeof(uint64_t);
754}
755void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
756 size_t entry_length,
757 uint16_t attr_handle,
758 uint8_t attr_type,
759 uint64_t cv)
760{
761 size_t length =
762 pldm_bios_table_attr_value_entry_encode_integer_length();
763 assert(length <= entry_length);
764
765 struct pldm_bios_attr_val_table_entry *table_entry = entry;
766 table_entry->attr_handle = htole16(attr_handle);
767 table_entry->attr_type = attr_type;
768 cv = htole64(cv);
769 memcpy(table_entry->value, &cv, sizeof(uint64_t));
770}
771
772int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
773 size_t entry_length,
774 uint16_t attr_handle,
775 uint8_t attr_type,
776 uint64_t cv)
777{
778 POINTER_CHECK(entry);
779 size_t length =
780 pldm_bios_table_attr_value_entry_encode_integer_length();
781 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
782 BUFFER_SIZE_EXPECT(entry_length, length);
783 pldm_bios_table_attr_value_entry_encode_integer(
784 entry, entry_length, attr_handle, attr_type, cv);
785 return PLDM_SUCCESS;
786}
787
John Wangb0da7a02020-01-07 16:55:00 +0800788uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
789 const struct pldm_bios_attr_val_table_entry *entry)
790{
791 uint64_t cv = 0;
792 memcpy(&cv, entry->value, sizeof(cv));
793 cv = le64toh(cv);
794 return cv;
795}
796
John Wang49484a12019-12-02 14:21:53 +0800797static size_t attr_value_table_entry_length_integer(const void *entry)
798{
799 (void)entry;
800 return pldm_bios_table_attr_value_entry_encode_integer_length();
801}
802
John Wangb6333cb2019-12-10 09:43:42 +0800803static const struct table_entry_length attr_value_table_entries[] = {
John Wang49484a12019-12-02 14:21:53 +0800804 {.attr_type = PLDM_BIOS_ENUMERATION,
805 .entry_length_handler = attr_value_table_entry_length_enum},
806 {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
807 .entry_length_handler = attr_value_table_entry_length_enum},
808 {.attr_type = PLDM_BIOS_STRING,
809 .entry_length_handler = attr_value_table_entry_length_string},
810 {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
811 .entry_length_handler = attr_value_table_entry_length_string},
812 {.attr_type = PLDM_BIOS_INTEGER,
813 .entry_length_handler = attr_value_table_entry_length_integer},
814 {.attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
815 .entry_length_handler = attr_value_table_entry_length_integer},
816};
817
818static size_t attr_value_table_entry_length(const void *table_entry)
819{
820 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
John Wangb6333cb2019-12-10 09:43:42 +0800821 const struct table_entry_length *entry_length =
John Wang49484a12019-12-02 14:21:53 +0800822 find_table_entry_length_by_type(
823 entry->attr_type, attr_value_table_entries,
824 ARRAY_SIZE(attr_value_table_entries));
825 assert(entry_length != NULL);
826 assert(entry_length->entry_length_handler != NULL);
827
828 return entry_length->entry_length_handler(entry);
829}
830
John Wang8e877e02020-02-03 16:06:55 +0800831size_t pldm_bios_table_attr_value_entry_length(
832 const struct pldm_bios_attr_val_table_entry *entry)
833{
834 return attr_value_table_entry_length(entry);
835}
836
John Wang3342adb2019-11-29 16:03:58 +0800837uint16_t pldm_bios_table_attr_value_entry_decode_handle(
838 const struct pldm_bios_attr_val_table_entry *entry)
839{
840 return le16toh(entry->attr_handle);
841}
842
John Wang79c37f12019-10-31 15:46:31 +0800843static size_t pad_size_get(size_t size_without_pad)
844{
845 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
846}
847
848static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
849{
850 while (pad_size--)
851 *table_end++ = 0;
852
853 return table_end;
854}
855
856static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
857{
858 checksum = htole32(checksum);
859 memcpy(table_end, &checksum, sizeof(checksum));
860
861 return table_end + sizeof(checksum);
862}
863
864size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
865{
866 size_t size = pad_size_get(size_without_pad) +
867 sizeof(uint32_t) /*sizeof(checksum)*/;
868 return size;
869}
870
John Wang871c9272019-12-09 18:02:15 +0800871size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
872 size_t size_without_pad)
John Wang79c37f12019-10-31 15:46:31 +0800873{
874
875 size_t pad_checksum_size =
876 pldm_bios_table_pad_checksum_size(size_without_pad);
John Wang871c9272019-12-09 18:02:15 +0800877 size_t total_length = size_without_pad + pad_checksum_size;
878 assert(size >= total_length);
John Wang79c37f12019-10-31 15:46:31 +0800879
880 uint8_t *table_end = (uint8_t *)table + size_without_pad;
881 size_t pad_size = pad_size_get(size_without_pad);
882 table_end = pad_append(table_end, pad_size);
883
884 uint32_t checksum = crc32(table, size_without_pad + pad_size);
885 checksum_append(table_end, checksum);
John Wang871c9272019-12-09 18:02:15 +0800886
887 return total_length;
John Wang79c37f12019-10-31 15:46:31 +0800888}
889
John Wang02700402019-10-06 16:34:29 +0800890struct pldm_bios_table_iter {
891 const uint8_t *table_data;
892 size_t table_len;
893 size_t current_pos;
894 size_t (*entry_length_handler)(const void *table_entry);
895};
896
897struct pldm_bios_table_iter *
898pldm_bios_table_iter_create(const void *table, size_t length,
899 enum pldm_bios_table_types type)
900{
901 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
902 assert(iter != NULL);
903 iter->table_data = table;
904 iter->table_len = length;
905 iter->current_pos = 0;
906 iter->entry_length_handler = NULL;
907 switch (type) {
908 case PLDM_BIOS_STRING_TABLE:
John Wangdd9a6282019-10-11 18:52:46 +0800909 iter->entry_length_handler = string_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800910 break;
911 case PLDM_BIOS_ATTR_TABLE:
912 iter->entry_length_handler = attr_table_entry_length;
913 break;
914 case PLDM_BIOS_ATTR_VAL_TABLE:
John Wang49484a12019-12-02 14:21:53 +0800915 iter->entry_length_handler = attr_value_table_entry_length;
John Wang02700402019-10-06 16:34:29 +0800916 break;
917 }
918
919 return iter;
920}
921
922void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
923{
924 free(iter);
925}
926
927#define pad_and_check_max 7
928bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
929{
930 if (iter->table_len - iter->current_pos <= pad_and_check_max)
931 return true;
932 return false;
933}
934
935void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
936{
937 if (pldm_bios_table_iter_is_end(iter))
938 return;
939 const void *entry = iter->table_data + iter->current_pos;
940 iter->current_pos += iter->entry_length_handler(entry);
941}
942
943const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
944{
945 return iter->table_data + iter->current_pos;
John Wang3ad21752019-10-06 16:42:21 +0800946}
John Wangdd9a6282019-10-11 18:52:46 +0800947
John Wang3342adb2019-11-29 16:03:58 +0800948typedef bool (*equal_handler)(const void *entry, const void *key);
949
John Wangdd9a6282019-10-11 18:52:46 +0800950static const void *
John Wang3342adb2019-11-29 16:03:58 +0800951pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
952 const void *key, equal_handler equal)
John Wangdd9a6282019-10-11 18:52:46 +0800953{
954 const void *entry;
955 while (!pldm_bios_table_iter_is_end(iter)) {
956 entry = pldm_bios_table_iter_value(iter);
957 if (equal(entry, key))
958 return entry;
959 pldm_bios_table_iter_next(iter);
960 }
961 return NULL;
962}
963
John Wang3342adb2019-11-29 16:03:58 +0800964static const void *
965pldm_bios_table_entry_find_from_table(const void *table, size_t length,
966 enum pldm_bios_table_types type,
967 equal_handler equal, const void *key)
968{
969 struct pldm_bios_table_iter *iter =
970 pldm_bios_table_iter_create(table, length, type);
971 const void *entry =
972 pldm_bios_table_entry_find_by_iter(iter, key, equal);
973 pldm_bios_table_iter_free(iter);
974 return entry;
975}
976
977static bool string_table_handle_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +0800978{
979 const struct pldm_bios_string_table_entry *string_entry = entry;
980 uint16_t handle = *(uint16_t *)key;
981 if (pldm_bios_table_string_entry_decode_handle(string_entry) == handle)
982 return true;
983 return false;
984}
985
John Wang3342adb2019-11-29 16:03:58 +0800986const struct pldm_bios_string_table_entry *
987pldm_bios_table_string_find_by_handle(const void *table, size_t length,
988 uint16_t handle)
989{
990 return pldm_bios_table_entry_find_from_table(
991 table, length, PLDM_BIOS_STRING_TABLE, string_table_handle_equal,
992 &handle);
993}
994
John Wangdd9a6282019-10-11 18:52:46 +0800995struct string_equal_arg {
996 uint16_t str_length;
997 const char *str;
998};
999
John Wang3342adb2019-11-29 16:03:58 +08001000static bool string_table_string_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +08001001{
1002 const struct pldm_bios_string_table_entry *string_entry = entry;
1003 const struct string_equal_arg *arg = key;
1004 if (arg->str_length !=
1005 pldm_bios_table_string_entry_decode_string_length(string_entry))
1006 return false;
1007 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0)
1008 return false;
1009 return true;
1010}
1011
1012const struct pldm_bios_string_table_entry *
1013pldm_bios_table_string_find_by_string(const void *table, size_t length,
1014 const char *str)
1015{
1016 uint16_t str_length = strlen(str);
1017 struct string_equal_arg arg = {str_length, str};
John Wang3342adb2019-11-29 16:03:58 +08001018 return pldm_bios_table_entry_find_from_table(
1019 table, length, PLDM_BIOS_STRING_TABLE, string_table_string_equal,
1020 &arg);
John Wangdd9a6282019-10-11 18:52:46 +08001021}
1022
John Wangb0da7a02020-01-07 16:55:00 +08001023static bool attr_table_handle_equal(const void *entry, const void *key)
1024{
1025 uint16_t handle = *(uint16_t *)key;
1026 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1027 handle;
1028}
1029
1030const struct pldm_bios_attr_table_entry *
1031pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1032 uint16_t handle)
1033{
1034 return pldm_bios_table_entry_find_from_table(
1035 table, length, PLDM_BIOS_ATTR_TABLE, attr_table_handle_equal,
1036 &handle);
1037}
1038
John Wang3342adb2019-11-29 16:03:58 +08001039static bool attr_value_table_handle_equal(const void *entry, const void *key)
John Wangdd9a6282019-10-11 18:52:46 +08001040{
John Wang3342adb2019-11-29 16:03:58 +08001041 uint16_t handle = *(uint16_t *)key;
1042 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1043}
1044
1045const struct pldm_bios_attr_val_table_entry *
1046pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1047 uint16_t handle)
1048{
1049 return pldm_bios_table_entry_find_from_table(
1050 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1051 attr_value_table_handle_equal, &handle);
John Wangdd9a6282019-10-11 18:52:46 +08001052}
John Wang871c9272019-12-09 18:02:15 +08001053
1054int pldm_bios_table_attr_value_copy_and_update(
1055 const void *src_table, size_t src_length, void *dest_table,
1056 size_t *dest_length, const void *entry, size_t entry_length)
1057{
1058 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
1059 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
1060
1061 int rc = PLDM_SUCCESS;
John Wange176a652020-02-14 14:57:50 +08001062 const struct pldm_bios_attr_val_table_entry *tmp, *to_update = entry;
John Wang871c9272019-12-09 18:02:15 +08001063 size_t buffer_length = *dest_length, copied_length = 0, length = 0;
1064 while (!pldm_bios_table_iter_is_end(iter)) {
1065 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1066 length = attr_value_table_entry_length(tmp);
1067
1068 /* we need the tmp's entry_length here, iter_next will calculate
1069 * it too, use current_pos directly to avoid calculating it
1070 * twice */
1071 iter->current_pos += length;
John Wange176a652020-02-14 14:57:50 +08001072 if (tmp->attr_handle == to_update->attr_handle) {
1073 if (tmp->attr_type != to_update->attr_type) {
1074 rc = PLDM_ERROR_INVALID_DATA;
1075 goto out;
1076 }
John Wang871c9272019-12-09 18:02:15 +08001077 if (attribute_is_readonly(tmp->attr_type)) {
1078 rc = PLDM_ERROR_INVALID_DATA;
1079 goto out;
1080 }
1081 length = entry_length;
1082 tmp = entry;
1083 }
1084 if (copied_length + length > buffer_length) {
1085 rc = PLDM_ERROR_INVALID_LENGTH;
1086 goto out;
1087 }
1088 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1089 copied_length += length;
1090 }
1091
1092 size_t pad_checksum_size =
1093 pldm_bios_table_pad_checksum_size(copied_length);
1094 if ((pad_checksum_size + copied_length) > buffer_length) {
1095 rc = PLDM_ERROR_INVALID_LENGTH;
1096 goto out;
1097 }
1098
1099 *dest_length = pldm_bios_table_append_pad_checksum(
1100 dest_table, buffer_length, copied_length);
1101out:
1102 pldm_bios_table_iter_free(iter);
1103 return rc;
1104}