diff options
author | Ilias Apalodimas <ilias.apalodimas@linaro.org> | 2022-10-06 16:08:46 +0300 |
---|---|---|
committer | Heinrich Schuchardt <heinrich.schuchardt@canonical.com> | 2022-10-06 22:54:58 +0200 |
commit | 05c4c9e21ae6f45ba1091917fc55f3ebc3916909 (patch) | |
tree | 8087cfd25c3ea958447dde7f96a0d8ac96460140 /lib/efi_loader/efi_boottime.c | |
parent | 1af680d5bc2e659a9bd532cf5c0009dd6d5bbdc3 (diff) |
efi_loader: define internal implementations of install/uninstallmultiple
A following patch is cleaning up the core EFI code trying to remove
sequences of efi_create_handle, efi_add_protocol.
Although this works fine there's a problem with the latter since it is
usually combined with efi_delete_handle() which blindly removes all
protocols on a handle and deletes the handle. We should try to adhere to
the EFI spec which only deletes a handle if the last instance of a protocol
has been removed. Another problem is that efi_delete_handle() never checks
for opened protocols, but the EFI spec defines that the caller is
responsible for ensuring that there are no references to a protocol
interface that is going to be removed.
So let's fix this by replacing all callsites of
efi_create_handle(), efi_add_protocol() , efi_delete_handle() with
Install/UninstallMultipleProtocol.
In order to do that redefine functions that can be used by the U-Boot
proper internally and add '_ext' variants that will be used from the
EFI API
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Diffstat (limited to 'lib/efi_loader/efi_boottime.c')
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 214 |
1 files changed, 159 insertions, 55 deletions
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1bfd094e89..e776d25830 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2590,35 +2590,31 @@ found: } /** - * efi_install_multiple_protocol_interfaces() - Install multiple protocol + * efi_install_multiple_protocol_interfaces_int() - Install multiple protocol * interfaces * @handle: handle on which the protocol interfaces shall be installed - * @...: NULL terminated argument list with pairs of protocol GUIDS and - * interfaces + * @argptr: va_list of args * - * This function implements the MultipleProtocolInterfaces service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. + * Core functionality of efi_install_multiple_protocol_interfaces + * Must not be called directly * * Return: status code */ -efi_status_t EFIAPI efi_install_multiple_protocol_interfaces - (efi_handle_t *handle, ...) +static efi_status_t EFIAPI +efi_install_multiple_protocol_interfaces_int(efi_handle_t *handle, + efi_va_list argptr) { - EFI_ENTRY("%p", handle); - - efi_va_list argptr; const efi_guid_t *protocol; void *protocol_interface; efi_handle_t old_handle; - efi_status_t r = EFI_SUCCESS; + efi_status_t ret = EFI_SUCCESS; int i = 0; + efi_va_list argptr_copy; if (!handle) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; - efi_va_start(argptr, handle); + efi_va_copy(argptr_copy, argptr); for (;;) { protocol = efi_va_arg(argptr, efi_guid_t*); if (!protocol) @@ -2628,104 +2624,212 @@ efi_status_t EFIAPI efi_install_multiple_protocol_interfaces if (!guidcmp(protocol, &efi_guid_device_path)) { struct efi_device_path *dp = protocol_interface; - r = EFI_CALL(efi_locate_device_path(protocol, &dp, - &old_handle)); - if (r == EFI_SUCCESS && + ret = EFI_CALL(efi_locate_device_path(protocol, &dp, + &old_handle)); + if (ret == EFI_SUCCESS && dp->type == DEVICE_PATH_TYPE_END) { EFI_PRINT("Path %pD already installed\n", protocol_interface); - r = EFI_ALREADY_STARTED; + ret = EFI_ALREADY_STARTED; break; } } - r = EFI_CALL(efi_install_protocol_interface( - handle, protocol, - EFI_NATIVE_INTERFACE, - protocol_interface)); - if (r != EFI_SUCCESS) + ret = EFI_CALL(efi_install_protocol_interface(handle, protocol, + EFI_NATIVE_INTERFACE, + protocol_interface)); + if (ret != EFI_SUCCESS) break; i++; } - efi_va_end(argptr); - if (r == EFI_SUCCESS) - return EFI_EXIT(r); + if (ret == EFI_SUCCESS) + goto out; /* If an error occurred undo all changes. */ - efi_va_start(argptr, handle); for (; i; --i) { - protocol = efi_va_arg(argptr, efi_guid_t*); - protocol_interface = efi_va_arg(argptr, void*); + protocol = efi_va_arg(argptr_copy, efi_guid_t*); + protocol_interface = efi_va_arg(argptr_copy, void*); EFI_CALL(efi_uninstall_protocol_interface(*handle, protocol, protocol_interface)); } - efi_va_end(argptr); - return EFI_EXIT(r); +out: + efi_va_end(argptr_copy); + return ret; + } /** - * efi_uninstall_multiple_protocol_interfaces() - uninstall multiple protocol - * interfaces - * @handle: handle from which the protocol interfaces shall be removed + * efi_install_multiple_protocol_interfaces() - Install multiple protocol + * interfaces + * @handle: handle on which the protocol interfaces shall be installed * @...: NULL terminated argument list with pairs of protocol GUIDS and * interfaces * - * This function implements the UninstallMultipleProtocolInterfaces service. + * + * This is the function for internal usage in U-Boot. For the API function + * implementing the InstallMultipleProtocol service see + * efi_install_multiple_protocol_interfaces_ext() + * + * Return: status code + */ +efi_status_t EFIAPI +efi_install_multiple_protocol_interfaces(efi_handle_t *handle, ...) +{ + efi_status_t ret; + efi_va_list argptr; + + efi_va_start(argptr, handle); + ret = efi_install_multiple_protocol_interfaces_int(handle, argptr); + efi_va_end(argptr); + return ret; +} + +/** + * efi_install_multiple_protocol_interfaces_ext() - Install multiple protocol + * interfaces + * @handle: handle on which the protocol interfaces shall be installed + * @...: NULL terminated argument list with pairs of protocol GUIDS and + * interfaces + * + * This function implements the MultipleProtocolInterfaces service. * * See the Unified Extensible Firmware Interface (UEFI) specification for * details. * * Return: status code */ -static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( - efi_handle_t handle, ...) +static efi_status_t EFIAPI +efi_install_multiple_protocol_interfaces_ext(efi_handle_t *handle, ...) { EFI_ENTRY("%p", handle); - + efi_status_t ret; efi_va_list argptr; + + efi_va_start(argptr, handle); + ret = efi_install_multiple_protocol_interfaces_int(handle, argptr); + efi_va_end(argptr); + return EFI_EXIT(ret); +} + +/** + * efi_uninstall_multiple_protocol_interfaces_int() - wrapper for uninstall + * multiple protocol + * interfaces + * @handle: handle from which the protocol interfaces shall be removed + * @argptr: va_list of args + * + * Core functionality of efi_uninstall_multiple_protocol_interfaces + * Must not be called directly + * + * Return: status code + */ +static efi_status_t EFIAPI +efi_uninstall_multiple_protocol_interfaces_int(efi_handle_t handle, + efi_va_list argptr) +{ const efi_guid_t *protocol; void *protocol_interface; - efi_status_t r = EFI_SUCCESS; + efi_status_t ret; size_t i = 0; + efi_va_list argptr_copy; if (!handle) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; - efi_va_start(argptr, handle); + efi_va_copy(argptr_copy, argptr); for (;;) { protocol = efi_va_arg(argptr, efi_guid_t*); if (!protocol) break; protocol_interface = efi_va_arg(argptr, void*); - r = efi_uninstall_protocol(handle, protocol, - protocol_interface); - if (r != EFI_SUCCESS) + ret = efi_uninstall_protocol(handle, protocol, + protocol_interface); + if (ret != EFI_SUCCESS) break; i++; } - efi_va_end(argptr); - if (r == EFI_SUCCESS) { + if (ret == EFI_SUCCESS) { /* If the last protocol has been removed, delete the handle. */ if (list_empty(&handle->protocols)) { list_del(&handle->link); free(handle); } - return EFI_EXIT(r); + goto out; } /* If an error occurred undo all changes. */ - efi_va_start(argptr, handle); for (; i; --i) { - protocol = efi_va_arg(argptr, efi_guid_t*); - protocol_interface = efi_va_arg(argptr, void*); + protocol = efi_va_arg(argptr_copy, efi_guid_t*); + protocol_interface = efi_va_arg(argptr_copy, void*); EFI_CALL(efi_install_protocol_interface(&handle, protocol, EFI_NATIVE_INTERFACE, protocol_interface)); } + /* + * If any errors are generated while the protocol interfaces are being + * uninstalled, then the protocols uninstalled prior to the error will + * be reinstalled using InstallProtocolInterface() and the status code + * EFI_INVALID_PARAMETER is returned. + */ + ret = EFI_INVALID_PARAMETER; + +out: + efi_va_end(argptr_copy); + return ret; +} + +/** + * efi_uninstall_multiple_protocol_interfaces() - uninstall multiple protocol + * interfaces + * @handle: handle from which the protocol interfaces shall be removed + * @...: NULL terminated argument list with pairs of protocol GUIDS and + * interfaces + * + * This function implements the UninstallMultipleProtocolInterfaces service. + * + * This is the function for internal usage in U-Boot. For the API function + * implementing the UninstallMultipleProtocolInterfaces service see + * efi_uninstall_multiple_protocol_interfaces_ext() + * + * Return: status code + */ +efi_status_t EFIAPI +efi_uninstall_multiple_protocol_interfaces(efi_handle_t handle, ...) +{ + efi_status_t ret; + efi_va_list argptr; + + efi_va_start(argptr, handle); + ret = efi_uninstall_multiple_protocol_interfaces_int(handle, argptr); efi_va_end(argptr); + return ret; +} + +/** + * efi_uninstall_multiple_protocol_interfaces_ext() - uninstall multiple protocol + * interfaces + * @handle: handle from which the protocol interfaces shall be removed + * @...: NULL terminated argument list with pairs of protocol GUIDS and + * interfaces + * + * This function implements the UninstallMultipleProtocolInterfaces service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +static efi_status_t EFIAPI +efi_uninstall_multiple_protocol_interfaces_ext(efi_handle_t handle, ...) +{ + EFI_ENTRY("%p", handle); + efi_status_t ret; + efi_va_list argptr; - /* In case of an error always return EFI_INVALID_PARAMETER */ - return EFI_EXIT(EFI_INVALID_PARAMETER); + efi_va_start(argptr, handle); + ret = efi_uninstall_multiple_protocol_interfaces_int(handle, argptr); + efi_va_end(argptr); + return EFI_EXIT(ret); } /** @@ -3785,9 +3889,9 @@ static struct efi_boot_services efi_boot_services = { .locate_handle_buffer = efi_locate_handle_buffer, .locate_protocol = efi_locate_protocol, .install_multiple_protocol_interfaces = - efi_install_multiple_protocol_interfaces, + efi_install_multiple_protocol_interfaces_ext, .uninstall_multiple_protocol_interfaces = - efi_uninstall_multiple_protocol_interfaces, + efi_uninstall_multiple_protocol_interfaces_ext, .calculate_crc32 = efi_calculate_crc32, .copy_mem = efi_copy_mem, .set_mem = efi_set_mem, |