aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorHeinrich Schuchardt2021-01-12 12:46:24 +0100
committerHeinrich Schuchardt2021-01-13 02:38:00 +0100
commit5f59518a7b1aef9ad3a91defa06cff82dd01cdc5 (patch)
tree10ae6cf6e06c87338628373ab9346e5922382789 /cmd
parentea1a9ec5f430359720d9a0621ed1acfbba6a142a (diff)
efi_loader: setting boot device
Up to now the bootefi command used the last file loaded to determine the boot partition. This has led to errors when the fdt had been loaded from another partition after the EFI binary. Before setting the boot device from a loaded file check if it is a PE-COFF image or a FIT image. For a PE-COFF image remember address and size, boot device and path. For a FIT image remember boot device and path. If the PE-COFF image is overwritten by loading another file, forget it. Do not allow to start an image via bootefi which is not the last loaded PE-COFF image. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/bootefi.c142
1 files changed, 87 insertions, 55 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index c82a5bacf63..8fa4a1c2876 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -29,6 +29,82 @@ DECLARE_GLOBAL_DATA_PTR;
static struct efi_device_path *bootefi_image_path;
static struct efi_device_path *bootefi_device_path;
+static void *image_addr;
+static size_t image_size;
+
+/**
+ * efi_clear_bootdev() - clear boot device
+ */
+static void efi_clear_bootdev(void)
+{
+ efi_free_pool(bootefi_device_path);
+ efi_free_pool(bootefi_image_path);
+ bootefi_device_path = NULL;
+ bootefi_image_path = NULL;
+ image_addr = NULL;
+ image_size = 0;
+}
+
+/**
+ * efi_set_bootdev() - set boot device
+ *
+ * This function is called when a file is loaded, e.g. via the 'load' command.
+ * We use the path to this file to inform the UEFI binary about the boot device.
+ *
+ * @dev: device, e.g. "MMC"
+ * @devnr: number of the device, e.g. "1:2"
+ * @path: path to file loaded
+ * @buffer: buffer with file loaded
+ * @buffer_size: size of file loaded
+ */
+void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
+ void *buffer, size_t buffer_size)
+{
+ struct efi_device_path *device, *image;
+ efi_status_t ret;
+
+ /* Forget overwritten image */
+ if (buffer + buffer_size >= image_addr &&
+ image_addr + image_size >= buffer)
+ efi_clear_bootdev();
+
+ /* Remember only PE-COFF and FIT images */
+ if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
+#ifdef CONFIG_FIT
+ if (!fit_check_format(buffer))
+ return;
+ /*
+ * FIT images of type EFI_OS are started via command bootm.
+ * We should not use their boot device with the bootefi command.
+ */
+ buffer = 0;
+ buffer_size = 0;
+#else
+ return;
+#endif
+ }
+
+ /* efi_set_bootdev() is typically called repeatedly, recover memory */
+ efi_clear_bootdev();
+
+ image_addr = buffer;
+ image_size = buffer_size;
+
+ ret = efi_dp_from_name(dev, devnr, path, &device, &image);
+ if (ret == EFI_SUCCESS) {
+ bootefi_device_path = device;
+ if (image) {
+ /* FIXME: image should not contain device */
+ struct efi_device_path *image_tmp = image;
+
+ efi_dp_split_file_path(image, &device, &image);
+ efi_free_pool(image_tmp);
+ }
+ bootefi_image_path = image;
+ } else {
+ efi_clear_bootdev();
+ }
+}
/**
* efi_env_set_load_options() - set load options from environment variable
@@ -398,33 +474,28 @@ static int do_bootefi_image(const char *image_opt)
{
void *image_buf;
unsigned long addr, size;
- const char *size_str;
efi_status_t ret;
#ifdef CONFIG_CMD_BOOTEFI_HELLO
if (!strcmp(image_opt, "hello")) {
image_buf = __efi_helloworld_begin;
size = __efi_helloworld_end - __efi_helloworld_begin;
-
- efi_free_pool(bootefi_device_path);
- efi_free_pool(bootefi_image_path);
- bootefi_device_path = NULL;
- bootefi_image_path = NULL;
+ efi_clear_bootdev();
} else
#endif
{
- size_str = env_get("filesize");
- if (size_str)
- size = simple_strtoul(size_str, NULL, 16);
- else
- size = 0;
-
- addr = simple_strtoul(image_opt, NULL, 16);
+ addr = strtoul(image_opt, NULL, 16);
/* Check that a numeric value was passed */
- if (!addr && *image_opt != '0')
+ if (!addr)
return CMD_RET_USAGE;
- image_buf = map_sysmem(addr, size);
+ image_buf = map_sysmem(addr, 0);
+
+ if (image_buf != image_addr) {
+ log_err("No UEFI binary known at %s\n", image_opt);
+ return CMD_RET_FAILURE;
+ }
+ size = image_size;
}
ret = efi_run_image(image_buf, size);
@@ -557,11 +628,8 @@ static efi_status_t bootefi_test_prepare
if (ret == EFI_SUCCESS)
return ret;
- efi_free_pool(bootefi_image_path);
- bootefi_image_path = NULL;
failure:
- efi_free_pool(bootefi_device_path);
- bootefi_device_path = NULL;
+ efi_clear_bootdev();
return ret;
}
@@ -681,39 +749,3 @@ U_BOOT_CMD(
"Boots an EFI payload from memory",
bootefi_help_text
);
-
-/**
- * efi_set_bootdev() - set boot device
- *
- * This function is called when a file is loaded, e.g. via the 'load' command.
- * We use the path to this file to inform the UEFI binary about the boot device.
- *
- * @dev: device, e.g. "MMC"
- * @devnr: number of the device, e.g. "1:2"
- * @path: path to file loaded
- */
-void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
-{
- struct efi_device_path *device, *image;
- efi_status_t ret;
-
- /* efi_set_bootdev is typically called repeatedly, recover memory */
- efi_free_pool(bootefi_device_path);
- efi_free_pool(bootefi_image_path);
-
- ret = efi_dp_from_name(dev, devnr, path, &device, &image);
- if (ret == EFI_SUCCESS) {
- bootefi_device_path = device;
- if (image) {
- /* FIXME: image should not contain device */
- struct efi_device_path *image_tmp = image;
-
- efi_dp_split_file_path(image, &device, &image);
- efi_free_pool(image_tmp);
- }
- bootefi_image_path = image;
- } else {
- bootefi_device_path = NULL;
- bootefi_image_path = NULL;
- }
-}