blob: 9a64e5799df8bdd67c450449b990db368dab921a [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
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093047LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093048size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
49{
50 return sizeof(struct pldm_bios_string_table_entry) -
51 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
52}
53
Andrew Jefferyd47e8ab2023-06-13 14:20:36 +093054LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +093055void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
56 const char *str, uint16_t str_length)
57{
58 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
59 assert(length <= entry_length);
60 struct pldm_bios_string_table_entry *string_entry = entry;
61 string_entry->string_handle = htole16(get_bios_string_handle());
62 string_entry->string_length = htole16(str_length);
63 memcpy(string_entry->name, str, str_length);
64}
65
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093066LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093067int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
68 const char *str,
69 uint16_t str_length)
70{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093071 if (str_length == 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093072 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093073 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093074 POINTER_CHECK(entry);
75 POINTER_CHECK(str);
76 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
77 BUFFER_SIZE_EXPECT(entry_length, length);
78 pldm_bios_table_string_entry_encode(entry, entry_length, str,
79 str_length);
80 return PLDM_SUCCESS;
81}
82
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093083LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093084uint16_t pldm_bios_table_string_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093085 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093086{
87 return le16toh(entry->string_handle);
88}
89
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093090LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093091uint16_t pldm_bios_table_string_entry_decode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093092 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093093{
94 return le16toh(entry->string_length);
95}
96
Andrew Jefferyd47e8ab2023-06-13 14:20:36 +093097LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +093098uint16_t pldm_bios_table_string_entry_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093099 const struct pldm_bios_string_table_entry *entry, char *buffer,
100 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930101{
102 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930103 pldm_bios_table_string_entry_decode_string_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930104 length = length < (size - 1) ? length : (size - 1);
105 memcpy(buffer, entry->name, length);
106 buffer[length] = 0;
107 return length;
108}
109
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930110LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930111int pldm_bios_table_string_entry_decode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930112 const struct pldm_bios_string_table_entry *entry, char *buffer,
113 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930114{
115 POINTER_CHECK(entry);
116 POINTER_CHECK(buffer);
Andrew Jeffery98c1e692023-06-14 14:41:19 +0930117 if (size == 0) {
118 return PLDM_ERROR_INVALID_LENGTH;
119 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930120 pldm_bios_table_string_entry_decode_string(entry, buffer, size);
121 return PLDM_SUCCESS;
122}
123
124static size_t string_table_entry_length(const void *table_entry)
125{
126 const struct pldm_bios_string_table_entry *entry = table_entry;
127 return sizeof(*entry) - sizeof(entry->name) +
128 pldm_bios_table_string_entry_decode_string_length(entry);
129}
130
Andrew Jeffery319304f2023-04-05 13:53:18 +0930131static uint16_t get_bios_attr_handle(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930132{
133 static uint16_t handle = 0;
134 assert(handle != UINT16_MAX);
135
136 return handle++;
137}
138
139static void attr_table_entry_encode_header(void *entry, size_t length,
140 uint8_t attr_type,
141 uint16_t string_handle)
142{
143 struct pldm_bios_attr_table_entry *attr_entry = entry;
144 assert(sizeof(*attr_entry) <= length);
145 attr_entry->attr_handle = htole16(get_bios_attr_handle());
146 attr_entry->attr_type = attr_type;
147 attr_entry->string_handle = htole16(string_handle);
148}
149
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930150LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930151uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930152 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930153{
154 return le16toh(entry->attr_handle);
155}
156
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930157LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930158uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930159 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930160{
161 return entry->attr_type;
162}
163
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930164LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930165uint16_t pldm_bios_table_attr_entry_decode_string_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930166 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930167{
168 return le16toh(entry->string_handle);
169}
170
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930171LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930172size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
173 uint8_t def_num)
174{
175 return sizeof(struct pldm_bios_attr_table_entry) -
176 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
177 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
178 def_num;
179}
180
Andrew Jefferyd47e8ab2023-06-13 14:20:36 +0930181LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930182void pldm_bios_table_attr_entry_enum_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930183 void *entry, size_t entry_length,
184 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185{
186 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930187 info->pv_num, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930188 assert(length <= entry_length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930189 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
190 PLDM_BIOS_ENUMERATION;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930191 attr_table_entry_encode_header(entry, entry_length, attr_type,
192 info->name_handle);
193 struct pldm_bios_attr_table_entry *attr_entry = entry;
194 attr_entry->metadata[0] = info->pv_num;
195 uint16_t *pv_hdls =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930196 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930197 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930198 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930199 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930200 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930201 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930202 info->def_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930203 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930204 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930205 info->def_index, info->def_num);
206}
207
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930208LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930209int pldm_bios_table_attr_entry_enum_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930210 void *entry, size_t entry_length,
211 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930212{
213 POINTER_CHECK(entry);
214 POINTER_CHECK(info);
215 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930216 info->pv_num, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930217 BUFFER_SIZE_EXPECT(entry_length, length);
218 pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
219 return PLDM_SUCCESS;
220}
221
222#define ATTR_TYPE_EXPECT(type, expected) \
223 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930224 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930225 return PLDM_ERROR_INVALID_DATA; \
226 } while (0)
227
Andrew Jefferyd47e8ab2023-06-13 14:20:36 +0930228LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930229uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930230 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930231{
232 return entry->metadata[0];
233}
234
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930235LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930236int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930237 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930238{
239 POINTER_CHECK(entry);
240 POINTER_CHECK(pv_num);
241 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
242 *pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
243 return PLDM_SUCCESS;
244}
245
Andrew Jefferyd47e8ab2023-06-13 14:20:36 +0930246LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930247uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930248 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930249{
250 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
251 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
252 sizeof(uint16_t) * pv_num];
253}
254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930255LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930256int pldm_bios_table_attr_entry_enum_decode_def_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930257 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930258{
259 POINTER_CHECK(entry);
260 POINTER_CHECK(def_num);
261 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
262 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
263 return PLDM_SUCCESS;
264}
265
Andrew Jefferyd47e8ab2023-06-13 14:20:36 +0930266LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930267uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930268 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
269 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930270{
271 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
272 num = num < pv_num ? num : pv_num;
273 size_t i;
274 for (i = 0; i < num; i++) {
275 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
276 i * sizeof(uint16_t));
277 pv_hdls[i] = le16toh(*hdl);
278 }
279 return num;
280}
281
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930282LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930284 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
285 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930286{
287 POINTER_CHECK(entry);
288 POINTER_CHECK(pv_hdls);
289 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930290 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
291 return PLDM_SUCCESS;
292}
293
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930294LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930295uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930296 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
297 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930298{
299 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
300 num = num < def_num ? num : def_num;
301 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
302 const uint8_t *p = entry->metadata +
303 sizeof(uint8_t) /* number of possible values*/
304 + pv_num * sizeof(uint16_t) /* possible values */
305 + sizeof(uint8_t); /* number of default values */
306 memcpy(def_indices, p, num);
307 return num;
308}
309
310/** @brief Get length of an enum attribute entry
311 */
312static size_t attr_table_entry_length_enum(const void *entry)
313{
314 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
315 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
316 return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
317}
318
319struct attr_table_string_entry_fields {
320 uint8_t string_type;
321 uint16_t min_length;
322 uint16_t max_length;
323 uint16_t def_length;
324 uint8_t def_string[1];
325} __attribute__((packed));
326
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930327LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
329{
330 return sizeof(struct pldm_bios_attr_table_entry) -
331 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
332 sizeof(struct attr_table_string_entry_fields) -
333 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
334 def_str_len;
335}
336
Andrew Jefferyd47e8ab2023-06-13 14:20:36 +0930337LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930338void pldm_bios_table_attr_entry_string_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930339 void *entry, size_t entry_length,
340 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930341{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930342 size_t length = pldm_bios_table_attr_entry_string_encode_length(
343 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930344 assert(length <= entry_length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930345 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
346 PLDM_BIOS_STRING;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930347 attr_table_entry_encode_header(entry, entry_length, attr_type,
348 info->name_handle);
349 struct pldm_bios_attr_table_entry *attr_entry = entry;
350 struct attr_table_string_entry_fields *attr_fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930351 (struct attr_table_string_entry_fields *)attr_entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930352 attr_fields->string_type = info->string_type;
353 attr_fields->min_length = htole16(info->min_length);
354 attr_fields->max_length = htole16(info->max_length);
355 attr_fields->def_length = htole16(info->def_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930356 if (info->def_length != 0 && info->def_string != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930357 memcpy(attr_fields->def_string, info->def_string,
358 info->def_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930359 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930360}
361
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930362#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930363#define PLDM_STRING_TYPE_VENDOR 0xff
364
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930365LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930366int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930367 const struct pldm_bios_table_attr_entry_string_info *info,
368 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930369{
370 if (info->min_length > info->max_length) {
371 set_errmsg(errmsg, "MinimumStingLength should not be greater "
372 "than MaximumStringLength");
373 return PLDM_ERROR_INVALID_DATA;
374 }
375 if (info->min_length == info->max_length &&
376 info->def_length != info->min_length) {
377 set_errmsg(errmsg, "Wrong DefaultStringLength");
378 return PLDM_ERROR_INVALID_DATA;
379 }
380 if (info->def_length > info->max_length ||
381 info->def_length < info->min_length) {
382 set_errmsg(errmsg, "Wrong DefaultStringLength");
383 return PLDM_ERROR_INVALID_DATA;
384 }
385 if (info->string_type > PLDM_STRING_TYPE_MAX &&
386 info->string_type != PLDM_STRING_TYPE_VENDOR) {
387 set_errmsg(errmsg, "Wrong StringType");
388 return PLDM_ERROR_INVALID_DATA;
389 }
Andrew Jefferydf02e362023-06-14 14:52:25 +0930390 if (info->def_string && info->def_length != strlen(info->def_string)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930391 set_errmsg(errmsg, "Length of DefaultString should be equal to "
392 "DefaultStringLength");
393 return PLDM_ERROR_INVALID_DATA;
394 }
395
396 return PLDM_SUCCESS;
397}
398
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930399LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930400int pldm_bios_table_attr_entry_string_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930401 void *entry, size_t entry_length,
402 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930403{
404 POINTER_CHECK(entry);
405 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930406 size_t length = pldm_bios_table_attr_entry_string_encode_length(
407 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930408 BUFFER_SIZE_EXPECT(entry_length, length);
409 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930410 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930411 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930412 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930413 pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
414 return PLDM_SUCCESS;
415}
416
Andrew Jefferyd47e8ab2023-06-13 14:20:36 +0930417LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930418uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
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 le16toh(fields->def_length);
424}
425
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930426LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930427int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930428 const struct pldm_bios_attr_table_entry *entry,
429 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930430{
431 POINTER_CHECK(entry);
432 POINTER_CHECK(def_string_length);
433 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
434 *def_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930435 pldm_bios_table_attr_entry_string_decode_def_string_length(
436 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930437 return PLDM_SUCCESS;
438}
439
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930440LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930441uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930442 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930443{
444 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930445 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930446 return fields->string_type;
447}
448
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930449LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930450uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930451 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930452{
453 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930454 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930455 return le16toh(fields->max_length);
456}
457
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930458LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930460 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930461{
462 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930463 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930464 return le16toh(fields->min_length);
465}
466
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930467LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930468uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930469 const struct pldm_bios_attr_table_entry *entry, char *buffer,
470 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930471{
472 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930473 pldm_bios_table_attr_entry_string_decode_def_string_length(
474 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930475 length = length < (size - 1) ? length : (size - 1);
476 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930477 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930478 memcpy(buffer, fields->def_string, length);
479 buffer[length] = 0;
480 return length;
481}
482
483/** @brief Get length of a string attribute entry
484 */
485static size_t attr_table_entry_length_string(const void *entry)
486{
487 uint16_t def_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930488 pldm_bios_table_attr_entry_string_decode_def_string_length(
489 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930490 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
491}
492
493struct attr_table_integer_entry_fields {
494 uint64_t lower_bound;
495 uint64_t upper_bound;
496 uint32_t scalar_increment;
497 uint64_t default_value;
498} __attribute__((packed));
499
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930500LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930501size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930502{
503 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
504 sizeof(struct attr_table_integer_entry_fields);
505}
506
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930507LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930508void pldm_bios_table_attr_entry_integer_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930509 void *entry, size_t entry_length,
510 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930511{
512 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
513 assert(length <= entry_length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930514 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
515 PLDM_BIOS_INTEGER;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930516 attr_table_entry_encode_header(entry, entry_length, attr_type,
517 info->name_handle);
518 struct pldm_bios_attr_table_entry *attr_entry = entry;
519 struct attr_table_integer_entry_fields *attr_fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930520 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930521 attr_fields->lower_bound = htole64(info->lower_bound);
522 attr_fields->upper_bound = htole64(info->upper_bound);
523 attr_fields->scalar_increment = htole32(info->scalar_increment);
524 attr_fields->default_value = htole64(info->default_value);
525}
526
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930527LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930528int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930529 const struct pldm_bios_table_attr_entry_integer_info *info,
530 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930531{
532 if (info->lower_bound == info->upper_bound) {
533 if (info->default_value != info->lower_bound) {
534 set_errmsg(errmsg, "Wrong DefaultValue");
535 return PLDM_ERROR_INVALID_DATA;
536 }
537 if (info->scalar_increment != 0) {
538 set_errmsg(errmsg, "Wrong ScalarIncrement");
539 return PLDM_ERROR_INVALID_DATA;
540 }
541 return PLDM_SUCCESS;
542 }
543 if (info->lower_bound > info->upper_bound) {
544 set_errmsg(errmsg,
545 "LowerBound should not be greater than UpperBound");
546 return PLDM_ERROR_INVALID_DATA;
547 }
548 if (info->default_value > info->upper_bound ||
549 info->default_value < info->lower_bound) {
550 set_errmsg(errmsg, "Wrong DefaultValue");
551 return PLDM_ERROR_INVALID_DATA;
552 }
553 if (info->scalar_increment == 0) {
554 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
555 "lower_bound != upper_bound");
556 return PLDM_ERROR_INVALID_DATA;
557 }
558 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930559 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930560 0) {
561 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
562 return PLDM_ERROR_INVALID_DATA;
563 }
564 return PLDM_SUCCESS;
565}
566
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930567LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930568int pldm_bios_table_attr_entry_integer_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930569 void *entry, size_t entry_length,
570 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571{
572 POINTER_CHECK(entry);
573 POINTER_CHECK(info);
574 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
575 BUFFER_SIZE_EXPECT(entry_length, length);
576 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930577 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930578 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930579 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580 pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
581 return PLDM_SUCCESS;
582}
583
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930584LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930585void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930586 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
587 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930588{
589 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930590 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930591 *lower = le64toh(fields->lower_bound);
592 *upper = le64toh(fields->upper_bound);
593 *scalar = le32toh(fields->scalar_increment);
594 *def = le64toh(fields->default_value);
595}
596
597static size_t attr_table_entry_length_integer(const void *entry)
598{
599 (void)entry;
600 return pldm_bios_table_attr_entry_integer_encode_length();
601}
602
603struct table_entry_length {
604 uint8_t attr_type;
605 size_t (*entry_length_handler)(const void *);
606};
607
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930608#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
Andrew Jeffery9c766792022-08-10 23:12:49 +0930609
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930610static const struct table_entry_length *
611find_table_entry_length_by_type(uint8_t attr_type,
612 const struct table_entry_length *handlers,
613 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930614{
615 size_t i;
616 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930617 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930619 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930620 }
621 return NULL;
622}
623
624static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930625 { .attr_type = PLDM_BIOS_ENUMERATION,
626 .entry_length_handler = attr_table_entry_length_enum },
627 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
628 .entry_length_handler = attr_table_entry_length_enum },
629 { .attr_type = PLDM_BIOS_STRING,
630 .entry_length_handler = attr_table_entry_length_string },
631 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
632 .entry_length_handler = attr_table_entry_length_string },
633 { .attr_type = PLDM_BIOS_INTEGER,
634 .entry_length_handler = attr_table_entry_length_integer },
635 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
636 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930637};
638
639static size_t attr_table_entry_length(const void *table_entry)
640{
641 const struct pldm_bios_attr_table_entry *entry = table_entry;
642 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930643 find_table_entry_length_by_type(entry->attr_type,
644 attr_table_entries,
645 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930646 assert(attr_table_entry != NULL);
647 assert(attr_table_entry->entry_length_handler != NULL);
648
649 return attr_table_entry->entry_length_handler(entry);
650}
651
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930652LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930653uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930654 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930655{
656 return le16toh(entry->attr_handle);
657}
658
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930659LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930660uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930661 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930662{
663 return entry->attr_type;
664}
665
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930666LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930667size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
668{
669 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
670 sizeof(count) + count;
671}
672
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930673LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930674void pldm_bios_table_attr_value_entry_encode_enum(
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, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677{
678 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930679 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680 assert(length <= entry_length);
681
682 struct pldm_bios_attr_val_table_entry *table_entry = entry;
683 table_entry->attr_handle = htole16(attr_handle);
684 table_entry->attr_type = attr_type;
685 table_entry->value[0] = count;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930686 if (count != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687 memcpy(&table_entry->value[1], handles, count);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930688 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930689}
690
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930691LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930692uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930693 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930694{
695 return entry->value[0];
696}
697
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930698LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930699uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930700 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
701 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930702{
703 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930704 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930705 number = number < curr_num ? number : curr_num;
706 memcpy(handles, &entry->value[1], number);
707
708 return number;
709}
710
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930711LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930712int pldm_bios_table_attr_value_entry_encode_enum_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930713 void *entry, size_t entry_length, uint16_t attr_handle,
714 uint8_t attr_type, uint8_t count, uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930715{
716 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930717 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930718 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930719 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930720 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
721 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930722 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930723 BUFFER_SIZE_EXPECT(entry_length, length);
724 pldm_bios_table_attr_value_entry_encode_enum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930725 entry, entry_length, attr_handle, attr_type, count, handles);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930726 return PLDM_SUCCESS;
727}
728
729static size_t attr_value_table_entry_length_enum(const void *entry)
730{
731 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930732 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930733 return pldm_bios_table_attr_value_entry_encode_enum_length(number);
734}
735
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930736LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930737size_t
738pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
739{
740 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
741 sizeof(string_length) + string_length;
742}
743
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930744LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745void pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930746 void *entry, size_t entry_length, uint16_t attr_handle,
747 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930749 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
750 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930751 assert(length <= entry_length);
752
753 struct pldm_bios_attr_val_table_entry *table_entry = entry;
754 table_entry->attr_handle = htole16(attr_handle);
755 table_entry->attr_type = attr_type;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930756 if (str_length != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930757 memcpy(table_entry->value + sizeof(str_length), str,
758 str_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930759 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760 str_length = htole16(str_length);
761 memcpy(table_entry->value, &str_length, sizeof(str_length));
762}
763
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930764LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930765uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930766 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930767{
768 uint16_t str_length = 0;
769 memcpy(&str_length, entry->value, sizeof(str_length));
770 return le16toh(str_length);
771}
772
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930773LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930774void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930775 const struct pldm_bios_attr_val_table_entry *entry,
776 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930777{
778 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930779 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930780 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930781 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930782}
783
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930784LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930785int pldm_bios_table_attr_value_entry_encode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930786 void *entry, size_t entry_length, uint16_t attr_handle,
787 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930788{
789 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930790 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930791 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930792 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930793 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930794 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
795 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930796 BUFFER_SIZE_EXPECT(entry_length, length);
797 pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930798 entry, entry_length, attr_handle, attr_type, str_length, str);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930799 return PLDM_SUCCESS;
800}
801
802static size_t attr_value_table_entry_length_string(const void *entry)
803{
804 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930805 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930806 return pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930807 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808}
809
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930810LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930811size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930812{
813 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
814 sizeof(uint64_t);
815}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930816
817LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930818void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
819 size_t entry_length,
820 uint16_t attr_handle,
821 uint8_t attr_type,
822 uint64_t cv)
823{
824 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930825 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930826 assert(length <= entry_length);
827
828 struct pldm_bios_attr_val_table_entry *table_entry = entry;
829 table_entry->attr_handle = htole16(attr_handle);
830 table_entry->attr_type = attr_type;
831 cv = htole64(cv);
832 memcpy(table_entry->value, &cv, sizeof(uint64_t));
833}
834
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930835LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930836int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
837 size_t entry_length,
838 uint16_t attr_handle,
839 uint8_t attr_type,
840 uint64_t cv)
841{
842 POINTER_CHECK(entry);
843 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930844 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930845 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
846 BUFFER_SIZE_EXPECT(entry_length, length);
847 pldm_bios_table_attr_value_entry_encode_integer(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930848 entry, entry_length, attr_handle, attr_type, cv);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930849 return PLDM_SUCCESS;
850}
851
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930852LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930854 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930855{
856 uint64_t cv = 0;
857 memcpy(&cv, entry->value, sizeof(cv));
858 cv = le64toh(cv);
859 return cv;
860}
861
862static size_t attr_value_table_entry_length_integer(const void *entry)
863{
864 (void)entry;
865 return pldm_bios_table_attr_value_entry_encode_integer_length();
866}
867
868static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930869 { .attr_type = PLDM_BIOS_ENUMERATION,
870 .entry_length_handler = attr_value_table_entry_length_enum },
871 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
872 .entry_length_handler = attr_value_table_entry_length_enum },
873 { .attr_type = PLDM_BIOS_STRING,
874 .entry_length_handler = attr_value_table_entry_length_string },
875 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
876 .entry_length_handler = attr_value_table_entry_length_string },
877 { .attr_type = PLDM_BIOS_INTEGER,
878 .entry_length_handler = attr_value_table_entry_length_integer },
879 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
880 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930881};
882
883static size_t attr_value_table_entry_length(const void *table_entry)
884{
885 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
886 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930887 find_table_entry_length_by_type(
888 entry->attr_type, attr_value_table_entries,
889 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890 assert(entry_length != NULL);
891 assert(entry_length->entry_length_handler != NULL);
892
893 return entry_length->entry_length_handler(entry);
894}
895
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930896LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930897size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930898 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899{
900 return attr_value_table_entry_length(entry);
901}
902
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930903LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930905 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930906{
907 return le16toh(entry->attr_handle);
908}
909
910static size_t pad_size_get(size_t size_without_pad)
911{
912 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
913}
914
915static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
916{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930917 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930919 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930920
921 return table_end;
922}
923
924static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
925{
926 checksum = htole32(checksum);
927 memcpy(table_end, &checksum, sizeof(checksum));
928
929 return table_end + sizeof(checksum);
930}
931
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930932LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930933size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
934{
935 size_t size = pad_size_get(size_without_pad) +
936 sizeof(uint32_t) /*sizeof(checksum)*/;
937 return size;
938}
939
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930940LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930941size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
942 size_t size_without_pad)
943{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930944 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930945 pldm_bios_table_pad_checksum_size(size_without_pad);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946 size_t total_length = size_without_pad + pad_checksum_size;
947 assert(size >= total_length);
948
949 uint8_t *table_end = (uint8_t *)table + size_without_pad;
950 size_t pad_size = pad_size_get(size_without_pad);
951 table_end = pad_append(table_end, pad_size);
952
953 uint32_t checksum = crc32(table, size_without_pad + pad_size);
954 checksum_append(table_end, checksum);
955
956 return total_length;
957}
958
959struct pldm_bios_table_iter {
960 const uint8_t *table_data;
961 size_t table_len;
962 size_t current_pos;
963 size_t (*entry_length_handler)(const void *table_entry);
964};
965
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930966LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967struct pldm_bios_table_iter *
968pldm_bios_table_iter_create(const void *table, size_t length,
969 enum pldm_bios_table_types type)
970{
971 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
972 assert(iter != NULL);
973 iter->table_data = table;
974 iter->table_len = length;
975 iter->current_pos = 0;
976 iter->entry_length_handler = NULL;
977 switch (type) {
978 case PLDM_BIOS_STRING_TABLE:
979 iter->entry_length_handler = string_table_entry_length;
980 break;
981 case PLDM_BIOS_ATTR_TABLE:
982 iter->entry_length_handler = attr_table_entry_length;
983 break;
984 case PLDM_BIOS_ATTR_VAL_TABLE:
985 iter->entry_length_handler = attr_value_table_entry_length;
986 break;
987 }
988
989 return iter;
990}
991
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930992LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930993void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
994{
995 free(iter);
996}
997
998#define pad_and_check_max 7
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930999LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301000bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
1001{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301002 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
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
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301008LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301009void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
1010{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301011 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301012 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301013 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301014 const void *entry = iter->table_data + iter->current_pos;
1015 iter->current_pos += iter->entry_length_handler(entry);
1016}
1017
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301018LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301019const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1020{
1021 return iter->table_data + iter->current_pos;
1022}
1023
1024typedef bool (*equal_handler)(const void *entry, const void *key);
1025
1026static const void *
1027pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1028 const void *key, equal_handler equal)
1029{
1030 const void *entry;
1031 while (!pldm_bios_table_iter_is_end(iter)) {
1032 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301033 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301034 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301035 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301036 pldm_bios_table_iter_next(iter);
1037 }
1038 return NULL;
1039}
1040
1041static const void *
1042pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1043 enum pldm_bios_table_types type,
1044 equal_handler equal, const void *key)
1045{
1046 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301047 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301048 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301049 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301050 pldm_bios_table_iter_free(iter);
1051 return entry;
1052}
1053
1054static bool string_table_handle_equal(const void *entry, const void *key)
1055{
1056 const struct pldm_bios_string_table_entry *string_entry = entry;
1057 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301058 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1059 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301060 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301061 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301062 return false;
1063}
1064
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301065LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301066const struct pldm_bios_string_table_entry *
1067pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1068 uint16_t handle)
1069{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301070 return pldm_bios_table_entry_find_from_table(table, length,
1071 PLDM_BIOS_STRING_TABLE,
1072 string_table_handle_equal,
1073 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301074}
1075
1076struct string_equal_arg {
1077 uint16_t str_length;
1078 const char *str;
1079};
1080
1081static bool string_table_string_equal(const void *entry, const void *key)
1082{
1083 const struct pldm_bios_string_table_entry *string_entry = entry;
1084 const struct string_equal_arg *arg = key;
1085 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301086 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301087 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301088 }
1089 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301090 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301091 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301092 return true;
1093}
1094
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301095LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301096const struct pldm_bios_string_table_entry *
1097pldm_bios_table_string_find_by_string(const void *table, size_t length,
1098 const char *str)
1099{
1100 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301101 struct string_equal_arg arg = { str_length, str };
1102 return pldm_bios_table_entry_find_from_table(table, length,
1103 PLDM_BIOS_STRING_TABLE,
1104 string_table_string_equal,
1105 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106}
1107
1108static bool attr_table_handle_equal(const void *entry, const void *key)
1109{
1110 uint16_t handle = *(uint16_t *)key;
1111 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1112 handle;
1113}
1114
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301115LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301116const struct pldm_bios_attr_table_entry *
1117pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1118 uint16_t handle)
1119{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301120 return pldm_bios_table_entry_find_from_table(table, length,
1121 PLDM_BIOS_ATTR_TABLE,
1122 attr_table_handle_equal,
1123 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301124}
1125
1126static bool attr_table_string_handle_equal(const void *entry, const void *key)
1127{
1128 uint16_t handle = *(uint16_t *)key;
1129 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1130}
1131
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301132LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301133const struct pldm_bios_attr_table_entry *
1134pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1135 uint16_t handle)
1136{
1137 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301138 table, length, PLDM_BIOS_ATTR_TABLE,
1139 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301140}
1141
1142static bool attr_value_table_handle_equal(const void *entry, const void *key)
1143{
1144 uint16_t handle = *(uint16_t *)key;
1145 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1146}
1147
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301148LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301149const struct pldm_bios_attr_val_table_entry *
1150pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1151 uint16_t handle)
1152{
1153 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301154 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1155 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301156}
1157
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301158LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301159int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301160 const void *src_table, size_t src_length, void *dest_table,
1161 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301162{
1163 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301164 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301165
1166 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301167 const struct pldm_bios_attr_val_table_entry *tmp;
1168 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1169 size_t buffer_length = *dest_length;
1170 size_t copied_length = 0;
1171 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301172 while (!pldm_bios_table_iter_is_end(iter)) {
1173 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1174 length = attr_value_table_entry_length(tmp);
1175
1176 /* we need the tmp's entry_length here, iter_next will calculate
1177 * it too, use current_pos directly to avoid calculating it
1178 * twice */
1179 iter->current_pos += length;
1180 if (tmp->attr_handle == to_update->attr_handle) {
1181 if (tmp->attr_type != to_update->attr_type) {
1182 rc = PLDM_ERROR_INVALID_DATA;
1183 goto out;
1184 }
1185 length = entry_length;
1186 tmp = entry;
1187 }
1188 if (copied_length + length > buffer_length) {
1189 rc = PLDM_ERROR_INVALID_LENGTH;
1190 goto out;
1191 }
1192 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1193 copied_length += length;
1194 }
1195
1196 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301197 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301198 if ((pad_checksum_size + copied_length) > buffer_length) {
1199 rc = PLDM_ERROR_INVALID_LENGTH;
1200 goto out;
1201 }
1202
1203 *dest_length = pldm_bios_table_append_pad_checksum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301204 dest_table, buffer_length, copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301205out:
1206 pldm_bios_table_iter_free(iter);
1207 return rc;
1208}
1209
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301210LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301211bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1212{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301213 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301215 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301216
1217 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1218 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301219 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301220 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301221 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301222
1223 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1224 uint32_t dst_crc = crc32(table, size - 4);
1225
1226 return src_crc == dst_crc;
1227}