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