blob: a8a5575381d5dd8215ba825a3582f445964b9f3d [file] [log] [blame]
Julian Hall65f7eb42021-11-22 16:06:42 +01001/*
2 * Copyright (c) 2021, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include <stdlib.h>
9#include <string.h>
10#include "variable_index.h"
11
12/* Private functions */
13static uint64_t name_hash(
14 const EFI_GUID *guid,
15 size_t name_size,
16 const int16_t *name)
17{
18 /* Using djb2 hash by Dan Bernstein */
19 uint64_t hash = 5381;
20
21 /* Calculate hash over GUID */
22 hash = ((hash << 5) + hash) + guid->Data1;
23 hash = ((hash << 5) + hash) + guid->Data2;
24 hash = ((hash << 5) + hash) + guid->Data3;
25
26 for (int i = 0; i < 8; ++i) {
27
28 hash = ((hash << 5) + hash) + guid->Data4[i];
29 }
30
31 /* Extend to cover name up to but not including null terminator */
32 for (int i = 0; i < name_size / sizeof(int16_t); ++i) {
33
34 if (!name[i]) break;
35 hash = ((hash << 5) + hash) + name[i];
36 }
37
38 return hash;
39}
40
41static uint64_t generate_uid(
42 const struct variable_index *context,
43 const EFI_GUID *guid,
44 size_t name_size,
45 const int16_t *name)
46{
47 uint64_t uid = name_hash(guid, name_size, name);
48
49 /* todo - handle collision */
50 (void)context;
51
52 return uid;
53}
54
55static int find_variable(
56 const struct variable_index *context,
57 const EFI_GUID *guid,
58 size_t name_size,
59 const int16_t *name)
60{
61 int found_pos = -1;
62 uint64_t uid = name_hash(guid, name_size, name);
63
64 for (int pos = 0; pos < context->max_variables; pos++) {
65
66 if ((context->entries[pos].in_use) &&
Julian Hall0a86f762021-11-08 13:31:23 +000067 (uid == context->entries[pos].info.metadata.uid)) {
Julian Hall65f7eb42021-11-22 16:06:42 +010068
69 found_pos = pos;
70 break;
71 }
72 }
73
74 return found_pos;
75}
76
77static int find_free(
78 const struct variable_index *context)
79{
80 int free_pos = -1;
81
82 for (int pos = 0; pos < context->max_variables; pos++) {
83
84 if (!context->entries[pos].in_use) {
85
86 free_pos = pos;
87 break;
88 }
89 }
90
91 return free_pos;
92}
93
94static void mark_dirty(struct variable_entry *entry)
95{
Julian Hall0a86f762021-11-08 13:31:23 +000096 if (entry->info.metadata.attributes & EFI_VARIABLE_NON_VOLATILE)
Julian Hall65f7eb42021-11-22 16:06:42 +010097 entry->dirty = true;
98}
99
Julian Hallc0d54dc2021-10-13 15:18:30 +0100100static struct variable_entry *containing_entry(const struct variable_info *info)
101{
102 size_t info_offset = offsetof(struct variable_entry, info);
103 struct variable_entry *entry = (struct variable_entry*)((uint8_t*)info - info_offset);
104 return entry;
105}
106
Julian Hall65f7eb42021-11-22 16:06:42 +0100107/* Public functions */
108efi_status_t variable_index_init(
109 struct variable_index *context,
110 size_t max_variables)
111{
112 context->max_variables = max_variables;
113 context->entries = (struct variable_entry*)
114 malloc(sizeof(struct variable_entry) * max_variables);
115
116 if (context->entries) {
117 memset(context->entries, 0, sizeof(struct variable_entry) * max_variables);
118 }
119
120 return (context->entries) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
121}
122
123void variable_index_deinit(
124 struct variable_index *context)
125{
126 free(context->entries);
127}
128
129size_t variable_index_max_dump_size(
130 struct variable_index *context)
131{
Julian Hall0a86f762021-11-08 13:31:23 +0000132 return sizeof(struct variable_metadata) * context->max_variables;
Julian Hall65f7eb42021-11-22 16:06:42 +0100133}
134
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000135struct variable_info *variable_index_find(
136 struct variable_index *context,
Julian Hall65f7eb42021-11-22 16:06:42 +0100137 const EFI_GUID *guid,
138 size_t name_size,
139 const int16_t *name)
140{
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000141 struct variable_info *result = NULL;
Julian Hall65f7eb42021-11-22 16:06:42 +0100142 int pos = find_variable(context, guid, name_size, name);
143
144 if (pos >= 0) {
145
146 result = &context->entries[pos].info;
147 }
148
149 return result;
150}
151
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000152struct variable_info *variable_index_find_next(
Julian Hall65f7eb42021-11-22 16:06:42 +0100153 const struct variable_index *context,
154 const EFI_GUID *guid,
155 size_t name_size,
156 const int16_t *name)
157{
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000158 struct variable_info *result = NULL;
Julian Hall65f7eb42021-11-22 16:06:42 +0100159
160 if (name_size >= sizeof(int16_t)) {
161
162 /*
163 * Name must be at least one character long to accommodate
164 * the mandatory null terminator.
165 */
166 if (name[0] != 0) {
167
168 /* Find next from current name */
169 int pos = find_variable(context, guid, name_size, name);
170
171 if (pos >= 0) {
172
173 /* Iterate to next used entry */
174 ++pos;
175 while (pos < context->max_variables) {
176
Julian Hall0a86f762021-11-08 13:31:23 +0000177 if (context->entries[pos].in_use &&
178 context->entries[pos].info.is_variable_set) {
Julian Hall65f7eb42021-11-22 16:06:42 +0100179
180 result = &context->entries[pos].info;
181 break;
182 }
183
184 ++pos;
185 }
186 }
187 }
188 else {
189
190 /* Find first */
191 int pos = 0;
192
193 while (pos < context->max_variables) {
194
Julian Hall0a86f762021-11-08 13:31:23 +0000195 if (context->entries[pos].in_use &&
196 context->entries[pos].info.is_variable_set) {
Julian Hall65f7eb42021-11-22 16:06:42 +0100197
198 result = &context->entries[pos].info;
199 break;
200 }
201
202 ++pos;
203 }
204 }
205 }
206
207 return result;
208}
209
210static void set_variable_name(
211 struct variable_info *info,
212 size_t name_size,
213 const int16_t *name)
214{
215 size_t trimmed_size = 0;
216
217 /* Trim the saved name to only include a single null terminator.
218 * Any additional terminators included in the client-set name size
219 * are discarded.
220 */
221 for (size_t i = 0; i < name_size; i++) {
222
223 ++trimmed_size;
Julian Hall0a86f762021-11-08 13:31:23 +0000224 info->metadata.name[i] = name[i];
Julian Hall65f7eb42021-11-22 16:06:42 +0100225
226 if (!name[i]) break;
227 }
228
Julian Hall0a86f762021-11-08 13:31:23 +0000229 info->metadata.name_size = trimmed_size * sizeof(int16_t);
Julian Hall65f7eb42021-11-22 16:06:42 +0100230}
231
Julian Hall0a86f762021-11-08 13:31:23 +0000232static struct variable_entry *add_entry(
Julian Hall65f7eb42021-11-22 16:06:42 +0100233 struct variable_index *context,
234 const EFI_GUID *guid,
235 size_t name_size,
Julian Hall0a86f762021-11-08 13:31:23 +0000236 const int16_t *name)
Julian Hall65f7eb42021-11-22 16:06:42 +0100237{
Julian Hall0a86f762021-11-08 13:31:23 +0000238 struct variable_entry *entry = NULL;
Julian Hall65f7eb42021-11-22 16:06:42 +0100239
240 if (name_size <= (VARIABLE_INDEX_MAX_NAME_SIZE * sizeof(int16_t))) {
241
242 int pos = find_free(context);
243
244 if (pos >= 0) {
245
Julian Hall0a86f762021-11-08 13:31:23 +0000246 entry = &context->entries[pos];
Julian Hall65f7eb42021-11-22 16:06:42 +0100247
Julian Hall0a86f762021-11-08 13:31:23 +0000248 struct variable_info *info = &entry->info;
249
250 /* Initialize metadata */
251 info->metadata.uid = generate_uid(context, guid, name_size, name);
252 info->metadata.guid = *guid;
253 info->metadata.attributes = 0;
Julian Hall65f7eb42021-11-22 16:06:42 +0100254 set_variable_name(info, name_size, name);
255
Julian Hall0a86f762021-11-08 13:31:23 +0000256 info->is_constraints_set = false;
257 info->is_variable_set = false;
258
Julian Hall65f7eb42021-11-22 16:06:42 +0100259 entry->in_use = true;
260 }
261 }
262
Julian Hall0a86f762021-11-08 13:31:23 +0000263 return entry;
264}
265
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000266struct variable_info *variable_index_add_entry(
Julian Hall0a86f762021-11-08 13:31:23 +0000267 struct variable_index *context,
268 const EFI_GUID *guid,
269 size_t name_size,
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000270 const int16_t *name)
271{
272 struct variable_info *info = NULL;
273 struct variable_entry *entry = add_entry(context, guid, name_size, name);
274
275 if (entry) {
276
277 info = &entry->info;
278 }
279
280 return info;
281}
282
283void variable_index_remove_unused_entry(
284 struct variable_index *context,
285 struct variable_info *info)
286{
287 if (info &&
288 !info->is_constraints_set &&
289 !info->is_variable_set) {
290
291 struct variable_entry *entry = containing_entry(info);
292 entry->in_use = false;
293
294 memset(info, 0, sizeof(struct variable_info));
295 }
296}
297
298void variable_index_set_variable(
299 struct variable_info *info,
Julian Hall0a86f762021-11-08 13:31:23 +0000300 uint32_t attributes)
301{
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000302 struct variable_entry *entry = containing_entry(info);
Julian Hall0a86f762021-11-08 13:31:23 +0000303
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000304 info->metadata.attributes = attributes;
305 info->is_variable_set = true;
Julian Hall0a86f762021-11-08 13:31:23 +0000306
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000307 mark_dirty(entry);
Julian Hall65f7eb42021-11-22 16:06:42 +0100308}
309
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000310void variable_index_clear_variable(
Julian Hall0a86f762021-11-08 13:31:23 +0000311 struct variable_index *context,
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000312 struct variable_info *info)
Julian Hall65f7eb42021-11-22 16:06:42 +0100313{
Julian Hallc0d54dc2021-10-13 15:18:30 +0100314 if (info) {
Julian Hall65f7eb42021-11-22 16:06:42 +0100315
Julian Hallc0d54dc2021-10-13 15:18:30 +0100316 struct variable_entry *entry = containing_entry(info);
Julian Hall65f7eb42021-11-22 16:06:42 +0100317 mark_dirty(entry);
Julian Hall65f7eb42021-11-22 16:06:42 +0100318
Julian Hall0a86f762021-11-08 13:31:23 +0000319 /* Mark variable as no longer set */
320 entry->info.is_variable_set = false;
Julian Hall65f7eb42021-11-22 16:06:42 +0100321 }
322}
323
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000324void variable_index_set_constraints(
325 struct variable_info *info,
Julian Hall0a86f762021-11-08 13:31:23 +0000326 const struct variable_constraints *constraints)
327{
328 if (info) {
329
Julian Hall4b8dd0a2021-12-02 10:15:54 +0000330 info->check_constraints = *constraints;
331 info->is_constraints_set = true;
Julian Hall0a86f762021-11-08 13:31:23 +0000332 }
333}
334
Julian Hall65f7eb42021-11-22 16:06:42 +0100335bool variable_index_dump(
336 struct variable_index *context,
337 size_t buffer_size,
338 uint8_t *buffer,
339 size_t *data_len)
340{
341 bool any_dirty = false;
342 uint8_t *dump_pos = buffer;
343 size_t bytes_dumped = 0;
344
345 for (int pos = 0; pos < context->max_variables; pos++) {
346
347 struct variable_entry *entry = &context->entries[pos];
Julian Hall0a86f762021-11-08 13:31:23 +0000348 struct variable_metadata *metadata = &entry->info.metadata;
Julian Hall65f7eb42021-11-22 16:06:42 +0100349
350 if (entry->in_use &&
Julian Hall0a86f762021-11-08 13:31:23 +0000351 entry->info.is_variable_set &&
352 (metadata->attributes & EFI_VARIABLE_NON_VOLATILE) &&
353 ((bytes_dumped + sizeof(struct variable_metadata)) <= buffer_size)) {
Julian Hall65f7eb42021-11-22 16:06:42 +0100354
Julian Hall0a86f762021-11-08 13:31:23 +0000355 memcpy(dump_pos, metadata, sizeof(struct variable_metadata));
356 bytes_dumped += sizeof(struct variable_metadata);
357 dump_pos += sizeof(struct variable_metadata);
Julian Hall65f7eb42021-11-22 16:06:42 +0100358 }
359
360 any_dirty |= entry->dirty;
361 entry->dirty = false;
362 }
363
364 *data_len = bytes_dumped;
365
366 return any_dirty;
367}
368
369size_t variable_index_restore(
370 const struct variable_index *context,
371 size_t data_len,
372 const uint8_t *buffer)
373{
374 size_t bytes_loaded = 0;
375 const uint8_t *load_pos = buffer;
376 int pos = 0;
377
378 while (bytes_loaded < data_len) {
379
Julian Hall0a86f762021-11-08 13:31:23 +0000380 if ((data_len - bytes_loaded) >= sizeof(struct variable_metadata)) {
Julian Hall65f7eb42021-11-22 16:06:42 +0100381
382 struct variable_entry *entry = &context->entries[pos];
Julian Hall0a86f762021-11-08 13:31:23 +0000383 struct variable_metadata *metadata = &entry->info.metadata;
Julian Hall65f7eb42021-11-22 16:06:42 +0100384
Julian Hall0a86f762021-11-08 13:31:23 +0000385 memcpy(metadata, load_pos, sizeof(struct variable_metadata));
Julian Hall65f7eb42021-11-22 16:06:42 +0100386
Julian Hall0a86f762021-11-08 13:31:23 +0000387 entry->info.is_variable_set = true;
Julian Hall65f7eb42021-11-22 16:06:42 +0100388 entry->in_use = true;
389
Julian Hall0a86f762021-11-08 13:31:23 +0000390 bytes_loaded += sizeof(struct variable_metadata);
391 load_pos += sizeof(struct variable_metadata);
Julian Hall65f7eb42021-11-22 16:06:42 +0100392
393 ++pos;
394 }
395 else {
396
Julian Hall0a86f762021-11-08 13:31:23 +0000397 /* Not a whole number of variable_metadata structs! */
Julian Hall65f7eb42021-11-22 16:06:42 +0100398 break;
399 }
400 }
401
402 return bytes_loaded;
403}