blob: d5cc62696a5b91d39ba9fbcd32f7d976eecfa4ac [file] [log] [blame]
Andrew Jefferyef47e2f2023-07-20 09:53:19 +09301#include "array.h"
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05302#include "bios_table.h"
3#include "base.h"
4#include "bios.h"
5#include "utils.h"
Andrew Jeffery9c766792022-08-10 23:12:49 +09306#include <assert.h>
7#include <endian.h>
Andrew Jeffery73d91762023-06-28 12:19:19 +09308#include <limits.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09309#include <stdbool.h>
10#include <stdint.h>
11#include <stdlib.h>
12#include <string.h>
13
Andrew Jeffery9c766792022-08-10 23:12:49 +093014#define POINTER_CHECK(pointer) \
15 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093016 if ((pointer) == NULL) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093017 return PLDM_ERROR_INVALID_DATA; \
18 } while (0)
19
20#define ATTR_TYPE_EXPECT(type, expected) \
21 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093022 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093023 return PLDM_ERROR_INVALID_DATA; \
24 } while (0)
25
26#define BUFFER_SIZE_EXPECT(current_size, expected_size) \
27 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093028 if ((current_size) < (expected_size)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093029 return PLDM_ERROR_INVALID_LENGTH; \
30 } while (0)
31
32#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
33
34static void set_errmsg(const char **errmsg, const char *msg)
35{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093036 if (errmsg != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093037 *errmsg = msg;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093038 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093039}
40
Andrew Jefferya873eca2023-06-26 17:25:37 +093041static int get_bios_string_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +093042{
43 static uint16_t handle = 0;
44 assert(handle != UINT16_MAX);
Andrew Jefferya873eca2023-06-26 17:25:37 +093045 if (handle == UINT16_MAX) {
46 return PLDM_ERROR_INVALID_DATA;
47 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093048
Andrew Jefferya873eca2023-06-26 17:25:37 +093049 *val = handle++;
50 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +093051}
52
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093053LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093054size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
55{
56 return sizeof(struct pldm_bios_string_table_entry) -
57 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
58}
59
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093060LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093061int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
62 const char *str,
63 uint16_t str_length)
64{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093065 if (str_length == 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093066 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093067 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093068 POINTER_CHECK(entry);
69 POINTER_CHECK(str);
70 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
71 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093072 struct pldm_bios_string_table_entry *string_entry = entry;
Andrew Jefferya873eca2023-06-26 17:25:37 +093073 uint16_t handle;
74 int rc = get_bios_string_handle(&handle);
75 if (rc != PLDM_SUCCESS) {
76 return rc;
77 }
78 string_entry->string_handle = htole16(handle);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093079 string_entry->string_length = htole16(str_length);
80 memcpy(string_entry->name, str, str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +093081 return PLDM_SUCCESS;
82}
83
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093084LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093085uint16_t pldm_bios_table_string_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093086 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093087{
88 return le16toh(entry->string_handle);
89}
90
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093091LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093092uint16_t pldm_bios_table_string_entry_decode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093093 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093094{
95 return le16toh(entry->string_length);
96}
97
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093098LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093099int pldm_bios_table_string_entry_decode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930100 const struct pldm_bios_string_table_entry *entry, char *buffer,
101 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930102{
103 POINTER_CHECK(entry);
104 POINTER_CHECK(buffer);
Andrew Jeffery98c1e692023-06-14 14:41:19 +0930105 if (size == 0) {
106 return PLDM_ERROR_INVALID_LENGTH;
107 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930108 size_t length =
109 pldm_bios_table_string_entry_decode_string_length(entry);
110 length = length < (size - 1) ? length : (size - 1);
111 memcpy(buffer, entry->name, length);
112 buffer[length] = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930113 return PLDM_SUCCESS;
114}
115
Andrew Jeffery73d91762023-06-28 12:19:19 +0930116static ssize_t string_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930117{
118 const struct pldm_bios_string_table_entry *entry = table_entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930119 size_t len = sizeof(*entry) - sizeof(entry->name) +
120 pldm_bios_table_string_entry_decode_string_length(entry);
121 if (len > SSIZE_MAX) {
122 return -1;
123 }
124 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930125}
126
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930127static int get_bios_attr_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930128{
129 static uint16_t handle = 0;
130 assert(handle != UINT16_MAX);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930131 if (handle == UINT16_MAX) {
132 return PLDM_ERROR_INVALID_DATA;
133 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930134
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930135 *val = handle++;
136 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930137}
138
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930139static int attr_table_entry_encode_header(void *entry, size_t length,
140 uint8_t attr_type,
141 uint16_t string_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930142{
143 struct pldm_bios_attr_table_entry *attr_entry = entry;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930144
Andrew Jeffery9c766792022-08-10 23:12:49 +0930145 assert(sizeof(*attr_entry) <= length);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930146 if (sizeof(*attr_entry) > length) {
147 return PLDM_ERROR_INVALID_LENGTH;
148 }
149
150 uint16_t handle;
151 int rc = get_bios_attr_handle(&handle);
152 if (rc != PLDM_SUCCESS) {
153 return rc;
154 }
155
156 attr_entry->attr_handle = htole16(handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930157 attr_entry->attr_type = attr_type;
158 attr_entry->string_handle = htole16(string_handle);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930159
160 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930161}
162
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930163LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930164uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930165 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930166{
167 return le16toh(entry->attr_handle);
168}
169
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930170LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930171uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930172 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930173{
174 return entry->attr_type;
175}
176
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930177LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930178uint16_t pldm_bios_table_attr_entry_decode_string_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930179 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930180{
181 return le16toh(entry->string_handle);
182}
183
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930184LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
186 uint8_t def_num)
187{
188 return sizeof(struct pldm_bios_attr_table_entry) -
189 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
190 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
191 def_num;
192}
193
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930194LIBPLDM_ABI_STABLE
195int pldm_bios_table_attr_entry_enum_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930196 void *entry, size_t entry_length,
197 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930198{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930199 POINTER_CHECK(entry);
200 POINTER_CHECK(info);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930201 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930202 info->pv_num, info->def_num);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930203 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930204 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
205 PLDM_BIOS_ENUMERATION;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930206 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
207 info->name_handle);
208 if (rc != PLDM_SUCCESS) {
209 return rc;
210 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930211 struct pldm_bios_attr_table_entry *attr_entry = entry;
212 attr_entry->metadata[0] = info->pv_num;
213 uint16_t *pv_hdls =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930214 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930215 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930216 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930217 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930218 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930219 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930220 info->def_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930221 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930222 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930223 info->def_index, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930224 return PLDM_SUCCESS;
225}
226
227#define ATTR_TYPE_EXPECT(type, expected) \
228 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930229 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930230 return PLDM_ERROR_INVALID_DATA; \
231 } while (0)
232
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930233LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930234int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930235 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930236{
237 POINTER_CHECK(entry);
238 POINTER_CHECK(pv_num);
239 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930240 *pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930241 return PLDM_SUCCESS;
242}
243
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930244static uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930245 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930246{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930247 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930248 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
249 sizeof(uint16_t) * pv_num];
250}
251
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930252LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930253int pldm_bios_table_attr_entry_enum_decode_def_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930254 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930255{
256 POINTER_CHECK(entry);
257 POINTER_CHECK(def_num);
258 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
259 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
260 return PLDM_SUCCESS;
261}
262
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930263LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930264int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930265 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
266 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930267{
268 POINTER_CHECK(entry);
269 POINTER_CHECK(pv_hdls);
270 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930271 uint8_t num = entry->metadata[0];
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 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930279 return PLDM_SUCCESS;
280}
281
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930282LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930284 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
285 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930286{
287 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
288 num = num < def_num ? num : def_num;
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930289 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930290 const uint8_t *p = entry->metadata +
291 sizeof(uint8_t) /* number of possible values*/
292 + pv_num * sizeof(uint16_t) /* possible values */
293 + sizeof(uint8_t); /* number of default values */
294 memcpy(def_indices, p, num);
295 return num;
296}
297
298/** @brief Get length of an enum attribute entry
299 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930300static ssize_t attr_table_entry_length_enum(const void *arg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930301{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930302 const struct pldm_bios_attr_table_entry *entry = arg;
303 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930304 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930305 size_t len =
306 pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
307 if (len > SSIZE_MAX) {
308 return -1;
309 }
310 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930311}
312
313struct attr_table_string_entry_fields {
314 uint8_t string_type;
315 uint16_t min_length;
316 uint16_t max_length;
317 uint16_t def_length;
318 uint8_t def_string[1];
319} __attribute__((packed));
320
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930321LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930322size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
323{
324 return sizeof(struct pldm_bios_attr_table_entry) -
325 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
326 sizeof(struct attr_table_string_entry_fields) -
327 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
328 def_str_len;
329}
330
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930331#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332#define PLDM_STRING_TYPE_VENDOR 0xff
333
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930334LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930335int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930336 const struct pldm_bios_table_attr_entry_string_info *info,
337 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930338{
339 if (info->min_length > info->max_length) {
340 set_errmsg(errmsg, "MinimumStingLength should not be greater "
341 "than MaximumStringLength");
342 return PLDM_ERROR_INVALID_DATA;
343 }
344 if (info->min_length == info->max_length &&
345 info->def_length != info->min_length) {
346 set_errmsg(errmsg, "Wrong DefaultStringLength");
347 return PLDM_ERROR_INVALID_DATA;
348 }
349 if (info->def_length > info->max_length ||
350 info->def_length < info->min_length) {
351 set_errmsg(errmsg, "Wrong DefaultStringLength");
352 return PLDM_ERROR_INVALID_DATA;
353 }
354 if (info->string_type > PLDM_STRING_TYPE_MAX &&
355 info->string_type != PLDM_STRING_TYPE_VENDOR) {
356 set_errmsg(errmsg, "Wrong StringType");
357 return PLDM_ERROR_INVALID_DATA;
358 }
Andrew Jefferydf02e362023-06-14 14:52:25 +0930359 if (info->def_string && info->def_length != strlen(info->def_string)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930360 set_errmsg(errmsg, "Length of DefaultString should be equal to "
361 "DefaultStringLength");
362 return PLDM_ERROR_INVALID_DATA;
363 }
364
365 return PLDM_SUCCESS;
366}
367
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930368LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930369int pldm_bios_table_attr_entry_string_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930370 void *entry, size_t entry_length,
371 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372{
373 POINTER_CHECK(entry);
374 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930375 size_t length = pldm_bios_table_attr_entry_string_encode_length(
376 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930377 BUFFER_SIZE_EXPECT(entry_length, length);
378 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930379 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930381 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930382 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
383 PLDM_BIOS_STRING;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930384 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
385 info->name_handle);
386 if (rc != PLDM_SUCCESS) {
387 return rc;
388 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930389 struct pldm_bios_attr_table_entry *attr_entry = entry;
390 struct attr_table_string_entry_fields *attr_fields =
391 (struct attr_table_string_entry_fields *)attr_entry->metadata;
392 attr_fields->string_type = info->string_type;
393 attr_fields->min_length = htole16(info->min_length);
394 attr_fields->max_length = htole16(info->max_length);
395 attr_fields->def_length = htole16(info->def_length);
396 if (info->def_length != 0 && info->def_string != NULL) {
397 memcpy(attr_fields->def_string, info->def_string,
398 info->def_length);
399 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930400 return PLDM_SUCCESS;
401}
402
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930403static uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930404 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930405{
406 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930407 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930408 return le16toh(fields->def_length);
409}
410
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930411LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930412int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930413 const struct pldm_bios_attr_table_entry *entry,
414 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930415{
416 POINTER_CHECK(entry);
417 POINTER_CHECK(def_string_length);
418 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
419 *def_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930420 pldm_bios_table_attr_entry_string_decode_def_string_length(
421 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930422 return PLDM_SUCCESS;
423}
424
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930425LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930426uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930427 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930428{
429 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930430 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930431 return fields->string_type;
432}
433
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930434LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930435uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930436 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930437{
438 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930439 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930440 return le16toh(fields->max_length);
441}
442
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930443LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930444uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930445 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930446{
447 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930448 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930449 return le16toh(fields->min_length);
450}
451
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930452LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930453uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930454 const struct pldm_bios_attr_table_entry *entry, char *buffer,
455 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930456{
457 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930458 pldm_bios_table_attr_entry_string_decode_def_string_length(
459 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930460 length = length < (size - 1) ? length : (size - 1);
461 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930462 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930463 memcpy(buffer, fields->def_string, length);
464 buffer[length] = 0;
465 return length;
466}
467
468/** @brief Get length of a string attribute entry
469 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930470static ssize_t attr_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930471{
472 uint16_t def_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930473 pldm_bios_table_attr_entry_string_decode_def_string_length(
474 entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930475 size_t len =
476 pldm_bios_table_attr_entry_string_encode_length(def_str_len);
477 if (len > SSIZE_MAX) {
478 return -1;
479 }
480 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930481}
482
483struct attr_table_integer_entry_fields {
484 uint64_t lower_bound;
485 uint64_t upper_bound;
486 uint32_t scalar_increment;
487 uint64_t default_value;
488} __attribute__((packed));
489
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930490LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930491size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930492{
493 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
494 sizeof(struct attr_table_integer_entry_fields);
495}
496
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930497LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930498int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930499 const struct pldm_bios_table_attr_entry_integer_info *info,
500 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930501{
502 if (info->lower_bound == info->upper_bound) {
503 if (info->default_value != info->lower_bound) {
504 set_errmsg(errmsg, "Wrong DefaultValue");
505 return PLDM_ERROR_INVALID_DATA;
506 }
507 if (info->scalar_increment != 0) {
508 set_errmsg(errmsg, "Wrong ScalarIncrement");
509 return PLDM_ERROR_INVALID_DATA;
510 }
511 return PLDM_SUCCESS;
512 }
513 if (info->lower_bound > info->upper_bound) {
514 set_errmsg(errmsg,
515 "LowerBound should not be greater than UpperBound");
516 return PLDM_ERROR_INVALID_DATA;
517 }
518 if (info->default_value > info->upper_bound ||
519 info->default_value < info->lower_bound) {
520 set_errmsg(errmsg, "Wrong DefaultValue");
521 return PLDM_ERROR_INVALID_DATA;
522 }
523 if (info->scalar_increment == 0) {
524 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
525 "lower_bound != upper_bound");
526 return PLDM_ERROR_INVALID_DATA;
527 }
528 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930529 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930530 0) {
531 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
532 return PLDM_ERROR_INVALID_DATA;
533 }
534 return PLDM_SUCCESS;
535}
536
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930537LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930538int pldm_bios_table_attr_entry_integer_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930539 void *entry, size_t entry_length,
540 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930541{
542 POINTER_CHECK(entry);
543 POINTER_CHECK(info);
544 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
545 BUFFER_SIZE_EXPECT(entry_length, length);
546 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930547 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930549 }
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930550 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
551 PLDM_BIOS_INTEGER;
552 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
553 info->name_handle);
554 if (rc != PLDM_SUCCESS) {
555 return rc;
556 }
557 struct pldm_bios_attr_table_entry *attr_entry = entry;
558 struct attr_table_integer_entry_fields *attr_fields =
559 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
560 attr_fields->lower_bound = htole64(info->lower_bound);
561 attr_fields->upper_bound = htole64(info->upper_bound);
562 attr_fields->scalar_increment = htole32(info->scalar_increment);
563 attr_fields->default_value = htole64(info->default_value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930564 return PLDM_SUCCESS;
565}
566
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930567LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930568void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930569 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
570 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571{
572 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930573 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930574 *lower = le64toh(fields->lower_bound);
575 *upper = le64toh(fields->upper_bound);
576 *scalar = le32toh(fields->scalar_increment);
577 *def = le64toh(fields->default_value);
578}
579
Andrew Jeffery73d91762023-06-28 12:19:19 +0930580static ssize_t attr_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930581{
582 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930583 size_t len = pldm_bios_table_attr_entry_integer_encode_length();
584 if (len > SSIZE_MAX) {
585 return -1;
586 }
587 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930588}
589
590struct table_entry_length {
591 uint8_t attr_type;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930592 ssize_t (*entry_length_handler)(const void *);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930593};
594
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930595static const struct table_entry_length *
596find_table_entry_length_by_type(uint8_t attr_type,
597 const struct table_entry_length *handlers,
598 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930599{
600 size_t i;
601 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930602 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930603 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930604 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930605 }
606 return NULL;
607}
608
609static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930610 { .attr_type = PLDM_BIOS_ENUMERATION,
611 .entry_length_handler = attr_table_entry_length_enum },
612 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
613 .entry_length_handler = attr_table_entry_length_enum },
614 { .attr_type = PLDM_BIOS_STRING,
615 .entry_length_handler = attr_table_entry_length_string },
616 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
617 .entry_length_handler = attr_table_entry_length_string },
618 { .attr_type = PLDM_BIOS_INTEGER,
619 .entry_length_handler = attr_table_entry_length_integer },
620 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
621 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622};
623
Andrew Jeffery73d91762023-06-28 12:19:19 +0930624static ssize_t attr_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930625{
626 const struct pldm_bios_attr_table_entry *entry = table_entry;
627 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930628 find_table_entry_length_by_type(entry->attr_type,
629 attr_table_entries,
630 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930631 assert(attr_table_entry != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930632 if (!attr_table_entry) {
633 return -1;
634 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930635 assert(attr_table_entry->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930636 if (!attr_table_entry->entry_length_handler) {
637 return -1;
638 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930639
640 return attr_table_entry->entry_length_handler(entry);
641}
642
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930643LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930644uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930645 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930646{
647 return le16toh(entry->attr_handle);
648}
649
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930650LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930651uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930652 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930653{
654 return entry->attr_type;
655}
656
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930657LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930658size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
659{
660 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
661 sizeof(count) + count;
662}
663
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930664LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930665uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930666 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930667{
668 return entry->value[0];
669}
670
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930671LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930672uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930673 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
674 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930675{
676 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930677 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930678 number = number < curr_num ? number : curr_num;
679 memcpy(handles, &entry->value[1], number);
680
681 return number;
682}
683
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930684LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685int pldm_bios_table_attr_value_entry_encode_enum_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930686 void *entry, size_t entry_length, uint16_t attr_handle,
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930687 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688{
689 POINTER_CHECK(entry);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930690 POINTER_CHECK(handles);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930691 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930692 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930693 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930694 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
695 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930696 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930697 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930698 struct pldm_bios_attr_val_table_entry *table_entry = entry;
699 table_entry->attr_handle = htole16(attr_handle);
700 table_entry->attr_type = attr_type;
701 table_entry->value[0] = count;
702 if (count != 0) {
703 memcpy(&table_entry->value[1], handles, count);
704 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930705 return PLDM_SUCCESS;
706}
707
Andrew Jeffery73d91762023-06-28 12:19:19 +0930708static ssize_t attr_value_table_entry_length_enum(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930709{
710 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930711 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930712 size_t len =
713 pldm_bios_table_attr_value_entry_encode_enum_length(number);
714 if (len > SSIZE_MAX) {
715 return -1;
716 }
717 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930718}
719
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930720LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930721size_t
722pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
723{
724 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
725 sizeof(string_length) + string_length;
726}
727
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930728LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930729uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930730 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930731{
732 uint16_t str_length = 0;
733 memcpy(&str_length, entry->value, sizeof(str_length));
734 return le16toh(str_length);
735}
736
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930737LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930738void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930739 const struct pldm_bios_attr_val_table_entry *entry,
740 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930741{
742 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930743 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930744 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930745 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930746}
747
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930748LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930749int pldm_bios_table_attr_value_entry_encode_string_check(
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{
753 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930754 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930756 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930757 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930758 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
759 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery2d663932023-06-27 14:19:15 +0930761 struct pldm_bios_attr_val_table_entry *table_entry = entry;
762 table_entry->attr_handle = htole16(attr_handle);
763 table_entry->attr_type = attr_type;
764 if (str_length != 0) {
765 memcpy(table_entry->value + sizeof(str_length), str,
766 str_length);
767 }
768 str_length = htole16(str_length);
769 memcpy(table_entry->value, &str_length, sizeof(str_length));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770 return PLDM_SUCCESS;
771}
772
Andrew Jeffery73d91762023-06-28 12:19:19 +0930773static ssize_t attr_value_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930774{
775 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930776 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930777 size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930778 str_length);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930779 if (len > SSIZE_MAX) {
780 return -1;
781 }
782 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930783}
784
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930785LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930786size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930787{
788 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
789 sizeof(uint64_t);
790}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930791
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930792LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930793int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
794 size_t entry_length,
795 uint16_t attr_handle,
796 uint8_t attr_type,
797 uint64_t cv)
798{
799 POINTER_CHECK(entry);
800 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930801 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930802 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
803 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery0088a6a2023-06-27 15:06:45 +0930804 struct pldm_bios_attr_val_table_entry *table_entry = entry;
805 table_entry->attr_handle = htole16(attr_handle);
806 table_entry->attr_type = attr_type;
807 cv = htole64(cv);
808 memcpy(table_entry->value, &cv, sizeof(uint64_t));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930809 return PLDM_SUCCESS;
810}
811
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930812LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930813uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930814 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930815{
816 uint64_t cv = 0;
817 memcpy(&cv, entry->value, sizeof(cv));
818 cv = le64toh(cv);
819 return cv;
820}
821
Andrew Jeffery73d91762023-06-28 12:19:19 +0930822static ssize_t attr_value_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930823{
824 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930825 size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
826 if (len > SSIZE_MAX) {
827 return -1;
828 }
829 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930830}
831
832static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930833 { .attr_type = PLDM_BIOS_ENUMERATION,
834 .entry_length_handler = attr_value_table_entry_length_enum },
835 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
836 .entry_length_handler = attr_value_table_entry_length_enum },
837 { .attr_type = PLDM_BIOS_STRING,
838 .entry_length_handler = attr_value_table_entry_length_string },
839 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
840 .entry_length_handler = attr_value_table_entry_length_string },
841 { .attr_type = PLDM_BIOS_INTEGER,
842 .entry_length_handler = attr_value_table_entry_length_integer },
843 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
844 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930845};
846
Andrew Jeffery73d91762023-06-28 12:19:19 +0930847static ssize_t attr_value_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930848{
849 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
850 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930851 find_table_entry_length_by_type(
852 entry->attr_type, attr_value_table_entries,
853 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930854 assert(entry_length != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930855 if (!entry_length) {
856 return -1;
857 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930858 assert(entry_length->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930859 if (!entry_length->entry_length_handler) {
860 return -1;
861 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930862
863 return entry_length->entry_length_handler(entry);
864}
865
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930866LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930867size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930868 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930869{
870 return attr_value_table_entry_length(entry);
871}
872
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930873LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930874uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930875 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930876{
877 return le16toh(entry->attr_handle);
878}
879
880static size_t pad_size_get(size_t size_without_pad)
881{
882 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
883}
884
885static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
886{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930887 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930888 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930889 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890
891 return table_end;
892}
893
894static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
895{
896 checksum = htole32(checksum);
897 memcpy(table_end, &checksum, sizeof(checksum));
898
899 return table_end + sizeof(checksum);
900}
901
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930902LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930903size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
904{
905 size_t size = pad_size_get(size_without_pad) +
906 sizeof(uint32_t) /*sizeof(checksum)*/;
907 return size;
908}
909
Andrew Jeffery1264fbd2023-07-07 09:44:07 +0930910LIBPLDM_ABI_STABLE
Andrew Jeffery044ee192023-06-28 11:26:00 +0930911int pldm_bios_table_append_pad_checksum_check(void *table, size_t capacity,
912 size_t *size)
913{
914 if (!table || !size) {
915 return PLDM_ERROR_INVALID_DATA;
916 }
917
918 size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
919 size_t total_length = *size + pad_checksum_size;
Andrew Jeffery044ee192023-06-28 11:26:00 +0930920 if (capacity < total_length) {
921 return PLDM_ERROR_INVALID_LENGTH;
922 }
923
924 uint8_t *table_end = (uint8_t *)table + *size;
925 size_t pad_size = pad_size_get(*size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930926 table_end = pad_append(table_end, pad_size);
927
Andrew Jeffery044ee192023-06-28 11:26:00 +0930928 uint32_t checksum = crc32(table, *size + pad_size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930929 checksum_append(table_end, checksum);
Andrew Jeffery044ee192023-06-28 11:26:00 +0930930 *size = total_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931
Andrew Jeffery044ee192023-06-28 11:26:00 +0930932 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930933}
934
935struct pldm_bios_table_iter {
936 const uint8_t *table_data;
937 size_t table_len;
938 size_t current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930939 ssize_t (*entry_length_handler)(const void *table_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930940};
941
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930942LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943struct pldm_bios_table_iter *
944pldm_bios_table_iter_create(const void *table, size_t length,
945 enum pldm_bios_table_types type)
946{
947 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
948 assert(iter != NULL);
Andrew Jeffery757e81a2023-06-28 12:15:59 +0930949 if (!iter) {
950 return NULL;
951 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952 iter->table_data = table;
953 iter->table_len = length;
954 iter->current_pos = 0;
955 iter->entry_length_handler = NULL;
956 switch (type) {
957 case PLDM_BIOS_STRING_TABLE:
958 iter->entry_length_handler = string_table_entry_length;
959 break;
960 case PLDM_BIOS_ATTR_TABLE:
961 iter->entry_length_handler = attr_table_entry_length;
962 break;
963 case PLDM_BIOS_ATTR_VAL_TABLE:
964 iter->entry_length_handler = attr_value_table_entry_length;
965 break;
966 }
967
968 return iter;
969}
970
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930971LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930972void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
973{
974 free(iter);
975}
976
977#define pad_and_check_max 7
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930978LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930979bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
980{
Andrew Jeffery73d91762023-06-28 12:19:19 +0930981 ssize_t len;
982
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930983 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930984 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930985 }
Andrew Jeffery73d91762023-06-28 12:19:19 +0930986
987 len = iter->entry_length_handler(iter->table_data + iter->current_pos);
988
989 return len < 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930990}
991
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930992LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930993void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
994{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930995 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930996 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930997 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930998 const void *entry = iter->table_data + iter->current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930999 ssize_t rc = iter->entry_length_handler(entry);
1000 /* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1001 if (rc < 0) {
1002 return;
1003 }
1004 iter->current_pos += rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301005}
1006
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301007LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301008const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1009{
1010 return iter->table_data + iter->current_pos;
1011}
1012
1013typedef bool (*equal_handler)(const void *entry, const void *key);
1014
1015static const void *
1016pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1017 const void *key, equal_handler equal)
1018{
1019 const void *entry;
1020 while (!pldm_bios_table_iter_is_end(iter)) {
1021 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301022 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301023 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301024 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301025 pldm_bios_table_iter_next(iter);
1026 }
1027 return NULL;
1028}
1029
1030static const void *
1031pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1032 enum pldm_bios_table_types type,
1033 equal_handler equal, const void *key)
1034{
1035 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301036 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301037 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301038 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301039 pldm_bios_table_iter_free(iter);
1040 return entry;
1041}
1042
1043static bool string_table_handle_equal(const void *entry, const void *key)
1044{
1045 const struct pldm_bios_string_table_entry *string_entry = entry;
1046 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301047 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1048 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301049 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301050 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301051 return false;
1052}
1053
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301054LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301055const struct pldm_bios_string_table_entry *
1056pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1057 uint16_t handle)
1058{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301059 return pldm_bios_table_entry_find_from_table(table, length,
1060 PLDM_BIOS_STRING_TABLE,
1061 string_table_handle_equal,
1062 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301063}
1064
1065struct string_equal_arg {
1066 uint16_t str_length;
1067 const char *str;
1068};
1069
1070static bool string_table_string_equal(const void *entry, const void *key)
1071{
1072 const struct pldm_bios_string_table_entry *string_entry = entry;
1073 const struct string_equal_arg *arg = key;
1074 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301075 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301076 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301077 }
1078 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301079 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301080 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301081 return true;
1082}
1083
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301084LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301085const struct pldm_bios_string_table_entry *
1086pldm_bios_table_string_find_by_string(const void *table, size_t length,
1087 const char *str)
1088{
1089 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301090 struct string_equal_arg arg = { str_length, str };
1091 return pldm_bios_table_entry_find_from_table(table, length,
1092 PLDM_BIOS_STRING_TABLE,
1093 string_table_string_equal,
1094 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301095}
1096
1097static bool attr_table_handle_equal(const void *entry, const void *key)
1098{
1099 uint16_t handle = *(uint16_t *)key;
1100 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1101 handle;
1102}
1103
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301104LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301105const struct pldm_bios_attr_table_entry *
1106pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1107 uint16_t handle)
1108{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301109 return pldm_bios_table_entry_find_from_table(table, length,
1110 PLDM_BIOS_ATTR_TABLE,
1111 attr_table_handle_equal,
1112 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301113}
1114
1115static bool attr_table_string_handle_equal(const void *entry, const void *key)
1116{
1117 uint16_t handle = *(uint16_t *)key;
1118 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1119}
1120
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301121LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301122const struct pldm_bios_attr_table_entry *
1123pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1124 uint16_t handle)
1125{
1126 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301127 table, length, PLDM_BIOS_ATTR_TABLE,
1128 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301129}
1130
1131static bool attr_value_table_handle_equal(const void *entry, const void *key)
1132{
1133 uint16_t handle = *(uint16_t *)key;
1134 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1135}
1136
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301137LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301138const struct pldm_bios_attr_val_table_entry *
1139pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1140 uint16_t handle)
1141{
1142 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301143 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1144 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301145}
1146
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301147LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301148int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301149 const void *src_table, size_t src_length, void *dest_table,
1150 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301151{
1152 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301153 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301154
1155 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301156 const struct pldm_bios_attr_val_table_entry *tmp;
1157 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1158 size_t buffer_length = *dest_length;
1159 size_t copied_length = 0;
1160 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301161 while (!pldm_bios_table_iter_is_end(iter)) {
1162 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1163 length = attr_value_table_entry_length(tmp);
1164
1165 /* we need the tmp's entry_length here, iter_next will calculate
1166 * it too, use current_pos directly to avoid calculating it
1167 * twice */
1168 iter->current_pos += length;
1169 if (tmp->attr_handle == to_update->attr_handle) {
1170 if (tmp->attr_type != to_update->attr_type) {
1171 rc = PLDM_ERROR_INVALID_DATA;
1172 goto out;
1173 }
1174 length = entry_length;
1175 tmp = entry;
1176 }
1177 if (copied_length + length > buffer_length) {
1178 rc = PLDM_ERROR_INVALID_LENGTH;
1179 goto out;
1180 }
1181 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1182 copied_length += length;
1183 }
1184
1185 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301186 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301187 if ((pad_checksum_size + copied_length) > buffer_length) {
1188 rc = PLDM_ERROR_INVALID_LENGTH;
1189 goto out;
1190 }
1191
Andrew Jeffery50dd1592023-07-14 16:02:05 +09301192 rc = pldm_bios_table_append_pad_checksum_check(
1193 dest_table, buffer_length, &copied_length);
1194 if (rc == PLDM_SUCCESS) {
1195 *dest_length = copied_length;
1196 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301197out:
1198 pldm_bios_table_iter_free(iter);
1199 return rc;
1200}
1201
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301202LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301203bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1204{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301205 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301206 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301207 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301208
1209 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1210 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301211 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301213 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214
1215 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1216 uint32_t dst_crc = crc32(table, size - 4);
1217
1218 return src_crc == dst_crc;
1219}