efi_loader: Add exit support

Some times you may want to exit an EFI payload again, for example
to default boot into a PXE installation and decide that you would
rather want to boot from the local disk instead.

This patch adds exit functionality to the EFI implementation, allowing
EFI payloads to exit.

Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Alexander Graf 2016-05-20 23:28:23 +02:00 committed by Tom Rini
parent 97d44b1f5c
commit a86aeaf228
3 changed files with 32 additions and 5 deletions

View File

@ -209,6 +209,12 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
#ifdef DEBUG_EFI #ifdef DEBUG_EFI
printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
#endif #endif
if (setjmp(&loaded_image_info.exit_jmp)) {
efi_status_t status = loaded_image_info.exit_status;
return status == EFI_SUCCESS ? 0 : -EINVAL;
}
return entry(&loaded_image_info, &systab); return entry(&loaded_image_info, &systab);
} }

View File

@ -17,6 +17,10 @@
#include <efi.h> #include <efi.h>
#ifdef CONFIG_EFI_LOADER
#include <asm/setjmp.h>
#endif
/* Types and defines for EFI CreateEvent */ /* Types and defines for EFI CreateEvent */
enum efi_event_type { enum efi_event_type {
EFI_TIMER_STOP = 0, EFI_TIMER_STOP = 0,
@ -239,6 +243,12 @@ struct efi_loaded_image {
unsigned int image_code_type; unsigned int image_code_type;
unsigned int image_data_type; unsigned int image_data_type;
unsigned long unload; unsigned long unload;
/* Below are efi loader private fields */
#ifdef CONFIG_EFI_LOADER
efi_status_t exit_status;
struct jmp_buf_data exit_jmp;
#endif
}; };
#define DEVICE_PATH_GUID \ #define DEVICE_PATH_GUID \

View File

@ -458,19 +458,30 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
efi_is_direct_boot = false; efi_is_direct_boot = false;
/* call the image! */ /* call the image! */
if (setjmp(&info->exit_jmp)) {
/* We returned from the child image */
return EFI_EXIT(info->exit_status);
}
entry(image_handle, &systab); entry(image_handle, &systab);
/* Should usually never get here */ /* Should usually never get here */
return EFI_EXIT(EFI_SUCCESS); return EFI_EXIT(EFI_SUCCESS);
} }
static efi_status_t EFIAPI efi_exit(void *image_handle, long exit_status, static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
unsigned long exit_data_size, efi_status_t exit_status, unsigned long exit_data_size,
uint16_t *exit_data) int16_t *exit_data)
{ {
struct efi_loaded_image *loaded_image_info = (void*)image_handle;
EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status, EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
exit_data_size, exit_data); exit_data_size, exit_data);
return EFI_EXIT(efi_unsupported(__func__));
loaded_image_info->exit_status = exit_status;
longjmp(&loaded_image_info->exit_jmp);
panic("EFI application exited");
} }
static struct efi_object *efi_search_obj(void *handle) static struct efi_object *efi_search_obj(void *handle)
@ -746,7 +757,7 @@ static const struct efi_boot_services efi_boot_services = {
.install_configuration_table = efi_install_configuration_table, .install_configuration_table = efi_install_configuration_table,
.load_image = efi_load_image, .load_image = efi_load_image,
.start_image = efi_start_image, .start_image = efi_start_image,
.exit = (void*)efi_exit, .exit = efi_exit,
.unload_image = efi_unload_image, .unload_image = efi_unload_image,
.exit_boot_services = efi_exit_boot_services, .exit_boot_services = efi_exit_boot_services,
.get_next_monotonic_count = efi_get_next_monotonic_count, .get_next_monotonic_count = efi_get_next_monotonic_count,