Merge git://git.denx.de/u-boot-sunxi
[platform/kernel/u-boot.git] / lib / efi_selftest / efi_selftest_events.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 uses timer events to check the implementation
9  * of the following boottime services:
10  * CreateEvent, CloseEvent, WaitForEvent, CheckEvent, SetTimer.
11  */
12
13 #include <efi_selftest.h>
14
15 static struct efi_event *event_notify;
16 static struct efi_event *event_wait;
17 static unsigned int timer_ticks;
18 static struct efi_boot_services *boottime;
19
20 /*
21  * Notification function, increments the notfication count if parameter
22  * context is provided.
23  *
24  * @event       notified event
25  * @context     pointer to the notification count
26  */
27 static void EFIAPI notify(struct efi_event *event, void *context)
28 {
29         unsigned int *count = context;
30
31         if (count)
32                 ++*count;
33 }
34
35 /*
36  * Setup unit test.
37  *
38  * Create two timer events.
39  * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT.
40  *
41  * @handle:     handle of the loaded image
42  * @systable:   system table
43  * @return:     EFI_ST_SUCCESS for success
44  */
45 static int setup(const efi_handle_t handle,
46                  const struct efi_system_table *systable)
47 {
48         efi_status_t ret;
49
50         boottime = systable->boottime;
51
52         ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL,
53                                      TPL_CALLBACK, notify, (void *)&timer_ticks,
54                                      &event_notify);
55         if (ret != EFI_SUCCESS) {
56                 efi_st_error("could not create event\n");
57                 return EFI_ST_FAILURE;
58         }
59         ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT,
60                                      TPL_CALLBACK, notify, NULL, &event_wait);
61         if (ret != EFI_SUCCESS) {
62                 efi_st_error("could not create event\n");
63                 return EFI_ST_FAILURE;
64         }
65         return EFI_ST_SUCCESS;
66 }
67
68 /*
69  * Tear down unit test.
70  *
71  * Close the events created in setup.
72  *
73  * @return:     EFI_ST_SUCCESS for success
74  */
75 static int teardown(void)
76 {
77         efi_status_t ret;
78
79         if (event_notify) {
80                 ret = boottime->close_event(event_notify);
81                 event_notify = NULL;
82                 if (ret != EFI_SUCCESS) {
83                         efi_st_error("could not close event\n");
84                         return EFI_ST_FAILURE;
85                 }
86         }
87         if (event_wait) {
88                 ret = boottime->close_event(event_wait);
89                 event_wait = NULL;
90                 if (ret != EFI_SUCCESS) {
91                         efi_st_error("could not close event\n");
92                         return EFI_ST_FAILURE;
93                 }
94         }
95         return EFI_ST_SUCCESS;
96 }
97
98 /*
99  * Execute unit test.
100  *
101  * Run a 10 ms periodic timer and check that it is called 10 times
102  * while waiting for 100 ms single shot timer.
103  *
104  * Run a 100 ms single shot timer and check that it is called once
105  * while waiting for 100 ms periodic timer for two periods.
106  *
107  * @return:     EFI_ST_SUCCESS for success
108  */
109 static int execute(void)
110 {
111         efi_uintn_t index;
112         efi_status_t ret;
113
114         /* Set 10 ms timer */
115         timer_ticks = 0;
116         ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
117         if (ret != EFI_SUCCESS) {
118                 efi_st_error("Could not set timer\n");
119                 return EFI_ST_FAILURE;
120         }
121         /* Set 100 ms timer */
122         ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
123         if (ret != EFI_SUCCESS) {
124                 efi_st_error("Could not set timer\n");
125                 return EFI_ST_FAILURE;
126         }
127
128         /* Set some arbitrary non-zero value to make change detectable. */
129         index = 5;
130         ret = boottime->wait_for_event(1, &event_wait, &index);
131         if (ret != EFI_SUCCESS) {
132                 efi_st_error("Could not wait for event\n");
133                 return EFI_ST_FAILURE;
134         }
135         ret = boottime->check_event(event_wait);
136         if (ret != EFI_NOT_READY) {
137                 efi_st_error("Signaled state was not cleared.\n");
138                 efi_st_printf("ret = %u\n", (unsigned int)ret);
139                 return EFI_ST_FAILURE;
140         }
141         if (index != 0) {
142                 efi_st_error("WaitForEvent returned wrong index\n");
143                 return EFI_ST_FAILURE;
144         }
145         efi_st_printf("Notification count periodic: %u\n", timer_ticks);
146         if (timer_ticks < 8 || timer_ticks > 12) {
147                 efi_st_error("Incorrect timing of events\n");
148                 return EFI_ST_FAILURE;
149         }
150         ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0);
151         if (index != 0) {
152                 efi_st_error("Could not cancel timer\n");
153                 return EFI_ST_FAILURE;
154         }
155         /* Set 10 ms timer */
156         timer_ticks = 0;
157         ret = boottime->set_timer(event_notify, EFI_TIMER_RELATIVE, 100000);
158         if (index != 0) {
159                 efi_st_error("Could not set timer\n");
160                 return EFI_ST_FAILURE;
161         }
162         /* Set 100 ms timer */
163         ret = boottime->set_timer(event_wait, EFI_TIMER_PERIODIC, 1000000);
164         if (index != 0) {
165                 efi_st_error("Could not set timer\n");
166                 return EFI_ST_FAILURE;
167         }
168         ret = boottime->wait_for_event(1, &event_wait, &index);
169         if (ret != EFI_SUCCESS) {
170                 efi_st_error("Could not wait for event\n");
171                 return EFI_ST_FAILURE;
172         }
173         efi_st_printf("Notification count single shot: %u\n", timer_ticks);
174         if (timer_ticks != 1) {
175                 efi_st_error("Single shot timer failed\n");
176                 return EFI_ST_FAILURE;
177         }
178         ret = boottime->wait_for_event(1, &event_wait, &index);
179         if (ret != EFI_SUCCESS) {
180                 efi_st_error("Could not wait for event\n");
181                 return EFI_ST_FAILURE;
182         }
183         efi_st_printf("Notification count stopped timer: %u\n", timer_ticks);
184         if (timer_ticks != 1) {
185                 efi_st_error("Stopped timer fired\n");
186                 return EFI_ST_FAILURE;
187         }
188         ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0);
189         if (ret != EFI_SUCCESS) {
190                 efi_st_error("Could not cancel timer\n");
191                 return EFI_ST_FAILURE;
192         }
193
194         return EFI_ST_SUCCESS;
195 }
196
197 EFI_UNIT_TEST(events) = {
198         .name = "event services",
199         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
200         .setup = setup,
201         .execute = execute,
202         .teardown = teardown,
203 };