efi_loader: simplify efi_allocate_pages()
[platform/kernel/u-boot.git] / lib / efi_selftest / efi_selftest_register_notify.c
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  */
46 static void EFIAPI notify(struct efi_event *event, void *context)
47 {
48         struct context *cp = context;
49         efi_status_t ret;
50
51         cp->notify_count++;
52
53         ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
54                                              cp->registration_key,
55                                              &cp->handle_count,
56                                              &cp->handles);
57         if (ret != EFI_SUCCESS)
58                 cp->handle_count = 0;
59 }
60
61 /*
62  * Setup unit test.
63  *
64  * @handle:     handle of the loaded image
65  * @systable:   system table
66  */
67 static int setup(const efi_handle_t img_handle,
68                  const struct efi_system_table *systable)
69 {
70         efi_status_t ret;
71
72         boottime = systable->boottime;
73
74         ret = boottime->create_event(EVT_NOTIFY_SIGNAL,
75                                      TPL_CALLBACK, notify, &context,
76                                      &event);
77         if (ret != EFI_SUCCESS) {
78                 efi_st_error("could not create event\n");
79                 return EFI_ST_FAILURE;
80         }
81
82         ret = boottime->register_protocol_notify(&guid1, event,
83                                                  &context.registration_key);
84         if (ret != EFI_SUCCESS) {
85                 efi_st_error("could not register event\n");
86                 return EFI_ST_FAILURE;
87         }
88
89         return EFI_ST_SUCCESS;
90 }
91
92 /*
93  * Tear down unit test.
94  *
95  */
96 static int teardown(void)
97 {
98         efi_status_t ret;
99
100         if (event) {
101                 ret = boottime->close_event(event);
102                 event = NULL;
103                 if (ret != EFI_SUCCESS) {
104                         efi_st_error("could not close event\n");
105                         return EFI_ST_FAILURE;
106                 }
107         }
108
109         return EFI_ST_SUCCESS;
110 }
111
112 /*
113  * Execute unit test.
114  *
115  */
116 static int execute(void)
117 {
118         efi_status_t ret;
119         efi_handle_t handle1 = NULL, handle2 = NULL;
120         struct interface interface1, interface2;
121
122         ret = boottime->install_protocol_interface(&handle1, &guid1,
123                                                    EFI_NATIVE_INTERFACE,
124                                                    &interface1);
125         if (ret != EFI_SUCCESS) {
126                 efi_st_error("could not install interface\n");
127                 return EFI_ST_FAILURE;
128         }
129         if (!context.notify_count) {
130                 efi_st_error("install was not notified\n");
131                 return EFI_ST_FAILURE;
132         }
133         if (context.notify_count > 1) {
134                 efi_st_error("install was notified too often\n");
135                 return EFI_ST_FAILURE;
136         }
137         if (context.handle_count != 1) {
138                 efi_st_error("LocateHandle failed\n");
139                 return EFI_ST_FAILURE;
140         }
141         ret = boottime->free_pool(context.handles);
142         if (ret != EFI_SUCCESS) {
143                 efi_st_error("FreePool failed\n");
144                 return EFI_ST_FAILURE;
145         }
146         context.notify_count = 0;
147         ret = boottime->install_protocol_interface(&handle1, &guid2,
148                                                    EFI_NATIVE_INTERFACE,
149                                                    &interface1);
150         if (ret != EFI_SUCCESS) {
151                 efi_st_error("could not install interface\n");
152                 return EFI_ST_FAILURE;
153         }
154         if (context.notify_count) {
155                 efi_st_error("wrong protocol was notified\n");
156                 return EFI_ST_FAILURE;
157         }
158         context.notify_count = 0;
159         ret = boottime->reinstall_protocol_interface(handle1, &guid1,
160                                                      &interface1, &interface2);
161         if (ret != EFI_SUCCESS) {
162                 efi_st_error("could not reinstall interface\n");
163                 return EFI_ST_FAILURE;
164         }
165         if (!context.notify_count) {
166                 efi_st_error("reinstall was not notified\n");
167                 return EFI_ST_FAILURE;
168         }
169         if (context.notify_count > 1) {
170                 efi_st_error("reinstall was notified too often\n");
171                 return EFI_ST_FAILURE;
172         }
173         if (context.handle_count != 1) {
174                 efi_st_error("LocateHandle failed\n");
175                 return EFI_ST_FAILURE;
176         }
177         ret = boottime->free_pool(context.handles);
178         if (ret != EFI_SUCCESS) {
179                 efi_st_error("FreePool failed\n");
180                 return EFI_ST_FAILURE;
181         }
182         context.notify_count = 0;
183         ret = boottime->install_protocol_interface(&handle2, &guid1,
184                                                    EFI_NATIVE_INTERFACE,
185                                                    &interface1);
186         if (ret != EFI_SUCCESS) {
187                 efi_st_error("could not install interface\n");
188                 return EFI_ST_FAILURE;
189         }
190         if (!context.notify_count) {
191                 efi_st_error("install was not notified\n");
192                 return EFI_ST_FAILURE;
193         }
194         if (context.notify_count > 1) {
195                 efi_st_error("install was notified too often\n");
196                 return EFI_ST_FAILURE;
197         }
198         if (context.handle_count != 2) {
199                 efi_st_error("LocateHandle failed\n");
200                 return EFI_ST_FAILURE;
201         }
202         ret = boottime->free_pool(context.handles);
203         if (ret != EFI_SUCCESS) {
204                 efi_st_error("FreePool failed\n");
205                 return EFI_ST_FAILURE;
206         }
207
208         ret = boottime->uninstall_multiple_protocol_interfaces
209                         (handle1, &guid1, &interface2,
210                          &guid2, &interface1, NULL);
211         if (ret != EFI_SUCCESS) {
212                 efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
213                 return EFI_ST_FAILURE;
214         }
215         ret = boottime->uninstall_multiple_protocol_interfaces
216                         (handle2, &guid1, &interface1, NULL);
217         if (ret != EFI_SUCCESS) {
218                 efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
219                 return EFI_ST_FAILURE;
220         }
221
222         return EFI_ST_SUCCESS;
223 }
224
225 EFI_UNIT_TEST(regprotnot) = {
226         .name = "register protocol notify",
227         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
228         .setup = setup,
229         .execute = execute,
230         .teardown = teardown,
231 };