summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2016-05-20 23:28:23 +0200
committerTom Rini <trini@konsulko.com>2016-06-06 13:39:15 -0400
commita86aeaf228da739bce6bc40927949efc33672050 (patch)
tree2f3f9a7dbf3ad0228ed1423e91dec1c0ca37fda4
parent97d44b1f5c328af97d3c381c77858c8dd32c8e20 (diff)
downloadblackbird-obmc-uboot-a86aeaf228da739bce6bc40927949efc33672050.tar.gz
blackbird-obmc-uboot-a86aeaf228da739bce6bc40927949efc33672050.zip
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>
-rw-r--r--cmd/bootefi.c6
-rw-r--r--include/efi_api.h10
-rw-r--r--lib/efi_loader/efi_boottime.c21
3 files changed, 32 insertions, 5 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index d3a2331870..2a62dce702 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -209,6 +209,12 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt)
#ifdef DEBUG_EFI
printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
#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);
}
diff --git a/include/efi_api.h b/include/efi_api.h
index 20035d7272..f572b88079 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -17,6 +17,10 @@
#include <efi.h>
+#ifdef CONFIG_EFI_LOADER
+#include <asm/setjmp.h>
+#endif
+
/* Types and defines for EFI CreateEvent */
enum efi_event_type {
EFI_TIMER_STOP = 0,
@@ -239,6 +243,12 @@ struct efi_loaded_image {
unsigned int image_code_type;
unsigned int image_data_type;
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 \
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 9daca50a72..15a1b90d65 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -458,19 +458,30 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
efi_is_direct_boot = false;
/* call the image! */
+ if (setjmp(&info->exit_jmp)) {
+ /* We returned from the child image */
+ return EFI_EXIT(info->exit_status);
+ }
+
entry(image_handle, &systab);
/* Should usually never get here */
return EFI_EXIT(EFI_SUCCESS);
}
-static efi_status_t EFIAPI efi_exit(void *image_handle, long exit_status,
- unsigned long exit_data_size,
- uint16_t *exit_data)
+static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
+ efi_status_t exit_status, unsigned long exit_data_size,
+ int16_t *exit_data)
{
+ struct efi_loaded_image *loaded_image_info = (void*)image_handle;
+
EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
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)
@@ -746,7 +757,7 @@ static const struct efi_boot_services efi_boot_services = {
.install_configuration_table = efi_install_configuration_table,
.load_image = efi_load_image,
.start_image = efi_start_image,
- .exit = (void*)efi_exit,
+ .exit = efi_exit,
.unload_image = efi_unload_image,
.exit_boot_services = efi_exit_boot_services,
.get_next_monotonic_count = efi_get_next_monotonic_count,
OpenPOWER on IntegriCloud