]>
Commit | Line | Data |
---|---|---|
24f6be7a HS |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * efi_selftest_register_notify | |
4 | * | |
5 | * Copyright (c) 2019 Heinrich Schuchardt <[email protected]> | |
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 | */ | |
46 | static void EFIAPI notify(struct efi_event *event, void *context) | |
47 | { | |
48 | struct context *cp = context; | |
49 | efi_status_t ret; | |
f09cea36 HS |
50 | efi_uintn_t handle_count; |
51 | efi_handle_t *handles; | |
24f6be7a HS |
52 | |
53 | cp->notify_count++; | |
54 | ||
f09cea36 HS |
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 | } | |
24f6be7a HS |
64 | } |
65 | ||
66 | /* | |
67 | * Setup unit test. | |
68 | * | |
69 | * @handle: handle of the loaded image | |
70 | * @systable: system table | |
71 | */ | |
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 | */ | |
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 | */ | |
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 | } | |
f09cea36 | 178 | if (context.handle_count != 2) { |
24f6be7a HS |
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 | } | |
f09cea36 | 203 | if (context.handle_count != 3) { |
24f6be7a HS |
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 | }; |