]> git.proxmox.com Git - efi-boot-shim.git/blame - mock-variables.c
Try again with includes
[efi-boot-shim.git] / mock-variables.c
CommitLineData
8529e0f7
SM
1// SPDX-License-Identifier: BSD-2-Clause-Patent
2/*
3 * mock-variables.c - a mock GetVariable/SetVariable/GNVN/etc
4 * implementation for testing.
5 * Copyright Peter Jones <pjones@redhat.com>
6 */
7#include "shim.h"
8#include "mock-variables.h"
9
10#include <dirent.h>
11#include <efivar/efivar.h>
12#include <err.h>
13#include <fcntl.h>
14#include <inttypes.h>
15#include <stdio.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18
19#pragma GCC diagnostic ignored "-Wunused-parameter"
20#pragma GCC diagnostic ignored "-Wunused-function"
21
22list_t mock_default_variable_limits;
23list_t *mock_qvi_limits = &mock_default_variable_limits;
24list_t *mock_sv_limits = &mock_default_variable_limits;
25
26list_t mock_variables = LIST_HEAD_INIT(mock_variables);
27
28mock_sort_policy_t mock_variable_sort_policy = MOCK_SORT_APPEND;
29mock_sort_policy_t mock_config_table_sort_policy = MOCK_SORT_APPEND;
30
31UINT32 mock_variable_delete_attr_policy;
32
33mock_set_variable_pre_hook_t *mock_set_variable_pre_hook = NULL;
34mock_set_variable_post_hook_t *mock_set_variable_post_hook = NULL;
35mock_get_variable_pre_hook_t *mock_get_variable_pre_hook = NULL;
36mock_get_variable_post_hook_t *mock_get_variable_post_hook = NULL;
37mock_get_next_variable_name_pre_hook_t *mock_get_next_variable_name_pre_hook = NULL;
38mock_get_next_variable_name_post_hook_t *mock_get_next_variable_name_post_hook = NULL;
39mock_query_variable_info_pre_hook_t *mock_query_variable_info_pre_hook = NULL;
40mock_query_variable_info_post_hook_t *mock_query_variable_info_post_hook = NULL;
41
42static EFI_STATUS
43mock_sv_pre_hook(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size,
44 VOID *data)
45{
46 EFI_STATUS status = EFI_SUCCESS;
47 if (mock_set_variable_pre_hook)
48 status = mock_set_variable_pre_hook(name, guid,
49 attrs, size, data);
50 return status;
51}
52
53static void
54mock_sv_post_hook_(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size,
55 VOID *data, EFI_STATUS *status, mock_variable_op_t op,
56 const char * const file, const int line,
57 const char * const func)
58{
59 if (mock_set_variable_post_hook)
60 mock_set_variable_post_hook(name, guid, attrs, size,
61 data, status, op, file, line, func);
62}
63#define mock_sv_post_hook(name, guid, attrs, size, data, status, op) \
64 mock_sv_post_hook_(name, guid, attrs, size, data, status, op,\
65 __FILE__, __LINE__, __func__)
66
67static EFI_STATUS
68mock_gv_pre_hook(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size,
69 VOID *data)
70{
71 EFI_STATUS status = EFI_SUCCESS;
72 if (mock_get_variable_pre_hook)
73 status = mock_get_variable_pre_hook(name, guid,
74 attrs, size, data);
75 return status;
76}
77
78static void
79mock_gv_post_hook_(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size,
80 VOID *data, EFI_STATUS *status, const char * const file,
81 const int line, const char * const func)
82{
83 if (mock_get_variable_post_hook)
84 mock_get_variable_post_hook(name, guid, attrs, size, data,
85 status, file, line, func);
86}
87#define mock_gv_post_hook(name, guid, attrs, size, data, status) \
88 mock_gv_post_hook_(name, guid, attrs, size, data, status,\
89 __FILE__, __LINE__, __func__)
90
91static EFI_STATUS
92mock_gnvn_pre_hook(UINTN *size, CHAR16 *name, EFI_GUID *guid)
93{
94 EFI_STATUS status = EFI_SUCCESS;
95 if (mock_get_next_variable_name_pre_hook)
96 status = mock_get_next_variable_name_pre_hook(size, name, guid);
97 return status;
98}
99
100static void
101mock_gnvn_post_hook_(UINTN *size, CHAR16 *name, EFI_GUID *guid,
102 EFI_STATUS *status, const char * const file,
103 const int line, const char * const func)
104{
105 if (mock_get_next_variable_name_post_hook)
106 mock_get_next_variable_name_post_hook(size, name, guid, status,
107 file, line, func);
108}
109#define mock_gnvn_post_hook(size, name, guid, status) \
110 mock_gnvn_post_hook_(size, name, guid, status,\
111 __FILE__, __LINE__, __func__)
112
113static EFI_STATUS
114mock_qvi_pre_hook(UINT32 attrs, UINT64 *max_var_storage,
115 UINT64 *remaining_var_storage, UINT64 *max_var_size)
116{
117 EFI_STATUS status = EFI_SUCCESS;
118 if (mock_query_variable_info_pre_hook)
119 status = mock_query_variable_info_pre_hook(
120 attrs, max_var_storage,
121 remaining_var_storage, max_var_size);
122 return status;
123}
124
125static void
126mock_qvi_post_hook_(UINT32 attrs, UINT64 *max_var_storage,
127 UINT64 *remaining_var_storage, UINT64 *max_var_size,
128 EFI_STATUS *status, const char * const file,
129 const int line, const char * const func)
130{
131 if (mock_query_variable_info_post_hook)
132 mock_query_variable_info_post_hook(attrs, max_var_storage,
133 remaining_var_storage,
134 max_var_size, status,
135 file, line, func);
136}
137#define mock_qvi_post_hook(attrs, max_var_storage, remaining_var_storage,\
138 max_var_size, status) \
139 mock_qvi_post_hook_(attrs, max_var_storage, remaining_var_storage,\
140 max_var_size, status, \
141 __FILE__, __LINE__, __func__)
142
143static const size_t guidstr_size = sizeof("8be4df61-93ca-11d2-aa0d-00e098032b8c");
144
145static int
146variable_limits_cmp(const struct mock_variable_limits * const v0,
147 const struct mock_variable_limits * const v1)
148{
149 UINT32 mask = EFI_VARIABLE_NON_VOLATILE |
150 EFI_VARIABLE_BOOTSERVICE_ACCESS |
151 EFI_VARIABLE_RUNTIME_ACCESS;
152
153 return (v0->attrs & mask) - (v1->attrs & mask);
154}
155
156static INT64
157variable_cmp(const struct mock_variable * const v0,
158 const struct mock_variable * const v1)
159{
160 INT64 ret;
161 if (v0 == NULL || v1 == NULL)
162 return (uintptr_t)v0 - (uintptr_t)v1;
163
164 ret = CompareGuid(&v0->guid, &v1->guid);
165 ret <<= 8ul;
166#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
167 printf("%s:%d:%s(): "GUID_FMT" %s "GUID_FMT" (0x%011"PRIx64" %"PRId64")\n",
168 __FILE__, __LINE__-1, __func__,
169 GUID_ARGS(v0->guid),
170 ret < 0 ? "<" : (ret > 0 ? ">" : "="),
171 GUID_ARGS(v1->guid),
172 (UINT64)ret & 0x1fffffffffful,
173 ret);
174#endif
175 if (ret != 0) {
176 return ret;
177 }
178
179 ret = StrCmp(v0->name, v1->name);
180#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
181 printf("%s:%d:%s(): \"%s\" %s \"%s\" (0x%02hhx (%d)\n",
182 __FILE__, __LINE__-1, __func__,
183 Str2str(v0->name),
184 ret < 0 ? "<" : (ret > 0 ? ">" : "=="),
185 Str2str(v1->name),
186 ret, ret);
187#endif
188 return ret;
189}
190
191static char *
192list2var(list_t *pos)
193{
194 static char buf0[1024];
195 static char buf1[1024];
196 char *out;
197 static int n;
198 struct mock_variable *var;
199
200 out = n++ % 2 ? buf0 : buf1;
201 if (n > 1)
202 n -= 2;
203 SetMem(out, 1024, 0);
204 if (pos == &mock_variables) {
205 strcpy(out, "list tail");
206 return out;
207 }
208 var = list_entry(pos, struct mock_variable, list);
209 snprintf(out, 1023, GUID_FMT"-%s",
210 GUID_ARGS(var->guid),
211 Str2str(var->name));
212 return out;
213}
214
215EFI_STATUS EFIAPI
216mock_get_variable(CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size,
217 VOID *data)
218{
219 list_t *pos = NULL;
220 struct mock_variable goal = {
221 .name = name,
222 .guid = *guid,
223 };
224 struct mock_variable *result = NULL;
225 EFI_STATUS status;
226
227 status = mock_gv_pre_hook(name, guid, attrs, size, data);
228 if (EFI_ERROR(status))
229 return status;
230
231 if (name == NULL || guid == NULL || size == NULL) {
232 status = EFI_INVALID_PARAMETER;
233 mock_gv_post_hook(name, guid, attrs, size, data, &status);
234 return status;
235 }
236
237 list_for_each(pos, &mock_variables) {
238 struct mock_variable *var;
239
240 var = list_entry(pos, struct mock_variable, list);
241#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
242 printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n",
243 __FILE__, __LINE__-1, __func__,
244 GUID_ARGS(goal.guid), Str2str(goal.name),
245 GUID_ARGS(var->guid), Str2str(var->name));
246#endif
247 if (variable_cmp(&goal, var) == 0) {
248 if (attrs != NULL)
249 *attrs = var->attrs;
250 if (var->size > *size) {
251 *size = var->size;
252 status = EFI_BUFFER_TOO_SMALL;
253 mock_gv_post_hook(name, guid, attrs, size, data,
254 &status);
255 return status;
256 }
257 if (data == NULL) {
258 status = EFI_INVALID_PARAMETER;
259 mock_gv_post_hook(name, guid, attrs, size, data,
260 &status);
261 return status;
262 }
263 *size = var->size;
264 memcpy(data, var->data, var->size);
265 status = EFI_SUCCESS;
266 mock_gv_post_hook(name, guid, attrs, size, data,
267 &status);
268 return status;
269 }
270 }
271
272 status = EFI_NOT_FOUND;
273 mock_gv_post_hook(name, guid, attrs, size, data, &status);
274 return status;
275}
276
277static EFI_STATUS
278mock_gnvn_set_result(UINTN *size, CHAR16 *name, EFI_GUID *guid,
279 struct mock_variable *result)
280{
281 EFI_STATUS status;
282
283 if (*size < StrSize(result->name)) {
284 *size = StrSize(result->name);
285 status = EFI_BUFFER_TOO_SMALL;
286 mock_gnvn_post_hook(size, name, guid, &status);
287#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
288 printf("%s:%d:%s(): returning %lx\n",
289 __FILE__, __LINE__-1, __func__, status);
290#endif
291 return status;
292 }
293
294 *size = StrLen(result->name) + 1;
295 StrCpy(name, result->name);
296 memcpy(guid, &result->guid, sizeof(EFI_GUID));
297
298 status = EFI_SUCCESS;
299 mock_gnvn_post_hook(size, name, guid, &status);
300#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
301 printf("%s:%d:%s(): returning %lx\n",
302 __FILE__, __LINE__-1, __func__, status);
303#endif
304 return status;
305}
306
307EFI_STATUS EFIAPI
308mock_get_next_variable_name(UINTN *size, CHAR16 *name, EFI_GUID *guid)
309{
310 list_t *pos = NULL;
311 struct mock_variable goal = {
312 .name = name,
313 .guid = *guid,
314 };
315 struct mock_variable *result = NULL;
316 bool found = false;
317 EFI_STATUS status;
318
319 status = mock_gnvn_pre_hook(size, name, guid);
320 if (EFI_ERROR(status))
321 return status;
322
323 if (size == NULL || name == NULL || guid == NULL) {
324 status = EFI_INVALID_PARAMETER;
325 mock_gnvn_post_hook(size, name, guid, &status);
326 return status;
327 }
328
329 for (size_t i = 0; i < *size; i++) {
330 if (name[i] == 0) {
331 found = true;
332 break;
333 }
334 }
335
336 if (found == false) {
337 status = EFI_INVALID_PARAMETER;
338 mock_gnvn_post_hook(size, name, guid, &status);
339 return status;
340 }
341
342 found = false;
343#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
344 printf("%s:%d:%s():searching for "GUID_FMT"%s%s\n",
345 __FILE__, __LINE__-1, __func__,
346 GUID_ARGS(*guid),
347 name[0] == 0 ? "" : "-",
348 name[0] == 0 ? "" : Str2str(name));
349#endif
350 list_for_each(pos, &mock_variables) {
351 struct mock_variable *var;
352
353 var = list_entry(pos, struct mock_variable, list);
354#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
355 printf("%s:%d:%s(): candidate var:%p &var->guid:%p &var->list:%p\n",
356 __FILE__, __LINE__-1, __func__, var, &var->guid, &var->list);
357#endif
358 if (name[0] == 0) {
359 if (CompareGuid(&var->guid, guid) == 0) {
360#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
361 printf("%s:%d:%s(): found\n",
362 __FILE__, __LINE__-1, __func__);
363#endif
364 result = var;
365 found = true;
366 break;
367 }
368 } else {
369 if (found) {
370 if (CompareGuid(&var->guid, guid) == 0) {
371 result = var;
372 break;
373 }
374 continue;
375 }
376
377#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
378 printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n",
379 __FILE__, __LINE__-1, __func__,
380 GUID_ARGS(goal.guid), Str2str(goal.name),
381 GUID_ARGS(var->guid), Str2str(var->name));
382#endif
383 if (variable_cmp(&goal, var) == 0) {
384#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
385 printf("%s:%d:%s(): found\n",
386 __FILE__, __LINE__-1, __func__);
387#endif
388 found = true;
389 }
390 }
391 }
392#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
393 if (result) {
394 printf("%s:%d:%s(): found:%d result:%p &result->guid:%p &result->list:%p\n"
395 __FILE__, __LINE__-1, __func__, found, result,
396 &result->guid, &result->list);
397 printf("%s:%d:%s(): "GUID_FMT"-%s\n",
398 __FILE__, __LINE__-1, __func__, GUID_ARGS(result->guid),
399 Str2str(result->name));
400 } else {
401 printf("%s:%d:%s(): not found\n",
402 __FILE__, __LINE__-1, __func__);
403 }
404#endif
405
406 if (!found) {
407 if (name[0] == 0)
408 status = EFI_NOT_FOUND;
409 else
410 status = EFI_INVALID_PARAMETER;
411 mock_gnvn_post_hook(size, name, guid, &status);
412 return status;
413 }
414
415 if (!result) {
416 status = EFI_NOT_FOUND;
417 mock_gnvn_post_hook(size, name, guid, &status);
418 return status;
419 }
420
421 return mock_gnvn_set_result(size, name, guid, result);
422}
423
424static void
425free_var(struct mock_variable *var)
426{
427 if (!var)
428 return;
429#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
430 printf("%s:%d:%s(): var:%p &var->guid:%p ",
431 __FILE__, __LINE__-1, __func__,
432 var, var ? &var->guid : NULL);
433 if (var)
434 printf(GUID_FMT"-%s", GUID_ARGS(var->guid),
435 var->name ? Str2str(var->name) : "");
436 printf("\n");
437#endif
438 list_del(&var->list);
439 if (var->size && var->data)
440 free(var->data);
441 SetMem(var, sizeof(*var), 0);
442 free(var);
443}
444
445static bool
446mock_sv_attrs_match(UINT32 old, UINT32 new)
447{
448 UINT32 mask = ~EFI_VARIABLE_APPEND_WRITE;
449
450 return (old & mask) == (new & mask);
451}
452
453static EFI_STATUS
454mock_sv_adjust_usage_data(UINT32 attrs, size_t size, ssize_t change)
455{
456 const UINT32 bs = EFI_VARIABLE_BOOTSERVICE_ACCESS;
457 const UINT32 bs_nv = bs | EFI_VARIABLE_NON_VOLATILE;
458 const UINT32 bs_rt = bs | EFI_VARIABLE_RUNTIME_ACCESS;
459 const UINT32 bs_rt_nv = bs_nv | bs_rt;
460 struct mock_variable_limits goal = {
461 .attrs = attrs & bs_rt_nv,
462 };
463 struct mock_variable_limits *qvi_limits = NULL;
464 struct mock_variable_limits *sv_limits = NULL;
465 list_t var, *pos = NULL;
466 UINT64 remaining;
467
468 list_for_each(pos, mock_qvi_limits) {
469 struct mock_variable_limits *candidate;
470
471 candidate = list_entry(pos, struct mock_variable_limits, list);
472 if (variable_limits_cmp(&goal, candidate) == 0) {
473 qvi_limits = candidate;
474 break;
475 }
476 }
477
478 list_for_each(pos, mock_sv_limits) {
479 struct mock_variable_limits *candidate;
480
481 candidate = list_entry(pos, struct mock_variable_limits, list);
482 if (variable_limits_cmp(&goal, candidate) == 0) {
483 sv_limits = candidate;
484 break;
485 }
486 }
487 if (!sv_limits) {
488 return EFI_UNSUPPORTED;
489 }
490
491 if (sv_limits->status != EFI_SUCCESS)
492 return sv_limits->status;
493
494 if (*sv_limits->max_var_size < size) {
495#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
496 printf("%s:%d:%s():*sv_limits->max_var_size:%zu size:%zu\n",
497 __FILE__, __LINE__, __func__,
498 *sv_limits->max_var_size, size);
499#endif
500 return EFI_OUT_OF_RESOURCES;
501 }
502
503 if (change > 0 && (UINT64)change > *sv_limits->remaining_var_storage) {
504#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
505 printf("%s:%d:%s():*sv_limits->remaining_var_storage:%zu change:%zd\n",
506 __FILE__, __LINE__, __func__,
507 *sv_limits->remaining_var_storage, change);
508#endif
509 return EFI_OUT_OF_RESOURCES;
510 }
511
512 *sv_limits->remaining_var_storage += change;
513
514 if (qvi_limits) {
515 /*
516 * If the adjustment here is wrong, we don't want to not do
517 * the set variable, we also don't want to not account
518 * for it, and of course we can't have any integer UB. So
519 * just limit it safely and move on, even though that may
520 * result in wrong checks against QueryVariableInfo() later.
521 *
522 * As if there are correct checks against QueryVariableInfo()...
523 */
524 if (qvi_limits->remaining_var_storage == sv_limits->remaining_var_storage)
525 ;
526 else if (change < 0 && (UINT64)-change > *qvi_limits->remaining_var_storage)
527 *qvi_limits->remaining_var_storage = 0;
528 else if (change > 0 && UINT64_MAX - *qvi_limits->remaining_var_storage < (UINT64)change)
529 *qvi_limits->remaining_var_storage = UINT64_MAX;
530 else
531 *qvi_limits->remaining_var_storage += change;
532 }
533 return EFI_SUCCESS;
534}
535
536static EFI_STATUS
537mock_delete_variable(struct mock_variable *var)
538{
539 EFI_STATUS status;
540
541 status = mock_sv_adjust_usage_data(var->attrs, 0, - var->size);
542 if (EFI_ERROR(status)) {
543 printf("%s:%d:%s(): status:0x%lx\n",
544 __FILE__, __LINE__ - 1, __func__, status);
545 mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
546 var->data, &status, DELETE);
547 return status;
548 }
549
550 status = EFI_SUCCESS;
551 mock_sv_post_hook(var->name, &var->guid, var->attrs, 0, 0, &status,
552 DELETE);
553 free_var(var);
554 return status;
555}
556
557static EFI_STATUS
558mock_replace_variable(struct mock_variable *var, VOID *data, UINTN size)
559{
560 EFI_STATUS status;
561 VOID *new;
562
563 status = mock_sv_adjust_usage_data(var->attrs, size,
564 - var->size + size);
565 if (EFI_ERROR(status)) {
566 mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
567 var->data, &status, REPLACE);
568 return status;
569 }
570
571 new = calloc(1, size);
572 if (!new) {
573#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
574 printf("%s:%d:%s():calloc(1, %zu) failed\n",
575 __FILE__, __LINE__, __func__,
576 size);
577#endif
578 status = EFI_OUT_OF_RESOURCES;
579 mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
580 var->data, &status, REPLACE);
581 return status;
582 }
583 memcpy(new, data, size);
584 free(var->data);
585 var->data = new;
586 var->size = size;
587
588 status = EFI_SUCCESS;
589 mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
590 var->data, &status, REPLACE);
591 return status;
592}
593
594static EFI_STATUS
595mock_sv_extend(struct mock_variable *var, VOID *data, UINTN size)
596{
597 EFI_STATUS status;
598 uint8_t *new;
599
600 if (size == 0) {
601 status = EFI_SUCCESS;
602 mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
603 var->data, &status, APPEND);
604 return status;
605 }
606
607 status = mock_sv_adjust_usage_data(var->attrs, var->size + size, size);
608 if (EFI_ERROR(status)) {
609 mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
610 var->data, &status, APPEND);
611 return status;
612 }
613
614 new = realloc(var->data, var->size + size);
615 if (!new) {
616#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
617 printf("%s:%d:%s():realloc(%zu) failed\n",
618 __FILE__, __LINE__, __func__,
619 var->size + size);
620#endif
621 status = EFI_OUT_OF_RESOURCES;
622 mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
623 var->data, &status, APPEND);
624 return status;
625 }
626
627 memcpy(&new[var->size], data, size);
628 var->data = (void *)new;
629 var->size += size;
630
631 status = EFI_SUCCESS;
632 mock_sv_post_hook(var->name, &var->guid, var->attrs, var->size,
633 var->data, &status, APPEND);
634 return status;
635}
636
637void
638mock_print_var_list(list_t *head)
639{
640 list_t *pos = NULL;
641#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
642 printf("%s:%d:%s():variables so far:\n", __FILE__, __LINE__, __func__);
643#endif
644 list_for_each(pos, head) {
645 struct mock_variable *var = NULL;
646
647 var = list_entry(pos, struct mock_variable, list);
648#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
649 printf("%s:%d:%s(): "GUID_FMT"-%s (%lu bytes)\n",
650 __FILE__, __LINE__ - 1, __func__,
651 GUID_ARGS(var->guid), Str2str(var->name), var->size);
652#endif
653 }
654}
655
656static EFI_STATUS
657mock_new_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size,
658 VOID *data, struct mock_variable **out)
659{
660 EFI_STATUS status;
661 struct mock_variable *var;
662 uint8_t *buf;
663
664 if (size == 0) {
665 status = EFI_INVALID_PARAMETER;
666 return status;
667 }
668
669 status = EFI_OUT_OF_RESOURCES;
670 buf = calloc(1, sizeof(struct mock_variable) + StrSize(name));
671 if (!buf) {
672#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
673 printf("%s:%d:%s(): calloc(1, %zu) failed\n",
674 __FILE__, __LINE__, __func__,
675 sizeof(struct mock_variable) + StrSize(name));
676#endif
677 goto err;
678 }
679 var = (struct mock_variable *)buf;
680
681#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
682 printf("%s:%d:%s(): var:%p &var->guid:%p &var->list:%p\n",
683 __FILE__, __LINE__-1, __func__, var, &var->guid, &var->list);
684#endif
685
686 var->data = malloc(size);
687 if (!var->data)
688 goto err_free;
689
690 var->name = (CHAR16 *)&buf[sizeof(*var)];
691 StrCpy(var->name, name);
692 memcpy(&var->guid, guid, sizeof(EFI_GUID));
693 memcpy(var->data, data, size);
694 var->size = size;
695 var->attrs = attrs;
696 INIT_LIST_HEAD(&var->list);
697
698#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
699 printf("%s:%d:%s(): var: "GUID_FMT"-%s\n",
700 __FILE__, __LINE__-1, __func__,
701 GUID_ARGS(var->guid), Str2str(var->name));
702#endif
703
704 *out = var;
705 status = EFI_SUCCESS;
706err_free:
707 if (EFI_ERROR(status))
708 free_var(var);
709err:
710 return status;
711}
712
713EFI_STATUS EFIAPI
714mock_set_variable(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size,
715 VOID *data)
716{
717 list_t *pos = NULL, *tmp = NULL, *var_list = NULL;
718 struct mock_variable goal = {
719 .name = name,
720 .guid = *guid,
721 };
722 struct mock_variable *var = NULL;
723 bool found = false;
724 bool add_tail = true;
725 EFI_STATUS status;
726 long cmp = -1;
727
728 status = mock_sv_pre_hook(name, guid, attrs, size, data);
729 if (EFI_ERROR(status))
730 return status;
731
732 if (!name || name[0] == 0 || !guid) {
733 status = EFI_INVALID_PARAMETER;
734 mock_sv_post_hook(name, guid, attrs, size, data, &status,
735 CREATE);
736 return status;
737 }
738
739 if ((attrs & EFI_VARIABLE_RUNTIME_ACCESS) &&
740 !(attrs & EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
741 status = EFI_INVALID_PARAMETER;
742 mock_sv_post_hook(name, guid, attrs, size, data, &status,
743 CREATE);
744 return status;
745 }
746
747#if 0
748 /*
749 * We don't ever operate after ExitBootServices(), so I'm not
750 * checking for the missing EFI_VARIABLE_RUNTIME_ACCESS case
751 */
752 if (has_exited_boot_services() && !(attrs & EFI_VARIABLE_RUNTIME_ACCESS)) {
753 status = EFI_INVALID_PARAMETER;
754 mock_sv_post_hook(name, guid, attrs, size, data, &status,
755 CREATE);
756 return status;
757 }
758#endif
759
760#if 0
761 /*
762 * For now, we're ignoring that we don't support these.
763 */
764 if (attrs & (EFI_VARIABLE_HARDWARE_ERROR_RECORD |
765 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
766 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS |
767 EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS)) {
768 status = EFI_UNSUPPORTED;
769 mock_sv_post_hook(name, guid, attrs, size, data, &status,
770 CREATE);
771 return status;
772 }
773#endif
774
775#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
776 printf("%s:%d:%s():Setting "GUID_FMT"-%s\n",
777 __FILE__, __LINE__ - 1, __func__,
778 GUID_ARGS(*guid), Str2str(name));
779#endif
780 switch (mock_variable_sort_policy) {
781 case MOCK_SORT_PREPEND:
782 var_list = &mock_variables;
783 add_tail = false;
784 break;
785 case MOCK_SORT_APPEND:
786 var_list = &mock_variables;
787 add_tail = true;
788 break;
789 case MOCK_SORT_DESCENDING:
790 add_tail = true;
791 break;
792 case MOCK_SORT_ASCENDING:
793 add_tail = true;
794 break;
795 default:
796 break;
797 }
798
799 pos = &mock_variables;
800 list_for_each_safe(pos, tmp, &mock_variables) {
801 found = false;
802 var = list_entry(pos, struct mock_variable, list);
803#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
804 printf("%s:%d:%s(): varcmp("GUID_FMT"-%s, "GUID_FMT"-%s)\n",
805 __FILE__, __LINE__-1, __func__,
806 GUID_ARGS(goal.guid), Str2str(goal.name),
807 GUID_ARGS(var->guid), Str2str(var->name));
808#endif
809 cmp = variable_cmp(&goal, var);
810 cmp = cmp < 0 ? -1 : (cmp > 0 ? 1 : 0);
811
812 switch (mock_variable_sort_policy) {
813 case MOCK_SORT_DESCENDING:
814 if (cmp >= 0) {
815 var_list = pos;
816 found = true;
817 }
818 break;
819 case MOCK_SORT_ASCENDING:
820 if (cmp <= 0) {
821 var_list = pos;
822 found = true;
823 }
824 break;
825 default:
826 if (cmp == 0) {
827 var_list = pos;
828 found = true;
829 }
830 break;
831 }
832 if (found)
833 break;
834 }
835#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
836 printf("%s:%d:%s():var_list:%p &mock_variables:%p cmp:%ld\n",
837 __FILE__, __LINE__ - 1, __func__,
838 var_list, &mock_variables, cmp);
839#endif
840 if (cmp != 0 || (cmp == 0 && var_list == &mock_variables)) {
841 size_t totalsz = size + StrSize(name);
842#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
843 printf("%s:%d:%s():var:%p attrs:0x%lx\n",
844 __FILE__, __LINE__ - 1, __func__, var, attrs);
845#endif
846 status = mock_new_variable(name, guid, attrs, size, data, &var);
847 if (EFI_ERROR(status)) {
848 mock_sv_post_hook(name, guid, attrs, size, data,
849 &status, CREATE);
850 return status;
851 }
852 mock_sv_adjust_usage_data(attrs, size, totalsz);
853 mock_sv_post_hook(name, guid, attrs, size, data,
854 &status, CREATE);
855 if (EFI_ERROR(status)) {
856 mock_sv_adjust_usage_data(attrs, 0, -totalsz);
857 return status;
858 }
859
860#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
861 printf("%s:%d:%s(): Adding "GUID_FMT"-%s %s %s\n",
862 __FILE__, __LINE__ - 1, __func__,
863 GUID_ARGS(var->guid), Str2str(var->name),
864 add_tail ? "after" : "before",
865 list2var(pos));
866#endif
867 if (add_tail)
868 list_add_tail(&var->list, pos);
869 else
870 list_add(&var->list, pos);
871 return status;
872 }
873
874 var = list_entry(var_list, struct mock_variable, list);
875#if defined(SHIM_DEBUG) && SHIM_DEBUG != 0
876 printf("%s:%d:%s():var:%p attrs:%s cmp:%ld size:%ld\n",
877 __FILE__, __LINE__ - 1, __func__,
878 var, format_var_attrs(var->attrs), cmp, size);
879#endif
880 if (!mock_sv_attrs_match(var->attrs, attrs)) {
881 status = EFI_INVALID_PARAMETER;
882 if (size == 0 && !(attrs & EFI_VARIABLE_APPEND_WRITE)) {
883 if ((mock_variable_delete_attr_policy & MOCK_VAR_DELETE_ATTR_ALLOW_ZERO)
884 && attrs == 0) {
885 status = EFI_SUCCESS;
886 } else if (mock_variable_delete_attr_policy & MOCK_VAR_DELETE_ATTR_ALOW_MISMATCH) {
887 status = EFI_SUCCESS;
888 }
889 }
890 if (EFI_ERROR(status)) {
891 printf("%s:%d:%s(): var->attrs:%s attrs:%s\n",
892 __FILE__, __LINE__ - 1, __func__,
893 format_var_attrs(var->attrs),
894 format_var_attrs(attrs));
895 mock_sv_post_hook(name, guid, attrs, size, data,
896 &status, REPLACE);
897 return status;
898 }
899 }
900
901 if (attrs & EFI_VARIABLE_APPEND_WRITE)
902 return mock_sv_extend(var, data, size);
903
904 if (size == 0) {
905 UINT32 mask = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
906 | EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS;
907 /*
908 * We can't process deletes on these correctly unless we
909 * parse the header.
910 */
911 if (attrs & mask) {
912 return EFI_INVALID_PARAMETER;
913 }
914
915 return mock_delete_variable(var);
916 }
917
918 return mock_replace_variable(var, data, size);
919}
920
921EFI_STATUS EFIAPI
922mock_query_variable_info(UINT32 attrs, UINT64 *max_var_storage,
923 UINT64 *remaining_var_storage, UINT64 *max_var_size)
924{
925 list_t mvl, *pos = NULL;
926 struct mock_variable_limits goal = {
927 .attrs = attrs,
928 };
929 struct mock_variable_limits *limits = NULL;
930 EFI_STATUS status;
931
932 status = mock_qvi_pre_hook(attrs, max_var_storage,
933 remaining_var_storage, max_var_size);
934 if (EFI_ERROR(status))
935 return status;
936
937 if (max_var_storage == NULL ||
938 remaining_var_storage == NULL ||
939 max_var_size == NULL) {
940 status = EFI_INVALID_PARAMETER;
941 mock_qvi_post_hook(attrs, max_var_storage,
942 remaining_var_storage, max_var_size,
943 &status);
944 return status;
945 }
946
947 list_for_each(pos, mock_qvi_limits) {
948 limits = list_entry(pos, struct mock_variable_limits, list);
949 if (variable_limits_cmp(&goal, limits) == 0) {
950 *max_var_storage = *limits->max_var_storage;
951 *remaining_var_storage = *limits->remaining_var_storage;
952 *max_var_size = *limits->max_var_size;
953
954 status = EFI_SUCCESS;
955 mock_qvi_post_hook(attrs, max_var_storage,
956 remaining_var_storage, max_var_size,
957 &status);
958 return status;
959 }
960 }
961
962 status = EFI_UNSUPPORTED;
963 mock_qvi_post_hook(attrs, max_var_storage, remaining_var_storage,
964 max_var_size, &status);
965 return status;
966}
967
968static UINT64 default_max_var_storage;
969static UINT64 default_remaining_var_storage;
970static UINT64 default_max_var_size;
971
972static struct mock_variable_limits default_limits[] = {
973 {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS,
974 .max_var_storage = &default_max_var_storage,
975 .remaining_var_storage = &default_remaining_var_storage,
976 .max_var_size = &default_max_var_size,
977 .status = EFI_SUCCESS,
978 },
979 {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
980 EFI_VARIABLE_RUNTIME_ACCESS,
981 .max_var_storage = &default_max_var_storage,
982 .remaining_var_storage = &default_remaining_var_storage,
983 .max_var_size = &default_max_var_size,
984 .status = EFI_SUCCESS,
985 },
986 {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
987 EFI_VARIABLE_NON_VOLATILE,
988 .max_var_storage = &default_max_var_storage,
989 .remaining_var_storage = &default_remaining_var_storage,
990 .max_var_size = &default_max_var_size,
991 .status = EFI_SUCCESS,
992 },
993 {.attrs = EFI_VARIABLE_BOOTSERVICE_ACCESS |
994 EFI_VARIABLE_RUNTIME_ACCESS |
995 EFI_VARIABLE_NON_VOLATILE,
996 .max_var_storage = &default_max_var_storage,
997 .remaining_var_storage = &default_remaining_var_storage,
998 .max_var_size = &default_max_var_size,
999 .status = EFI_SUCCESS,
1000 },
1001 {.attrs = 0, }
1002};
1003
1004void
1005mock_set_default_usage_limits(void)
1006{
1007 default_max_var_storage = 65536;
1008 default_remaining_var_storage = 65536;
1009 default_max_var_size = 32768;
1010
1011 INIT_LIST_HEAD(&mock_default_variable_limits);
1012 for (size_t i = 0; default_limits[i].attrs != 0; i++) {
1013 INIT_LIST_HEAD(&default_limits[i].list);
1014 list_add_tail(&default_limits[i].list,
1015 &mock_default_variable_limits);
1016 }
1017}
1018
1019void
1020mock_load_one_variable(int dfd, const char * const dirname, char * const name)
1021{
1022 int fd;
1023 FILE *f;
1024 int rc;
1025 struct stat statbuf;
1026 size_t guidlen, namelen;
1027 efi_guid_t guid;
1028 size_t sz;
1029 ssize_t offset = 0;
1030 EFI_STATUS status;
1031 UINT32 attrs;
1032
1033 rc = fstatat(dfd, name, &statbuf, 0);
1034 if (rc < 0)
1035 err(2, "Could not stat \"%s/%s\"", dirname, name);
1036
1037 if (!(S_ISREG(statbuf.st_mode)))
1038 return;
1039
1040 if (statbuf.st_size < 5)
1041 errx(2, "Test data variable \"%s/%s\" is too small (%ld bytes)",
1042 dirname, name, statbuf.st_size);
1043
1044#if 0
1045 mock_print_var_list(&mock_variables);
1046#endif
1047
1048 uint8_t buf[statbuf.st_size];
1049
1050 fd = openat(dfd, name, O_RDONLY);
1051 if (fd < 0)
1052 err(2, "Could not open \"%s/%s\"", dirname, name);
1053
1054 f = fdopen(fd, "r");
1055 if (!f)
1056 err(2, "Could not open \"%s/%s\"", dirname, name);
1057
1058 while (offset != statbuf.st_size) {
1059 sz = fread(buf + offset, 1, statbuf.st_size - offset, f);
1060 if (sz == 0) {
1061 if (ferror(f))
1062 err(2, "Could not read from \"%s/%s\"",
1063 dirname, name);
1064 if (feof(f))
1065 errx(2, "Unexpected end of file reading \"%s/%s\"",
1066 dirname, name);
1067 }
1068
1069 offset += sz;
1070 }
1071
1072 guidlen = strlen("8be4df61-93ca-11d2-aa0d-00e098032b8c");
1073 namelen = strlen(name) - guidlen;
1074
1075 if (namelen < 2)
1076 errx(2, "namelen for \"%s\" is %zu!?!", name, namelen);
1077
1078 CHAR16 namebuf[namelen];
1079
1080 name[namelen-1] = 0;
1081#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
1082 printf("loading %s-%s\n", &name[namelen], name);
1083#endif
1084 for (size_t i = 0; i < namelen; i++)
1085 namebuf[i] = name[i];
1086
1087 rc = efi_str_to_guid(&name[namelen], &guid);
1088 if (rc < 0)
1089 err(2, "Could not parse \"%s\" as EFI GUID", &name[namelen]);
1090
1091 memcpy(&attrs, (UINT32 *)buf, sizeof(UINT32));
1092
1093 status = RT->SetVariable(namebuf, (EFI_GUID *)&guid, attrs,
1094 statbuf.st_size - sizeof(attrs),
1095 &buf[sizeof(attrs)]);
1096 if (EFI_ERROR(status))
1097 errx(2, "%s:%d:%s(): Could not set variable: 0x%llx",
1098 __FILE__, __LINE__ - 1, __func__,
1099 (unsigned long long)status);
1100
1101 fclose(f);
1102}
1103
1104void
1105mock_load_variables(const char *const dirname, const char *filters[],
1106 bool filter_out)
1107{
1108 int dfd;
1109 DIR *d;
1110 struct dirent *entry;
1111
1112 d = opendir(dirname);
1113 if (!d)
1114 err(1, "Could not open directory \"%s\"", dirname);
1115
1116 dfd = dirfd(d);
1117 if (dfd < 0)
1118 err(1, "Could not get directory file descriptor for \"%s\"",
1119 dirname);
1120
1121 while ((entry = readdir(d)) != NULL) {
1122 size_t len = strlen(entry->d_name);
1123 bool found = false;
1124 if (filters && len > guidstr_size + 1) {
1125 char spacebuf[len];
1126
1127 len -= guidstr_size;
1128 SetMem(spacebuf, sizeof(spacebuf)-1, ' ');
1129 spacebuf[len] = '\0';
1130 for (size_t i = 0; filters[i]; i++) {
1131 if (strlen(filters[i]) > len)
1132 continue;
1133 if (!strncmp(entry->d_name, filters[i], len)) {
1134 found = true;
1135 break;
1136 }
1137 }
1138 }
1139 if ((found == false && filter_out == true) ||
1140 (found == true && filter_out == false)) {
1141 mock_load_one_variable(dfd, dirname, entry->d_name);
1142 }
1143 }
1144
1145 closedir(d);
1146#if 0
1147 mock_print_var_list(&mock_variables);
1148#endif
1149}
1150
1151static bool qvi_installed = false;
1152
1153void
1154mock_install_query_variable_info(void)
1155{
1156 qvi_installed = true;
1157 RT->Hdr.Revision = 2ul << 16ul;
1158 RT->QueryVariableInfo = mock_query_variable_info;
1159}
1160
1161void
1162mock_uninstall_query_variable_info(void)
1163{
1164 qvi_installed = false;
1165 RT->Hdr.Revision = EFI_1_10_SYSTEM_TABLE_REVISION;
1166 RT->QueryVariableInfo = mock_efi_unsupported;
1167}
1168
1169EFI_CONFIGURATION_TABLE mock_config_table[MOCK_CONFIG_TABLE_ENTRIES] = {
1170 {
1171 .VendorGuid = { 0, },
1172 .VendorTable = NULL
1173 },
1174};
1175
1176int
1177mock_config_table_cmp(const void *p0, const void *p1)
1178{
1179 EFI_CONFIGURATION_TABLE *entry0, *entry1;
1180 long cmp;
1181
1182 if (!p0 || !p1) {
1183 cmp = (int)((intptr_t)p0 - (intptr_t)p1);
1184 } else {
1185 entry0 = (EFI_CONFIGURATION_TABLE *)p0;
1186 entry1 = (EFI_CONFIGURATION_TABLE *)p1;
1187#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
1188 printf("comparing %p to %p\n", p0, p1);
1189#endif
1190 cmp = CompareGuid(&entry0->VendorGuid, &entry1->VendorGuid);
1191 }
1192
1193 if (mock_config_table_sort_policy == MOCK_SORT_DESCENDING) {
1194 cmp = -cmp;
1195 }
1196
1197 return cmp;
1198}
1199
1200EFI_STATUS EFIAPI
1201mock_install_configuration_table(EFI_GUID *guid, VOID *table)
1202{
1203 bool found = false;
1204 EFI_CONFIGURATION_TABLE *entry;
1205 int idx = 0;
1206 size_t sz;
1207
1208 if (!guid)
1209 return EFI_INVALID_PARAMETER;
1210
1211 for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) {
1212 EFI_CONFIGURATION_TABLE *entry = &ST->ConfigurationTable[i];
1213
1214 if (CompareGuid(guid, &entry->VendorGuid) == 0) {
1215 found = true;
1216 if (table) {
1217 // replace it
1218 entry->VendorTable = table;
1219 } else {
1220 // delete it
1221 ST->NumberOfTableEntries -= 1;
1222 sz = ST->NumberOfTableEntries - i;
1223 sz *= sizeof(*entry);
1224 memmove(&entry[0], &entry[1], sz);
1225 }
1226 return EFI_SUCCESS;
1227 }
1228 }
1229 if (!found && table == NULL)
1230 return EFI_NOT_FOUND;
1231 if (ST->NumberOfTableEntries == MOCK_CONFIG_TABLE_ENTRIES - 1) {
1232 /*
1233 * If necessary, we could allocate another table and copy
1234 * the data, but I'm lazy and we probably don't need to.
1235 */
1236 return EFI_OUT_OF_RESOURCES;
1237 }
1238
1239 switch (mock_config_table_sort_policy) {
1240 case MOCK_SORT_DESCENDING:
1241 case MOCK_SORT_ASCENDING:
1242 case MOCK_SORT_APPEND:
1243 idx = ST->NumberOfTableEntries;
1244 break;
1245 case MOCK_SORT_PREPEND:
1246 sz = ST->NumberOfTableEntries ? ST->NumberOfTableEntries : 0;
1247 sz *= sizeof(ST->ConfigurationTable[0]);
1248 memmove(&ST->ConfigurationTable[1], &ST->ConfigurationTable[0], sz);
1249 idx = 0;
1250 break;
1251 default:
1252 break;
1253 }
1254
1255 entry = &ST->ConfigurationTable[idx];
1256 memcpy(&entry->VendorGuid, guid, sizeof(EFI_GUID));
1257 entry->VendorTable = table;
1258#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
1259 printf("%s:%d:%s(): installing entry %p={%p,%p} as entry %d\n",
1260 __FILE__, __LINE__, __func__,
1261 entry, &entry->VendorGuid, entry->VendorTable, idx);
1262#endif
1263 ST->NumberOfTableEntries += 1;
1264
1265#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
1266 printf("%s:%d:%s():ST->ConfigurationTable:%p\n"
1267 "\t[%d]:%p\n"
1268 "\t[%d]:%p\n",
1269 __FILE__, __LINE__, __func__, ST->ConfigurationTable,
1270 0, &ST->ConfigurationTable[0],
1271 1, &ST->ConfigurationTable[1]);
1272#endif
1273 switch (mock_config_table_sort_policy) {
1274 case MOCK_SORT_DESCENDING:
1275 case MOCK_SORT_ASCENDING:
1276#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
1277 printf("%s:%d:%s(): entries before sorting:\n", __FILE__, __LINE__, __func__);
1278 for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) {
1279 printf("\t[%d] = %p = {", i, &ST->ConfigurationTable[i]);
1280 printf(".VendorGuid=" GUID_FMT, GUID_ARGS(ST->ConfigurationTable[i].VendorGuid));
1281 printf(".VendorTable=%p}\n", ST->ConfigurationTable[i].VendorTable);
1282 }
1283#endif
1284 qsort(&ST->ConfigurationTable[0], ST->NumberOfTableEntries,
1285 sizeof(ST->ConfigurationTable[0]),
1286 mock_config_table_cmp);
1287 break;
1288 default:
1289 break;
1290 }
1291#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
1292 printf("%s:%d:%s(): entries:\n", __FILE__, __LINE__, __func__);
1293 for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) {
1294 printf("\t[%d] = %p = {", i, &ST->ConfigurationTable[i]);
1295 printf(".VendorGuid=" GUID_FMT, GUID_ARGS(ST->ConfigurationTable[i].VendorGuid));
1296 printf(".VendorTable=%p}\n", ST->ConfigurationTable[i].VendorTable);
1297 }
1298#endif
1299
1300 return EFI_SUCCESS;
1301}
1302
1303void CONSTRUCTOR
1304mock_reset_variables(void)
1305{
1306 list_t *pos = NULL, *tmp = NULL;
1307 static bool once = true;
1308
1309 init_efi_system_table();
1310
1311 mock_set_variable_pre_hook = NULL;
1312 mock_set_variable_post_hook = NULL;
1313 mock_get_variable_pre_hook = NULL;
1314 mock_get_variable_post_hook = NULL;
1315 mock_get_next_variable_name_pre_hook = NULL;
1316 mock_get_next_variable_name_post_hook = NULL;
1317 mock_query_variable_info_pre_hook = NULL;
1318 mock_query_variable_info_post_hook = NULL;
1319
1320 if (once) {
1321 INIT_LIST_HEAD(&mock_variables);
1322 once = false;
1323#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
1324 printf("%s:%d:%s():mock_variables = {%p,%p};\n",
1325 __FILE__, __LINE__-1, __func__,
1326 mock_variables.next,
1327 mock_variables.prev);
1328 printf("%s:%d:%s():list_empty(&mock_variables):%d\n",
1329 __FILE__, __LINE__-1, __func__, list_empty(&mock_variables));
1330 printf("%s:%d:%s():list_size(&mock_variables):%d\n",
1331 __FILE__, __LINE__-1, __func__, list_size(&mock_variables));
1332#endif
1333 }
1334
1335 list_for_each_safe(pos, tmp, &mock_variables) {
1336 struct mock_variable *var = NULL;
1337 var = list_entry(pos, struct mock_variable, list);
1338
1339#if (defined(SHIM_DEBUG) && SHIM_DEBUG != 0)
1340 printf("%s:%d:%s():var:"GUID_FMT"-%s\n",
1341 __FILE__, __LINE__-1, __func__,
1342 GUID_ARGS(var->guid), Str2str(var->name));
1343#endif
1344 mock_delete_variable(var);
1345 }
1346 INIT_LIST_HEAD(&mock_variables);
1347 mock_set_default_usage_limits();
1348
1349 mock_variable_delete_attr_policy = MOCK_VAR_DELETE_ATTR_ALLOW_ZERO;
1350
1351 RT->GetVariable = mock_get_variable;
1352 RT->GetNextVariableName = mock_get_next_variable_name;
1353 RT->SetVariable = mock_set_variable;
1354 if (qvi_installed)
1355 mock_install_query_variable_info();
1356 else
1357 mock_uninstall_query_variable_info();
1358}
1359
1360void CONSTRUCTOR
1361mock_reset_config_table(void)
1362{
1363 init_efi_system_table();
1364
1365 /*
1366 * Note that BS->InstallConfigurationTable() is *not* defined as
1367 * freeing these. If a test case installs non-malloc()ed tables,
1368 * it needs to call BS->InstallConfigurationTable(guid, NULL) to
1369 * clear them.
1370 */
1371 for (UINTN i = 0; i < ST->NumberOfTableEntries; i++) {
1372 EFI_CONFIGURATION_TABLE *entry = &ST->ConfigurationTable[i];
1373
1374 if (entry->VendorTable)
1375 free(entry->VendorTable);
1376 }
1377
1378 SetMem(ST->ConfigurationTable,
1379 ST->NumberOfTableEntries * sizeof(EFI_CONFIGURATION_TABLE),
1380 0);
1381
1382 ST->NumberOfTableEntries = 0;
1383
1384 if (ST->ConfigurationTable != mock_config_table) {
1385 free(ST->ConfigurationTable);
1386 ST->ConfigurationTable = mock_config_table;
1387 SetMem(mock_config_table, sizeof(mock_config_table), 0);
1388 }
1389
1390 BS->InstallConfigurationTable = mock_install_configuration_table;
1391}
1392
1393void DESTRUCTOR
1394mock_finalize_vars_and_configs(void)
1395{
1396 mock_reset_variables();
1397 mock_reset_config_table();
1398}
1399
1400// vim:fenc=utf-8:tw=75:noet