Commit f0959dbee2b043c4b1bf16a570be9242cf603819

Authored by Heinrich Schuchardt
Committed by Alexander Graf
1 parent d550414434

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

... ... @@ -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 = {