Home | History | Annotate | Download | only in efi_selftest
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * efi_selftest_devicepath
      4  *
      5  * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk (at) 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 	void *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