1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * efi_selftest_register_notify
4 *
5 * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 *
7 * This unit test checks the following protocol services:
8 * InstallProtocolInterface, UninstallProtocolInterface,
9 * RegisterProtocolNotify, CreateEvent, CloseEvent.
10 */
11
12 #include <efi_selftest.h>
13
14 /*
15 * The test currently does not actually call the interface function.
16 * So this is just a dummy structure.
17 */
18 struct interface {
19 void (EFIAPI * inc)(void);
20 };
21
22 struct context {
23 void *registration_key;
24 efi_uintn_t notify_count;
25 efi_uintn_t handle_count;
26 efi_handle_t *handles;
27 efi_status_t ret;
28 };
29
30 static struct efi_boot_services *boottime;
31 static efi_guid_t guid1 =
32 EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a,
33 0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf);
34 static efi_guid_t guid2 =
35 EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77,
36 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f);
37 static struct context context;
38 static struct efi_event *event;
39
40 /*
41 * Notification function, increments the notification count if parameter
42 * context is provided.
43 *
44 * @event notified event
45 * @context pointer to the notification count
46 */
notify(struct efi_event * event,void * context)47 static void EFIAPI notify(struct efi_event *event, void *context)
48 {
49 struct context *cp = context;
50 efi_uintn_t handle_count;
51 efi_handle_t *handles;
52
53 cp->notify_count++;
54
55 for (;;) {
56 cp->ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY,
57 NULL,
58 cp->registration_key,
59 &handle_count,
60 &handles);
61 if (cp->ret != EFI_SUCCESS)
62 break;
63 cp->handle_count += handle_count;
64 cp->handles = handles;
65 }
66 }
67
68 /*
69 * Setup unit test.
70 *
71 * @handle: handle of the loaded image
72 * @systable: system table
73 */
setup(const efi_handle_t img_handle,const struct efi_system_table * systable)74 static int setup(const efi_handle_t img_handle,
75 const struct efi_system_table *systable)
76 {
77 efi_status_t ret;
78
79 boottime = systable->boottime;
80
81 ret = boottime->create_event(EVT_NOTIFY_SIGNAL,
82 TPL_CALLBACK, notify, &context,
83 &event);
84 if (ret != EFI_SUCCESS) {
85 efi_st_error("could not create event\n");
86 return EFI_ST_FAILURE;
87 }
88
89 ret = boottime->register_protocol_notify(&guid1, event,
90 &context.registration_key);
91 if (ret != EFI_SUCCESS) {
92 efi_st_error("could not register event\n");
93 return EFI_ST_FAILURE;
94 }
95
96 return EFI_ST_SUCCESS;
97 }
98
99 /*
100 * Tear down unit test.
101 *
102 */
teardown(void)103 static int teardown(void)
104 {
105 efi_status_t ret;
106
107 if (event) {
108 ret = boottime->close_event(event);
109 event = NULL;
110 if (ret != EFI_SUCCESS) {
111 efi_st_error("could not close event\n");
112 return EFI_ST_FAILURE;
113 }
114 }
115
116 return EFI_ST_SUCCESS;
117 }
118
119 /*
120 * Execute unit test.
121 *
122 */
execute(void)123 static int execute(void)
124 {
125 efi_status_t ret;
126 efi_handle_t handle1 = NULL, handle2 = NULL;
127 struct interface *interface;
128 struct interface interface1, interface2;
129
130 ret = boottime->install_protocol_interface(&handle1, &guid1,
131 EFI_NATIVE_INTERFACE,
132 &interface1);
133 if (ret != EFI_SUCCESS) {
134 efi_st_error("could not install interface\n");
135 return EFI_ST_FAILURE;
136 }
137 if (!context.notify_count) {
138 efi_st_error("install was not notified\n");
139 return EFI_ST_FAILURE;
140 }
141 if (context.notify_count > 1) {
142 efi_st_error("install was notified too often\n");
143 return EFI_ST_FAILURE;
144 }
145 if (context.handle_count != 1) {
146 efi_st_error("LocateHandle failed\n");
147 return EFI_ST_FAILURE;
148 }
149 interface = NULL;
150 ret = boottime->open_protocol(handle1, &guid1, (void**)&interface,
151 NULL, NULL,
152 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
153 if (ret != EFI_SUCCESS) {
154 efi_st_error("Cannot find installed protocol on handle\n");
155 return EFI_ST_FAILURE;
156 }
157 if (interface != &interface1) {
158 efi_st_error("Wrong interface after install\n");
159 return EFI_ST_FAILURE;
160 }
161 ret = boottime->free_pool(context.handles);
162 if (ret != EFI_SUCCESS) {
163 efi_st_error("FreePool failed\n");
164 return EFI_ST_FAILURE;
165 }
166 context.notify_count = 0;
167 ret = boottime->install_protocol_interface(&handle1, &guid2,
168 EFI_NATIVE_INTERFACE,
169 &interface1);
170 if (ret != EFI_SUCCESS) {
171 efi_st_error("could not install interface\n");
172 return EFI_ST_FAILURE;
173 }
174 if (context.notify_count) {
175 efi_st_error("wrong protocol was notified\n");
176 return EFI_ST_FAILURE;
177 }
178 context.notify_count = 0;
179 ret = boottime->reinstall_protocol_interface(handle1, &guid1,
180 &interface1, &interface2);
181 if (ret != EFI_SUCCESS) {
182 efi_st_error("could not reinstall interface\n");
183 return EFI_ST_FAILURE;
184 }
185 if (!context.notify_count) {
186 efi_st_error("reinstall was not notified\n");
187 return EFI_ST_FAILURE;
188 }
189 if (context.notify_count > 1) {
190 efi_st_error("reinstall was notified too often\n");
191 return EFI_ST_FAILURE;
192 }
193 if (context.handle_count != 2) {
194 efi_st_error("LocateHandle failed\n");
195 return EFI_ST_FAILURE;
196 }
197 ret = boottime->free_pool(context.handles);
198 if (ret != EFI_SUCCESS) {
199 efi_st_error("FreePool failed\n");
200 return EFI_ST_FAILURE;
201 }
202 interface = NULL;
203 ret = boottime->open_protocol(handle1, &guid1, (void**)&interface,
204 NULL, NULL,
205 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
206 if (ret != EFI_SUCCESS) {
207 efi_st_error("Cannot find reinstalled protocol on handle\n");
208 return EFI_ST_FAILURE;
209 }
210 if (interface != &interface2) {
211 efi_st_error("Wrong interface after reinstall\n");
212 return EFI_ST_FAILURE;
213 }
214 context.notify_count = 0;
215 ret = boottime->install_protocol_interface(&handle2, &guid1,
216 EFI_NATIVE_INTERFACE,
217 &interface1);
218 if (ret != EFI_SUCCESS) {
219 efi_st_error("could not install interface\n");
220 return EFI_ST_FAILURE;
221 }
222 if (!context.notify_count) {
223 efi_st_error("install was not notified\n");
224 return EFI_ST_FAILURE;
225 }
226 if (context.notify_count > 1) {
227 efi_st_error("install was notified too often\n");
228 return EFI_ST_FAILURE;
229 }
230 if (context.handle_count != 3) {
231 efi_st_error("LocateHandle failed\n");
232 return EFI_ST_FAILURE;
233 }
234 if (context.ret != EFI_NOT_FOUND) {
235 efi_st_error("LocateHandle did not return EFI_NOT_FOUND\n");
236 return EFI_ST_FAILURE;
237 }
238 ret = boottime->free_pool(context.handles);
239 if (ret != EFI_SUCCESS) {
240 efi_st_error("FreePool failed\n");
241 return EFI_ST_FAILURE;
242 }
243
244 ret = boottime->uninstall_multiple_protocol_interfaces
245 (handle1, &guid1, &interface2,
246 &guid2, &interface1, NULL);
247 if (ret != EFI_SUCCESS) {
248 efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
249 return EFI_ST_FAILURE;
250 }
251 ret = boottime->uninstall_multiple_protocol_interfaces
252 (handle2, &guid1, &interface1, NULL);
253 if (ret != EFI_SUCCESS) {
254 efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
255 return EFI_ST_FAILURE;
256 }
257
258 return EFI_ST_SUCCESS;
259 }
260
261 EFI_UNIT_TEST(regprotnot) = {
262 .name = "register protocol notify",
263 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
264 .setup = setup,
265 .execute = execute,
266 .teardown = teardown,
267 };
268