]>
Commit | Line | Data |
---|---|---|
bf19064b HS |
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 | } | |
5be9744a HS |
302 | /* |
303 | * CloseProtocol cannot be called without agent handle. | |
304 | * There is no need to close the device path protocol. | |
305 | */ | |
bf19064b HS |
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 | }; |