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