* [PATCH v2 0/6] efi: implement generic compressed boot support
@ 2022-08-09 8:09 Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 1/6] efi: stub: add some missing boot service prototypes Ard Biesheuvel
` (7 more replies)
0 siblings, 8 replies; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 8:09 UTC (permalink / raw)
To: linux-efi
Cc: catalin.marinas, will, Ard Biesheuvel, James E.J. Bottomley,
Matthew Garrett, Peter Jones, Ilias Apalodimas,
Heinrich Schuchardt, AKASHI Takahiro, Palmer Dabbelt, Atish Patra,
Arnd Bergmann, Huacai Chen, Lennart Poettering
Relatively modern architectures such as arm64 or RISC-V don't implement
a self-decompressing kernel, and leave it up to the bootloader to
decompress the compressed image before executing it. For bare metal
boot, this policy makes sense, as a self-decompressing image essentially
duplicates a lot of fiddly preparation work to create a 1:1 mapping and
set up the C runtime, and to discover or infer where DRAM lives from
device trees or other firmware tables.
For EFI boot, the situation is a bit different: the EFI entrypoint is
called with a 1:1 cached mapping covering all of DRAM already active,
and with a stack, a heap, a memory map and boot services to load and
start images. This means it is rather trivial to implement a
self-decompressing wrapper for EFI boot in a generic manner, and reuse
it across architectures that implement EFI boot.
The only slight downside is that when UEFI secure boot is enabled, the
generic LoadImage/StartImage only allow signed images to be loaded and
started, and we prefer to avoid the need to sign both the inner and
outer PE/COFF images. This series adopts the EFI shim approach, i.e., to
override an internal UEFI/PI protocol that is used by the image loader,
to allow the inner image to be booted after decompression. This has been
tested to work with Tianocore based EFI implementations on arm64, but
u-boot will need some interoperability tweaks as well, ideally just a
protocol that exposes a LoadImage/StartImage combo that the decompresor
can use directly to circumvent the signature check. (Note that EFI apps
have full control over the CPU, page tables, etc. so having code that
circumvents authentication checks is not as crazy as it sounds, given
that the app can do anything it pleases already.)
The code is wired up for arm64 and RISC-V. The latter was build tested
only.
Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Peter Jones <pjones@redhat.com>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Atish Patra <atishp@atishpatra.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Huacai Chen <chenhuacai@loongson.cn>
Cc: Lennart Poettering <lennart@poettering.net>
Ard Biesheuvel (6):
efi: stub: add some missing boot service prototypes
efi: stub: split off printk() routines
efi: stub: move efi_system_table global var into separate object
efi: stub: implement generic EFI zboot
arm64: efi: enable generic EFI compressed boot
riscv: efi: enable generic EFI compressed boot
arch/arm64/Makefile | 5 +
arch/arm64/boot/Makefile | 12 ++
arch/riscv/Makefile | 5 +
arch/riscv/boot/Makefile | 14 ++
drivers/firmware/efi/Kconfig | 9 +
drivers/firmware/efi/libstub/Makefile | 7 +-
drivers/firmware/efi/libstub/Makefile.zboot | 30 +++
drivers/firmware/efi/libstub/efi-stub-helper.c | 141 ---------------
drivers/firmware/efi/libstub/efi-stub.c | 2 -
drivers/firmware/efi/libstub/efistub.h | 12 +-
drivers/firmware/efi/libstub/printk.c | 158 ++++++++++++++++
drivers/firmware/efi/libstub/systable.c | 8 +
drivers/firmware/efi/libstub/zboot-header.S | 144 +++++++++++++++
drivers/firmware/efi/libstub/zboot.c | 191 ++++++++++++++++++++
drivers/firmware/efi/libstub/zboot.lds | 41 +++++
include/linux/efi.h | 2 +
16 files changed, 633 insertions(+), 148 deletions(-)
create mode 100644 drivers/firmware/efi/libstub/Makefile.zboot
create mode 100644 drivers/firmware/efi/libstub/printk.c
create mode 100644 drivers/firmware/efi/libstub/systable.c
create mode 100644 drivers/firmware/efi/libstub/zboot-header.S
create mode 100644 drivers/firmware/efi/libstub/zboot.c
create mode 100644 drivers/firmware/efi/libstub/zboot.lds
--
2.35.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 1/6] efi: stub: add some missing boot service prototypes
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
@ 2022-08-09 8:09 ` Ard Biesheuvel
2022-08-09 8:42 ` Heinrich Schuchardt
2022-08-09 8:09 ` [PATCH v2 2/6] efi: stub: split off printk() routines Ard Biesheuvel
` (6 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 8:09 UTC (permalink / raw)
To: linux-efi
Cc: catalin.marinas, will, Ard Biesheuvel, James E.J. Bottomley,
Matthew Garrett, Peter Jones, Ilias Apalodimas,
Heinrich Schuchardt, AKASHI Takahiro, Palmer Dabbelt, Atish Patra,
Arnd Bergmann, Huacai Chen, Lennart Poettering
Define the correct prototypes for the load_image/start_image and
install_multiple_protocol_interfaces boot service pointers so we can
call them from the EFI zboot code.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
drivers/firmware/efi/libstub/efistub.h | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index ab9e990447d3..33215d7bd276 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -254,8 +254,12 @@ union efi_boot_services {
efi_handle_t *);
efi_status_t (__efiapi *install_configuration_table)(efi_guid_t *,
void *);
- void *load_image;
- void *start_image;
+ efi_status_t (__efiapi *load_image)(bool, efi_handle_t,
+ efi_device_path_protocol_t *,
+ void *, unsigned long,
+ efi_handle_t *);
+ efi_status_t (__efiapi *start_image)(efi_handle_t, unsigned long *,
+ efi_char16_t **);
efi_status_t __noreturn (__efiapi *exit)(efi_handle_t,
efi_status_t,
unsigned long,
@@ -277,8 +281,8 @@ union efi_boot_services {
void *locate_handle_buffer;
efi_status_t (__efiapi *locate_protocol)(efi_guid_t *, void *,
void **);
- void *install_multiple_protocol_interfaces;
- void *uninstall_multiple_protocol_interfaces;
+ efi_status_t (__efiapi *install_multiple_protocol_interfaces)(efi_handle_t *, ...);
+ efi_status_t (__efiapi *uninstall_multiple_protocol_interfaces)(efi_handle_t, ...);
void *calculate_crc32;
void *copy_mem;
void *set_mem;
--
2.35.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 2/6] efi: stub: split off printk() routines
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 1/6] efi: stub: add some missing boot service prototypes Ard Biesheuvel
@ 2022-08-09 8:09 ` Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 3/6] efi: stub: move efi_system_table global var into separate object Ard Biesheuvel
` (5 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 8:09 UTC (permalink / raw)
To: linux-efi
Cc: catalin.marinas, will, Ard Biesheuvel, James E.J. Bottomley,
Matthew Garrett, Peter Jones, Ilias Apalodimas,
Heinrich Schuchardt, AKASHI Takahiro, Palmer Dabbelt, Atish Patra,
Arnd Bergmann, Huacai Chen, Lennart Poettering
We will be using the libstub static library also to build the EFI zboot
decompressor, which is a separate binary and does not carry all the
dependencies of efi-stub-helper.c, which is where efi_printk() currently
lives.
So split it off into printk.c so we can incorporate it separately.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
drivers/firmware/efi/libstub/Makefile | 2 +-
drivers/firmware/efi/libstub/efi-stub-helper.c | 141 -----------------
drivers/firmware/efi/libstub/printk.c | 158 ++++++++++++++++++++
3 files changed, 159 insertions(+), 142 deletions(-)
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index d0537573501e..475224be08e1 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -55,7 +55,7 @@ KCOV_INSTRUMENT := n
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
file.o mem.o random.o randomalloc.o pci.o \
skip_spaces.o lib-cmdline.o lib-ctype.o \
- alignedmem.o relocate.o vsprintf.o
+ alignedmem.o relocate.o vsprintf.o printk.o
# include the stub's generic dependencies from lib/ when building for ARM/arm64
efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 3d972061c1b0..45910c834133 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -20,7 +20,6 @@
bool efi_nochunk;
bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
-int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
bool efi_novamap;
static bool efi_noinitrd;
@@ -32,146 +31,6 @@ bool __pure __efi_soft_reserve_enabled(void)
return !efi_nosoftreserve;
}
-/**
- * efi_char16_puts() - Write a UCS-2 encoded string to the console
- * @str: UCS-2 encoded string
- */
-void efi_char16_puts(efi_char16_t *str)
-{
- efi_call_proto(efi_table_attr(efi_system_table, con_out),
- output_string, str);
-}
-
-static
-u32 utf8_to_utf32(const u8 **s8)
-{
- u32 c32;
- u8 c0, cx;
- size_t clen, i;
-
- c0 = cx = *(*s8)++;
- /*
- * The position of the most-significant 0 bit gives us the length of
- * a multi-octet encoding.
- */
- for (clen = 0; cx & 0x80; ++clen)
- cx <<= 1;
- /*
- * If the 0 bit is in position 8, this is a valid single-octet
- * encoding. If the 0 bit is in position 7 or positions 1-3, the
- * encoding is invalid.
- * In either case, we just return the first octet.
- */
- if (clen < 2 || clen > 4)
- return c0;
- /* Get the bits from the first octet. */
- c32 = cx >> clen--;
- for (i = 0; i < clen; ++i) {
- /* Trailing octets must have 10 in most significant bits. */
- cx = (*s8)[i] ^ 0x80;
- if (cx & 0xc0)
- return c0;
- c32 = (c32 << 6) | cx;
- }
- /*
- * Check for validity:
- * - The character must be in the Unicode range.
- * - It must not be a surrogate.
- * - It must be encoded using the correct number of octets.
- */
- if (c32 > 0x10ffff ||
- (c32 & 0xf800) == 0xd800 ||
- clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000))
- return c0;
- *s8 += clen;
- return c32;
-}
-
-/**
- * efi_puts() - Write a UTF-8 encoded string to the console
- * @str: UTF-8 encoded string
- */
-void efi_puts(const char *str)
-{
- efi_char16_t buf[128];
- size_t pos = 0, lim = ARRAY_SIZE(buf);
- const u8 *s8 = (const u8 *)str;
- u32 c32;
-
- while (*s8) {
- if (*s8 == '\n')
- buf[pos++] = L'\r';
- c32 = utf8_to_utf32(&s8);
- if (c32 < 0x10000) {
- /* Characters in plane 0 use a single word. */
- buf[pos++] = c32;
- } else {
- /*
- * Characters in other planes encode into a surrogate
- * pair.
- */
- buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10);
- buf[pos++] = 0xdc00 + (c32 & 0x3ff);
- }
- if (*s8 == '\0' || pos >= lim - 2) {
- buf[pos] = L'\0';
- efi_char16_puts(buf);
- pos = 0;
- }
- }
-}
-
-/**
- * efi_printk() - Print a kernel message
- * @fmt: format string
- *
- * The first letter of the format string is used to determine the logging level
- * of the message. If the level is less then the current EFI logging level, the
- * message is suppressed. The message will be truncated to 255 bytes.
- *
- * Return: number of printed characters
- */
-int efi_printk(const char *fmt, ...)
-{
- char printf_buf[256];
- va_list args;
- int printed;
- int loglevel = printk_get_level(fmt);
-
- switch (loglevel) {
- case '0' ... '9':
- loglevel -= '0';
- break;
- default:
- /*
- * Use loglevel -1 for cases where we just want to print to
- * the screen.
- */
- loglevel = -1;
- break;
- }
-
- if (loglevel >= efi_loglevel)
- return 0;
-
- if (loglevel >= 0)
- efi_puts("EFI stub: ");
-
- fmt = printk_skip_level(fmt);
-
- va_start(args, fmt);
- printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
- va_end(args);
-
- efi_puts(printf_buf);
- if (printed >= sizeof(printf_buf)) {
- efi_puts("[Message truncated]\n");
- return -1;
- }
-
- return printed;
-}
-
/**
* efi_parse_options() - Parse EFI command line options
* @cmdline: kernel command line
diff --git a/drivers/firmware/efi/libstub/printk.c b/drivers/firmware/efi/libstub/printk.c
new file mode 100644
index 000000000000..ec09bf895c1a
--- /dev/null
+++ b/drivers/firmware/efi/libstub/printk.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Helper functions used by the EFI stub on multiple
+ * architectures. This should be #included by the EFI stub
+ * implementation files.
+ *
+ * Copyright 2011 Intel Corporation; author Matt Fleming
+ */
+
+#include <linux/ctype.h>
+#include <linux/efi.h>
+#include <linux/kernel.h>
+#include <linux/printk.h> /* For CONSOLE_LOGLEVEL_* */
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+int efi_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
+
+/**
+ * efi_char16_puts() - Write a UCS-2 encoded string to the console
+ * @str: UCS-2 encoded string
+ */
+void efi_char16_puts(efi_char16_t *str)
+{
+ efi_call_proto(efi_table_attr(efi_system_table, con_out),
+ output_string, str);
+}
+
+static
+u32 utf8_to_utf32(const u8 **s8)
+{
+ u32 c32;
+ u8 c0, cx;
+ size_t clen, i;
+
+ c0 = cx = *(*s8)++;
+ /*
+ * The position of the most-significant 0 bit gives us the length of
+ * a multi-octet encoding.
+ */
+ for (clen = 0; cx & 0x80; ++clen)
+ cx <<= 1;
+ /*
+ * If the 0 bit is in position 8, this is a valid single-octet
+ * encoding. If the 0 bit is in position 7 or positions 1-3, the
+ * encoding is invalid.
+ * In either case, we just return the first octet.
+ */
+ if (clen < 2 || clen > 4)
+ return c0;
+ /* Get the bits from the first octet. */
+ c32 = cx >> clen--;
+ for (i = 0; i < clen; ++i) {
+ /* Trailing octets must have 10 in most significant bits. */
+ cx = (*s8)[i] ^ 0x80;
+ if (cx & 0xc0)
+ return c0;
+ c32 = (c32 << 6) | cx;
+ }
+ /*
+ * Check for validity:
+ * - The character must be in the Unicode range.
+ * - It must not be a surrogate.
+ * - It must be encoded using the correct number of octets.
+ */
+ if (c32 > 0x10ffff ||
+ (c32 & 0xf800) == 0xd800 ||
+ clen != (c32 >= 0x80) + (c32 >= 0x800) + (c32 >= 0x10000))
+ return c0;
+ *s8 += clen;
+ return c32;
+}
+
+/**
+ * efi_puts() - Write a UTF-8 encoded string to the console
+ * @str: UTF-8 encoded string
+ */
+void efi_puts(const char *str)
+{
+ efi_char16_t buf[128];
+ size_t pos = 0, lim = ARRAY_SIZE(buf);
+ const u8 *s8 = (const u8 *)str;
+ u32 c32;
+
+ while (*s8) {
+ if (*s8 == '\n')
+ buf[pos++] = L'\r';
+ c32 = utf8_to_utf32(&s8);
+ if (c32 < 0x10000) {
+ /* Characters in plane 0 use a single word. */
+ buf[pos++] = c32;
+ } else {
+ /*
+ * Characters in other planes encode into a surrogate
+ * pair.
+ */
+ buf[pos++] = (0xd800 - (0x10000 >> 10)) + (c32 >> 10);
+ buf[pos++] = 0xdc00 + (c32 & 0x3ff);
+ }
+ if (*s8 == '\0' || pos >= lim - 2) {
+ buf[pos] = L'\0';
+ efi_char16_puts(buf);
+ pos = 0;
+ }
+ }
+}
+
+/**
+ * efi_printk() - Print a kernel message
+ * @fmt: format string
+ *
+ * The first letter of the format string is used to determine the logging level
+ * of the message. If the level is less then the current EFI logging level, the
+ * message is suppressed. The message will be truncated to 255 bytes.
+ *
+ * Return: number of printed characters
+ */
+int efi_printk(const char *fmt, ...)
+{
+ char printf_buf[256];
+ va_list args;
+ int printed;
+ int loglevel = printk_get_level(fmt);
+
+ switch (loglevel) {
+ case '0' ... '9':
+ loglevel -= '0';
+ break;
+ default:
+ /*
+ * Use loglevel -1 for cases where we just want to print to
+ * the screen.
+ */
+ loglevel = -1;
+ break;
+ }
+
+ if (loglevel >= efi_loglevel)
+ return 0;
+
+ if (loglevel >= 0)
+ efi_puts("EFI stub: ");
+
+ fmt = printk_skip_level(fmt);
+
+ va_start(args, fmt);
+ printed = vsnprintf(printf_buf, sizeof(printf_buf), fmt, args);
+ va_end(args);
+
+ efi_puts(printf_buf);
+ if (printed >= sizeof(printf_buf)) {
+ efi_puts("[Message truncated]\n");
+ return -1;
+ }
+
+ return printed;
+}
--
2.35.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/6] efi: stub: move efi_system_table global var into separate object
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 1/6] efi: stub: add some missing boot service prototypes Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 2/6] efi: stub: split off printk() routines Ard Biesheuvel
@ 2022-08-09 8:09 ` Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 4/6] efi: stub: implement generic EFI zboot Ard Biesheuvel
` (4 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 8:09 UTC (permalink / raw)
To: linux-efi
Cc: catalin.marinas, will, Ard Biesheuvel, James E.J. Bottomley,
Matthew Garrett, Peter Jones, Ilias Apalodimas,
Heinrich Schuchardt, AKASHI Takahiro, Palmer Dabbelt, Atish Patra,
Arnd Bergmann, Huacai Chen, Lennart Poettering
To avoid pulling in the wrong object when using the libstub static
library to build the decompressor, define efi_system_table in a separate
compilation unit.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
drivers/firmware/efi/libstub/Makefile | 3 ++-
drivers/firmware/efi/libstub/efi-stub.c | 2 --
drivers/firmware/efi/libstub/systable.c | 8 ++++++++
3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 475224be08e1..a8e26d5a1d14 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -55,7 +55,8 @@ KCOV_INSTRUMENT := n
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
file.o mem.o random.o randomalloc.o pci.o \
skip_spaces.o lib-cmdline.o lib-ctype.o \
- alignedmem.o relocate.o vsprintf.o printk.o
+ alignedmem.o relocate.o vsprintf.o printk.o \
+ systable.o
# include the stub's generic dependencies from lib/ when building for ARM/arm64
efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index f515394cce6e..ad179632f99f 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -49,8 +49,6 @@
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
static bool flat_va_mapping;
-const efi_system_table_t *efi_system_table;
-
static struct screen_info *setup_graphics(void)
{
efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
diff --git a/drivers/firmware/efi/libstub/systable.c b/drivers/firmware/efi/libstub/systable.c
new file mode 100644
index 000000000000..91d016b02f8c
--- /dev/null
+++ b/drivers/firmware/efi/libstub/systable.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+const efi_system_table_t *efi_system_table;
--
2.35.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 4/6] efi: stub: implement generic EFI zboot
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
` (2 preceding siblings ...)
2022-08-09 8:09 ` [PATCH v2 3/6] efi: stub: move efi_system_table global var into separate object Ard Biesheuvel
@ 2022-08-09 8:09 ` Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 5/6] arm64: efi: enable generic EFI compressed boot Ard Biesheuvel
` (3 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 8:09 UTC (permalink / raw)
To: linux-efi
Cc: catalin.marinas, will, Ard Biesheuvel, James E.J. Bottomley,
Matthew Garrett, Peter Jones, Ilias Apalodimas,
Heinrich Schuchardt, AKASHI Takahiro, Palmer Dabbelt, Atish Patra,
Arnd Bergmann, Huacai Chen, Lennart Poettering
Implement a minimal EFI app that decompresses the real kernel image and
launches it using the firmware's LoadImage and StartImage boot services.
This removes the need for any arch-specific hacks.
Note that on systems that have UEFI secure boot policies enabled,
LoadImage/StartImage require images to be signed, or their hashes known
a priori, in order to be permitted to boot. We adopt the same approach
as the EFI shim used by the distros, which is to override the security
arch protocol implementations used internally by the firmware,
permitting the inner, compressed image to be loaded and started after
decompression. The outer PE/COFF image will be signed as usual in such
cases, preserving the chain of trust.
BZIP2 has been omitted from the set of supported compression algorithms,
given that its performance is mediocre both in speed and size, and it
uses a disproportionate amount of memory. For optimal compression, use
LZMA. For the fastest boot speed, use LZO.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
drivers/firmware/efi/Kconfig | 9 +
drivers/firmware/efi/libstub/Makefile | 4 +
drivers/firmware/efi/libstub/Makefile.zboot | 30 +++
| 144 +++++++++++++++
drivers/firmware/efi/libstub/zboot.c | 191 ++++++++++++++++++++
drivers/firmware/efi/libstub/zboot.lds | 41 +++++
include/linux/efi.h | 2 +
7 files changed, 421 insertions(+)
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 6cb7384ad2ac..9ee0944f80bf 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -105,6 +105,15 @@ config EFI_RUNTIME_WRAPPERS
config EFI_GENERIC_STUB
bool
+config EFI_ZBOOT
+ bool "Enable the generic EFI decompressor"
+ depends on EFI_GENERIC_STUB
+ depends on !ARM && !X86
+ select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_LZ4
+ select HAVE_KERNEL_LZMA
+ select HAVE_KERNEL_LZO
+
config EFI_ARMSTUB_DTB_LOADER
bool "Enable the DTB loader"
depends on EFI_GENERIC_STUB && !RISCV
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index a8e26d5a1d14..721f948950b8 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -112,8 +112,12 @@ STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS
# a verification pass to see if any absolute relocations exist in any of the
# object files.
#
+lib-$(CONFIG_EFI_ZBOOT) += zboot.o
extra-y := $(lib-y)
lib-y := $(patsubst %.o,%.stub.o,$(lib-y))
+lib-$(CONFIG_EFI_ZBOOT) += zboot-header.o
+AFLAGS_zboot-header.o += -DZIMAGE_EFI_PATH="\"$(realpath \
+ $(objtree)/arch/$(ARCH)/boot/zImage.efi.elf)\""
STUBCOPY_FLAGS-$(CONFIG_ARM64) += --prefix-alloc-sections=.init \
--prefix-symbols=__efistub_
diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot
new file mode 100644
index 000000000000..37d95d90db47
--- /dev/null
+++ b/drivers/firmware/efi/libstub/Makefile.zboot
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0
+
+# to be include'd by arch/$(ARCH)/boot/Makefile after setting
+# ZBOOT_PAYLOAD, ZBOOT_BFD_TARGET, ZBOOT_LD_FLAGS and ZBOOT_EXTRA_DEPS
+
+zimage-method-$(CONFIG_KERNEL_GZIP) := gzip
+zimage-method-$(CONFIG_KERNEL_LZ4) := lz4_with_size
+zimage-method-$(CONFIG_KERNEL_LZMA) := lzma_with_size
+zimage-method-$(CONFIG_KERNEL_LZO) := lzo_with_size
+
+$(obj)/zImage: $(ZBOOT_PAYLOAD) FORCE
+ $(call if_changed,$(zimage-method-y))
+
+OBJCOPYFLAGS_zImage.o := -I binary -O $(ZBOOT_BFD_TARGET) \
+ --rename-section .data=.gzdata,load,alloc,readonly,contents
+$(obj)/zImage.o: $(obj)/zImage FORCE
+ $(call if_changed,objcopy)
+
+ZBOOT_DEPS := $(ZBOOT_EXTRA_DEPS) $(objtree)/drivers/firmware/efi/libstub/lib.a
+
+LDFLAGS_zImage.efi.elf := -T $(srctree)/drivers/firmware/efi/libstub/zboot.lds \
+ $(ZBOOT_LD_FLAGS)
+$(obj)/zImage.efi.elf: $(obj)/zImage.o $(ZBOOT_DEPS) FORCE
+ $(call if_changed,ld)
+
+OBJCOPYFLAGS_zImage.efi := -O binary
+$(obj)/zImage.efi: $(obj)/zImage.efi.elf FORCE
+ $(call if_changed,objcopy)
+
+targets += zImage zImage.o zImage.efi.elf zImage.efi
--git a/drivers/firmware/efi/libstub/zboot-header.S b/drivers/firmware/efi/libstub/zboot-header.S
new file mode 100644
index 000000000000..59ede6f253df
--- /dev/null
+++ b/drivers/firmware/efi/libstub/zboot-header.S
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/pe.h>
+
+#if defined(CONFIG_ARM64)
+ .set .Lmachine_type, IMAGE_FILE_MACHINE_ARM64
+#elif defined(CONFIG_RISCV)
+#ifdef CONFIG_64BIT
+ .set .Lmachine_type, IMAGE_FILE_MACHINE_RISCV64
+#else
+ .set .Lmachine_type, IMAGE_FILE_MACHINE_RISCV32
+#endif
+#else
+#error
+#endif
+
+ .section ".head", "a"
+ .globl __efistub_efi_zboot_header
+__efistub_efi_zboot_header:
+.Ldoshdr:
+ .long MZ_MAGIC
+ .org .Ldoshdr + 0x38
+
+ // GRUB wants this on arm64 but doesn't (and shouldn't!) care on other
+ // architectures so let's just put the arm64 magic signature here.
+ .ascii "ARM\x64"
+
+ .long .Lpehdr - .Ldoshdr
+
+.Lpehdr:
+ .long PE_MAGIC
+ .short .Lmachine_type
+ .short .Lsection_count
+ .long 0
+ .long 0
+ .long 0
+ .short .Lsection_table - .Loptional_header
+ .short IMAGE_FILE_DEBUG_STRIPPED | \
+ IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED
+
+.Loptional_header:
+#ifdef CONFIG_64BIT
+ .short PE_OPT_MAGIC_PE32PLUS
+#else
+ .short PE_OPT_MAGIC_PE32
+#endif
+ .byte 0, 0
+ .long _etext - .Lefi_header_end
+ .long __data_size
+ .long 0
+ .long __efistub_efi_zboot_entry - .Ldoshdr
+ .long .Lefi_header_end - .Ldoshdr
+
+#ifdef CONFIG_64BIT
+ .quad 0
+#else
+ .long _etext - .Lhead
+ .long 0
+#endif
+ .long 4096
+ .long 512
+ .short 0, 0, 0, 0, 0, 0
+ .long 0
+ .long _end - .Ldoshdr
+
+ .long .Lefi_header_end - .Ldoshdr
+ .long 0
+ .short IMAGE_SUBSYSTEM_EFI_APPLICATION
+ .short 0
+ .quad 0, 0, 0, 0
+ .long 0
+ .long (.Lsection_table - .) / 8
+
+ .quad 0 // ExportTable
+ .quad 0 // ImportTable
+ .quad 0 // ResourceTable
+ .quad 0 // ExceptionTable
+ .quad 0 // CertificationTable
+ .quad 0 // BaseRelocationTable
+#ifdef CONFIG_DEBUG_EFI
+ .long .Lefi_debug_table - .Ldoshdr // DebugTable
+ .long .Lefi_debug_table_size
+#endif
+
+.Lsection_table:
+ .ascii ".text\0\0\0"
+ .long _etext - .Lefi_header_end
+ .long .Lefi_header_end - .Ldoshdr
+ .long _etext - .Lefi_header_end
+ .long .Lefi_header_end - .Ldoshdr
+
+ .long 0, 0
+ .short 0, 0
+ .long IMAGE_SCN_CNT_CODE | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_EXECUTE
+
+ .ascii ".data\0\0\0"
+ .long __data_size
+ .long _etext - .Ldoshdr
+ .long __data_rawsize
+ .long _etext - .Ldoshdr
+
+ .long 0, 0
+ .short 0, 0
+ .long IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_WRITE
+
+ .set .Lsection_count, (. - .Lsection_table) / 40
+
+#ifdef CONFIG_DEBUG_EFI
+ .section ".rodata", "a"
+ .align 2
+.Lefi_debug_table:
+ // EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
+ .long 0 // Characteristics
+ .long 0 // TimeDateStamp
+ .short 0 // MajorVersion
+ .short 0 // MinorVersion
+ .long IMAGE_DEBUG_TYPE_CODEVIEW // Type
+ .long .Lefi_debug_entry_size // SizeOfData
+ .long 0 // RVA
+ .long .Lefi_debug_entry - .Ldoshdr // FileOffset
+
+ .set .Lefi_debug_table_size, . - .Lefi_debug_table
+ .previous
+
+.Lefi_debug_entry:
+ // EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
+ .ascii "NB10" // Signature
+ .long 0 // Unknown
+ .long 0 // Unknown2
+ .long 0 // Unknown3
+
+ .asciz ZIMAGE_EFI_PATH
+
+ .set .Lefi_debug_entry_size, . - .Lefi_debug_entry
+#endif
+
+ .p2align 12
+.Lefi_header_end:
+
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
new file mode 100644
index 000000000000..31868b74d152
--- /dev/null
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <linux/pe.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+#define STATIC static
+
+static unsigned char zboot_heap[SZ_64K] __aligned(64);
+static unsigned long free_mem_ptr, free_mem_end_ptr;
+
+#if defined(CONFIG_KERNEL_GZIP)
+#include "../../../../lib/decompress_inflate.c"
+#elif defined(CONFIG_KERNEL_LZ4)
+#include "../../../../lib/decompress_unlz4.c"
+#elif defined(CONFIG_KERNEL_LZMA)
+#include "../../../../lib/decompress_unlzma.c"
+#elif defined(CONFIG_KERNEL_LZO)
+#include "../../../../lib/decompress_unlzo.c"
+#endif
+
+extern char _gzdata_start[], _gzdata_end[];
+extern u32 uncompressed_size __aligned(1);
+
+typedef struct efi_security_arch_protocol efi_security_arch_protocol_t;
+
+typedef efi_status_t
+(* __efiapi file_auth_state_fn)(efi_security_arch_protocol_t *,
+ u32, efi_device_path_protocol_t *);
+
+struct efi_security_arch_protocol {
+ file_auth_state_fn file_auth_state;
+};
+
+
+typedef struct efi_security_arch2_protocol efi_security_arch2_protocol_t;
+
+typedef efi_status_t
+(* __efiapi file_auth_fn)(efi_security_arch2_protocol_t *,
+ efi_device_path_protocol_t *,
+ void *, unsigned long, bool);
+
+struct efi_security_arch2_protocol {
+ file_auth_fn file_auth;
+};
+
+static file_auth_state_fn prev_file_auth_state;
+static file_auth_fn prev_file_auth;
+
+static efi_status_t __efiapi
+file_auth_state_override(efi_security_arch_protocol_t *this,
+ u32 auth_state,
+ efi_device_path_protocol_t *file)
+{
+ prev_file_auth_state(this, auth_state, file);
+ return EFI_SUCCESS;
+}
+
+static efi_status_t __efiapi
+file_auth_override(efi_security_arch2_protocol_t *this,
+ efi_device_path_protocol_t *file,
+ void *file_buffer, unsigned long file_size,
+ bool boot_policy)
+{
+ prev_file_auth(this, file, file_buffer, file_size, boot_policy);
+ return EFI_SUCCESS;
+}
+
+static void error(char *x)
+{
+ efi_err("%s\n", x);
+}
+
+efi_status_t __efiapi efi_zboot_entry(efi_handle_t handle,
+ efi_system_table_t *systab)
+{
+ efi_guid_t security_arch = EFI_SECURITY_ARCH_PROTOCOL_GUID;
+ efi_guid_t security_arch2 = EFI_SECURITY_ARCH2_PROTOCOL_GUID;
+ efi_guid_t loaded_image = LOADED_IMAGE_PROTOCOL_GUID;
+ struct efi_security_arch_protocol *sec_proto = NULL;
+ struct efi_security_arch2_protocol *sec2_proto = NULL;
+ efi_loaded_image_t *parent, *child;
+ efi_handle_t child_handle = NULL;
+ unsigned long image_buffer;
+ efi_status_t status;
+ int ret;
+
+ free_mem_ptr = (unsigned long)&zboot_heap;
+ free_mem_end_ptr = free_mem_ptr + sizeof(zboot_heap);
+
+ efi_system_table = systab;
+
+ efi_info("Entering EFI decompressor\n");
+
+ status = efi_bs_call(handle_protocol, handle, &loaded_image,
+ (void **)&parent);
+ if (status != EFI_SUCCESS) {
+ efi_err("Failed to locate parent's loaded image protocol\n");
+ return status;
+ }
+
+ status = efi_allocate_pages(uncompressed_size, &image_buffer, ULONG_MAX);
+ if (status != EFI_SUCCESS) {
+ efi_err("Failed to allocate memory\n");
+ return status;
+ }
+
+ ret = __decompress(_gzdata_start, _gzdata_end - _gzdata_start, NULL,
+ NULL, (unsigned char *)image_buffer, 0, NULL,
+ error);
+ if (ret < 0) {
+ efi_err("Decompression failed (ret == %d)\n", ret);
+ return EFI_LOAD_ERROR;
+ }
+
+ //
+ // This is where it becomes slightly nasty: when UEFI secure boot
+ // policies are in effect, LoadImage() and StartImage() will reject
+ // unsigned images, in a slightly peculiar and inconsistent way:
+ // Tiancore's reference implementation will return
+ // EFI_SECURITY_VIOLATION from LoadImage() if authentication fails, but
+ // will not unload the image from memory, potentially allowing the
+ // image to be invoked anyway, by branching to the right offset in the
+ // image. Other implementations exist that deviate from this behavior,
+ // and return a fatal error from LoadImage() that does not allow the
+ // above workaround. In any case, StartImage() only permits starting
+ // images for which LoadImage() returned EFI_SUCCESS.
+ //
+ // Let's take the shim approach here, and manipulate the underlying
+ // protocol that performs the file authentication. That way, we should
+ // be able to rely on LoadImage/StartImage on all firmware built from
+ // Tianocore or derived from it, without dealing with the individual
+ // quirks. For non-EDK2 based implementations, we really need some kind
+ // of protocol that can start an image after the signature check has
+ // failed.
+ //
+
+ // TODO the protocols below are defined in the PI spec and interoperate
+ // with the DXE foundation, which EFI firmware may not implement. So we
+ // need to define a protocol that the firmware will invoke which allows
+ // us to indicate that the image we are loading should be permitted
+ // regardless of secure boot restrictions.
+
+ status = efi_bs_call(locate_protocol, &security_arch, NULL,
+ (void **)&sec_proto);
+ if (status == EFI_SUCCESS) {
+ prev_file_auth_state = sec_proto->file_auth_state;
+ sec_proto->file_auth_state = file_auth_state_override;
+ }
+
+ status = efi_bs_call(locate_protocol, &security_arch2, NULL,
+ (void **)&sec2_proto);
+ if (status == EFI_SUCCESS) {
+ prev_file_auth = sec2_proto->file_auth;
+ sec2_proto->file_auth = file_auth_override;
+ }
+
+ status = efi_bs_call(load_image, true, handle, NULL,
+ (void *)image_buffer, uncompressed_size,
+ &child_handle);
+ if (status != EFI_SUCCESS) {
+ efi_err("Failed to load image: %lx\n", status);
+ return status;
+ }
+
+ status = efi_bs_call(handle_protocol, child_handle, &loaded_image,
+ (void **)&child);
+ if (status != EFI_SUCCESS) {
+ efi_err("Failed to locate child's loaded image protocol\n");
+ return status;
+ }
+
+ // Copy the kernel command line
+ child->load_options = parent->load_options;
+ child->load_options_size = parent->load_options_size;
+
+ status = efi_bs_call(start_image, child_handle, NULL, NULL);
+ if (status != EFI_SUCCESS) {
+ efi_err("StartImage() return with error: %lx\n", status);
+ return status;
+ }
+
+ if (sec_proto != NULL)
+ sec_proto->file_auth_state = prev_file_auth_state;
+ if (sec2_proto != NULL)
+ sec2_proto->file_auth = prev_file_auth;
+
+ return EFI_SUCCESS;
+}
diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds
new file mode 100644
index 000000000000..f7721b2c1e0e
--- /dev/null
+++ b/drivers/firmware/efi/libstub/zboot.lds
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+ENTRY(__efistub_efi_zboot_header);
+
+SECTIONS
+{
+ .text : ALIGN(4096) {
+ *(.head)
+ *(.text* .init.text*)
+ }
+
+ .rodata : ALIGN(8) {
+ __efistub__gzdata_start = .;
+ *(.gzdata)
+ __efistub__gzdata_end = .;
+ *(.rodata* .init.rodata* .srodata*)
+ _etext = ALIGN(4096);
+ . = _etext;
+ }
+
+ .data : ALIGN(4096) {
+ *(.data* .init.data*)
+ _edata = ALIGN(512);
+ . = _edata;
+ }
+
+ .bss : {
+ *(.bss* .init.bss*)
+ _end = ALIGN(512);
+ . = _end;
+ }
+
+ /DISCARD/ : {
+ *(__ksymtab_strings ___ksymtab+*)
+ }
+}
+
+PROVIDE(__efistub_uncompressed_size = __efistub__gzdata_end - 4);
+
+PROVIDE(__data_rawsize = ABSOLUTE(_edata - _etext));
+PROVIDE(__data_size = ABSOLUTE(_end - _etext));
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 75f16e9bc0c0..07f17e2c5f69 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -387,6 +387,8 @@ void efi_native_runtime_setup(void);
#define EFI_RT_PROPERTIES_TABLE_GUID EFI_GUID(0xeb66918a, 0x7eef, 0x402a, 0x84, 0x2e, 0x93, 0x1d, 0x21, 0xc3, 0x8a, 0xe9)
#define EFI_DXE_SERVICES_TABLE_GUID EFI_GUID(0x05ad34ba, 0x6f02, 0x4214, 0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9)
+#define EFI_SECURITY_ARCH_PROTOCOL_GUID EFI_GUID(0xA46423E3, 0x4617, 0x49f1, 0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39)
+#define EFI_SECURITY_ARCH2_PROTOCOL_GUID EFI_GUID(0x94ab2f58, 0x1438, 0x4ef1, 0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68)
#define EFI_IMAGE_SECURITY_DATABASE_GUID EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
#define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
--
2.35.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 5/6] arm64: efi: enable generic EFI compressed boot
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
` (3 preceding siblings ...)
2022-08-09 8:09 ` [PATCH v2 4/6] efi: stub: implement generic EFI zboot Ard Biesheuvel
@ 2022-08-09 8:09 ` Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 6/6] riscv: " Ard Biesheuvel
` (2 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 8:09 UTC (permalink / raw)
To: linux-efi
Cc: catalin.marinas, will, Ard Biesheuvel, James E.J. Bottomley,
Matthew Garrett, Peter Jones, Ilias Apalodimas,
Heinrich Schuchardt, AKASHI Takahiro, Palmer Dabbelt, Atish Patra,
Arnd Bergmann, Huacai Chen, Lennart Poettering
Wire up the generic EFI zboot support for arm64.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/arm64/Makefile | 5 +++++
arch/arm64/boot/Makefile | 12 ++++++++++++
2 files changed, 17 insertions(+)
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 6d9d4a58b898..ad4f849b91e8 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -162,6 +162,11 @@ Image: vmlinux
Image.%: Image
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+ifneq ($(CONFIG_EFI_ZBOOT),)
+zImage.efi: Image
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+endif
+
install: KBUILD_IMAGE := $(boot)/Image
install zinstall:
$(call cmd,install)
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index a0e3dedd2883..08fcd39ae808 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -38,3 +38,15 @@ $(obj)/Image.lzo: $(obj)/Image FORCE
$(obj)/Image.zst: $(obj)/Image FORCE
$(call if_changed,zstd)
+
+ZBOOT_PAYLOAD := $(obj)/Image
+ZBOOT_BFD_TARGET := elf64-littleaarch64
+ZBOOT_LD_FLAGS := --defsym=__efistub_strnlen=__pi_strnlen \
+ --defsym=__efistub_memmove=__pi_memmove \
+ --defsym=__efistub_memcpy=__pi_memcpy \
+ --defsym=__efistub_memset=__pi_memset
+
+ZBOOT_EXTRA_OBJS := memcpy.o memset.o strnlen.o
+ZBOOT_EXTRA_DEPS := $(addprefix $(objtree)/arch/arm64/lib/,$(ZBOOT_EXTRA_OBJS))
+
+include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot
--
2.35.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 6/6] riscv: efi: enable generic EFI compressed boot
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
` (4 preceding siblings ...)
2022-08-09 8:09 ` [PATCH v2 5/6] arm64: efi: enable generic EFI compressed boot Ard Biesheuvel
@ 2022-08-09 8:09 ` Ard Biesheuvel
2022-09-12 14:26 ` Palmer Dabbelt
2022-08-09 8:38 ` [PATCH v2 0/6] efi: implement generic compressed boot support Heinrich Schuchardt
2022-08-09 8:47 ` Matthew Garrett
7 siblings, 1 reply; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 8:09 UTC (permalink / raw)
To: linux-efi
Cc: catalin.marinas, will, Ard Biesheuvel, James E.J. Bottomley,
Matthew Garrett, Peter Jones, Ilias Apalodimas,
Heinrich Schuchardt, AKASHI Takahiro, Palmer Dabbelt, Atish Patra,
Arnd Bergmann, Huacai Chen, Lennart Poettering
Wire up the generic EFI zboot support for RISC-V.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/riscv/Makefile | 5 +++++
arch/riscv/boot/Makefile | 14 ++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 81029d40a672..c30ea65ec877 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -142,6 +142,11 @@ $(BOOT_TARGETS): vmlinux
Image.%: Image
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+ifneq ($(CONFIG_EFI_ZBOOT),)
+zImage.efi: Image
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+endif
+
install: KBUILD_IMAGE := $(boot)/Image
zinstall: KBUILD_IMAGE := $(boot)/Image.gz
install zinstall:
diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile
index becd0621071c..60cd319685ea 100644
--- a/arch/riscv/boot/Makefile
+++ b/arch/riscv/boot/Makefile
@@ -58,3 +58,17 @@ $(obj)/Image.lzo: $(obj)/Image FORCE
$(obj)/loader.bin: $(obj)/loader FORCE
$(call if_changed,objcopy)
+
+ZBOOT_PAYLOAD := $(obj)/Image
+ZBOOT_BFD_TARGET := elf$(BITS)-littleriscv
+ZBOOT_LD_FLAGS := --defsym=__efistub_strnlen=strnlen \
+ --defsym=__efistub_memmove=memmove \
+ --defsym=__efistub_memcpy=memcpy \
+ --defsym=__efistub_memset=memset
+
+ZBOOT_EXTRA_OBJS := memcpy.o memset.o memmove.o
+ZBOOT_EXTRA_DEPS := $(objtree)/lib/string.o \
+ $(objtree)/lib/ctype.o \
+ $(addprefix $(objtree)/arch/riscv/lib/,$(ZBOOT_EXTRA_OBJS))
+
+include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot
--
2.35.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2 0/6] efi: implement generic compressed boot support
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
` (5 preceding siblings ...)
2022-08-09 8:09 ` [PATCH v2 6/6] riscv: " Ard Biesheuvel
@ 2022-08-09 8:38 ` Heinrich Schuchardt
2022-08-09 8:46 ` Ard Biesheuvel
2022-08-09 8:47 ` Matthew Garrett
7 siblings, 1 reply; 14+ messages in thread
From: Heinrich Schuchardt @ 2022-08-09 8:38 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: catalin.marinas, will, James E.J. Bottomley, Matthew Garrett,
Peter Jones, Ilias Apalodimas, AKASHI Takahiro, Palmer Dabbelt,
Atish Patra, Arnd Bergmann, Huacai Chen, Lennart Poettering,
linux-efi
On 8/9/22 10:09, Ard Biesheuvel wrote:
> Relatively modern architectures such as arm64 or RISC-V don't implement
> a self-decompressing kernel, and leave it up to the bootloader to
> decompress the compressed image before executing it. For bare metal
> boot, this policy makes sense, as a self-decompressing image essentially
> duplicates a lot of fiddly preparation work to create a 1:1 mapping and
> set up the C runtime, and to discover or infer where DRAM lives from
> device trees or other firmware tables.
>
> For EFI boot, the situation is a bit different: the EFI entrypoint is
> called with a 1:1 cached mapping covering all of DRAM already active,
> and with a stack, a heap, a memory map and boot services to load and
> start images. This means it is rather trivial to implement a
> self-decompressing wrapper for EFI boot in a generic manner, and reuse
> it across architectures that implement EFI boot.
>
> The only slight downside is that when UEFI secure boot is enabled, the
> generic LoadImage/StartImage only allow signed images to be loaded and
> started, and we prefer to avoid the need to sign both the inner and
> outer PE/COFF images. This series adopts the EFI shim approach, i.e., to
> override an internal UEFI/PI protocol that is used by the image loader,
> to allow the inner image to be booted after decompression. This has been
We should avoid requiring anything that is not in the UEFI
specification. If you have any additional requirements, please, create a
change request for the UEFI specification.
Overriding the services of the system table is dangerous and should be
avoided.
There is no need for two UEFI binaries one inside the other and we
should avoid such overengineering.
Today we append an uncompressed kernel to the EFI stub. The stub
relocates it, sets up the memory map and calls it entry point.
Just add decompressor code to the EFI stub and instead of appending an
uncompressed kernel append a compressed one. Then sign a binary
consisting of the EFI stub and the compressed kernel.
This way you don't need any change to UEFI firmware at all and you don't
need to override UEFI services.
Another reasonable approach would be to zip the signed UEFI binary (EFI
stub with uncompressed kernel) and let the UEFI firmware unzip it and
check the signature of the decompressed UEFI binary. This would not
require any patch in Linux at all and would be simple to implement in
U-Boot.
Best regards
Heinrich
> tested to work with Tianocore based EFI implementations on arm64, but
> u-boot will need some interoperability tweaks as well, ideally just a
> protocol that exposes a LoadImage/StartImage combo that the decompresor
> can use directly to circumvent the signature check. (Note that EFI apps
> have full control over the CPU, page tables, etc. so having code that
> circumvents authentication checks is not as crazy as it sounds, given
> that the app can do anything it pleases already.)
>
> The code is wired up for arm64 and RISC-V. The latter was build tested
> only.
>
> Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
> Cc: Matthew Garrett <mjg59@srcf.ucam.org>
> Cc: Peter Jones <pjones@redhat.com>
> Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> Cc: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Cc: Palmer Dabbelt <palmer@dabbelt.com>
> Cc: Atish Patra <atishp@atishpatra.org>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Huacai Chen <chenhuacai@loongson.cn>
> Cc: Lennart Poettering <lennart@poettering.net>
>
> Ard Biesheuvel (6):
> efi: stub: add some missing boot service prototypes
> efi: stub: split off printk() routines
> efi: stub: move efi_system_table global var into separate object
> efi: stub: implement generic EFI zboot
> arm64: efi: enable generic EFI compressed boot
> riscv: efi: enable generic EFI compressed boot
>
> arch/arm64/Makefile | 5 +
> arch/arm64/boot/Makefile | 12 ++
> arch/riscv/Makefile | 5 +
> arch/riscv/boot/Makefile | 14 ++
> drivers/firmware/efi/Kconfig | 9 +
> drivers/firmware/efi/libstub/Makefile | 7 +-
> drivers/firmware/efi/libstub/Makefile.zboot | 30 +++
> drivers/firmware/efi/libstub/efi-stub-helper.c | 141 ---------------
> drivers/firmware/efi/libstub/efi-stub.c | 2 -
> drivers/firmware/efi/libstub/efistub.h | 12 +-
> drivers/firmware/efi/libstub/printk.c | 158 ++++++++++++++++
> drivers/firmware/efi/libstub/systable.c | 8 +
> drivers/firmware/efi/libstub/zboot-header.S | 144 +++++++++++++++
> drivers/firmware/efi/libstub/zboot.c | 191 ++++++++++++++++++++
> drivers/firmware/efi/libstub/zboot.lds | 41 +++++
> include/linux/efi.h | 2 +
> 16 files changed, 633 insertions(+), 148 deletions(-)
> create mode 100644 drivers/firmware/efi/libstub/Makefile.zboot
> create mode 100644 drivers/firmware/efi/libstub/printk.c
> create mode 100644 drivers/firmware/efi/libstub/systable.c
> create mode 100644 drivers/firmware/efi/libstub/zboot-header.S
> create mode 100644 drivers/firmware/efi/libstub/zboot.c
> create mode 100644 drivers/firmware/efi/libstub/zboot.lds
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 1/6] efi: stub: add some missing boot service prototypes
2022-08-09 8:09 ` [PATCH v2 1/6] efi: stub: add some missing boot service prototypes Ard Biesheuvel
@ 2022-08-09 8:42 ` Heinrich Schuchardt
0 siblings, 0 replies; 14+ messages in thread
From: Heinrich Schuchardt @ 2022-08-09 8:42 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: catalin.marinas, will, James E.J. Bottomley, Matthew Garrett,
Peter Jones, Ilias Apalodimas, AKASHI Takahiro, Palmer Dabbelt,
Atish Patra, Arnd Bergmann, Huacai Chen, Lennart Poettering,
linux-efi
On 8/9/22 10:09, Ard Biesheuvel wrote:
> Define the correct prototypes for the load_image/start_image and
> install_multiple_protocol_interfaces boot service pointers so we can
> call them from the EFI zboot code.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> ---
> drivers/firmware/efi/libstub/efistub.h | 12 ++++++++----
> 1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
> index ab9e990447d3..33215d7bd276 100644
> --- a/drivers/firmware/efi/libstub/efistub.h
> +++ b/drivers/firmware/efi/libstub/efistub.h
> @@ -254,8 +254,12 @@ union efi_boot_services {
> efi_handle_t *);
> efi_status_t (__efiapi *install_configuration_table)(efi_guid_t *,
> void *);
> - void *load_image;
> - void *start_image;
> + efi_status_t (__efiapi *load_image)(bool, efi_handle_t,
> + efi_device_path_protocol_t *,
> + void *, unsigned long,
> + efi_handle_t *);
> + efi_status_t (__efiapi *start_image)(efi_handle_t, unsigned long *,
> + efi_char16_t **);
> efi_status_t __noreturn (__efiapi *exit)(efi_handle_t,
> efi_status_t,
> unsigned long,
> @@ -277,8 +281,8 @@ union efi_boot_services {
> void *locate_handle_buffer;
> efi_status_t (__efiapi *locate_protocol)(efi_guid_t *, void *,
> void **);
> - void *install_multiple_protocol_interfaces;
> - void *uninstall_multiple_protocol_interfaces;
> + efi_status_t (__efiapi *install_multiple_protocol_interfaces)(efi_handle_t *, ...);
> + efi_status_t (__efiapi *uninstall_multiple_protocol_interfaces)(efi_handle_t, ...);
> void *calculate_crc32;
> void *copy_mem;
> void *set_mem;
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 0/6] efi: implement generic compressed boot support
2022-08-09 8:38 ` [PATCH v2 0/6] efi: implement generic compressed boot support Heinrich Schuchardt
@ 2022-08-09 8:46 ` Ard Biesheuvel
2022-08-09 9:03 ` Heinrich Schuchardt
0 siblings, 1 reply; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 8:46 UTC (permalink / raw)
To: Heinrich Schuchardt
Cc: catalin.marinas, will, James E.J. Bottomley, Matthew Garrett,
Peter Jones, Ilias Apalodimas, AKASHI Takahiro, Palmer Dabbelt,
Atish Patra, Arnd Bergmann, Huacai Chen, Lennart Poettering,
linux-efi
On Tue, 9 Aug 2022 at 10:38, Heinrich Schuchardt
<heinrich.schuchardt@canonical.com> wrote:
>
> On 8/9/22 10:09, Ard Biesheuvel wrote:
> > Relatively modern architectures such as arm64 or RISC-V don't implement
> > a self-decompressing kernel, and leave it up to the bootloader to
> > decompress the compressed image before executing it. For bare metal
> > boot, this policy makes sense, as a self-decompressing image essentially
> > duplicates a lot of fiddly preparation work to create a 1:1 mapping and
> > set up the C runtime, and to discover or infer where DRAM lives from
> > device trees or other firmware tables.
> >
> > For EFI boot, the situation is a bit different: the EFI entrypoint is
> > called with a 1:1 cached mapping covering all of DRAM already active,
> > and with a stack, a heap, a memory map and boot services to load and
> > start images. This means it is rather trivial to implement a
> > self-decompressing wrapper for EFI boot in a generic manner, and reuse
> > it across architectures that implement EFI boot.
> >
> > The only slight downside is that when UEFI secure boot is enabled, the
> > generic LoadImage/StartImage only allow signed images to be loaded and
> > started, and we prefer to avoid the need to sign both the inner and
> > outer PE/COFF images. This series adopts the EFI shim approach, i.e., to
> > override an internal UEFI/PI protocol that is used by the image loader,
> > to allow the inner image to be booted after decompression. This has been
>
> We should avoid requiring anything that is not in the UEFI
> specification. If you have any additional requirements, please, create a
> change request for the UEFI specification.
>
As I have explained numerous times before, the EFI spec was intended
to be extensible (hence the 'E'). The ACPI, SMBIOS and TCG specs all
augment the EFI specification by defining protocols, GUIDs and other
things that are only relevant in a EFI context, but none of those are
covered by the EFI spec itself.
> Overriding the services of the system table is dangerous and should be
> avoided.
>
Agreed. But this is not what is happening here.
> There is no need for two UEFI binaries one inside the other and we
> should avoid such overengineering.
>
I disagree. Using an EFI app to encapsulate another one is the only
generic way to go about this, as far as I can tell.
> Today we append an uncompressed kernel to the EFI stub. The stub
> relocates it, sets up the memory map and calls it entry point.
>
Not exactly. On arm64 as well as RISC-V, the EFI stub and the kernel
proper are essentially the same executable image.
> Just add decompressor code to the EFI stub and instead of appending an
> uncompressed kernel append a compressed one. Then sign a binary
> consisting of the EFI stub and the compressed kernel.
>
Yes, this would be a cleaner approach, although it would require more
re-engineering of the EFI stub, in particular, it would require
cloning more code, and adding additional build and link steps.
> This way you don't need any change to UEFI firmware at all and you don't
> need to override UEFI services.
>
> Another reasonable approach would be to zip the signed UEFI binary (EFI
> stub with uncompressed kernel) and let the UEFI firmware unzip it and
> check the signature of the decompressed UEFI binary. This would not
> require any patch in Linux at all and would be simple to implement in
> U-Boot.
>
This is how it works today. One problem with this is that the image
needs to be decompressed in order to sign it, or verify its signature.
In general, having compression at the outside like this is fiddly
because it is no longer a PE/COFF image, and the EFI spec only reasons
about PE/COFF images as executable images. So we'd need to change the
UEFI spec or the PE/COFF spec.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 0/6] efi: implement generic compressed boot support
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
` (6 preceding siblings ...)
2022-08-09 8:38 ` [PATCH v2 0/6] efi: implement generic compressed boot support Heinrich Schuchardt
@ 2022-08-09 8:47 ` Matthew Garrett
7 siblings, 0 replies; 14+ messages in thread
From: Matthew Garrett @ 2022-08-09 8:47 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-efi, catalin.marinas, will, James E.J. Bottomley,
Peter Jones, Ilias Apalodimas, Heinrich Schuchardt,
AKASHI Takahiro, Palmer Dabbelt, Atish Patra, Arnd Bergmann,
Huacai Chen, Lennart Poettering
On Tue, Aug 09, 2022 at 10:09:38AM +0200, Ard Biesheuvel wrote:
> The only slight downside is that when UEFI secure boot is enabled, the
> generic LoadImage/StartImage only allow signed images to be loaded and
> started, and we prefer to avoid the need to sign both the inner and
> outer PE/COFF images. This series adopts the EFI shim approach, i.e., to
> override an internal UEFI/PI protocol that is used by the image loader,
> to allow the inner image to be booted after decompression. This has been
> tested to work with Tianocore based EFI implementations on arm64, but
> u-boot will need some interoperability tweaks as well, ideally just a
> protocol that exposes a LoadImage/StartImage combo that the decompresor
> can use directly to circumvent the signature check. (Note that EFI apps
> have full control over the CPU, page tables, etc. so having code that
> circumvents authentication checks is not as crazy as it sounds, given
> that the app can do anything it pleases already.)
I think it's worth mentioning that Shim doesn't do this by default
because it's not guaranteed that something implementing the UEFI DXE
layer also implements the PI layer. I don't have an objection to it
being an expectation on any Linux-supporting platform that the
implementation works this way, but it should maybe be made clear that
this could unexpectedly fail on generic platforms.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 0/6] efi: implement generic compressed boot support
2022-08-09 8:46 ` Ard Biesheuvel
@ 2022-08-09 9:03 ` Heinrich Schuchardt
2022-08-09 9:10 ` Ard Biesheuvel
0 siblings, 1 reply; 14+ messages in thread
From: Heinrich Schuchardt @ 2022-08-09 9:03 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: catalin.marinas, will, James E.J. Bottomley, Matthew Garrett,
Peter Jones, Ilias Apalodimas, AKASHI Takahiro, Palmer Dabbelt,
Atish Patra, Arnd Bergmann, Huacai Chen, Lennart Poettering,
linux-efi
On 8/9/22 10:46, Ard Biesheuvel wrote:
> On Tue, 9 Aug 2022 at 10:38, Heinrich Schuchardt
> <heinrich.schuchardt@canonical.com> wrote:
>>
>> On 8/9/22 10:09, Ard Biesheuvel wrote:
>>> Relatively modern architectures such as arm64 or RISC-V don't implement
>>> a self-decompressing kernel, and leave it up to the bootloader to
>>> decompress the compressed image before executing it. For bare metal
>>> boot, this policy makes sense, as a self-decompressing image essentially
>>> duplicates a lot of fiddly preparation work to create a 1:1 mapping and
>>> set up the C runtime, and to discover or infer where DRAM lives from
>>> device trees or other firmware tables.
>>>
>>> For EFI boot, the situation is a bit different: the EFI entrypoint is
>>> called with a 1:1 cached mapping covering all of DRAM already active,
>>> and with a stack, a heap, a memory map and boot services to load and
>>> start images. This means it is rather trivial to implement a
>>> self-decompressing wrapper for EFI boot in a generic manner, and reuse
>>> it across architectures that implement EFI boot.
>>>
>>> The only slight downside is that when UEFI secure boot is enabled, the
>>> generic LoadImage/StartImage only allow signed images to be loaded and
>>> started, and we prefer to avoid the need to sign both the inner and
>>> outer PE/COFF images. This series adopts the EFI shim approach, i.e., to
>>> override an internal UEFI/PI protocol that is used by the image loader,
>>> to allow the inner image to be booted after decompression. This has been
>>
>> We should avoid requiring anything that is not in the UEFI
>> specification. If you have any additional requirements, please, create a
>> change request for the UEFI specification.
>>
>
> As I have explained numerous times before, the EFI spec was intended
> to be extensible (hence the 'E'). The ACPI, SMBIOS and TCG specs all
> augment the EFI specification by defining protocols, GUIDs and other
> things that are only relevant in a EFI context, but none of those are
> covered by the EFI spec itself.
>
>> Overriding the services of the system table is dangerous and should be
>> avoided.
>>
>
> Agreed. But this is not what is happening here.
>
>> There is no need for two UEFI binaries one inside the other and we
>> should avoid such overengineering.
>>
>
> I disagree. Using an EFI app to encapsulate another one is the only
> generic way to go about this, as far as I can tell.
Please, elaborate why the inner compressed binary needs to be UEFI to
boot into Linux while currently we don't need a an uncompressed inner
UEFI binary.
>
>> Today we append an uncompressed kernel to the EFI stub. The stub
>> relocates it, sets up the memory map and calls it entry point.
>>
>
> Not exactly. On arm64 as well as RISC-V, the EFI stub and the kernel
> proper are essentially the same executable image.
Currently on ARM and RISC-V you have a file with two entry points:
* EFI stub
* legacy entry point
The EFI stub calls the legacy entry point. In the EFI case some part of
the EFI stub lives on at runtime. The same pointers passed to the legacy
entry point could also be passed to a decompressed legacy kernel.
The EFI stub and the kernel should be completely separate binaries. Then
you just need the cp command to join them.
>
>> Just add decompressor code to the EFI stub and instead of appending an
>> uncompressed kernel append a compressed one. Then sign a binary
>> consisting of the EFI stub and the compressed kernel.
>>
>
> Yes, this would be a cleaner approach, although it would require more
> re-engineering of the EFI stub, in particular, it would require
> cloning more code, and adding additional build and link steps.
If this is the cleanest approach, we should go for it.
Best regards
Heinrich
>
>> This way you don't need any change to UEFI firmware at all and you don't
>> need to override UEFI services.
>>
>> Another reasonable approach would be to zip the signed UEFI binary (EFI
>> stub with uncompressed kernel) and let the UEFI firmware unzip it and
>> check the signature of the decompressed UEFI binary. This would not
>> require any patch in Linux at all and would be simple to implement in
>> U-Boot.
>>
>
> This is how it works today. One problem with this is that the image
> needs to be decompressed in order to sign it, or verify its signature.
> In general, having compression at the outside like this is fiddly
> because it is no longer a PE/COFF image, and the EFI spec only reasons
> about PE/COFF images as executable images. So we'd need to change the
> UEFI spec or the PE/COFF spec.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 0/6] efi: implement generic compressed boot support
2022-08-09 9:03 ` Heinrich Schuchardt
@ 2022-08-09 9:10 ` Ard Biesheuvel
0 siblings, 0 replies; 14+ messages in thread
From: Ard Biesheuvel @ 2022-08-09 9:10 UTC (permalink / raw)
To: Heinrich Schuchardt
Cc: catalin.marinas, will, James E.J. Bottomley, Matthew Garrett,
Peter Jones, Ilias Apalodimas, AKASHI Takahiro, Palmer Dabbelt,
Atish Patra, Arnd Bergmann, Huacai Chen, Lennart Poettering,
linux-efi
On Tue, 9 Aug 2022 at 11:03, Heinrich Schuchardt
<heinrich.schuchardt@canonical.com> wrote:
>
> On 8/9/22 10:46, Ard Biesheuvel wrote:
> > On Tue, 9 Aug 2022 at 10:38, Heinrich Schuchardt
> > <heinrich.schuchardt@canonical.com> wrote:
> >>
> >> On 8/9/22 10:09, Ard Biesheuvel wrote:
> >>> Relatively modern architectures such as arm64 or RISC-V don't implement
> >>> a self-decompressing kernel, and leave it up to the bootloader to
> >>> decompress the compressed image before executing it. For bare metal
> >>> boot, this policy makes sense, as a self-decompressing image essentially
> >>> duplicates a lot of fiddly preparation work to create a 1:1 mapping and
> >>> set up the C runtime, and to discover or infer where DRAM lives from
> >>> device trees or other firmware tables.
> >>>
> >>> For EFI boot, the situation is a bit different: the EFI entrypoint is
> >>> called with a 1:1 cached mapping covering all of DRAM already active,
> >>> and with a stack, a heap, a memory map and boot services to load and
> >>> start images. This means it is rather trivial to implement a
> >>> self-decompressing wrapper for EFI boot in a generic manner, and reuse
> >>> it across architectures that implement EFI boot.
> >>>
> >>> The only slight downside is that when UEFI secure boot is enabled, the
> >>> generic LoadImage/StartImage only allow signed images to be loaded and
> >>> started, and we prefer to avoid the need to sign both the inner and
> >>> outer PE/COFF images. This series adopts the EFI shim approach, i.e., to
> >>> override an internal UEFI/PI protocol that is used by the image loader,
> >>> to allow the inner image to be booted after decompression. This has been
> >>
> >> We should avoid requiring anything that is not in the UEFI
> >> specification. If you have any additional requirements, please, create a
> >> change request for the UEFI specification.
> >>
> >
> > As I have explained numerous times before, the EFI spec was intended
> > to be extensible (hence the 'E'). The ACPI, SMBIOS and TCG specs all
> > augment the EFI specification by defining protocols, GUIDs and other
> > things that are only relevant in a EFI context, but none of those are
> > covered by the EFI spec itself.
> >
> >> Overriding the services of the system table is dangerous and should be
> >> avoided.
> >>
> >
> > Agreed. But this is not what is happening here.
> >
> >> There is no need for two UEFI binaries one inside the other and we
> >> should avoid such overengineering.
> >>
> >
> > I disagree. Using an EFI app to encapsulate another one is the only
> > generic way to go about this, as far as I can tell.
>
> Please, elaborate why the inner compressed binary needs to be UEFI to
> boot into Linux while currently we don't need a an uncompressed inner
> UEFI binary.
>
If the inner binary is not EFI / PE/COFF, there is no generic way to
boot it. Every architecture has its own rules of how this needs to be
implemented.
> >
> >> Today we append an uncompressed kernel to the EFI stub. The stub
> >> relocates it, sets up the memory map and calls it entry point.
> >>
> >
> > Not exactly. On arm64 as well as RISC-V, the EFI stub and the kernel
> > proper are essentially the same executable image.
>
> Currently on ARM and RISC-V you have a file with two entry points:
>
> * EFI stub
> * legacy entry point
>
> The EFI stub calls the legacy entry point. In the EFI case some part of
> the EFI stub lives on at runtime. The same pointers passed to the legacy
> entry point could also be passed to a decompressed legacy kernel.
>
Nit: no part of the EFI stub lives on at runtime, but that is beside the point.
You are right that the EFI stub could be logically disjoint from the
payload, and so it could theoretically decompress its payload before
starting it.
> The EFI stub and the kernel should be completely separate binaries. Then
> you just need the cp command to join them.
>
It is not that simple, unfortunately. The EFI stub on arm64 and RISC-V
refers to many ELF symbols directly, and so splitting those images
requires some intrusive build system changes.
> >
> >> Just add decompressor code to the EFI stub and instead of appending an
> >> uncompressed kernel append a compressed one. Then sign a binary
> >> consisting of the EFI stub and the compressed kernel.
> >>
> >
> > Yes, this would be a cleaner approach, although it would require more
> > re-engineering of the EFI stub, in particular, it would require
> > cloning more code, and adding additional build and link steps.
>
> If this is the cleanest approach, we should go for it.
>
That is a fair point. Unfortunately, it will no longer be generic, and
each architecture will have to implement this individually.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 6/6] riscv: efi: enable generic EFI compressed boot
2022-08-09 8:09 ` [PATCH v2 6/6] riscv: " Ard Biesheuvel
@ 2022-09-12 14:26 ` Palmer Dabbelt
0 siblings, 0 replies; 14+ messages in thread
From: Palmer Dabbelt @ 2022-09-12 14:26 UTC (permalink / raw)
To: ardb
Cc: linux-efi, catalin.marinas, Will Deacon, ardb, James.Bottomley,
mjg59, pjones, ilias.apalodimas, heinrich.schuchardt,
takahiro.akashi, atishp, Arnd Bergmann, chenhuacai, lennart
On Tue, 09 Aug 2022 01:09:44 PDT (-0700), ardb@kernel.org wrote:
> Wire up the generic EFI zboot support for RISC-V.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/riscv/Makefile | 5 +++++
> arch/riscv/boot/Makefile | 14 ++++++++++++++
> 2 files changed, 19 insertions(+)
>
> diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> index 81029d40a672..c30ea65ec877 100644
> --- a/arch/riscv/Makefile
> +++ b/arch/riscv/Makefile
> @@ -142,6 +142,11 @@ $(BOOT_TARGETS): vmlinux
> Image.%: Image
> $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
>
> +ifneq ($(CONFIG_EFI_ZBOOT),)
> +zImage.efi: Image
> + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
> +endif
> +
> install: KBUILD_IMAGE := $(boot)/Image
> zinstall: KBUILD_IMAGE := $(boot)/Image.gz
> install zinstall:
> diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile
> index becd0621071c..60cd319685ea 100644
> --- a/arch/riscv/boot/Makefile
> +++ b/arch/riscv/boot/Makefile
> @@ -58,3 +58,17 @@ $(obj)/Image.lzo: $(obj)/Image FORCE
>
> $(obj)/loader.bin: $(obj)/loader FORCE
> $(call if_changed,objcopy)
> +
> +ZBOOT_PAYLOAD := $(obj)/Image
> +ZBOOT_BFD_TARGET := elf$(BITS)-littleriscv
> +ZBOOT_LD_FLAGS := --defsym=__efistub_strnlen=strnlen \
> + --defsym=__efistub_memmove=memmove \
> + --defsym=__efistub_memcpy=memcpy \
> + --defsym=__efistub_memset=memset
> +
> +ZBOOT_EXTRA_OBJS := memcpy.o memset.o memmove.o
> +ZBOOT_EXTRA_DEPS := $(objtree)/lib/string.o \
> + $(objtree)/lib/ctype.o \
> + $(addprefix $(objtree)/arch/riscv/lib/,$(ZBOOT_EXTRA_OBJS))
> +
> +include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot
Acked-by: Palmer Dabbelt <palmer@rivosinc.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2022-09-12 14:26 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-08-09 8:09 [PATCH v2 0/6] efi: implement generic compressed boot support Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 1/6] efi: stub: add some missing boot service prototypes Ard Biesheuvel
2022-08-09 8:42 ` Heinrich Schuchardt
2022-08-09 8:09 ` [PATCH v2 2/6] efi: stub: split off printk() routines Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 3/6] efi: stub: move efi_system_table global var into separate object Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 4/6] efi: stub: implement generic EFI zboot Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 5/6] arm64: efi: enable generic EFI compressed boot Ard Biesheuvel
2022-08-09 8:09 ` [PATCH v2 6/6] riscv: " Ard Biesheuvel
2022-09-12 14:26 ` Palmer Dabbelt
2022-08-09 8:38 ` [PATCH v2 0/6] efi: implement generic compressed boot support Heinrich Schuchardt
2022-08-09 8:46 ` Ard Biesheuvel
2022-08-09 9:03 ` Heinrich Schuchardt
2022-08-09 9:10 ` Ard Biesheuvel
2022-08-09 8:47 ` Matthew Garrett
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox