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_error("UninstallProtocolInterface failed\n");
200 		return EFI_ST_FAILURE;
201 	}
202 	ret = boottime->uninstall_protocol_interface(handle1,
203 						     &guid_protocol,
204 						     &interface);
205 	if (ret != EFI_SUCCESS) {
206 		efi_st_error("UninstallProtocolInterface failed\n");
207 		return EFI_ST_FAILURE;
208 	}
209 	ret = boottime->uninstall_protocol_interface(handle2,
210 						     &guid_device_path,
211 						     dp2);
212 	if (ret != EFI_SUCCESS) {
213 		efi_st_error("UninstallProtocolInterface failed\n");
214 		return EFI_ST_FAILURE;
215 	}
216 	ret = boottime->uninstall_protocol_interface(handle2,
217 						     &guid_protocol,
218 						     &interface);
219 	if (ret != EFI_SUCCESS) {
220 		efi_st_error("UninstallProtocolInterface failed\n");
221 		return EFI_ST_FAILURE;
222 	}
223 	ret = boottime->uninstall_protocol_interface(handle3,
224 						     &guid_device_path,
225 						     dp3);
226 	if (ret != EFI_SUCCESS) {
227 		efi_st_error("UninstallProtocolInterface failed\n");
228 		return EFI_ST_FAILURE;
229 	}
230 	if (dp1) {
231 		ret = boottime->free_pool(dp1);
232 		if (ret != EFI_SUCCESS) {
233 			efi_st_error("FreePool failed\n");
234 			return EFI_ST_FAILURE;
235 		}
236 	}
237 	if (dp2) {
238 		ret = boottime->free_pool(dp2);
239 		if (ret != EFI_SUCCESS) {
240 			efi_st_error("FreePool failed\n");
241 			return EFI_ST_FAILURE;
242 		}
243 	}
244 	if (dp3) {
245 		ret = boottime->free_pool(dp3);
246 		if (ret != EFI_SUCCESS) {
247 			efi_st_error("FreePool failed\n");
248 			return EFI_ST_FAILURE;
249 		}
250 	}
251 	return EFI_ST_SUCCESS;
252 }
253 
254 /*
255  * Execute unit test.
256  *
257  */
258 static int execute(void)
259 {
260 	struct efi_device_path *remaining_dp;
261 	void *handle;
262 	/*
263 	 * This device path node ends with the letter 't' of 'u-boot'.
264 	 * The following '.bin' does not belong to the node but is
265 	 * helps to test the correct truncation.
266 	 */
267 	struct {
268 		struct efi_device_path dp;
269 		u16 text[12];
270 	} __packed dp_node = {
271 			{ DEVICE_PATH_TYPE_MEDIA_DEVICE,
272 			  DEVICE_PATH_SUB_TYPE_FILE_PATH,
273 			  sizeof(struct efi_device_path) + 12},
274 			L"u-boot.bin",
275 		};
276 	u16 *string;
277 	efi_status_t ret;
278 	efi_uintn_t i, no_handles;
279 	efi_handle_t *handles;
280 	struct efi_device_path *dp;
281 
282 	/* Display all available device paths */
283 	ret = boottime->locate_handle_buffer(BY_PROTOCOL,
284 					     &guid_device_path,
285 					     NULL, &no_handles, &handles);
286 	if (ret != EFI_SUCCESS) {
287 		efi_st_error("Cannot retrieve device path protocols.\n");
288 		return EFI_ST_FAILURE;
289 	}
290 
291 	efi_st_printf("Installed device path protocols:\n");
292 	for (i = 0; i < no_handles; ++i) {
293 		ret = boottime->open_protocol(handles[i], &guid_device_path,
294 					      (void **)&dp, NULL, NULL,
295 					      EFI_OPEN_PROTOCOL_GET_PROTOCOL);
296 		if (ret != EFI_SUCCESS) {
297 			efi_st_error("Cannot open device path protocol.\n");
298 			return EFI_ST_FAILURE;
299 		}
300 		string = device_path_to_text->convert_device_path_to_text(
301 					dp, true, false);
302 		if (!string) {
303 			efi_st_error("ConvertDevicePathToText failed\n");
304 			return EFI_ST_FAILURE;
305 		}
306 		efi_st_printf("%ps\n", string);
307 		ret = boottime->free_pool(string);
308 		if (ret != EFI_SUCCESS) {
309 			efi_st_error("FreePool failed\n");
310 			return EFI_ST_FAILURE;
311 		}
312 		/*
313 		 * CloseProtocol cannot be called without agent handle.
314 		 * There is no need to close the device path protocol.
315 		 */
316 	}
317 	ret = boottime->free_pool(handles);
318 	if (ret != EFI_SUCCESS) {
319 		efi_st_error("FreePool failed\n");
320 		return EFI_ST_FAILURE;
321 	}
322 
323 	/* Test ConvertDevicePathToText */
324 	string = device_path_to_text->convert_device_path_to_text(
325 			(struct efi_device_path *)dp2, true, false);
326 	if (!string) {
327 		efi_st_error("ConvertDevicePathToText failed\n");
328 		return EFI_ST_FAILURE;
329 	}
330 	if (efi_st_strcmp_16_8(
331 		string,
332 		"/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)")
333 	    ) {
334 		efi_st_printf("dp2: %ps\n", string);
335 		efi_st_error("Incorrect text from ConvertDevicePathToText\n");
336 		return EFI_ST_FAILURE;
337 	}
338 	ret = boottime->free_pool(string);
339 	if (ret != EFI_SUCCESS) {
340 		efi_st_error("FreePool failed\n");
341 		return EFI_ST_FAILURE;
342 	}
343 
344 	/* Test ConvertDeviceNodeToText */
345 	string = device_path_to_text->convert_device_node_to_text(
346 			(struct efi_device_path *)&dp_node, true, false);
347 	if (!string) {
348 		efi_st_error("ConvertDeviceNodeToText failed\n");
349 		return EFI_ST_FAILURE;
350 	}
351 	if (efi_st_strcmp_16_8(string, "u-boot")) {
352 		efi_st_printf("dp_node: %ps\n", string);
353 		efi_st_error(
354 			"Incorrect conversion by ConvertDeviceNodeToText\n");
355 		return EFI_ST_FAILURE;
356 	}
357 	ret = boottime->free_pool(string);
358 	if (ret != EFI_SUCCESS) {
359 		efi_st_error("FreePool failed\n");
360 		return EFI_ST_FAILURE;
361 	}
362 
363 	/* Test LocateDevicePath */
364 	remaining_dp = (struct efi_device_path *)dp3;
365 	ret = boottime->locate_device_path(&guid_protocol, &remaining_dp,
366 					   &handle);
367 	if (ret != EFI_SUCCESS) {
368 		efi_st_error("LocateDevicePath failed\n");
369 		return EFI_ST_FAILURE;
370 	}
371 	if (handle != handle2) {
372 		efi_st_error("LocateDevicePath returned wrong handle\n");
373 		return EFI_ST_FAILURE;
374 	}
375 	string = device_path_to_text->convert_device_path_to_text(remaining_dp,
376 								  true, false);
377 	if (!string) {
378 		efi_st_error("ConvertDevicePathToText failed\n");
379 		return EFI_ST_FAILURE;
380 	}
381 	if (efi_st_strcmp_16_8(string,
382 			       "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)")
383 	    ) {
384 		efi_st_printf("remaining device path: %ps\n", string);
385 		efi_st_error("LocateDevicePath: wrong remaining device path\n");
386 		return EFI_ST_FAILURE;
387 	}
388 	ret = boottime->free_pool(string);
389 	if (ret != EFI_SUCCESS) {
390 		efi_st_error("FreePool failed\n");
391 		return EFI_ST_FAILURE;
392 	}
393 
394 	return EFI_ST_SUCCESS;
395 }
396 
397 EFI_UNIT_TEST(devicepath) = {
398 	.name = "device path",
399 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
400 	.setup = setup,
401 	.execute = execute,
402 	.teardown = teardown,
403 };
404