
Hi Heinrick,
On 17 December 2017 at 08:43, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Implement the ConnectController boot service.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
include/efi_api.h | 22 ++++++ include/efi_loader.h | 2 + lib/efi_loader/efi_boottime.c | 178 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 178 insertions(+), 24 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Please see below. Also please mention when tests come for these.
diff --git a/include/efi_api.h b/include/efi_api.h index 46963f2891..81e580dbbc 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -805,4 +805,26 @@ struct efi_file_info { s16 file_name[0]; };
+#define EFI_DRIVER_BINDING_PROTOCOL_GUID \
EFI_GUID(0x18a031ab, 0xb443, 0x4d1a,\
0xa5, 0xc0, 0x0c, 0x09, 0x26, 0x1e, 0x9f, 0x71)
+struct efi_driver_binding_protocol {
efi_status_t (EFIAPI * supported)(
struct efi_driver_binding_protocol *this,
efi_handle_t controller_handle,
struct efi_device_path *remaining_device_path);
efi_status_t (EFIAPI * start)(
struct efi_driver_binding_protocol *this,
efi_handle_t controller_handle,
struct efi_device_path *remaining_device_path);
efi_status_t (EFIAPI * stop)(
struct efi_driver_binding_protocol *this,
efi_handle_t controller_handle,
efi_uintn_t number_of_children,
efi_handle_t *child_handle_buffer);
u32 version;
efi_handle_t image_handle;
efi_handle_t driver_binding_handle;
+};
#endif diff --git a/include/efi_loader.h b/include/efi_loader.h index 637e6e166d..9e1ae8866b 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -88,6 +88,8 @@ uint16_t *efi_dp_str(struct efi_device_path *dp); extern const efi_guid_t efi_global_variable_guid; extern const efi_guid_t efi_guid_console_control; extern const efi_guid_t efi_guid_device_path; +/* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ +extern const efi_guid_t efi_guid_driver_binding_protocol; extern const efi_guid_t efi_guid_loaded_image; extern const efi_guid_t efi_guid_device_path_to_text_protocol; extern const efi_guid_t efi_simple_file_system_protocol_guid; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b5d6808bf7..6cc0659eb9 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -56,6 +56,9 @@ static volatile void *efi_gd, *app_gd;
static int entry_count; static int nesting_level; +/* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ +const efi_guid_t efi_guid_driver_binding_protocol =
EFI_DRIVER_BINDING_PROTOCOL_GUID;
/* Called on every callback entry */ int __efi_entry_check(void) @@ -1619,30 +1622,6 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, return EFI_EXIT(efi_set_watchdog(timeout)); }
-/*
- Connect a controller to a driver.
- This function implements the ConnectController service.
- See the Unified Extensible Firmware Interface (UEFI) specification
- for details.
- @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_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
remain_device_path, recursive);
return EFI_EXIT(EFI_NOT_FOUND);
-}
/*
- Disconnect a controller from a driver.
@@ -2352,6 +2331,157 @@ static efi_status_t EFIAPI efi_handle_protocol(void *handle, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); }
+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);
if (r == EFI_SUCCESS)
++connected;
What happens to any error here?
}
}
}
}
/*
* TODO: Some overrides are not yet implemented:
* - Platform Driver Override
* - Driver Family Override Search
* - Bus Specific Driver Override
Bus-specific ?
*/
/* 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.
Well I think it would be good to explain briefly what it does.
- @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);
+}
static const struct efi_boot_services efi_boot_services = { .hdr = { .headersize = sizeof(struct efi_table_hdr), -- 2.14.2
Regards, Simon