blob: d9a669789243ddd8d023a2b17b24a75e422ab362 [file] [log] [blame]
Heinrich Schuchardt37daf872017-11-26 14:05:11 +01001/*
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
14static struct efi_boot_services *boottime;
15
16static efi_handle_t handle1;
17static efi_handle_t handle2;
18static efi_handle_t handle3;
19
20struct interface {
21 void (EFIAPI * inc)(void);
22} interface;
23
24static efi_guid_t guid_device_path = DEVICE_PATH_GUID;
25
26static efi_guid_t guid_device_path_to_text_protocol =
27 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
28
29static efi_guid_t guid_protocol =
30 EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
31 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0x7d);
32
33static efi_guid_t guid_vendor1 =
34 EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
35 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xb1);
36
37static efi_guid_t guid_vendor2 =
38 EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
39 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xa2);
40
41static efi_guid_t guid_vendor3 =
42 EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d,
43 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xc3);
44
45static u8 *dp1;
46static u8 *dp2;
47static u8 *dp3;
48
49struct 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 */
66static 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
182out_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 */
191static 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 */
248static 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 }
Heinrich Schuchardt5d09b5e2018-01-11 08:15:56 +0100302 /*
303 * CloseProtocol cannot be called without agent handle.
304 * There is no need to close the device path protocol.
305 */
Heinrich Schuchardt37daf872017-11-26 14:05:11 +0100306 }
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
384EFI_UNIT_TEST(devicepath) = {
385 .name = "device path",
386 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
387 .setup = setup,
388 .execute = execute,
389 .teardown = teardown,
390};