186 lines
6.1 KiB
Diff
186 lines
6.1 KiB
Diff
|
From dafccc9baef4cb395d0dbd91ddf683e622212f47 Mon Sep 17 00:00:00 2001
|
||
|
From: Alexander Graf <agraf@suse.de>
|
||
|
Date: Wed, 2 Mar 2016 23:54:23 +0100
|
||
|
Subject: [PATCH] efi_loader: Pass proper device path in on boot
|
||
|
|
||
|
EFI payloads can query for the device they were booted from. Because
|
||
|
we have a disconnect between loading binaries and running binaries,
|
||
|
we passed in a dummy device path so far.
|
||
|
|
||
|
Unfortunately that breaks grub2's logic to find its configuration
|
||
|
file from the same device it was booted from.
|
||
|
|
||
|
This patch adds logic to have the "load" command call into our efi
|
||
|
code to set the device path to the one we last loaded a binary from.
|
||
|
|
||
|
With this grub2 properly detects where we got booted from and can
|
||
|
find its configuration file, even when searching by-partition.
|
||
|
|
||
|
Signed-off-by: Alexander Graf <agraf@suse.de>
|
||
|
---
|
||
|
cmd/bootefi.c | 34 +++++++++++++++++++++++++---------
|
||
|
cmd/fs.c | 2 ++
|
||
|
include/efi_loader.h | 10 ++++++++++
|
||
|
lib/efi_loader/efi_disk.c | 6 ------
|
||
|
4 files changed, 37 insertions(+), 15 deletions(-)
|
||
|
|
||
|
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
|
||
|
index 45d193a..6119854 100644
|
||
|
--- a/cmd/bootefi.c
|
||
|
+++ b/cmd/bootefi.c
|
||
|
@@ -20,16 +20,16 @@
|
||
|
* In addition to the originating device we also declare the file path
|
||
|
* of "bootefi" based loads to be /bootefi.
|
||
|
*/
|
||
|
-static struct efi_device_path_file_path bootefi_dummy_path[] = {
|
||
|
+static struct efi_device_path_file_path bootefi_image_path[] = {
|
||
|
{
|
||
|
.dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
|
||
|
.dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
|
||
|
- .dp.length = sizeof(bootefi_dummy_path[0]),
|
||
|
+ .dp.length = sizeof(bootefi_image_path[0]),
|
||
|
.str = { 'b','o','o','t','e','f','i' },
|
||
|
}, {
|
||
|
.dp.type = DEVICE_PATH_TYPE_END,
|
||
|
.dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
|
||
|
- .dp.length = sizeof(bootefi_dummy_path[0]),
|
||
|
+ .dp.length = sizeof(bootefi_image_path[0]),
|
||
|
}
|
||
|
};
|
||
|
|
||
|
@@ -37,14 +37,14 @@ static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol,
|
||
|
void **protocol_interface, void *agent_handle,
|
||
|
void *controller_handle, uint32_t attributes)
|
||
|
{
|
||
|
- *protocol_interface = bootefi_dummy_path;
|
||
|
+ *protocol_interface = bootefi_image_path;
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/* The EFI loaded_image interface for the image executed via "bootefi" */
|
||
|
static struct efi_loaded_image loaded_image_info = {
|
||
|
- .device_handle = bootefi_dummy_path,
|
||
|
- .file_path = bootefi_dummy_path,
|
||
|
+ .device_handle = bootefi_image_path,
|
||
|
+ .file_path = bootefi_image_path,
|
||
|
};
|
||
|
|
||
|
/* The EFI object struct for the image executed via "bootefi" */
|
||
|
@@ -62,7 +62,7 @@ static struct efi_object loaded_image_info_obj = {
|
||
|
{
|
||
|
/*
|
||
|
* When asking for the device path interface, return
|
||
|
- * bootefi_dummy_path
|
||
|
+ * bootefi_image_path
|
||
|
*/
|
||
|
.guid = &efi_guid_device_path,
|
||
|
.open = &bootefi_open_dp,
|
||
|
@@ -72,11 +72,11 @@ static struct efi_object loaded_image_info_obj = {
|
||
|
|
||
|
/* The EFI object struct for the device the "bootefi" image was loaded from */
|
||
|
static struct efi_object bootefi_device_obj = {
|
||
|
- .handle = bootefi_dummy_path,
|
||
|
+ .handle = bootefi_image_path,
|
||
|
.protocols = {
|
||
|
{
|
||
|
/* When asking for the device path interface, return
|
||
|
- * bootefi_dummy_path */
|
||
|
+ * bootefi_image_path */
|
||
|
.guid = &efi_guid_device_path,
|
||
|
.open = &bootefi_open_dp,
|
||
|
}
|
||
|
@@ -173,3 +173,19 @@ U_BOOT_CMD(
|
||
|
"Boots an EFI payload from memory\n",
|
||
|
bootefi_help_text
|
||
|
);
|
||
|
+
|
||
|
+void efi_set_bootdev(const char *dev, const char *devnr)
|
||
|
+{
|
||
|
+ char devname[16] = { 0 }; /* dp->str is u16[16] long */
|
||
|
+ char *colon;
|
||
|
+
|
||
|
+ /* Assemble the condensed device name we use in efi_disk.c */
|
||
|
+ snprintf(devname, sizeof(devname), "%s%s", dev, devnr);
|
||
|
+ colon = strchr(devname, ':');
|
||
|
+ if (colon)
|
||
|
+ *colon = '\0';
|
||
|
+
|
||
|
+ /* Patch the bootefi_image_path to the target device */
|
||
|
+ memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str));
|
||
|
+ ascii2unicode(bootefi_image_path[0].str, devname);
|
||
|
+}
|
||
|
diff --git a/cmd/fs.c b/cmd/fs.c
|
||
|
index 8f8f1b2..be8f289 100644
|
||
|
--- a/cmd/fs.c
|
||
|
+++ b/cmd/fs.c
|
||
|
@@ -9,6 +9,7 @@
|
||
|
#include <common.h>
|
||
|
#include <command.h>
|
||
|
#include <fs.h>
|
||
|
+#include <efi_loader.h>
|
||
|
|
||
|
static int do_size_wrapper(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||
|
{
|
||
|
@@ -26,6 +27,7 @@ U_BOOT_CMD(
|
||
|
static int do_load_wrapper(cmd_tbl_t *cmdtp, int flag, int argc,
|
||
|
char * const argv[])
|
||
|
{
|
||
|
+ efi_set_bootdev(argv[1], (argc > 2) ? argv[2] : "");
|
||
|
return do_load(cmdtp, flag, argc, argv, FS_TYPE_ANY);
|
||
|
}
|
||
|
|
||
|
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
||
|
index e344566..385239b 100644
|
||
|
--- a/include/efi_loader.h
|
||
|
+++ b/include/efi_loader.h
|
||
|
@@ -108,6 +108,8 @@ void efi_restore_gd(void);
|
||
|
efi_status_t efi_exit_func(efi_status_t ret);
|
||
|
/* Call this to relocate the runtime section to an address space */
|
||
|
void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
|
||
|
+/* Call this to set the current device name */
|
||
|
+void efi_set_bootdev(const char *dev, const char *devnr);
|
||
|
|
||
|
/* Generic EFI memory allocator, call this to get memory */
|
||
|
void *efi_alloc(uint64_t len, int memory_type);
|
||
|
@@ -128,6 +130,13 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
|
||
|
/* Called by board init to initialize the EFI memory map */
|
||
|
int efi_memory_init(void);
|
||
|
|
||
|
+/* Convert strings from normal C strings to uEFI strings */
|
||
|
+static inline void ascii2unicode(u16 *unicode, char *ascii)
|
||
|
+{
|
||
|
+ while (*ascii)
|
||
|
+ *(unicode++) = *(ascii++);
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* Use these to indicate that your code / data should go into the EFI runtime
|
||
|
* section and thus still be available when the OS is running
|
||
|
@@ -143,5 +152,6 @@ int efi_memory_init(void);
|
||
|
|
||
|
/* No loader configured, stub out EFI_ENTRY */
|
||
|
static inline void efi_restore_gd(void) { }
|
||
|
+static inline void efi_set_bootdev(const char *dev, const char *devnr) { }
|
||
|
|
||
|
#endif
|
||
|
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
|
||
|
index f93fcb2..9bdfad3 100644
|
||
|
--- a/lib/efi_loader/efi_disk.c
|
||
|
+++ b/lib/efi_loader/efi_disk.c
|
||
|
@@ -29,12 +29,6 @@ struct efi_disk_obj {
|
||
|
struct efi_device_path_file_path *dp;
|
||
|
};
|
||
|
|
||
|
-static void ascii2unicode(u16 *unicode, char *ascii)
|
||
|
-{
|
||
|
- while (*ascii)
|
||
|
- *(unicode++) = *(ascii++);
|
||
|
-}
|
||
|
-
|
||
|
static efi_status_t efi_disk_open_block(void *handle, efi_guid_t *protocol,
|
||
|
void **protocol_interface, void *agent_handle,
|
||
|
void *controller_handle, uint32_t attributes)
|
||
|
--
|
||
|
2.7.1
|
||
|
|