diff options
author | Heinrich Schuchardt <xypron.glpk@gmx.de> | 2019-04-30 17:57:30 +0200 |
---|---|---|
committer | Heinrich Schuchardt <xypron.glpk@gmx.de> | 2019-05-02 18:17:50 +0200 |
commit | 556d8dc937f74fa8a5fa849b7e1393db3446f3b2 (patch) | |
tree | 0079463ca29cfa732c68747cc0062fce6daa6245 | |
parent | 45203e0ccbfaab5eafe3b6a7b8bb742182a83077 (diff) | |
download | u-boot-556d8dc937f74fa8a5fa849b7e1393db3446f3b2.tar.gz |
efi_loader: implement support of exit data
In case of a failure exit data may be passed to Exit() which in turn is
returned by StartImage().
Let the `bootefi` command print the exit data string in case of an error.
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
-rw-r--r-- | cmd/bootefi.c | 11 | ||||
-rw-r--r-- | include/efi_loader.h | 5 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 47 |
3 files changed, 60 insertions, 3 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index b93d8c6a32..f1d7d8bc66 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -297,6 +297,8 @@ static efi_status_t efi_install_fdt(const char *fdt_opt) static efi_status_t do_bootefi_exec(efi_handle_t handle) { efi_status_t ret; + efi_uintn_t exit_data_size = 0; + u16 *exit_data = NULL; /* Transfer environment variable as load options */ ret = set_load_options(handle, "bootargs"); @@ -304,7 +306,12 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle) return ret; /* Call our payload! */ - ret = EFI_CALL(efi_start_image(handle, NULL, NULL)); + ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data)); + printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK); + if (ret && exit_data) { + printf("## %ls\n", exit_data); + efi_free_pool(exit_data); + } efi_restore_gd(); @@ -357,7 +364,6 @@ static int do_efibootmgr(const char *fdt_opt) } ret = do_bootefi_exec(handle); - printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK); if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; @@ -472,7 +478,6 @@ static int do_bootefi_image(const char *image_opt, const char *fdt_opt) goto out; ret = do_bootefi_exec(handle); - printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK); out: if (mem_handle) diff --git a/include/efi_loader.h b/include/efi_loader.h index 07b913d256..7af3f16ef8 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -207,12 +207,17 @@ struct efi_object { * struct efi_loaded_image_obj - handle of a loaded image * * @header: EFI object header + * @exit_status: exit status passed to Exit() + * @exit_data_size: exit data size passed to Exit() + * @exit_data: exit data passed to Exit() * @exit_jmp: long jump buffer for returning form started image * @entry: entry address of the relocated image */ struct efi_loaded_image_obj { struct efi_object header; efi_status_t exit_status; + efi_uintn_t *exit_data_size; + u16 **exit_data; struct jmp_buf_data exit_jmp; EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, struct efi_system_table *st); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index a72cbe1559..6d2dc2dda3 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2626,6 +2626,9 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, efi_is_direct_boot = false; + image_obj->exit_data_size = exit_data_size; + image_obj->exit_data = exit_data; + /* call the image! */ if (setjmp(&image_obj->exit_jmp)) { /* @@ -2670,6 +2673,41 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, } /** + * efi_update_exit_data() - fill exit data parameters of StartImage() + * + * @image_obj image handle + * @exit_data_size size of the exit data buffer + * @exit_data buffer with data returned by UEFI payload + * Return: status code + */ +static efi_status_t efi_update_exit_data(struct efi_loaded_image_obj *image_obj, + efi_uintn_t exit_data_size, + u16 *exit_data) +{ + efi_status_t ret; + + /* + * If exit_data is not provided to StartImage(), exit_data_size must be + * ignored. + */ + if (!image_obj->exit_data) + return EFI_SUCCESS; + if (image_obj->exit_data_size) + *image_obj->exit_data_size = exit_data_size; + if (exit_data_size && exit_data) { + ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, + exit_data_size, + (void **)image_obj->exit_data); + if (ret != EFI_SUCCESS) + return ret; + memcpy(*image_obj->exit_data, exit_data, exit_data_size); + } else { + image_obj->exit_data = NULL; + } + return EFI_SUCCESS; +} + +/** * efi_exit() - leave an EFI application or driver * @image_handle: handle of the application or driver that is exiting * @exit_status: status code @@ -2709,6 +2747,15 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, if (ret != EFI_SUCCESS) goto out; + /* Exit data is only foreseen in case of failure. */ + if (exit_status != EFI_SUCCESS) { + ret = efi_update_exit_data(image_obj, exit_data_size, + exit_data); + /* Exiting has priority. Don't return error to caller. */ + if (ret != EFI_SUCCESS) + EFI_PRINT("%s: out of memory\n", __func__); + } + /* Make sure entry/exit counts for EFI world cross-overs match */ EFI_EXIT(exit_status); |