]>
Commit | Line | Data |
---|---|---|
bd126692 HS |
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; | |
e67e7249 | 17 | static unsigned int timer_ticks; |
bd126692 HS |
18 | static struct efi_boot_services *boottime; |
19 | ||
20 | /* | |
e67e7249 HS |
21 | * Notification function, increments the notfication count if parameter |
22 | * context is provided. | |
bd126692 HS |
23 | * |
24 | * @event notified event | |
e67e7249 | 25 | * @context pointer to the notification count |
bd126692 HS |
26 | */ |
27 | static void EFIAPI notify(struct efi_event *event, void *context) | |
28 | { | |
e67e7249 HS |
29 | unsigned int *count = context; |
30 | ||
31 | if (count) | |
32 | ++*count; | |
bd126692 HS |
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 | |
e67e7249 | 43 | * @return: EFI_ST_SUCCESS for success |
bd126692 HS |
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, | |
e67e7249 | 53 | TPL_CALLBACK, notify, (void *)&timer_ticks, |
bd126692 HS |
54 | &event_notify); |
55 | if (ret != EFI_SUCCESS) { | |
56 | efi_st_error("could not create event\n"); | |
e67e7249 | 57 | return EFI_ST_FAILURE; |
bd126692 HS |
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"); | |
e67e7249 | 63 | return EFI_ST_FAILURE; |
bd126692 | 64 | } |
e67e7249 | 65 | return EFI_ST_SUCCESS; |
bd126692 HS |
66 | } |
67 | ||
68 | /* | |
69 | * Tear down unit test. | |
70 | * | |
71 | * Close the events created in setup. | |
e67e7249 HS |
72 | * |
73 | * @return: EFI_ST_SUCCESS for success | |
bd126692 HS |
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"); | |
e67e7249 | 84 | return EFI_ST_FAILURE; |
bd126692 HS |
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"); | |
e67e7249 | 92 | return EFI_ST_FAILURE; |
bd126692 HS |
93 | } |
94 | } | |
e67e7249 | 95 | return EFI_ST_SUCCESS; |
bd126692 HS |
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. | |
e67e7249 HS |
106 | * |
107 | * @return: EFI_ST_SUCCESS for success | |
bd126692 HS |
108 | */ |
109 | static int execute(void) | |
110 | { | |
ca379e1b | 111 | size_t index; |
bd126692 HS |
112 | efi_status_t ret; |
113 | ||
114 | /* Set 10 ms timer */ | |
e67e7249 | 115 | timer_ticks = 0; |
bd126692 HS |
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"); | |
e67e7249 | 119 | return EFI_ST_FAILURE; |
bd126692 HS |
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"); | |
e67e7249 | 125 | return EFI_ST_FAILURE; |
bd126692 HS |
126 | } |
127 | ||
e67e7249 | 128 | /* Set some arbitrary non-zero value to make change detectable. */ |
bd126692 HS |
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"); | |
e67e7249 | 133 | return EFI_ST_FAILURE; |
bd126692 HS |
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); | |
e67e7249 | 139 | return EFI_ST_FAILURE; |
bd126692 HS |
140 | } |
141 | if (index != 0) { | |
142 | efi_st_error("WaitForEvent returned wrong index\n"); | |
e67e7249 | 143 | return EFI_ST_FAILURE; |
bd126692 | 144 | } |
e67e7249 HS |
145 | efi_st_printf("Notification count periodic: %u\n", timer_ticks); |
146 | if (timer_ticks < 8 || timer_ticks > 12) { | |
bd126692 | 147 | efi_st_error("Incorrect timing of events\n"); |
e67e7249 | 148 | return EFI_ST_FAILURE; |
bd126692 HS |
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"); | |
e67e7249 | 153 | return EFI_ST_FAILURE; |
bd126692 HS |
154 | } |
155 | /* Set 10 ms timer */ | |
e67e7249 | 156 | timer_ticks = 0; |
bd126692 HS |
157 | ret = boottime->set_timer(event_notify, EFI_TIMER_RELATIVE, 100000); |
158 | if (index != 0) { | |
159 | efi_st_error("Could not set timer\n"); | |
e67e7249 | 160 | return EFI_ST_FAILURE; |
bd126692 HS |
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"); | |
e67e7249 | 166 | return EFI_ST_FAILURE; |
bd126692 HS |
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"); | |
e67e7249 | 171 | return EFI_ST_FAILURE; |
bd126692 | 172 | } |
e67e7249 HS |
173 | efi_st_printf("Notification count single shot: %u\n", timer_ticks); |
174 | if (timer_ticks != 1) { | |
bd126692 | 175 | efi_st_error("Single shot timer failed\n"); |
e67e7249 | 176 | return EFI_ST_FAILURE; |
bd126692 HS |
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"); | |
e67e7249 | 181 | return EFI_ST_FAILURE; |
bd126692 | 182 | } |
e67e7249 HS |
183 | efi_st_printf("Notification count stopped timer: %u\n", timer_ticks); |
184 | if (timer_ticks != 1) { | |
bd126692 | 185 | efi_st_error("Stopped timer fired\n"); |
e67e7249 | 186 | return EFI_ST_FAILURE; |
bd126692 HS |
187 | } |
188 | ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); | |
abe99463 | 189 | if (ret != EFI_SUCCESS) { |
bd126692 | 190 | efi_st_error("Could not cancel timer\n"); |
e67e7249 | 191 | return EFI_ST_FAILURE; |
bd126692 HS |
192 | } |
193 | ||
e67e7249 | 194 | return EFI_ST_SUCCESS; |
bd126692 HS |
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 | }; |