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 * Try to uninstall more protocols than there are installed. 193 */ 194 ret = boottime->uninstall_multiple_protocol_interfaces( 195 handle2, 196 &guid1, &interface4, 197 &guid2, &interface2, 198 &guid3, &interface3, 199 NULL); 200 if (ret == EFI_SUCCESS) { 201 efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n"); 202 return EFI_ST_FAILURE; 203 } 204 205 /* 206 * Test LocateHandleBuffer with ByProtocol 207 */ 208 count = buffer_size; 209 ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, 210 &count, &buffer); 211 if (ret != EFI_SUCCESS) { 212 efi_st_error("LocateHandleBuffer failed to locate new handles\n"); 213 return EFI_ST_FAILURE; 214 } 215 if (count != 2) { 216 efi_st_error("LocateHandleBuffer failed to locate new handles\n"); 217 return EFI_ST_FAILURE; 218 } 219 ret = find_in_buffer(handle1, count, buffer); 220 if (ret != EFI_SUCCESS) { 221 efi_st_error("LocateHandleBuffer failed to locate new handle\n"); 222 return EFI_ST_FAILURE; 223 } 224 ret = find_in_buffer(handle2, count, buffer); 225 if (ret != EFI_SUCCESS) { 226 efi_st_error("LocateHandleBuffer failed to locate new handle\n"); 227 return EFI_ST_FAILURE; 228 } 229 /* Clear the buffer, we are reusing it it the next step. */ 230 boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); 231 232 /* 233 * Test LocateHandle with ByProtocol 234 */ 235 count = buffer_size * sizeof(efi_handle_t); 236 ret = boottime->locate_handle(BY_PROTOCOL, &guid1, NULL, 237 &count, buffer); 238 if (ret != EFI_SUCCESS) { 239 efi_st_error("LocateHandle with ByProtocol failed\n"); 240 return EFI_ST_FAILURE; 241 } 242 if (count / sizeof(efi_handle_t) != 2) { 243 efi_st_error("LocateHandle failed to locate new handles\n"); 244 return EFI_ST_FAILURE; 245 } 246 buffer_size = count; 247 ret = find_in_buffer(handle1, 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 ret = find_in_buffer(handle2, count, buffer); 253 if (ret != EFI_SUCCESS) { 254 efi_st_error("LocateHandle failed to locate new handles\n"); 255 return EFI_ST_FAILURE; 256 } 257 /* Release buffer */ 258 ret = boottime->free_pool(buffer); 259 if (ret != EFI_SUCCESS) { 260 efi_st_error("FreePool failed\n"); 261 return EFI_ST_FAILURE; 262 } 263 264 /* 265 * Test LocateProtocol 266 */ 267 ret = boottime->locate_protocol(&guid1, NULL, (void **)&interface); 268 if (ret != EFI_SUCCESS) { 269 efi_st_error("LocateProtocol failed\n"); 270 return EFI_ST_FAILURE; 271 } 272 if (interface != &interface1 && interface != &interface4) { 273 efi_st_error("LocateProtocol failed to locate protocol\n"); 274 return EFI_ST_FAILURE; 275 } 276 277 /* 278 * Test UninstallMultipleProtocols 279 */ 280 ret = boottime->uninstall_multiple_protocol_interfaces( 281 handle2, 282 &guid1, &interface4, 283 &guid2, &interface2, 284 NULL); 285 if (ret != EFI_SUCCESS) { 286 efi_st_error("UninstallMultipleProtocolInterfaces failed\n"); 287 return EFI_ST_FAILURE; 288 } 289 /* 290 * Check that the protocols are really uninstalled. 291 */ 292 count = buffer_size; 293 ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, 294 &count, &buffer); 295 if (ret != EFI_SUCCESS) { 296 efi_st_error("LocateHandleBuffer failed\n"); 297 return EFI_ST_FAILURE; 298 } 299 if (count != 1) { 300 efi_st_error("UninstallMultipleProtocolInterfaces failed to uninstall protocols\n"); 301 return EFI_ST_FAILURE; 302 } 303 ret = find_in_buffer(handle1, count, buffer); 304 if (ret != EFI_SUCCESS) { 305 efi_st_error("Failed to locate new handle\n"); 306 return EFI_ST_FAILURE; 307 } 308 boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); 309 310 /* 311 * Test ProtocolsPerHandle 312 */ 313 ret = boottime->protocols_per_handle(handle1, 314 &prot_buffer, &prot_count); 315 if (ret != EFI_SUCCESS) { 316 efi_st_error("Failed to get protocols per handle\n"); 317 return EFI_ST_FAILURE; 318 } 319 if (prot_count != 2) { 320 efi_st_error("Failed to get protocols per handle\n"); 321 return EFI_ST_FAILURE; 322 } 323 if (efi_st_memcmp(prot_buffer[0], &guid1, 16) && 324 efi_st_memcmp(prot_buffer[1], &guid1, 16)) { 325 efi_st_error("Failed to get protocols per handle\n"); 326 return EFI_ST_FAILURE; 327 } 328 if (efi_st_memcmp(prot_buffer[0], &guid3, 16) && 329 efi_st_memcmp(prot_buffer[1], &guid3, 16)) { 330 efi_st_error("Failed to get protocols per handle\n"); 331 return EFI_ST_FAILURE; 332 } 333 /* Release buffer */ 334 ret = boottime->free_pool(prot_buffer); 335 if (ret != EFI_SUCCESS) { 336 efi_st_error("FreePool failed\n"); 337 return EFI_ST_FAILURE; 338 } 339 340 /* 341 * Uninstall remaining protocols 342 */ 343 ret = boottime->uninstall_protocol_interface(handle1, &guid1, 344 &interface1); 345 if (ret != EFI_SUCCESS) { 346 efi_st_error("UninstallProtocolInterface failed\n"); 347 return EFI_ST_FAILURE; 348 } 349 ret = boottime->handle_protocol(handle1, &guid1, (void **)&interface); 350 if (ret == EFI_SUCCESS) { 351 efi_st_error("UninstallProtocolInterface failed\n"); 352 return EFI_ST_FAILURE; 353 } 354 ret = boottime->uninstall_protocol_interface(handle1, &guid3, 355 &interface3); 356 if (ret != EFI_SUCCESS) { 357 efi_st_error("UninstallProtocolInterface failed\n"); 358 return EFI_ST_FAILURE; 359 } 360 361 return EFI_ST_SUCCESS; 362 } 363 364 EFI_UNIT_TEST(protserv) = { 365 .name = "manage protocols", 366 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 367 .setup = setup, 368 .execute = execute, 369 .teardown = teardown, 370 }; 371