Commit f0959dbee2b043c4b1bf16a570be9242cf603819
Committed by
Alexander Graf
1 parent
d550414434
Exists in
smarc_8mq_lf_v2020.04
and in
17 other branches
efi_loader: implement ConnectController
Implement the ConnectController boot service. A unit test is supplied in a subsequent patch. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Alexander Graf <agraf@suse.de>
Showing 3 changed files with 187 additions and 24 deletions Side-by-side Diff
include/efi_api.h
... | ... | @@ -805,5 +805,27 @@ |
805 | 805 | s16 file_name[0]; |
806 | 806 | }; |
807 | 807 | |
808 | +#define EFI_DRIVER_BINDING_PROTOCOL_GUID \ | |
809 | + EFI_GUID(0x18a031ab, 0xb443, 0x4d1a,\ | |
810 | + 0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71) | |
811 | +struct efi_driver_binding_protocol { | |
812 | + efi_status_t (EFIAPI * supported)( | |
813 | + struct efi_driver_binding_protocol *this, | |
814 | + efi_handle_t controller_handle, | |
815 | + struct efi_device_path *remaining_device_path); | |
816 | + efi_status_t (EFIAPI * start)( | |
817 | + struct efi_driver_binding_protocol *this, | |
818 | + efi_handle_t controller_handle, | |
819 | + struct efi_device_path *remaining_device_path); | |
820 | + efi_status_t (EFIAPI * stop)( | |
821 | + struct efi_driver_binding_protocol *this, | |
822 | + efi_handle_t controller_handle, | |
823 | + efi_uintn_t number_of_children, | |
824 | + efi_handle_t *child_handle_buffer); | |
825 | + u32 version; | |
826 | + efi_handle_t image_handle; | |
827 | + efi_handle_t driver_binding_handle; | |
828 | +}; | |
829 | + | |
808 | 830 | #endif |
include/efi_loader.h
... | ... | @@ -89,6 +89,8 @@ |
89 | 89 | extern const efi_guid_t efi_global_variable_guid; |
90 | 90 | extern const efi_guid_t efi_guid_console_control; |
91 | 91 | extern const efi_guid_t efi_guid_device_path; |
92 | +/* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ | |
93 | +extern const efi_guid_t efi_guid_driver_binding_protocol; | |
92 | 94 | extern const efi_guid_t efi_guid_loaded_image; |
93 | 95 | extern const efi_guid_t efi_guid_device_path_to_text_protocol; |
94 | 96 | extern const efi_guid_t efi_simple_file_system_protocol_guid; |
lib/efi_loader/efi_boottime.c
... | ... | @@ -56,6 +56,9 @@ |
56 | 56 | |
57 | 57 | static int entry_count; |
58 | 58 | static int nesting_level; |
59 | +/* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ | |
60 | +const efi_guid_t efi_guid_driver_binding_protocol = | |
61 | + EFI_DRIVER_BINDING_PROTOCOL_GUID; | |
59 | 62 | |
60 | 63 | /* Called on every callback entry */ |
61 | 64 | int __efi_entry_check(void) |
... | ... | @@ -1635,30 +1638,6 @@ |
1635 | 1638 | } |
1636 | 1639 | |
1637 | 1640 | /* |
1638 | - * Connect a controller to a driver. | |
1639 | - * | |
1640 | - * This function implements the ConnectController service. | |
1641 | - * See the Unified Extensible Firmware Interface (UEFI) specification | |
1642 | - * for details. | |
1643 | - * | |
1644 | - * @controller_handle handle of the controller | |
1645 | - * @driver_image_handle handle of the driver | |
1646 | - * @remain_device_path device path of a child controller | |
1647 | - * @recursive true to connect all child controllers | |
1648 | - * @return status code | |
1649 | - */ | |
1650 | -static efi_status_t EFIAPI efi_connect_controller( | |
1651 | - efi_handle_t controller_handle, | |
1652 | - efi_handle_t *driver_image_handle, | |
1653 | - struct efi_device_path *remain_device_path, | |
1654 | - bool recursive) | |
1655 | -{ | |
1656 | - EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle, | |
1657 | - remain_device_path, recursive); | |
1658 | - return EFI_EXIT(EFI_NOT_FOUND); | |
1659 | -} | |
1660 | - | |
1661 | -/* | |
1662 | 1641 | * Disconnect a controller from a driver. |
1663 | 1642 | * |
1664 | 1643 | * This function implements the DisconnectController service. |
... | ... | @@ -2366,6 +2345,166 @@ |
2366 | 2345 | { |
2367 | 2346 | return efi_open_protocol(handle, protocol, protocol_interface, NULL, |
2368 | 2347 | NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); |
2348 | +} | |
2349 | + | |
2350 | +static efi_status_t efi_bind_controller( | |
2351 | + efi_handle_t controller_handle, | |
2352 | + efi_handle_t driver_image_handle, | |
2353 | + struct efi_device_path *remain_device_path) | |
2354 | +{ | |
2355 | + struct efi_driver_binding_protocol *binding_protocol; | |
2356 | + efi_status_t r; | |
2357 | + | |
2358 | + r = EFI_CALL(efi_open_protocol(driver_image_handle, | |
2359 | + &efi_guid_driver_binding_protocol, | |
2360 | + (void **)&binding_protocol, | |
2361 | + driver_image_handle, NULL, | |
2362 | + EFI_OPEN_PROTOCOL_GET_PROTOCOL)); | |
2363 | + if (r != EFI_SUCCESS) | |
2364 | + return r; | |
2365 | + r = EFI_CALL(binding_protocol->supported(binding_protocol, | |
2366 | + controller_handle, | |
2367 | + remain_device_path)); | |
2368 | + if (r == EFI_SUCCESS) | |
2369 | + r = EFI_CALL(binding_protocol->start(binding_protocol, | |
2370 | + controller_handle, | |
2371 | + remain_device_path)); | |
2372 | + EFI_CALL(efi_close_protocol(driver_image_handle, | |
2373 | + &efi_guid_driver_binding_protocol, | |
2374 | + driver_image_handle, NULL)); | |
2375 | + return r; | |
2376 | +} | |
2377 | + | |
2378 | +static efi_status_t efi_connect_single_controller( | |
2379 | + efi_handle_t controller_handle, | |
2380 | + efi_handle_t *driver_image_handle, | |
2381 | + struct efi_device_path *remain_device_path) | |
2382 | +{ | |
2383 | + efi_handle_t *buffer; | |
2384 | + size_t count; | |
2385 | + size_t i; | |
2386 | + efi_status_t r; | |
2387 | + size_t connected = 0; | |
2388 | + | |
2389 | + /* Get buffer with all handles with driver binding protocol */ | |
2390 | + r = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, | |
2391 | + &efi_guid_driver_binding_protocol, | |
2392 | + NULL, &count, &buffer)); | |
2393 | + if (r != EFI_SUCCESS) | |
2394 | + return r; | |
2395 | + | |
2396 | + /* Context Override */ | |
2397 | + if (driver_image_handle) { | |
2398 | + for (; *driver_image_handle; ++driver_image_handle) { | |
2399 | + for (i = 0; i < count; ++i) { | |
2400 | + if (buffer[i] == *driver_image_handle) { | |
2401 | + buffer[i] = NULL; | |
2402 | + r = efi_bind_controller( | |
2403 | + controller_handle, | |
2404 | + *driver_image_handle, | |
2405 | + remain_device_path); | |
2406 | + /* | |
2407 | + * For drivers that do not support the | |
2408 | + * controller or are already connected | |
2409 | + * we receive an error code here. | |
2410 | + */ | |
2411 | + if (r == EFI_SUCCESS) | |
2412 | + ++connected; | |
2413 | + } | |
2414 | + } | |
2415 | + } | |
2416 | + } | |
2417 | + | |
2418 | + /* | |
2419 | + * TODO: Some overrides are not yet implemented: | |
2420 | + * - Platform Driver Override | |
2421 | + * - Driver Family Override Search | |
2422 | + * - Bus Specific Driver Override | |
2423 | + */ | |
2424 | + | |
2425 | + /* Driver Binding Search */ | |
2426 | + for (i = 0; i < count; ++i) { | |
2427 | + if (buffer[i]) { | |
2428 | + r = efi_bind_controller(controller_handle, | |
2429 | + buffer[i], | |
2430 | + remain_device_path); | |
2431 | + if (r == EFI_SUCCESS) | |
2432 | + ++connected; | |
2433 | + } | |
2434 | + } | |
2435 | + | |
2436 | + efi_free_pool(buffer); | |
2437 | + if (!connected) | |
2438 | + return EFI_NOT_FOUND; | |
2439 | + return EFI_SUCCESS; | |
2440 | +} | |
2441 | + | |
2442 | +/* | |
2443 | + * Connect a controller to a driver. | |
2444 | + * | |
2445 | + * This function implements the ConnectController service. | |
2446 | + * See the Unified Extensible Firmware Interface (UEFI) specification | |
2447 | + * for details. | |
2448 | + * | |
2449 | + * First all driver binding protocol handles are tried for binding drivers. | |
2450 | + * Afterwards all handles that have openened a protocol of the controller | |
2451 | + * with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers. | |
2452 | + * | |
2453 | + * @controller_handle handle of the controller | |
2454 | + * @driver_image_handle handle of the driver | |
2455 | + * @remain_device_path device path of a child controller | |
2456 | + * @recursive true to connect all child controllers | |
2457 | + * @return status code | |
2458 | + */ | |
2459 | +static efi_status_t EFIAPI efi_connect_controller( | |
2460 | + efi_handle_t controller_handle, | |
2461 | + efi_handle_t *driver_image_handle, | |
2462 | + struct efi_device_path *remain_device_path, | |
2463 | + bool recursive) | |
2464 | +{ | |
2465 | + efi_status_t r; | |
2466 | + efi_status_t ret = EFI_NOT_FOUND; | |
2467 | + struct efi_object *efiobj; | |
2468 | + | |
2469 | + EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle, | |
2470 | + remain_device_path, recursive); | |
2471 | + | |
2472 | + efiobj = efi_search_obj(controller_handle); | |
2473 | + if (!efiobj) { | |
2474 | + ret = EFI_INVALID_PARAMETER; | |
2475 | + goto out; | |
2476 | + } | |
2477 | + | |
2478 | + r = efi_connect_single_controller(controller_handle, | |
2479 | + driver_image_handle, | |
2480 | + remain_device_path); | |
2481 | + if (r == EFI_SUCCESS) | |
2482 | + ret = EFI_SUCCESS; | |
2483 | + if (recursive) { | |
2484 | + struct efi_handler *handler; | |
2485 | + struct efi_open_protocol_info_item *item; | |
2486 | + | |
2487 | + list_for_each_entry(handler, &efiobj->protocols, link) { | |
2488 | + list_for_each_entry(item, &handler->open_infos, link) { | |
2489 | + if (item->info.attributes & | |
2490 | + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { | |
2491 | + r = EFI_CALL(efi_connect_controller( | |
2492 | + item->info.controller_handle, | |
2493 | + driver_image_handle, | |
2494 | + remain_device_path, | |
2495 | + recursive)); | |
2496 | + if (r == EFI_SUCCESS) | |
2497 | + ret = EFI_SUCCESS; | |
2498 | + } | |
2499 | + } | |
2500 | + } | |
2501 | + } | |
2502 | + /* Check for child controller specified by end node */ | |
2503 | + if (ret != EFI_SUCCESS && remain_device_path && | |
2504 | + remain_device_path->type == DEVICE_PATH_TYPE_END) | |
2505 | + ret = EFI_SUCCESS; | |
2506 | +out: | |
2507 | + return EFI_EXIT(ret); | |
2369 | 2508 | } |
2370 | 2509 | |
2371 | 2510 | static const struct efi_boot_services efi_boot_services = { |