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 };
28
29 static struct efi_boot_services *boottime;
30 static efi_guid_t guid1 =
31 EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a,
32 0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf);
33 static efi_guid_t guid2 =
34 EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77,
35 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f);
36 static struct context context;
37 static struct efi_event *event;
38
39 /*
40 * Notification function, increments the notification count if parameter
41 * context is provided.
42 *
43 * @event notified event
44 * @context pointer to the notification count
45 */
notify(struct efi_event * event,void * context)46 static void EFIAPI notify(struct efi_event *event, void *context)
47 {
48 struct context *cp = context;
49 efi_status_t ret;
50 efi_uintn_t handle_count;
51 efi_handle_t *handles;
52
53 cp->notify_count++;
54
55 for (;;) {
56 ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
57 cp->registration_key,
58 &handle_count, &handles);
59 if (ret != EFI_SUCCESS)
60 break;
61 cp->handle_count += handle_count;
62 cp->handles = handles;
63 }
64 }
65
66 /*
67 * Setup unit test.
68 *
69 * @handle: handle of the loaded image
70 * @systable: system table
71 */
setup(const efi_handle_t img_handle,const struct efi_system_table * systable)72 static int setup(const efi_handle_t img_handle,
73 const struct efi_system_table *systable)
74 {
75 efi_status_t ret;
76
77 boottime = systable->boottime;
78
79 ret = boottime->create_event(EVT_NOTIFY_SIGNAL,
80 TPL_CALLBACK, notify, &context,
81 &event);
82 if (ret != EFI_SUCCESS) {
83 efi_st_error("could not create event\n");
84 return EFI_ST_FAILURE;
85 }
86
87 ret = boottime->register_protocol_notify(&guid1, event,
88 &context.registration_key);
89 if (ret != EFI_SUCCESS) {
90 efi_st_error("could not register event\n");
91 return EFI_ST_FAILURE;
92 }
93
94 return EFI_ST_SUCCESS;
95 }
96
97 /*
98 * Tear down unit test.
99 *
100 */
teardown(void)101 static int teardown(void)
102 {
103 efi_status_t ret;
104
105 if (event) {
106 ret = boottime->close_event(event);
107 event = NULL;
108 if (ret != EFI_SUCCESS) {
109 efi_st_error("could not close event\n");
110 return EFI_ST_FAILURE;
111 }
112 }
113
114 return EFI_ST_SUCCESS;
115 }
116
117 /*
118 * Execute unit test.
119 *
120 */
execute(void)121 static int execute(void)
122 {
123 efi_status_t ret;
124 efi_handle_t handle1 = NULL, handle2 = NULL;
125 struct interface interface1, interface2;
126
127 ret = boottime->install_protocol_interface(&handle1, &guid1,
128 EFI_NATIVE_INTERFACE,
129 &interface1);
130 if (ret != EFI_SUCCESS) {
131 efi_st_error("could not install interface\n");
132 return EFI_ST_FAILURE;
133 }
134 if (!context.notify_count) {
135 efi_st_error("install was not notified\n");
136 return EFI_ST_FAILURE;
137 }
138 if (context.notify_count > 1) {
139 efi_st_error("install was notified too often\n");
140 return EFI_ST_FAILURE;
141 }
142 if (context.handle_count != 1) {
143 efi_st_error("LocateHandle failed\n");
144 return EFI_ST_FAILURE;
145 }
146 ret = boottime->free_pool(context.handles);
147 if (ret != EFI_SUCCESS) {
148 efi_st_error("FreePool failed\n");
149 return EFI_ST_FAILURE;
150 }
151 context.notify_count = 0;
152 ret = boottime->install_protocol_interface(&handle1, &guid2,
153 EFI_NATIVE_INTERFACE,
154 &interface1);
155 if (ret != EFI_SUCCESS) {
156 efi_st_error("could not install interface\n");
157 return EFI_ST_FAILURE;
158 }
159 if (context.notify_count) {
160 efi_st_error("wrong protocol was notified\n");
161 return EFI_ST_FAILURE;
162 }
163 context.notify_count = 0;
164 ret = boottime->reinstall_protocol_interface(handle1, &guid1,
165 &interface1, &interface2);
166 if (ret != EFI_SUCCESS) {
167 efi_st_error("could not reinstall interface\n");
168 return EFI_ST_FAILURE;
169 }
170 if (!context.notify_count) {
171 efi_st_error("reinstall was not notified\n");
172 return EFI_ST_FAILURE;
173 }
174 if (context.notify_count > 1) {
175 efi_st_error("reinstall was notified too often\n");
176 return EFI_ST_FAILURE;
177 }
178 if (context.handle_count != 2) {
179 efi_st_error("LocateHandle failed\n");
180 return EFI_ST_FAILURE;
181 }
182 ret = boottime->free_pool(context.handles);
183 if (ret != EFI_SUCCESS) {
184 efi_st_error("FreePool failed\n");
185 return EFI_ST_FAILURE;
186 }
187 context.notify_count = 0;
188 ret = boottime->install_protocol_interface(&handle2, &guid1,
189 EFI_NATIVE_INTERFACE,
190 &interface1);
191 if (ret != EFI_SUCCESS) {
192 efi_st_error("could not install interface\n");
193 return EFI_ST_FAILURE;
194 }
195 if (!context.notify_count) {
196 efi_st_error("install was not notified\n");
197 return EFI_ST_FAILURE;
198 }
199 if (context.notify_count > 1) {
200 efi_st_error("install was notified too often\n");
201 return EFI_ST_FAILURE;
202 }
203 if (context.handle_count != 3) {
204 efi_st_error("LocateHandle failed\n");
205 return EFI_ST_FAILURE;
206 }
207 ret = boottime->free_pool(context.handles);
208 if (ret != EFI_SUCCESS) {
209 efi_st_error("FreePool failed\n");
210 return EFI_ST_FAILURE;
211 }
212
213 ret = boottime->uninstall_multiple_protocol_interfaces
214 (handle1, &guid1, &interface2,
215 &guid2, &interface1, NULL);
216 if (ret != EFI_SUCCESS) {
217 efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
218 return EFI_ST_FAILURE;
219 }
220 ret = boottime->uninstall_multiple_protocol_interfaces
221 (handle2, &guid1, &interface1, NULL);
222 if (ret != EFI_SUCCESS) {
223 efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
224 return EFI_ST_FAILURE;
225 }
226
227 return EFI_ST_SUCCESS;
228 }
229
230 EFI_UNIT_TEST(regprotnot) = {
231 .name = "register protocol notify",
232 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
233 .setup = setup,
234 .execute = execute,
235 .teardown = teardown,
236 };
237