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>
This commit is contained in:
Heinrich Schuchardt 2019-04-30 17:57:30 +02:00
parent 45203e0ccb
commit 556d8dc937
3 changed files with 60 additions and 3 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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)) {
/*
@ -2669,6 +2672,41 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
return EFI_CALL(systab.boottime->exit(image_handle, ret, 0, NULL));
}
/**
* 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
@ -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);