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