linux-efi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] efi: Improve command line initrd loader support
@ 2022-09-27  8:58 Ard Biesheuvel
  2022-09-27  8:58 ` [PATCH 1/4] efi: libstub: Implement devicepath support for initrd commandline loader Ard Biesheuvel
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2022-09-27  8:58 UTC (permalink / raw)
  To: linux-efi
  Cc: Ard Biesheuvel, Huacai Chen, Palmer Dabbelt, Jeremy Linton,
	Atish Patra, Lennart Poettering, Ilias Apalodimas

Given that the command line initrd loader can only load files from the
same simple FS volume from which the kernel itself was loaded, it was
not flexible enough for use in loaders such as GRUB that don't even
implement the FS volume abstraction, and load images as anonymous
buffers in memory. As x86 mixed mode was based on a GRUB specific EFI
handover protocol, and the simple FS protocol method prototypes were not
mixed mode safe, the initrd command line loader did not work for mixed
mode at all.

For this reason, we support arch specific methods (bootparam, DT) as
well, and have added support for a generic method based on the LoadFile2
protocol, which is much easier to implement and use.

However, there are cases where the command line loader is useful,
especially when using fully generic loaders such as the UEFI shell.
Here, it is generally not possible to use Linux specific structs or data
structures, or implement the Linux specific LoadFile2 protocol
implementation for initrd loading.

So let's fix the issues with the initrd command line loader:
- add the ability to use fully qualified device paths as the initrd=
  argument, so that the initrd image can reside on any simple FS volume,
  even if the kernel itself was not loaded from one;
- fix the mixed mode issues, by using the mixed mode wrappers for the
  protocol invocations, and defining some recipes for the prototypes
  that cannot be marshalled 1:1

The above means that mixed mode loaders that boot via the compat entry
point (e.g., systemd-boot) can use the initrd= command line option as
before to pass the initrd, if desired.

With those fixes in place, let's remove the deprecation notice, and
permit the feature to be enabled on LoongArch and RISC-V as well.

Note that LoadFile2 is still preferred, and will continue to take
precedence. It is also the only generic method that cannot be compiled
out.

Cc: Huacai Chen <chenhuacai@loongson.cn>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Jeremy Linton <jeremy.linton@arm.com>
Cc: Atish Patra <atishp@atishpatra.org>
Cc: Lennart Poettering <lennart@poettering.net>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>

Ard Biesheuvel (4):
  efi: libstub: Implement devicepath support for initrd commandline
    loader
  efi: libstub: Permit mixed mode return types other than efi_status_t
  efi: libstub: Add mixed mode support to command line initrd loader
  efi: libstub: Undeprecate the command line initrd loader

 arch/x86/boot/compressed/efi_thunk_64.S        |   6 --
 arch/x86/include/asm/efi.h                     |  49 +++++----
 drivers/firmware/efi/Kconfig                   |  13 ++-
 drivers/firmware/efi/libstub/efi-stub-helper.c |   2 +-
 drivers/firmware/efi/libstub/efistub.h         | 112 ++++++++++++++------
 drivers/firmware/efi/libstub/file.c            | 105 +++++++++++++-----
 include/linux/efi.h                            |   6 ++
 7 files changed, 202 insertions(+), 91 deletions(-)

-- 
2.35.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/4] efi: libstub: Implement devicepath support for initrd commandline loader
  2022-09-27  8:58 [PATCH 0/4] efi: Improve command line initrd loader support Ard Biesheuvel
@ 2022-09-27  8:58 ` Ard Biesheuvel
  2022-09-27  8:58 ` [PATCH 2/4] efi: libstub: Permit mixed mode return types other than efi_status_t Ard Biesheuvel
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2022-09-27  8:58 UTC (permalink / raw)
  To: linux-efi
  Cc: Ard Biesheuvel, Huacai Chen, Palmer Dabbelt, Jeremy Linton,
	Atish Patra, Lennart Poettering, Ilias Apalodimas

Currently, the initrd= command line option to the EFI stub only supports
loading files that reside on the same volume as the loaded image, which
is not workable for loaders like GRUB that don't even implement the
volume abstraction (EFI_SIMPLE_FILE_SYSTEM_PROTOCOL), and load the
kernel from an anonymous buffer in memory. For this reason, another
method was devised that relies on the LoadFile2 protocol.

However, the command line loader is rather useful when using the UEFI
shell or other generic loaders that have no awareness of Linux specific
protocols so let's make it a bit more flexible, by permitting textual
device paths to be provided to initrd= as well, provided that they refer
to a file hosted on a EFI_SIMPLE_FILE_SYSTEM_PROTOCOL volume. E.g.,

  initrd=PciRoot(0x0)/Pci(0x3,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/rootfs.cpio.gz

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/libstub/efistub.h | 15 ++++
 drivers/firmware/efi/libstub/file.c    | 77 +++++++++++++++++---
 include/linux/efi.h                    |  6 ++
 3 files changed, 87 insertions(+), 11 deletions(-)

diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 7e619f7ad438..f403aebf0182 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -179,6 +179,21 @@ union efi_device_path_to_text_protocol {
 
 typedef union efi_device_path_to_text_protocol efi_device_path_to_text_protocol_t;
 
+union efi_device_path_from_text_protocol {
+	struct {
+		efi_device_path_protocol_t *
+			(__efiapi *convert_text_to_device_node)(const efi_char16_t *);
+		efi_device_path_protocol_t *
+			(__efiapi *convert_text_to_device_path)(const efi_char16_t *);
+	};
+	struct {
+		u32 convert_text_to_device_node;
+		u32 convert_text_to_device_path;
+	} mixed_mode;
+};
+
+typedef union efi_device_path_from_text_protocol efi_device_path_from_text_protocol_t;
+
 typedef void *efi_event_t;
 /* Note that notifications won't work in mixed mode */
 typedef void (__efiapi *efi_event_notify_t)(efi_event_t, void *);
diff --git a/drivers/firmware/efi/libstub/file.c b/drivers/firmware/efi/libstub/file.c
index bf133d39a543..972ecc97b1d1 100644
--- a/drivers/firmware/efi/libstub/file.c
+++ b/drivers/firmware/efi/libstub/file.c
@@ -43,6 +43,13 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
 	efi_file_protocol_t *fh;
 	unsigned long info_sz;
 	efi_status_t status;
+	efi_char16_t *c;
+
+	/* Replace UNIX dir separators with EFI standard ones */
+	for (c = fi->filename; *c != L'\0'; c++) {
+		if (*c == L'/')
+			*c = L'\\';
+	}
 
 	status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0);
 	if (status != EFI_SUCCESS) {
@@ -129,16 +136,61 @@ static int find_file_option(const efi_char16_t *cmdline, int cmdline_len,
 
 		if (c == L'\0' || c == L'\n' || c == L' ')
 			break;
-		else if (c == L'/')
-			/* Replace UNIX dir separators with EFI standard ones */
-			*result++ = L'\\';
-		else
-			*result++ = c;
+		*result++ = c;
 	}
 	*result = L'\0';
 	return i;
 }
 
+static efi_status_t efi_open_device_path(efi_file_protocol_t **volume,
+					 struct finfo *fi)
+{
+	efi_guid_t text_to_dp_guid = EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID;
+	static efi_device_path_from_text_protocol_t *text_to_dp = NULL;
+	efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+	efi_device_path_protocol_t *initrd_dp;
+	efi_simple_file_system_protocol_t *io;
+	struct efi_file_path_dev_path *fpath;
+	efi_handle_t handle;
+	efi_status_t status;
+
+	/* See if the text to device path protocol exists */
+	if (!text_to_dp &&
+	    efi_bs_call(locate_protocol, &text_to_dp_guid, NULL,
+			(void **)&text_to_dp) != EFI_SUCCESS)
+		return EFI_UNSUPPORTED;
+
+
+	/* Convert the filename wide string into a device path */
+	initrd_dp = text_to_dp->convert_text_to_device_path(fi->filename);
+
+	/* Check whether the device path in question implements simple FS */
+	if ((efi_bs_call(locate_device_path, &fs_proto, &initrd_dp, &handle) ?:
+	     efi_bs_call(handle_protocol, handle, &fs_proto, (void **)&io))
+	    != EFI_SUCCESS)
+		return EFI_NOT_FOUND;
+
+	/* Check whether the remaining device path is a file device path */
+	if (initrd_dp->type != EFI_DEV_MEDIA ||
+	    initrd_dp->sub_type != EFI_DEV_MEDIA_FILE) {
+		efi_warn("Unexpected device path node type: (%x, %x)\n",
+			 initrd_dp->type, initrd_dp->sub_type);
+		return EFI_LOAD_ERROR;
+	}
+
+	/* Copy the remaining file path into the fi structure */
+	fpath = (struct efi_file_path_dev_path *)initrd_dp;
+	memcpy(fi->filename, fpath->filename,
+	       min(sizeof(fi->filename),
+		   fpath->header.length - sizeof(fpath->header)));
+
+	status = io->open_volume(io, volume);
+	if (status != EFI_SUCCESS)
+		efi_err("Failed to open volume\n");
+
+	return status;
+}
+
 /*
  * Check the cmdline for a LILO-style file= arguments.
  *
@@ -188,11 +240,13 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
 		cmdline += offset;
 		cmdline_len -= offset;
 
-		if (!volume) {
+		status = efi_open_device_path(&volume, &fi);
+		if (status == EFI_UNSUPPORTED || status == EFI_NOT_FOUND)
+			/* try the volume that holds the kernel itself */
 			status = efi_open_volume(image, &volume);
-			if (status != EFI_SUCCESS)
-				return status;
-		}
+
+		if (status != EFI_SUCCESS)
+			goto err_free_alloc;
 
 		status = efi_open_file(volume, &fi, &file, &size);
 		if (status != EFI_SUCCESS)
@@ -249,13 +303,12 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
 			size -= chunksize;
 		}
 		file->close(file);
+		volume->close(volume);
 	} while (offset > 0);
 
 	*load_addr = alloc_addr;
 	*load_size = alloc_size;
 
-	if (volume)
-		volume->close(volume);
 	return EFI_SUCCESS;
 
 err_close_file:
@@ -263,6 +316,8 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
 
 err_close_volume:
 	volume->close(volume);
+
+err_free_alloc:
 	efi_free(alloc_size, alloc_addr);
 	return status;
 }
diff --git a/include/linux/efi.h b/include/linux/efi.h
index da3974bf05d3..e739196ce9b2 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -371,6 +371,7 @@ void efi_native_runtime_setup(void);
 #define LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID	EFI_GUID(0xbc62157e, 0x3e33, 0x4fec,  0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf)
 #define EFI_DEVICE_PATH_PROTOCOL_GUID		EFI_GUID(0x09576e91, 0x6d3f, 0x11d2,  0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 #define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID	EFI_GUID(0x8b843e20, 0x8132, 0x4852,  0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c)
+#define EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID	EFI_GUID(0x05c99a21, 0xc70f, 0x4ad2,  0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e)
 #define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID	EFI_GUID(0x9042a9de, 0x23dc, 0x4a38,  0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a)
 #define EFI_UGA_PROTOCOL_GUID			EFI_GUID(0x982c298b, 0xf4fa, 0x41cb,  0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39)
 #define EFI_PCI_IO_PROTOCOL_GUID		EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5,  0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a)
@@ -1011,6 +1012,11 @@ struct efi_mem_mapped_dev_path {
 	u64				ending_addr;
 } __packed;
 
+struct efi_file_path_dev_path {
+	struct efi_generic_dev_path	header;
+	efi_char16_t			filename[];
+} __packed;
+
 struct efi_dev_path {
 	union {
 		struct efi_generic_dev_path	header;
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/4] efi: libstub: Permit mixed mode return types other than efi_status_t
  2022-09-27  8:58 [PATCH 0/4] efi: Improve command line initrd loader support Ard Biesheuvel
  2022-09-27  8:58 ` [PATCH 1/4] efi: libstub: Implement devicepath support for initrd commandline loader Ard Biesheuvel
@ 2022-09-27  8:58 ` Ard Biesheuvel
  2022-09-27  8:58 ` [PATCH 3/4] efi: libstub: Add mixed mode support to command line initrd loader Ard Biesheuvel
  2022-09-27  8:58 ` [PATCH 4/4] efi: libstub: Undeprecate the " Ard Biesheuvel
  3 siblings, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2022-09-27  8:58 UTC (permalink / raw)
  To: linux-efi
  Cc: Ard Biesheuvel, Huacai Chen, Palmer Dabbelt, Jeremy Linton,
	Atish Patra, Lennart Poettering, Ilias Apalodimas

Rework the EFI stub macro wrappers around protocol method calls and
other indirect calls in order to allow return types other than
efi_status_t. This means the widening should be conditional on whether
or not the return type is efi_status_t, and should be omitted otherwise.

Note that this does not take into account that unsigned long types might
exist that are not efi_status_t, but that can be addressed when it
becomes an issue.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/x86/boot/compressed/efi_thunk_64.S |  6 ----
 arch/x86/include/asm/efi.h              | 38 ++++++++------------
 drivers/firmware/efi/libstub/efistub.h  | 16 ++++++---
 3 files changed, 26 insertions(+), 34 deletions(-)

diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S
index 67e7edcdfea8..0c988f2a1243 100644
--- a/arch/x86/boot/compressed/efi_thunk_64.S
+++ b/arch/x86/boot/compressed/efi_thunk_64.S
@@ -93,12 +93,6 @@ SYM_FUNC_START(__efi64_thunk)
 	movl	%ebx, %fs
 	movl	%ebx, %gs
 
-	/*
-	 * Convert 32-bit status code into 64-bit.
-	 */
-	roll	$1, %eax
-	rorq	$1, %rax
-
 	pop	%rbx
 	pop	%rbp
 	RET
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 233ae6986d6f..8edead8568ec 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -178,7 +178,7 @@ struct efi_setup_data {
 extern u64 efi_setup;
 
 #ifdef CONFIG_EFI
-extern efi_status_t __efi64_thunk(u32, ...);
+extern u64 __efi64_thunk(u32, ...);
 
 #define efi64_thunk(...) ({						\
 	u64 __pad[3]; /* must have space for 3 args on the stack */	\
@@ -344,31 +344,23 @@ static inline u32 efi64_convert_status(efi_status_t status)
 #define __efi_eat(...)
 #define __efi_eval(...) __VA_ARGS__
 
-/* The three macros below handle dispatching via the thunk if needed */
-
-#define efi_call_proto(inst, func, ...)					\
-	(efi_is_native()						\
-		? inst->func(inst, ##__VA_ARGS__)			\
-		: __efi64_thunk_map(inst, func, inst, ##__VA_ARGS__))
-
-#define efi_bs_call(func, ...)						\
-	(efi_is_native()						\
-		? efi_system_table->boottime->func(__VA_ARGS__)		\
-		: __efi64_thunk_map(efi_table_attr(efi_system_table,	\
-						   boottime),		\
-				    func, __VA_ARGS__))
+static inline efi_status_t __efi64_widen_efi_status(u64 status)
+{
+	return status ? status ^ 0x8000000080000000ULL : 0;
+}
 
-#define efi_rt_call(func, ...)						\
-	(efi_is_native()						\
-		? efi_system_table->runtime->func(__VA_ARGS__)		\
-		: __efi64_thunk_map(efi_table_attr(efi_system_table,	\
-						   runtime),		\
-				    func, __VA_ARGS__))
+/* The macro below handles dispatching via the thunk if needed */
 
-#define efi_dxe_call(func, ...)						\
+#define efi_fn_call(inst, func, ...)					\
 	(efi_is_native()						\
-		? efi_dxe_table->func(__VA_ARGS__)			\
-		: __efi64_thunk_map(efi_dxe_table, func, __VA_ARGS__))
+	? inst->func(__VA_ARGS__)					\
+	: __builtin_choose_expr(					\
+		__builtin_types_compatible_p(efi_status_t,		\
+			__typeof__(inst->func(__VA_ARGS__))),		\
+		__efi64_widen_efi_status(				\
+			__efi64_thunk_map(inst, func, ##__VA_ARGS__)),	\
+		(__typeof__(inst->func(__VA_ARGS__)))			\
+			__efi64_thunk_map(inst, func, ##__VA_ARGS__)))
 
 #else /* CONFIG_EFI_MIXED */
 
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index f403aebf0182..d26d3d7b99c0 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -44,15 +44,21 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
 
 #ifndef ARCH_HAS_EFISTUB_WRAPPERS
 
-#define efi_is_native()		(true)
-#define efi_bs_call(func, ...)	efi_system_table->boottime->func(__VA_ARGS__)
-#define efi_rt_call(func, ...)	efi_system_table->runtime->func(__VA_ARGS__)
-#define efi_dxe_call(func, ...)	efi_dxe_table->func(__VA_ARGS__)
+#define efi_is_native()			(true)
 #define efi_table_attr(inst, attr)	(inst->attr)
-#define efi_call_proto(inst, func, ...) inst->func(inst, ##__VA_ARGS__)
+#define efi_fn_call(inst, func, ...)	inst->func(__VA_ARGS__)
 
 #endif
 
+#define efi_call_proto(inst, func, ...) \
+	efi_fn_call(inst, func, inst, ##__VA_ARGS__)
+#define efi_bs_call(func, ...) \
+	efi_fn_call(efi_table_attr(efi_system_table, boottime), func, ##__VA_ARGS__)
+#define efi_rt_call(func, ...) \
+	efi_fn_call(efi_table_attr(efi_system_table, runtime), func, ##__VA_ARGS__)
+#define efi_dxe_call(func, ...) \
+	efi_fn_call(efi_dxe_table, func, ##__VA_ARGS__)
+
 #define efi_info(fmt, ...) \
 	efi_printk(KERN_INFO fmt, ##__VA_ARGS__)
 #define efi_warn(fmt, ...) \
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/4] efi: libstub: Add mixed mode support to command line initrd loader
  2022-09-27  8:58 [PATCH 0/4] efi: Improve command line initrd loader support Ard Biesheuvel
  2022-09-27  8:58 ` [PATCH 1/4] efi: libstub: Implement devicepath support for initrd commandline loader Ard Biesheuvel
  2022-09-27  8:58 ` [PATCH 2/4] efi: libstub: Permit mixed mode return types other than efi_status_t Ard Biesheuvel
@ 2022-09-27  8:58 ` Ard Biesheuvel
  2022-09-27  8:58 ` [PATCH 4/4] efi: libstub: Undeprecate the " Ard Biesheuvel
  3 siblings, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2022-09-27  8:58 UTC (permalink / raw)
  To: linux-efi
  Cc: Ard Biesheuvel, Huacai Chen, Palmer Dabbelt, Jeremy Linton,
	Atish Patra, Lennart Poettering, Ilias Apalodimas

Now that we have support for calling protocols that need additional
marshalling for mixed mode, wire up the initrd command line loader.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/x86/include/asm/efi.h                     | 11 +++
 drivers/firmware/efi/libstub/efi-stub-helper.c |  2 +-
 drivers/firmware/efi/libstub/efistub.h         | 81 +++++++++++++-------
 drivers/firmware/efi/libstub/file.c            | 34 ++++----
 4 files changed, 84 insertions(+), 44 deletions(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 8edead8568ec..9e56bd489b29 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -325,6 +325,17 @@ static inline u32 efi64_convert_status(efi_status_t status)
 #define __efi64_argmap_set_memory_space_attributes(phys, size, flags) \
 	(__efi64_split(phys), __efi64_split(size), __efi64_split(flags))
 
+/* file protocol */
+#define __efi64_argmap_open(prot, newh, fname, mode, attr) \
+	((prot), efi64_zero_upper(newh), (fname), __efi64_split(mode), \
+	 __efi64_split(attr))
+
+#define __efi64_argmap_set_position(pos) (__efi64_split(pos))
+
+/* file system protocol */
+#define __efi64_argmap_open_volume(prot, file) \
+	((prot), efi64_zero_upper(file))
+
 /*
  * The macros below handle the plumbing for the argument mapping. To add a
  * mapping for a specific EFI method, simply define a macro
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 3249d7927c88..37f42a1d1777 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -682,7 +682,7 @@ efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image,
 				     unsigned long hard_limit)
 {
 	if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER) ||
-	    (IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL)))
+	    (IS_ENABLED(CONFIG_X86) && image == NULL))
 		return EFI_UNSUPPORTED;
 
 	return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index d26d3d7b99c0..23b7880be11a 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -593,36 +593,63 @@ typedef struct {
 	efi_char16_t		filename[];
 } efi_file_info_t;
 
-typedef struct efi_file_protocol efi_file_protocol_t;
-
-struct efi_file_protocol {
-	u64		revision;
-	efi_status_t	(__efiapi *open)	(efi_file_protocol_t *,
-						 efi_file_protocol_t **,
-						 efi_char16_t *, u64, u64);
-	efi_status_t	(__efiapi *close)	(efi_file_protocol_t *);
-	efi_status_t	(__efiapi *delete)	(efi_file_protocol_t *);
-	efi_status_t	(__efiapi *read)	(efi_file_protocol_t *,
-						 unsigned long *, void *);
-	efi_status_t	(__efiapi *write)	(efi_file_protocol_t *,
-						 unsigned long, void *);
-	efi_status_t	(__efiapi *get_position)(efi_file_protocol_t *, u64 *);
-	efi_status_t	(__efiapi *set_position)(efi_file_protocol_t *, u64);
-	efi_status_t	(__efiapi *get_info)	(efi_file_protocol_t *,
-						 efi_guid_t *, unsigned long *,
-						 void *);
-	efi_status_t	(__efiapi *set_info)	(efi_file_protocol_t *,
-						 efi_guid_t *, unsigned long,
-						 void *);
-	efi_status_t	(__efiapi *flush)	(efi_file_protocol_t *);
+typedef union efi_file_protocol efi_file_protocol_t;
+
+union efi_file_protocol {
+	struct {
+		u64		revision;
+		efi_status_t	(__efiapi *open)	(efi_file_protocol_t *,
+							 efi_file_protocol_t **,
+							 efi_char16_t *, u64,
+							 u64);
+		efi_status_t	(__efiapi *close)	(efi_file_protocol_t *);
+		efi_status_t	(__efiapi *delete)	(efi_file_protocol_t *);
+		efi_status_t	(__efiapi *read)	(efi_file_protocol_t *,
+							 unsigned long *,
+							 void *);
+		efi_status_t	(__efiapi *write)	(efi_file_protocol_t *,
+							 unsigned long, void *);
+		efi_status_t	(__efiapi *get_position)(efi_file_protocol_t *,
+							 u64 *);
+		efi_status_t	(__efiapi *set_position)(efi_file_protocol_t *,
+							 u64);
+		efi_status_t	(__efiapi *get_info)	(efi_file_protocol_t *,
+							 efi_guid_t *,
+							 unsigned long *,
+							 void *);
+		efi_status_t	(__efiapi *set_info)	(efi_file_protocol_t *,
+							 efi_guid_t *,
+							 unsigned long,
+							 void *);
+		efi_status_t	(__efiapi *flush)	(efi_file_protocol_t *);
+	};
+	struct {
+		u64 revision;
+		u32 open;
+		u32 close;
+		u32 delete;
+		u32 read;
+		u32 write;
+		u32 get_position;
+		u32 set_position;
+		u32 get_info;
+		u32 set_info;
+		u32 flush;
+	} mixed_mode;
 };
 
-typedef struct efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
+typedef union efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
 
-struct efi_simple_file_system_protocol {
-	u64	revision;
-	int	(__efiapi *open_volume)(efi_simple_file_system_protocol_t *,
-					efi_file_protocol_t **);
+union efi_simple_file_system_protocol {
+	struct {
+		u64		revision;
+		efi_status_t	(__efiapi *open_volume)(efi_simple_file_system_protocol_t *,
+							efi_file_protocol_t **);
+	};
+	struct {
+		u64 revision;
+		u32 open_volume;
+	} mixed_mode;
 };
 
 #define EFI_FILE_MODE_READ	0x0000000000000001
diff --git a/drivers/firmware/efi/libstub/file.c b/drivers/firmware/efi/libstub/file.c
index 972ecc97b1d1..b16c6bdc9359 100644
--- a/drivers/firmware/efi/libstub/file.c
+++ b/drivers/firmware/efi/libstub/file.c
@@ -51,17 +51,18 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
 			*c = L'\\';
 	}
 
-	status = volume->open(volume, &fh, fi->filename, EFI_FILE_MODE_READ, 0);
+	status = efi_call_proto(volume, open, &fh, fi->filename,
+				EFI_FILE_MODE_READ, 0);
 	if (status != EFI_SUCCESS) {
 		efi_err("Failed to open file: %ls\n", fi->filename);
 		return status;
 	}
 
 	info_sz = sizeof(struct finfo);
-	status = fh->get_info(fh, &info_guid, &info_sz, fi);
+	status = efi_call_proto(fh, get_info, &info_guid, &info_sz, fi);
 	if (status != EFI_SUCCESS) {
 		efi_err("Failed to get file info\n");
-		fh->close(fh);
+		efi_call_proto(fh, close);
 		return status;
 	}
 
@@ -73,7 +74,7 @@ static efi_status_t efi_open_file(efi_file_protocol_t *volume,
 static efi_status_t efi_open_volume(efi_loaded_image_t *image,
 				    efi_file_protocol_t **fh)
 {
-	struct efi_vendor_dev_path *dp = image->file_path;
+	struct efi_vendor_dev_path *dp = efi_table_attr(image, file_path);
 	efi_guid_t li_proto = LOADED_IMAGE_PROTOCOL_GUID;
 	efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
 	efi_simple_file_system_protocol_t *io;
@@ -95,14 +96,14 @@ static efi_status_t efi_open_volume(efi_loaded_image_t *image,
 		}
 	}
 
-	status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto,
-			     (void **)&io);
+	status = efi_bs_call(handle_protocol, efi_table_attr(image, device_handle),
+			     &fs_proto, (void **)&io);
 	if (status != EFI_SUCCESS) {
 		efi_err("Failed to handle fs_proto\n");
 		return status;
 	}
 
-	status = io->open_volume(io, fh);
+	status = efi_call_proto(io, open_volume, fh);
 	if (status != EFI_SUCCESS)
 		efi_err("Failed to open volume\n");
 
@@ -162,7 +163,8 @@ static efi_status_t efi_open_device_path(efi_file_protocol_t **volume,
 
 
 	/* Convert the filename wide string into a device path */
-	initrd_dp = text_to_dp->convert_text_to_device_path(fi->filename);
+	initrd_dp = efi_fn_call(text_to_dp, convert_text_to_device_path,
+				fi->filename);
 
 	/* Check whether the device path in question implements simple FS */
 	if ((efi_bs_call(locate_device_path, &fs_proto, &initrd_dp, &handle) ?:
@@ -184,7 +186,7 @@ static efi_status_t efi_open_device_path(efi_file_protocol_t **volume,
 	       min(sizeof(fi->filename),
 		   fpath->header.length - sizeof(fpath->header)));
 
-	status = io->open_volume(io, volume);
+	status = efi_call_proto(io, open_volume, volume);
 	if (status != EFI_SUCCESS)
 		efi_err("Failed to open volume\n");
 
@@ -205,8 +207,8 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
 				  unsigned long *load_addr,
 				  unsigned long *load_size)
 {
-	const efi_char16_t *cmdline = image->load_options;
-	u32 cmdline_len = image->load_options_size;
+	const efi_char16_t *cmdline = efi_table_attr(image, load_options);
+	u32 cmdline_len = efi_table_attr(image, load_options_size);
 	unsigned long efi_chunk_size = ULONG_MAX;
 	efi_file_protocol_t *volume = NULL;
 	efi_file_protocol_t *file;
@@ -294,7 +296,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
 		while (size) {
 			unsigned long chunksize = min(size, efi_chunk_size);
 
-			status = file->read(file, &chunksize, addr);
+			status = efi_call_proto(file, read, &chunksize, addr);
 			if (status != EFI_SUCCESS) {
 				efi_err("Failed to read file\n");
 				goto err_close_file;
@@ -302,8 +304,8 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
 			addr += chunksize;
 			size -= chunksize;
 		}
-		file->close(file);
-		volume->close(volume);
+		efi_call_proto(file, close);
+		efi_call_proto(volume, close);
 	} while (offset > 0);
 
 	*load_addr = alloc_addr;
@@ -312,10 +314,10 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
 	return EFI_SUCCESS;
 
 err_close_file:
-	file->close(file);
+	efi_call_proto(file, close);
 
 err_close_volume:
-	volume->close(volume);
+	efi_call_proto(volume, close);
 
 err_free_alloc:
 	efi_free(alloc_size, alloc_addr);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 4/4] efi: libstub: Undeprecate the command line initrd loader
  2022-09-27  8:58 [PATCH 0/4] efi: Improve command line initrd loader support Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2022-09-27  8:58 ` [PATCH 3/4] efi: libstub: Add mixed mode support to command line initrd loader Ard Biesheuvel
@ 2022-09-27  8:58 ` Ard Biesheuvel
  3 siblings, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2022-09-27  8:58 UTC (permalink / raw)
  To: linux-efi
  Cc: Ard Biesheuvel, Huacai Chen, Palmer Dabbelt, Jeremy Linton,
	Atish Patra, Lennart Poettering, Ilias Apalodimas

The initrd= command line loader can be useful for development, but it
was limited to loading files from the same file system as the loaded
kernel (and it didn't work on x86 mixed mode).

As both issues have been fixed, and the initrd= can now be used with
files residing on any simply file system exposed by the EFI firmware,
let's permit it to be enabled on RISC-V and LoongArch, which did not
support it up to this point.

Note that LoadFile2 remains the preferred option, as it is much simpler
to use and implement, but generic loaders (including the UEFI shell) may
not implement this so there, initrd= can now be used as well (if enabled
in the build)

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/Kconfig | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 5b79a4a4a88d..4f7e65293297 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -165,13 +165,16 @@ config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
 	bool "Enable the command line initrd loader" if !X86
 	depends on EFI_STUB && (EFI_GENERIC_STUB || X86)
 	default y if X86
-	depends on !RISCV && !LOONGARCH
 	help
 	  Select this config option to add support for the initrd= command
-	  line parameter, allowing an initrd that resides on the same volume
-	  as the kernel image to be loaded into memory.
-
-	  This method is deprecated.
+	  line parameter, allowing an initrd to be loaded into memory that
+	  resides on a file system backed by an implementation of
+	  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.
+
+	  This method has been superseded by the simpler LoadFile2 based
+	  initrd loading method, but the initrd= loader is retained as it
+	  can be used from the UEFI Shell or other generic loaders that
+	  don't implement the Linux specific LoadFile2 method.
 
 config EFI_BOOTLOADER_CONTROL
 	tristate "EFI Bootloader Control"
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-09-27  8:59 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-27  8:58 [PATCH 0/4] efi: Improve command line initrd loader support Ard Biesheuvel
2022-09-27  8:58 ` [PATCH 1/4] efi: libstub: Implement devicepath support for initrd commandline loader Ard Biesheuvel
2022-09-27  8:58 ` [PATCH 2/4] efi: libstub: Permit mixed mode return types other than efi_status_t Ard Biesheuvel
2022-09-27  8:58 ` [PATCH 3/4] efi: libstub: Add mixed mode support to command line initrd loader Ard Biesheuvel
2022-09-27  8:58 ` [PATCH 4/4] efi: libstub: Undeprecate the " Ard Biesheuvel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).