[PATCH v2 093/113] efi: payload: dynamically determine bootloader file name

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



\EFI\BOOT\BOOTx64.EFI is only the default file path for x86_64. It's
different for other architectures and even for x86_64, the EFI loader
may be configured to execute a differently named file.

Fix this by querying the EFI loader for the file name instead of
hardcoding it and while at it, we add debug prints for the loaded image
and its parent to make it easier to debug in future.

On the off chance, that the EFI firmware doesn't inform us of a file
name this way, we revert back to a hardcoded value, that is
architecture-dependent.

Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx>
---
 efi/Kconfig        | 10 ++++++++++
 efi/devicepath.c   | 39 +++++++++++++++++++++++++++++++++------
 efi/payload/init.c | 23 ++++++++++++++++++-----
 include/efi.h      |  1 +
 4 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/efi/Kconfig b/efi/Kconfig
index 35a57a3a42de..3bda02600c94 100644
--- a/efi/Kconfig
+++ b/efi/Kconfig
@@ -35,4 +35,14 @@ config EFI_GUID
 config EFI_DEVICEPATH
 	bool
 
+config EFI_PAYLOAD_DEFAULT_PATH
+	string
+	default "EFI/BOOT/BOOTARM.EFI"		if CPU_32
+	default "EFI/BOOT/BOOTAA64.EFI"		if CPU_64
+	default "EFI/BOOT/BOOTIA32.EFI"		if X86_32
+	default "EFI/BOOT/BOOTx64.EFI"		if X86_64
+	default "EFI/BOOT/BOOTRISCV32.EFI"	if ARCH_RV32I
+	default "EFI/BOOT/BOOTRISCV64.EFI"	if ARCH_RV64I
+	default "EFI/BOOT/BAREBOX.EFI"
+
 endmenu
diff --git a/efi/devicepath.c b/efi/devicepath.c
index 0c2fc4d86927..98aba6289e18 100644
--- a/efi/devicepath.c
+++ b/efi/devicepath.c
@@ -83,15 +83,23 @@ const struct efi_device_path end_instance_device_path = {
 const struct efi_device_path *
 device_path_from_handle(efi_handle_t Handle)
 {
+	const efi_guid_t *const protocols[] = {
+		&efi_loaded_image_device_path_guid,
+		&efi_device_path_protocol_guid,
+		NULL
+	};
+	const efi_guid_t * const*proto;
 	efi_status_t Status;
-	const struct efi_device_path *device_path;
 
-	Status = BS->handle_protocol(Handle, &efi_device_path_protocol_guid,
-				(void *) &device_path);
-	if (EFI_ERROR(Status))
-		device_path = NULL;
+	for (proto = protocols; *proto; proto++) {
+		const struct efi_device_path *device_path;
 
-	return device_path;
+		Status = BS->handle_protocol(Handle, *proto, (void *) &device_path);
+		if (!EFI_ERROR(Status) && device_path)
+			return device_path;
+	}
+
+	return NULL;
 }
 
 static struct efi_device_path *
@@ -871,3 +879,22 @@ char *device_path_to_partuuid(const struct efi_device_path *dev_path)
 	return NULL;
 }
 
+char *device_path_to_filepath(const struct efi_device_path *dev_path)
+{
+	struct filepath_device_path *fp = NULL;
+	char *path;
+
+	dev_path = unpack_device_path(dev_path);
+
+	while ((dev_path = device_path_next_compatible_node(dev_path,
+				 MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP))) {
+		fp = container_of(dev_path, struct filepath_device_path, header);
+		dev_path = next_device_path_node(&fp->header);
+	}
+
+	path = strdup_wchar_to_char(fp->path_name);
+	if (!path)
+		return NULL;
+
+	return strreplace(path, '\\', '/');
+}
diff --git a/efi/payload/init.c b/efi/payload/init.c
index d5ec86fafe1a..0f518d4954cb 100644
--- a/efi/payload/init.c
+++ b/efi/payload/init.c
@@ -300,7 +300,10 @@ core_efi_initcall(efi_core_init);
 
 static int efi_postcore_init(void)
 {
-	char *uuid;
+	const struct efi_device_path *parent_image_dp, *loaded_image_dp;
+	char *bbu_path = "/boot/" CONFIG_EFI_PAYLOAD_DEFAULT_PATH;
+
+	char *filepath, *uuid;
 	static const uint64_t loader_features =
 		EFI_LOADER_FEATURE_DEVICETREE;
 
@@ -322,8 +325,10 @@ static int efi_postcore_init(void)
 	efi_set_variable_uint64_le("LoaderFeatures", &efi_systemd_vendor_guid,
 				   loader_features);
 
-	uuid = device_path_to_partuuid(device_path_from_handle(
-				       efi_loaded_image->device_handle));
+	loaded_image_dp = device_path_from_handle(efi_loaded_image->device_handle);
+	pr_debug("loaded-image: %pD\n", loaded_image_dp);
+
+	uuid = device_path_to_partuuid(loaded_image_dp);
 	if (uuid) {
 		wchar_t *uuid16 = xstrdup_char_to_wchar(uuid);
 		efi_set_variable("LoaderDevicePartUUID",
@@ -335,8 +340,16 @@ static int efi_postcore_init(void)
 		free(uuid16);
 	}
 
-	bbu_register_std_file_update("fat", 0,	"/boot/EFI/BOOT/BOOTx64.EFI",
-				     filetype_exe);
+	parent_image_dp = device_path_from_handle(efi_parent_image);
+	pr_debug("parent-image: %pD\n", parent_image_dp);
+
+	filepath = device_path_to_filepath(parent_image_dp);
+	if (filepath) {
+		bbu_path = basprintf("/boot/%s", filepath);
+		free(filepath);
+	}
+
+	bbu_register_std_file_update("fat", 0, bbu_path, filetype_exe);
 
 	return 0;
 }
diff --git a/include/efi.h b/include/efi.h
index 45e4080fac08..6bb5f8cb0a30 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -884,6 +884,7 @@ size_t device_path_to_str_buf(const struct efi_device_path *dev_path, char buf[]
 u8 device_path_to_type(const struct efi_device_path *dev_path);
 u8 device_path_to_subtype(const struct efi_device_path *dev_path);
 char *device_path_to_partuuid(const struct efi_device_path *dev_path);
+char *device_path_to_filepath(const struct efi_device_path *dev_path);
 
 const char *efi_guid_string(efi_guid_t *g);
 
-- 
2.39.2





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux