[U-Boot] [PATCH 0/9] EFI protocol services

Currently only a small fraction of the UEFI specification is implemented in U-Boot. It is sufficient to load grub but it fails on iPXE.
With this patch series all EFI protocol services are implemented that are needed to reach the console prompt of the bin-<ARCH>-efi/snponly.efi target of iPXE.
Futher patches for event services are needed to use the iPXE console. These will be provided in a separate patch series.
The 1st patch refactors efi_open_protocol to enable the implementation of InstallProtocolInterface. This patch eliminates the open protocol functions in efi_disk, efi_gop, and efi_net.
The 2nd patch adds missing parameter checks to efi_open_protocol.
The 3rd patch implements InstallProtocolInteface.
The 4th patch partially implements UninstallProtocolInterface.
The 5th patch refactors efi_install_protocol_interface to make it callable internally.
The 6th patch refactors efi_uninstall_protocol_interface to make it callable internally.
The 7th patch implements InstallMultipleProtocolInterfaces by calling efi_install_protocol_interface.
The 8th patch refactors efi_locate_handle to make it callable internally.
The 9th patch implements LocateHandleBuffer.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
Heinrich Schuchardt (9): efi_loader: refactor efi_open_protocol efi_loader: efi_open_protocol: parameter checks efi_loader: implement InstallProtocolInterface efi_loader: implement UninstallProtocolInterface efi_loader: refactor efi_install_protocol_interface efi_loader: refactor efi_uninstall_protocol_interface efi_loader: implement InstallMultipleProtocolInterfaces efi_loader: refactor efi_locate_handle efi_loader: implement LocateHandleBuffer
cmd/bootefi.c | 14 +-- include/efi_api.h | 2 +- include/efi_loader.h | 17 +-- lib/efi_loader/efi_boottime.c | 237 ++++++++++++++++++++++++++++++++++++++---- lib/efi_loader/efi_disk.c | 29 +----- lib/efi_loader/efi_gop.c | 2 +- lib/efi_loader/efi_net.c | 30 +----- 7 files changed, 232 insertions(+), 99 deletions(-)

efi_open_protocol was implemented to call a protocol specific 'open' function to retrieve the protocol interface.
The UEFI specification does not know of such a function.
It is not possible to implement InstallProtocolInterface with the current design.
With the patch the protocol interface itself is stored in the list of installed protocols of an efi_object instead of an open function.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- cmd/bootefi.c | 14 +++----------- include/efi_loader.h | 17 ++--------------- lib/efi_loader/efi_boottime.c | 18 ++++++++++++++---- lib/efi_loader/efi_disk.c | 29 +++-------------------------- lib/efi_loader/efi_gop.c | 2 +- lib/efi_loader/efi_net.c | 30 +++--------------------------- 6 files changed, 26 insertions(+), 84 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 90ecde65d1..d80cb0723f 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -54,14 +54,6 @@ static struct efi_device_path_file_path bootefi_device_path[] = { } };
-static efi_status_t EFIAPI bootefi_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - *protocol_interface = bootefi_device_path; - return EFI_SUCCESS; -} - /* The EFI loaded_image interface for the image executed via "bootefi" */ static struct efi_loaded_image loaded_image_info = { .device_handle = bootefi_device_path, @@ -78,7 +70,7 @@ static struct efi_object loaded_image_info_obj = { * return handle which points to loaded_image_info */ .guid = &efi_guid_loaded_image, - .open = &efi_return_handle, + .protocol_interface = &loaded_image_info, }, { /* @@ -86,7 +78,7 @@ static struct efi_object loaded_image_info_obj = { * bootefi_device_path */ .guid = &efi_guid_device_path, - .open = &bootefi_open_dp, + .protocol_interface = bootefi_device_path, }, }, }; @@ -99,7 +91,7 @@ static struct efi_object bootefi_device_obj = { /* When asking for the device path interface, return * bootefi_device_path */ .guid = &efi_guid_device_path, - .open = &bootefi_open_dp, + .protocol_interface = bootefi_device_path } }, }; diff --git a/include/efi_loader.h b/include/efi_loader.h index 99619f53a9..c620652307 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -49,15 +49,10 @@ struct efi_class_map { /* * When the UEFI payload wants to open a protocol on an object to get its * interface (usually a struct with callback functions), this struct maps the - * protocol GUID to the respective protocol handler open function for that - * object protocol combination. - */ + * protocol GUID to the respective protocol interface */ struct efi_handler { const efi_guid_t *guid; - efi_status_t (EFIAPI *open)(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes); + void *protocol_interface; };
/* @@ -91,14 +86,6 @@ void efi_smbios_register(void); /* Called by networking code to memorize the dhcp ack package */ void efi_net_set_dhcp_ack(void *pkt, int len);
-/* - * Stub implementation for a protocol opener that just returns the handle as - * interface - */ -efi_status_t EFIAPI efi_return_handle(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes); /* Called from places to check whether a timer expired */ void efi_timer_check(void); /* PE loader implementation */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 27e51a253f..5c72f92474 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -442,7 +442,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, .protocols = { { .guid = &efi_guid_loaded_image, - .open = &efi_return_handle, }, }, }; @@ -452,6 +451,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image, file_path, source_buffer, source_size, image_handle); info = malloc(sizeof(*info)); + loaded_image_info_obj.protocols[0].protocol_interface = info; obj = malloc(sizeof(loaded_image_info_obj)); memset(info, 0, sizeof(*info)); memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj)); @@ -723,6 +723,13 @@ static efi_status_t EFIAPI efi_open_protocol( EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol, protocol_interface, agent_handle, controller_handle, attributes); + + if (!protocol_interface && attributes != + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { + r = EFI_INVALID_PARAMETER; + goto out; + } + list_for_each(lhandle, &efi_obj_list) { struct efi_object *efiobj; efiobj = list_entry(lhandle, struct efi_object, link); @@ -736,9 +743,12 @@ static efi_status_t EFIAPI efi_open_protocol( if (!hprotocol) break; if (!guidcmp(hprotocol, protocol)) { - r = handler->open(handle, protocol, - protocol_interface, agent_handle, - controller_handle, attributes); + if (attributes != + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { + *protocol_interface = + handler->protocol_interface; + } + r = EFI_SUCCESS; goto out; } } diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 39e602a868..3ad7706472 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -35,29 +35,6 @@ struct efi_disk_obj { const struct blk_desc *desc; };
-static efi_status_t EFIAPI efi_disk_open_block(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes) -{ - struct efi_disk_obj *diskobj = handle; - - *protocol_interface = &diskobj->ops; - - return EFI_SUCCESS; -} - -static efi_status_t EFIAPI efi_disk_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_disk_obj *diskobj = handle; - - *protocol_interface = diskobj->dp; - - return EFI_SUCCESS; -} - static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, char extended_verification) { @@ -210,10 +187,11 @@ static void efi_disk_add_dev(const char *name, diskobj = calloc(1, objlen);
/* Fill in object data */ + dp = (void *)&diskobj[1]; diskobj->parent.protocols[0].guid = &efi_block_io_guid; - diskobj->parent.protocols[0].open = efi_disk_open_block; + diskobj->parent.protocols[0].protocol_interface = &diskobj->ops; diskobj->parent.protocols[1].guid = &efi_guid_device_path; - diskobj->parent.protocols[1].open = efi_disk_open_dp; + diskobj->parent.protocols[1].protocol_interface = dp; diskobj->parent.handle = diskobj; diskobj->ops = block_io_disk_template; diskobj->ifname = if_typename; @@ -230,7 +208,6 @@ static void efi_disk_add_dev(const char *name, diskobj->ops.media = &diskobj->media;
/* Fill in device path */ - dp = (void*)&diskobj[1]; diskobj->dp = dp; dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 286ad83097..c491ca0815 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -172,7 +172,7 @@ int efi_gop_register(void)
/* Fill in object data */ gopobj->parent.protocols[0].guid = &efi_gop_guid; - gopobj->parent.protocols[0].open = efi_return_handle; + gopobj->parent.protocols[0].open = &gopobj->ops; gopobj->parent.handle = &gopobj->ops; gopobj->ops.query_mode = gop_query_mode; gopobj->ops.set_mode = gop_set_mode; diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 604ac6e040..0b949d86e8 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -199,30 +199,6 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, return EFI_EXIT(EFI_SUCCESS); }
-static efi_status_t EFIAPI efi_net_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_simple_network *net = handle; - struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); - - *protocol_interface = &netobj->dp_mac; - - return EFI_SUCCESS; -} - -static efi_status_t EFIAPI efi_net_open_pxe(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_simple_network *net = handle; - struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); - - *protocol_interface = &netobj->pxe; - - return EFI_SUCCESS; -} - void efi_net_set_dhcp_ack(void *pkt, int len) { int maxsize = sizeof(*dhcp_ack); @@ -258,11 +234,11 @@ int efi_net_register(void **handle)
/* Fill in object data */ netobj->parent.protocols[0].guid = &efi_net_guid; - netobj->parent.protocols[0].open = efi_return_handle; + netobj->parent.protocols[0].protocol_interface = &netobj->net; netobj->parent.protocols[1].guid = &efi_guid_device_path; - netobj->parent.protocols[1].open = efi_net_open_dp; + netobj->parent.protocols[1].protocol_interface = &netobj->dp_mac; netobj->parent.protocols[2].guid = &efi_pxe_guid; - netobj->parent.protocols[2].open = efi_net_open_pxe; + netobj->parent.protocols[2].protocol_interface = &netobj->pxe; netobj->parent.handle = &netobj->net; netobj->net.start = efi_net_start; netobj->net.stop = efi_net_stop;

Add all parameter checks for function efi_open_protocol that do not depend on a locking table.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_boottime.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5c72f92474..22e9e6001d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -718,15 +718,35 @@ static efi_status_t EFIAPI efi_open_protocol( { struct list_head *lhandle; int i; - efi_status_t r = EFI_UNSUPPORTED; + efi_status_t r = EFI_INVALID_PARAMETER;
EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol, protocol_interface, agent_handle, controller_handle, attributes);
- if (!protocol_interface && attributes != - EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { - r = EFI_INVALID_PARAMETER; + 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: + if (controller_handle == NULL) + goto out; + case EFI_OPEN_PROTOCOL_EXCLUSIVE: + if (agent_handle == NULL) + goto out; + break; + default: goto out; }
@@ -752,8 +772,11 @@ static efi_status_t EFIAPI efi_open_protocol( goto out; } } + goto unsupported; }
+unsupported: + r = EFI_UNSUPPORTED; out: return EFI_EXIT(r); }

efi_install_protocol_interface up to now only returned an error code.
The patch implements the UEFI specification for InstallProtocolInterface with the exception that it will not create new handles.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 52 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h index f071b36b53..42cd47ff08 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -58,7 +58,7 @@ struct efi_boot_services { efi_status_t (EFIAPI *signal_event)(void *event); efi_status_t (EFIAPI *close_event)(void *event); efi_status_t (EFIAPI *check_event)(void *event); - +#define EFI_NATIVE_INTERFACE 0x00000000 efi_status_t (EFIAPI *install_protocol_interface)( void **handle, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 22e9e6001d..7596f16b84 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -303,10 +303,60 @@ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) { + struct list_head *lhandle; + int i; + efi_status_t r; + EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, protocol_interface); - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + if (!handle || !protocol || + protocol_interface_type != EFI_NATIVE_INTERFACE) { + r = EFI_INVALID_PARAMETER; + goto out; + } + + /* Create new handle if requested. */ + if (!*handle) { + r = EFI_OUT_OF_RESOURCES; + goto out; + } + /* Find object. */ + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + efiobj = list_entry(lhandle, struct efi_object, link); + + if (efiobj->handle != *handle) + continue; + /* Check if protocol is already installed on the handle. */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + + if (handler->guid == protocol) { + r = EFI_INVALID_PARAMETER; + goto out; + } + /* Install protocol in first empty slot. */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + + if (handler->guid) + continue; + + handler->guid = protocol; + handler->protocol_interface = protocol_interface; + r = EFI_SUCCESS; + goto out; + } + } + r = EFI_OUT_OF_RESOURCES; + goto out; + } + r = EFI_INVALID_PARAMETER; +out: + return EFI_EXIT(r); } + static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, efi_guid_t *protocol, void *old_interface, void *new_interface)

Without the patch efi_uninstall_protocol_interface always returns an error.
With the patch protocols without interface can be uninstalled.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_boottime.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 7596f16b84..b3a59b4219 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -369,8 +369,41 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, efi_guid_t *protocol, void *protocol_interface) { + struct list_head *lhandle; + int i; + efi_status_t r = EFI_NOT_FOUND; + EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface); - return EFI_EXIT(EFI_NOT_FOUND); + + if (!handle || !protocol) { + r = EFI_INVALID_PARAMETER; + goto out; + } + + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + efiobj = list_entry(lhandle, struct efi_object, link); + + if (efiobj->handle != handle) + continue; + + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + const efi_guid_t *hprotocol = handler->guid; + if (!guidcmp(hprotocol, protocol)) { + if (handler->protocol_interface) { + r = EFI_ACCESS_DENIED; + } else { + handler->guid = 0; + r = EFI_SUCCESS; + } + goto out; + } + } + } + +out: + return EFI_EXIT(r); }
static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, @@ -811,7 +844,7 @@ static efi_status_t EFIAPI efi_open_protocol( struct efi_handler *handler = &efiobj->protocols[i]; const efi_guid_t *hprotocol = handler->guid; if (!hprotocol) - break; + continue; if (!guidcmp(hprotocol, protocol)) { if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {

For the implementation of InstallMultipleProtocolInterfaces we need to call efi_install_protocol_interface. In internal calls we should not pass through EFI_EXIT.
The patch introduces a wrapper function efi_install_protocol_interface_ext.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_boottime.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b3a59b4219..0075ccaaa2 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -307,9 +307,6 @@ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, int i; efi_status_t r;
- EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, - protocol_interface); - if (!handle || !protocol || protocol_interface_type != EFI_NATIVE_INTERFACE) { r = EFI_INVALID_PARAMETER; @@ -354,7 +351,19 @@ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, } r = EFI_INVALID_PARAMETER; out: - return EFI_EXIT(r); + return r; +} + +static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, + efi_guid_t *protocol, int protocol_interface_type, + void *protocol_interface) +{ + EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, + protocol_interface); + + return EFI_EXIT(efi_install_protocol_interface(handle, protocol, + protocol_interface_type, + protocol_interface)); }
static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, @@ -889,7 +898,7 @@ static const struct efi_boot_services efi_boot_services = { .signal_event = efi_signal_event, .close_event = efi_close_event, .check_event = efi_check_event, - .install_protocol_interface = efi_install_protocol_interface, + .install_protocol_interface = efi_install_protocol_interface_ext, .reinstall_protocol_interface = efi_reinstall_protocol_interface, .uninstall_protocol_interface = efi_uninstall_protocol_interface, .handle_protocol = efi_handle_protocol,

For the implementation of UninstallMultipleProtocolInterfaces we need to call efi_uninstall_protocol_interface. In internal calls we should not pass through EFI_EXIT.
The patch introduces a wrapper function efi_uninstall_protocol_interface_ext.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_boottime.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0075ccaaa2..607287d01f 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -382,8 +382,6 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, int i; efi_status_t r = EFI_NOT_FOUND;
- EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface); - if (!handle || !protocol) { r = EFI_INVALID_PARAMETER; goto out; @@ -412,7 +410,16 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, }
out: - return EFI_EXIT(r); + return r; +} + +static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, + efi_guid_t *protocol, void *protocol_interface) +{ + EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface); + + return EFI_EXIT(efi_uninstall_protocol_interface(handle, protocol, + protocol_interface)); }
static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, @@ -900,7 +907,7 @@ static const struct efi_boot_services efi_boot_services = { .check_event = efi_check_event, .install_protocol_interface = efi_install_protocol_interface_ext, .reinstall_protocol_interface = efi_reinstall_protocol_interface, - .uninstall_protocol_interface = efi_uninstall_protocol_interface, + .uninstall_protocol_interface = efi_uninstall_protocol_interface_ext, .handle_protocol = efi_handle_protocol, .reserved = NULL, .register_protocol_notify = efi_register_protocol_notify,

Implement InstallMultipleProtocolInterfaces in function efi_install_multiple_protocol_interfaces by repeatedly calling efi_install_protocol_interface.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_boottime.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 607287d01f..74b9620ad8 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -778,7 +778,44 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( void **handle, ...) { EFI_ENTRY("%p", handle); - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + va_list argptr; + 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_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 occured undo all changes. */ + va_start(argptr, handle); + for (; i; --i) { + protocol = va_arg(argptr, efi_guid_t*); + protocol_interface = va_arg(argptr, void*); + efi_uninstall_protocol_interface(handle, protocol, + protocol_interface); + } + va_end(argptr); + + return EFI_EXIT(r); }
static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(

To implement LocateHandleBuffer we need to call efi_locate_handle internally without running through EFI_EXIT.
So put EFI_ENTRY and EFI_EXIT into a new wrapper function efi_locate_handle_ext.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_boottime.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 74b9620ad8..888207681c 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -461,9 +461,6 @@ static efi_status_t EFIAPI efi_locate_handle( struct list_head *lhandle; unsigned long size = 0;
- EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, - buffer_size, buffer); - /* Count how much space we need */ list_for_each(lhandle, &efi_obj_list) { struct efi_object *efiobj; @@ -475,7 +472,7 @@ static efi_status_t EFIAPI efi_locate_handle(
if (*buffer_size < size) { *buffer_size = size; - return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + return EFI_BUFFER_TOO_SMALL; }
/* Then fill the array */ @@ -488,7 +485,19 @@ static efi_status_t EFIAPI efi_locate_handle( }
*buffer_size = size; - return EFI_EXIT(EFI_SUCCESS); + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI efi_locate_handle_ext( + enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *buffer_size, efi_handle_t *buffer) +{ + EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, + buffer_size, buffer); + + return EFI_EXIT(efi_locate_handle(search_type, protocol, search_key, + buffer_size, buffer)); }
static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol, @@ -948,7 +957,7 @@ static const struct efi_boot_services efi_boot_services = { .handle_protocol = efi_handle_protocol, .reserved = NULL, .register_protocol_notify = efi_register_protocol_notify, - .locate_handle = efi_locate_handle, + .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,

UEFI boot service LocateHandleBuffer is implemented by calling efi_allocate_handle and efi_locate_handle.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- lib/efi_loader/efi_boottime.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 888207681c..3060c25a2a 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -753,9 +753,32 @@ static efi_status_t EFIAPI efi_locate_handle_buffer( efi_guid_t *protocol, void *search_key, unsigned long *no_handles, efi_handle_t **buffer) { + efi_status_t r; + unsigned long buffer_size = 0; + EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, no_handles, buffer); - return EFI_EXIT(EFI_NOT_FOUND); + + 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(void *); +out: + return EFI_EXIT(r); }
static struct efi_class_map efi_class_maps[] = {
participants (1)
-
Heinrich Schuchardt