blob: 753f7eeff01351556be292b2bc554ed135045f6c [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"
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10303
4#include <libpldm/base.h>
5#include <libpldm/bios.h>
6#include <libpldm/bios_table.h>
7#include <libpldm/utils.h>
8
Andrew Jeffery9c766792022-08-10 23:12:49 +09309#include <assert.h>
10#include <endian.h>
Andrew Jeffery73d91762023-06-28 12:19:19 +093011#include <limits.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093012#include <stdbool.h>
13#include <stdint.h>
14#include <stdlib.h>
15#include <string.h>
16
Andrew Jeffery9c766792022-08-10 23:12:49 +093017#define POINTER_CHECK(pointer) \
18 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093019 if ((pointer) == NULL) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093020 return PLDM_ERROR_INVALID_DATA; \
21 } while (0)
22
23#define ATTR_TYPE_EXPECT(type, expected) \
24 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093025 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093026 return PLDM_ERROR_INVALID_DATA; \
27 } while (0)
28
29#define BUFFER_SIZE_EXPECT(current_size, expected_size) \
30 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +093031 if ((current_size) < (expected_size)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +093032 return PLDM_ERROR_INVALID_LENGTH; \
33 } while (0)
34
35#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
36
37static void set_errmsg(const char **errmsg, const char *msg)
38{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093039 if (errmsg != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093040 *errmsg = msg;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093041 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093042}
43
Andrew Jefferya873eca2023-06-26 17:25:37 +093044static int get_bios_string_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +093045{
46 static uint16_t handle = 0;
47 assert(handle != UINT16_MAX);
Andrew Jefferya873eca2023-06-26 17:25:37 +093048 if (handle == UINT16_MAX) {
49 return PLDM_ERROR_INVALID_DATA;
50 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093051
Andrew Jefferya873eca2023-06-26 17:25:37 +093052 *val = handle++;
53 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +093054}
55
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093056LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093057size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
58{
59 return sizeof(struct pldm_bios_string_table_entry) -
60 MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
61}
62
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093063LIBPLDM_ABI_STABLE
Andrew Jefferye48fdd62024-06-25 00:36:20 +093064int pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
65 const char *str, uint16_t str_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +093066{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093067 if (str_length == 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093068 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093069 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093070 POINTER_CHECK(entry);
71 POINTER_CHECK(str);
72 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
73 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093074 struct pldm_bios_string_table_entry *string_entry = entry;
Andrew Jefferya873eca2023-06-26 17:25:37 +093075 uint16_t handle;
76 int rc = get_bios_string_handle(&handle);
77 if (rc != PLDM_SUCCESS) {
78 return rc;
79 }
80 string_entry->string_handle = htole16(handle);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093081 string_entry->string_length = htole16(str_length);
82 memcpy(string_entry->name, str, str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +093083 return PLDM_SUCCESS;
84}
85
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093086LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093087uint16_t pldm_bios_table_string_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093088 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093089{
90 return le16toh(entry->string_handle);
91}
92
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093093LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093094uint16_t pldm_bios_table_string_entry_decode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093095 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093096{
97 return le16toh(entry->string_length);
98}
99
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930100LIBPLDM_ABI_STABLE
Andrew Jeffery8c37ab32024-06-25 15:34:27 +0930101int pldm_bios_table_string_entry_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930102 const struct pldm_bios_string_table_entry *entry, char *buffer,
103 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930104{
105 POINTER_CHECK(entry);
106 POINTER_CHECK(buffer);
Andrew Jeffery98c1e692023-06-14 14:41:19 +0930107 if (size == 0) {
108 return PLDM_ERROR_INVALID_LENGTH;
109 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930110 size_t length =
111 pldm_bios_table_string_entry_decode_string_length(entry);
112 length = length < (size - 1) ? length : (size - 1);
113 memcpy(buffer, entry->name, length);
114 buffer[length] = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930115 return PLDM_SUCCESS;
116}
117
Andrew Jeffery73d91762023-06-28 12:19:19 +0930118static ssize_t string_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930119{
120 const struct pldm_bios_string_table_entry *entry = table_entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930121 size_t len = sizeof(*entry) - sizeof(entry->name) +
122 pldm_bios_table_string_entry_decode_string_length(entry);
123 if (len > SSIZE_MAX) {
124 return -1;
125 }
126 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930127}
128
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930129static int get_bios_attr_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930130{
131 static uint16_t handle = 0;
132 assert(handle != UINT16_MAX);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930133 if (handle == UINT16_MAX) {
134 return PLDM_ERROR_INVALID_DATA;
135 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930136
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930137 *val = handle++;
138 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930139}
140
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930141static int attr_table_entry_encode_header(void *entry, size_t length,
142 uint8_t attr_type,
143 uint16_t string_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930144{
145 struct pldm_bios_attr_table_entry *attr_entry = entry;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930146
Andrew Jeffery9c766792022-08-10 23:12:49 +0930147 assert(sizeof(*attr_entry) <= length);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930148 if (sizeof(*attr_entry) > length) {
149 return PLDM_ERROR_INVALID_LENGTH;
150 }
151
152 uint16_t handle;
153 int rc = get_bios_attr_handle(&handle);
154 if (rc != PLDM_SUCCESS) {
155 return rc;
156 }
157
158 attr_entry->attr_handle = htole16(handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930159 attr_entry->attr_type = attr_type;
160 attr_entry->string_handle = htole16(string_handle);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930161
162 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930163}
164
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930165LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930166uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930167 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930168{
169 return le16toh(entry->attr_handle);
170}
171
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930172LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930173uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930174 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930175{
176 return entry->attr_type;
177}
178
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930179LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930180uint16_t pldm_bios_table_attr_entry_decode_string_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930181 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930182{
183 return le16toh(entry->string_handle);
184}
185
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930186LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
188 uint8_t def_num)
189{
190 return sizeof(struct pldm_bios_attr_table_entry) -
191 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
192 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
193 def_num;
194}
195
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930196LIBPLDM_ABI_STABLE
197int pldm_bios_table_attr_entry_enum_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930198 void *entry, size_t entry_length,
199 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930200{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930201 POINTER_CHECK(entry);
202 POINTER_CHECK(info);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930203 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930204 info->pv_num, info->def_num);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930205 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930206 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
207 PLDM_BIOS_ENUMERATION;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930208 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
209 info->name_handle);
210 if (rc != PLDM_SUCCESS) {
211 return rc;
212 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930213 struct pldm_bios_attr_table_entry *attr_entry = entry;
214 attr_entry->metadata[0] = info->pv_num;
215 uint16_t *pv_hdls =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930216 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930217 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930218 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930219 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930220 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930221 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930222 info->def_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930223 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930224 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930225 info->def_index, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930226 return PLDM_SUCCESS;
227}
228
229#define ATTR_TYPE_EXPECT(type, expected) \
230 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930231 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930232 return PLDM_ERROR_INVALID_DATA; \
233 } while (0)
234
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930235LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930236int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930237 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930238{
239 POINTER_CHECK(entry);
240 POINTER_CHECK(pv_num);
241 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930242 *pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930243 return PLDM_SUCCESS;
244}
245
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930246static uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930247 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930248{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930249 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930250 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
251 sizeof(uint16_t) * pv_num];
252}
253
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930254LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930255int pldm_bios_table_attr_entry_enum_decode_def_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930256 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930257{
258 POINTER_CHECK(entry);
259 POINTER_CHECK(def_num);
260 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
261 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
262 return PLDM_SUCCESS;
263}
264
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930265LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930266int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930267 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
268 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930269{
270 POINTER_CHECK(entry);
271 POINTER_CHECK(pv_hdls);
272 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930273 uint8_t num = entry->metadata[0];
274 num = num < pv_num ? num : pv_num;
275 size_t i;
276 for (i = 0; i < num; i++) {
277 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
278 i * sizeof(uint16_t));
279 pv_hdls[i] = le16toh(*hdl);
280 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930281 return PLDM_SUCCESS;
282}
283
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930284LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930285uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930286 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
287 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930288{
289 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
290 num = num < def_num ? num : def_num;
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930291 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930292 const uint8_t *p = entry->metadata +
293 sizeof(uint8_t) /* number of possible values*/
294 + pv_num * sizeof(uint16_t) /* possible values */
295 + sizeof(uint8_t); /* number of default values */
296 memcpy(def_indices, p, num);
297 return num;
298}
299
300/** @brief Get length of an enum attribute entry
301 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930302static ssize_t attr_table_entry_length_enum(const void *arg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930303{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930304 const struct pldm_bios_attr_table_entry *entry = arg;
305 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930306 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930307 size_t len =
308 pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
309 if (len > SSIZE_MAX) {
310 return -1;
311 }
312 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930313}
314
315struct attr_table_string_entry_fields {
316 uint8_t string_type;
317 uint16_t min_length;
318 uint16_t max_length;
319 uint16_t def_length;
320 uint8_t def_string[1];
321} __attribute__((packed));
322
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930323LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930324size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
325{
326 return sizeof(struct pldm_bios_attr_table_entry) -
327 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
328 sizeof(struct attr_table_string_entry_fields) -
329 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
330 def_str_len;
331}
332
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930333#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930334#define PLDM_STRING_TYPE_VENDOR 0xff
335
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930336LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930338 const struct pldm_bios_table_attr_entry_string_info *info,
339 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930340{
341 if (info->min_length > info->max_length) {
342 set_errmsg(errmsg, "MinimumStingLength should not be greater "
343 "than MaximumStringLength");
344 return PLDM_ERROR_INVALID_DATA;
345 }
346 if (info->min_length == info->max_length &&
347 info->def_length != info->min_length) {
348 set_errmsg(errmsg, "Wrong DefaultStringLength");
349 return PLDM_ERROR_INVALID_DATA;
350 }
351 if (info->def_length > info->max_length ||
352 info->def_length < info->min_length) {
353 set_errmsg(errmsg, "Wrong DefaultStringLength");
354 return PLDM_ERROR_INVALID_DATA;
355 }
356 if (info->string_type > PLDM_STRING_TYPE_MAX &&
357 info->string_type != PLDM_STRING_TYPE_VENDOR) {
358 set_errmsg(errmsg, "Wrong StringType");
359 return PLDM_ERROR_INVALID_DATA;
360 }
Andrew Jefferydf02e362023-06-14 14:52:25 +0930361 if (info->def_string && info->def_length != strlen(info->def_string)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930362 set_errmsg(errmsg, "Length of DefaultString should be equal to "
363 "DefaultStringLength");
364 return PLDM_ERROR_INVALID_DATA;
365 }
366
367 return PLDM_SUCCESS;
368}
369
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930370LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930371int pldm_bios_table_attr_entry_string_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930372 void *entry, size_t entry_length,
373 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374{
375 POINTER_CHECK(entry);
376 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930377 size_t length = pldm_bios_table_attr_entry_string_encode_length(
378 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930379 BUFFER_SIZE_EXPECT(entry_length, length);
380 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930381 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930382 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930383 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930384 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
385 PLDM_BIOS_STRING;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930386 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
387 info->name_handle);
388 if (rc != PLDM_SUCCESS) {
389 return rc;
390 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930391 struct pldm_bios_attr_table_entry *attr_entry = entry;
392 struct attr_table_string_entry_fields *attr_fields =
393 (struct attr_table_string_entry_fields *)attr_entry->metadata;
394 attr_fields->string_type = info->string_type;
395 attr_fields->min_length = htole16(info->min_length);
396 attr_fields->max_length = htole16(info->max_length);
397 attr_fields->def_length = htole16(info->def_length);
398 if (info->def_length != 0 && info->def_string != NULL) {
399 memcpy(attr_fields->def_string, info->def_string,
400 info->def_length);
401 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930402 return PLDM_SUCCESS;
403}
404
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930405static uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930406 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930407{
408 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930409 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930410 return le16toh(fields->def_length);
411}
412
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930413LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930414int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930415 const struct pldm_bios_attr_table_entry *entry,
416 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930417{
418 POINTER_CHECK(entry);
419 POINTER_CHECK(def_string_length);
420 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
421 *def_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930422 pldm_bios_table_attr_entry_string_decode_def_string_length(
423 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930424 return PLDM_SUCCESS;
425}
426
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930427LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930428uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930429 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930430{
431 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930432 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930433 return fields->string_type;
434}
435
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930436LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930437uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930438 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930439{
440 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930441 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930442 return le16toh(fields->max_length);
443}
444
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930445LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930446uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930447 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930448{
449 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930450 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930451 return le16toh(fields->min_length);
452}
453
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930454LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930455uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930456 const struct pldm_bios_attr_table_entry *entry, char *buffer,
457 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930458{
459 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930460 pldm_bios_table_attr_entry_string_decode_def_string_length(
461 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930462 length = length < (size - 1) ? length : (size - 1);
463 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930464 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930465 memcpy(buffer, fields->def_string, length);
466 buffer[length] = 0;
467 return length;
468}
469
470/** @brief Get length of a string attribute entry
471 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930472static ssize_t attr_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930473{
474 uint16_t def_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930475 pldm_bios_table_attr_entry_string_decode_def_string_length(
476 entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930477 size_t len =
478 pldm_bios_table_attr_entry_string_encode_length(def_str_len);
479 if (len > SSIZE_MAX) {
480 return -1;
481 }
482 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930483}
484
485struct attr_table_integer_entry_fields {
486 uint64_t lower_bound;
487 uint64_t upper_bound;
488 uint32_t scalar_increment;
489 uint64_t default_value;
490} __attribute__((packed));
491
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930492LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930493size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930494{
495 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
496 sizeof(struct attr_table_integer_entry_fields);
497}
498
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930499LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930500int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930501 const struct pldm_bios_table_attr_entry_integer_info *info,
502 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930503{
504 if (info->lower_bound == info->upper_bound) {
505 if (info->default_value != info->lower_bound) {
506 set_errmsg(errmsg, "Wrong DefaultValue");
507 return PLDM_ERROR_INVALID_DATA;
508 }
509 if (info->scalar_increment != 0) {
510 set_errmsg(errmsg, "Wrong ScalarIncrement");
511 return PLDM_ERROR_INVALID_DATA;
512 }
513 return PLDM_SUCCESS;
514 }
515 if (info->lower_bound > info->upper_bound) {
516 set_errmsg(errmsg,
517 "LowerBound should not be greater than UpperBound");
518 return PLDM_ERROR_INVALID_DATA;
519 }
520 if (info->default_value > info->upper_bound ||
521 info->default_value < info->lower_bound) {
522 set_errmsg(errmsg, "Wrong DefaultValue");
523 return PLDM_ERROR_INVALID_DATA;
524 }
525 if (info->scalar_increment == 0) {
526 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
527 "lower_bound != upper_bound");
528 return PLDM_ERROR_INVALID_DATA;
529 }
530 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930531 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930532 0) {
533 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
534 return PLDM_ERROR_INVALID_DATA;
535 }
536 return PLDM_SUCCESS;
537}
538
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930539LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930540int pldm_bios_table_attr_entry_integer_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930541 void *entry, size_t entry_length,
542 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930543{
544 POINTER_CHECK(entry);
545 POINTER_CHECK(info);
546 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
547 BUFFER_SIZE_EXPECT(entry_length, length);
548 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930549 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930550 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930551 }
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930552 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
553 PLDM_BIOS_INTEGER;
554 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
555 info->name_handle);
556 if (rc != PLDM_SUCCESS) {
557 return rc;
558 }
559 struct pldm_bios_attr_table_entry *attr_entry = entry;
560 struct attr_table_integer_entry_fields *attr_fields =
561 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
562 attr_fields->lower_bound = htole64(info->lower_bound);
563 attr_fields->upper_bound = htole64(info->upper_bound);
564 attr_fields->scalar_increment = htole32(info->scalar_increment);
565 attr_fields->default_value = htole64(info->default_value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930566 return PLDM_SUCCESS;
567}
568
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930569LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930570void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930571 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
572 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930573{
574 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930575 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930576 *lower = le64toh(fields->lower_bound);
577 *upper = le64toh(fields->upper_bound);
578 *scalar = le32toh(fields->scalar_increment);
579 *def = le64toh(fields->default_value);
580}
581
Andrew Jeffery73d91762023-06-28 12:19:19 +0930582static ssize_t attr_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930583{
584 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930585 size_t len = pldm_bios_table_attr_entry_integer_encode_length();
586 if (len > SSIZE_MAX) {
587 return -1;
588 }
589 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930590}
591
592struct table_entry_length {
593 uint8_t attr_type;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930594 ssize_t (*entry_length_handler)(const void *);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930595};
596
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930597static const struct table_entry_length *
598find_table_entry_length_by_type(uint8_t attr_type,
599 const struct table_entry_length *handlers,
600 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930601{
602 size_t i;
603 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930604 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930605 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930606 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930607 }
608 return NULL;
609}
610
611static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930612 { .attr_type = PLDM_BIOS_ENUMERATION,
613 .entry_length_handler = attr_table_entry_length_enum },
614 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
615 .entry_length_handler = attr_table_entry_length_enum },
616 { .attr_type = PLDM_BIOS_STRING,
617 .entry_length_handler = attr_table_entry_length_string },
618 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
619 .entry_length_handler = attr_table_entry_length_string },
620 { .attr_type = PLDM_BIOS_INTEGER,
621 .entry_length_handler = attr_table_entry_length_integer },
622 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
623 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930624};
625
Andrew Jeffery73d91762023-06-28 12:19:19 +0930626static ssize_t attr_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930627{
628 const struct pldm_bios_attr_table_entry *entry = table_entry;
629 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930630 find_table_entry_length_by_type(entry->attr_type,
631 attr_table_entries,
632 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930633 assert(attr_table_entry != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930634 if (!attr_table_entry) {
635 return -1;
636 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930637 assert(attr_table_entry->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930638 if (!attr_table_entry->entry_length_handler) {
639 return -1;
640 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930641
642 return attr_table_entry->entry_length_handler(entry);
643}
644
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930645LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930646uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930647 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930648{
649 return le16toh(entry->attr_handle);
650}
651
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930652LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930653uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930654 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930655{
656 return entry->attr_type;
657}
658
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930659LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930660size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
661{
662 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
663 sizeof(count) + count;
664}
665
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930666LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930667uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930668 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930669{
670 return entry->value[0];
671}
672
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930673LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930674uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930675 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
676 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677{
678 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930679 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Archana Kakanib9d951f2023-10-17 05:47:58 -0500680 curr_num = number < curr_num ? number : curr_num;
681 memcpy(handles, &entry->value[1], curr_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930682
Archana Kakanib9d951f2023-10-17 05:47:58 -0500683 return curr_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930684}
685
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930686LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687int pldm_bios_table_attr_value_entry_encode_enum_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930688 void *entry, size_t entry_length, uint16_t attr_handle,
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930689 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930690{
691 POINTER_CHECK(entry);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930692 POINTER_CHECK(handles);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930693 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930694 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930695 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930696 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
697 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930698 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930699 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930700 struct pldm_bios_attr_val_table_entry *table_entry = entry;
701 table_entry->attr_handle = htole16(attr_handle);
702 table_entry->attr_type = attr_type;
703 table_entry->value[0] = count;
704 if (count != 0) {
705 memcpy(&table_entry->value[1], handles, count);
706 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930707 return PLDM_SUCCESS;
708}
709
Andrew Jeffery73d91762023-06-28 12:19:19 +0930710static ssize_t attr_value_table_entry_length_enum(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930711{
712 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930713 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930714 size_t len =
715 pldm_bios_table_attr_value_entry_encode_enum_length(number);
716 if (len > SSIZE_MAX) {
717 return -1;
718 }
719 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930720}
721
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930722LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930723size_t
724pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
725{
726 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
727 sizeof(string_length) + string_length;
728}
729
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930730LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930731uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930732 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930733{
734 uint16_t str_length = 0;
735 memcpy(&str_length, entry->value, sizeof(str_length));
736 return le16toh(str_length);
737}
738
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930739LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930740void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930741 const struct pldm_bios_attr_val_table_entry *entry,
742 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930743{
744 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930745 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930746 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930747 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748}
749
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930750LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930751int pldm_bios_table_attr_value_entry_encode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930752 void *entry, size_t entry_length, uint16_t attr_handle,
753 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930754{
755 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930756 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930757 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930758 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930759 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930760 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
761 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930762 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery2d663932023-06-27 14:19:15 +0930763 struct pldm_bios_attr_val_table_entry *table_entry = entry;
764 table_entry->attr_handle = htole16(attr_handle);
765 table_entry->attr_type = attr_type;
766 if (str_length != 0) {
767 memcpy(table_entry->value + sizeof(str_length), str,
768 str_length);
769 }
770 str_length = htole16(str_length);
771 memcpy(table_entry->value, &str_length, sizeof(str_length));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930772 return PLDM_SUCCESS;
773}
774
Andrew Jeffery73d91762023-06-28 12:19:19 +0930775static ssize_t attr_value_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930776{
777 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930778 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930779 size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930780 str_length);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930781 if (len > SSIZE_MAX) {
782 return -1;
783 }
784 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930785}
786
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930787LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930788size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930789{
790 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
791 sizeof(uint64_t);
792}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930793
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930794LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930795int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
796 size_t entry_length,
797 uint16_t attr_handle,
798 uint8_t attr_type,
799 uint64_t cv)
800{
801 POINTER_CHECK(entry);
802 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930803 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930804 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
805 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery0088a6a2023-06-27 15:06:45 +0930806 struct pldm_bios_attr_val_table_entry *table_entry = entry;
807 table_entry->attr_handle = htole16(attr_handle);
808 table_entry->attr_type = attr_type;
809 cv = htole64(cv);
810 memcpy(table_entry->value, &cv, sizeof(uint64_t));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930811 return PLDM_SUCCESS;
812}
813
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930814LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930815uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930816 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930817{
818 uint64_t cv = 0;
819 memcpy(&cv, entry->value, sizeof(cv));
820 cv = le64toh(cv);
821 return cv;
822}
823
Andrew Jeffery73d91762023-06-28 12:19:19 +0930824static ssize_t attr_value_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930825{
826 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930827 size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
828 if (len > SSIZE_MAX) {
829 return -1;
830 }
831 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930832}
833
834static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930835 { .attr_type = PLDM_BIOS_ENUMERATION,
836 .entry_length_handler = attr_value_table_entry_length_enum },
837 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
838 .entry_length_handler = attr_value_table_entry_length_enum },
839 { .attr_type = PLDM_BIOS_STRING,
840 .entry_length_handler = attr_value_table_entry_length_string },
841 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
842 .entry_length_handler = attr_value_table_entry_length_string },
843 { .attr_type = PLDM_BIOS_INTEGER,
844 .entry_length_handler = attr_value_table_entry_length_integer },
845 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
846 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847};
848
Andrew Jeffery73d91762023-06-28 12:19:19 +0930849static ssize_t attr_value_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930850{
851 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
852 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930853 find_table_entry_length_by_type(
854 entry->attr_type, attr_value_table_entries,
855 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930856 assert(entry_length != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930857 if (!entry_length) {
858 return -1;
859 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930860 assert(entry_length->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930861 if (!entry_length->entry_length_handler) {
862 return -1;
863 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930864
865 return entry_length->entry_length_handler(entry);
866}
867
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930868LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930869size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930870 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930871{
872 return attr_value_table_entry_length(entry);
873}
874
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930875LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930876uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930877 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930878{
879 return le16toh(entry->attr_handle);
880}
881
882static size_t pad_size_get(size_t size_without_pad)
883{
884 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
885}
886
887static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
888{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930889 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930891 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930892
893 return table_end;
894}
895
896static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
897{
898 checksum = htole32(checksum);
899 memcpy(table_end, &checksum, sizeof(checksum));
900
901 return table_end + sizeof(checksum);
902}
903
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930904LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
906{
907 size_t size = pad_size_get(size_without_pad) +
908 sizeof(uint32_t) /*sizeof(checksum)*/;
909 return size;
910}
911
Andrew Jeffery1264fbd2023-07-07 09:44:07 +0930912LIBPLDM_ABI_STABLE
Andrew Jeffery044ee192023-06-28 11:26:00 +0930913int pldm_bios_table_append_pad_checksum_check(void *table, size_t capacity,
914 size_t *size)
915{
916 if (!table || !size) {
917 return PLDM_ERROR_INVALID_DATA;
918 }
919
920 size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
921 size_t total_length = *size + pad_checksum_size;
Andrew Jeffery044ee192023-06-28 11:26:00 +0930922 if (capacity < total_length) {
923 return PLDM_ERROR_INVALID_LENGTH;
924 }
925
926 uint8_t *table_end = (uint8_t *)table + *size;
927 size_t pad_size = pad_size_get(*size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930928 table_end = pad_append(table_end, pad_size);
929
Andrew Jeffery044ee192023-06-28 11:26:00 +0930930 uint32_t checksum = crc32(table, *size + pad_size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931 checksum_append(table_end, checksum);
Andrew Jeffery044ee192023-06-28 11:26:00 +0930932 *size = total_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930933
Andrew Jeffery044ee192023-06-28 11:26:00 +0930934 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930935}
936
937struct pldm_bios_table_iter {
938 const uint8_t *table_data;
939 size_t table_len;
940 size_t current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930941 ssize_t (*entry_length_handler)(const void *table_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930942};
943
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930944LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945struct pldm_bios_table_iter *
946pldm_bios_table_iter_create(const void *table, size_t length,
947 enum pldm_bios_table_types type)
948{
949 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
950 assert(iter != NULL);
Andrew Jeffery757e81a2023-06-28 12:15:59 +0930951 if (!iter) {
952 return NULL;
953 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930954 iter->table_data = table;
955 iter->table_len = length;
956 iter->current_pos = 0;
957 iter->entry_length_handler = NULL;
958 switch (type) {
959 case PLDM_BIOS_STRING_TABLE:
960 iter->entry_length_handler = string_table_entry_length;
961 break;
962 case PLDM_BIOS_ATTR_TABLE:
963 iter->entry_length_handler = attr_table_entry_length;
964 break;
965 case PLDM_BIOS_ATTR_VAL_TABLE:
966 iter->entry_length_handler = attr_value_table_entry_length;
967 break;
968 }
969
970 return iter;
971}
972
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930973LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930974void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
975{
976 free(iter);
977}
978
979#define pad_and_check_max 7
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930980LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
982{
Andrew Jeffery73d91762023-06-28 12:19:19 +0930983 ssize_t len;
984
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930985 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930986 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930987 }
Andrew Jeffery73d91762023-06-28 12:19:19 +0930988
989 len = iter->entry_length_handler(iter->table_data + iter->current_pos);
990
991 return len < 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930992}
993
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930994LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930995void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
996{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930997 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930998 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930999 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301000 const void *entry = iter->table_data + iter->current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +09301001 ssize_t rc = iter->entry_length_handler(entry);
1002 /* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1003 if (rc < 0) {
1004 return;
1005 }
1006 iter->current_pos += rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301007}
1008
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301009LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301010const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1011{
1012 return iter->table_data + iter->current_pos;
1013}
1014
1015typedef bool (*equal_handler)(const void *entry, const void *key);
1016
1017static const void *
1018pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1019 const void *key, equal_handler equal)
1020{
1021 const void *entry;
1022 while (!pldm_bios_table_iter_is_end(iter)) {
1023 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301024 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301025 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301026 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301027 pldm_bios_table_iter_next(iter);
1028 }
1029 return NULL;
1030}
1031
1032static const void *
1033pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1034 enum pldm_bios_table_types type,
1035 equal_handler equal, const void *key)
1036{
1037 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301038 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301039 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301040 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301041 pldm_bios_table_iter_free(iter);
1042 return entry;
1043}
1044
1045static bool string_table_handle_equal(const void *entry, const void *key)
1046{
1047 const struct pldm_bios_string_table_entry *string_entry = entry;
1048 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301049 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1050 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301051 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301052 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301053 return false;
1054}
1055
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301056LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301057const struct pldm_bios_string_table_entry *
1058pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1059 uint16_t handle)
1060{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301061 return pldm_bios_table_entry_find_from_table(table, length,
1062 PLDM_BIOS_STRING_TABLE,
1063 string_table_handle_equal,
1064 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301065}
1066
1067struct string_equal_arg {
1068 uint16_t str_length;
1069 const char *str;
1070};
1071
1072static bool string_table_string_equal(const void *entry, const void *key)
1073{
1074 const struct pldm_bios_string_table_entry *string_entry = entry;
1075 const struct string_equal_arg *arg = key;
1076 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301077 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301078 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301079 }
1080 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301081 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301082 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301083 return true;
1084}
1085
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301086LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301087const struct pldm_bios_string_table_entry *
1088pldm_bios_table_string_find_by_string(const void *table, size_t length,
1089 const char *str)
1090{
1091 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301092 struct string_equal_arg arg = { str_length, str };
1093 return pldm_bios_table_entry_find_from_table(table, length,
1094 PLDM_BIOS_STRING_TABLE,
1095 string_table_string_equal,
1096 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301097}
1098
1099static bool attr_table_handle_equal(const void *entry, const void *key)
1100{
1101 uint16_t handle = *(uint16_t *)key;
1102 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1103 handle;
1104}
1105
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301106LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301107const struct pldm_bios_attr_table_entry *
1108pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1109 uint16_t handle)
1110{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301111 return pldm_bios_table_entry_find_from_table(table, length,
1112 PLDM_BIOS_ATTR_TABLE,
1113 attr_table_handle_equal,
1114 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301115}
1116
1117static bool attr_table_string_handle_equal(const void *entry, const void *key)
1118{
1119 uint16_t handle = *(uint16_t *)key;
1120 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1121}
1122
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301123LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301124const struct pldm_bios_attr_table_entry *
1125pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1126 uint16_t handle)
1127{
1128 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301129 table, length, PLDM_BIOS_ATTR_TABLE,
1130 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301131}
1132
1133static bool attr_value_table_handle_equal(const void *entry, const void *key)
1134{
1135 uint16_t handle = *(uint16_t *)key;
1136 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1137}
1138
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301139LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301140const struct pldm_bios_attr_val_table_entry *
1141pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1142 uint16_t handle)
1143{
1144 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301145 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1146 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301147}
1148
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301149LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301150int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301151 const void *src_table, size_t src_length, void *dest_table,
1152 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301153{
1154 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301155 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301156
1157 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301158 const struct pldm_bios_attr_val_table_entry *tmp;
1159 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1160 size_t buffer_length = *dest_length;
1161 size_t copied_length = 0;
1162 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301163 while (!pldm_bios_table_iter_is_end(iter)) {
1164 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1165 length = attr_value_table_entry_length(tmp);
1166
1167 /* we need the tmp's entry_length here, iter_next will calculate
1168 * it too, use current_pos directly to avoid calculating it
1169 * twice */
1170 iter->current_pos += length;
1171 if (tmp->attr_handle == to_update->attr_handle) {
1172 if (tmp->attr_type != to_update->attr_type) {
1173 rc = PLDM_ERROR_INVALID_DATA;
1174 goto out;
1175 }
1176 length = entry_length;
1177 tmp = entry;
1178 }
1179 if (copied_length + length > buffer_length) {
1180 rc = PLDM_ERROR_INVALID_LENGTH;
1181 goto out;
1182 }
1183 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1184 copied_length += length;
1185 }
1186
1187 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301188 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301189 if ((pad_checksum_size + copied_length) > buffer_length) {
1190 rc = PLDM_ERROR_INVALID_LENGTH;
1191 goto out;
1192 }
1193
Andrew Jeffery50dd1592023-07-14 16:02:05 +09301194 rc = pldm_bios_table_append_pad_checksum_check(
1195 dest_table, buffer_length, &copied_length);
1196 if (rc == PLDM_SUCCESS) {
1197 *dest_length = copied_length;
1198 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301199out:
1200 pldm_bios_table_iter_free(iter);
1201 return rc;
1202}
1203
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301204LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301205bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1206{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301207 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301208 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301209 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301210
1211 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1212 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301213 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301215 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301216
1217 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1218 uint32_t dst_crc = crc32(table, size - 4);
1219
1220 return src_crc == dst_crc;
1221}