1 /* 2 * efi_selftest_manageprotocols 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 * InstallProtocolInterface, UninstallProtocolInterface, 10 * InstallMultipleProtocolsInterfaces, UninstallMultipleProtocolsInterfaces, 11 * HandleProtocol, ProtocolsPerHandle, 12 * LocateHandle, LocateHandleBuffer. 13 */ 14 15 #include <efi_selftest.h> 16 17 /* 18 * The test currently does not actually call the interface function. 19 * So this is just a dummy structure. 20 */ 21 struct interface { 22 void (EFIAPI * inc)(void); 23 }; 24 25 static struct efi_boot_services *boottime; 26 static efi_guid_t guid1 = 27 EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a, 28 0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf); 29 static efi_guid_t guid2 = 30 EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77, 31 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f); 32 static efi_guid_t guid3 = 33 EFI_GUID(0x06d641a3, 0xf4e7, 0xe0c9, 34 0xe7, 0x8d, 0x41, 0x2d, 0x72, 0xa6, 0xb1, 0x24); 35 static efi_handle_t handle1; 36 static efi_handle_t handle2; 37 static struct interface interface1; 38 static struct interface interface2; 39 static struct interface interface3; 40 static struct interface interface4; 41 42 /* 43 * Find a handle in an array. 44 * 45 * @handle: handle to find 46 * @count: number of entries in the array 47 * @buffer: array to search 48 */ 49 efi_status_t find_in_buffer(efi_handle_t handle, size_t count, 50 efi_handle_t *buffer) 51 { 52 size_t i; 53 54 for (i = 0; i < count; ++i) { 55 if (buffer[i] == handle) 56 return EFI_SUCCESS; 57 } 58 return EFI_NOT_FOUND; 59 } 60 61 /* 62 * Setup unit test. 63 * 64 * Create two handles and install two out of three protocol interfaces on each 65 * of them: 66 * 67 * handle1 68 * guid1 interface1 69 * guid3 interface3 70 * handle2 71 * guid1 interface4 72 * guid2 interface2 73 * 74 * @handle: handle of the loaded image 75 * @systable: system table 76 */ 77 static int setup(const efi_handle_t img_handle, 78 const struct efi_system_table *systable) 79 { 80 efi_status_t ret; 81 efi_handle_t handle; 82 83 boottime = systable->boottime; 84 85 ret = boottime->install_protocol_interface(&handle1, &guid3, 86 EFI_NATIVE_INTERFACE, 87 &interface3); 88 if (ret != EFI_SUCCESS) { 89 efi_st_error("InstallProtocolInterface failed\n"); 90 return EFI_ST_FAILURE; 91 } 92 if (!handle1) { 93 efi_st_error("InstallProtocolInterface failed to create handle\n"); 94 return EFI_ST_FAILURE; 95 } 96 handle = handle1; 97 ret = boottime->install_protocol_interface(&handle1, &guid1, 98 EFI_NATIVE_INTERFACE, 99 &interface1); 100 if (ret != EFI_SUCCESS) { 101 efi_st_error("InstallProtocolInterface failed\n"); 102 return EFI_ST_FAILURE; 103 } 104 if (handle != handle1) { 105 efi_st_error("InstallProtocolInterface failed to use handle\n"); 106 return EFI_ST_FAILURE; 107 } 108 ret = boottime->install_multiple_protocol_interfaces(&handle2, 109 &guid1, &interface4, &guid2, &interface2, NULL); 110 if (ret != EFI_SUCCESS) { 111 efi_st_error("InstallMultipleProtocolInterfaces failed\n"); 112 return EFI_ST_FAILURE; 113 } 114 if (!handle2 || handle1 == handle2) { 115 efi_st_error("InstallMultipleProtocolInterfaces failed to create handle\n"); 116 return EFI_ST_FAILURE; 117 } 118 119 return EFI_ST_SUCCESS; 120 } 121 122 /* 123 * Tear down unit test. 124 * 125 */ 126 static int teardown(void) 127 { 128 return EFI_ST_SUCCESS; 129 } 130 131 /* 132 * Execute unit test. 133 * 134 */ 135 static int execute(void) 136 { 137 struct interface *interface; 138 efi_status_t ret; 139 efi_handle_t *buffer; 140 size_t buffer_size; 141 efi_uintn_t count = 0; 142 efi_guid_t **prot_buffer; 143 efi_uintn_t prot_count; 144 145 /* 146 * Test HandleProtocol 147 */ 148 ret = boottime->handle_protocol(handle1, &guid3, (void **)&interface); 149 if (ret != EFI_SUCCESS) { 150 efi_st_error("HandleProtocol failed to retrieve interface\n"); 151 return EFI_ST_FAILURE; 152 } 153 if (interface != &interface3) { 154 efi_st_error("HandleProtocol returned wrong interface\n"); 155 return EFI_ST_FAILURE; 156 } 157 ret = boottime->handle_protocol(handle1, &guid2, (void **)&interface); 158 if (ret == EFI_SUCCESS) { 159 efi_st_error("HandleProtocol returned not installed interface\n"); 160 return EFI_ST_FAILURE; 161 } 162 163 /* 164 * Test LocateHandleBuffer with AllHandles 165 */ 166 ret = boottime->locate_handle_buffer(ALL_HANDLES, NULL, NULL, 167 &count, &buffer); 168 if (ret != EFI_SUCCESS) { 169 efi_st_error("LocateHandleBuffer with AllHandles failed\n"); 170 return EFI_ST_FAILURE; 171 } 172 buffer_size = count; 173 ret = find_in_buffer(handle1, count, buffer); 174 if (ret != EFI_SUCCESS) { 175 efi_st_error("LocateHandleBuffer failed to locate new handle\n"); 176 return EFI_ST_FAILURE; 177 } 178 ret = find_in_buffer(handle2, count, buffer); 179 if (ret != EFI_SUCCESS) { 180 efi_st_error("LocateHandleBuffer failed to locate new handle\n"); 181 return EFI_ST_FAILURE; 182 } 183 boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); 184 185 /* 186 * Test error handling in UninstallMultipleProtocols 187 * 188 * Try to uninstall more protocols than there are installed. 189 */ 190 ret = boottime->uninstall_multiple_protocol_interfaces( 191 handle2, 192 &guid1, &interface4, 193 &guid2, &interface2, 194 &guid3, &interface3, 195 NULL); 196 if (ret == EFI_SUCCESS) { 197 efi_st_todo("UninstallMultipleProtocolInterfaces did not catch error\n"); 198 return EFI_ST_FAILURE; 199 } 200 201 /* 202 * Test LocateHandleBuffer with ByProtocol 203 */ 204 count = buffer_size; 205 ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, 206 &count, &buffer); 207 if (ret != EFI_SUCCESS) { 208 efi_st_error("LocateHandleBuffer failed to locate new handles\n"); 209 return EFI_ST_FAILURE; 210 } 211 if (count != 2) { 212 efi_st_error("LocateHandleBuffer failed to locate new handles\n"); 213 return EFI_ST_FAILURE; 214 } 215 ret = find_in_buffer(handle1, count, buffer); 216 if (ret != EFI_SUCCESS) { 217 efi_st_error("LocateHandleBuffer failed to locate new handle\n"); 218 return EFI_ST_FAILURE; 219 } 220 ret = find_in_buffer(handle2, count, buffer); 221 if (ret != EFI_SUCCESS) { 222 efi_st_error("LocateHandleBuffer failed to locate new handle\n"); 223 return EFI_ST_FAILURE; 224 } 225 boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); 226 227 /* 228 * Test LocateHandle with ByProtocol 229 */ 230 count = buffer_size * sizeof(efi_handle_t); 231 ret = boottime->locate_handle(BY_PROTOCOL, &guid1, NULL, 232 &count, buffer); 233 if (ret != EFI_SUCCESS) { 234 efi_st_error("LocateHandle with ByProtocol failed\n"); 235 return EFI_ST_FAILURE; 236 } 237 if (count / sizeof(efi_handle_t) != 2) { 238 efi_st_error("LocateHandle failed to locate new handles\n"); 239 return EFI_ST_FAILURE; 240 } 241 buffer_size = count; 242 ret = find_in_buffer(handle1, count, buffer); 243 if (ret != EFI_SUCCESS) { 244 efi_st_error("LocateHandle failed to locate new handles\n"); 245 return EFI_ST_FAILURE; 246 } 247 ret = find_in_buffer(handle2, count, buffer); 248 if (ret != EFI_SUCCESS) { 249 efi_st_error("LocateHandle failed to locate new handles\n"); 250 return EFI_ST_FAILURE; 251 } 252 boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); 253 254 /* 255 * Test LocateProtocol 256 */ 257 ret = boottime->locate_protocol(&guid1, NULL, (void **)&interface); 258 if (ret != EFI_SUCCESS) { 259 efi_st_error("LocateProtocol failed\n"); 260 return EFI_ST_FAILURE; 261 } 262 if (interface != &interface1 && interface != &interface4) { 263 efi_st_error("LocateProtocol failed to locate protocol\n"); 264 return EFI_ST_FAILURE; 265 } 266 267 /* 268 * Test UninstallMultipleProtocols 269 */ 270 ret = boottime->uninstall_multiple_protocol_interfaces( 271 handle2, 272 &guid1, &interface4, 273 &guid2, &interface2, 274 NULL); 275 if (ret != EFI_SUCCESS) { 276 efi_st_todo("UninstallMultipleProtocolInterfaces failed\n"); 277 /* This test is known to fail due to missing implementation */ 278 } 279 /* 280 * Check that the protocols are really uninstalled. 281 */ 282 count = buffer_size; 283 ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, 284 &count, &buffer); 285 if (ret != EFI_SUCCESS) { 286 efi_st_error("LocateHandleBuffer failed\n"); 287 return EFI_ST_FAILURE; 288 } 289 if (count != 1) { 290 efi_st_todo("UninstallMultipleProtocolInterfaces failed to uninstall protocols\n"); 291 /* This test is known to fail due to missing implementation */ 292 } 293 ret = find_in_buffer(handle1, count, buffer); 294 if (ret != EFI_SUCCESS) { 295 efi_st_error("Failed to locate new handle\n"); 296 return EFI_ST_FAILURE; 297 } 298 boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); 299 300 /* 301 * Test ProtocolsPerHandle 302 */ 303 ret = boottime->protocols_per_handle(handle1, 304 &prot_buffer, &prot_count); 305 if (ret != EFI_SUCCESS) { 306 efi_st_error("Failed to get protocols per handle\n"); 307 return EFI_ST_FAILURE; 308 } 309 if (prot_count != 2) { 310 efi_st_error("Failed to get protocols per handle\n"); 311 return EFI_ST_FAILURE; 312 } 313 if (efi_st_memcmp(prot_buffer[0], &guid1, 16) && 314 efi_st_memcmp(prot_buffer[1], &guid1, 16)) { 315 efi_st_error("Failed to get protocols per handle\n"); 316 return EFI_ST_FAILURE; 317 } 318 if (efi_st_memcmp(prot_buffer[0], &guid3, 16) && 319 efi_st_memcmp(prot_buffer[1], &guid3, 16)) { 320 efi_st_error("Failed to get protocols per handle\n"); 321 return EFI_ST_FAILURE; 322 } 323 324 /* 325 * Uninstall remaining protocols 326 */ 327 ret = boottime->uninstall_protocol_interface(handle1, &guid1, 328 &interface1); 329 if (ret != EFI_SUCCESS) { 330 efi_st_todo("UninstallProtocolInterface failed\n"); 331 /* This test is known to fail due to missing implementation */ 332 } 333 ret = boottime->handle_protocol(handle1, &guid1, (void **)&interface); 334 if (ret == EFI_SUCCESS) { 335 efi_st_todo("UninstallProtocolInterface failed\n"); 336 /* This test is known to fail due to missing implementation */ 337 } 338 ret = boottime->uninstall_protocol_interface(handle1, &guid3, 339 &interface1); 340 if (ret != EFI_SUCCESS) { 341 efi_st_todo("UninstallProtocolInterface failed\n"); 342 /* This test is known to fail due to missing implementation */ 343 } 344 345 return EFI_ST_SUCCESS; 346 } 347 348 EFI_UNIT_TEST(protserv) = { 349 .name = "manage protocols", 350 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 351 .setup = setup, 352 .execute = execute, 353 .teardown = teardown, 354 }; 355