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 */ 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 */ 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 */ 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