• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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