Newer
Older
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
r = efi_search_protocol(handle, protocol, &handler);
if (r != EFI_SUCCESS)
goto out;
/* Count entries */
count = 0;
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.open_count)
++count;
}
*entry_count = count;
*entry_buffer = NULL;
if (!count) {
r = EFI_SUCCESS;
goto out;
}
/* Copy entries */
buffer_size = count * sizeof(struct efi_open_protocol_info_entry);
r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size,
(void **)entry_buffer);
if (r != EFI_SUCCESS)
goto out;
list_for_each_entry_reverse(item, &handler->open_infos, link) {
if (item->info.open_count)
(*entry_buffer)[--count] = item->info;
}
out:
return EFI_EXIT(r);
/*
* Get protocols installed on a handle.
*
* This function implements the ProtocolsPerHandleService.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @handle handle for which the information is retrieved
* @protocol_buffer buffer with protocol GUIDs
* @protocol_buffer_count number of entries in the buffer
* @return status code
static efi_status_t EFIAPI efi_protocols_per_handle(
efi_handle_t handle, efi_guid_t ***protocol_buffer,
efi_uintn_t *protocol_buffer_count)
unsigned long buffer_size;
struct efi_object *efiobj;
struct list_head *protocol_handle;
EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
protocol_buffer_count);
if (!handle || !protocol_buffer || !protocol_buffer_count)
return EFI_EXIT(EFI_INVALID_PARAMETER);
*protocol_buffer = NULL;
efiobj = efi_search_obj(handle);
if (!efiobj)
return EFI_EXIT(EFI_INVALID_PARAMETER);
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
/* Count protocols */
list_for_each(protocol_handle, &efiobj->protocols) {
++*protocol_buffer_count;
}
/* Copy guids */
if (*protocol_buffer_count) {
size_t j = 0;
buffer_size = sizeof(efi_guid_t *) * *protocol_buffer_count;
r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size,
(void **)protocol_buffer);
if (r != EFI_SUCCESS)
return EFI_EXIT(r);
list_for_each(protocol_handle, &efiobj->protocols) {
struct efi_handler *protocol;
protocol = list_entry(protocol_handle,
struct efi_handler, link);
(*protocol_buffer)[j] = (void *)protocol->guid;
++j;
}
}
return EFI_EXIT(EFI_SUCCESS);
/*
* Locate handles implementing a protocol.
*
* This function implements the LocateHandleBuffer service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @search_type selection criterion
* @protocol GUID of the protocol
* @search_key registration key
* @no_handles number of returned handles
* @buffer buffer with the returned handles
* @return status code
*/
static efi_status_t EFIAPI efi_locate_handle_buffer(
enum efi_locate_search_type search_type,
const efi_guid_t *protocol, void *search_key,
efi_uintn_t *no_handles, efi_handle_t **buffer)
efi_uintn_t buffer_size = 0;
EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key,
if (!no_handles || !buffer) {
r = EFI_INVALID_PARAMETER;
goto out;
}
*no_handles = 0;
*buffer = NULL;
r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
*buffer);
if (r != EFI_BUFFER_TOO_SMALL)
goto out;
r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size,
(void **)buffer);
if (r != EFI_SUCCESS)
goto out;
r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
*buffer);
if (r == EFI_SUCCESS)
*no_handles = buffer_size / sizeof(efi_handle_t);
out:
return EFI_EXIT(r);
/*
* Find an interface implementing a protocol.
*
* This function implements the LocateProtocol service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @protocol GUID of the protocol
* @registration registration key passed to the notification function
* @protocol_interface interface implementing the protocol
* @return status code
static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol,
void *registration,
void **protocol_interface)
{
struct list_head *lhandle;
EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface);
if (!protocol || !protocol_interface)
return EFI_EXIT(EFI_INVALID_PARAMETER);
list_for_each(lhandle, &efi_obj_list) {
struct efi_object *efiobj;
struct efi_handler *handler;
efiobj = list_entry(lhandle, struct efi_object, link);
ret = efi_search_protocol(efiobj->handle, protocol, &handler);
if (ret == EFI_SUCCESS) {
*protocol_interface = handler->protocol_interface;
return EFI_EXIT(EFI_SUCCESS);
*protocol_interface = NULL;
return EFI_EXIT(EFI_NOT_FOUND);
}
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
/*
* Get the device path and handle of an device implementing a protocol.
*
* This function implements the LocateDevicePath service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @protocol GUID of the protocol
* @device_path device path
* @device handle of the device
* @return status code
*/
static efi_status_t EFIAPI efi_locate_device_path(
const efi_guid_t *protocol,
struct efi_device_path **device_path,
efi_handle_t *device)
{
struct efi_device_path *dp;
size_t i;
struct efi_handler *handler;
efi_handle_t *handles;
size_t len, len_dp;
size_t len_best = 0;
efi_uintn_t no_handles;
u8 *remainder;
efi_status_t ret;
EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
if (!protocol || !device_path || !*device_path || !device) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
/* Find end of device path */
len = efi_dp_size(*device_path);
/* Get all handles implementing the protocol */
ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
&no_handles, &handles));
if (ret != EFI_SUCCESS)
goto out;
for (i = 0; i < no_handles; ++i) {
/* Find the device path protocol */
ret = efi_search_protocol(handles[i], &efi_guid_device_path,
&handler);
if (ret != EFI_SUCCESS)
continue;
dp = (struct efi_device_path *)handler->protocol_interface;
len_dp = efi_dp_size(dp);
/*
* This handle can only be a better fit
* if its device path length is longer than the best fit and
* if its device path length is shorter of equal the searched
* device path.
*/
if (len_dp <= len_best || len_dp > len)
continue;
/* Check if dp is a subpath of device_path */
if (memcmp(*device_path, dp, len_dp))
continue;
*device = handles[i];
len_best = len_dp;
}
if (len_best) {
remainder = (u8 *)*device_path + len_best;
*device_path = (struct efi_device_path *)remainder;
ret = EFI_SUCCESS;
} else {
ret = EFI_NOT_FOUND;
}
out:
return EFI_EXIT(ret);
}
/*
* Install multiple protocol interfaces.
*
* This function implements the MultipleProtocolInterfaces service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @handle handle on which the protocol interfaces shall be installed
* @... NULL terminated argument list with pairs of protocol GUIDS and
* interfaces
* @return status code
*/
static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
void **handle, ...)
{
EFI_ENTRY("%p", handle);
va_list argptr;
const efi_guid_t *protocol;
void *protocol_interface;
efi_status_t r = EFI_SUCCESS;
int i = 0;
if (!handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
va_start(argptr, handle);
for (;;) {
protocol = va_arg(argptr, efi_guid_t*);
if (!protocol)
break;
protocol_interface = va_arg(argptr, void*);
r = EFI_CALL(efi_install_protocol_interface(
handle, protocol,
EFI_NATIVE_INTERFACE,
protocol_interface));
if (r != EFI_SUCCESS)
break;
i++;
}
va_end(argptr);
if (r == EFI_SUCCESS)
return EFI_EXIT(r);
/* If an error occurred undo all changes. */
va_start(argptr, handle);
for (; i; --i) {
protocol = va_arg(argptr, efi_guid_t*);
protocol_interface = va_arg(argptr, void*);
EFI_CALL(efi_uninstall_protocol_interface(handle, protocol,
protocol_interface));
}
va_end(argptr);
return EFI_EXIT(r);
/*
* Uninstall multiple protocol interfaces.
*
* This function implements the UninstallMultipleProtocolInterfaces service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @handle handle from which the protocol interfaces shall be removed
* @... NULL terminated argument list with pairs of protocol GUIDS and
* interfaces
* @return status code
*/
static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
void *handle, ...)
{
EFI_ENTRY("%p", handle);
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
va_list argptr;
const efi_guid_t *protocol;
void *protocol_interface;
efi_status_t r = EFI_SUCCESS;
size_t i = 0;
if (!handle)
return EFI_EXIT(EFI_INVALID_PARAMETER);
va_start(argptr, handle);
for (;;) {
protocol = va_arg(argptr, efi_guid_t*);
if (!protocol)
break;
protocol_interface = va_arg(argptr, void*);
r = EFI_CALL(efi_uninstall_protocol_interface(
handle, protocol,
protocol_interface));
if (r != EFI_SUCCESS)
break;
i++;
}
va_end(argptr);
if (r == EFI_SUCCESS)
return EFI_EXIT(r);
/* If an error occurred undo all changes. */
va_start(argptr, handle);
for (; i; --i) {
protocol = va_arg(argptr, efi_guid_t*);
protocol_interface = va_arg(argptr, void*);
EFI_CALL(efi_install_protocol_interface(&handle, protocol,
EFI_NATIVE_INTERFACE,
protocol_interface));
}
va_end(argptr);
return EFI_EXIT(r);
/*
* Calculate cyclic redundancy code.
*
* This function implements the CalculateCrc32 service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @data buffer with data
* @data_size size of buffer in bytes
* @crc32_p cyclic redundancy code
* @return status code
*/
static efi_status_t EFIAPI efi_calculate_crc32(void *data,
unsigned long data_size,
uint32_t *crc32_p)
{
EFI_ENTRY("%p, %ld", data, data_size);
*crc32_p = crc32(0, data, data_size);
return EFI_EXIT(EFI_SUCCESS);
}
/*
* Copy memory.
*
* This function implements the CopyMem service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @destination destination of the copy operation
* @source source of the copy operation
* @length number of bytes to copy
*/
static void EFIAPI efi_copy_mem(void *destination, const void *source,
size_t length)
EFI_ENTRY("%p, %p, %ld", destination, source, (unsigned long)length);
memcpy(destination, source, length);
EFI_EXIT(EFI_SUCCESS);
/*
* Fill memory with a byte value.
*
* This function implements the SetMem service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @buffer buffer to fill
* @size size of buffer in bytes
* @value byte to copy to the buffer
*/
static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value)
EFI_ENTRY("%p, %ld, 0x%x", buffer, (unsigned long)size, value);
EFI_EXIT(EFI_SUCCESS);
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
/*
* Open protocol interface on a handle.
*
* @handler handler of a protocol
* @protocol_interface interface implementing the protocol
* @agent_handle handle of the driver
* @controller_handle handle of the controller
* @attributes attributes indicating how to open the protocol
* @return status code
*/
static efi_status_t efi_protocol_open(
struct efi_handler *handler,
void **protocol_interface, void *agent_handle,
void *controller_handle, uint32_t attributes)
{
struct efi_open_protocol_info_item *item;
struct efi_open_protocol_info_entry *match = NULL;
bool opened_by_driver = false;
bool opened_exclusive = false;
/* If there is no agent, only return the interface */
if (!agent_handle)
goto out;
/* For TEST_PROTOCOL ignore interface attribute */
if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
*protocol_interface = NULL;
/*
* Check if the protocol is already opened by a driver with the same
* attributes or opened exclusively
*/
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.agent_handle == agent_handle) {
if ((attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) &&
(item->info.attributes == attributes))
return EFI_ALREADY_STARTED;
}
if (item->info.attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE)
opened_exclusive = true;
}
/* Only one controller can open the protocol exclusively */
if (opened_exclusive && attributes &
(EFI_OPEN_PROTOCOL_EXCLUSIVE | EFI_OPEN_PROTOCOL_BY_DRIVER))
return EFI_ACCESS_DENIED;
/* Prepare exclusive opening */
if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) {
/* Try to disconnect controllers */
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.attributes ==
EFI_OPEN_PROTOCOL_BY_DRIVER)
EFI_CALL(efi_disconnect_controller(
item->info.controller_handle,
item->info.agent_handle,
NULL));
}
opened_by_driver = false;
/* Check if all controllers are disconnected */
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.attributes & EFI_OPEN_PROTOCOL_BY_DRIVER)
opened_by_driver = true;
}
/* Only one controller can be conncected */
if (opened_by_driver)
return EFI_ACCESS_DENIED;
}
/* Find existing entry */
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.agent_handle == agent_handle &&
item->info.controller_handle == controller_handle)
match = &item->info;
}
/* None found, create one */
if (!match) {
match = efi_create_open_info(handler);
if (!match)
return EFI_OUT_OF_RESOURCES;
}
match->agent_handle = agent_handle;
match->controller_handle = controller_handle;
match->attributes = attributes;
match->open_count++;
out:
/* For TEST_PROTOCOL ignore interface attribute. */
if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
*protocol_interface = handler->protocol_interface;
return EFI_SUCCESS;
}
/*
* Open protocol interface on a handle.
*
* This function implements the OpenProtocol interface.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @handle handle on which the protocol shall be opened
* @protocol GUID of the protocol
* @protocol_interface interface implementing the protocol
* @agent_handle handle of the driver
* @controller_handle handle of the controller
* @attributes attributes indicating how to open the protocol
* @return status code
*/
static efi_status_t EFIAPI efi_open_protocol(
void *handle, const efi_guid_t *protocol,
void **protocol_interface, void *agent_handle,
void *controller_handle, uint32_t attributes)
{
struct efi_handler *handler;
efi_status_t r = EFI_INVALID_PARAMETER;
EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol,
protocol_interface, agent_handle, controller_handle,
attributes);
if (!handle || !protocol ||
(!protocol_interface && attributes !=
EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) {
goto out;
}
switch (attributes) {
case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:
break;
case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
if (controller_handle == handle)
goto out;
case EFI_OPEN_PROTOCOL_BY_DRIVER:
case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
/* Check that the controller handle is valid */
if (!efi_search_obj(controller_handle))
case EFI_OPEN_PROTOCOL_EXCLUSIVE:
/* Check that the agent handle is valid */
if (!efi_search_obj(agent_handle))
goto out;
break;
default:
r = efi_search_protocol(handle, protocol, &handler);
if (r != EFI_SUCCESS)
goto out;
r = efi_protocol_open(handler, protocol_interface, agent_handle,
controller_handle, attributes);
out:
return EFI_EXIT(r);
}
/*
* Get interface of a protocol on a handle.
*
* This function implements the HandleProtocol service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @handle handle on which the protocol shall be opened
* @protocol GUID of the protocol
* @protocol_interface interface implementing the protocol
* @return status code
*/
static efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle,
const efi_guid_t *protocol,
return efi_open_protocol(handle, protocol, protocol_interface, NULL,
NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
static efi_status_t efi_bind_controller(
efi_handle_t controller_handle,
efi_handle_t driver_image_handle,
struct efi_device_path *remain_device_path)
{
struct efi_driver_binding_protocol *binding_protocol;
efi_status_t r;
r = EFI_CALL(efi_open_protocol(driver_image_handle,
&efi_guid_driver_binding_protocol,
(void **)&binding_protocol,
driver_image_handle, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL));
if (r != EFI_SUCCESS)
return r;
r = EFI_CALL(binding_protocol->supported(binding_protocol,
controller_handle,
remain_device_path));
if (r == EFI_SUCCESS)
r = EFI_CALL(binding_protocol->start(binding_protocol,
controller_handle,
remain_device_path));
EFI_CALL(efi_close_protocol(driver_image_handle,
&efi_guid_driver_binding_protocol,
driver_image_handle, NULL));
return r;
}
static efi_status_t efi_connect_single_controller(
efi_handle_t controller_handle,
efi_handle_t *driver_image_handle,
struct efi_device_path *remain_device_path)
{
efi_handle_t *buffer;
size_t count;
size_t i;
efi_status_t r;
size_t connected = 0;
/* Get buffer with all handles with driver binding protocol */
r = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL,
&efi_guid_driver_binding_protocol,
NULL, &count, &buffer));
if (r != EFI_SUCCESS)
return r;
/* Context Override */
if (driver_image_handle) {
for (; *driver_image_handle; ++driver_image_handle) {
for (i = 0; i < count; ++i) {
if (buffer[i] == *driver_image_handle) {
buffer[i] = NULL;
r = efi_bind_controller(
controller_handle,
*driver_image_handle,
remain_device_path);
/*
* For drivers that do not support the
* controller or are already connected
* we receive an error code here.
*/
if (r == EFI_SUCCESS)
++connected;
}
}
}
}
/*
* TODO: Some overrides are not yet implemented:
* - Platform Driver Override
* - Driver Family Override Search
* - Bus Specific Driver Override
*/
/* Driver Binding Search */
for (i = 0; i < count; ++i) {
if (buffer[i]) {
r = efi_bind_controller(controller_handle,
buffer[i],
remain_device_path);
if (r == EFI_SUCCESS)
++connected;
}
}
efi_free_pool(buffer);
if (!connected)
return EFI_NOT_FOUND;
return EFI_SUCCESS;
}
/*
* Connect a controller to a driver.
*
* This function implements the ConnectController service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* First all driver binding protocol handles are tried for binding drivers.
* Afterwards all handles that have openened a protocol of the controller
* with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers.
*
* @controller_handle handle of the controller
* @driver_image_handle handle of the driver
* @remain_device_path device path of a child controller
* @recursive true to connect all child controllers
* @return status code
*/
static efi_status_t EFIAPI efi_connect_controller(
efi_handle_t controller_handle,
efi_handle_t *driver_image_handle,
struct efi_device_path *remain_device_path,
bool recursive)
{
efi_status_t r;
efi_status_t ret = EFI_NOT_FOUND;
struct efi_object *efiobj;
EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
remain_device_path, recursive);
efiobj = efi_search_obj(controller_handle);
if (!efiobj) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
r = efi_connect_single_controller(controller_handle,
driver_image_handle,
remain_device_path);
if (r == EFI_SUCCESS)
ret = EFI_SUCCESS;
if (recursive) {
struct efi_handler *handler;
struct efi_open_protocol_info_item *item;
list_for_each_entry(handler, &efiobj->protocols, link) {
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.attributes &
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
r = EFI_CALL(efi_connect_controller(
item->info.controller_handle,
driver_image_handle,
remain_device_path,
recursive));
if (r == EFI_SUCCESS)
ret = EFI_SUCCESS;
}
}
}
}
/* Check for child controller specified by end node */
if (ret != EFI_SUCCESS && remain_device_path &&
remain_device_path->type == DEVICE_PATH_TYPE_END)
ret = EFI_SUCCESS;
out:
return EFI_EXIT(ret);
}
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
/*
* Get all child controllers associated to a driver.
* The allocated buffer has to be freed with free().
*
* @efiobj handle of the controller
* @driver_handle handle of the driver
* @number_of_children number of child controllers
* @child_handle_buffer handles of the the child controllers
*/
static efi_status_t efi_get_child_controllers(
struct efi_object *efiobj,
efi_handle_t driver_handle,
efi_uintn_t *number_of_children,
efi_handle_t **child_handle_buffer)
{
struct efi_handler *handler;
struct efi_open_protocol_info_item *item;
efi_uintn_t count = 0, i;
bool duplicate;
/* Count all child controller associations */
list_for_each_entry(handler, &efiobj->protocols, link) {
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.agent_handle == driver_handle &&
item->info.attributes &
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
++count;
}
}
/*
* Create buffer. In case of duplicate child controller assignments
* the buffer will be too large. But that does not harm.
*/
*number_of_children = 0;
*child_handle_buffer = calloc(count, sizeof(efi_handle_t));
if (!*child_handle_buffer)
return EFI_OUT_OF_RESOURCES;
/* Copy unique child handles */
list_for_each_entry(handler, &efiobj->protocols, link) {
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.agent_handle == driver_handle &&
item->info.attributes &
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
/* Check this is a new child controller */
duplicate = false;
for (i = 0; i < *number_of_children; ++i) {
if ((*child_handle_buffer)[i] ==
item->info.controller_handle)
duplicate = true;
}
/* Copy handle to buffer */
if (!duplicate) {
i = (*number_of_children)++;
(*child_handle_buffer)[i] =
item->info.controller_handle;
}
}
}
}
return EFI_SUCCESS;
}
/*
* Disconnect a controller from a driver.
*
* This function implements the DisconnectController service.
* See the Unified Extensible Firmware Interface (UEFI) specification
* for details.
*
* @controller_handle handle of the controller
* @driver_image_handle handle of the driver
* @child_handle handle of the child to destroy
* @return status code
*/
static efi_status_t EFIAPI efi_disconnect_controller(
efi_handle_t controller_handle,
efi_handle_t driver_image_handle,
efi_handle_t child_handle)
{
struct efi_driver_binding_protocol *binding_protocol;
efi_handle_t *child_handle_buffer = NULL;
size_t number_of_children = 0;
efi_status_t r;
size_t stop_count = 0;
struct efi_object *efiobj;
EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
child_handle);
efiobj = efi_search_obj(controller_handle);
if (!efiobj) {
r = EFI_INVALID_PARAMETER;
goto out;
}
if (child_handle && !efi_search_obj(child_handle)) {
r = EFI_INVALID_PARAMETER;
goto out;
}
/* If no driver handle is supplied, disconnect all drivers */
if (!driver_image_handle) {
r = efi_disconnect_all_drivers(efiobj, NULL, child_handle);
goto out;
}
/* Create list of child handles */
if (child_handle) {
number_of_children = 1;
child_handle_buffer = &child_handle;
} else {
efi_get_child_controllers(efiobj,
driver_image_handle,
&number_of_children,
&child_handle_buffer);
}
/* Get the driver binding protocol */
r = EFI_CALL(efi_open_protocol(driver_image_handle,
&efi_guid_driver_binding_protocol,
(void **)&binding_protocol,
driver_image_handle, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL));
if (r != EFI_SUCCESS)
goto out;
/* Remove the children */
if (number_of_children) {
r = EFI_CALL(binding_protocol->stop(binding_protocol,
controller_handle,
number_of_children,
child_handle_buffer));
if (r == EFI_SUCCESS)
++stop_count;
}
/* Remove the driver */
if (!child_handle)
r = EFI_CALL(binding_protocol->stop(binding_protocol,
controller_handle,
0, NULL));
if (r == EFI_SUCCESS)
++stop_count;
EFI_CALL(efi_close_protocol(driver_image_handle,
&efi_guid_driver_binding_protocol,
driver_image_handle, NULL));
if (stop_count)
r = EFI_SUCCESS;
else
r = EFI_NOT_FOUND;
out:
if (!child_handle)
free(child_handle_buffer);
return EFI_EXIT(r);
}
static const struct efi_boot_services efi_boot_services = {
.hdr = {
.headersize = sizeof(struct efi_table_hdr),
},
.raise_tpl = efi_raise_tpl,
.restore_tpl = efi_restore_tpl,
.allocate_pages = efi_allocate_pages_ext,
.free_pages = efi_free_pages_ext,
.get_memory_map = efi_get_memory_map_ext,
.allocate_pool = efi_allocate_pool_ext,
.free_pool = efi_free_pool_ext,
.create_event = efi_create_event_ext,
.set_timer = efi_set_timer_ext,
.wait_for_event = efi_wait_for_event,
.signal_event = efi_signal_event_ext,
.close_event = efi_close_event,
.check_event = efi_check_event,
.install_protocol_interface = efi_install_protocol_interface,
.reinstall_protocol_interface = efi_reinstall_protocol_interface,
.uninstall_protocol_interface = efi_uninstall_protocol_interface,
.handle_protocol = efi_handle_protocol,
.reserved = NULL,
.register_protocol_notify = efi_register_protocol_notify,
.locate_handle = efi_locate_handle_ext,
.locate_device_path = efi_locate_device_path,
.install_configuration_table = efi_install_configuration_table_ext,
.load_image = efi_load_image,
.start_image = efi_start_image,
.unload_image = efi_unload_image,
.exit_boot_services = efi_exit_boot_services,
.get_next_monotonic_count = efi_get_next_monotonic_count,
.stall = efi_stall,
.set_watchdog_timer = efi_set_watchdog_timer,
.connect_controller = efi_connect_controller,
.disconnect_controller = efi_disconnect_controller,
.open_protocol = efi_open_protocol,
.close_protocol = efi_close_protocol,
.open_protocol_information = efi_open_protocol_information,
.protocols_per_handle = efi_protocols_per_handle,
.locate_handle_buffer = efi_locate_handle_buffer,
.locate_protocol = efi_locate_protocol,
.install_multiple_protocol_interfaces =
efi_install_multiple_protocol_interfaces,
.uninstall_multiple_protocol_interfaces =
efi_uninstall_multiple_protocol_interfaces,
.calculate_crc32 = efi_calculate_crc32,
.copy_mem = efi_copy_mem,
.set_mem = efi_set_mem,
.create_event_ex = efi_create_event_ex,
static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot";
struct efi_system_table __efi_runtime_data systab = {
.hdr = {
.signature = EFI_SYSTEM_TABLE_SIGNATURE,
.revision = 2 << 16 | 70, /* 2.7 */
.headersize = sizeof(struct efi_table_hdr),
},
.fw_vendor = (long)firmware_vendor,
.con_in = (void *)&efi_con_in,
.con_out = (void *)&efi_con_out,
.std_err = (void *)&efi_con_out,
.runtime = (void *)&efi_runtime_services,
.boottime = (void *)&efi_boot_services,
.tables = (void *)efi_conf_table,