arch/x86/Kconfig | 1 + arch/x86/boot/compressed/Makefile | 3 +++ arch/x86/boot/compressed/misc.c | 4 ++++ arch/x86/boot/header.S | 2 ++ drivers/firmware/efi/libstub/zboot.c | 2 ++ lib/decompress_dummy.c | 15 +++++++++++++++ scripts/Makefile.lib | 3 +++ 7 files changed, 30 insertions(+)
Support storing the kernel uncompressed for developers who want to quickly
iterate with one-off kernel builds.
Store it in the usual format with a 4-byte length suffix and keep this new
codepath as close as possible to the normal path where decompression
happens.
The other compression methods offered by the kernel take some time;
even LZ4 (which the kernel uses at compression level 9) takes ~2.8
seconds to compress a 110M large vmlinux.bin on my machine.
An alternate approach to this would be to offer customization of the LZ4
compression level through a kconfig variable; and yet another approach
would be to abuse the existing gzip decompression logic by storing the
kernel as "non-compressed" DEFLATE blocks, so that the decompression code
will essentially end up just doing a bunch of memcpy() calls.
Signed-off-by: Jann Horn <jannh@google.com>
---
arch/x86/Kconfig | 1 +
arch/x86/boot/compressed/Makefile | 3 +++
arch/x86/boot/compressed/misc.c | 4 ++++
arch/x86/boot/header.S | 2 ++
drivers/firmware/efi/libstub/zboot.c | 2 ++
lib/decompress_dummy.c | 15 +++++++++++++++
scripts/Makefile.lib | 3 +++
7 files changed, 30 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ef6cfea9df7333c52e331f487a0b29f037a6bf14..6d468d47861ae0b6ec6b7649af6ab4dd123eb5c8 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -250,6 +250,7 @@ config X86
select HAVE_KERNEL_LZO
select HAVE_KERNEL_XZ
select HAVE_KERNEL_ZSTD
+ select HAVE_KERNEL_UNCOMPRESSED
select HAVE_KPROBES
select HAVE_KPROBES_ON_FTRACE
select HAVE_FUNCTION_ERROR_INJECTION
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index f2051644de9432e3466ac0ef1c4d3abc378e37d3..06079e02d9e01704cc0da06c1195854c8d0602ac 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -137,6 +137,8 @@ $(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) FORCE
$(call if_changed,lz4_with_size)
$(obj)/vmlinux.bin.zst: $(vmlinux.bin.all-y) FORCE
$(call if_changed,zstd22_with_size)
+$(obj)/vmlinux.bin.store: $(vmlinux.bin.all-y) FORCE
+ $(call if_changed,store_with_size)
suffix-$(CONFIG_KERNEL_GZIP) := gz
suffix-$(CONFIG_KERNEL_BZIP2) := bz2
@@ -145,6 +147,7 @@ suffix-$(CONFIG_KERNEL_XZ) := xz
suffix-$(CONFIG_KERNEL_LZO) := lzo
suffix-$(CONFIG_KERNEL_LZ4) := lz4
suffix-$(CONFIG_KERNEL_ZSTD) := zst
+suffix-$(CONFIG_KERNEL_UNCOMPRESSED) := store
quiet_cmd_mkpiggy = MKPIGGY $@
cmd_mkpiggy = $(obj)/mkpiggy $< > $@
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 0d37420cad0259554f8160dea0c502cb7e2fc6cd..5d514a147d5d1ae252419e4c7cdc09e9c29f110f 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -88,6 +88,10 @@ static int cols __section(".data");
#ifdef CONFIG_KERNEL_ZSTD
#include "../../../../lib/decompress_unzstd.c"
#endif
+
+#ifdef CONFIG_KERNEL_UNCOMPRESSED
+#include "../../../../lib/decompress_dummy.c"
+#endif
/*
* NOTE: When adding a new decompressor, please update the analysis in
* ../header.S.
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index b5c79f43359bcde2c4c3c5ed796e8780f7979774..8397470231cf571a33ac75f7ca7020608e170eef 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -483,6 +483,8 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
# larger margin.
#
# extra_bytes = (uncompressed_size >> 8) + 131072
+#
+# Uncompressed data does not grow.
#define ZO_z_extra_bytes ((ZO_z_output_len >> 8) + 131072)
#if ZO_z_output_len > ZO_z_input_len
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index af23b3c502282f9bd644c38af445875c225cdf42..1c43a6ae5e665aa3bff3bd467c8a2f5525b1a6e9 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -27,6 +27,8 @@ static unsigned long free_mem_ptr, free_mem_end_ptr;
#include "../../../../lib/decompress_unxz.c"
#elif defined(CONFIG_KERNEL_ZSTD)
#include "../../../../lib/decompress_unzstd.c"
+#elif defined(CONFIG_KERNEL_UNCOMPRESSED)
+#include "../../../../lib/decompress_dummy.c"
#endif
extern char efi_zboot_header[];
diff --git a/lib/decompress_dummy.c b/lib/decompress_dummy.c
new file mode 100644
index 0000000000000000000000000000000000000000..49435e199a07f6ed376ff93adeae8ee08a9dd3d7
--- /dev/null
+++ b/lib/decompress_dummy.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+STATIC int INIT __decompress(unsigned char *buf, long len,
+ long (*fill)(void*, unsigned long),
+ long (*flush)(void*, unsigned long),
+ unsigned char *out_buf, long out_len,
+ long *pos,
+ void (*error)(char *x))
+{
+ if (out_len < len-4) {
+ error("output buffer too small");
+ return -1;
+ }
+ memcpy(out_buf, buf, len-4);
+ return 0;
+}
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 7395200538da89a2f6e6d21f8959f3f60d291d79..bb8116ba8ba189d5246fcb0e71c7be6e05ce5148 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -525,6 +525,9 @@ quiet_cmd_zstd22 = ZSTD22 $@
quiet_cmd_zstd22_with_size = ZSTD22 $@
cmd_zstd22_with_size = { cat $(real-prereqs) | $(ZSTD) -22 --ultra; $(size_append); } > $@
+quiet_cmd_store_with_size = STORE $@
+ cmd_store_with_size = { cat $(real-prereqs); $(size_append); } > $@
+
# ASM offsets
# ---------------------------------------------------------------------------
---
base-commit: 95ec54a420b8f445e04a7ca0ea8deb72c51fe1d3
change-id: 20250121-kernel-compress-fast-350ce5801c28
--
Jann Horn <jannh@google.com>
© 2016 - 2025 Red Hat, Inc.