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