blob: 436f3e65682d28559832a140fc37a173d26821d3 [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 Jeffery9d2a1c62023-06-05 13:02:16 +093054LIBPLDM_ABI_STABLE
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 Jeffery9d2a1c62023-06-05 13:02:16 +093097LIBPLDM_ABI_STABLE
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);
117 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930118 pldm_bios_table_string_entry_decode_string_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930119 BUFFER_SIZE_EXPECT(size, length + 1);
120 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 Jeffery9d2a1c62023-06-05 13:02:16 +0930181LIBPLDM_ABI_STABLE
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 Jeffery9d2a1c62023-06-05 13:02:16 +0930228LIBPLDM_ABI_STABLE
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 Jeffery9d2a1c62023-06-05 13:02:16 +0930246LIBPLDM_ABI_STABLE
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 Jeffery9d2a1c62023-06-05 13:02:16 +0930266LIBPLDM_ABI_STABLE
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);
290 uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930291 if (num != pv_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930292 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930293 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930294 pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
295 return PLDM_SUCCESS;
296}
297
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930298LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930299uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930300 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
301 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302{
303 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
304 num = num < def_num ? num : def_num;
305 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
306 const uint8_t *p = entry->metadata +
307 sizeof(uint8_t) /* number of possible values*/
308 + pv_num * sizeof(uint16_t) /* possible values */
309 + sizeof(uint8_t); /* number of default values */
310 memcpy(def_indices, p, num);
311 return num;
312}
313
314/** @brief Get length of an enum attribute entry
315 */
316static size_t attr_table_entry_length_enum(const void *entry)
317{
318 uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
319 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
320 return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
321}
322
323struct attr_table_string_entry_fields {
324 uint8_t string_type;
325 uint16_t min_length;
326 uint16_t max_length;
327 uint16_t def_length;
328 uint8_t def_string[1];
329} __attribute__((packed));
330
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930331LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
333{
334 return sizeof(struct pldm_bios_attr_table_entry) -
335 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
336 sizeof(struct attr_table_string_entry_fields) -
337 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
338 def_str_len;
339}
340
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930341LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342void pldm_bios_table_attr_entry_string_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930343 void *entry, size_t entry_length,
344 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930345{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930346 size_t length = pldm_bios_table_attr_entry_string_encode_length(
347 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930348 assert(length <= entry_length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930349 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
350 PLDM_BIOS_STRING;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930351 attr_table_entry_encode_header(entry, entry_length, attr_type,
352 info->name_handle);
353 struct pldm_bios_attr_table_entry *attr_entry = entry;
354 struct attr_table_string_entry_fields *attr_fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930355 (struct attr_table_string_entry_fields *)attr_entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930356 attr_fields->string_type = info->string_type;
357 attr_fields->min_length = htole16(info->min_length);
358 attr_fields->max_length = htole16(info->max_length);
359 attr_fields->def_length = htole16(info->def_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930360 if (info->def_length != 0 && info->def_string != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930361 memcpy(attr_fields->def_string, info->def_string,
362 info->def_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930363 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930364}
365
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930366#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930367#define PLDM_STRING_TYPE_VENDOR 0xff
368
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930369LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930370int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930371 const struct pldm_bios_table_attr_entry_string_info *info,
372 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930373{
374 if (info->min_length > info->max_length) {
375 set_errmsg(errmsg, "MinimumStingLength should not be greater "
376 "than MaximumStringLength");
377 return PLDM_ERROR_INVALID_DATA;
378 }
379 if (info->min_length == info->max_length &&
380 info->def_length != info->min_length) {
381 set_errmsg(errmsg, "Wrong DefaultStringLength");
382 return PLDM_ERROR_INVALID_DATA;
383 }
384 if (info->def_length > info->max_length ||
385 info->def_length < info->min_length) {
386 set_errmsg(errmsg, "Wrong DefaultStringLength");
387 return PLDM_ERROR_INVALID_DATA;
388 }
389 if (info->string_type > PLDM_STRING_TYPE_MAX &&
390 info->string_type != PLDM_STRING_TYPE_VENDOR) {
391 set_errmsg(errmsg, "Wrong StringType");
392 return PLDM_ERROR_INVALID_DATA;
393 }
Andrew Jefferydf02e362023-06-14 14:52:25 +0930394 if (info->def_string && info->def_length != strlen(info->def_string)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930395 set_errmsg(errmsg, "Length of DefaultString should be equal to "
396 "DefaultStringLength");
397 return PLDM_ERROR_INVALID_DATA;
398 }
399
400 return PLDM_SUCCESS;
401}
402
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930403LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930404int pldm_bios_table_attr_entry_string_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930405 void *entry, size_t entry_length,
406 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930407{
408 POINTER_CHECK(entry);
409 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930410 size_t length = pldm_bios_table_attr_entry_string_encode_length(
411 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930412 BUFFER_SIZE_EXPECT(entry_length, length);
413 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930414 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930415 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930416 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930417 pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
418 return PLDM_SUCCESS;
419}
420
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930421LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930422uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930423 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930424{
425 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930426 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930427 return le16toh(fields->def_length);
428}
429
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930430LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930431int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930432 const struct pldm_bios_attr_table_entry *entry,
433 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930434{
435 POINTER_CHECK(entry);
436 POINTER_CHECK(def_string_length);
437 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
438 *def_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930439 pldm_bios_table_attr_entry_string_decode_def_string_length(
440 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930441 return PLDM_SUCCESS;
442}
443
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930444LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930445uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930446 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930447{
448 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930449 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930450 return fields->string_type;
451}
452
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930453LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930454uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930455 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930456{
457 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930458 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459 return le16toh(fields->max_length);
460}
461
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930462LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930463uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930464 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930465{
466 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930467 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930468 return le16toh(fields->min_length);
469}
470
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930471LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930472uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930473 const struct pldm_bios_attr_table_entry *entry, char *buffer,
474 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930475{
476 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930477 pldm_bios_table_attr_entry_string_decode_def_string_length(
478 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930479 length = length < (size - 1) ? length : (size - 1);
480 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930481 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930482 memcpy(buffer, fields->def_string, length);
483 buffer[length] = 0;
484 return length;
485}
486
487/** @brief Get length of a string attribute entry
488 */
489static size_t attr_table_entry_length_string(const void *entry)
490{
491 uint16_t def_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930492 pldm_bios_table_attr_entry_string_decode_def_string_length(
493 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930494 return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
495}
496
497struct attr_table_integer_entry_fields {
498 uint64_t lower_bound;
499 uint64_t upper_bound;
500 uint32_t scalar_increment;
501 uint64_t default_value;
502} __attribute__((packed));
503
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930504LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930505size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930506{
507 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
508 sizeof(struct attr_table_integer_entry_fields);
509}
510
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930511LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930512void pldm_bios_table_attr_entry_integer_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930513 void *entry, size_t entry_length,
514 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930515{
516 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
517 assert(length <= entry_length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930518 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
519 PLDM_BIOS_INTEGER;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930520 attr_table_entry_encode_header(entry, entry_length, attr_type,
521 info->name_handle);
522 struct pldm_bios_attr_table_entry *attr_entry = entry;
523 struct attr_table_integer_entry_fields *attr_fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930524 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930525 attr_fields->lower_bound = htole64(info->lower_bound);
526 attr_fields->upper_bound = htole64(info->upper_bound);
527 attr_fields->scalar_increment = htole32(info->scalar_increment);
528 attr_fields->default_value = htole64(info->default_value);
529}
530
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930531LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930532int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930533 const struct pldm_bios_table_attr_entry_integer_info *info,
534 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930535{
536 if (info->lower_bound == info->upper_bound) {
537 if (info->default_value != info->lower_bound) {
538 set_errmsg(errmsg, "Wrong DefaultValue");
539 return PLDM_ERROR_INVALID_DATA;
540 }
541 if (info->scalar_increment != 0) {
542 set_errmsg(errmsg, "Wrong ScalarIncrement");
543 return PLDM_ERROR_INVALID_DATA;
544 }
545 return PLDM_SUCCESS;
546 }
547 if (info->lower_bound > info->upper_bound) {
548 set_errmsg(errmsg,
549 "LowerBound should not be greater than UpperBound");
550 return PLDM_ERROR_INVALID_DATA;
551 }
552 if (info->default_value > info->upper_bound ||
553 info->default_value < info->lower_bound) {
554 set_errmsg(errmsg, "Wrong DefaultValue");
555 return PLDM_ERROR_INVALID_DATA;
556 }
557 if (info->scalar_increment == 0) {
558 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
559 "lower_bound != upper_bound");
560 return PLDM_ERROR_INVALID_DATA;
561 }
562 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930563 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930564 0) {
565 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
566 return PLDM_ERROR_INVALID_DATA;
567 }
568 return PLDM_SUCCESS;
569}
570
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930571LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930572int pldm_bios_table_attr_entry_integer_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930573 void *entry, size_t entry_length,
574 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930575{
576 POINTER_CHECK(entry);
577 POINTER_CHECK(info);
578 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
579 BUFFER_SIZE_EXPECT(entry_length, length);
580 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930581 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930582 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930583 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930584 pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
585 return PLDM_SUCCESS;
586}
587
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930588LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930590 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
591 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930592{
593 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930594 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930595 *lower = le64toh(fields->lower_bound);
596 *upper = le64toh(fields->upper_bound);
597 *scalar = le32toh(fields->scalar_increment);
598 *def = le64toh(fields->default_value);
599}
600
601static size_t attr_table_entry_length_integer(const void *entry)
602{
603 (void)entry;
604 return pldm_bios_table_attr_entry_integer_encode_length();
605}
606
607struct table_entry_length {
608 uint8_t attr_type;
609 size_t (*entry_length_handler)(const void *);
610};
611
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930612#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
Andrew Jeffery9c766792022-08-10 23:12:49 +0930613
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930614static const struct table_entry_length *
615find_table_entry_length_by_type(uint8_t attr_type,
616 const struct table_entry_length *handlers,
617 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618{
619 size_t i;
620 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930621 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930623 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930624 }
625 return NULL;
626}
627
628static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930629 { .attr_type = PLDM_BIOS_ENUMERATION,
630 .entry_length_handler = attr_table_entry_length_enum },
631 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
632 .entry_length_handler = attr_table_entry_length_enum },
633 { .attr_type = PLDM_BIOS_STRING,
634 .entry_length_handler = attr_table_entry_length_string },
635 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
636 .entry_length_handler = attr_table_entry_length_string },
637 { .attr_type = PLDM_BIOS_INTEGER,
638 .entry_length_handler = attr_table_entry_length_integer },
639 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
640 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930641};
642
643static size_t attr_table_entry_length(const void *table_entry)
644{
645 const struct pldm_bios_attr_table_entry *entry = table_entry;
646 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930647 find_table_entry_length_by_type(entry->attr_type,
648 attr_table_entries,
649 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930650 assert(attr_table_entry != NULL);
651 assert(attr_table_entry->entry_length_handler != NULL);
652
653 return attr_table_entry->entry_length_handler(entry);
654}
655
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930656LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930657uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930658 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930659{
660 return le16toh(entry->attr_handle);
661}
662
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930663LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930664uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930665 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666{
667 return entry->attr_type;
668}
669
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930670LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930671size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
672{
673 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
674 sizeof(count) + count;
675}
676
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930677LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930678void pldm_bios_table_attr_value_entry_encode_enum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930679 void *entry, size_t entry_length, uint16_t attr_handle,
680 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930681{
682 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930683 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930684 assert(length <= entry_length);
685
686 struct pldm_bios_attr_val_table_entry *table_entry = entry;
687 table_entry->attr_handle = htole16(attr_handle);
688 table_entry->attr_type = attr_type;
689 table_entry->value[0] = count;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930690 if (count != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930691 memcpy(&table_entry->value[1], handles, count);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930692 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930693}
694
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930695LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930696uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930697 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930698{
699 return entry->value[0];
700}
701
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930702LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930703uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930704 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
705 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930706{
707 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930708 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930709 number = number < curr_num ? number : curr_num;
710 memcpy(handles, &entry->value[1], number);
711
712 return number;
713}
714
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930715LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930716int pldm_bios_table_attr_value_entry_encode_enum_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930717 void *entry, size_t entry_length, uint16_t attr_handle,
718 uint8_t attr_type, uint8_t count, uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930719{
720 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930721 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930722 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930723 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930724 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
725 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930726 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727 BUFFER_SIZE_EXPECT(entry_length, length);
728 pldm_bios_table_attr_value_entry_encode_enum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930729 entry, entry_length, attr_handle, attr_type, count, handles);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930730 return PLDM_SUCCESS;
731}
732
733static size_t attr_value_table_entry_length_enum(const void *entry)
734{
735 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930736 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930737 return pldm_bios_table_attr_value_entry_encode_enum_length(number);
738}
739
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930740LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930741size_t
742pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
743{
744 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
745 sizeof(string_length) + string_length;
746}
747
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930748LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930749void pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930750 void *entry, size_t entry_length, uint16_t attr_handle,
751 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930752{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930753 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
754 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755 assert(length <= entry_length);
756
757 struct pldm_bios_attr_val_table_entry *table_entry = entry;
758 table_entry->attr_handle = htole16(attr_handle);
759 table_entry->attr_type = attr_type;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930760 if (str_length != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930761 memcpy(table_entry->value + sizeof(str_length), str,
762 str_length);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930763 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930764 str_length = htole16(str_length);
765 memcpy(table_entry->value, &str_length, sizeof(str_length));
766}
767
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930768LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930769uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930770 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930771{
772 uint16_t str_length = 0;
773 memcpy(&str_length, entry->value, sizeof(str_length));
774 return le16toh(str_length);
775}
776
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930777LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930778void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930779 const struct pldm_bios_attr_val_table_entry *entry,
780 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930781{
782 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930783 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930784 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930785 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930786}
787
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930788LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930789int pldm_bios_table_attr_value_entry_encode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930790 void *entry, size_t entry_length, uint16_t attr_handle,
791 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930792{
793 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930794 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930795 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930796 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930797 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930798 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
799 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930800 BUFFER_SIZE_EXPECT(entry_length, length);
801 pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930802 entry, entry_length, attr_handle, attr_type, str_length, str);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930803 return PLDM_SUCCESS;
804}
805
806static size_t attr_value_table_entry_length_string(const void *entry)
807{
808 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930809 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930810 return pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930811 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930812}
813
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930814LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930815size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930816{
817 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
818 sizeof(uint64_t);
819}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930820
821LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930822void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
823 size_t entry_length,
824 uint16_t attr_handle,
825 uint8_t attr_type,
826 uint64_t cv)
827{
828 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930829 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930830 assert(length <= entry_length);
831
832 struct pldm_bios_attr_val_table_entry *table_entry = entry;
833 table_entry->attr_handle = htole16(attr_handle);
834 table_entry->attr_type = attr_type;
835 cv = htole64(cv);
836 memcpy(table_entry->value, &cv, sizeof(uint64_t));
837}
838
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930839LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930840int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
841 size_t entry_length,
842 uint16_t attr_handle,
843 uint8_t attr_type,
844 uint64_t cv)
845{
846 POINTER_CHECK(entry);
847 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930848 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930849 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
850 BUFFER_SIZE_EXPECT(entry_length, length);
851 pldm_bios_table_attr_value_entry_encode_integer(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930852 entry, entry_length, attr_handle, attr_type, cv);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853 return PLDM_SUCCESS;
854}
855
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930856LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930857uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930858 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930859{
860 uint64_t cv = 0;
861 memcpy(&cv, entry->value, sizeof(cv));
862 cv = le64toh(cv);
863 return cv;
864}
865
866static size_t attr_value_table_entry_length_integer(const void *entry)
867{
868 (void)entry;
869 return pldm_bios_table_attr_value_entry_encode_integer_length();
870}
871
872static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930873 { .attr_type = PLDM_BIOS_ENUMERATION,
874 .entry_length_handler = attr_value_table_entry_length_enum },
875 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
876 .entry_length_handler = attr_value_table_entry_length_enum },
877 { .attr_type = PLDM_BIOS_STRING,
878 .entry_length_handler = attr_value_table_entry_length_string },
879 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
880 .entry_length_handler = attr_value_table_entry_length_string },
881 { .attr_type = PLDM_BIOS_INTEGER,
882 .entry_length_handler = attr_value_table_entry_length_integer },
883 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
884 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930885};
886
887static size_t attr_value_table_entry_length(const void *table_entry)
888{
889 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
890 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930891 find_table_entry_length_by_type(
892 entry->attr_type, attr_value_table_entries,
893 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894 assert(entry_length != NULL);
895 assert(entry_length->entry_length_handler != NULL);
896
897 return entry_length->entry_length_handler(entry);
898}
899
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930900LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930901size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930902 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930903{
904 return attr_value_table_entry_length(entry);
905}
906
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930907LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930908uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930909 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930910{
911 return le16toh(entry->attr_handle);
912}
913
914static size_t pad_size_get(size_t size_without_pad)
915{
916 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
917}
918
919static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
920{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930921 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930922 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930923 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930924
925 return table_end;
926}
927
928static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
929{
930 checksum = htole32(checksum);
931 memcpy(table_end, &checksum, sizeof(checksum));
932
933 return table_end + sizeof(checksum);
934}
935
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930936LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930937size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
938{
939 size_t size = pad_size_get(size_without_pad) +
940 sizeof(uint32_t) /*sizeof(checksum)*/;
941 return size;
942}
943
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930944LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
946 size_t size_without_pad)
947{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930949 pldm_bios_table_pad_checksum_size(size_without_pad);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 size_t total_length = size_without_pad + pad_checksum_size;
951 assert(size >= total_length);
952
953 uint8_t *table_end = (uint8_t *)table + size_without_pad;
954 size_t pad_size = pad_size_get(size_without_pad);
955 table_end = pad_append(table_end, pad_size);
956
957 uint32_t checksum = crc32(table, size_without_pad + pad_size);
958 checksum_append(table_end, checksum);
959
960 return total_length;
961}
962
963struct pldm_bios_table_iter {
964 const uint8_t *table_data;
965 size_t table_len;
966 size_t current_pos;
967 size_t (*entry_length_handler)(const void *table_entry);
968};
969
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930970LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930971struct pldm_bios_table_iter *
972pldm_bios_table_iter_create(const void *table, size_t length,
973 enum pldm_bios_table_types type)
974{
975 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
976 assert(iter != NULL);
977 iter->table_data = table;
978 iter->table_len = length;
979 iter->current_pos = 0;
980 iter->entry_length_handler = NULL;
981 switch (type) {
982 case PLDM_BIOS_STRING_TABLE:
983 iter->entry_length_handler = string_table_entry_length;
984 break;
985 case PLDM_BIOS_ATTR_TABLE:
986 iter->entry_length_handler = attr_table_entry_length;
987 break;
988 case PLDM_BIOS_ATTR_VAL_TABLE:
989 iter->entry_length_handler = attr_value_table_entry_length;
990 break;
991 }
992
993 return iter;
994}
995
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930996LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930997void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
998{
999 free(iter);
1000}
1001
1002#define pad_and_check_max 7
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301003LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301004bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
1005{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301006 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301007 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301008 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301009 return false;
1010}
1011
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301012LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301013void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
1014{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301015 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301016 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301017 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301018 const void *entry = iter->table_data + iter->current_pos;
1019 iter->current_pos += iter->entry_length_handler(entry);
1020}
1021
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301022LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301023const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1024{
1025 return iter->table_data + iter->current_pos;
1026}
1027
1028typedef bool (*equal_handler)(const void *entry, const void *key);
1029
1030static const void *
1031pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1032 const void *key, equal_handler equal)
1033{
1034 const void *entry;
1035 while (!pldm_bios_table_iter_is_end(iter)) {
1036 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301037 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301038 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301039 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301040 pldm_bios_table_iter_next(iter);
1041 }
1042 return NULL;
1043}
1044
1045static const void *
1046pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1047 enum pldm_bios_table_types type,
1048 equal_handler equal, const void *key)
1049{
1050 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301051 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301052 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301053 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301054 pldm_bios_table_iter_free(iter);
1055 return entry;
1056}
1057
1058static bool string_table_handle_equal(const void *entry, const void *key)
1059{
1060 const struct pldm_bios_string_table_entry *string_entry = entry;
1061 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301062 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1063 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301064 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301065 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301066 return false;
1067}
1068
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301069LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301070const struct pldm_bios_string_table_entry *
1071pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1072 uint16_t handle)
1073{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301074 return pldm_bios_table_entry_find_from_table(table, length,
1075 PLDM_BIOS_STRING_TABLE,
1076 string_table_handle_equal,
1077 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301078}
1079
1080struct string_equal_arg {
1081 uint16_t str_length;
1082 const char *str;
1083};
1084
1085static bool string_table_string_equal(const void *entry, const void *key)
1086{
1087 const struct pldm_bios_string_table_entry *string_entry = entry;
1088 const struct string_equal_arg *arg = key;
1089 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301090 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301091 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301092 }
1093 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301094 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301095 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301096 return true;
1097}
1098
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301099LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301100const struct pldm_bios_string_table_entry *
1101pldm_bios_table_string_find_by_string(const void *table, size_t length,
1102 const char *str)
1103{
1104 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301105 struct string_equal_arg arg = { str_length, str };
1106 return pldm_bios_table_entry_find_from_table(table, length,
1107 PLDM_BIOS_STRING_TABLE,
1108 string_table_string_equal,
1109 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301110}
1111
1112static bool attr_table_handle_equal(const void *entry, const void *key)
1113{
1114 uint16_t handle = *(uint16_t *)key;
1115 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1116 handle;
1117}
1118
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301119LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301120const struct pldm_bios_attr_table_entry *
1121pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1122 uint16_t handle)
1123{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301124 return pldm_bios_table_entry_find_from_table(table, length,
1125 PLDM_BIOS_ATTR_TABLE,
1126 attr_table_handle_equal,
1127 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301128}
1129
1130static bool attr_table_string_handle_equal(const void *entry, const void *key)
1131{
1132 uint16_t handle = *(uint16_t *)key;
1133 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1134}
1135
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301136LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137const struct pldm_bios_attr_table_entry *
1138pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1139 uint16_t handle)
1140{
1141 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301142 table, length, PLDM_BIOS_ATTR_TABLE,
1143 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301144}
1145
1146static bool attr_value_table_handle_equal(const void *entry, const void *key)
1147{
1148 uint16_t handle = *(uint16_t *)key;
1149 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1150}
1151
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301152LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301153const struct pldm_bios_attr_val_table_entry *
1154pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1155 uint16_t handle)
1156{
1157 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301158 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1159 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301160}
1161
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301162LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301163int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301164 const void *src_table, size_t src_length, void *dest_table,
1165 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301166{
1167 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301168 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301169
1170 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301171 const struct pldm_bios_attr_val_table_entry *tmp;
1172 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1173 size_t buffer_length = *dest_length;
1174 size_t copied_length = 0;
1175 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301176 while (!pldm_bios_table_iter_is_end(iter)) {
1177 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1178 length = attr_value_table_entry_length(tmp);
1179
1180 /* we need the tmp's entry_length here, iter_next will calculate
1181 * it too, use current_pos directly to avoid calculating it
1182 * twice */
1183 iter->current_pos += length;
1184 if (tmp->attr_handle == to_update->attr_handle) {
1185 if (tmp->attr_type != to_update->attr_type) {
1186 rc = PLDM_ERROR_INVALID_DATA;
1187 goto out;
1188 }
1189 length = entry_length;
1190 tmp = entry;
1191 }
1192 if (copied_length + length > buffer_length) {
1193 rc = PLDM_ERROR_INVALID_LENGTH;
1194 goto out;
1195 }
1196 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1197 copied_length += length;
1198 }
1199
1200 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301201 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301202 if ((pad_checksum_size + copied_length) > buffer_length) {
1203 rc = PLDM_ERROR_INVALID_LENGTH;
1204 goto out;
1205 }
1206
1207 *dest_length = pldm_bios_table_append_pad_checksum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301208 dest_table, buffer_length, copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301209out:
1210 pldm_bios_table_iter_free(iter);
1211 return rc;
1212}
1213
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301214LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301215bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1216{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301217 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301218 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301219 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301220
1221 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1222 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301223 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301224 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301225 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301226
1227 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1228 uint32_t dst_crc = crc32(table, size - 4);
1229
1230 return src_crc == dst_crc;
1231}