Merge git://git.denx.de/u-boot-rockchip
[oweals/u-boot.git] / lib / efi_selftest / efi_selftest_exitbootservices.c
1 /*
2  * efi_selftest_events
3  *
4  * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  *
8  * This unit test checks that the notification function of an
9  * EVT_SIGNAL_EXIT_BOOT_SERVICES event is called exactly once.
10  */
11
12 #include <efi_selftest.h>
13
14 static struct efi_boot_services *boottime;
15 static struct efi_event *event_notify;
16 static unsigned int counter;
17
18 /*
19  * Notification function, increments a counter.
20  *
21  * @event       notified event
22  * @context     pointer to the counter
23  */
24 static void EFIAPI notify(struct efi_event *event, void *context)
25 {
26         if (!context)
27                 return;
28         ++*(unsigned int *)context;
29 }
30
31 /*
32  * Setup unit test.
33  *
34  * Create an EVT_SIGNAL_EXIT_BOOT_SERVICES event.
35  *
36  * @handle:     handle of the loaded image
37  * @systable:   system table
38  */
39 static int setup(const efi_handle_t handle,
40                  const struct efi_system_table *systable)
41 {
42         efi_status_t ret;
43
44         boottime = systable->boottime;
45
46         counter = 0;
47         ret = boottime->create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES,
48                                      TPL_CALLBACK, notify, (void *)&counter,
49                                      &event_notify);
50         if (ret != EFI_SUCCESS) {
51                 efi_st_error("could not create event\n");
52                 return 1;
53         }
54         return 0;
55 }
56
57 /*
58  * Tear down unit test.
59  *
60  * Close the event created in setup.
61  */
62 static int teardown(void)
63 {
64         efi_status_t ret;
65
66         if (event_notify) {
67                 ret = boottime->close_event(event_notify);
68                 event_notify = NULL;
69                 if (ret != EFI_SUCCESS) {
70                         efi_st_error("could not close event\n");
71                         return 1;
72                 }
73         }
74         return 0;
75 }
76
77 /*
78  * Execute unit test.
79  *
80  * Check that the notification function of the EVT_SIGNAL_EXIT_BOOT_SERVICES
81  * event has been called.
82  *
83  * Call ExitBootServices again and check that the notification function is
84  * not called again.
85  */
86 static int execute(void)
87 {
88         if (counter != 1) {
89                 efi_st_error("ExitBootServices was not notified");
90                 return 1;
91         }
92         efi_st_exit_boot_services();
93         if (counter != 1) {
94                 efi_st_error("ExitBootServices was notified twice");
95                 return 1;
96         }
97         return 0;
98 }
99
100 EFI_UNIT_TEST(exitbootservices) = {
101         .name = "ExitBootServices",
102         .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
103         .setup = setup,
104         .execute = execute,
105         .teardown = teardown,
106 };