summaryrefslogtreecommitdiffstats
path: root/common/efi
diff options
context:
space:
mode:
Diffstat (limited to 'common/efi')
-rw-r--r--common/efi/Makefile3
-rw-r--r--common/efi/efi-image.c293
-rw-r--r--common/efi/efi.c388
-rw-r--r--common/efi/env-efi/network/eth0-discover5
4 files changed, 689 insertions, 0 deletions
diff --git a/common/efi/Makefile b/common/efi/Makefile
new file mode 100644
index 0000000000..ef19969f93
--- /dev/null
+++ b/common/efi/Makefile
@@ -0,0 +1,3 @@
+obj-y += efi.o
+obj-y += efi-image.o
+bbenv-y += env-efi
diff --git a/common/efi/efi-image.c b/common/efi/efi-image.c
new file mode 100644
index 0000000000..885348da45
--- /dev/null
+++ b/common/efi/efi-image.c
@@ -0,0 +1,293 @@
+/*
+ * efi-image.c - barebox EFI payload support
+ *
+ * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <clock.h>
+#include <common.h>
+#include <linux/sizes.h>
+#include <memory.h>
+#include <command.h>
+#include <magicvar.h>
+#include <init.h>
+#include <driver.h>
+#include <io.h>
+#include <efi.h>
+#include <malloc.h>
+#include <string.h>
+#include <linux/err.h>
+#include <boot.h>
+#include <bootm.h>
+#include <fs.h>
+#include <libfile.h>
+#include <binfmt.h>
+#include <wchar.h>
+#include <efi/efi.h>
+#include <efi/efi-device.h>
+
+struct linux_kernel_header {
+ /* first sector of the image */
+ uint8_t code1[0x0020];
+ uint16_t cl_magic; /**< Magic number 0xA33F */
+ uint16_t cl_offset; /**< The offset of command line */
+ uint8_t code2[0x01F1 - 0x0020 - 2 - 2];
+ uint8_t setup_sects; /**< The size of the setup in sectors */
+ uint16_t root_flags; /**< If the root is mounted readonly */
+ uint16_t syssize; /**< obsolete */
+ uint16_t swap_dev; /**< obsolete */
+ uint16_t ram_size; /**< obsolete */
+ uint16_t vid_mode; /**< Video mode control */
+ uint16_t root_dev; /**< Default root device number */
+ uint16_t boot_flag; /**< 0xAA55 magic number */
+
+ /* second sector of the image */
+ uint16_t jump; /**< Jump instruction (this is code!) */
+ uint32_t header; /**< Magic signature "HdrS" */
+ uint16_t version; /**< Boot protocol version supported */
+ uint32_t realmode_swtch; /**< Boot loader hook */
+ uint16_t start_sys; /**< The load-low segment (obsolete) */
+ uint16_t kernel_version; /**< Points to kernel version string */
+ uint8_t type_of_loader; /**< Boot loader identifier */
+ uint8_t loadflags; /**< Boot protocol option flags */
+ uint16_t setup_move_size; /**< Move to high memory size */
+ uint32_t code32_start; /**< Boot loader hook */
+ uint32_t ramdisk_image; /**< initrd load address */
+ uint32_t ramdisk_size; /**< initrd size */
+ uint32_t bootsect_kludge; /**< obsolete */
+ uint16_t heap_end_ptr; /**< Free memory after setup end */
+ uint8_t ext_loader_ver; /**< boot loader's extension of the version number */
+ uint8_t ext_loader_type; /**< boot loader's extension of its type */
+ uint32_t cmd_line_ptr; /**< Points to the kernel command line */
+ uint32_t initrd_addr_max; /**< Highest address for initrd */
+ uint32_t kernel_alignment; /**< Alignment unit required by the kernel */
+ uint8_t relocatable_kernel; /** */
+ uint8_t min_alignment; /** */
+ uint16_t xloadflags; /** */
+ uint32_t cmdline_size; /** */
+ uint32_t hardware_subarch; /** */
+ uint64_t hardware_subarch_data; /** */
+ uint32_t payload_offset; /** */
+ uint32_t payload_length; /** */
+ uint64_t setup_data; /** */
+ uint64_t pref_address; /** */
+ uint32_t init_size; /** */
+ uint32_t handover_offset; /** */
+} __attribute__ ((packed));
+
+int efi_load_image(const char *file, efi_loaded_image_t **loaded_image,
+ efi_handle_t *h)
+{
+ void *exe;
+ size_t size;
+ efi_handle_t handle;
+ efi_status_t efiret = EFI_SUCCESS;
+
+ exe = read_file(file, &size);
+ if (!exe)
+ return -EINVAL;
+
+ efiret = BS->load_image(false, efi_parent_image, efi_device_path, exe, size,
+ &handle);
+ if (EFI_ERROR(efiret)) {
+ pr_err("failed to LoadImage: %s\n", efi_strerror(efiret));
+ goto out;
+ };
+
+ efiret = BS->open_protocol(handle, &efi_loaded_image_protocol_guid,
+ (void **)loaded_image,
+ efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(efiret)) {
+ pr_err("failed to OpenProtocol: %s\n", efi_strerror(efiret));
+ BS->unload_image(handle);
+ goto out;
+ }
+
+ *h = handle;
+out:
+ memset(exe, 0, size);
+ free(exe);
+ return -efi_errno(efiret);
+}
+
+static int efi_execute_image(const char *file)
+{
+ efi_handle_t handle;
+ efi_loaded_image_t *loaded_image;
+ efi_status_t efiret;
+ struct linux_kernel_header *image_header;
+ const char *options;
+ bool is_driver;
+ int ret;
+
+ ret = efi_load_image(file, &loaded_image, &handle);
+ if (ret)
+ return ret;
+
+ is_driver = (loaded_image->image_code_type == EFI_BOOT_SERVICES_CODE) ||
+ (loaded_image->image_code_type == EFI_RUNTIME_SERVICES_CODE);
+
+ image_header = (struct linux_kernel_header *)loaded_image->image_base;
+ if (image_header->boot_flag == 0xAA55 &&
+ image_header->header == 0x53726448) {
+ pr_debug("Linux kernel detected. Adding bootargs.");
+ options = linux_bootargs_get();
+ pr_err("add linux options '%s'\n", options);
+ loaded_image->load_options = xstrdup_char_to_wchar(options);
+ loaded_image->load_options_size =
+ (strlen(options) + 1) * sizeof(wchar_t);
+ shutdown_barebox();
+ }
+
+ efiret = BS->start_image(handle, NULL, NULL);
+ if (EFI_ERROR(efiret))
+ pr_err("failed to StartImage: %s\n", efi_strerror(efiret));
+
+ if (!is_driver)
+ BS->unload_image(handle);
+
+ efi_connect_all();
+ efi_register_devices();
+
+ return -efi_errno(efiret);
+}
+
+#ifdef __x86_64__
+typedef void(*handover_fn)(void *image, efi_system_table_t *table,
+ struct linux_kernel_header *header);
+
+static inline void linux_efi_handover(efi_handle_t handle,
+ struct linux_kernel_header *header)
+{
+ handover_fn handover;
+
+ asm volatile ("cli");
+ handover = (handover_fn)((long)header->code32_start + 512 +
+ header->handover_offset);
+ handover(handle, efi_sys_table, header);
+}
+#else
+typedef void(*handover_fn)(VOID *image, EFI_SYSTEM_TABLE *table,
+ struct SetupHeader *setup) __attribute__((regparm(0)));
+
+static inline void linux_efi_handover(efi_handle_t handle,
+ struct linux_kernel_header *header)
+{
+ handover_fn handover;
+
+ handover = (handover_fn)((long)header->code32_start +
+ header->handover_offset);
+ handover(handle, efi_sys_table, header);
+}
+#endif
+
+static int do_bootm_efi(struct image_data *data)
+{
+ void *tmp;
+ void *initrd = NULL;
+ size_t size;
+ efi_handle_t handle;
+ int ret;
+ const char *options;
+ efi_loaded_image_t *loaded_image;
+ struct linux_kernel_header *image_header, *boot_header;
+
+ ret = efi_load_image(data->os_file, &loaded_image, &handle);
+ if (ret)
+ return ret;
+
+ image_header = (struct linux_kernel_header *)loaded_image->image_base;
+
+ if (image_header->boot_flag != 0xAA55 ||
+ image_header->header != 0x53726448 ||
+ image_header->version < 0x20b ||
+ !image_header->relocatable_kernel) {
+ pr_err("Not a valid kernel image!\n");
+ BS->unload_image(handle);
+ return -EINVAL;
+ }
+
+ boot_header = xmalloc(0x4000);
+ memset(boot_header, 0, 0x4000);
+ memcpy(boot_header, image_header, sizeof(*image_header));
+
+ boot_header->type_of_loader = 0xff;
+
+ if (data->initrd_file) {
+ tmp = read_file(data->initrd_file, &size);
+ initrd = xmemalign(PAGE_SIZE, PAGE_ALIGN(size));
+ memcpy(initrd, tmp, size);
+ memset(initrd + size, 0, PAGE_ALIGN(size) - size);
+ free(tmp);
+ boot_header->ramdisk_image = (uint64_t)initrd;
+ boot_header->ramdisk_size = PAGE_ALIGN(size);
+ }
+
+ options = linux_bootargs_get();
+ boot_header->cmd_line_ptr = (uint64_t)options;
+ boot_header->cmdline_size = strlen(options);
+
+ boot_header->code32_start = (uint64_t)loaded_image->image_base +
+ (image_header->setup_sects+1) * 512;
+
+ if (bootm_verbose(data)) {
+ printf("\nStarting kernel at 0x%p", loaded_image->image_base);
+ if (data->initrd_file)
+ printf(", initrd at 0x%08x",
+ boot_header->ramdisk_image);
+ printf("...\n");
+ }
+
+ if (data->dryrun) {
+ BS->unload_image(handle);
+ free(boot_header);
+ free(initrd);
+ return 0;
+ }
+
+ efi_set_variable_usec("LoaderTimeExecUSec", &efi_systemd_vendor_guid,
+ get_time_ns()/1000);
+
+ shutdown_barebox();
+ linux_efi_handover(handle, boot_header);
+
+ return 0;
+}
+
+static struct image_handler efi_handle_tr = {
+ .name = "EFI Application",
+ .bootm = do_bootm_efi,
+ .filetype = filetype_exe,
+};
+
+static int efi_execute(struct binfmt_hook *b, char *file, int argc, char **argv)
+{
+ return efi_execute_image(file);
+}
+
+static struct binfmt_hook binfmt_efi_hook = {
+ .type = filetype_exe,
+ .hook = efi_execute,
+};
+
+static int efi_register_image_handler(void)
+{
+ register_image_handler(&efi_handle_tr);
+ binfmt_register(&binfmt_efi_hook);
+
+ return 0;
+}
+late_initcall(efi_register_image_handler);
diff --git a/common/efi/efi.c b/common/efi/efi.c
new file mode 100644
index 0000000000..217a6bea81
--- /dev/null
+++ b/common/efi/efi.c
@@ -0,0 +1,388 @@
+/*
+ * efi.c - barebox EFI payload support
+ *
+ * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <linux/sizes.h>
+#include <memory.h>
+#include <clock.h>
+#include <command.h>
+#include <magicvar.h>
+#include <init.h>
+#include <restart.h>
+#include <driver.h>
+#include <platform_data/serial-ns16550.h>
+#include <io.h>
+#include <efi.h>
+#include <malloc.h>
+#include <string.h>
+#include <linux/err.h>
+#include <boot.h>
+#include <fs.h>
+#include <binfmt.h>
+#include <wchar.h>
+#include <envfs.h>
+#include <efi.h>
+#include <efi/efi.h>
+#include <efi/efi-device.h>
+
+efi_runtime_services_t *RT;
+efi_boot_services_t *BS;
+efi_system_table_t *efi_sys_table;
+efi_handle_t efi_parent_image;
+struct efi_device_path *efi_device_path;
+efi_loaded_image_t *efi_loaded_image;
+
+void *efi_get_variable(char *name, efi_guid_t *vendor, int *var_size)
+{
+ efi_status_t efiret;
+ void *buf;
+ unsigned long size = 0;
+ s16 *name16 = xstrdup_char_to_wchar(name);
+
+ efiret = RT->get_variable(name16, vendor, NULL, &size, NULL);
+
+ if (EFI_ERROR(efiret) && efiret != EFI_BUFFER_TOO_SMALL) {
+ buf = ERR_PTR(-efi_errno(efiret));
+ goto out;
+ }
+
+ buf = malloc(size);
+ if (!buf) {
+ buf = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ efiret = RT->get_variable(name16, vendor, NULL, &size, buf);
+ if (EFI_ERROR(efiret)) {
+ free(buf);
+ buf = ERR_PTR(-efi_errno(efiret));
+ goto out;
+ }
+
+ if (var_size)
+ *var_size = size;
+
+out:
+ free(name16);
+
+ return buf;
+}
+
+int efi_set_variable(char *name, efi_guid_t *vendor, uint32_t attributes,
+ void *buf, unsigned long size)
+{
+ efi_status_t efiret = EFI_SUCCESS;
+ s16 *name16 = xstrdup_char_to_wchar(name);
+
+ efiret = RT->set_variable(name16, vendor, attributes, size, buf);
+
+ free(name16);
+
+ return -efi_errno(efiret);
+}
+
+int efi_set_variable_usec(char *name, efi_guid_t *vendor, uint64_t usec)
+{
+ char buf[20];
+ wchar_t buf16[40];
+
+ snprintf(buf, sizeof(buf), "%lld", usec);
+ strcpy_char_to_wchar(buf16, buf);
+
+ return efi_set_variable(name, vendor,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS, buf16,
+ (strlen(buf)+1) * sizeof(wchar_t));
+}
+
+struct efi_boot {
+ u32 attributes;
+ u16 file_path_len;
+ char *description;
+ struct efi_device_path *path;
+ void *binary;
+};
+
+static struct efi_boot *efi_get_boot(int num)
+{
+ struct efi_boot *boot = xzalloc(sizeof(*boot));
+ void *buf, *ptr;
+ int size;
+ char *name;
+
+ name = xasprintf("Boot%04X", num);
+
+ buf = efi_get_global_var(name, &size);
+
+ free(name);
+
+ if (IS_ERR(buf)) {
+ free(boot);
+ return NULL;
+ }
+
+ ptr = buf;
+
+ boot->attributes = *(u32 *)ptr;
+
+ ptr += sizeof(u32);
+
+ boot->file_path_len = *(u16 *)ptr;
+
+ ptr += sizeof(u16);
+
+ boot->description = xstrdup_wchar_to_char(ptr);
+
+ ptr += (strlen(boot->description) + 1) * 2;
+
+ printf("description: %s\n", boot->description);
+
+ boot->path = memdup(ptr, boot->file_path_len);
+
+ printf("path: %s\n", device_path_to_str(boot->path));
+
+ return boot;
+}
+
+static int misc_init(void)
+{
+ efi_get_boot(1);
+ efi_get_boot(2);
+ efi_get_boot(3);
+
+ return 0;
+}
+late_initcall(misc_init);
+
+const char *efi_strerror(efi_status_t err)
+{
+ const char *str;
+
+ switch (err) {
+ case EFI_SUCCESS: str = "Success"; break;
+ case EFI_LOAD_ERROR: str = "Load Error"; break;
+ case EFI_INVALID_PARAMETER: str = "Invalid Parameter"; break;
+ case EFI_UNSUPPORTED: str = "Unsupported"; break;
+ case EFI_BAD_BUFFER_SIZE: str = "Bad Buffer Size"; break;
+ case EFI_BUFFER_TOO_SMALL: str = "Buffer Too Small"; break;
+ case EFI_NOT_READY: str = "Not Ready"; break;
+ case EFI_DEVICE_ERROR: str = "Device Error"; break;
+ case EFI_WRITE_PROTECTED: str = "Write Protected"; break;
+ case EFI_OUT_OF_RESOURCES: str = "Out of Resources"; break;
+ case EFI_VOLUME_CORRUPTED: str = "Volume Corrupt"; break;
+ case EFI_VOLUME_FULL: str = "Volume Full"; break;
+ case EFI_NO_MEDIA: str = "No Media"; break;
+ case EFI_MEDIA_CHANGED: str = "Media changed"; break;
+ case EFI_NOT_FOUND: str = "Not Found"; break;
+ case EFI_ACCESS_DENIED: str = "Access Denied"; break;
+ case EFI_NO_RESPONSE: str = "No Response"; break;
+ case EFI_NO_MAPPING: str = "No mapping"; break;
+ case EFI_TIMEOUT: str = "Time out"; break;
+ case EFI_NOT_STARTED: str = "Not started"; break;
+ case EFI_ALREADY_STARTED: str = "Already started"; break;
+ case EFI_ABORTED: str = "Aborted"; break;
+ case EFI_ICMP_ERROR: str = "ICMP Error"; break;
+ case EFI_TFTP_ERROR: str = "TFTP Error"; break;
+ case EFI_PROTOCOL_ERROR: str = "Protocol Error"; break;
+ case EFI_INCOMPATIBLE_VERSION: str = "Incompatible Version"; break;
+ case EFI_SECURITY_VIOLATION: str = "Security Violation"; break;
+ case EFI_CRC_ERROR: str = "CRC Error"; break;
+ case EFI_END_OF_MEDIA: str = "End of Media"; break;
+ case EFI_END_OF_FILE: str = "End of File"; break;
+ case EFI_INVALID_LANGUAGE: str = "Invalid Language"; break;
+ case EFI_COMPROMISED_DATA: str = "Compromised Data"; break;
+ default: str = "unknown error";
+ }
+
+ return str;
+}
+
+int efi_errno(efi_status_t err)
+{
+ int ret;
+
+ switch (err) {
+ case EFI_SUCCESS: ret = 0; break;
+ case EFI_LOAD_ERROR: ret = EIO; break;
+ case EFI_INVALID_PARAMETER: ret = EINVAL; break;
+ case EFI_UNSUPPORTED: ret = ENOTSUPP; break;
+ case EFI_BAD_BUFFER_SIZE: ret = EINVAL; break;
+ case EFI_BUFFER_TOO_SMALL: ret = EINVAL; break;
+ case EFI_NOT_READY: ret = EAGAIN; break;
+ case EFI_DEVICE_ERROR: ret = EIO; break;
+ case EFI_WRITE_PROTECTED: ret = EROFS; break;
+ case EFI_OUT_OF_RESOURCES: ret = ENOMEM; break;
+ case EFI_VOLUME_CORRUPTED: ret = EIO; break;
+ case EFI_VOLUME_FULL: ret = ENOSPC; break;
+ case EFI_NO_MEDIA: ret = ENOMEDIUM; break;
+ case EFI_MEDIA_CHANGED: ret = ENOMEDIUM; break;
+ case EFI_NOT_FOUND: ret = ENODEV; break;
+ case EFI_ACCESS_DENIED: ret = EACCES; break;
+ case EFI_NO_RESPONSE: ret = ETIMEDOUT; break;
+ case EFI_NO_MAPPING: ret = EINVAL; break;
+ case EFI_TIMEOUT: ret = ETIMEDOUT; break;
+ case EFI_NOT_STARTED: ret = EINVAL; break;
+ case EFI_ALREADY_STARTED: ret = EINVAL; break;
+ case EFI_ABORTED: ret = EINTR; break;
+ case EFI_ICMP_ERROR: ret = EINVAL; break;
+ case EFI_TFTP_ERROR: ret = EINVAL; break;
+ case EFI_PROTOCOL_ERROR: ret = EPROTO; break;
+ case EFI_INCOMPATIBLE_VERSION: ret = EINVAL; break;
+ case EFI_SECURITY_VIOLATION: ret = EINVAL; break;
+ case EFI_CRC_ERROR: ret = EINVAL; break;
+ case EFI_END_OF_MEDIA: ret = EINVAL; break;
+ case EFI_END_OF_FILE: ret = EINVAL; break;
+ case EFI_INVALID_LANGUAGE: ret = EINVAL; break;
+ case EFI_COMPROMISED_DATA: ret = EINVAL; break;
+ default: ret = EINVAL;
+ }
+
+ return ret;
+}
+
+static struct NS16550_plat ns16550_plat = {
+ .clock = 115200 * 16,
+};
+
+static int efi_console_init(void)
+{
+ barebox_set_model("barebox EFI payload");
+
+ add_generic_device("efi-stdio", DEVICE_ID_SINGLE, NULL, 0 , 0, 0, NULL);
+
+ if (IS_ENABLED(CONFIG_ARCH_EFI_REGISTER_COM1))
+ add_ns16550_device(0, 0x3f8, 0x10, IORESOURCE_IO | IORESOURCE_MEM_8BIT,
+ &ns16550_plat);
+
+ return 0;
+}
+console_initcall(efi_console_init);
+
+static void __noreturn efi_restart_system(struct restart_handler *rst)
+{
+ RT->reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
+
+ hang();
+}
+
+static int restart_register_feature(void)
+{
+ restart_handler_register_fn(efi_restart_system);
+
+ return 0;
+}
+coredevice_initcall(restart_register_feature);
+
+extern char image_base[];
+extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
+ __barebox_initcalls_end[];
+
+static int efi_init(void)
+{
+ char *env;
+
+ defaultenv_append_directory(env_efi);
+
+ env = xasprintf("/efivars/barebox-env-%pUl", &efi_barebox_vendor_guid);
+ default_environment_path_set(env);
+
+ return 0;
+}
+device_initcall(efi_init);
+
+/**
+ * efi-main - Entry point for EFI images
+ */
+efi_status_t efi_main(efi_handle_t image, efi_system_table_t *sys_table)
+{
+ efi_physical_addr_t mem;
+ size_t memsize;
+ efi_status_t efiret;
+ char *uuid;
+
+#ifdef DEBUG
+ sys_table->con_out->output_string(sys_table->con_out, L"barebox\n");
+#endif
+
+ BS = sys_table->boottime;
+
+ efi_parent_image = image;
+ efi_sys_table = sys_table;
+ RT = sys_table->runtime;
+
+ efiret = BS->open_protocol(efi_parent_image, &efi_loaded_image_protocol_guid,
+ (void **)&efi_loaded_image,
+ efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!EFI_ERROR(efiret))
+ BS->handle_protocol(efi_loaded_image->device_handle,
+ &efi_device_path_protocol_guid, (void **)&efi_device_path);
+
+ mem = 0x3fffffff;
+ for (memsize = SZ_256M; memsize >= SZ_8M; memsize /= 2) {
+ efiret = BS->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
+ EFI_LOADER_DATA,
+ memsize/PAGE_SIZE, &mem);
+ if (!EFI_ERROR(efiret))
+ break;
+ if (efiret != EFI_OUT_OF_RESOURCES)
+ panic("failed to allocate malloc pool: %s\n",
+ efi_strerror(efiret));
+ }
+ if (EFI_ERROR(efiret))
+ panic("failed to allocate malloc pool: %s\n",
+ efi_strerror(efiret));
+ mem_malloc_init((void *)mem, (void *)mem + memsize);
+
+ efi_clocksource_init();
+ efi_set_variable_usec("LoaderTimeInitUSec", &efi_systemd_vendor_guid,
+ get_time_ns()/1000);
+
+ uuid = device_path_to_partuuid(device_path_from_handle(
+ efi_loaded_image->device_handle));
+ if (uuid) {
+ wchar_t *uuid16 = xstrdup_char_to_wchar(uuid);
+ efi_set_variable("LoaderDevicePartUUID",
+ &efi_systemd_vendor_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ uuid16, (strlen(uuid)+1) * sizeof(wchar_t));
+ free(uuid);
+ free(uuid16);
+ }
+
+ start_barebox();
+
+ return EFI_SUCCESS;
+}
+
+static int do_efiexit(int argc, char *argv[])
+{
+ return BS->exit(efi_parent_image, EFI_SUCCESS, 0, NULL);
+}
+
+BAREBOX_CMD_HELP_START(efiexit)
+BAREBOX_CMD_HELP_TEXT("Leave barebox and return to the calling EFI process\n")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(efiexit)
+ .cmd = do_efiexit,
+ BAREBOX_CMD_DESC("Usage: efiexit")
+ BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+ BAREBOX_CMD_HELP(cmd_efiexit_help)
+BAREBOX_CMD_END
diff --git a/common/efi/env-efi/network/eth0-discover b/common/efi/env-efi/network/eth0-discover
new file mode 100644
index 0000000000..62c31a553c
--- /dev/null
+++ b/common/efi/env-efi/network/eth0-discover
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+for i in /boot/network-drivers/*; do
+ $i;
+done