blob: a4280feceaeea5286ef6f0dc7605d5cb43acc492 [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
Andrew Jeffery7126b1d2024-06-25 15:48:34 +0930197int pldm_bios_table_attr_entry_enum_encode(
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 Jefferyb06882f2024-06-25 15:52:02 +0930236int pldm_bios_table_attr_entry_enum_decode_pv_num(
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 Jeffery9d2a1c62023-06-05 13:02:16 +0930246LIBPLDM_ABI_STABLE
Andrew Jeffery46673f42024-06-25 16:02:25 +0930247int 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, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930249{
Andrew Jeffery46673f42024-06-25 16:02:25 +0930250 uint8_t pv_num;
251
Andrew Jeffery9c766792022-08-10 23:12:49 +0930252 POINTER_CHECK(entry);
253 POINTER_CHECK(def_num);
254 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery46673f42024-06-25 16:02:25 +0930255 pv_num = entry->metadata[0];
256 *def_num = entry->metadata[sizeof(uint8_t) + sizeof(uint16_t) * pv_num];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930257 return PLDM_SUCCESS;
258}
259
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930260LIBPLDM_ABI_STABLE
Andrew Jeffery82b4d3b2024-06-25 16:22:36 +0930261int pldm_bios_table_attr_entry_enum_decode_pv_hdls(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930262 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
263 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930264{
265 POINTER_CHECK(entry);
266 POINTER_CHECK(pv_hdls);
267 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930268 uint8_t num = entry->metadata[0];
269 num = num < pv_num ? num : pv_num;
270 size_t i;
271 for (i = 0; i < num; i++) {
272 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
273 i * sizeof(uint16_t));
274 pv_hdls[i] = le16toh(*hdl);
275 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930276 return PLDM_SUCCESS;
277}
278
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930279LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930280uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930281 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
282 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283{
Andrew Jeffery46673f42024-06-25 16:02:25 +0930284 uint8_t num = 0;
285
286 /* TODO: Fix the API to propagate errors */
287 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930288 num = num < def_num ? num : def_num;
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930289 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930290 const uint8_t *p = entry->metadata +
291 sizeof(uint8_t) /* number of possible values*/
292 + pv_num * sizeof(uint16_t) /* possible values */
293 + sizeof(uint8_t); /* number of default values */
294 memcpy(def_indices, p, num);
295 return num;
296}
297
298/** @brief Get length of an enum attribute entry
299 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930300static ssize_t attr_table_entry_length_enum(const void *arg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930301{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930302 const struct pldm_bios_attr_table_entry *entry = arg;
303 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery46673f42024-06-25 16:02:25 +0930304 uint8_t def_num = 0;
305
306 /* TODO: Fix the API to propagate errors */
307 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &def_num);
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 Jefferyf6be4932024-06-25 16:44:06 +0930372int pldm_bios_table_attr_entry_string_encode(
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 Jeffery9d2a1c62023-06-05 13:02:16 +0930406LIBPLDM_ABI_STABLE
Andrew Jefferyc668ffc2024-06-25 16:50:08 +0930407int pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930408 const struct pldm_bios_attr_table_entry *entry,
409 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930410{
411 POINTER_CHECK(entry);
412 POINTER_CHECK(def_string_length);
413 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
Andrew Jefferyc668ffc2024-06-25 16:50:08 +0930414 struct attr_table_string_entry_fields *fields =
415 (struct attr_table_string_entry_fields *)entry->metadata;
416 *def_string_length = le16toh(fields->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930417 return PLDM_SUCCESS;
418}
419
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930420LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930421uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930422 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930423{
424 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930425 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930426 return fields->string_type;
427}
428
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930429LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930430uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930431 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930432{
433 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930434 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930435 return le16toh(fields->max_length);
436}
437
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930438LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930439uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930440 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930441{
442 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930443 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930444 return le16toh(fields->min_length);
445}
446
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930447LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930448uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930449 const struct pldm_bios_attr_table_entry *entry, char *buffer,
450 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930451{
Andrew Jefferyc668ffc2024-06-25 16:50:08 +0930452 uint16_t length = 0;
453 int rc;
454
455 if (!entry || !buffer || size == 0) {
456 return 0;
457 }
458
459 /* TODO: Rework the API to propagate the error */
460 rc = pldm_bios_table_attr_entry_string_decode_def_string_length(
461 entry, &length);
462 if (rc != PLDM_SUCCESS) {
463 return 0;
464 }
465
Andrew Jeffery9c766792022-08-10 23:12:49 +0930466 length = length < (size - 1) ? length : (size - 1);
467 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930468 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930469 memcpy(buffer, fields->def_string, length);
470 buffer[length] = 0;
471 return length;
472}
473
474/** @brief Get length of a string attribute entry
475 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930476static ssize_t attr_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930477{
Andrew Jefferyc668ffc2024-06-25 16:50:08 +0930478 uint16_t def_str_len = 0;
479
480 /* TODO: Rework the API to propagate the error */
481 pldm_bios_table_attr_entry_string_decode_def_string_length(
482 entry, &def_str_len);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930483 size_t len =
484 pldm_bios_table_attr_entry_string_encode_length(def_str_len);
485 if (len > SSIZE_MAX) {
486 return -1;
487 }
488 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930489}
490
491struct attr_table_integer_entry_fields {
492 uint64_t lower_bound;
493 uint64_t upper_bound;
494 uint32_t scalar_increment;
495 uint64_t default_value;
496} __attribute__((packed));
497
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930498LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930499size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930500{
501 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
502 sizeof(struct attr_table_integer_entry_fields);
503}
504
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930505LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930506int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930507 const struct pldm_bios_table_attr_entry_integer_info *info,
508 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930509{
510 if (info->lower_bound == info->upper_bound) {
511 if (info->default_value != info->lower_bound) {
512 set_errmsg(errmsg, "Wrong DefaultValue");
513 return PLDM_ERROR_INVALID_DATA;
514 }
515 if (info->scalar_increment != 0) {
516 set_errmsg(errmsg, "Wrong ScalarIncrement");
517 return PLDM_ERROR_INVALID_DATA;
518 }
519 return PLDM_SUCCESS;
520 }
521 if (info->lower_bound > info->upper_bound) {
522 set_errmsg(errmsg,
523 "LowerBound should not be greater than UpperBound");
524 return PLDM_ERROR_INVALID_DATA;
525 }
526 if (info->default_value > info->upper_bound ||
527 info->default_value < info->lower_bound) {
528 set_errmsg(errmsg, "Wrong DefaultValue");
529 return PLDM_ERROR_INVALID_DATA;
530 }
531 if (info->scalar_increment == 0) {
532 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
533 "lower_bound != upper_bound");
534 return PLDM_ERROR_INVALID_DATA;
535 }
536 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930537 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930538 0) {
539 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
540 return PLDM_ERROR_INVALID_DATA;
541 }
542 return PLDM_SUCCESS;
543}
544
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930545LIBPLDM_ABI_STABLE
Andrew Jeffery5347e272024-06-29 22:05:36 +0930546int pldm_bios_table_attr_entry_integer_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930547 void *entry, size_t entry_length,
548 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930549{
550 POINTER_CHECK(entry);
551 POINTER_CHECK(info);
552 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
553 BUFFER_SIZE_EXPECT(entry_length, length);
554 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930555 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930556 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930557 }
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930558 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
559 PLDM_BIOS_INTEGER;
560 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
561 info->name_handle);
562 if (rc != PLDM_SUCCESS) {
563 return rc;
564 }
565 struct pldm_bios_attr_table_entry *attr_entry = entry;
566 struct attr_table_integer_entry_fields *attr_fields =
567 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
568 attr_fields->lower_bound = htole64(info->lower_bound);
569 attr_fields->upper_bound = htole64(info->upper_bound);
570 attr_fields->scalar_increment = htole32(info->scalar_increment);
571 attr_fields->default_value = htole64(info->default_value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930572 return PLDM_SUCCESS;
573}
574
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930575LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930576void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930577 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
578 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930579{
580 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930581 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930582 *lower = le64toh(fields->lower_bound);
583 *upper = le64toh(fields->upper_bound);
584 *scalar = le32toh(fields->scalar_increment);
585 *def = le64toh(fields->default_value);
586}
587
Andrew Jeffery73d91762023-06-28 12:19:19 +0930588static ssize_t attr_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589{
590 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930591 size_t len = pldm_bios_table_attr_entry_integer_encode_length();
592 if (len > SSIZE_MAX) {
593 return -1;
594 }
595 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930596}
597
598struct table_entry_length {
599 uint8_t attr_type;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930600 ssize_t (*entry_length_handler)(const void *);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930601};
602
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930603static const struct table_entry_length *
604find_table_entry_length_by_type(uint8_t attr_type,
605 const struct table_entry_length *handlers,
606 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930607{
608 size_t i;
609 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930610 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930612 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930613 }
614 return NULL;
615}
616
617static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930618 { .attr_type = PLDM_BIOS_ENUMERATION,
619 .entry_length_handler = attr_table_entry_length_enum },
620 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
621 .entry_length_handler = attr_table_entry_length_enum },
622 { .attr_type = PLDM_BIOS_STRING,
623 .entry_length_handler = attr_table_entry_length_string },
624 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
625 .entry_length_handler = attr_table_entry_length_string },
626 { .attr_type = PLDM_BIOS_INTEGER,
627 .entry_length_handler = attr_table_entry_length_integer },
628 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
629 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930630};
631
Andrew Jeffery73d91762023-06-28 12:19:19 +0930632static ssize_t attr_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930633{
634 const struct pldm_bios_attr_table_entry *entry = table_entry;
635 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930636 find_table_entry_length_by_type(entry->attr_type,
637 attr_table_entries,
638 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930639 assert(attr_table_entry != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930640 if (!attr_table_entry) {
641 return -1;
642 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930643 assert(attr_table_entry->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930644 if (!attr_table_entry->entry_length_handler) {
645 return -1;
646 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930647
648 return attr_table_entry->entry_length_handler(entry);
649}
650
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930651LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930652uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930653 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930654{
655 return le16toh(entry->attr_handle);
656}
657
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930658LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930659uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930660 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930661{
662 return entry->attr_type;
663}
664
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930665LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
667{
668 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
669 sizeof(count) + count;
670}
671
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930672LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930673uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930674 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930675{
676 return entry->value[0];
677}
678
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930679LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930681 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
682 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930683{
684 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930685 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Archana Kakanib9d951f2023-10-17 05:47:58 -0500686 curr_num = number < curr_num ? number : curr_num;
687 memcpy(handles, &entry->value[1], curr_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688
Archana Kakanib9d951f2023-10-17 05:47:58 -0500689 return curr_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930690}
691
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930692LIBPLDM_ABI_STABLE
Andrew Jeffery09004d62024-06-29 22:12:15 +0930693int pldm_bios_table_attr_value_entry_encode_enum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930694 void *entry, size_t entry_length, uint16_t attr_handle,
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930695 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930696{
Andrew Jeffery92967be2024-10-02 22:13:57 +0930697 struct pldm_bios_attr_val_table_entry *table_entry;
698
Andrew Jeffery9c766792022-08-10 23:12:49 +0930699 POINTER_CHECK(entry);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930700 POINTER_CHECK(handles);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930701 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930702 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930703 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930704 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery92967be2024-10-02 22:13:57 +0930705 BUFFER_SIZE_EXPECT(entry_length, sizeof(*table_entry));
706 table_entry = entry;
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930707 table_entry->attr_handle = htole16(attr_handle);
708 table_entry->attr_type = attr_type;
709 table_entry->value[0] = count;
Andrew Jeffery92967be2024-10-02 22:13:57 +0930710 if (entry_length - sizeof(*table_entry) < count) {
711 return PLDM_ERROR_INVALID_LENGTH;
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930712 }
Andrew Jeffery92967be2024-10-02 22:13:57 +0930713 memcpy(&table_entry->value[1], handles, count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930714 return PLDM_SUCCESS;
715}
716
Andrew Jeffery73d91762023-06-28 12:19:19 +0930717static ssize_t attr_value_table_entry_length_enum(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930718{
719 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930720 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930721 size_t len =
722 pldm_bios_table_attr_value_entry_encode_enum_length(number);
723 if (len > SSIZE_MAX) {
724 return -1;
725 }
726 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727}
728
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930729LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930730size_t
731pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
732{
733 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
734 sizeof(string_length) + string_length;
735}
736
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930737LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930738uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930739 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930740{
741 uint16_t str_length = 0;
742 memcpy(&str_length, entry->value, sizeof(str_length));
743 return le16toh(str_length);
744}
745
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930746LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930747void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930748 const struct pldm_bios_attr_val_table_entry *entry,
749 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930750{
751 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930752 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930753 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930754 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755}
756
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930757LIBPLDM_ABI_STABLE
Andrew Jeffery1a3983c2024-06-29 22:17:58 +0930758int pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930759 void *entry, size_t entry_length, uint16_t attr_handle,
760 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930761{
Andrew Jefferyd96d21f2024-10-02 22:04:28 +0930762 struct pldm_bios_attr_val_table_entry *table_entry;
763
Andrew Jeffery9c766792022-08-10 23:12:49 +0930764 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930765 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930766 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930767 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930768 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jefferyd96d21f2024-10-02 22:04:28 +0930769 BUFFER_SIZE_EXPECT(entry_length,
770 (sizeof(*table_entry) - 1 + sizeof(str_length)));
771 table_entry = entry;
Andrew Jeffery2d663932023-06-27 14:19:15 +0930772 table_entry->attr_handle = htole16(attr_handle);
773 table_entry->attr_type = attr_type;
Andrew Jefferyd96d21f2024-10-02 22:04:28 +0930774 if (entry_length - (sizeof(*table_entry) - 1 + sizeof(str_length)) <
775 str_length) {
776 return PLDM_ERROR_INVALID_LENGTH;
Andrew Jeffery2d663932023-06-27 14:19:15 +0930777 }
Andrew Jefferyd96d21f2024-10-02 22:04:28 +0930778 memcpy(table_entry->value + sizeof(str_length), str, str_length);
Andrew Jeffery2d663932023-06-27 14:19:15 +0930779 str_length = htole16(str_length);
780 memcpy(table_entry->value, &str_length, sizeof(str_length));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930781 return PLDM_SUCCESS;
782}
783
Andrew Jeffery73d91762023-06-28 12:19:19 +0930784static ssize_t attr_value_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930785{
786 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930787 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930788 size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930789 str_length);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930790 if (len > SSIZE_MAX) {
791 return -1;
792 }
793 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930794}
795
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930796LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930797size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930798{
799 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
800 sizeof(uint64_t);
801}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930802
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930803LIBPLDM_ABI_STABLE
Andrew Jeffery504dd172024-06-29 22:23:15 +0930804int pldm_bios_table_attr_value_entry_encode_integer(void *entry,
805 size_t entry_length,
806 uint16_t attr_handle,
807 uint8_t attr_type,
808 uint64_t cv)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930809{
810 POINTER_CHECK(entry);
811 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930812 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930813 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
814 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery0088a6a2023-06-27 15:06:45 +0930815 struct pldm_bios_attr_val_table_entry *table_entry = entry;
816 table_entry->attr_handle = htole16(attr_handle);
817 table_entry->attr_type = attr_type;
818 cv = htole64(cv);
819 memcpy(table_entry->value, &cv, sizeof(uint64_t));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930820 return PLDM_SUCCESS;
821}
822
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930823LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930824uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930825 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930826{
827 uint64_t cv = 0;
828 memcpy(&cv, entry->value, sizeof(cv));
829 cv = le64toh(cv);
830 return cv;
831}
832
Andrew Jeffery73d91762023-06-28 12:19:19 +0930833static ssize_t attr_value_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930834{
835 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930836 size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
837 if (len > SSIZE_MAX) {
838 return -1;
839 }
840 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930841}
842
843static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930844 { .attr_type = PLDM_BIOS_ENUMERATION,
845 .entry_length_handler = attr_value_table_entry_length_enum },
846 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
847 .entry_length_handler = attr_value_table_entry_length_enum },
848 { .attr_type = PLDM_BIOS_STRING,
849 .entry_length_handler = attr_value_table_entry_length_string },
850 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
851 .entry_length_handler = attr_value_table_entry_length_string },
852 { .attr_type = PLDM_BIOS_INTEGER,
853 .entry_length_handler = attr_value_table_entry_length_integer },
854 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
855 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930856};
857
Andrew Jeffery73d91762023-06-28 12:19:19 +0930858static ssize_t attr_value_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930859{
860 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
861 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930862 find_table_entry_length_by_type(
863 entry->attr_type, attr_value_table_entries,
864 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930865 assert(entry_length != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930866 if (!entry_length) {
867 return -1;
868 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930869 assert(entry_length->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930870 if (!entry_length->entry_length_handler) {
871 return -1;
872 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930873
874 return entry_length->entry_length_handler(entry);
875}
876
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930877LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930878size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930879 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930880{
881 return attr_value_table_entry_length(entry);
882}
883
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930884LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930885uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930886 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930887{
888 return le16toh(entry->attr_handle);
889}
890
891static size_t pad_size_get(size_t size_without_pad)
892{
Andrew Jeffery72dd2dd2024-10-02 21:04:21 +0930893 return (4 - (size_without_pad % 4)) % 4;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894}
895
896static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
897{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930898 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930900 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930901
902 return table_end;
903}
904
905static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
906{
907 checksum = htole32(checksum);
908 memcpy(table_end, &checksum, sizeof(checksum));
909
910 return table_end + sizeof(checksum);
911}
912
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930913LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930914size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
915{
Andrew Jefferya16f70c2024-10-02 21:19:25 +0930916 return pad_size_get(size_without_pad) + sizeof(uint32_t);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930917}
918
Andrew Jeffery1264fbd2023-07-07 09:44:07 +0930919LIBPLDM_ABI_STABLE
Andrew Jefferyd8bb75c2024-06-29 22:29:02 +0930920int pldm_bios_table_append_pad_checksum(void *table, size_t capacity,
921 size_t *size)
Andrew Jeffery044ee192023-06-28 11:26:00 +0930922{
923 if (!table || !size) {
924 return PLDM_ERROR_INVALID_DATA;
925 }
926
927 size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
Andrew Jefferyd610b002024-10-02 21:27:30 +0930928
929 if (SIZE_MAX - pad_checksum_size < *size) {
930 return PLDM_ERROR_INVALID_LENGTH;
931 }
932
Andrew Jeffery044ee192023-06-28 11:26:00 +0930933 size_t total_length = *size + pad_checksum_size;
Andrew Jeffery044ee192023-06-28 11:26:00 +0930934 if (capacity < total_length) {
935 return PLDM_ERROR_INVALID_LENGTH;
936 }
937
Andrew Jefferyd610b002024-10-02 21:27:30 +0930938 if (UINTPTR_MAX - *size < (uintptr_t)table) {
939 return PLDM_ERROR_INVALID_LENGTH;
940 }
Andrew Jeffery044ee192023-06-28 11:26:00 +0930941 uint8_t *table_end = (uint8_t *)table + *size;
942 size_t pad_size = pad_size_get(*size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943 table_end = pad_append(table_end, pad_size);
944
Andrew Jeffery044ee192023-06-28 11:26:00 +0930945 uint32_t checksum = crc32(table, *size + pad_size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946 checksum_append(table_end, checksum);
Andrew Jeffery044ee192023-06-28 11:26:00 +0930947 *size = total_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948
Andrew Jeffery044ee192023-06-28 11:26:00 +0930949 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950}
951
952struct pldm_bios_table_iter {
953 const uint8_t *table_data;
954 size_t table_len;
955 size_t current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930956 ssize_t (*entry_length_handler)(const void *table_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930957};
958
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930959LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960struct pldm_bios_table_iter *
961pldm_bios_table_iter_create(const void *table, size_t length,
962 enum pldm_bios_table_types type)
963{
964 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
965 assert(iter != NULL);
Andrew Jeffery757e81a2023-06-28 12:15:59 +0930966 if (!iter) {
967 return NULL;
968 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930969 iter->table_data = table;
970 iter->table_len = length;
971 iter->current_pos = 0;
972 iter->entry_length_handler = NULL;
973 switch (type) {
974 case PLDM_BIOS_STRING_TABLE:
975 iter->entry_length_handler = string_table_entry_length;
976 break;
977 case PLDM_BIOS_ATTR_TABLE:
978 iter->entry_length_handler = attr_table_entry_length;
979 break;
980 case PLDM_BIOS_ATTR_VAL_TABLE:
981 iter->entry_length_handler = attr_value_table_entry_length;
982 break;
983 }
984
985 return iter;
986}
987
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930988LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930989void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
990{
991 free(iter);
992}
993
994#define pad_and_check_max 7
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930995LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930996bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
997{
Andrew Jeffery73d91762023-06-28 12:19:19 +0930998 ssize_t len;
999
Andrew Jeffery3b5ab922024-09-22 15:20:50 +09301000 if (!iter) {
1001 return true;
1002 }
1003
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301004 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301005 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301006 }
Andrew Jeffery73d91762023-06-28 12:19:19 +09301007
1008 len = iter->entry_length_handler(iter->table_data + iter->current_pos);
1009
1010 return len < 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301011}
1012
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301013LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301014void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
1015{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301016 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301017 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301018 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301019 const void *entry = iter->table_data + iter->current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +09301020 ssize_t rc = iter->entry_length_handler(entry);
1021 /* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1022 if (rc < 0) {
1023 return;
1024 }
1025 iter->current_pos += rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301026}
1027
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301028LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301029const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1030{
1031 return iter->table_data + iter->current_pos;
1032}
1033
1034typedef bool (*equal_handler)(const void *entry, const void *key);
1035
1036static const void *
1037pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1038 const void *key, equal_handler equal)
1039{
1040 const void *entry;
1041 while (!pldm_bios_table_iter_is_end(iter)) {
1042 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301043 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301044 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301045 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301046 pldm_bios_table_iter_next(iter);
1047 }
1048 return NULL;
1049}
1050
1051static const void *
1052pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1053 enum pldm_bios_table_types type,
1054 equal_handler equal, const void *key)
1055{
1056 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301057 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301058 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301059 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301060 pldm_bios_table_iter_free(iter);
1061 return entry;
1062}
1063
1064static bool string_table_handle_equal(const void *entry, const void *key)
1065{
1066 const struct pldm_bios_string_table_entry *string_entry = entry;
1067 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301068 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1069 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301070 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301071 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301072 return false;
1073}
1074
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301075LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301076const struct pldm_bios_string_table_entry *
1077pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1078 uint16_t handle)
1079{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301080 return pldm_bios_table_entry_find_from_table(table, length,
1081 PLDM_BIOS_STRING_TABLE,
1082 string_table_handle_equal,
1083 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301084}
1085
1086struct string_equal_arg {
1087 uint16_t str_length;
1088 const char *str;
1089};
1090
1091static bool string_table_string_equal(const void *entry, const void *key)
1092{
1093 const struct pldm_bios_string_table_entry *string_entry = entry;
1094 const struct string_equal_arg *arg = key;
1095 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301096 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301097 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301098 }
1099 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301100 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301101 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301102 return true;
1103}
1104
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301105LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106const struct pldm_bios_string_table_entry *
1107pldm_bios_table_string_find_by_string(const void *table, size_t length,
1108 const char *str)
1109{
1110 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301111 struct string_equal_arg arg = { str_length, str };
1112 return pldm_bios_table_entry_find_from_table(table, length,
1113 PLDM_BIOS_STRING_TABLE,
1114 string_table_string_equal,
1115 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301116}
1117
1118static bool attr_table_handle_equal(const void *entry, const void *key)
1119{
1120 uint16_t handle = *(uint16_t *)key;
1121 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1122 handle;
1123}
1124
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301125LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301126const struct pldm_bios_attr_table_entry *
1127pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1128 uint16_t handle)
1129{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301130 return pldm_bios_table_entry_find_from_table(table, length,
1131 PLDM_BIOS_ATTR_TABLE,
1132 attr_table_handle_equal,
1133 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301134}
1135
1136static bool attr_table_string_handle_equal(const void *entry, const void *key)
1137{
1138 uint16_t handle = *(uint16_t *)key;
1139 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1140}
1141
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301142LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301143const struct pldm_bios_attr_table_entry *
1144pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1145 uint16_t handle)
1146{
1147 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301148 table, length, PLDM_BIOS_ATTR_TABLE,
1149 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301150}
1151
1152static bool attr_value_table_handle_equal(const void *entry, const void *key)
1153{
1154 uint16_t handle = *(uint16_t *)key;
1155 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1156}
1157
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301158LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301159const struct pldm_bios_attr_val_table_entry *
1160pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1161 uint16_t handle)
1162{
1163 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301164 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1165 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301166}
1167
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301168LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301169int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301170 const void *src_table, size_t src_length, void *dest_table,
1171 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301172{
1173 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301174 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301175
1176 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301177 const struct pldm_bios_attr_val_table_entry *tmp;
1178 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1179 size_t buffer_length = *dest_length;
1180 size_t copied_length = 0;
1181 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301182 while (!pldm_bios_table_iter_is_end(iter)) {
1183 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1184 length = attr_value_table_entry_length(tmp);
1185
1186 /* we need the tmp's entry_length here, iter_next will calculate
1187 * it too, use current_pos directly to avoid calculating it
1188 * twice */
1189 iter->current_pos += length;
1190 if (tmp->attr_handle == to_update->attr_handle) {
1191 if (tmp->attr_type != to_update->attr_type) {
1192 rc = PLDM_ERROR_INVALID_DATA;
1193 goto out;
1194 }
1195 length = entry_length;
1196 tmp = entry;
1197 }
1198 if (copied_length + length > buffer_length) {
1199 rc = PLDM_ERROR_INVALID_LENGTH;
1200 goto out;
1201 }
1202 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1203 copied_length += length;
1204 }
1205
1206 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301207 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301208 if ((pad_checksum_size + copied_length) > buffer_length) {
1209 rc = PLDM_ERROR_INVALID_LENGTH;
1210 goto out;
1211 }
1212
Andrew Jefferyd8bb75c2024-06-29 22:29:02 +09301213 rc = pldm_bios_table_append_pad_checksum(dest_table, buffer_length,
1214 &copied_length);
Andrew Jeffery50dd1592023-07-14 16:02:05 +09301215 if (rc == PLDM_SUCCESS) {
1216 *dest_length = copied_length;
1217 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301218out:
1219 pldm_bios_table_iter_free(iter);
1220 return rc;
1221}
1222
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301223LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301224bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1225{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301226 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301227 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301228 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301229
1230 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1231 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301232 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301233 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301234 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235
1236 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1237 uint32_t dst_crc = crc32(table, size - 4);
1238
1239 return src_crc == dst_crc;
1240}