blob: 1ca984ed83e677566c5552253375c83b986277e3 [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>
Andrew Jeffery73d91762023-06-28 12:19:19 +09307#include <limits.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09308#include <stdbool.h>
9#include <stdint.h>
10#include <stdlib.h>
11#include <string.h>
12
Andrew Jeffery9c766792022-08-10 23:12:49 +093013#define POINTER_CHECK(pointer) \
14 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093015 if ((pointer) == NULL) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093016 return PLDM_ERROR_INVALID_DATA; \
17 } while (0)
18
19#define ATTR_TYPE_EXPECT(type, expected) \
20 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093021 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093022 return PLDM_ERROR_INVALID_DATA; \
23 } while (0)
24
25#define BUFFER_SIZE_EXPECT(current_size, expected_size) \
26 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093027 if ((current_size) < (expected_size)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093028 return PLDM_ERROR_INVALID_LENGTH; \
29 } while (0)
30
31#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
32
33static void set_errmsg(const char **errmsg, const char *msg)
34{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093035 if (errmsg != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093036 *errmsg = msg;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093037 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093038}
39
Andrew Jefferya873eca2023-06-26 17:25:37 +093040static int get_bios_string_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +093041{
42 static uint16_t handle = 0;
43 assert(handle != UINT16_MAX);
Andrew Jefferya873eca2023-06-26 17:25:37 +093044 if (handle == UINT16_MAX) {
45 return PLDM_ERROR_INVALID_DATA;
46 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093047
Andrew Jefferya873eca2023-06-26 17:25:37 +093048 *val = handle++;
49 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +093050}
51
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093052LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093053size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
54{
55 return sizeof(struct pldm_bios_string_table_entry) -
56 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
57}
58
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093059LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093060int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
61 const char *str,
62 uint16_t str_length)
63{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093064 if (str_length == 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093065 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093066 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093067 POINTER_CHECK(entry);
68 POINTER_CHECK(str);
69 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
70 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093071 struct pldm_bios_string_table_entry *string_entry = entry;
Andrew Jefferya873eca2023-06-26 17:25:37 +093072 uint16_t handle;
73 int rc = get_bios_string_handle(&handle);
74 if (rc != PLDM_SUCCESS) {
75 return rc;
76 }
77 string_entry->string_handle = htole16(handle);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093078 string_entry->string_length = htole16(str_length);
79 memcpy(string_entry->name, str, str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +093080 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 +093098int pldm_bios_table_string_entry_decode_string_check(
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 POINTER_CHECK(entry);
103 POINTER_CHECK(buffer);
Andrew Jeffery98c1e692023-06-14 14:41:19 +0930104 if (size == 0) {
105 return PLDM_ERROR_INVALID_LENGTH;
106 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930107 size_t length =
108 pldm_bios_table_string_entry_decode_string_length(entry);
109 length = length < (size - 1) ? length : (size - 1);
110 memcpy(buffer, entry->name, length);
111 buffer[length] = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930112 return PLDM_SUCCESS;
113}
114
Andrew Jeffery73d91762023-06-28 12:19:19 +0930115static ssize_t string_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930116{
117 const struct pldm_bios_string_table_entry *entry = table_entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930118 size_t len = sizeof(*entry) - sizeof(entry->name) +
119 pldm_bios_table_string_entry_decode_string_length(entry);
120 if (len > SSIZE_MAX) {
121 return -1;
122 }
123 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930124}
125
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930126static int get_bios_attr_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930127{
128 static uint16_t handle = 0;
129 assert(handle != UINT16_MAX);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930130 if (handle == UINT16_MAX) {
131 return PLDM_ERROR_INVALID_DATA;
132 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930133
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930134 *val = handle++;
135 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930136}
137
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930138static int attr_table_entry_encode_header(void *entry, size_t length,
139 uint8_t attr_type,
140 uint16_t string_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930141{
142 struct pldm_bios_attr_table_entry *attr_entry = entry;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930143
Andrew Jeffery9c766792022-08-10 23:12:49 +0930144 assert(sizeof(*attr_entry) <= length);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930145 if (sizeof(*attr_entry) > length) {
146 return PLDM_ERROR_INVALID_LENGTH;
147 }
148
149 uint16_t handle;
150 int rc = get_bios_attr_handle(&handle);
151 if (rc != PLDM_SUCCESS) {
152 return rc;
153 }
154
155 attr_entry->attr_handle = htole16(handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930156 attr_entry->attr_type = attr_type;
157 attr_entry->string_handle = htole16(string_handle);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930158
159 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930160}
161
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930162LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930163uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930164 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930165{
166 return le16toh(entry->attr_handle);
167}
168
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930169LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930170uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930171 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930172{
173 return entry->attr_type;
174}
175
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930176LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930177uint16_t pldm_bios_table_attr_entry_decode_string_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930178 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930179{
180 return le16toh(entry->string_handle);
181}
182
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930183LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930184size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
185 uint8_t def_num)
186{
187 return sizeof(struct pldm_bios_attr_table_entry) -
188 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
189 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
190 def_num;
191}
192
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930193LIBPLDM_ABI_STABLE
194int pldm_bios_table_attr_entry_enum_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930195 void *entry, size_t entry_length,
196 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930197{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930198 POINTER_CHECK(entry);
199 POINTER_CHECK(info);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930200 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930201 info->pv_num, info->def_num);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930202 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930203 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
204 PLDM_BIOS_ENUMERATION;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930205 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
206 info->name_handle);
207 if (rc != PLDM_SUCCESS) {
208 return rc;
209 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930210 struct pldm_bios_attr_table_entry *attr_entry = entry;
211 attr_entry->metadata[0] = info->pv_num;
212 uint16_t *pv_hdls =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930213 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930214 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930215 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930216 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930217 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930218 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930219 info->def_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930220 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930221 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930222 info->def_index, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930223 return PLDM_SUCCESS;
224}
225
226#define ATTR_TYPE_EXPECT(type, expected) \
227 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930228 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930229 return PLDM_ERROR_INVALID_DATA; \
230 } while (0)
231
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930232LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930233int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930234 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930235{
236 POINTER_CHECK(entry);
237 POINTER_CHECK(pv_num);
238 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930239 *pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930240 return PLDM_SUCCESS;
241}
242
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930243static uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930244 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930245{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930246 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930247 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
248 sizeof(uint16_t) * pv_num];
249}
250
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930251LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930252int pldm_bios_table_attr_entry_enum_decode_def_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930253 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930254{
255 POINTER_CHECK(entry);
256 POINTER_CHECK(def_num);
257 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
258 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
259 return PLDM_SUCCESS;
260}
261
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930262LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930263int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930264 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
265 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930266{
267 POINTER_CHECK(entry);
268 POINTER_CHECK(pv_hdls);
269 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930270 uint8_t num = entry->metadata[0];
271 num = num < pv_num ? num : pv_num;
272 size_t i;
273 for (i = 0; i < num; i++) {
274 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
275 i * sizeof(uint16_t));
276 pv_hdls[i] = le16toh(*hdl);
277 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930278 return PLDM_SUCCESS;
279}
280
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930281LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930282uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930283 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
284 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930285{
286 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
287 num = num < def_num ? num : def_num;
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930288 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930289 const uint8_t *p = entry->metadata +
290 sizeof(uint8_t) /* number of possible values*/
291 + pv_num * sizeof(uint16_t) /* possible values */
292 + sizeof(uint8_t); /* number of default values */
293 memcpy(def_indices, p, num);
294 return num;
295}
296
297/** @brief Get length of an enum attribute entry
298 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930299static ssize_t attr_table_entry_length_enum(const void *arg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930300{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930301 const struct pldm_bios_attr_table_entry *entry = arg;
302 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930303 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930304 size_t len =
305 pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
306 if (len > SSIZE_MAX) {
307 return -1;
308 }
309 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930310}
311
312struct attr_table_string_entry_fields {
313 uint8_t string_type;
314 uint16_t min_length;
315 uint16_t max_length;
316 uint16_t def_length;
317 uint8_t def_string[1];
318} __attribute__((packed));
319
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930320LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
322{
323 return sizeof(struct pldm_bios_attr_table_entry) -
324 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
325 sizeof(struct attr_table_string_entry_fields) -
326 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
327 def_str_len;
328}
329
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930330#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930331#define PLDM_STRING_TYPE_VENDOR 0xff
332
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930333LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930334int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930335 const struct pldm_bios_table_attr_entry_string_info *info,
336 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337{
338 if (info->min_length > info->max_length) {
339 set_errmsg(errmsg, "MinimumStingLength should not be greater "
340 "than MaximumStringLength");
341 return PLDM_ERROR_INVALID_DATA;
342 }
343 if (info->min_length == info->max_length &&
344 info->def_length != info->min_length) {
345 set_errmsg(errmsg, "Wrong DefaultStringLength");
346 return PLDM_ERROR_INVALID_DATA;
347 }
348 if (info->def_length > info->max_length ||
349 info->def_length < info->min_length) {
350 set_errmsg(errmsg, "Wrong DefaultStringLength");
351 return PLDM_ERROR_INVALID_DATA;
352 }
353 if (info->string_type > PLDM_STRING_TYPE_MAX &&
354 info->string_type != PLDM_STRING_TYPE_VENDOR) {
355 set_errmsg(errmsg, "Wrong StringType");
356 return PLDM_ERROR_INVALID_DATA;
357 }
Andrew Jefferydf02e362023-06-14 14:52:25 +0930358 if (info->def_string && info->def_length != strlen(info->def_string)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359 set_errmsg(errmsg, "Length of DefaultString should be equal to "
360 "DefaultStringLength");
361 return PLDM_ERROR_INVALID_DATA;
362 }
363
364 return PLDM_SUCCESS;
365}
366
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930367LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930368int pldm_bios_table_attr_entry_string_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930369 void *entry, size_t entry_length,
370 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930371{
372 POINTER_CHECK(entry);
373 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930374 size_t length = pldm_bios_table_attr_entry_string_encode_length(
375 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930376 BUFFER_SIZE_EXPECT(entry_length, length);
377 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930378 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930379 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930380 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930381 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
382 PLDM_BIOS_STRING;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930383 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
384 info->name_handle);
385 if (rc != PLDM_SUCCESS) {
386 return rc;
387 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930388 struct pldm_bios_attr_table_entry *attr_entry = entry;
389 struct attr_table_string_entry_fields *attr_fields =
390 (struct attr_table_string_entry_fields *)attr_entry->metadata;
391 attr_fields->string_type = info->string_type;
392 attr_fields->min_length = htole16(info->min_length);
393 attr_fields->max_length = htole16(info->max_length);
394 attr_fields->def_length = htole16(info->def_length);
395 if (info->def_length != 0 && info->def_string != NULL) {
396 memcpy(attr_fields->def_string, info->def_string,
397 info->def_length);
398 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930399 return PLDM_SUCCESS;
400}
401
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930402static uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930403 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930404{
405 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930406 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930407 return le16toh(fields->def_length);
408}
409
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930410LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930411int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930412 const struct pldm_bios_attr_table_entry *entry,
413 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930414{
415 POINTER_CHECK(entry);
416 POINTER_CHECK(def_string_length);
417 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
418 *def_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930419 pldm_bios_table_attr_entry_string_decode_def_string_length(
420 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930421 return PLDM_SUCCESS;
422}
423
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930424LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930425uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930426 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930427{
428 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930429 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930430 return fields->string_type;
431}
432
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930433LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930434uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930435 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930436{
437 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930438 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930439 return le16toh(fields->max_length);
440}
441
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930442LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930443uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930444 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930445{
446 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930447 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930448 return le16toh(fields->min_length);
449}
450
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930451LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930452uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930453 const struct pldm_bios_attr_table_entry *entry, char *buffer,
454 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930455{
456 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930457 pldm_bios_table_attr_entry_string_decode_def_string_length(
458 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459 length = length < (size - 1) ? length : (size - 1);
460 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930461 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930462 memcpy(buffer, fields->def_string, length);
463 buffer[length] = 0;
464 return length;
465}
466
467/** @brief Get length of a string attribute entry
468 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930469static ssize_t attr_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930470{
471 uint16_t def_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930472 pldm_bios_table_attr_entry_string_decode_def_string_length(
473 entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930474 size_t len =
475 pldm_bios_table_attr_entry_string_encode_length(def_str_len);
476 if (len > SSIZE_MAX) {
477 return -1;
478 }
479 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930480}
481
482struct attr_table_integer_entry_fields {
483 uint64_t lower_bound;
484 uint64_t upper_bound;
485 uint32_t scalar_increment;
486 uint64_t default_value;
487} __attribute__((packed));
488
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930489LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930490size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930491{
492 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
493 sizeof(struct attr_table_integer_entry_fields);
494}
495
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930496LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930497void pldm_bios_table_attr_entry_integer_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930498 void *entry, size_t entry_length,
499 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930500{
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930501 int rc = pldm_bios_table_attr_entry_integer_encode_check(
502 entry, entry_length, info);
503 (void)rc;
504 assert(rc == PLDM_SUCCESS);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930505}
506
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930507LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930508int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930509 const struct pldm_bios_table_attr_entry_integer_info *info,
510 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930511{
512 if (info->lower_bound == info->upper_bound) {
513 if (info->default_value != info->lower_bound) {
514 set_errmsg(errmsg, "Wrong DefaultValue");
515 return PLDM_ERROR_INVALID_DATA;
516 }
517 if (info->scalar_increment != 0) {
518 set_errmsg(errmsg, "Wrong ScalarIncrement");
519 return PLDM_ERROR_INVALID_DATA;
520 }
521 return PLDM_SUCCESS;
522 }
523 if (info->lower_bound > info->upper_bound) {
524 set_errmsg(errmsg,
525 "LowerBound should not be greater than UpperBound");
526 return PLDM_ERROR_INVALID_DATA;
527 }
528 if (info->default_value > info->upper_bound ||
529 info->default_value < info->lower_bound) {
530 set_errmsg(errmsg, "Wrong DefaultValue");
531 return PLDM_ERROR_INVALID_DATA;
532 }
533 if (info->scalar_increment == 0) {
534 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
535 "lower_bound != upper_bound");
536 return PLDM_ERROR_INVALID_DATA;
537 }
538 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930539 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930540 0) {
541 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
542 return PLDM_ERROR_INVALID_DATA;
543 }
544 return PLDM_SUCCESS;
545}
546
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930547LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548int pldm_bios_table_attr_entry_integer_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930549 void *entry, size_t entry_length,
550 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930551{
552 POINTER_CHECK(entry);
553 POINTER_CHECK(info);
554 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
555 BUFFER_SIZE_EXPECT(entry_length, length);
556 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930557 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930558 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930559 }
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930560 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
561 PLDM_BIOS_INTEGER;
562 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
563 info->name_handle);
564 if (rc != PLDM_SUCCESS) {
565 return rc;
566 }
567 struct pldm_bios_attr_table_entry *attr_entry = entry;
568 struct attr_table_integer_entry_fields *attr_fields =
569 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
570 attr_fields->lower_bound = htole64(info->lower_bound);
571 attr_fields->upper_bound = htole64(info->upper_bound);
572 attr_fields->scalar_increment = htole32(info->scalar_increment);
573 attr_fields->default_value = htole64(info->default_value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930574 return PLDM_SUCCESS;
575}
576
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930577LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930578void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930579 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
580 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930581{
582 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930583 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930584 *lower = le64toh(fields->lower_bound);
585 *upper = le64toh(fields->upper_bound);
586 *scalar = le32toh(fields->scalar_increment);
587 *def = le64toh(fields->default_value);
588}
589
Andrew Jeffery73d91762023-06-28 12:19:19 +0930590static ssize_t attr_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930591{
592 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930593 size_t len = pldm_bios_table_attr_entry_integer_encode_length();
594 if (len > SSIZE_MAX) {
595 return -1;
596 }
597 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930598}
599
600struct table_entry_length {
601 uint8_t attr_type;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930602 ssize_t (*entry_length_handler)(const void *);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930603};
604
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930605#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930607static const struct table_entry_length *
608find_table_entry_length_by_type(uint8_t attr_type,
609 const struct table_entry_length *handlers,
610 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611{
612 size_t i;
613 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930614 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930615 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930616 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930617 }
618 return NULL;
619}
620
621static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930622 { .attr_type = PLDM_BIOS_ENUMERATION,
623 .entry_length_handler = attr_table_entry_length_enum },
624 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
625 .entry_length_handler = attr_table_entry_length_enum },
626 { .attr_type = PLDM_BIOS_STRING,
627 .entry_length_handler = attr_table_entry_length_string },
628 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
629 .entry_length_handler = attr_table_entry_length_string },
630 { .attr_type = PLDM_BIOS_INTEGER,
631 .entry_length_handler = attr_table_entry_length_integer },
632 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
633 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930634};
635
Andrew Jeffery73d91762023-06-28 12:19:19 +0930636static ssize_t attr_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930637{
638 const struct pldm_bios_attr_table_entry *entry = table_entry;
639 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930640 find_table_entry_length_by_type(entry->attr_type,
641 attr_table_entries,
642 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930643 assert(attr_table_entry != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930644 if (!attr_table_entry) {
645 return -1;
646 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930647 assert(attr_table_entry->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930648 if (!attr_table_entry->entry_length_handler) {
649 return -1;
650 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930651
652 return attr_table_entry->entry_length_handler(entry);
653}
654
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930655LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930656uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930657 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930658{
659 return le16toh(entry->attr_handle);
660}
661
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930662LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930663uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930664 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930665{
666 return entry->attr_type;
667}
668
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930669LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930670size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
671{
672 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
673 sizeof(count) + count;
674}
675
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930676LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677void pldm_bios_table_attr_value_entry_encode_enum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930678 void *entry, size_t entry_length, uint16_t attr_handle,
679 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680{
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930681 int rc = pldm_bios_table_attr_value_entry_encode_enum_check(
682 entry, entry_length, attr_handle, attr_type, count, handles);
683 (void)rc;
684 assert(rc == PLDM_SUCCESS);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685}
686
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930687LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930689 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930690{
691 return entry->value[0];
692}
693
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930694LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930696 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
697 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930698{
699 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930700 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930701 number = number < curr_num ? number : curr_num;
702 memcpy(handles, &entry->value[1], number);
703
704 return number;
705}
706
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930707LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930708int pldm_bios_table_attr_value_entry_encode_enum_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930709 void *entry, size_t entry_length, uint16_t attr_handle,
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930710 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930711{
712 POINTER_CHECK(entry);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930713 POINTER_CHECK(handles);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930714 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930715 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930716 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930717 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
718 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930719 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930720 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930721 struct pldm_bios_attr_val_table_entry *table_entry = entry;
722 table_entry->attr_handle = htole16(attr_handle);
723 table_entry->attr_type = attr_type;
724 table_entry->value[0] = count;
725 if (count != 0) {
726 memcpy(&table_entry->value[1], handles, count);
727 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930728 return PLDM_SUCCESS;
729}
730
Andrew Jeffery73d91762023-06-28 12:19:19 +0930731static ssize_t attr_value_table_entry_length_enum(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930732{
733 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930734 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930735 size_t len =
736 pldm_bios_table_attr_value_entry_encode_enum_length(number);
737 if (len > SSIZE_MAX) {
738 return -1;
739 }
740 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930741}
742
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930743LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930744size_t
745pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
746{
747 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
748 sizeof(string_length) + string_length;
749}
750
Andrew Jeffery2d663932023-06-27 14:19:15 +0930751LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930752void pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930753 void *entry, size_t entry_length, uint16_t attr_handle,
754 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755{
Andrew Jeffery2d663932023-06-27 14:19:15 +0930756 int rc = pldm_bios_table_attr_value_entry_encode_string_check(
757 entry, entry_length, attr_handle, attr_type, str_length, str);
758 (void)rc;
759 assert(rc == PLDM_SUCCESS);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760}
761
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930762LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930763uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930764 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930765{
766 uint16_t str_length = 0;
767 memcpy(&str_length, entry->value, sizeof(str_length));
768 return le16toh(str_length);
769}
770
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930771LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930772void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930773 const struct pldm_bios_attr_val_table_entry *entry,
774 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930775{
776 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930777 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930778 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930779 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930780}
781
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930782LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930783int pldm_bios_table_attr_value_entry_encode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930784 void *entry, size_t entry_length, uint16_t attr_handle,
785 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930786{
787 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930788 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930789 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930790 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930791 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930792 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
793 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930794 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery2d663932023-06-27 14:19:15 +0930795 struct pldm_bios_attr_val_table_entry *table_entry = entry;
796 table_entry->attr_handle = htole16(attr_handle);
797 table_entry->attr_type = attr_type;
798 if (str_length != 0) {
799 memcpy(table_entry->value + sizeof(str_length), str,
800 str_length);
801 }
802 str_length = htole16(str_length);
803 memcpy(table_entry->value, &str_length, sizeof(str_length));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930804 return PLDM_SUCCESS;
805}
806
Andrew Jeffery73d91762023-06-28 12:19:19 +0930807static ssize_t attr_value_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808{
809 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930810 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930811 size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930812 str_length);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930813 if (len > SSIZE_MAX) {
814 return -1;
815 }
816 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930817}
818
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930819LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930820size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930821{
822 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
823 sizeof(uint64_t);
824}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930825
Andrew Jeffery9e33be92023-07-12 08:12:14 +0930826LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930827void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
828 size_t entry_length,
829 uint16_t attr_handle,
830 uint8_t attr_type,
831 uint64_t cv)
832{
Andrew Jeffery0088a6a2023-06-27 15:06:45 +0930833 int rc = pldm_bios_table_attr_value_entry_encode_integer_check(
834 entry, entry_length, attr_handle, attr_type, cv);
835 (void)rc;
836 assert(rc == PLDM_SUCCESS);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930837}
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);
Andrew Jeffery0088a6a2023-06-27 15:06:45 +0930851 struct pldm_bios_attr_val_table_entry *table_entry = entry;
852 table_entry->attr_handle = htole16(attr_handle);
853 table_entry->attr_type = attr_type;
854 cv = htole64(cv);
855 memcpy(table_entry->value, &cv, sizeof(uint64_t));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930856 return PLDM_SUCCESS;
857}
858
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930859LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930860uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930861 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930862{
863 uint64_t cv = 0;
864 memcpy(&cv, entry->value, sizeof(cv));
865 cv = le64toh(cv);
866 return cv;
867}
868
Andrew Jeffery73d91762023-06-28 12:19:19 +0930869static ssize_t attr_value_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870{
871 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930872 size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
873 if (len > SSIZE_MAX) {
874 return -1;
875 }
876 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930877}
878
879static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930880 { .attr_type = PLDM_BIOS_ENUMERATION,
881 .entry_length_handler = attr_value_table_entry_length_enum },
882 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
883 .entry_length_handler = attr_value_table_entry_length_enum },
884 { .attr_type = PLDM_BIOS_STRING,
885 .entry_length_handler = attr_value_table_entry_length_string },
886 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
887 .entry_length_handler = attr_value_table_entry_length_string },
888 { .attr_type = PLDM_BIOS_INTEGER,
889 .entry_length_handler = attr_value_table_entry_length_integer },
890 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
891 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930892};
893
Andrew Jeffery73d91762023-06-28 12:19:19 +0930894static ssize_t attr_value_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930895{
896 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
897 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930898 find_table_entry_length_by_type(
899 entry->attr_type, attr_value_table_entries,
900 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930901 assert(entry_length != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930902 if (!entry_length) {
903 return -1;
904 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905 assert(entry_length->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930906 if (!entry_length->entry_length_handler) {
907 return -1;
908 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930909
910 return entry_length->entry_length_handler(entry);
911}
912
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930913LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930914size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930915 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916{
917 return attr_value_table_entry_length(entry);
918}
919
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930920LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930921uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930922 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930923{
924 return le16toh(entry->attr_handle);
925}
926
927static size_t pad_size_get(size_t size_without_pad)
928{
929 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
930}
931
932static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
933{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930934 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930935 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930936 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930937
938 return table_end;
939}
940
941static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
942{
943 checksum = htole32(checksum);
944 memcpy(table_end, &checksum, sizeof(checksum));
945
946 return table_end + sizeof(checksum);
947}
948
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930949LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
951{
952 size_t size = pad_size_get(size_without_pad) +
953 sizeof(uint32_t) /*sizeof(checksum)*/;
954 return size;
955}
956
Andrew Jeffery1264fbd2023-07-07 09:44:07 +0930957LIBPLDM_ABI_DEPRECATED
Andrew Jeffery044ee192023-06-28 11:26:00 +0930958size_t pldm_bios_table_append_pad_checksum(void *table, size_t capacity,
959 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960{
Andrew Jeffery044ee192023-06-28 11:26:00 +0930961 int rc = pldm_bios_table_append_pad_checksum_check(table, capacity,
962 &size);
963 (void)rc;
964 assert(rc == PLDM_SUCCESS);
965 return size;
966}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967
Andrew Jeffery1264fbd2023-07-07 09:44:07 +0930968LIBPLDM_ABI_STABLE
Andrew Jeffery044ee192023-06-28 11:26:00 +0930969int pldm_bios_table_append_pad_checksum_check(void *table, size_t capacity,
970 size_t *size)
971{
972 if (!table || !size) {
973 return PLDM_ERROR_INVALID_DATA;
974 }
975
976 size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
977 size_t total_length = *size + pad_checksum_size;
Andrew Jeffery044ee192023-06-28 11:26:00 +0930978 if (capacity < total_length) {
979 return PLDM_ERROR_INVALID_LENGTH;
980 }
981
982 uint8_t *table_end = (uint8_t *)table + *size;
983 size_t pad_size = pad_size_get(*size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930984 table_end = pad_append(table_end, pad_size);
985
Andrew Jeffery044ee192023-06-28 11:26:00 +0930986 uint32_t checksum = crc32(table, *size + pad_size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930987 checksum_append(table_end, checksum);
Andrew Jeffery044ee192023-06-28 11:26:00 +0930988 *size = total_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930989
Andrew Jeffery044ee192023-06-28 11:26:00 +0930990 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930991}
992
993struct pldm_bios_table_iter {
994 const uint8_t *table_data;
995 size_t table_len;
996 size_t current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930997 ssize_t (*entry_length_handler)(const void *table_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930998};
999
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301000LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001struct pldm_bios_table_iter *
1002pldm_bios_table_iter_create(const void *table, size_t length,
1003 enum pldm_bios_table_types type)
1004{
1005 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
1006 assert(iter != NULL);
Andrew Jeffery757e81a2023-06-28 12:15:59 +09301007 if (!iter) {
1008 return NULL;
1009 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301010 iter->table_data = table;
1011 iter->table_len = length;
1012 iter->current_pos = 0;
1013 iter->entry_length_handler = NULL;
1014 switch (type) {
1015 case PLDM_BIOS_STRING_TABLE:
1016 iter->entry_length_handler = string_table_entry_length;
1017 break;
1018 case PLDM_BIOS_ATTR_TABLE:
1019 iter->entry_length_handler = attr_table_entry_length;
1020 break;
1021 case PLDM_BIOS_ATTR_VAL_TABLE:
1022 iter->entry_length_handler = attr_value_table_entry_length;
1023 break;
1024 }
1025
1026 return iter;
1027}
1028
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301029LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301030void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
1031{
1032 free(iter);
1033}
1034
1035#define pad_and_check_max 7
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301036LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301037bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
1038{
Andrew Jeffery73d91762023-06-28 12:19:19 +09301039 ssize_t len;
1040
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301041 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301042 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301043 }
Andrew Jeffery73d91762023-06-28 12:19:19 +09301044
1045 len = iter->entry_length_handler(iter->table_data + iter->current_pos);
1046
1047 return len < 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301048}
1049
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301050LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301051void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
1052{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301053 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301054 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301055 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301056 const void *entry = iter->table_data + iter->current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +09301057 ssize_t rc = iter->entry_length_handler(entry);
1058 /* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1059 if (rc < 0) {
1060 return;
1061 }
1062 iter->current_pos += rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301063}
1064
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301065LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301066const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1067{
1068 return iter->table_data + iter->current_pos;
1069}
1070
1071typedef bool (*equal_handler)(const void *entry, const void *key);
1072
1073static const void *
1074pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1075 const void *key, equal_handler equal)
1076{
1077 const void *entry;
1078 while (!pldm_bios_table_iter_is_end(iter)) {
1079 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301080 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301081 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301082 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301083 pldm_bios_table_iter_next(iter);
1084 }
1085 return NULL;
1086}
1087
1088static const void *
1089pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1090 enum pldm_bios_table_types type,
1091 equal_handler equal, const void *key)
1092{
1093 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301094 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301095 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301096 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301097 pldm_bios_table_iter_free(iter);
1098 return entry;
1099}
1100
1101static bool string_table_handle_equal(const void *entry, const void *key)
1102{
1103 const struct pldm_bios_string_table_entry *string_entry = entry;
1104 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301105 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1106 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301107 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301108 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301109 return false;
1110}
1111
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301112LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301113const struct pldm_bios_string_table_entry *
1114pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1115 uint16_t handle)
1116{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301117 return pldm_bios_table_entry_find_from_table(table, length,
1118 PLDM_BIOS_STRING_TABLE,
1119 string_table_handle_equal,
1120 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301121}
1122
1123struct string_equal_arg {
1124 uint16_t str_length;
1125 const char *str;
1126};
1127
1128static bool string_table_string_equal(const void *entry, const void *key)
1129{
1130 const struct pldm_bios_string_table_entry *string_entry = entry;
1131 const struct string_equal_arg *arg = key;
1132 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301133 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301134 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301135 }
1136 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301138 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301139 return true;
1140}
1141
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301142LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301143const struct pldm_bios_string_table_entry *
1144pldm_bios_table_string_find_by_string(const void *table, size_t length,
1145 const char *str)
1146{
1147 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301148 struct string_equal_arg arg = { str_length, str };
1149 return pldm_bios_table_entry_find_from_table(table, length,
1150 PLDM_BIOS_STRING_TABLE,
1151 string_table_string_equal,
1152 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301153}
1154
1155static bool attr_table_handle_equal(const void *entry, const void *key)
1156{
1157 uint16_t handle = *(uint16_t *)key;
1158 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1159 handle;
1160}
1161
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301162LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301163const struct pldm_bios_attr_table_entry *
1164pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1165 uint16_t handle)
1166{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301167 return pldm_bios_table_entry_find_from_table(table, length,
1168 PLDM_BIOS_ATTR_TABLE,
1169 attr_table_handle_equal,
1170 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301171}
1172
1173static bool attr_table_string_handle_equal(const void *entry, const void *key)
1174{
1175 uint16_t handle = *(uint16_t *)key;
1176 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1177}
1178
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301179LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301180const struct pldm_bios_attr_table_entry *
1181pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1182 uint16_t handle)
1183{
1184 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301185 table, length, PLDM_BIOS_ATTR_TABLE,
1186 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301187}
1188
1189static bool attr_value_table_handle_equal(const void *entry, const void *key)
1190{
1191 uint16_t handle = *(uint16_t *)key;
1192 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1193}
1194
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301195LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301196const struct pldm_bios_attr_val_table_entry *
1197pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1198 uint16_t handle)
1199{
1200 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301201 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1202 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301203}
1204
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301205LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301206int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301207 const void *src_table, size_t src_length, void *dest_table,
1208 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301209{
1210 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301211 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212
1213 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301214 const struct pldm_bios_attr_val_table_entry *tmp;
1215 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1216 size_t buffer_length = *dest_length;
1217 size_t copied_length = 0;
1218 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301219 while (!pldm_bios_table_iter_is_end(iter)) {
1220 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1221 length = attr_value_table_entry_length(tmp);
1222
1223 /* we need the tmp's entry_length here, iter_next will calculate
1224 * it too, use current_pos directly to avoid calculating it
1225 * twice */
1226 iter->current_pos += length;
1227 if (tmp->attr_handle == to_update->attr_handle) {
1228 if (tmp->attr_type != to_update->attr_type) {
1229 rc = PLDM_ERROR_INVALID_DATA;
1230 goto out;
1231 }
1232 length = entry_length;
1233 tmp = entry;
1234 }
1235 if (copied_length + length > buffer_length) {
1236 rc = PLDM_ERROR_INVALID_LENGTH;
1237 goto out;
1238 }
1239 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1240 copied_length += length;
1241 }
1242
1243 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301244 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301245 if ((pad_checksum_size + copied_length) > buffer_length) {
1246 rc = PLDM_ERROR_INVALID_LENGTH;
1247 goto out;
1248 }
1249
1250 *dest_length = pldm_bios_table_append_pad_checksum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301251 dest_table, buffer_length, copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301252out:
1253 pldm_bios_table_iter_free(iter);
1254 return rc;
1255}
1256
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301257LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301258bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1259{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301260 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301261 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301262 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301263
1264 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1265 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301266 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301267 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301268 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301269
1270 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1271 uint32_t dst_crc = crc32(table, size - 4);
1272
1273 return src_crc == dst_crc;
1274}