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