blob: 436b7e32def35b02047adad8c5c095200ce845b9 [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 Jeffery21cb0522024-10-04 21:01:06 +093074 if (entry_length - (sizeof(struct pldm_bios_string_table_entry) -
75 MEMBER_SIZE(pldm_bios_string_table_entry, name)) <
76 str_length) {
77 return PLDM_ERROR_INVALID_LENGTH;
78 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093079 struct pldm_bios_string_table_entry *string_entry = entry;
Andrew Jefferya873eca2023-06-26 17:25:37 +093080 uint16_t handle;
81 int rc = get_bios_string_handle(&handle);
82 if (rc != PLDM_SUCCESS) {
83 return rc;
84 }
85 string_entry->string_handle = htole16(handle);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +093086 string_entry->string_length = htole16(str_length);
87 memcpy(string_entry->name, str, str_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +093088 return PLDM_SUCCESS;
89}
90
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093091LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093092uint16_t pldm_bios_table_string_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093093 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +093094{
95 return le16toh(entry->string_handle);
96}
97
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093098LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +093099uint16_t pldm_bios_table_string_entry_decode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930100 const struct pldm_bios_string_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930101{
102 return le16toh(entry->string_length);
103}
104
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930105LIBPLDM_ABI_STABLE
Andrew Jeffery8c37ab32024-06-25 15:34:27 +0930106int pldm_bios_table_string_entry_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930107 const struct pldm_bios_string_table_entry *entry, char *buffer,
108 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930109{
110 POINTER_CHECK(entry);
111 POINTER_CHECK(buffer);
Andrew Jeffery98c1e692023-06-14 14:41:19 +0930112 if (size == 0) {
113 return PLDM_ERROR_INVALID_LENGTH;
114 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930115 size_t length =
116 pldm_bios_table_string_entry_decode_string_length(entry);
117 length = length < (size - 1) ? length : (size - 1);
118 memcpy(buffer, entry->name, length);
119 buffer[length] = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930120 return PLDM_SUCCESS;
121}
122
Andrew Jeffery73d91762023-06-28 12:19:19 +0930123static ssize_t string_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930124{
125 const struct pldm_bios_string_table_entry *entry = table_entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930126 size_t len = sizeof(*entry) - sizeof(entry->name) +
127 pldm_bios_table_string_entry_decode_string_length(entry);
128 if (len > SSIZE_MAX) {
129 return -1;
130 }
131 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930132}
133
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930134static int get_bios_attr_handle(uint16_t *val)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930135{
136 static uint16_t handle = 0;
137 assert(handle != UINT16_MAX);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930138 if (handle == UINT16_MAX) {
139 return PLDM_ERROR_INVALID_DATA;
140 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930141
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930142 *val = handle++;
143 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930144}
145
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930146static int attr_table_entry_encode_header(void *entry, size_t length,
147 uint8_t attr_type,
148 uint16_t string_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930149{
150 struct pldm_bios_attr_table_entry *attr_entry = entry;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930151
Andrew Jeffery9c766792022-08-10 23:12:49 +0930152 assert(sizeof(*attr_entry) <= length);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930153 if (sizeof(*attr_entry) > length) {
154 return PLDM_ERROR_INVALID_LENGTH;
155 }
156
157 uint16_t handle;
158 int rc = get_bios_attr_handle(&handle);
159 if (rc != PLDM_SUCCESS) {
160 return rc;
161 }
162
163 attr_entry->attr_handle = htole16(handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930164 attr_entry->attr_type = attr_type;
165 attr_entry->string_handle = htole16(string_handle);
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930166
167 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930168}
169
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930170LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930171uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930172 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930173{
174 return le16toh(entry->attr_handle);
175}
176
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930177LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930178uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930179 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930180{
181 return entry->attr_type;
182}
183
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930184LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185uint16_t pldm_bios_table_attr_entry_decode_string_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930186 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187{
188 return le16toh(entry->string_handle);
189}
190
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930191LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930192size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
193 uint8_t def_num)
194{
195 return sizeof(struct pldm_bios_attr_table_entry) -
196 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
197 sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
198 def_num;
199}
200
Andrew Jeffery36324f62024-09-25 13:41:41 +0930201LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery7126b1d2024-06-25 15:48:34 +0930202int pldm_bios_table_attr_entry_enum_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930203 void *entry, size_t entry_length,
204 const struct pldm_bios_table_attr_entry_enum_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930205{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930206 POINTER_CHECK(entry);
207 POINTER_CHECK(info);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930208 size_t length = pldm_bios_table_attr_entry_enum_encode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930209 info->pv_num, info->def_num);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930210 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930211 uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
212 PLDM_BIOS_ENUMERATION;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930213 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
214 info->name_handle);
215 if (rc != PLDM_SUCCESS) {
216 return rc;
217 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930218 struct pldm_bios_attr_table_entry *attr_entry = entry;
219 attr_entry->metadata[0] = info->pv_num;
220 uint16_t *pv_hdls =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930221 (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930222 size_t i;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930223 for (i = 0; i < info->pv_num; i++) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930224 pv_hdls[i] = htole16(info->pv_handle[i]);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930225 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930226 attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930227 info->def_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930228 memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930229 info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930230 info->def_index, info->def_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930231 return PLDM_SUCCESS;
232}
233
234#define ATTR_TYPE_EXPECT(type, expected) \
235 do { \
Andrew Jeffery0a05b122023-04-05 14:03:36 +0930236 if ((type) != (expected) && (type) != ((expected) | 0x80)) \
Andrew Jeffery9c766792022-08-10 23:12:49 +0930237 return PLDM_ERROR_INVALID_DATA; \
238 } while (0)
239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930240LIBPLDM_ABI_STABLE
Andrew Jefferyb06882f2024-06-25 15:52:02 +0930241int pldm_bios_table_attr_entry_enum_decode_pv_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930242 const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930243{
244 POINTER_CHECK(entry);
245 POINTER_CHECK(pv_num);
246 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930247 *pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930248 return PLDM_SUCCESS;
249}
250
Andrew Jeffery36324f62024-09-25 13:41:41 +0930251LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery46673f42024-06-25 16:02:25 +0930252int pldm_bios_table_attr_entry_enum_decode_def_num(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930253 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930254{
Andrew Jeffery46673f42024-06-25 16:02:25 +0930255 uint8_t pv_num;
256
Andrew Jeffery9c766792022-08-10 23:12:49 +0930257 POINTER_CHECK(entry);
258 POINTER_CHECK(def_num);
259 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery46673f42024-06-25 16:02:25 +0930260 pv_num = entry->metadata[0];
261 *def_num = entry->metadata[sizeof(uint8_t) + sizeof(uint16_t) * pv_num];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930262 return PLDM_SUCCESS;
263}
264
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930265LIBPLDM_ABI_STABLE
Andrew Jeffery82b4d3b2024-06-25 16:22:36 +0930266int pldm_bios_table_attr_entry_enum_decode_pv_hdls(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930267 const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
268 uint8_t pv_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930269{
270 POINTER_CHECK(entry);
271 POINTER_CHECK(pv_hdls);
272 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930273 uint8_t num = entry->metadata[0];
274 num = num < pv_num ? num : pv_num;
275 size_t i;
276 for (i = 0; i < num; i++) {
277 uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
278 i * sizeof(uint16_t));
279 pv_hdls[i] = le16toh(*hdl);
280 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930281 return PLDM_SUCCESS;
282}
283
Andrew Jeffery36324f62024-09-25 13:41:41 +0930284LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930285uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930286 const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
287 uint8_t def_num)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930288{
Andrew Jeffery46673f42024-06-25 16:02:25 +0930289 uint8_t num = 0;
290
291 /* TODO: Fix the API to propagate errors */
292 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930293 num = num < def_num ? num : def_num;
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930294 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930295 const uint8_t *p = entry->metadata +
296 sizeof(uint8_t) /* number of possible values*/
297 + pv_num * sizeof(uint16_t) /* possible values */
298 + sizeof(uint8_t); /* number of default values */
299 memcpy(def_indices, p, num);
300 return num;
301}
302
303/** @brief Get length of an enum attribute entry
304 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930305static ssize_t attr_table_entry_length_enum(const void *arg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930306{
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930307 const struct pldm_bios_attr_table_entry *entry = arg;
308 uint8_t pv_num = entry->metadata[0];
Andrew Jeffery46673f42024-06-25 16:02:25 +0930309 uint8_t def_num = 0;
310
311 /* TODO: Fix the API to propagate errors */
312 pldm_bios_table_attr_entry_enum_decode_def_num(entry, &def_num);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930313 size_t len =
314 pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
315 if (len > SSIZE_MAX) {
316 return -1;
317 }
318 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930319}
320
321struct attr_table_string_entry_fields {
322 uint8_t string_type;
323 uint16_t min_length;
324 uint16_t max_length;
325 uint16_t def_length;
326 uint8_t def_string[1];
327} __attribute__((packed));
328
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930329LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930330size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
331{
332 return sizeof(struct pldm_bios_attr_table_entry) -
333 MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
334 sizeof(struct attr_table_string_entry_fields) -
335 MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
336 def_str_len;
337}
338
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930339#define PLDM_STRING_TYPE_MAX 5
Andrew Jeffery9c766792022-08-10 23:12:49 +0930340#define PLDM_STRING_TYPE_VENDOR 0xff
341
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930342LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930343int pldm_bios_table_attr_entry_string_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930344 const struct pldm_bios_table_attr_entry_string_info *info,
345 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930346{
347 if (info->min_length > info->max_length) {
348 set_errmsg(errmsg, "MinimumStingLength should not be greater "
349 "than MaximumStringLength");
350 return PLDM_ERROR_INVALID_DATA;
351 }
352 if (info->min_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->def_length > info->max_length ||
358 info->def_length < info->min_length) {
359 set_errmsg(errmsg, "Wrong DefaultStringLength");
360 return PLDM_ERROR_INVALID_DATA;
361 }
362 if (info->string_type > PLDM_STRING_TYPE_MAX &&
363 info->string_type != PLDM_STRING_TYPE_VENDOR) {
364 set_errmsg(errmsg, "Wrong StringType");
365 return PLDM_ERROR_INVALID_DATA;
366 }
Andrew Jefferydf02e362023-06-14 14:52:25 +0930367 if (info->def_string && info->def_length != strlen(info->def_string)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930368 set_errmsg(errmsg, "Length of DefaultString should be equal to "
369 "DefaultStringLength");
370 return PLDM_ERROR_INVALID_DATA;
371 }
372
373 return PLDM_SUCCESS;
374}
375
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930376LIBPLDM_ABI_STABLE
Andrew Jefferyf6be4932024-06-25 16:44:06 +0930377int pldm_bios_table_attr_entry_string_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930378 void *entry, size_t entry_length,
379 const struct pldm_bios_table_attr_entry_string_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380{
381 POINTER_CHECK(entry);
382 POINTER_CHECK(info);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930383 size_t length = pldm_bios_table_attr_entry_string_encode_length(
384 info->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930385 BUFFER_SIZE_EXPECT(entry_length, length);
386 if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930387 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930388 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930389 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930390 uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
391 PLDM_BIOS_STRING;
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930392 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
393 info->name_handle);
394 if (rc != PLDM_SUCCESS) {
395 return rc;
396 }
Andrew Jeffery6409c8a2023-06-14 11:38:31 +0930397 struct pldm_bios_attr_table_entry *attr_entry = entry;
398 struct attr_table_string_entry_fields *attr_fields =
399 (struct attr_table_string_entry_fields *)attr_entry->metadata;
400 attr_fields->string_type = info->string_type;
401 attr_fields->min_length = htole16(info->min_length);
402 attr_fields->max_length = htole16(info->max_length);
403 attr_fields->def_length = htole16(info->def_length);
404 if (info->def_length != 0 && info->def_string != NULL) {
405 memcpy(attr_fields->def_string, info->def_string,
406 info->def_length);
407 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930408 return PLDM_SUCCESS;
409}
410
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930411LIBPLDM_ABI_STABLE
Andrew Jefferyc668ffc2024-06-25 16:50:08 +0930412int pldm_bios_table_attr_entry_string_decode_def_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930413 const struct pldm_bios_attr_table_entry *entry,
414 uint16_t *def_string_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930415{
416 POINTER_CHECK(entry);
417 POINTER_CHECK(def_string_length);
418 ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
Andrew Jefferyc668ffc2024-06-25 16:50:08 +0930419 struct attr_table_string_entry_fields *fields =
420 (struct attr_table_string_entry_fields *)entry->metadata;
421 *def_string_length = le16toh(fields->def_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930422 return PLDM_SUCCESS;
423}
424
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930425LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930426uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930427 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930428{
429 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930430 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930431 return fields->string_type;
432}
433
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930434LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930435uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930436 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930437{
438 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930439 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930440 return le16toh(fields->max_length);
441}
442
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930443LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930444uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930445 const struct pldm_bios_attr_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930446{
447 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930448 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930449 return le16toh(fields->min_length);
450}
451
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930452LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930453uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930454 const struct pldm_bios_attr_table_entry *entry, char *buffer,
455 size_t size)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930456{
Andrew Jefferyc668ffc2024-06-25 16:50:08 +0930457 uint16_t length = 0;
458 int rc;
459
460 if (!entry || !buffer || size == 0) {
461 return 0;
462 }
463
464 /* TODO: Rework the API to propagate the error */
465 rc = pldm_bios_table_attr_entry_string_decode_def_string_length(
466 entry, &length);
467 if (rc != PLDM_SUCCESS) {
468 return 0;
469 }
470
Andrew Jeffery9c766792022-08-10 23:12:49 +0930471 length = length < (size - 1) ? length : (size - 1);
472 struct attr_table_string_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930473 (struct attr_table_string_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474 memcpy(buffer, fields->def_string, length);
475 buffer[length] = 0;
476 return length;
477}
478
479/** @brief Get length of a string attribute entry
480 */
Andrew Jeffery73d91762023-06-28 12:19:19 +0930481static ssize_t attr_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930482{
Andrew Jefferyc668ffc2024-06-25 16:50:08 +0930483 uint16_t def_str_len = 0;
484
485 /* TODO: Rework the API to propagate the error */
486 pldm_bios_table_attr_entry_string_decode_def_string_length(
487 entry, &def_str_len);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930488 size_t len =
489 pldm_bios_table_attr_entry_string_encode_length(def_str_len);
490 if (len > SSIZE_MAX) {
491 return -1;
492 }
493 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930494}
495
496struct attr_table_integer_entry_fields {
497 uint64_t lower_bound;
498 uint64_t upper_bound;
499 uint32_t scalar_increment;
500 uint64_t default_value;
501} __attribute__((packed));
502
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930503LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930504size_t pldm_bios_table_attr_entry_integer_encode_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930505{
506 return sizeof(struct pldm_bios_attr_table_entry) - 1 +
507 sizeof(struct attr_table_integer_entry_fields);
508}
509
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930510LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930511int pldm_bios_table_attr_entry_integer_info_check(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930512 const struct pldm_bios_table_attr_entry_integer_info *info,
513 const char **errmsg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930514{
515 if (info->lower_bound == info->upper_bound) {
516 if (info->default_value != info->lower_bound) {
517 set_errmsg(errmsg, "Wrong DefaultValue");
518 return PLDM_ERROR_INVALID_DATA;
519 }
520 if (info->scalar_increment != 0) {
521 set_errmsg(errmsg, "Wrong ScalarIncrement");
522 return PLDM_ERROR_INVALID_DATA;
523 }
524 return PLDM_SUCCESS;
525 }
526 if (info->lower_bound > info->upper_bound) {
527 set_errmsg(errmsg,
528 "LowerBound should not be greater than UpperBound");
529 return PLDM_ERROR_INVALID_DATA;
530 }
531 if (info->default_value > info->upper_bound ||
532 info->default_value < info->lower_bound) {
533 set_errmsg(errmsg, "Wrong DefaultValue");
534 return PLDM_ERROR_INVALID_DATA;
535 }
536 if (info->scalar_increment == 0) {
537 set_errmsg(errmsg, "ScalarIncrement should not be zero when "
538 "lower_bound != upper_bound");
539 return PLDM_ERROR_INVALID_DATA;
540 }
541 if ((info->default_value - info->lower_bound) %
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930542 info->scalar_increment !=
Andrew Jeffery9c766792022-08-10 23:12:49 +0930543 0) {
544 set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
545 return PLDM_ERROR_INVALID_DATA;
546 }
547 return PLDM_SUCCESS;
548}
549
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930550LIBPLDM_ABI_STABLE
Andrew Jeffery5347e272024-06-29 22:05:36 +0930551int pldm_bios_table_attr_entry_integer_encode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930552 void *entry, size_t entry_length,
553 const struct pldm_bios_table_attr_entry_integer_info *info)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930554{
555 POINTER_CHECK(entry);
556 POINTER_CHECK(info);
557 size_t length = pldm_bios_table_attr_entry_integer_encode_length();
558 BUFFER_SIZE_EXPECT(entry_length, length);
559 if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930560 PLDM_SUCCESS) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930561 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930562 }
Andrew Jefferyfe0f01d2023-06-27 11:51:58 +0930563 uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
564 PLDM_BIOS_INTEGER;
565 int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
566 info->name_handle);
567 if (rc != PLDM_SUCCESS) {
568 return rc;
569 }
570 struct pldm_bios_attr_table_entry *attr_entry = entry;
571 struct attr_table_integer_entry_fields *attr_fields =
572 (struct attr_table_integer_entry_fields *)attr_entry->metadata;
573 attr_fields->lower_bound = htole64(info->lower_bound);
574 attr_fields->upper_bound = htole64(info->upper_bound);
575 attr_fields->scalar_increment = htole32(info->scalar_increment);
576 attr_fields->default_value = htole64(info->default_value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930577 return PLDM_SUCCESS;
578}
579
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930580LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930581void pldm_bios_table_attr_entry_integer_decode(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930582 const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
583 uint64_t *upper, uint32_t *scalar, uint64_t *def)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930584{
585 struct attr_table_integer_entry_fields *fields =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930586 (struct attr_table_integer_entry_fields *)entry->metadata;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930587 *lower = le64toh(fields->lower_bound);
588 *upper = le64toh(fields->upper_bound);
589 *scalar = le32toh(fields->scalar_increment);
590 *def = le64toh(fields->default_value);
591}
592
Andrew Jeffery73d91762023-06-28 12:19:19 +0930593static ssize_t attr_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930594{
595 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930596 size_t len = pldm_bios_table_attr_entry_integer_encode_length();
597 if (len > SSIZE_MAX) {
598 return -1;
599 }
600 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930601}
602
603struct table_entry_length {
604 uint8_t attr_type;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930605 ssize_t (*entry_length_handler)(const void *);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606};
607
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930608static const struct table_entry_length *
609find_table_entry_length_by_type(uint8_t attr_type,
610 const struct table_entry_length *handlers,
611 size_t count)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930612{
613 size_t i;
614 for (i = 0; i < count; i++) {
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930615 if (attr_type == handlers[i].attr_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930616 return &handlers[i];
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930617 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618 }
619 return NULL;
620}
621
622static const struct table_entry_length attr_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930623 { .attr_type = PLDM_BIOS_ENUMERATION,
624 .entry_length_handler = attr_table_entry_length_enum },
625 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
626 .entry_length_handler = attr_table_entry_length_enum },
627 { .attr_type = PLDM_BIOS_STRING,
628 .entry_length_handler = attr_table_entry_length_string },
629 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
630 .entry_length_handler = attr_table_entry_length_string },
631 { .attr_type = PLDM_BIOS_INTEGER,
632 .entry_length_handler = attr_table_entry_length_integer },
633 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
634 .entry_length_handler = attr_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930635};
636
Andrew Jeffery73d91762023-06-28 12:19:19 +0930637static ssize_t attr_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930638{
639 const struct pldm_bios_attr_table_entry *entry = table_entry;
640 const struct table_entry_length *attr_table_entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930641 find_table_entry_length_by_type(entry->attr_type,
642 attr_table_entries,
643 ARRAY_SIZE(attr_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930644 assert(attr_table_entry != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930645 if (!attr_table_entry) {
646 return -1;
647 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930648 assert(attr_table_entry->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930649 if (!attr_table_entry->entry_length_handler) {
650 return -1;
651 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930652
653 return attr_table_entry->entry_length_handler(entry);
654}
655
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930656LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930657uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930658 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930659{
660 return le16toh(entry->attr_handle);
661}
662
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930663LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930664uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930665 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666{
667 return entry->attr_type;
668}
669
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930670LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930671size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
672{
673 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
674 sizeof(count) + count;
675}
676
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930677LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930678uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930679 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680{
681 return entry->value[0];
682}
683
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930684LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930686 const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
687 uint8_t number)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688{
689 uint8_t curr_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930690 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Archana Kakanib9d951f2023-10-17 05:47:58 -0500691 curr_num = number < curr_num ? number : curr_num;
692 memcpy(handles, &entry->value[1], curr_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930693
Archana Kakanib9d951f2023-10-17 05:47:58 -0500694 return curr_num;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695}
696
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930697LIBPLDM_ABI_STABLE
Andrew Jeffery09004d62024-06-29 22:12:15 +0930698int pldm_bios_table_attr_value_entry_encode_enum(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930699 void *entry, size_t entry_length, uint16_t attr_handle,
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930700 uint8_t attr_type, uint8_t count, const uint8_t *handles)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930701{
Andrew Jeffery92967be2024-10-02 22:13:57 +0930702 struct pldm_bios_attr_val_table_entry *table_entry;
703
Andrew Jeffery9c766792022-08-10 23:12:49 +0930704 POINTER_CHECK(entry);
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930705 POINTER_CHECK(handles);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930706 if (count != 0 && handles == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930707 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930708 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930709 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
Andrew Jeffery92967be2024-10-02 22:13:57 +0930710 BUFFER_SIZE_EXPECT(entry_length, sizeof(*table_entry));
711 table_entry = entry;
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930712 table_entry->attr_handle = htole16(attr_handle);
713 table_entry->attr_type = attr_type;
714 table_entry->value[0] = count;
Andrew Jeffery92967be2024-10-02 22:13:57 +0930715 if (entry_length - sizeof(*table_entry) < count) {
716 return PLDM_ERROR_INVALID_LENGTH;
Andrew Jeffery7aeb7ed2023-06-27 13:13:36 +0930717 }
Andrew Jeffery92967be2024-10-02 22:13:57 +0930718 memcpy(&table_entry->value[1], handles, count);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930719 return PLDM_SUCCESS;
720}
721
Andrew Jeffery73d91762023-06-28 12:19:19 +0930722static ssize_t attr_value_table_entry_length_enum(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930723{
724 uint8_t number =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930725 pldm_bios_table_attr_value_entry_enum_decode_number(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930726 size_t len =
727 pldm_bios_table_attr_value_entry_encode_enum_length(number);
728 if (len > SSIZE_MAX) {
729 return -1;
730 }
731 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930732}
733
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930734LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930735size_t
736pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
737{
738 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
739 sizeof(string_length) + string_length;
740}
741
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930742LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930743uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930744 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745{
746 uint16_t str_length = 0;
747 memcpy(&str_length, entry->value, sizeof(str_length));
748 return le16toh(str_length);
749}
750
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930751LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930752void pldm_bios_table_attr_value_entry_string_decode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930753 const struct pldm_bios_attr_val_table_entry *entry,
754 struct variable_field *current_string)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755{
756 current_string->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930757 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758 current_string->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930759 entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760}
761
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930762LIBPLDM_ABI_STABLE
Andrew Jeffery1a3983c2024-06-29 22:17:58 +0930763int pldm_bios_table_attr_value_entry_encode_string(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930764 void *entry, size_t entry_length, uint16_t attr_handle,
765 uint8_t attr_type, uint16_t str_length, const char *str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930766{
Andrew Jefferyd96d21f2024-10-02 22:04:28 +0930767 struct pldm_bios_attr_val_table_entry *table_entry;
768
Andrew Jeffery9c766792022-08-10 23:12:49 +0930769 POINTER_CHECK(entry);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930770 if (str_length != 0 && str == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930771 return PLDM_ERROR_INVALID_DATA;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930772 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930773 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
Andrew Jefferyd96d21f2024-10-02 22:04:28 +0930774 BUFFER_SIZE_EXPECT(entry_length,
775 (sizeof(*table_entry) - 1 + sizeof(str_length)));
776 table_entry = entry;
Andrew Jeffery2d663932023-06-27 14:19:15 +0930777 table_entry->attr_handle = htole16(attr_handle);
778 table_entry->attr_type = attr_type;
Andrew Jefferyd96d21f2024-10-02 22:04:28 +0930779 if (entry_length - (sizeof(*table_entry) - 1 + sizeof(str_length)) <
780 str_length) {
781 return PLDM_ERROR_INVALID_LENGTH;
Andrew Jeffery2d663932023-06-27 14:19:15 +0930782 }
Andrew Jefferyd96d21f2024-10-02 22:04:28 +0930783 memcpy(table_entry->value + sizeof(str_length), str, str_length);
Andrew Jeffery2d663932023-06-27 14:19:15 +0930784 str_length = htole16(str_length);
785 memcpy(table_entry->value, &str_length, sizeof(str_length));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930786 return PLDM_SUCCESS;
787}
788
Andrew Jeffery73d91762023-06-28 12:19:19 +0930789static ssize_t attr_value_table_entry_length_string(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930790{
791 uint16_t str_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930792 pldm_bios_table_attr_value_entry_string_decode_length(entry);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930793 size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930794 str_length);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930795 if (len > SSIZE_MAX) {
796 return -1;
797 }
798 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930799}
800
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930801LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930802size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930803{
804 return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
805 sizeof(uint64_t);
806}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930807
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930808LIBPLDM_ABI_STABLE
Andrew Jeffery504dd172024-06-29 22:23:15 +0930809int pldm_bios_table_attr_value_entry_encode_integer(void *entry,
810 size_t entry_length,
811 uint16_t attr_handle,
812 uint8_t attr_type,
813 uint64_t cv)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930814{
815 POINTER_CHECK(entry);
816 size_t length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930817 pldm_bios_table_attr_value_entry_encode_integer_length();
Andrew Jeffery9c766792022-08-10 23:12:49 +0930818 ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
819 BUFFER_SIZE_EXPECT(entry_length, length);
Andrew Jeffery0088a6a2023-06-27 15:06:45 +0930820 struct pldm_bios_attr_val_table_entry *table_entry = entry;
821 table_entry->attr_handle = htole16(attr_handle);
822 table_entry->attr_type = attr_type;
823 cv = htole64(cv);
824 memcpy(table_entry->value, &cv, sizeof(uint64_t));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930825 return PLDM_SUCCESS;
826}
827
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930828LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930829uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930830 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930831{
832 uint64_t cv = 0;
833 memcpy(&cv, entry->value, sizeof(cv));
834 cv = le64toh(cv);
835 return cv;
836}
837
Andrew Jeffery73d91762023-06-28 12:19:19 +0930838static ssize_t attr_value_table_entry_length_integer(const void *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930839{
840 (void)entry;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930841 size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
842 if (len > SSIZE_MAX) {
843 return -1;
844 }
845 return (ssize_t)len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846}
847
848static const struct table_entry_length attr_value_table_entries[] = {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930849 { .attr_type = PLDM_BIOS_ENUMERATION,
850 .entry_length_handler = attr_value_table_entry_length_enum },
851 { .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
852 .entry_length_handler = attr_value_table_entry_length_enum },
853 { .attr_type = PLDM_BIOS_STRING,
854 .entry_length_handler = attr_value_table_entry_length_string },
855 { .attr_type = PLDM_BIOS_STRING_READ_ONLY,
856 .entry_length_handler = attr_value_table_entry_length_string },
857 { .attr_type = PLDM_BIOS_INTEGER,
858 .entry_length_handler = attr_value_table_entry_length_integer },
859 { .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
860 .entry_length_handler = attr_value_table_entry_length_integer },
Andrew Jeffery9c766792022-08-10 23:12:49 +0930861};
862
Andrew Jeffery73d91762023-06-28 12:19:19 +0930863static ssize_t attr_value_table_entry_length(const void *table_entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930864{
865 const struct pldm_bios_attr_val_table_entry *entry = table_entry;
866 const struct table_entry_length *entry_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930867 find_table_entry_length_by_type(
868 entry->attr_type, attr_value_table_entries,
869 ARRAY_SIZE(attr_value_table_entries));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870 assert(entry_length != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930871 if (!entry_length) {
872 return -1;
873 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930874 assert(entry_length->entry_length_handler != NULL);
Andrew Jeffery73d91762023-06-28 12:19:19 +0930875 if (!entry_length->entry_length_handler) {
876 return -1;
877 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930878
879 return entry_length->entry_length_handler(entry);
880}
881
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930882LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930883size_t pldm_bios_table_attr_value_entry_length(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930884 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930885{
886 return attr_value_table_entry_length(entry);
887}
888
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930889LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890uint16_t pldm_bios_table_attr_value_entry_decode_handle(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930891 const struct pldm_bios_attr_val_table_entry *entry)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930892{
893 return le16toh(entry->attr_handle);
894}
895
896static size_t pad_size_get(size_t size_without_pad)
897{
Andrew Jeffery72dd2dd2024-10-02 21:04:21 +0930898 return (4 - (size_without_pad % 4)) % 4;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899}
900
901static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
902{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930903 while (pad_size--) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904 *table_end++ = 0;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +0930905 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930906
907 return table_end;
908}
909
910static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
911{
912 checksum = htole32(checksum);
913 memcpy(table_end, &checksum, sizeof(checksum));
914
915 return table_end + sizeof(checksum);
916}
917
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930918LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930919size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
920{
Andrew Jefferya16f70c2024-10-02 21:19:25 +0930921 return pad_size_get(size_without_pad) + sizeof(uint32_t);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930922}
923
Andrew Jeffery1264fbd2023-07-07 09:44:07 +0930924LIBPLDM_ABI_STABLE
Andrew Jefferyd8bb75c2024-06-29 22:29:02 +0930925int pldm_bios_table_append_pad_checksum(void *table, size_t capacity,
926 size_t *size)
Andrew Jeffery044ee192023-06-28 11:26:00 +0930927{
928 if (!table || !size) {
929 return PLDM_ERROR_INVALID_DATA;
930 }
931
932 size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
Andrew Jefferyd610b002024-10-02 21:27:30 +0930933
934 if (SIZE_MAX - pad_checksum_size < *size) {
935 return PLDM_ERROR_INVALID_LENGTH;
936 }
937
Andrew Jeffery044ee192023-06-28 11:26:00 +0930938 size_t total_length = *size + pad_checksum_size;
Andrew Jeffery044ee192023-06-28 11:26:00 +0930939 if (capacity < total_length) {
940 return PLDM_ERROR_INVALID_LENGTH;
941 }
942
Andrew Jefferyd610b002024-10-02 21:27:30 +0930943 if (UINTPTR_MAX - *size < (uintptr_t)table) {
944 return PLDM_ERROR_INVALID_LENGTH;
945 }
Andrew Jeffery044ee192023-06-28 11:26:00 +0930946 uint8_t *table_end = (uint8_t *)table + *size;
947 size_t pad_size = pad_size_get(*size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948 table_end = pad_append(table_end, pad_size);
949
Andrew Jeffery044ee192023-06-28 11:26:00 +0930950 uint32_t checksum = crc32(table, *size + pad_size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951 checksum_append(table_end, checksum);
Andrew Jeffery044ee192023-06-28 11:26:00 +0930952 *size = total_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953
Andrew Jeffery044ee192023-06-28 11:26:00 +0930954 return PLDM_SUCCESS;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955}
956
957struct pldm_bios_table_iter {
958 const uint8_t *table_data;
959 size_t table_len;
960 size_t current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +0930961 ssize_t (*entry_length_handler)(const void *table_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930962};
963
Andrew Jeffery36324f62024-09-25 13:41:41 +0930964LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965struct pldm_bios_table_iter *
966pldm_bios_table_iter_create(const void *table, size_t length,
967 enum pldm_bios_table_types type)
968{
969 struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
970 assert(iter != NULL);
Andrew Jeffery757e81a2023-06-28 12:15:59 +0930971 if (!iter) {
972 return NULL;
973 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930974 iter->table_data = table;
975 iter->table_len = length;
976 iter->current_pos = 0;
977 iter->entry_length_handler = NULL;
978 switch (type) {
979 case PLDM_BIOS_STRING_TABLE:
980 iter->entry_length_handler = string_table_entry_length;
981 break;
982 case PLDM_BIOS_ATTR_TABLE:
983 iter->entry_length_handler = attr_table_entry_length;
984 break;
985 case PLDM_BIOS_ATTR_VAL_TABLE:
986 iter->entry_length_handler = attr_value_table_entry_length;
987 break;
988 }
989
990 return iter;
991}
992
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930993LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930994void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
995{
996 free(iter);
997}
998
999#define pad_and_check_max 7
Andrew Jeffery36324f62024-09-25 13:41:41 +09301000LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
1002{
Andrew Jeffery73d91762023-06-28 12:19:19 +09301003 ssize_t len;
1004
Andrew Jeffery3b5ab922024-09-22 15:20:50 +09301005 if (!iter) {
1006 return true;
1007 }
1008
Andrew Jeffery36324f62024-09-25 13:41:41 +09301009 if (iter->current_pos > iter->table_len) {
1010 return true;
1011 }
1012
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301013 if (iter->table_len - iter->current_pos <= pad_and_check_max) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301014 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301015 }
Andrew Jeffery73d91762023-06-28 12:19:19 +09301016
1017 len = iter->entry_length_handler(iter->table_data + iter->current_pos);
1018
1019 return len < 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301020}
1021
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301022LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301023void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
1024{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301025 if (pldm_bios_table_iter_is_end(iter)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301026 return;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301027 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301028 const void *entry = iter->table_data + iter->current_pos;
Andrew Jeffery73d91762023-06-28 12:19:19 +09301029 ssize_t rc = iter->entry_length_handler(entry);
1030 /* Prevent bad behaviour by acting as if we've hit the end of the iterator */
1031 if (rc < 0) {
1032 return;
1033 }
1034 iter->current_pos += rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301035}
1036
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301037LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301038const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
1039{
1040 return iter->table_data + iter->current_pos;
1041}
1042
1043typedef bool (*equal_handler)(const void *entry, const void *key);
1044
1045static const void *
1046pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
1047 const void *key, equal_handler equal)
1048{
1049 const void *entry;
1050 while (!pldm_bios_table_iter_is_end(iter)) {
1051 entry = pldm_bios_table_iter_value(iter);
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301052 if (equal(entry, key)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301053 return entry;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301054 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301055 pldm_bios_table_iter_next(iter);
1056 }
1057 return NULL;
1058}
1059
1060static const void *
1061pldm_bios_table_entry_find_from_table(const void *table, size_t length,
1062 enum pldm_bios_table_types type,
1063 equal_handler equal, const void *key)
1064{
1065 struct pldm_bios_table_iter *iter =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301066 pldm_bios_table_iter_create(table, length, type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301067 const void *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301068 pldm_bios_table_entry_find_by_iter(iter, key, equal);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301069 pldm_bios_table_iter_free(iter);
1070 return entry;
1071}
1072
1073static bool string_table_handle_equal(const void *entry, const void *key)
1074{
1075 const struct pldm_bios_string_table_entry *string_entry = entry;
1076 uint16_t handle = *(uint16_t *)key;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301077 if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
1078 handle) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301079 return true;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301080 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301081 return false;
1082}
1083
Andrew Jeffery36324f62024-09-25 13:41:41 +09301084LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301085const struct pldm_bios_string_table_entry *
1086pldm_bios_table_string_find_by_handle(const void *table, size_t length,
1087 uint16_t handle)
1088{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301089 return pldm_bios_table_entry_find_from_table(table, length,
1090 PLDM_BIOS_STRING_TABLE,
1091 string_table_handle_equal,
1092 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301093}
1094
1095struct string_equal_arg {
1096 uint16_t str_length;
1097 const char *str;
1098};
1099
1100static bool string_table_string_equal(const void *entry, const void *key)
1101{
1102 const struct pldm_bios_string_table_entry *string_entry = entry;
1103 const struct string_equal_arg *arg = key;
1104 if (arg->str_length !=
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301105 pldm_bios_table_string_entry_decode_string_length(string_entry)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301107 }
1108 if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301109 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301110 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301111 return true;
1112}
1113
Andrew Jeffery36324f62024-09-25 13:41:41 +09301114LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301115const struct pldm_bios_string_table_entry *
1116pldm_bios_table_string_find_by_string(const void *table, size_t length,
1117 const char *str)
1118{
1119 uint16_t str_length = strlen(str);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301120 struct string_equal_arg arg = { str_length, str };
1121 return pldm_bios_table_entry_find_from_table(table, length,
1122 PLDM_BIOS_STRING_TABLE,
1123 string_table_string_equal,
1124 &arg);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301125}
1126
1127static bool attr_table_handle_equal(const void *entry, const void *key)
1128{
1129 uint16_t handle = *(uint16_t *)key;
1130 return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
1131 handle;
1132}
1133
Andrew Jeffery36324f62024-09-25 13:41:41 +09301134LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301135const struct pldm_bios_attr_table_entry *
1136pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
1137 uint16_t handle)
1138{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301139 return pldm_bios_table_entry_find_from_table(table, length,
1140 PLDM_BIOS_ATTR_TABLE,
1141 attr_table_handle_equal,
1142 &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301143}
1144
1145static bool attr_table_string_handle_equal(const void *entry, const void *key)
1146{
1147 uint16_t handle = *(uint16_t *)key;
1148 return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
1149}
1150
Andrew Jeffery36324f62024-09-25 13:41:41 +09301151LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301152const struct pldm_bios_attr_table_entry *
1153pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
1154 uint16_t handle)
1155{
1156 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301157 table, length, PLDM_BIOS_ATTR_TABLE,
1158 attr_table_string_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301159}
1160
1161static bool attr_value_table_handle_equal(const void *entry, const void *key)
1162{
1163 uint16_t handle = *(uint16_t *)key;
1164 return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
1165}
1166
Andrew Jeffery36324f62024-09-25 13:41:41 +09301167LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301168const struct pldm_bios_attr_val_table_entry *
1169pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
1170 uint16_t handle)
1171{
1172 return pldm_bios_table_entry_find_from_table(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301173 table, length, PLDM_BIOS_ATTR_VAL_TABLE,
1174 attr_value_table_handle_equal, &handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301175}
1176
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301177LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301178int pldm_bios_table_attr_value_copy_and_update(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301179 const void *src_table, size_t src_length, void *dest_table,
1180 size_t *dest_length, const void *entry, size_t entry_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301181{
1182 struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301183 src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301184
1185 int rc = PLDM_SUCCESS;
Andrew Jefferyfbe61d72023-04-05 20:28:23 +09301186 const struct pldm_bios_attr_val_table_entry *tmp;
1187 const struct pldm_bios_attr_val_table_entry *to_update = entry;
1188 size_t buffer_length = *dest_length;
1189 size_t copied_length = 0;
1190 size_t length = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301191 while (!pldm_bios_table_iter_is_end(iter)) {
1192 tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
1193 length = attr_value_table_entry_length(tmp);
1194
1195 /* we need the tmp's entry_length here, iter_next will calculate
1196 * it too, use current_pos directly to avoid calculating it
1197 * twice */
1198 iter->current_pos += length;
1199 if (tmp->attr_handle == to_update->attr_handle) {
1200 if (tmp->attr_type != to_update->attr_type) {
1201 rc = PLDM_ERROR_INVALID_DATA;
1202 goto out;
1203 }
1204 length = entry_length;
1205 tmp = entry;
1206 }
1207 if (copied_length + length > buffer_length) {
1208 rc = PLDM_ERROR_INVALID_LENGTH;
1209 goto out;
1210 }
1211 memcpy((uint8_t *)dest_table + copied_length, tmp, length);
1212 copied_length += length;
1213 }
1214
1215 size_t pad_checksum_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301216 pldm_bios_table_pad_checksum_size(copied_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301217 if ((pad_checksum_size + copied_length) > buffer_length) {
1218 rc = PLDM_ERROR_INVALID_LENGTH;
1219 goto out;
1220 }
1221
Andrew Jefferyd8bb75c2024-06-29 22:29:02 +09301222 rc = pldm_bios_table_append_pad_checksum(dest_table, buffer_length,
1223 &copied_length);
Andrew Jeffery50dd1592023-07-14 16:02:05 +09301224 if (rc == PLDM_SUCCESS) {
1225 *dest_length = copied_length;
1226 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301227out:
1228 pldm_bios_table_iter_free(iter);
1229 return rc;
1230}
1231
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301232LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301233bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
1234{
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301235 if (table == NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301236 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301237 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301238
1239 // 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
1240 // Variable(4) + checksum(uint32)
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301241 if (size < 12) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301242 return false;
Andrew Jefferyd2c64cb2023-04-05 19:51:39 +09301243 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301244
1245 uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
1246 uint32_t dst_crc = crc32(table, size - 4);
1247
1248 return src_crc == dst_crc;
1249}