1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * efi_selftest_controllers 4 * 5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 6 * 7 * This unit test checks the following protocol services: 8 * ConnectController, DisconnectController, 9 * InstallProtocol, ReinstallProtocol, UninstallProtocol, 10 * OpenProtocol, CloseProtcol, OpenProtocolInformation 11 */ 12 13 #include <efi_selftest.h> 14 15 #define NUMBER_OF_CHILD_CONTROLLERS 4 16 17 static int interface1 = 1; 18 static int interface2 = 2; 19 static struct efi_boot_services *boottime; 20 const efi_guid_t guid_driver_binding_protocol = 21 EFI_DRIVER_BINDING_PROTOCOL_GUID; 22 static efi_guid_t guid_controller = 23 EFI_GUID(0xe6ab1d96, 0x6bff, 0xdb42, 24 0xaa, 0x05, 0xc8, 0x1f, 0x7f, 0x45, 0x26, 0x34); 25 static efi_guid_t guid_child_controller = 26 EFI_GUID(0x1d41f6f5, 0x2c41, 0xddfb, 27 0xe2, 0x9b, 0xb8, 0x0e, 0x2e, 0xe8, 0x3a, 0x85); 28 static efi_handle_t handle_controller; 29 static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS]; 30 static efi_handle_t handle_driver; 31 32 /* 33 * Count child controllers 34 * 35 * @handle handle on which child controllers are installed 36 * @protocol protocol for which the child controlles where installed 37 * @count number of child controllers 38 * @return status code 39 */ 40 static efi_status_t count_child_controllers(efi_handle_t handle, 41 efi_guid_t *protocol, 42 efi_uintn_t *count) 43 { 44 efi_status_t ret; 45 efi_uintn_t entry_count; 46 struct efi_open_protocol_info_entry *entry_buffer; 47 48 *count = 0; 49 ret = boottime->open_protocol_information(handle, protocol, 50 &entry_buffer, &entry_count); 51 if (ret != EFI_SUCCESS) 52 return ret; 53 if (!entry_count) 54 return EFI_SUCCESS; 55 while (entry_count) { 56 if (entry_buffer[--entry_count].attributes & 57 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) 58 ++*count; 59 } 60 ret = boottime->free_pool(entry_buffer); 61 if (ret != EFI_SUCCESS) 62 efi_st_error("Cannot free buffer\n"); 63 return ret; 64 } 65 66 /* 67 * Check if the driver supports the controller. 68 * 69 * @this driver binding protocol 70 * @controller_handle handle of the controller 71 * @remaining_device_path path specifying the child controller 72 * @return status code 73 */ 74 static efi_status_t EFIAPI supported( 75 struct efi_driver_binding_protocol *this, 76 efi_handle_t controller_handle, 77 struct efi_device_path *remaining_device_path) 78 { 79 efi_status_t ret; 80 void *interface; 81 82 ret = boottime->open_protocol( 83 controller_handle, &guid_controller, 84 &interface, handle_driver, 85 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER); 86 switch (ret) { 87 case EFI_ACCESS_DENIED: 88 case EFI_ALREADY_STARTED: 89 return ret; 90 case EFI_SUCCESS: 91 break; 92 default: 93 return EFI_UNSUPPORTED; 94 } 95 ret = boottime->close_protocol( 96 controller_handle, &guid_controller, 97 handle_driver, controller_handle); 98 if (ret != EFI_SUCCESS) 99 ret = EFI_UNSUPPORTED; 100 return ret; 101 } 102 103 /* 104 * Create child controllers and attach driver. 105 * 106 * @this driver binding protocol 107 * @controller_handle handle of the controller 108 * @remaining_device_path path specifying the child controller 109 * @return status code 110 */ 111 static efi_status_t EFIAPI start( 112 struct efi_driver_binding_protocol *this, 113 efi_handle_t controller_handle, 114 struct efi_device_path *remaining_device_path) 115 { 116 size_t i; 117 efi_status_t ret; 118 void *interface; 119 120 /* Attach driver to controller */ 121 ret = boottime->open_protocol( 122 controller_handle, &guid_controller, 123 &interface, handle_driver, 124 controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER); 125 switch (ret) { 126 case EFI_ACCESS_DENIED: 127 case EFI_ALREADY_STARTED: 128 return ret; 129 case EFI_SUCCESS: 130 break; 131 default: 132 return EFI_UNSUPPORTED; 133 } 134 135 /* Create child controllers */ 136 for (i = 0; i < NUMBER_OF_CHILD_CONTROLLERS; ++i) { 137 /* Creating a new handle for the child controller */ 138 handle_child_controller[i] = 0; 139 ret = boottime->install_protocol_interface( 140 &handle_child_controller[i], &guid_child_controller, 141 EFI_NATIVE_INTERFACE, NULL); 142 if (ret != EFI_SUCCESS) { 143 efi_st_error("InstallProtocolInterface failed\n"); 144 return EFI_ST_FAILURE; 145 } 146 ret = boottime->open_protocol( 147 controller_handle, &guid_controller, 148 &interface, handle_child_controller[i], 149 handle_child_controller[i], 150 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); 151 if (ret != EFI_SUCCESS) { 152 efi_st_error("OpenProtocol failed\n"); 153 return EFI_ST_FAILURE; 154 } 155 } 156 return ret; 157 } 158 159 /* 160 * Remove a single child controller from the parent controller. 161 * 162 * @controller_handle parent controller 163 * @child_handle child controller 164 * @return status code 165 */ 166 static efi_status_t disconnect_child(efi_handle_t controller_handle, 167 efi_handle_t child_handle) 168 { 169 efi_status_t ret; 170 171 ret = boottime->close_protocol( 172 controller_handle, &guid_controller, 173 child_handle, child_handle); 174 if (ret != EFI_SUCCESS) { 175 efi_st_error("Cannot close protocol\n"); 176 return ret; 177 } 178 ret = boottime->uninstall_protocol_interface( 179 child_handle, &guid_child_controller, NULL); 180 if (ret != EFI_SUCCESS) { 181 efi_st_error("Cannot uninstall protocol interface\n"); 182 return ret; 183 } 184 return ret; 185 } 186 187 /* 188 * Remove child controllers and disconnect the controller. 189 * 190 * @this driver binding protocol 191 * @controller_handle handle of the controller 192 * @number_of_children number of child controllers to remove 193 * @child_handle_buffer handles of the child controllers to remove 194 * @return status code 195 */ 196 static efi_status_t EFIAPI stop( 197 struct efi_driver_binding_protocol *this, 198 efi_handle_t controller_handle, 199 size_t number_of_children, 200 efi_handle_t *child_handle_buffer) 201 { 202 efi_status_t ret; 203 efi_uintn_t count; 204 struct efi_open_protocol_info_entry *entry_buffer; 205 206 /* Destroy provided child controllers */ 207 if (number_of_children) { 208 efi_uintn_t i; 209 210 for (i = 0; i < number_of_children; ++i) { 211 ret = disconnect_child(controller_handle, 212 child_handle_buffer[i]); 213 if (ret != EFI_SUCCESS) 214 return ret; 215 } 216 return EFI_SUCCESS; 217 } 218 219 /* Destroy all children */ 220 ret = boottime->open_protocol_information( 221 controller_handle, &guid_controller, 222 &entry_buffer, &count); 223 if (ret != EFI_SUCCESS) { 224 efi_st_error("OpenProtocolInformation failed\n"); 225 return ret; 226 } 227 while (count) { 228 if (entry_buffer[--count].attributes & 229 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { 230 ret = disconnect_child( 231 controller_handle, 232 entry_buffer[count].agent_handle); 233 if (ret != EFI_SUCCESS) 234 return ret; 235 } 236 } 237 ret = boottime->free_pool(entry_buffer); 238 if (ret != EFI_SUCCESS) 239 efi_st_error("Cannot free buffer\n"); 240 241 /* Detach driver from controller */ 242 ret = boottime->close_protocol( 243 controller_handle, &guid_controller, 244 handle_driver, controller_handle); 245 if (ret != EFI_SUCCESS) { 246 efi_st_error("Cannot close protocol\n"); 247 return ret; 248 } 249 return EFI_SUCCESS; 250 } 251 252 /* Driver binding protocol interface */ 253 static struct efi_driver_binding_protocol binding_interface = { 254 supported, 255 start, 256 stop, 257 0xffffffff, 258 NULL, 259 NULL, 260 }; 261 262 /* 263 * Setup unit test. 264 * 265 * @handle handle of the loaded image 266 * @systable system table 267 */ 268 static int setup(const efi_handle_t img_handle, 269 const struct efi_system_table *systable) 270 { 271 efi_status_t ret; 272 273 boottime = systable->boottime; 274 275 /* Create controller handle */ 276 ret = boottime->install_protocol_interface( 277 &handle_controller, &guid_controller, 278 EFI_NATIVE_INTERFACE, &interface1); 279 if (ret != EFI_SUCCESS) { 280 efi_st_error("InstallProtocolInterface failed\n"); 281 return EFI_ST_FAILURE; 282 } 283 /* Create driver handle */ 284 ret = boottime->install_protocol_interface( 285 &handle_driver, &guid_driver_binding_protocol, 286 EFI_NATIVE_INTERFACE, &binding_interface); 287 if (ret != EFI_SUCCESS) { 288 efi_st_error("InstallProtocolInterface failed\n"); 289 return EFI_ST_FAILURE; 290 } 291 292 return EFI_ST_SUCCESS; 293 } 294 295 /* 296 * Execute unit test. 297 * 298 * The number of child controllers is checked after each of the following 299 * actions: 300 * 301 * Connect a controller to a driver. 302 * Disconnect and destroy a child controller. 303 * Disconnect and destroy the remaining child controllers. 304 * 305 * Connect a controller to a driver. 306 * Reinstall the driver protocol on the controller. 307 * Uninstall the driver protocol from the controller. 308 */ 309 static int execute(void) 310 { 311 efi_status_t ret; 312 efi_uintn_t count; 313 314 /* Connect controller to driver */ 315 ret = boottime->connect_controller(handle_controller, NULL, NULL, 1); 316 if (ret != EFI_SUCCESS) { 317 efi_st_error("Failed to connect controller\n"); 318 return EFI_ST_FAILURE; 319 } 320 /* Check number of child controllers */ 321 ret = count_child_controllers(handle_controller, &guid_controller, 322 &count); 323 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) { 324 efi_st_error("Number of children %u != %u\n", 325 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS); 326 } 327 /* Destroy second child controller */ 328 ret = boottime->disconnect_controller(handle_controller, 329 handle_driver, 330 handle_child_controller[1]); 331 if (ret != EFI_SUCCESS) { 332 efi_st_error("Failed to disconnect child controller\n"); 333 return EFI_ST_FAILURE; 334 } 335 /* Check number of child controllers */ 336 ret = count_child_controllers(handle_controller, &guid_controller, 337 &count); 338 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS - 1) { 339 efi_st_error("Destroying single child controller failed\n"); 340 return EFI_ST_FAILURE; 341 } 342 /* Destroy remaining child controllers and disconnect controller */ 343 ret = boottime->disconnect_controller(handle_controller, NULL, NULL); 344 if (ret != EFI_SUCCESS) { 345 efi_st_error("Failed to disconnect controller\n"); 346 return EFI_ST_FAILURE; 347 } 348 /* Check number of child controllers */ 349 ret = count_child_controllers(handle_controller, &guid_controller, 350 &count); 351 if (ret != EFI_SUCCESS || count) { 352 efi_st_error("Destroying child controllers failed\n"); 353 return EFI_ST_FAILURE; 354 } 355 356 /* Connect controller to driver */ 357 ret = boottime->connect_controller(handle_controller, NULL, NULL, 1); 358 if (ret != EFI_SUCCESS) { 359 efi_st_error("Failed to connect controller\n"); 360 return EFI_ST_FAILURE; 361 } 362 /* Check number of child controllers */ 363 ret = count_child_controllers(handle_controller, &guid_controller, 364 &count); 365 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) { 366 efi_st_error("Number of children %u != %u\n", 367 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS); 368 } 369 /* Try to uninstall controller protocol using the wrong interface */ 370 ret = boottime->uninstall_protocol_interface(handle_controller, 371 &guid_controller, 372 &interface2); 373 if (ret == EFI_SUCCESS) { 374 efi_st_error( 375 "Interface not checked when uninstalling protocol\n"); 376 return EFI_ST_FAILURE; 377 } 378 /* Reinstall controller protocol */ 379 ret = boottime->reinstall_protocol_interface(handle_controller, 380 &guid_controller, 381 &interface1, 382 &interface2); 383 if (ret != EFI_SUCCESS) { 384 efi_st_error("Failed to reinstall protocols\n"); 385 return EFI_ST_FAILURE; 386 } 387 /* Check number of child controllers */ 388 ret = count_child_controllers(handle_controller, &guid_controller, 389 &count); 390 if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) { 391 efi_st_error("Number of children %u != %u\n", 392 (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS); 393 } 394 /* Uninstall controller protocol */ 395 ret = boottime->uninstall_protocol_interface(handle_controller, 396 &guid_controller, 397 &interface2); 398 if (ret != EFI_SUCCESS) { 399 efi_st_error("Failed to uninstall protocols\n"); 400 return EFI_ST_FAILURE; 401 } 402 /* Check number of child controllers */ 403 ret = count_child_controllers(handle_controller, &guid_controller, 404 &count); 405 if (ret == EFI_SUCCESS) 406 efi_st_error("Uninstall failed\n"); 407 return EFI_ST_SUCCESS; 408 } 409 410 EFI_UNIT_TEST(controllers) = { 411 .name = "controllers", 412 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 413 .setup = setup, 414 .execute = execute, 415 }; 416