]> git.sur5r.net Git - u-boot/blob - lib/efi_selftest/efi_selftest_devicepath.c
efi_selftest: do not try to close device path protocol
[u-boot] / lib / efi_selftest / efi_selftest_devicepath.c
1 /*
2  * efi_selftest_devicepath
3  *
4  * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
5  *
6  * SPDX-License-Identifier:     GPL-2.0+
7  *
8  * This unit test checks the following protocol services:
9  * DevicePathToText
10  */
11
12 #include <efi_selftest.h>
13
14 static struct efi_boot_services *boottime;
15
16 static efi_handle_t handle1;
17 static efi_handle_t handle2;
18 static efi_handle_t handle3;
19
20 struct interface {
21         void (EFIAPI * inc)(void);
22 } interface;
23
24 static efi_guid_t guid_device_path = DEVICE_PATH_GUID;
25
26 static efi_guid_t guid_device_path_to_text_protocol =
27         EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
28
29 static efi_guid_t guid_protocol =
30         EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
31                  0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0x7d);
32
33 static efi_guid_t guid_vendor1 =
34         EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
35                  0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xb1);
36
37 static efi_guid_t guid_vendor2 =
38         EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
39                  0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xa2);
40
41 static efi_guid_t guid_vendor3 =
42         EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
43                  0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xc3);
44
45 static u8 *dp1;
46 static u8 *dp2;
47 static u8 *dp3;
48
49 struct efi_device_path_to_text_protocol *device_path_to_text;
50
51 /*
52  * Setup unit test.
53  *
54  * Create three handles. Install a new protocol on two of them and
55  * provice device paths.
56  *
57  * handle1
58  *   guid interface
59  * handle2
60  *   guid interface
61  * handle3
62  *
63  * @handle:     handle of the loaded image
64  * @systable:   system table
65  */
66 static int setup(const efi_handle_t img_handle,
67                  const struct efi_system_table *systable)
68 {
69         struct efi_device_path_vendor vendor_node;
70         struct efi_device_path end_node;
71         efi_status_t ret;
72
73         boottime = systable->boottime;
74
75         ret = boottime->locate_protocol(&guid_device_path_to_text_protocol,
76                                         NULL, (void **)&device_path_to_text);
77         if (ret != EFI_SUCCESS) {
78                 device_path_to_text = NULL;
79                 efi_st_error(
80                         "Device path to text protocol is not available.\n");
81                 return EFI_ST_FAILURE;
82         }
83
84         ret = boottime->allocate_pool(EFI_LOADER_DATA,
85                                       sizeof(struct efi_device_path_vendor) +
86                                       sizeof(struct efi_device_path),
87                                       (void **)&dp1);
88         if (ret != EFI_SUCCESS)
89                 goto out_of_memory;
90
91         ret = boottime->allocate_pool(EFI_LOADER_DATA, 2 *
92                                       sizeof(struct efi_device_path_vendor) +
93                                       sizeof(struct efi_device_path),
94                                       (void **)&dp2);
95         if (ret != EFI_SUCCESS)
96                 goto out_of_memory;
97
98         ret = boottime->allocate_pool(EFI_LOADER_DATA, 3 *
99                                       sizeof(struct efi_device_path_vendor) +
100                                       sizeof(struct efi_device_path),
101                                       (void **)&dp3);
102         if (ret != EFI_SUCCESS)
103                 goto out_of_memory;
104
105         vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
106         vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
107         vendor_node.dp.length = sizeof(struct efi_device_path_vendor);
108
109         boottime->copy_mem(&vendor_node.guid, &guid_vendor1,
110                            sizeof(efi_guid_t));
111         boottime->copy_mem(dp1, &vendor_node,
112                            sizeof(struct efi_device_path_vendor));
113         boottime->copy_mem(dp2, &vendor_node,
114                            sizeof(struct efi_device_path_vendor));
115         boottime->copy_mem(dp3, &vendor_node,
116                            sizeof(struct efi_device_path_vendor));
117
118         boottime->copy_mem(&vendor_node.guid, &guid_vendor2,
119                            sizeof(efi_guid_t));
120         boottime->copy_mem(dp2 + sizeof(struct efi_device_path_vendor),
121                            &vendor_node, sizeof(struct efi_device_path_vendor));
122         boottime->copy_mem(dp3 + sizeof(struct efi_device_path_vendor),
123                            &vendor_node, sizeof(struct efi_device_path_vendor));
124
125         boottime->copy_mem(&vendor_node.guid, &guid_vendor3,
126                            sizeof(efi_guid_t));
127         boottime->copy_mem(dp3 + 2 * sizeof(struct efi_device_path_vendor),
128                            &vendor_node, sizeof(struct efi_device_path_vendor));
129
130         end_node.type = DEVICE_PATH_TYPE_END;
131         end_node.sub_type = DEVICE_PATH_SUB_TYPE_END;
132         end_node.length = sizeof(struct efi_device_path);
133         boottime->copy_mem(dp1 + sizeof(struct efi_device_path_vendor),
134                            &end_node, sizeof(struct efi_device_path));
135         boottime->copy_mem(dp2 + 2 * sizeof(struct efi_device_path_vendor),
136                            &end_node, sizeof(struct efi_device_path));
137         boottime->copy_mem(dp3 + 3 * sizeof(struct efi_device_path_vendor),
138                            &end_node, sizeof(struct efi_device_path));
139
140         ret = boottime->install_protocol_interface(&handle1,
141                                                    &guid_device_path,
142                                                    EFI_NATIVE_INTERFACE,
143                                                    dp1);
144         if (ret != EFI_SUCCESS) {
145                 efi_st_error("InstallProtocolInterface failed\n");
146                 return EFI_ST_FAILURE;
147         }
148         ret = boottime->install_protocol_interface(&handle1,
149                                                    &guid_protocol,
150                                                    EFI_NATIVE_INTERFACE,
151                                                    &interface);
152         if (ret != EFI_SUCCESS) {
153                 efi_st_error("InstallProtocolInterface failed\n");
154                 return EFI_ST_FAILURE;
155         }
156         ret = boottime->install_protocol_interface(&handle2,
157                                                    &guid_device_path,
158                                                    EFI_NATIVE_INTERFACE,
159                                                    dp2);
160         if (ret != EFI_SUCCESS) {
161                 efi_st_error("InstallProtocolInterface failed\n");
162                 return EFI_ST_FAILURE;
163         }
164         ret = boottime->install_protocol_interface(&handle2,
165                                                    &guid_protocol,
166                                                    EFI_NATIVE_INTERFACE,
167                                                    &interface);
168         if (ret != EFI_SUCCESS) {
169                 efi_st_error("InstallProtocolInterface failed\n");
170                 return EFI_ST_FAILURE;
171         }
172         ret = boottime->install_protocol_interface(&handle3,
173                                                    &guid_device_path,
174                                                    EFI_NATIVE_INTERFACE,
175                                                    dp3);
176         if (ret != EFI_SUCCESS) {
177                 efi_st_error("InstallProtocolInterface failed\n");
178                 return EFI_ST_FAILURE;
179         }
180         return EFI_ST_SUCCESS;
181
182 out_of_memory:
183         efi_st_error("Out of memory\n");
184         return EFI_ST_FAILURE;
185 }
186
187 /*
188  * Tear down unit test.
189  *
190  */
191 static int teardown(void)
192 {
193         efi_status_t ret;
194
195         ret = boottime->uninstall_protocol_interface(&handle1,
196                                                      &guid_device_path,
197                                                      dp1);
198         if (ret != EFI_SUCCESS)
199                 efi_st_todo("UninstallProtocolInterface failed\n");
200         ret = boottime->uninstall_protocol_interface(&handle1,
201                                                      &guid_protocol,
202                                                      &interface);
203         if (ret != EFI_SUCCESS)
204                 efi_st_todo("UninstallProtocolInterface failed\n");
205         ret = boottime->uninstall_protocol_interface(&handle2,
206                                                      &guid_device_path,
207                                                      dp2);
208         if (ret != EFI_SUCCESS)
209                 efi_st_todo("UninstallProtocolInterface failed\n");
210         ret = boottime->uninstall_protocol_interface(&handle2,
211                                                      &guid_protocol,
212                                                      &interface);
213         if (ret != EFI_SUCCESS)
214                 efi_st_todo("UninstallProtocolInterface failed\n");
215         ret = boottime->uninstall_protocol_interface(&handle3,
216                                                      &guid_device_path,
217                                                      dp3);
218         if (ret != EFI_SUCCESS)
219                 efi_st_todo("UninstallProtocolInterface failed\n");
220         if (dp1) {
221                 ret = boottime->free_pool(dp1);
222                 if (ret != EFI_SUCCESS) {
223                         efi_st_error("FreePool failed\n");
224                         return EFI_ST_FAILURE;
225                 }
226         }
227         if (dp2) {
228                 ret = boottime->free_pool(dp2);
229                 if (ret != EFI_SUCCESS) {
230                         efi_st_error("FreePool failed\n");
231                         return EFI_ST_FAILURE;
232                 }
233         }
234         if (dp3) {
235                 ret = boottime->free_pool(dp3);
236                 if (ret != EFI_SUCCESS) {
237                         efi_st_error("FreePool failed\n");
238                         return EFI_ST_FAILURE;
239                 }
240         }
241         return EFI_ST_SUCCESS;
242 }
243
244 /*
245  * Execute unit test.
246  *
247  */
248 static int execute(void)
249 {
250         struct efi_device_path *remaining_dp;
251         void *handle;
252         /*
253          * This device path node ends with the letter 't' of 'u-boot'.
254          * The following '.bin' does not belong to the node but is
255          * helps to test the correct truncation.
256          */
257         struct {
258                 struct efi_device_path dp;
259                 u16 text[12];
260         } __packed dp_node = {
261                         { DEVICE_PATH_TYPE_MEDIA_DEVICE,
262                           DEVICE_PATH_SUB_TYPE_FILE_PATH,
263                           sizeof(struct efi_device_path) + 12},
264                         L"u-boot.bin",
265                 };
266         u16 *string;
267         efi_status_t ret;
268         efi_uintn_t i, no_handles;
269         efi_handle_t *handles;
270         struct efi_device_path *dp;
271
272         /* Display all available device paths */
273         ret = boottime->locate_handle_buffer(BY_PROTOCOL,
274                                              &guid_device_path,
275                                              NULL, &no_handles, &handles);
276         if (ret != EFI_SUCCESS) {
277                 efi_st_error("Cannot retrieve device path protocols.\n");
278                 return EFI_ST_FAILURE;
279         }
280
281         efi_st_printf("Installed device path protocols:\n");
282         for (i = 0; i < no_handles; ++i) {
283                 ret = boottime->open_protocol(handles[i], &guid_device_path,
284                                               (void **)&dp, NULL, NULL,
285                                               EFI_OPEN_PROTOCOL_GET_PROTOCOL);
286                 if (ret != EFI_SUCCESS) {
287                         efi_st_error("Cannot open device path protocol.\n");
288                         return EFI_ST_FAILURE;
289                 }
290                 string = device_path_to_text->convert_device_path_to_text(
291                                         dp, true, false);
292                 if (!string) {
293                         efi_st_error("ConvertDevicePathToText failed\n");
294                         return EFI_ST_FAILURE;
295                 }
296                 efi_st_printf("%ps\n", string);
297                 ret = boottime->free_pool(string);
298                 if (ret != EFI_SUCCESS) {
299                         efi_st_error("FreePool failed\n");
300                         return EFI_ST_FAILURE;
301                 }
302                 /*
303                  * CloseProtocol cannot be called without agent handle.
304                  * There is no need to close the device path protocol.
305                  */
306         }
307         ret = boottime->free_pool(handles);
308         if (ret != EFI_SUCCESS) {
309                 efi_st_error("FreePool failed\n");
310                 return EFI_ST_FAILURE;
311         }
312         efi_st_printf("\n");
313
314         /* Test ConvertDevicePathToText */
315         string = device_path_to_text->convert_device_path_to_text(
316                         (struct efi_device_path *)dp2, true, false);
317         if (!string) {
318                 efi_st_error("ConvertDevicePathToText failed\n");
319                 return EFI_ST_FAILURE;
320         }
321         efi_st_printf("dp2: %ps\n", string);
322         if (efi_st_strcmp_16_8(
323                 string,
324                 "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)")
325             ) {
326                 efi_st_error("Incorrect text from ConvertDevicePathToText\n");
327                 return EFI_ST_FAILURE;
328         }
329
330         ret = boottime->free_pool(string);
331         if (ret != EFI_SUCCESS) {
332                 efi_st_error("FreePool failed\n");
333                 return EFI_ST_FAILURE;
334         }
335
336         /* Test ConvertDeviceNodeToText */
337         string = device_path_to_text->convert_device_node_to_text(
338                         (struct efi_device_path *)&dp_node, true, false);
339         if (!string) {
340                 efi_st_error("ConvertDeviceNodeToText failed\n");
341                 return EFI_ST_FAILURE;
342         }
343         efi_st_printf("dp_node: %ps\n", string);
344         ret = boottime->free_pool(string);
345         if (ret != EFI_SUCCESS) {
346                 efi_st_error("FreePool failed\n");
347                 return EFI_ST_FAILURE;
348         }
349         if (efi_st_strcmp_16_8(string, "u-boot")) {
350                 efi_st_error(
351                         "Incorrect conversion by ConvertDeviceNodeToText\n");
352                 return EFI_ST_FAILURE;
353         }
354
355         /* Test LocateDevicePath */
356         remaining_dp = (struct efi_device_path *)dp3;
357         ret = boottime->locate_device_path(&guid_protocol, &remaining_dp,
358                                            &handle);
359         if (ret != EFI_SUCCESS) {
360                 efi_st_error("LocateDevicePath failed\n");
361                 return EFI_ST_FAILURE;
362         }
363         if (handle != handle2) {
364                 efi_st_error("LocateDevicePath returned wrong handle\n");
365                 return EFI_ST_FAILURE;
366         }
367         string = device_path_to_text->convert_device_path_to_text(remaining_dp,
368                                                                   true, false);
369         if (!string) {
370                 efi_st_error("ConvertDevicePathToText failed\n");
371                 return EFI_ST_FAILURE;
372         }
373         efi_st_printf("remaining device path: %ps\n", string);
374         if (efi_st_strcmp_16_8(string,
375                                "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)")
376             ) {
377                 efi_st_error("LocateDevicePath: wrong remaining device path\n");
378                 return EFI_ST_FAILURE;
379         }
380
381         return EFI_ST_SUCCESS;
382 }
383
384 EFI_UNIT_TEST(devicepath) = {
385         .name = "device path",
386         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
387         .setup = setup,
388         .execute = execute,
389         .teardown = teardown,
390 };