blob: 228bff45bafd2b5cedf50abb9f7fdcb4fb91c9db [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jefferyef47e2f2023-07-20 09:53:19 +09302#include "array.h"
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05303#include "bios_table.h"
4#include "base.h"
5#include "bios.h"
6#include "utils.h"
Andrew Jeffery9c766792022-08-10 23:12:49 +09307#include <assert.h>
8#include <endian.h>
Andrew Jeffery73d91762023-06-28 12:19:19 +09309#include <limits.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093010#include <stdbool.h>
11#include <stdint.h>
12#include <stdlib.h>
13#include <string.h>
14
Andrew Jeffery9c766792022-08-10 23:12:49 +093015#define POINTER_CHECK(pointer) \
16 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093017 if ((pointer) == NULL) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093018 return PLDM_ERROR_INVALID_DATA; \
19 } while (0)
20
21#define ATTR_TYPE_EXPECT(type, expected) \
22 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093023 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093024 return PLDM_ERROR_INVALID_DATA; \
25 } while (0)
26
27#define BUFFER_SIZE_EXPECT(current_size, expected_size) \
28 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093029 if ((current_size) < (expected_size)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093030 return PLDM_ERROR_INVALID_LENGTH; \
31 } while (0)
32
33#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
34
35static void set_errmsg(const char **errmsg, const char *msg)
36{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093037 if (errmsg != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093038 *errmsg = msg;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093039 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093040}
41
Andrew Jefferya873eca2023-06-26 17:25:37 +093042static int get_bios_string_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +093043{
44 static uint16_t handle = 0;
45 assert(handle != UINT16_MAX);
Andrew Jefferya873eca2023-06-26 17:25:37 +093046 if (handle == UINT16_MAX) {
47 return PLDM_ERROR_INVALID_DATA;
48 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093049
Andrew Jefferya873eca2023-06-26 17:25:37 +093050 *val = handle++;
51 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +093052}
53
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093054LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093055size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
56{
57 return sizeof(struct pldm_bios_string_table_entry) -
58 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
59}
60
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093061LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093062int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
63 const char *str,
64 uint16_t str_length)
65{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093066 if (str_length == 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093067 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093068 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093069 POINTER_CHECK(entry);
70 POINTER_CHECK(str);
71 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
72 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093073 struct pldm_bios_string_table_entry *string_entry = entry;
Andrew Jefferya873eca2023-06-26 17:25:37 +093074 uint16_t handle;
75 int rc = get_bios_string_handle(&handle);
76 if (rc != PLDM_SUCCESS) {
77 return rc;
78 }
79 string_entry->string_handle = htole16(handle);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093080 string_entry->string_length = htole16(str_length);
81 memcpy(string_entry->name, str, str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +093082 return PLDM_SUCCESS;
83}
84
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093085LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093086uint16_t pldm_bios_table_string_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093087 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093088{
89 return le16toh(entry->string_handle);
90}
91
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093092LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093093uint16_t pldm_bios_table_string_entry_decode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093094 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093095{
96 return le16toh(entry->string_length);
97}
98
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093099LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930100int pldm_bios_table_string_entry_decode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930101 const struct pldm_bios_string_table_entry *entry, char *buffer,
102 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930103{
104 POINTER_CHECK(entry);
105 POINTER_CHECK(buffer);
Andrew Jeffery98c1e692023-06-14 14:41:19 +0930106 if (size == 0) {
107 return PLDM_ERROR_INVALID_LENGTH;
108 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930109 size_t length =
110 pldm_bios_table_string_entry_decode_string_length(entry);
111 length = length < (size - 1) ? length : (size - 1);
112 memcpy(buffer, entry->name, length);
113 buffer[length] = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930114 return PLDM_SUCCESS;
115}
116
Andrew Jeffery73d91762023-06-28 12:19:19 +0930117static ssize_t string_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118{
119 const struct pldm_bios_string_table_entry *entry = table_entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930120 size_t len = sizeof(*entry) - sizeof(entry->name) +
121 pldm_bios_table_string_entry_decode_string_length(entry);
122 if (len > SSIZE_MAX) {
123 return -1;
124 }
125 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930126}
127
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930128static int get_bios_attr_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930129{
130 static uint16_t handle = 0;
131 assert(handle != UINT16_MAX);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930132 if (handle == UINT16_MAX) {
133 return PLDM_ERROR_INVALID_DATA;
134 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930135
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930136 *val = handle++;
137 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930138}
139
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930140static int attr_table_entry_encode_header(void *entry, size_t length,
141 uint8_t attr_type,
142 uint16_t string_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930143{
144 struct pldm_bios_attr_table_entry *attr_entry = entry;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930145
Andrew Jeffery9c766792022-08-10 23:12:49 +0930146 assert(sizeof(*attr_entry) <= length);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930147 if (sizeof(*attr_entry) > length) {
148 return PLDM_ERROR_INVALID_LENGTH;
149 }
150
151 uint16_t handle;
152 int rc = get_bios_attr_handle(&handle);
153 if (rc != PLDM_SUCCESS) {
154 return rc;
155 }
156
157 attr_entry->attr_handle = htole16(handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930158 attr_entry->attr_type = attr_type;
159 attr_entry->string_handle = htole16(string_handle);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930160
161 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930162}
163
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930164LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930165uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930166 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930167{
168 return le16toh(entry->attr_handle);
169}
170
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930171LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930172uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930173 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930174{
175 return entry->attr_type;
176}
177
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930178LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930179uint16_t pldm_bios_table_attr_entry_decode_string_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930180 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930181{
182 return le16toh(entry->string_handle);
183}
184
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930185LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930186size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
187 uint8_t def_num)
188{
189 return sizeof(struct pldm_bios_attr_table_entry) -
190 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
191 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
192 def_num;
193}
194
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930195LIBPLDM_ABI_STABLE
196int pldm_bios_table_attr_entry_enum_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930197 void *entry, size_t entry_length,
198 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930199{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930200 POINTER_CHECK(entry);
201 POINTER_CHECK(info);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930202 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930203 info->pv_num, info->def_num);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930204 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930205 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
206 PLDM_BIOS_ENUMERATION;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930207 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
208 info->name_handle);
209 if (rc != PLDM_SUCCESS) {
210 return rc;
211 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930212 struct pldm_bios_attr_table_entry *attr_entry = entry;
213 attr_entry->metadata[0] = info->pv_num;
214 uint16_t *pv_hdls =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930215 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930216 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930217 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930218 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930219 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930220 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930221 info->def_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930222 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930223 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930224 info->def_index, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930225 return PLDM_SUCCESS;
226}
227
228#define ATTR_TYPE_EXPECT(type, expected) \
229 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930230 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930231 return PLDM_ERROR_INVALID_DATA; \
232 } while (0)
233
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930234LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930235int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930236 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930237{
238 POINTER_CHECK(entry);
239 POINTER_CHECK(pv_num);
240 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930241 *pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930242 return PLDM_SUCCESS;
243}
244
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930245static uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930246 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930247{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930248 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930249 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
250 sizeof(uint16_t) * pv_num];
251}
252
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930253LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930254int pldm_bios_table_attr_entry_enum_decode_def_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930255 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930256{
257 POINTER_CHECK(entry);
258 POINTER_CHECK(def_num);
259 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
260 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
261 return PLDM_SUCCESS;
262}
263
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930264LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930265int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930266 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
267 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930268{
269 POINTER_CHECK(entry);
270 POINTER_CHECK(pv_hdls);
271 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930272 uint8_t num = entry->metadata[0];
273 num = num < pv_num ? num : pv_num;
274 size_t i;
275 for (i = 0; i < num; i++) {
276 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
277 i * sizeof(uint16_t));
278 pv_hdls[i] = le16toh(*hdl);
279 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930280 return PLDM_SUCCESS;
281}
282
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930283LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930284uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930285 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
286 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930287{
288 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
289 num = num < def_num ? num : def_num;
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930290 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930291 const uint8_t *p = entry->metadata +
292 sizeof(uint8_t) /* number of possible values*/
293 + pv_num * sizeof(uint16_t) /* possible values */
294 + sizeof(uint8_t); /* number of default values */
295 memcpy(def_indices, p, num);
296 return num;
297}
298
299/** @brief Get length of an enum attribute entry
300 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930301static ssize_t attr_table_entry_length_enum(const void *arg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930303 const struct pldm_bios_attr_table_entry *entry = arg;
304 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930305 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930306 size_t len =
307 pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
308 if (len > SSIZE_MAX) {
309 return -1;
310 }
311 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930312}
313
314struct attr_table_string_entry_fields {
315 uint8_t string_type;
316 uint16_t min_length;
317 uint16_t max_length;
318 uint16_t def_length;
319 uint8_t def_string[1];
320} __attribute__((packed));
321
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930322LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930323size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
324{
325 return sizeof(struct pldm_bios_attr_table_entry) -
326 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
327 sizeof(struct attr_table_string_entry_fields) -
328 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
329 def_str_len;
330}
331
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930332#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930333#define PLDM_STRING_TYPE_VENDOR 0xff
334
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930335LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930336int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930337 const struct pldm_bios_table_attr_entry_string_info *info,
338 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930339{
340 if (info->min_length > info->max_length) {
341 set_errmsg(errmsg, "MinimumStingLength should not be greater "
342 "than MaximumStringLength");
343 return PLDM_ERROR_INVALID_DATA;
344 }
345 if (info->min_length == info->max_length &&
346 info->def_length != info->min_length) {
347 set_errmsg(errmsg, "Wrong DefaultStringLength");
348 return PLDM_ERROR_INVALID_DATA;
349 }
350 if (info->def_length > info->max_length ||
351 info->def_length < info->min_length) {
352 set_errmsg(errmsg, "Wrong DefaultStringLength");
353 return PLDM_ERROR_INVALID_DATA;
354 }
355 if (info->string_type > PLDM_STRING_TYPE_MAX &&
356 info->string_type != PLDM_STRING_TYPE_VENDOR) {
357 set_errmsg(errmsg, "Wrong StringType");
358 return PLDM_ERROR_INVALID_DATA;
359 }
Andrew Jefferydf02e362023-06-14 14:52:25 +0930360 if (info->def_string && info->def_length != strlen(info->def_string)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930361 set_errmsg(errmsg, "Length of DefaultString should be equal to "
362 "DefaultStringLength");
363 return PLDM_ERROR_INVALID_DATA;
364 }
365
366 return PLDM_SUCCESS;
367}
368
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930369LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930370int pldm_bios_table_attr_entry_string_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930371 void *entry, size_t entry_length,
372 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930373{
374 POINTER_CHECK(entry);
375 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930376 size_t length = pldm_bios_table_attr_entry_string_encode_length(
377 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378 BUFFER_SIZE_EXPECT(entry_length, length);
379 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930380 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930381 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930382 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930383 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
384 PLDM_BIOS_STRING;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930385 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
386 info->name_handle);
387 if (rc != PLDM_SUCCESS) {
388 return rc;
389 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930390 struct pldm_bios_attr_table_entry *attr_entry = entry;
391 struct attr_table_string_entry_fields *attr_fields =
392 (struct attr_table_string_entry_fields *)attr_entry->metadata;
393 attr_fields->string_type = info->string_type;
394 attr_fields->min_length = htole16(info->min_length);
395 attr_fields->max_length = htole16(info->max_length);
396 attr_fields->def_length = htole16(info->def_length);
397 if (info->def_length != 0 && info->def_string != NULL) {
398 memcpy(attr_fields->def_string, info->def_string,
399 info->def_length);
400 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930401 return PLDM_SUCCESS;
402}
403
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930404static uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930405 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930406{
407 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930408 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930409 return le16toh(fields->def_length);
410}
411
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930412LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930413int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930414 const struct pldm_bios_attr_table_entry *entry,
415 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930416{
417 POINTER_CHECK(entry);
418 POINTER_CHECK(def_string_length);
419 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
420 *def_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930421 pldm_bios_table_attr_entry_string_decode_def_string_length(
422 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930423 return PLDM_SUCCESS;
424}
425
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930426LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930427uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930428 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930429{
430 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930431 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930432 return fields->string_type;
433}
434
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930435LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930436uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930437 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930438{
439 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930440 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930441 return le16toh(fields->max_length);
442}
443
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930444LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930445uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930446 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930447{
448 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930449 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930450 return le16toh(fields->min_length);
451}
452
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930453LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930454uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930455 const struct pldm_bios_attr_table_entry *entry, char *buffer,
456 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930457{
458 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930459 pldm_bios_table_attr_entry_string_decode_def_string_length(
460 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930461 length = length < (size - 1) ? length : (size - 1);
462 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930463 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930464 memcpy(buffer, fields->def_string, length);
465 buffer[length] = 0;
466 return length;
467}
468
469/** @brief Get length of a string attribute entry
470 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930471static ssize_t attr_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930472{
473 uint16_t def_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930474 pldm_bios_table_attr_entry_string_decode_def_string_length(
475 entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930476 size_t len =
477 pldm_bios_table_attr_entry_string_encode_length(def_str_len);
478 if (len > SSIZE_MAX) {
479 return -1;
480 }
481 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930482}
483
484struct attr_table_integer_entry_fields {
485 uint64_t lower_bound;
486 uint64_t upper_bound;
487 uint32_t scalar_increment;
488 uint64_t default_value;
489} __attribute__((packed));
490
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930491LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930492size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930493{
494 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
495 sizeof(struct attr_table_integer_entry_fields);
496}
497
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930498LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930499int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930500 const struct pldm_bios_table_attr_entry_integer_info *info,
501 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930502{
503 if (info->lower_bound == info->upper_bound) {
504 if (info->default_value != info->lower_bound) {
505 set_errmsg(errmsg, "Wrong DefaultValue");
506 return PLDM_ERROR_INVALID_DATA;
507 }
508 if (info->scalar_increment != 0) {
509 set_errmsg(errmsg, "Wrong ScalarIncrement");
510 return PLDM_ERROR_INVALID_DATA;
511 }
512 return PLDM_SUCCESS;
513 }
514 if (info->lower_bound > info->upper_bound) {
515 set_errmsg(errmsg,
516 "LowerBound should not be greater than UpperBound");
517 return PLDM_ERROR_INVALID_DATA;
518 }
519 if (info->default_value > info->upper_bound ||
520 info->default_value < info->lower_bound) {
521 set_errmsg(errmsg, "Wrong DefaultValue");
522 return PLDM_ERROR_INVALID_DATA;
523 }
524 if (info->scalar_increment == 0) {
525 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
526 "lower_bound != upper_bound");
527 return PLDM_ERROR_INVALID_DATA;
528 }
529 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930530 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930531 0) {
532 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
533 return PLDM_ERROR_INVALID_DATA;
534 }
535 return PLDM_SUCCESS;
536}
537
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930538LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930539int pldm_bios_table_attr_entry_integer_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930540 void *entry, size_t entry_length,
541 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930542{
543 POINTER_CHECK(entry);
544 POINTER_CHECK(info);
545 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
546 BUFFER_SIZE_EXPECT(entry_length, length);
547 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930548 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930549 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930550 }
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930551 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
552 PLDM_BIOS_INTEGER;
553 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
554 info->name_handle);
555 if (rc != PLDM_SUCCESS) {
556 return rc;
557 }
558 struct pldm_bios_attr_table_entry *attr_entry = entry;
559 struct attr_table_integer_entry_fields *attr_fields =
560 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
561 attr_fields->lower_bound = htole64(info->lower_bound);
562 attr_fields->upper_bound = htole64(info->upper_bound);
563 attr_fields->scalar_increment = htole32(info->scalar_increment);
564 attr_fields->default_value = htole64(info->default_value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565 return PLDM_SUCCESS;
566}
567
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930568LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930569void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930570 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
571 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930572{
573 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930574 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930575 *lower = le64toh(fields->lower_bound);
576 *upper = le64toh(fields->upper_bound);
577 *scalar = le32toh(fields->scalar_increment);
578 *def = le64toh(fields->default_value);
579}
580
Andrew Jeffery73d91762023-06-28 12:19:19 +0930581static ssize_t attr_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930582{
583 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930584 size_t len = pldm_bios_table_attr_entry_integer_encode_length();
585 if (len > SSIZE_MAX) {
586 return -1;
587 }
588 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589}
590
591struct table_entry_length {
592 uint8_t attr_type;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930593 ssize_t (*entry_length_handler)(const void *);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930594};
595
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930596static const struct table_entry_length *
597find_table_entry_length_by_type(uint8_t attr_type,
598 const struct table_entry_length *handlers,
599 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930600{
601 size_t i;
602 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930603 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930604 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930605 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606 }
607 return NULL;
608}
609
610static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930611 { .attr_type = PLDM_BIOS_ENUMERATION,
612 .entry_length_handler = attr_table_entry_length_enum },
613 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
614 .entry_length_handler = attr_table_entry_length_enum },
615 { .attr_type = PLDM_BIOS_STRING,
616 .entry_length_handler = attr_table_entry_length_string },
617 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
618 .entry_length_handler = attr_table_entry_length_string },
619 { .attr_type = PLDM_BIOS_INTEGER,
620 .entry_length_handler = attr_table_entry_length_integer },
621 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
622 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930623};
624
Andrew Jeffery73d91762023-06-28 12:19:19 +0930625static ssize_t attr_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930626{
627 const struct pldm_bios_attr_table_entry *entry = table_entry;
628 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930629 find_table_entry_length_by_type(entry->attr_type,
630 attr_table_entries,
631 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930632 assert(attr_table_entry != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930633 if (!attr_table_entry) {
634 return -1;
635 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930636 assert(attr_table_entry->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930637 if (!attr_table_entry->entry_length_handler) {
638 return -1;
639 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930640
641 return attr_table_entry->entry_length_handler(entry);
642}
643
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930644LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930645uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930646 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930647{
648 return le16toh(entry->attr_handle);
649}
650
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930651LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930652uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930653 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930654{
655 return entry->attr_type;
656}
657
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930658LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930659size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
660{
661 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
662 sizeof(count) + count;
663}
664
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930665LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930667 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930668{
669 return entry->value[0];
670}
671
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930672LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930673uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930674 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
675 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930676{
677 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930678 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Archana Kakanib9d951f2023-10-17 05:47:58 -0500679 curr_num = number < curr_num ? number : curr_num;
680 memcpy(handles, &entry->value[1], curr_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930681
Archana Kakanib9d951f2023-10-17 05:47:58 -0500682 return curr_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930683}
684
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930685LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930686int pldm_bios_table_attr_value_entry_encode_enum_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930687 void *entry, size_t entry_length, uint16_t attr_handle,
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930688 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930689{
690 POINTER_CHECK(entry);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930691 POINTER_CHECK(handles);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930692 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930693 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930694 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
696 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930697 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930698 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930699 struct pldm_bios_attr_val_table_entry *table_entry = entry;
700 table_entry->attr_handle = htole16(attr_handle);
701 table_entry->attr_type = attr_type;
702 table_entry->value[0] = count;
703 if (count != 0) {
704 memcpy(&table_entry->value[1], handles, count);
705 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930706 return PLDM_SUCCESS;
707}
708
Andrew Jeffery73d91762023-06-28 12:19:19 +0930709static ssize_t attr_value_table_entry_length_enum(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930710{
711 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930712 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930713 size_t len =
714 pldm_bios_table_attr_value_entry_encode_enum_length(number);
715 if (len > SSIZE_MAX) {
716 return -1;
717 }
718 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930719}
720
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930721LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930722size_t
723pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
724{
725 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
726 sizeof(string_length) + string_length;
727}
728
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930729LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930730uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930731 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930732{
733 uint16_t str_length = 0;
734 memcpy(&str_length, entry->value, sizeof(str_length));
735 return le16toh(str_length);
736}
737
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930738LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930739void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930740 const struct pldm_bios_attr_val_table_entry *entry,
741 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930742{
743 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930744 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930746 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930747}
748
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930749LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930750int pldm_bios_table_attr_value_entry_encode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930751 void *entry, size_t entry_length, uint16_t attr_handle,
752 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930753{
754 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930755 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930756 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930757 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930759 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
760 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930761 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery2d663932023-06-27 14:19:15 +0930762 struct pldm_bios_attr_val_table_entry *table_entry = entry;
763 table_entry->attr_handle = htole16(attr_handle);
764 table_entry->attr_type = attr_type;
765 if (str_length != 0) {
766 memcpy(table_entry->value + sizeof(str_length), str,
767 str_length);
768 }
769 str_length = htole16(str_length);
770 memcpy(table_entry->value, &str_length, sizeof(str_length));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930771 return PLDM_SUCCESS;
772}
773
Andrew Jeffery73d91762023-06-28 12:19:19 +0930774static ssize_t attr_value_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930775{
776 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930777 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930778 size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930779 str_length);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930780 if (len > SSIZE_MAX) {
781 return -1;
782 }
783 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930784}
785
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930786LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930787size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930788{
789 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
790 sizeof(uint64_t);
791}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930792
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930793LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930794int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
795 size_t entry_length,
796 uint16_t attr_handle,
797 uint8_t attr_type,
798 uint64_t cv)
799{
800 POINTER_CHECK(entry);
801 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930802 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930803 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
804 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery0088a6a2023-06-27 15:06:45 +0930805 struct pldm_bios_attr_val_table_entry *table_entry = entry;
806 table_entry->attr_handle = htole16(attr_handle);
807 table_entry->attr_type = attr_type;
808 cv = htole64(cv);
809 memcpy(table_entry->value, &cv, sizeof(uint64_t));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930810 return PLDM_SUCCESS;
811}
812
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930813LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930814uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930815 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930816{
817 uint64_t cv = 0;
818 memcpy(&cv, entry->value, sizeof(cv));
819 cv = le64toh(cv);
820 return cv;
821}
822
Andrew Jeffery73d91762023-06-28 12:19:19 +0930823static ssize_t attr_value_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930824{
825 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930826 size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
827 if (len > SSIZE_MAX) {
828 return -1;
829 }
830 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930831}
832
833static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930834 { .attr_type = PLDM_BIOS_ENUMERATION,
835 .entry_length_handler = attr_value_table_entry_length_enum },
836 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
837 .entry_length_handler = attr_value_table_entry_length_enum },
838 { .attr_type = PLDM_BIOS_STRING,
839 .entry_length_handler = attr_value_table_entry_length_string },
840 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
841 .entry_length_handler = attr_value_table_entry_length_string },
842 { .attr_type = PLDM_BIOS_INTEGER,
843 .entry_length_handler = attr_value_table_entry_length_integer },
844 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
845 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846};
847
Andrew Jeffery73d91762023-06-28 12:19:19 +0930848static ssize_t attr_value_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930849{
850 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
851 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930852 find_table_entry_length_by_type(
853 entry->attr_type, attr_value_table_entries,
854 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930855 assert(entry_length != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930856 if (!entry_length) {
857 return -1;
858 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930859 assert(entry_length->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930860 if (!entry_length->entry_length_handler) {
861 return -1;
862 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930863
864 return entry_length->entry_length_handler(entry);
865}
866
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930867LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930868size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930869 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870{
871 return attr_value_table_entry_length(entry);
872}
873
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930874LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930875uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930876 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930877{
878 return le16toh(entry->attr_handle);
879}
880
881static size_t pad_size_get(size_t size_without_pad)
882{
883 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
884}
885
886static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
887{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930888 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930889 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930890 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891
892 return table_end;
893}
894
895static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
896{
897 checksum = htole32(checksum);
898 memcpy(table_end, &checksum, sizeof(checksum));
899
900 return table_end + sizeof(checksum);
901}
902
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930903LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
905{
906 size_t size = pad_size_get(size_without_pad) +
907 sizeof(uint32_t) /*sizeof(checksum)*/;
908 return size;
909}
910
Andrew Jeffery1264fbd2023-07-07 09:44:07 +0930911LIBPLDM_ABI_STABLE
Andrew Jeffery044ee192023-06-28 11:26:00 +0930912int pldm_bios_table_append_pad_checksum_check(void *table, size_t capacity,
913 size_t *size)
914{
915 if (!table || !size) {
916 return PLDM_ERROR_INVALID_DATA;
917 }
918
919 size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
920 size_t total_length = *size + pad_checksum_size;
Andrew Jeffery044ee192023-06-28 11:26:00 +0930921 if (capacity < total_length) {
922 return PLDM_ERROR_INVALID_LENGTH;
923 }
924
925 uint8_t *table_end = (uint8_t *)table + *size;
926 size_t pad_size = pad_size_get(*size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927 table_end = pad_append(table_end, pad_size);
928
Andrew Jeffery044ee192023-06-28 11:26:00 +0930929 uint32_t checksum = crc32(table, *size + pad_size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930930 checksum_append(table_end, checksum);
Andrew Jeffery044ee192023-06-28 11:26:00 +0930931 *size = total_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930932
Andrew Jeffery044ee192023-06-28 11:26:00 +0930933 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934}
935
936struct pldm_bios_table_iter {
937 const uint8_t *table_data;
938 size_t table_len;
939 size_t current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930940 ssize_t (*entry_length_handler)(const void *table_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930941};
942
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930943LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930944struct pldm_bios_table_iter *
945pldm_bios_table_iter_create(const void *table, size_t length,
946 enum pldm_bios_table_types type)
947{
948 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
949 assert(iter != NULL);
Andrew Jeffery757e81a2023-06-28 12:15:59 +0930950 if (!iter) {
951 return NULL;
952 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953 iter->table_data = table;
954 iter->table_len = length;
955 iter->current_pos = 0;
956 iter->entry_length_handler = NULL;
957 switch (type) {
958 case PLDM_BIOS_STRING_TABLE:
959 iter->entry_length_handler = string_table_entry_length;
960 break;
961 case PLDM_BIOS_ATTR_TABLE:
962 iter->entry_length_handler = attr_table_entry_length;
963 break;
964 case PLDM_BIOS_ATTR_VAL_TABLE:
965 iter->entry_length_handler = attr_value_table_entry_length;
966 break;
967 }
968
969 return iter;
970}
971
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930972LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930973void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
974{
975 free(iter);
976}
977
978#define pad_and_check_max 7
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930979LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930980bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
981{
Andrew Jeffery73d91762023-06-28 12:19:19 +0930982 ssize_t len;
983
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930984 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930985 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930986 }
Andrew Jeffery73d91762023-06-28 12:19:19 +0930987
988 len = iter->entry_length_handler(iter->table_data + iter->current_pos);
989
990 return len < 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930991}
992
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930993LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930994void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
995{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930996 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930997 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930998 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930999 const void *entry = iter->table_data + iter->current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +09301000 ssize_t rc = iter->entry_length_handler(entry);
1001 /* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1002 if (rc < 0) {
1003 return;
1004 }
1005 iter->current_pos += rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301006}
1007
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301008LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301009const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1010{
1011 return iter->table_data + iter->current_pos;
1012}
1013
1014typedef bool (*equal_handler)(const void *entry, const void *key);
1015
1016static const void *
1017pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1018 const void *key, equal_handler equal)
1019{
1020 const void *entry;
1021 while (!pldm_bios_table_iter_is_end(iter)) {
1022 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301023 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301024 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301025 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301026 pldm_bios_table_iter_next(iter);
1027 }
1028 return NULL;
1029}
1030
1031static const void *
1032pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1033 enum pldm_bios_table_types type,
1034 equal_handler equal, const void *key)
1035{
1036 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301037 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301038 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301039 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301040 pldm_bios_table_iter_free(iter);
1041 return entry;
1042}
1043
1044static bool string_table_handle_equal(const void *entry, const void *key)
1045{
1046 const struct pldm_bios_string_table_entry *string_entry = entry;
1047 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301048 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1049 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301050 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301051 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301052 return false;
1053}
1054
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301055LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301056const struct pldm_bios_string_table_entry *
1057pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1058 uint16_t handle)
1059{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301060 return pldm_bios_table_entry_find_from_table(table, length,
1061 PLDM_BIOS_STRING_TABLE,
1062 string_table_handle_equal,
1063 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301064}
1065
1066struct string_equal_arg {
1067 uint16_t str_length;
1068 const char *str;
1069};
1070
1071static bool string_table_string_equal(const void *entry, const void *key)
1072{
1073 const struct pldm_bios_string_table_entry *string_entry = entry;
1074 const struct string_equal_arg *arg = key;
1075 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301076 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301077 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301078 }
1079 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301080 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301081 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301082 return true;
1083}
1084
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301085LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301086const struct pldm_bios_string_table_entry *
1087pldm_bios_table_string_find_by_string(const void *table, size_t length,
1088 const char *str)
1089{
1090 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301091 struct string_equal_arg arg = { str_length, str };
1092 return pldm_bios_table_entry_find_from_table(table, length,
1093 PLDM_BIOS_STRING_TABLE,
1094 string_table_string_equal,
1095 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301096}
1097
1098static bool attr_table_handle_equal(const void *entry, const void *key)
1099{
1100 uint16_t handle = *(uint16_t *)key;
1101 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1102 handle;
1103}
1104
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301105LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106const struct pldm_bios_attr_table_entry *
1107pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1108 uint16_t handle)
1109{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301110 return pldm_bios_table_entry_find_from_table(table, length,
1111 PLDM_BIOS_ATTR_TABLE,
1112 attr_table_handle_equal,
1113 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301114}
1115
1116static bool attr_table_string_handle_equal(const void *entry, const void *key)
1117{
1118 uint16_t handle = *(uint16_t *)key;
1119 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1120}
1121
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301122LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301123const struct pldm_bios_attr_table_entry *
1124pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1125 uint16_t handle)
1126{
1127 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301128 table, length, PLDM_BIOS_ATTR_TABLE,
1129 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301130}
1131
1132static bool attr_value_table_handle_equal(const void *entry, const void *key)
1133{
1134 uint16_t handle = *(uint16_t *)key;
1135 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1136}
1137
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301138LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301139const struct pldm_bios_attr_val_table_entry *
1140pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1141 uint16_t handle)
1142{
1143 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301144 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1145 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301146}
1147
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301148LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301149int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301150 const void *src_table, size_t src_length, void *dest_table,
1151 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301152{
1153 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301154 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301155
1156 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301157 const struct pldm_bios_attr_val_table_entry *tmp;
1158 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1159 size_t buffer_length = *dest_length;
1160 size_t copied_length = 0;
1161 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301162 while (!pldm_bios_table_iter_is_end(iter)) {
1163 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1164 length = attr_value_table_entry_length(tmp);
1165
1166 /* we need the tmp's entry_length here, iter_next will calculate
1167 * it too, use current_pos directly to avoid calculating it
1168 * twice */
1169 iter->current_pos += length;
1170 if (tmp->attr_handle == to_update->attr_handle) {
1171 if (tmp->attr_type != to_update->attr_type) {
1172 rc = PLDM_ERROR_INVALID_DATA;
1173 goto out;
1174 }
1175 length = entry_length;
1176 tmp = entry;
1177 }
1178 if (copied_length + length > buffer_length) {
1179 rc = PLDM_ERROR_INVALID_LENGTH;
1180 goto out;
1181 }
1182 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1183 copied_length += length;
1184 }
1185
1186 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301187 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301188 if ((pad_checksum_size + copied_length) > buffer_length) {
1189 rc = PLDM_ERROR_INVALID_LENGTH;
1190 goto out;
1191 }
1192
Andrew Jeffery50dd1592023-07-14 16:02:05 +09301193 rc = pldm_bios_table_append_pad_checksum_check(
1194 dest_table, buffer_length, &copied_length);
1195 if (rc == PLDM_SUCCESS) {
1196 *dest_length = copied_length;
1197 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301198out:
1199 pldm_bios_table_iter_free(iter);
1200 return rc;
1201}
1202
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301203LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301204bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1205{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301206 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301207 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301208 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301209
1210 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1211 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301212 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301213 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301214 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301215
1216 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1217 uint32_t dst_crc = crc32(table, size - 4);
1218
1219 return src_crc == dst_crc;
1220}