blob: 10b24951459be788e1def7768996ca6299ce28f8 [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 Jeffery9c766792022-08-10 23:12:49 +093064int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
65 const char *str,
66 uint16_t str_length)
67{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093068 if (str_length == 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093069 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +093070 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093071 POINTER_CHECK(entry);
72 POINTER_CHECK(str);
73 size_t length = pldm_bios_table_string_entry_encode_length(str_length);
74 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093075 struct pldm_bios_string_table_entry *string_entry = entry;
Andrew Jefferya873eca2023-06-26 17:25:37 +093076 uint16_t handle;
77 int rc = get_bios_string_handle(&handle);
78 if (rc != PLDM_SUCCESS) {
79 return rc;
80 }
81 string_entry->string_handle = htole16(handle);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093082 string_entry->string_length = htole16(str_length);
83 memcpy(string_entry->name, str, str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +093084 return PLDM_SUCCESS;
85}
86
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093087LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093088uint16_t pldm_bios_table_string_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093089 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093090{
91 return le16toh(entry->string_handle);
92}
93
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093094LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093095uint16_t pldm_bios_table_string_entry_decode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093096 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093097{
98 return le16toh(entry->string_length);
99}
100
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930101LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930102int pldm_bios_table_string_entry_decode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930103 const struct pldm_bios_string_table_entry *entry, char *buffer,
104 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930105{
106 POINTER_CHECK(entry);
107 POINTER_CHECK(buffer);
Andrew Jeffery98c1e692023-06-14 14:41:19 +0930108 if (size == 0) {
109 return PLDM_ERROR_INVALID_LENGTH;
110 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930111 size_t length =
112 pldm_bios_table_string_entry_decode_string_length(entry);
113 length = length < (size - 1) ? length : (size - 1);
114 memcpy(buffer, entry->name, length);
115 buffer[length] = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930116 return PLDM_SUCCESS;
117}
118
Andrew Jeffery73d91762023-06-28 12:19:19 +0930119static ssize_t string_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930120{
121 const struct pldm_bios_string_table_entry *entry = table_entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930122 size_t len = sizeof(*entry) - sizeof(entry->name) +
123 pldm_bios_table_string_entry_decode_string_length(entry);
124 if (len > SSIZE_MAX) {
125 return -1;
126 }
127 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930128}
129
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930130static int get_bios_attr_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930131{
132 static uint16_t handle = 0;
133 assert(handle != UINT16_MAX);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930134 if (handle == UINT16_MAX) {
135 return PLDM_ERROR_INVALID_DATA;
136 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930137
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930138 *val = handle++;
139 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930140}
141
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930142static int attr_table_entry_encode_header(void *entry, size_t length,
143 uint8_t attr_type,
144 uint16_t string_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930145{
146 struct pldm_bios_attr_table_entry *attr_entry = entry;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930147
Andrew Jeffery9c766792022-08-10 23:12:49 +0930148 assert(sizeof(*attr_entry) <= length);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930149 if (sizeof(*attr_entry) > length) {
150 return PLDM_ERROR_INVALID_LENGTH;
151 }
152
153 uint16_t handle;
154 int rc = get_bios_attr_handle(&handle);
155 if (rc != PLDM_SUCCESS) {
156 return rc;
157 }
158
159 attr_entry->attr_handle = htole16(handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930160 attr_entry->attr_type = attr_type;
161 attr_entry->string_handle = htole16(string_handle);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930162
163 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930164}
165
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930166LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930167uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930168 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930169{
170 return le16toh(entry->attr_handle);
171}
172
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930173LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930174uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930175 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930176{
177 return entry->attr_type;
178}
179
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930180LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930181uint16_t pldm_bios_table_attr_entry_decode_string_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930182 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930183{
184 return le16toh(entry->string_handle);
185}
186
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930187LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930188size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
189 uint8_t def_num)
190{
191 return sizeof(struct pldm_bios_attr_table_entry) -
192 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
193 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
194 def_num;
195}
196
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930197LIBPLDM_ABI_STABLE
198int pldm_bios_table_attr_entry_enum_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930199 void *entry, size_t entry_length,
200 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930201{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930202 POINTER_CHECK(entry);
203 POINTER_CHECK(info);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930204 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930205 info->pv_num, info->def_num);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930206 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930207 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
208 PLDM_BIOS_ENUMERATION;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930209 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
210 info->name_handle);
211 if (rc != PLDM_SUCCESS) {
212 return rc;
213 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930214 struct pldm_bios_attr_table_entry *attr_entry = entry;
215 attr_entry->metadata[0] = info->pv_num;
216 uint16_t *pv_hdls =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930217 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930218 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930219 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930220 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930221 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930222 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930223 info->def_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930224 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930225 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930226 info->def_index, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930227 return PLDM_SUCCESS;
228}
229
230#define ATTR_TYPE_EXPECT(type, expected) \
231 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930232 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930233 return PLDM_ERROR_INVALID_DATA; \
234 } while (0)
235
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930236LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930237int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930238 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930239{
240 POINTER_CHECK(entry);
241 POINTER_CHECK(pv_num);
242 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930243 *pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930244 return PLDM_SUCCESS;
245}
246
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930247static uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930248 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930249{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930250 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930251 return entry->metadata[sizeof(uint8_t) /* pv_num */ +
252 sizeof(uint16_t) * pv_num];
253}
254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930255LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930256int pldm_bios_table_attr_entry_enum_decode_def_num_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930257 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930258{
259 POINTER_CHECK(entry);
260 POINTER_CHECK(def_num);
261 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
262 *def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
263 return PLDM_SUCCESS;
264}
265
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930266LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930267int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930268 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
269 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930270{
271 POINTER_CHECK(entry);
272 POINTER_CHECK(pv_hdls);
273 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930274 uint8_t num = entry->metadata[0];
275 num = num < pv_num ? num : pv_num;
276 size_t i;
277 for (i = 0; i < num; i++) {
278 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
279 i * sizeof(uint16_t));
280 pv_hdls[i] = le16toh(*hdl);
281 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930282 return PLDM_SUCCESS;
283}
284
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930285LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930286uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930287 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
288 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930289{
290 uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
291 num = num < def_num ? num : def_num;
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930292 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930293 const uint8_t *p = entry->metadata +
294 sizeof(uint8_t) /* number of possible values*/
295 + pv_num * sizeof(uint16_t) /* possible values */
296 + sizeof(uint8_t); /* number of default values */
297 memcpy(def_indices, p, num);
298 return num;
299}
300
301/** @brief Get length of an enum attribute entry
302 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930303static ssize_t attr_table_entry_length_enum(const void *arg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930304{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930305 const struct pldm_bios_attr_table_entry *entry = arg;
306 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930307 uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930308 size_t len =
309 pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
310 if (len > SSIZE_MAX) {
311 return -1;
312 }
313 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930314}
315
316struct attr_table_string_entry_fields {
317 uint8_t string_type;
318 uint16_t min_length;
319 uint16_t max_length;
320 uint16_t def_length;
321 uint8_t def_string[1];
322} __attribute__((packed));
323
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930324LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930325size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
326{
327 return sizeof(struct pldm_bios_attr_table_entry) -
328 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
329 sizeof(struct attr_table_string_entry_fields) -
330 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
331 def_str_len;
332}
333
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930334#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930335#define PLDM_STRING_TYPE_VENDOR 0xff
336
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930337LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930338int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930339 const struct pldm_bios_table_attr_entry_string_info *info,
340 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930341{
342 if (info->min_length > info->max_length) {
343 set_errmsg(errmsg, "MinimumStingLength should not be greater "
344 "than MaximumStringLength");
345 return PLDM_ERROR_INVALID_DATA;
346 }
347 if (info->min_length == info->max_length &&
348 info->def_length != info->min_length) {
349 set_errmsg(errmsg, "Wrong DefaultStringLength");
350 return PLDM_ERROR_INVALID_DATA;
351 }
352 if (info->def_length > info->max_length ||
353 info->def_length < info->min_length) {
354 set_errmsg(errmsg, "Wrong DefaultStringLength");
355 return PLDM_ERROR_INVALID_DATA;
356 }
357 if (info->string_type > PLDM_STRING_TYPE_MAX &&
358 info->string_type != PLDM_STRING_TYPE_VENDOR) {
359 set_errmsg(errmsg, "Wrong StringType");
360 return PLDM_ERROR_INVALID_DATA;
361 }
Andrew Jefferydf02e362023-06-14 14:52:25 +0930362 if (info->def_string && info->def_length != strlen(info->def_string)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930363 set_errmsg(errmsg, "Length of DefaultString should be equal to "
364 "DefaultStringLength");
365 return PLDM_ERROR_INVALID_DATA;
366 }
367
368 return PLDM_SUCCESS;
369}
370
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930371LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372int pldm_bios_table_attr_entry_string_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930373 void *entry, size_t entry_length,
374 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930375{
376 POINTER_CHECK(entry);
377 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930378 size_t length = pldm_bios_table_attr_entry_string_encode_length(
379 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380 BUFFER_SIZE_EXPECT(entry_length, length);
381 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930382 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930383 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930384 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930385 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
386 PLDM_BIOS_STRING;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930387 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
388 info->name_handle);
389 if (rc != PLDM_SUCCESS) {
390 return rc;
391 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930392 struct pldm_bios_attr_table_entry *attr_entry = entry;
393 struct attr_table_string_entry_fields *attr_fields =
394 (struct attr_table_string_entry_fields *)attr_entry->metadata;
395 attr_fields->string_type = info->string_type;
396 attr_fields->min_length = htole16(info->min_length);
397 attr_fields->max_length = htole16(info->max_length);
398 attr_fields->def_length = htole16(info->def_length);
399 if (info->def_length != 0 && info->def_string != NULL) {
400 memcpy(attr_fields->def_string, info->def_string,
401 info->def_length);
402 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930403 return PLDM_SUCCESS;
404}
405
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930406static uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930407 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930408{
409 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930410 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930411 return le16toh(fields->def_length);
412}
413
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930414LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930415int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930416 const struct pldm_bios_attr_table_entry *entry,
417 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930418{
419 POINTER_CHECK(entry);
420 POINTER_CHECK(def_string_length);
421 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
422 *def_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930423 pldm_bios_table_attr_entry_string_decode_def_string_length(
424 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930425 return PLDM_SUCCESS;
426}
427
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930428LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930429uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930430 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930431{
432 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930433 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930434 return fields->string_type;
435}
436
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930437LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930438uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930439 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930440{
441 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930442 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930443 return le16toh(fields->max_length);
444}
445
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930446LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930447uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930448 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930449{
450 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930451 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930452 return le16toh(fields->min_length);
453}
454
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930455LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930456uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930457 const struct pldm_bios_attr_table_entry *entry, char *buffer,
458 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459{
460 uint16_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930461 pldm_bios_table_attr_entry_string_decode_def_string_length(
462 entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930463 length = length < (size - 1) ? length : (size - 1);
464 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930465 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930466 memcpy(buffer, fields->def_string, length);
467 buffer[length] = 0;
468 return length;
469}
470
471/** @brief Get length of a string attribute entry
472 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930473static ssize_t attr_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474{
475 uint16_t def_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930476 pldm_bios_table_attr_entry_string_decode_def_string_length(
477 entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930478 size_t len =
479 pldm_bios_table_attr_entry_string_encode_length(def_str_len);
480 if (len > SSIZE_MAX) {
481 return -1;
482 }
483 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930484}
485
486struct attr_table_integer_entry_fields {
487 uint64_t lower_bound;
488 uint64_t upper_bound;
489 uint32_t scalar_increment;
490 uint64_t default_value;
491} __attribute__((packed));
492
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930493LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930494size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930495{
496 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
497 sizeof(struct attr_table_integer_entry_fields);
498}
499
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930500LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930501int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930502 const struct pldm_bios_table_attr_entry_integer_info *info,
503 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930504{
505 if (info->lower_bound == info->upper_bound) {
506 if (info->default_value != info->lower_bound) {
507 set_errmsg(errmsg, "Wrong DefaultValue");
508 return PLDM_ERROR_INVALID_DATA;
509 }
510 if (info->scalar_increment != 0) {
511 set_errmsg(errmsg, "Wrong ScalarIncrement");
512 return PLDM_ERROR_INVALID_DATA;
513 }
514 return PLDM_SUCCESS;
515 }
516 if (info->lower_bound > info->upper_bound) {
517 set_errmsg(errmsg,
518 "LowerBound should not be greater than UpperBound");
519 return PLDM_ERROR_INVALID_DATA;
520 }
521 if (info->default_value > info->upper_bound ||
522 info->default_value < info->lower_bound) {
523 set_errmsg(errmsg, "Wrong DefaultValue");
524 return PLDM_ERROR_INVALID_DATA;
525 }
526 if (info->scalar_increment == 0) {
527 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
528 "lower_bound != upper_bound");
529 return PLDM_ERROR_INVALID_DATA;
530 }
531 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930532 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930533 0) {
534 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
535 return PLDM_ERROR_INVALID_DATA;
536 }
537 return PLDM_SUCCESS;
538}
539
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930540LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930541int pldm_bios_table_attr_entry_integer_encode_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930542 void *entry, size_t entry_length,
543 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930544{
545 POINTER_CHECK(entry);
546 POINTER_CHECK(info);
547 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
548 BUFFER_SIZE_EXPECT(entry_length, length);
549 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930550 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930551 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930552 }
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930553 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
554 PLDM_BIOS_INTEGER;
555 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
556 info->name_handle);
557 if (rc != PLDM_SUCCESS) {
558 return rc;
559 }
560 struct pldm_bios_attr_table_entry *attr_entry = entry;
561 struct attr_table_integer_entry_fields *attr_fields =
562 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
563 attr_fields->lower_bound = htole64(info->lower_bound);
564 attr_fields->upper_bound = htole64(info->upper_bound);
565 attr_fields->scalar_increment = htole32(info->scalar_increment);
566 attr_fields->default_value = htole64(info->default_value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930567 return PLDM_SUCCESS;
568}
569
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930570LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930572 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
573 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930574{
575 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930576 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930577 *lower = le64toh(fields->lower_bound);
578 *upper = le64toh(fields->upper_bound);
579 *scalar = le32toh(fields->scalar_increment);
580 *def = le64toh(fields->default_value);
581}
582
Andrew Jeffery73d91762023-06-28 12:19:19 +0930583static ssize_t attr_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930584{
585 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930586 size_t len = pldm_bios_table_attr_entry_integer_encode_length();
587 if (len > SSIZE_MAX) {
588 return -1;
589 }
590 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930591}
592
593struct table_entry_length {
594 uint8_t attr_type;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930595 ssize_t (*entry_length_handler)(const void *);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930596};
597
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930598static const struct table_entry_length *
599find_table_entry_length_by_type(uint8_t attr_type,
600 const struct table_entry_length *handlers,
601 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930602{
603 size_t i;
604 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930605 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930607 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930608 }
609 return NULL;
610}
611
612static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930613 { .attr_type = PLDM_BIOS_ENUMERATION,
614 .entry_length_handler = attr_table_entry_length_enum },
615 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
616 .entry_length_handler = attr_table_entry_length_enum },
617 { .attr_type = PLDM_BIOS_STRING,
618 .entry_length_handler = attr_table_entry_length_string },
619 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
620 .entry_length_handler = attr_table_entry_length_string },
621 { .attr_type = PLDM_BIOS_INTEGER,
622 .entry_length_handler = attr_table_entry_length_integer },
623 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
624 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930625};
626
Andrew Jeffery73d91762023-06-28 12:19:19 +0930627static ssize_t attr_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930628{
629 const struct pldm_bios_attr_table_entry *entry = table_entry;
630 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930631 find_table_entry_length_by_type(entry->attr_type,
632 attr_table_entries,
633 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930634 assert(attr_table_entry != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930635 if (!attr_table_entry) {
636 return -1;
637 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930638 assert(attr_table_entry->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930639 if (!attr_table_entry->entry_length_handler) {
640 return -1;
641 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930642
643 return attr_table_entry->entry_length_handler(entry);
644}
645
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930646LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930647uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930648 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930649{
650 return le16toh(entry->attr_handle);
651}
652
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930653LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930654uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930655 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930656{
657 return entry->attr_type;
658}
659
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930660LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930661size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
662{
663 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
664 sizeof(count) + count;
665}
666
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930667LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930668uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930669 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930670{
671 return entry->value[0];
672}
673
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930674LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930675uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930676 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
677 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930678{
679 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930680 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Archana Kakanib9d951f2023-10-17 05:47:58 -0500681 curr_num = number < curr_num ? number : curr_num;
682 memcpy(handles, &entry->value[1], curr_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930683
Archana Kakanib9d951f2023-10-17 05:47:58 -0500684 return curr_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685}
686
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930687LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688int pldm_bios_table_attr_value_entry_encode_enum_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930689 void *entry, size_t entry_length, uint16_t attr_handle,
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930690 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930691{
692 POINTER_CHECK(entry);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930693 POINTER_CHECK(handles);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930694 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930696 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930697 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
698 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930699 pldm_bios_table_attr_value_entry_encode_enum_length(count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930700 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930701 struct pldm_bios_attr_val_table_entry *table_entry = entry;
702 table_entry->attr_handle = htole16(attr_handle);
703 table_entry->attr_type = attr_type;
704 table_entry->value[0] = count;
705 if (count != 0) {
706 memcpy(&table_entry->value[1], handles, count);
707 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930708 return PLDM_SUCCESS;
709}
710
Andrew Jeffery73d91762023-06-28 12:19:19 +0930711static ssize_t attr_value_table_entry_length_enum(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930712{
713 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930714 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930715 size_t len =
716 pldm_bios_table_attr_value_entry_encode_enum_length(number);
717 if (len > SSIZE_MAX) {
718 return -1;
719 }
720 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930721}
722
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930723LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930724size_t
725pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
726{
727 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
728 sizeof(string_length) + string_length;
729}
730
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930731LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930732uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930733 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930734{
735 uint16_t str_length = 0;
736 memcpy(&str_length, entry->value, sizeof(str_length));
737 return le16toh(str_length);
738}
739
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930740LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930741void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930742 const struct pldm_bios_attr_val_table_entry *entry,
743 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930744{
745 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930746 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930747 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930748 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930749}
750
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930751LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930752int pldm_bios_table_attr_value_entry_encode_string_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930753 void *entry, size_t entry_length, uint16_t attr_handle,
754 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755{
756 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930757 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930759 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930761 size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
762 str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930763 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery2d663932023-06-27 14:19:15 +0930764 struct pldm_bios_attr_val_table_entry *table_entry = entry;
765 table_entry->attr_handle = htole16(attr_handle);
766 table_entry->attr_type = attr_type;
767 if (str_length != 0) {
768 memcpy(table_entry->value + sizeof(str_length), str,
769 str_length);
770 }
771 str_length = htole16(str_length);
772 memcpy(table_entry->value, &str_length, sizeof(str_length));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930773 return PLDM_SUCCESS;
774}
775
Andrew Jeffery73d91762023-06-28 12:19:19 +0930776static ssize_t attr_value_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930777{
778 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930779 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930780 size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930781 str_length);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930782 if (len > SSIZE_MAX) {
783 return -1;
784 }
785 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930786}
787
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930788LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930789size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930790{
791 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
792 sizeof(uint64_t);
793}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930794
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930795LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930796int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
797 size_t entry_length,
798 uint16_t attr_handle,
799 uint8_t attr_type,
800 uint64_t cv)
801{
802 POINTER_CHECK(entry);
803 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930804 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930805 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
806 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery0088a6a2023-06-27 15:06:45 +0930807 struct pldm_bios_attr_val_table_entry *table_entry = entry;
808 table_entry->attr_handle = htole16(attr_handle);
809 table_entry->attr_type = attr_type;
810 cv = htole64(cv);
811 memcpy(table_entry->value, &cv, sizeof(uint64_t));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930812 return PLDM_SUCCESS;
813}
814
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930815LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930816uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930817 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930818{
819 uint64_t cv = 0;
820 memcpy(&cv, entry->value, sizeof(cv));
821 cv = le64toh(cv);
822 return cv;
823}
824
Andrew Jeffery73d91762023-06-28 12:19:19 +0930825static ssize_t attr_value_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930826{
827 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930828 size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
829 if (len > SSIZE_MAX) {
830 return -1;
831 }
832 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930833}
834
835static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930836 { .attr_type = PLDM_BIOS_ENUMERATION,
837 .entry_length_handler = attr_value_table_entry_length_enum },
838 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
839 .entry_length_handler = attr_value_table_entry_length_enum },
840 { .attr_type = PLDM_BIOS_STRING,
841 .entry_length_handler = attr_value_table_entry_length_string },
842 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
843 .entry_length_handler = attr_value_table_entry_length_string },
844 { .attr_type = PLDM_BIOS_INTEGER,
845 .entry_length_handler = attr_value_table_entry_length_integer },
846 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
847 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930848};
849
Andrew Jeffery73d91762023-06-28 12:19:19 +0930850static ssize_t attr_value_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930851{
852 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
853 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930854 find_table_entry_length_by_type(
855 entry->attr_type, attr_value_table_entries,
856 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930857 assert(entry_length != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930858 if (!entry_length) {
859 return -1;
860 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930861 assert(entry_length->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930862 if (!entry_length->entry_length_handler) {
863 return -1;
864 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930865
866 return entry_length->entry_length_handler(entry);
867}
868
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930869LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930871 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930872{
873 return attr_value_table_entry_length(entry);
874}
875
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930876LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930877uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930878 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930879{
880 return le16toh(entry->attr_handle);
881}
882
883static size_t pad_size_get(size_t size_without_pad)
884{
885 return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
886}
887
888static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
889{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930890 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930892 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930893
894 return table_end;
895}
896
897static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
898{
899 checksum = htole32(checksum);
900 memcpy(table_end, &checksum, sizeof(checksum));
901
902 return table_end + sizeof(checksum);
903}
904
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930905LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930906size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
907{
908 size_t size = pad_size_get(size_without_pad) +
909 sizeof(uint32_t) /*sizeof(checksum)*/;
910 return size;
911}
912
Andrew Jeffery1264fbd2023-07-07 09:44:07 +0930913LIBPLDM_ABI_STABLE
Andrew Jeffery044ee192023-06-28 11:26:00 +0930914int pldm_bios_table_append_pad_checksum_check(void *table, size_t capacity,
915 size_t *size)
916{
917 if (!table || !size) {
918 return PLDM_ERROR_INVALID_DATA;
919 }
920
921 size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
922 size_t total_length = *size + pad_checksum_size;
Andrew Jeffery044ee192023-06-28 11:26:00 +0930923 if (capacity < total_length) {
924 return PLDM_ERROR_INVALID_LENGTH;
925 }
926
927 uint8_t *table_end = (uint8_t *)table + *size;
928 size_t pad_size = pad_size_get(*size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930929 table_end = pad_append(table_end, pad_size);
930
Andrew Jeffery044ee192023-06-28 11:26:00 +0930931 uint32_t checksum = crc32(table, *size + pad_size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930932 checksum_append(table_end, checksum);
Andrew Jeffery044ee192023-06-28 11:26:00 +0930933 *size = total_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934
Andrew Jeffery044ee192023-06-28 11:26:00 +0930935 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930936}
937
938struct pldm_bios_table_iter {
939 const uint8_t *table_data;
940 size_t table_len;
941 size_t current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930942 ssize_t (*entry_length_handler)(const void *table_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943};
944
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930945LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946struct pldm_bios_table_iter *
947pldm_bios_table_iter_create(const void *table, size_t length,
948 enum pldm_bios_table_types type)
949{
950 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
951 assert(iter != NULL);
Andrew Jeffery757e81a2023-06-28 12:15:59 +0930952 if (!iter) {
953 return NULL;
954 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955 iter->table_data = table;
956 iter->table_len = length;
957 iter->current_pos = 0;
958 iter->entry_length_handler = NULL;
959 switch (type) {
960 case PLDM_BIOS_STRING_TABLE:
961 iter->entry_length_handler = string_table_entry_length;
962 break;
963 case PLDM_BIOS_ATTR_TABLE:
964 iter->entry_length_handler = attr_table_entry_length;
965 break;
966 case PLDM_BIOS_ATTR_VAL_TABLE:
967 iter->entry_length_handler = attr_value_table_entry_length;
968 break;
969 }
970
971 return iter;
972}
973
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930974LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930975void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
976{
977 free(iter);
978}
979
980#define pad_and_check_max 7
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930981LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930982bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
983{
Andrew Jeffery73d91762023-06-28 12:19:19 +0930984 ssize_t len;
985
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930986 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930987 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930988 }
Andrew Jeffery73d91762023-06-28 12:19:19 +0930989
990 len = iter->entry_length_handler(iter->table_data + iter->current_pos);
991
992 return len < 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930993}
994
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930995LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930996void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
997{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930998 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930999 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301000 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001 const void *entry = iter->table_data + iter->current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +09301002 ssize_t rc = iter->entry_length_handler(entry);
1003 /* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1004 if (rc < 0) {
1005 return;
1006 }
1007 iter->current_pos += rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301008}
1009
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301010LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301011const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1012{
1013 return iter->table_data + iter->current_pos;
1014}
1015
1016typedef bool (*equal_handler)(const void *entry, const void *key);
1017
1018static const void *
1019pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1020 const void *key, equal_handler equal)
1021{
1022 const void *entry;
1023 while (!pldm_bios_table_iter_is_end(iter)) {
1024 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301025 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301026 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301027 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301028 pldm_bios_table_iter_next(iter);
1029 }
1030 return NULL;
1031}
1032
1033static const void *
1034pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1035 enum pldm_bios_table_types type,
1036 equal_handler equal, const void *key)
1037{
1038 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301039 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301040 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301041 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301042 pldm_bios_table_iter_free(iter);
1043 return entry;
1044}
1045
1046static bool string_table_handle_equal(const void *entry, const void *key)
1047{
1048 const struct pldm_bios_string_table_entry *string_entry = entry;
1049 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301050 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1051 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301052 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301053 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301054 return false;
1055}
1056
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301057LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301058const struct pldm_bios_string_table_entry *
1059pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1060 uint16_t handle)
1061{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301062 return pldm_bios_table_entry_find_from_table(table, length,
1063 PLDM_BIOS_STRING_TABLE,
1064 string_table_handle_equal,
1065 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301066}
1067
1068struct string_equal_arg {
1069 uint16_t str_length;
1070 const char *str;
1071};
1072
1073static bool string_table_string_equal(const void *entry, const void *key)
1074{
1075 const struct pldm_bios_string_table_entry *string_entry = entry;
1076 const struct string_equal_arg *arg = key;
1077 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301078 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301079 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301080 }
1081 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301082 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301083 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301084 return true;
1085}
1086
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301087LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301088const struct pldm_bios_string_table_entry *
1089pldm_bios_table_string_find_by_string(const void *table, size_t length,
1090 const char *str)
1091{
1092 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301093 struct string_equal_arg arg = { str_length, str };
1094 return pldm_bios_table_entry_find_from_table(table, length,
1095 PLDM_BIOS_STRING_TABLE,
1096 string_table_string_equal,
1097 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301098}
1099
1100static bool attr_table_handle_equal(const void *entry, const void *key)
1101{
1102 uint16_t handle = *(uint16_t *)key;
1103 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1104 handle;
1105}
1106
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301107LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301108const struct pldm_bios_attr_table_entry *
1109pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1110 uint16_t handle)
1111{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301112 return pldm_bios_table_entry_find_from_table(table, length,
1113 PLDM_BIOS_ATTR_TABLE,
1114 attr_table_handle_equal,
1115 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301116}
1117
1118static bool attr_table_string_handle_equal(const void *entry, const void *key)
1119{
1120 uint16_t handle = *(uint16_t *)key;
1121 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1122}
1123
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301124LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301125const struct pldm_bios_attr_table_entry *
1126pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1127 uint16_t handle)
1128{
1129 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301130 table, length, PLDM_BIOS_ATTR_TABLE,
1131 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301132}
1133
1134static bool attr_value_table_handle_equal(const void *entry, const void *key)
1135{
1136 uint16_t handle = *(uint16_t *)key;
1137 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1138}
1139
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301140LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301141const struct pldm_bios_attr_val_table_entry *
1142pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1143 uint16_t handle)
1144{
1145 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301146 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1147 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301148}
1149
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301150LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301151int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301152 const void *src_table, size_t src_length, void *dest_table,
1153 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301154{
1155 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301156 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301157
1158 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301159 const struct pldm_bios_attr_val_table_entry *tmp;
1160 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1161 size_t buffer_length = *dest_length;
1162 size_t copied_length = 0;
1163 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301164 while (!pldm_bios_table_iter_is_end(iter)) {
1165 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1166 length = attr_value_table_entry_length(tmp);
1167
1168 /* we need the tmp's entry_length here, iter_next will calculate
1169 * it too, use current_pos directly to avoid calculating it
1170 * twice */
1171 iter->current_pos += length;
1172 if (tmp->attr_handle == to_update->attr_handle) {
1173 if (tmp->attr_type != to_update->attr_type) {
1174 rc = PLDM_ERROR_INVALID_DATA;
1175 goto out;
1176 }
1177 length = entry_length;
1178 tmp = entry;
1179 }
1180 if (copied_length + length > buffer_length) {
1181 rc = PLDM_ERROR_INVALID_LENGTH;
1182 goto out;
1183 }
1184 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1185 copied_length += length;
1186 }
1187
1188 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301189 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301190 if ((pad_checksum_size + copied_length) > buffer_length) {
1191 rc = PLDM_ERROR_INVALID_LENGTH;
1192 goto out;
1193 }
1194
Andrew Jeffery50dd1592023-07-14 16:02:05 +09301195 rc = pldm_bios_table_append_pad_checksum_check(
1196 dest_table, buffer_length, &copied_length);
1197 if (rc == PLDM_SUCCESS) {
1198 *dest_length = copied_length;
1199 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301200out:
1201 pldm_bios_table_iter_free(iter);
1202 return rc;
1203}
1204
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301205LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301206bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1207{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301208 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301209 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301210 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301211
1212 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1213 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301214 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301215 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301216 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301217
1218 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1219 uint32_t dst_crc = crc32(table, size - 4);
1220
1221 return src_crc == dst_crc;
1222}