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 } 302 ret = boottime->close_protocol(handles[i], &guid_device_path, 303 NULL, NULL); 304 if (ret != EFI_SUCCESS) 305 efi_st_todo("Cannot close device path protocol.\n"); 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 }; 391