efi_loader: validate load option
[oweals/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         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  */
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         }
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 };