* [PATCH 0/3] alpha: self-extracting compressed kernel images
@ 2026-09-12 19:55 Matt Turner
2026-09-12 19:55 ` [PATCH 1/3] xz: add arch-specific tuning for alpha Matt Turner
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Matt Turner @ 2026-09-12 19:55 UTC (permalink / raw)
To: Lasse Collin, Richard Henderson, Magnus Lindholm, Nick Terrell,
David Sterba
Cc: linux-kernel, linux-alpha, Matt Turner
Alpha is the last architecture whose boot loader decompresses the kernel
itself: aboot carries its own inflate code, so vmlinux.gz has always
been plain gzip, and adding a compression format meant writing a
decompressor for aboot as well as for the kernel.
Build a self-extracting image instead, a small ELF stub with the
compressed vmlinux linked in, which aboot loads and enters like any
other kernel. The compression format then becomes an ordinary kernel
Kconfig choice, and all seven formats become available: xz gives the
smallest image, 5547496 bytes against 7677280 for the equivalent gzip
one. The build now emits arch/alpha/boot/vmlinuz, since the image is no
longer gzip data.
The SRM netboot path (bootpz.c) has its own boot protocol and keeps
using gzip.
Signed-off-by: Matt Turner <mattst88@gmail.com>
---
Matt Turner (3):
xz: add arch-specific tuning for alpha
alpha: add self-extracting compressed kernel boot stub
alpha: support the remaining kernel compression formats
arch/alpha/Kconfig | 7 ++
arch/alpha/Makefile | 6 +-
arch/alpha/boot/.gitignore | 2 +
arch/alpha/boot/Makefile | 16 ++-
arch/alpha/boot/compressed/.gitignore | 3 +
arch/alpha/boot/compressed/Makefile | 63 ++++++++++
arch/alpha/boot/compressed/head.S | 36 ++++++
arch/alpha/boot/compressed/misc.c | 209 +++++++++++++++++++++++++++++++
arch/alpha/boot/compressed/trampoline.S | 46 +++++++
arch/alpha/boot/compressed/vmlinux.lds.S | 83 ++++++++++++
arch/alpha/boot/compressed/vmlinux.scr | 10 ++
scripts/xz_wrap.sh | 5 +
12 files changed, 478 insertions(+), 8 deletions(-)
---
base-commit: 4407825b2f96b0e48a4bd08ab196b50a30eb3aef
change-id: 20260912-alpha-kernel-compression-2043f806fb75
Best regards,
--
Matt Turner <mattst88@gmail.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/3] xz: add arch-specific tuning for alpha
2026-09-12 19:55 [PATCH 0/3] alpha: self-extracting compressed kernel images Matt Turner
@ 2026-09-12 19:55 ` Matt Turner
2026-09-12 19:55 ` [PATCH 2/3] alpha: add self-extracting compressed kernel boot stub Matt Turner
2026-09-12 19:55 ` [PATCH 3/3] alpha: support the remaining kernel compression formats Matt Turner
2 siblings, 0 replies; 4+ messages in thread
From: Matt Turner @ 2026-09-12 19:55 UTC (permalink / raw)
To: Lasse Collin, Richard Henderson, Magnus Lindholm, Nick Terrell,
David Sterba
Cc: linux-kernel, linux-alpha, Matt Turner
Alpha has fixed-length, 4-byte-aligned instructions and no XZ BCJ
filter, so it wants the same LZMA2 settings as the other 4-byte-aligned
targets. Without an entry it hits the default case, which warns
scripts/xz_wrap.sh: Arch-specific tuning is missing for 'alpha'
and conservatively assumes 2-byte alignment. Alpha gains HAVE_KERNEL_XZ
later in this series; the correct alignment also shrinks a UP1500
kernel's XZ image from 6469320 to 6448840 bytes.
Signed-off-by: Matt Turner <mattst88@gmail.com>
---
scripts/xz_wrap.sh | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/scripts/xz_wrap.sh b/scripts/xz_wrap.sh
index f19369687030..5af0d9045cbc 100755
--- a/scripts/xz_wrap.sh
+++ b/scripts/xz_wrap.sh
@@ -10,6 +10,7 @@
# XZ-compressed kernel isn't currently supported on every listed arch.
#
# Arch Align Notes
+# alpha 4
# arm 2/4 ARM and ARM-Thumb2
# arm64 4
# csky 2
@@ -44,6 +45,10 @@ BCJ=
# Set the BCJ filter if one is available.
# It must match the #ifdef usage in lib/decompress_unxz.c.
case $SRCARCH in
+ alpha)
+ ALIGN=4
+ ;;
+
arm)
if is_enabled CONFIG_THUMB2_KERNEL; then
ALIGN=2
--
2.54.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/3] alpha: add self-extracting compressed kernel boot stub
2026-09-12 19:55 [PATCH 0/3] alpha: self-extracting compressed kernel images Matt Turner
2026-09-12 19:55 ` [PATCH 1/3] xz: add arch-specific tuning for alpha Matt Turner
@ 2026-09-12 19:55 ` Matt Turner
2026-09-12 19:55 ` [PATCH 3/3] alpha: support the remaining kernel compression formats Matt Turner
2 siblings, 0 replies; 4+ messages in thread
From: Matt Turner @ 2026-09-12 19:55 UTC (permalink / raw)
To: Lasse Collin, Richard Henderson, Magnus Lindholm, Nick Terrell,
David Sterba
Cc: linux-kernel, linux-alpha, Matt Turner
Alpha only ever supported gzip for the kernel image, and did so in a way
out of step with every other architecture: aboot, the disk boot loader,
decompresses vmlinux.gz itself with its own bundled inflate code, so
adding a compression format meant writing a new decompressor inside
aboot as well as in the kernel.
Build a proper self-extracting arch/alpha/boot/compressed/vmlinux
instead, modeled on parisc: a small ELF stub with the real, compressed
vmlinux linked in, which decompresses the kernel, relocates it into
place and jumps to its entry point. aboot needs no changes.
The build now emits arch/alpha/boot/vmlinuz rather than vmlinux.gz,
which was never a name aboot cared about and would be a lie for an ELF
stub: the bootpz path in the same directory still produces real gzip
data as vmlinux.nh.gz. Existing aboot.conf files name the image as it
was installed in /boot, so only the command that copies it out of the
build tree changes.
Unlike parisc and mips, the stub is linked at START_ADDR rather than at
a separate low address; see compressed/vmlinux.lds.S. It has no console
output, since bringing up the HWRPB console callbacks needs more than
the CRB dispatch the kernel proper does much later, so error() just
halts.
The legacy SRM netboot path (bootpz.c) is left alone: it has its own
boot protocol (PALcode reinitialization, self-populated ZERO_PGE,
build-time-computed image sizes) that does not fit this design without a
separate rewrite, and keeps using plain gzip via vmlinux.nh.gz.
Signed-off-by: Matt Turner <mattst88@gmail.com>
---
arch/alpha/Kconfig | 1 +
arch/alpha/Makefile | 6 +-
arch/alpha/boot/.gitignore | 2 +
arch/alpha/boot/Makefile | 16 ++-
arch/alpha/boot/compressed/.gitignore | 3 +
arch/alpha/boot/compressed/Makefile | 36 +++++++
arch/alpha/boot/compressed/head.S | 36 +++++++
arch/alpha/boot/compressed/misc.c | 178 +++++++++++++++++++++++++++++++
arch/alpha/boot/compressed/trampoline.S | 46 ++++++++
arch/alpha/boot/compressed/vmlinux.lds.S | 83 ++++++++++++++
arch/alpha/boot/compressed/vmlinux.scr | 10 ++
11 files changed, 409 insertions(+), 8 deletions(-)
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 04511242506b..2688bb00f175 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -30,6 +30,7 @@ config ALPHA
select HAVE_ASM_MODVERSIONS
select HAVE_DEBUG_KMEMLEAK
select HAVE_GUP_FAST
+ select HAVE_KERNEL_GZIP
select HAVE_PAGE_SIZE_8KB
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile
index 7074602dca94..405d4bfd644c 100644
--- a/arch/alpha/Makefile
+++ b/arch/alpha/Makefile
@@ -47,9 +47,9 @@ export LIBS_Y
boot := arch/alpha/boot
#Default target when executing make with no arguments
-all boot: $(boot)/vmlinux.gz
+all boot: $(boot)/vmlinuz
-$(boot)/vmlinux.gz: vmlinux
+$(boot)/vmlinuz: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $@
bootimage bootpfile bootpzfile: vmlinux
@@ -59,7 +59,7 @@ archheaders:
$(Q)$(MAKE) $(build)=arch/alpha/kernel/syscalls all
define archhelp
- echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinux.gz)'
+ echo '* boot - Compressed kernel image (arch/alpha/boot/vmlinuz)'
echo ' bootimage - SRM bootable image (arch/alpha/boot/bootimage)'
echo ' bootpfile - BOOTP bootable image (arch/alpha/boot/bootpfile)'
echo ' bootpzfile - compressed kernel BOOTP image (arch/alpha/boot/bootpzfile)'
diff --git a/arch/alpha/boot/.gitignore b/arch/alpha/boot/.gitignore
new file mode 100644
index 000000000000..4125506521f6
--- /dev/null
+++ b/arch/alpha/boot/.gitignore
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+vmlinuz
diff --git a/arch/alpha/boot/Makefile b/arch/alpha/boot/Makefile
index d8dba85e606c..7c2a41c1e2a0 100644
--- a/arch/alpha/boot/Makefile
+++ b/arch/alpha/boot/Makefile
@@ -9,9 +9,10 @@
#
hostprogs := tools/mkbb tools/objstrip
-targets := vmlinux.gz vmlinux \
+targets := vmlinuz vmlinux \
vmlinux.nh tools/lxboot tools/bootlx tools/bootph \
- tools/bootpzh bootloader bootpheader bootpzheader
+ tools/bootpzh bootloader bootpheader bootpzheader
+subdir- := compressed
OBJSTRIP := $(obj)/tools/objstrip
KBUILD_HOSTCFLAGS := -Wall -I$(objtree)/usr/include
@@ -38,9 +39,14 @@ ifdef INITRD
cat $(INITRD) >> $@
endif
-# Compressed kernel image
-$(obj)/vmlinux.gz: $(obj)/vmlinux FORCE
- $(call if_changed,gzip)
+# Self-extracting compressed kernel image: a small ELF stub (see
+# compressed/) with the real vmlinux linked in compressed, which aboot
+# loads and enters like a plain vmlinux.
+$(obj)/compressed/vmlinux: vmlinux FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/compressed $@
+
+$(obj)/vmlinuz: $(obj)/compressed/vmlinux FORCE
+ $(call if_changed,copy)
@echo ' Kernel $@ is ready'
$(obj)/main.o: $(obj)/ksize.h
diff --git a/arch/alpha/boot/compressed/.gitignore b/arch/alpha/boot/compressed/.gitignore
new file mode 100644
index 000000000000..765a08f1bd77
--- /dev/null
+++ b/arch/alpha/boot/compressed/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+vmlinux
+vmlinux.lds
diff --git a/arch/alpha/boot/compressed/Makefile b/arch/alpha/boot/compressed/Makefile
new file mode 100644
index 000000000000..d826f7e4384d
--- /dev/null
+++ b/arch/alpha/boot/compressed/Makefile
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Create a self-extracting compressed vmlinux image from the original
+# vmlinux. aboot loads and enters it like a plain vmlinux.
+#
+
+OBJECTS := head.o misc.o trampoline.o piggy.o
+targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz
+targets += $(OBJECTS)
+
+# The stub runs before the kernel has identified the CPU it booted on, so
+# build it for the base Alpha instruction set rather than inheriting the
+# kernel's -mcpu=.
+KBUILD_CFLAGS := -D__KERNEL__ -std=gnu11 -Os -fno-strict-aliasing
+KBUILD_CFLAGS += -fno-PIE -ffreestanding -fno-stack-protector
+KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
+KBUILD_CFLAGS += -pipe -mno-fp-regs -ffixed-8
+KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS
+KBUILD_CFLAGS += $(CC_FLAGS_DIALECT)
+
+LDFLAGS_vmlinux := -X --orphan-handling=warn -T
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(addprefix $(obj)/, $(OBJECTS)) $(LIBS_Y) FORCE
+ $(call if_changed,ld)
+
+OBJCOPYFLAGS_vmlinux.bin := -R .comment -R .note -S
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+suffix-$(CONFIG_KERNEL_GZIP) := gz
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf64-alpha -T
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE
+ $(call if_changed,ld)
diff --git a/arch/alpha/boot/compressed/head.S b/arch/alpha/boot/compressed/head.S
new file mode 100644
index 000000000000..c689ac439d15
--- /dev/null
+++ b/arch/alpha/boot/compressed/head.S
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Entry point for the self-extracting compressed kernel stub. aboot
+ * jumps here with the OSF/1 parameter page (ZERO_PGE) already populated
+ * and $30 set to INIT_STACK, exactly as it would for an uncompressed
+ * vmlinux.
+ */
+
+#include <linux/init.h>
+#include <asm/pal.h>
+
+ .set noreorder
+
+__HEAD
+ .globl __start
+ .ent __start
+__start:
+ br $29,1f
+1: ldgp $29,0($29)
+
+ /*
+ * Clear our own bss. The decompressors keep state there, and
+ * nothing guarantees that aboot zeroed the part of our PT_LOAD
+ * segment that has no file backing.
+ */
+ lda $1,_bss
+ lda $2,_ebss
+2: cmpult $1,$2,$3
+ beq $3,3f
+ stq $31,0($1)
+ addq $1,8,$1
+ br $31,2b
+
+3: jsr $26,decompress_and_boot
+ call_pal PAL_halt
+ .end __start
diff --git a/arch/alpha/boot/compressed/misc.c b/arch/alpha/boot/compressed/misc.c
new file mode 100644
index 000000000000..72998582be68
--- /dev/null
+++ b/arch/alpha/boot/compressed/misc.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Decompression and self-relocation for the compressed kernel boot stub,
+ * based on arch/parisc/boot/compressed/misc.c.
+ *
+ * aboot loads the stub as an ordinary ELF at START_ADDR and jumps to it
+ * with the parameter page and stack already set up; vmlinux.lds.S
+ * explains why the stub has to be linked there. We decompress above our
+ * own bss and never write below START_ADDR, so what aboot prepared stays
+ * valid for the real kernel.
+ */
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/hwrpb.h>
+#include <asm/page.h>
+#include <asm/pal.h>
+#include <asm/setup.h>
+
+#define STATIC static
+#define memzero(s, n) memset((s), 0, (n))
+
+extern char input_data[];
+extern int input_len;
+/* output_len is inserted by the linker, possibly at an unaligned address */
+extern char output_len;
+
+extern char _ebss[];
+extern char trampoline_start[], trampoline_end[];
+
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+static unsigned long mem_end;
+
+/* The stub has no console, so the message is only for debuggers. */
+void __noreturn error(char *m)
+{
+ while (1)
+ __halt();
+}
+
+#ifdef CONFIG_KERNEL_GZIP
+#include "../../../../lib/decompress_inflate.c"
+#endif
+
+/* Scratch heap for the decompressors, larger than any of them needs. */
+#define STUB_HEAP_SIZE (4 * 1024 * 1024)
+
+/*
+ * Type punning through a packed struct, to avoid the warnings the regular
+ * get_unaligned_le32() produces when reading a char-typed symbol as an
+ * integer.
+ */
+static u32 punned_get_unaligned_le32(const void *p)
+{
+ const struct { __le32 x; } __packed *pp = p;
+
+ return le32_to_cpu(pp->x);
+}
+
+/*
+ * End of the usable memory cluster that holds the kernel, or 0 if the
+ * HWRPB does not describe one. Used to check that the decompressed image
+ * and the stub's scratch space fit before anything is written.
+ */
+static unsigned long usable_memory_end(void)
+{
+ struct hwrpb_struct *hwrpb;
+ struct memdesc_struct *memdesc;
+ unsigned long pfn = (START_ADDR - PAGE_OFFSET) >> PAGE_SHIFT;
+ unsigned long i;
+
+ hwrpb = (struct hwrpb_struct *)(PAGE_OFFSET + INIT_HWRPB->phys_addr);
+ memdesc = (struct memdesc_struct *)((unsigned long)hwrpb +
+ hwrpb->mddt_offset);
+
+ for (i = 0; i < memdesc->numclusters; i++) {
+ struct memclust_struct *cluster = &memdesc->cluster[i];
+ unsigned long end_pfn = cluster->start_pfn + cluster->numpages;
+
+ if (cluster->usage)
+ continue;
+ if (pfn >= cluster->start_pfn && pfn < end_pfn)
+ return PAGE_OFFSET + (end_pfn << PAGE_SHIFT);
+ }
+
+ return 0;
+}
+
+/*
+ * Move the decompressed kernel's single PT_LOAD segment down onto
+ * START_ADDR and jump to its entry point. The kernel is always linked
+ * with exactly one PT_LOAD whose p_vaddr equals its e_entry equals
+ * START_ADDR (see arch/alpha/kernel/vmlinux.lds.S); anything else we do
+ * not know how to boot.
+ *
+ * The copy cannot run from this stub, which is itself executing at
+ * START_ADDR; see trampoline.S.
+ */
+static void __noreturn relocate_and_jump(void *image)
+{
+ void (*trampoline)(unsigned long dest, unsigned long src,
+ unsigned long filesz, unsigned long memsz,
+ unsigned long entry);
+ unsigned long tramp_len = trampoline_end - trampoline_start;
+ Elf64_Phdr phdr, load_phdr = {};
+ Elf64_Ehdr ehdr;
+ int i, found_load = 0;
+ unsigned long tramp;
+
+ memcpy(&ehdr, image, sizeof(ehdr));
+
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr.e_ident[EI_MAG3] != ELFMAG3 ||
+ ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
+ ehdr.e_ident[EI_DATA] != ELFDATA2LSB ||
+ ehdr.e_machine != EM_ALPHA ||
+ ehdr.e_type != ET_EXEC ||
+ ehdr.e_entry != START_ADDR)
+ error("Not a bootable Alpha kernel image");
+
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ memcpy(&phdr, image + ehdr.e_phoff + i * ehdr.e_phentsize,
+ sizeof(phdr));
+
+ if (phdr.p_type != PT_LOAD)
+ continue;
+ if (found_load || phdr.p_vaddr != START_ADDR)
+ error("Unexpected kernel segment layout");
+ found_load = 1;
+ load_phdr = phdr;
+ }
+ if (!found_load)
+ error("Kernel image has no PT_LOAD segment");
+
+ /*
+ * The trampoline has to outlive both the scratch heap it is copied
+ * into and the region it is about to write, which extends past the
+ * kernel's file image to the end of its bss.
+ */
+ tramp = ALIGN(max(free_mem_end_ptr, START_ADDR + load_phdr.p_memsz), 8);
+ if (mem_end && tramp + tramp_len > mem_end)
+ error("Not enough memory to relocate the kernel");
+
+ memcpy((void *)tramp, trampoline_start, tramp_len);
+ imb();
+
+ trampoline = (void *)tramp;
+ trampoline(load_phdr.p_vaddr,
+ (unsigned long)image + load_phdr.p_offset,
+ load_phdr.p_filesz, load_phdr.p_memsz, ehdr.e_entry);
+ unreachable();
+}
+
+void __noreturn decompress_and_boot(void)
+{
+ unsigned long image_len = punned_get_unaligned_le32(&output_len);
+ void *image = (void *)ALIGN((unsigned long)_ebss, PAGE_SIZE);
+
+ free_mem_ptr = ALIGN((unsigned long)image + image_len, PAGE_SIZE);
+ free_mem_end_ptr = free_mem_ptr + STUB_HEAP_SIZE;
+
+ mem_end = usable_memory_end();
+ if (mem_end && free_mem_end_ptr > mem_end)
+ error("Not enough memory to decompress the kernel");
+
+ /* Some decompressors report failure only through the return value. */
+ if (__decompress(input_data, input_len, NULL, NULL, image, image_len,
+ NULL, error))
+ error("Kernel decompression failed");
+
+ relocate_and_jump(image);
+}
diff --git a/arch/alpha/boot/compressed/trampoline.S b/arch/alpha/boot/compressed/trampoline.S
new file mode 100644
index 000000000000..bf57d3b0fd7f
--- /dev/null
+++ b/arch/alpha/boot/compressed/trampoline.S
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copy the decompressed kernel onto START_ADDR, clear its bss and jump to
+ * its entry point. See relocate_and_jump() in misc.c for why this cannot
+ * run from the stub itself. It is position independent (no data or
+ * rodata references, no gp) and clobbers only its argument registers and
+ * $1, so misc.c can copy it anywhere and call it there.
+ */
+
+ .set noreorder
+
+ .globl trampoline_start
+ .globl trampoline_end
+ .ent trampoline_start
+trampoline_start:
+ /* $16 = dest, $17 = src, $18 = p_filesz, $19 = p_memsz, $20 = entry */
+
+ /*
+ * dest and src are both page aligned, and everything above
+ * p_filesz is bss, so round both lengths up and work in quadwords
+ * only, using instructions every Alpha implements.
+ */
+ addq $18,7,$18
+ bic $18,7,$18
+ addq $19,7,$19
+ bic $19,7,$19
+ subq $19,$18,$19 /* bytes to zero after the copy */
+
+1: beq $18,2f
+ ldq $1,0($17)
+ stq $1,0($16)
+ addq $17,8,$17
+ addq $16,8,$16
+ subq $18,8,$18
+ br $31,1b
+
+2: beq $19,3f
+ stq $31,0($16)
+ addq $16,8,$16
+ subq $19,8,$19
+ br $31,2b
+
+3: imb
+ jmp $31,($20)
+ .end trampoline_start
+trampoline_end:
diff --git a/arch/alpha/boot/compressed/vmlinux.lds.S b/arch/alpha/boot/compressed/vmlinux.lds.S
new file mode 100644
index 000000000000..5328c1ccaccf
--- /dev/null
+++ b/arch/alpha/boot/compressed/vmlinux.lds.S
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+
+OUTPUT_FORMAT("elf64-alpha")
+OUTPUT_ARCH(alpha)
+ENTRY(__start)
+
+SECTIONS
+{
+ /*
+ * Link the stub at the address the real, uncompressed vmlinux has
+ * always occupied. aboot derives the OSF/1 parameter-page
+ * (ZERO_PGE) and initial stack (INIT_STACK) addresses from the
+ * loaded image's own p_vaddr, so a stub linked anywhere else would
+ * hand the real kernel a parameter page it does not expect.
+ */
+ . = START_ADDR;
+
+ .head.text : {
+ _head = .;
+ HEAD_TEXT
+ _ehead = .;
+ }
+
+ . = ALIGN(8);
+ .rodata.compressed : {
+ *(.rodata.compressed)
+ }
+
+ . = ALIGN(PAGE_SIZE);
+ .text : {
+ _text = .;
+ *(.text)
+ *(.text.*)
+ _etext = .;
+ }
+ . = ALIGN(8);
+ .rodata : {
+ *(.rodata)
+ *(.rodata.*)
+ }
+ . = ALIGN(8);
+ .data : {
+ *(.data)
+ *(.data.*)
+ }
+ .got : {
+ *(.got)
+ }
+ .sdata : {
+ *(.sdata)
+ }
+ /*
+ * misc.c decompresses to _ebss, so nothing that the stub still
+ * needs may be placed after .bss. --orphan-handling=warn keeps a
+ * new section from silently landing there.
+ */
+ . = ALIGN(8);
+ .bss : {
+ _bss = .;
+ *(.sbss)
+ *(.scommon)
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ . = ALIGN(8);
+ _ebss = .;
+ }
+
+ STABS_DEBUG
+ DWARF_DEBUG
+ ELF_DETAILS
+
+ DISCARDS
+ /DISCARD/ : {
+ *(.eh_frame)
+ *(.modinfo)
+ *(.note)
+ *(.note.*)
+ }
+}
diff --git a/arch/alpha/boot/compressed/vmlinux.scr b/arch/alpha/boot/compressed/vmlinux.scr
new file mode 100644
index 000000000000..dac2d142bcfa
--- /dev/null
+++ b/arch/alpha/boot/compressed/vmlinux.scr
@@ -0,0 +1,10 @@
+SECTIONS
+{
+ .rodata.compressed : {
+ input_len = .;
+ LONG(input_data_end - input_data) input_data = .;
+ *(.data)
+ output_len = . - 4; /* can be at unaligned address */
+ input_data_end = .;
+ }
+}
--
2.54.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 3/3] alpha: support the remaining kernel compression formats
2026-09-12 19:55 [PATCH 0/3] alpha: self-extracting compressed kernel images Matt Turner
2026-09-12 19:55 ` [PATCH 1/3] xz: add arch-specific tuning for alpha Matt Turner
2026-09-12 19:55 ` [PATCH 2/3] alpha: add self-extracting compressed kernel boot stub Matt Turner
@ 2026-09-12 19:55 ` Matt Turner
2 siblings, 0 replies; 4+ messages in thread
From: Matt Turner @ 2026-09-12 19:55 UTC (permalink / raw)
To: Lasse Collin, Richard Henderson, Magnus Lindholm, Nick Terrell,
David Sterba
Cc: linux-kernel, linux-alpha, Matt Turner
Nothing about the boot stub is specific to gzip, so wire up bzip2, lz4,
lzma, lzo, xz and zstd as well: select the matching HAVE_KERNEL_*
symbol, add a suffix-y entry and a compression rule for the piggy-backed
image, and include the decompressor into the stub's misc.c.
Only gzip's trailer already carries the uncompressed size, so the other
formats use the _with_size variants; output_len, which vmlinux.scr takes
from the last 4 bytes of the payload, then works for all of them. The
stub passes it to __decompress(), which zstd requires.
Signed-off-by: Matt Turner <mattst88@gmail.com>
---
arch/alpha/Kconfig | 6 ++++++
arch/alpha/boot/compressed/Makefile | 31 +++++++++++++++++++++++++++++--
arch/alpha/boot/compressed/misc.c | 31 +++++++++++++++++++++++++++++++
3 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 2688bb00f175..92cc7bb8d29a 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -30,7 +30,13 @@ config ALPHA
select HAVE_ASM_MODVERSIONS
select HAVE_DEBUG_KMEMLEAK
select HAVE_GUP_FAST
+ select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_LZ4
+ select HAVE_KERNEL_LZMA
+ select HAVE_KERNEL_LZO
+ select HAVE_KERNEL_XZ
+ select HAVE_KERNEL_ZSTD
select HAVE_PAGE_SIZE_8KB
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
diff --git a/arch/alpha/boot/compressed/Makefile b/arch/alpha/boot/compressed/Makefile
index d826f7e4384d..06deaf51fcfa 100644
--- a/arch/alpha/boot/compressed/Makefile
+++ b/arch/alpha/boot/compressed/Makefile
@@ -5,7 +5,10 @@
#
OBJECTS := head.o misc.o trampoline.o piggy.o
-targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz
+targets := vmlinux.lds vmlinux vmlinux.bin
+targets += vmlinux.bin.bz2 vmlinux.bin.gz vmlinux.bin.lz4
+targets += vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.xz
+targets += vmlinux.bin.zst
targets += $(OBJECTS)
# The stub runs before the kernel has identified the CPU it booted on, so
@@ -18,18 +21,42 @@ KBUILD_CFLAGS += -pipe -mno-fp-regs -ffixed-8
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING -D__DISABLE_EXPORTS
KBUILD_CFLAGS += $(CC_FLAGS_DIALECT)
+# zstd's decompressor uses __builtin_ctzll()/__builtin_clzll(). Those are
+# inline code only with the CIX extension, which the base instruction set
+# the stub is built for does not have, so they become calls to libgcc's
+# __ctzdi2/__clzdi2.
+LIBGCC := $(shell $(CC) -print-libgcc-file-name)
+
LDFLAGS_vmlinux := -X --orphan-handling=warn -T
-$(obj)/vmlinux: $(obj)/vmlinux.lds $(addprefix $(obj)/, $(OBJECTS)) $(LIBS_Y) FORCE
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(addprefix $(obj)/, $(OBJECTS)) $(LIBS_Y) $(LIBGCC) FORCE
$(call if_changed,ld)
OBJCOPYFLAGS_vmlinux.bin := -R .comment -R .note -S
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
+suffix-$(CONFIG_KERNEL_BZIP2) := bz2
suffix-$(CONFIG_KERNEL_GZIP) := gz
+suffix-$(CONFIG_KERNEL_LZ4) := lz4
+suffix-$(CONFIG_KERNEL_LZMA) := lzma
+suffix-$(CONFIG_KERNEL_LZO) := lzo
+suffix-$(CONFIG_KERNEL_XZ) := xz
+suffix-$(CONFIG_KERNEL_ZSTD) := zst
+$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,bzip2_with_size)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
$(call if_changed,gzip)
+$(obj)/vmlinux.bin.lz4: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,lz4_with_size)
+$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,lzma_with_size)
+$(obj)/vmlinux.bin.lzo: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,lzo_with_size)
+$(obj)/vmlinux.bin.xz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,xzkern_with_size)
+$(obj)/vmlinux.bin.zst: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,zstd22_with_size)
LDFLAGS_piggy.o := -r --format binary --oformat elf64-alpha -T
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE
diff --git a/arch/alpha/boot/compressed/misc.c b/arch/alpha/boot/compressed/misc.c
index 72998582be68..8ffc546e1a15 100644
--- a/arch/alpha/boot/compressed/misc.c
+++ b/arch/alpha/boot/compressed/misc.c
@@ -23,6 +23,13 @@
#define STATIC static
#define memzero(s, n) memset((s), 0, (n))
+/*
+ * decompress_unxz.c supplies its own memmove() unless the identifier is
+ * already a macro. arch/alpha/lib/ has a better one and is already on
+ * our link line, so take that instead.
+ */
+#define memmove memmove
+
extern char input_data[];
extern int input_len;
/* output_len is inserted by the linker, possibly at an unaligned address */
@@ -42,10 +49,34 @@ void __noreturn error(char *m)
__halt();
}
+#ifdef CONFIG_KERNEL_BZIP2
+#include "../../../../lib/decompress_bunzip2.c"
+#endif
+
#ifdef CONFIG_KERNEL_GZIP
#include "../../../../lib/decompress_inflate.c"
#endif
+#ifdef CONFIG_KERNEL_LZ4
+#include "../../../../lib/decompress_unlz4.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZMA
+#include "../../../../lib/decompress_unlzma.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZO
+#include "../../../../lib/decompress_unlzo.c"
+#endif
+
+#ifdef CONFIG_KERNEL_XZ
+#include "../../../../lib/decompress_unxz.c"
+#endif
+
+#ifdef CONFIG_KERNEL_ZSTD
+#include "../../../../lib/decompress_unzstd.c"
+#endif
+
/* Scratch heap for the decompressors, larger than any of them needs. */
#define STUB_HEAP_SIZE (4 * 1024 * 1024)
--
2.54.0
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-12 19:55 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-12 19:55 [PATCH 0/3] alpha: self-extracting compressed kernel images Matt Turner
2026-09-12 19:55 ` [PATCH 1/3] xz: add arch-specific tuning for alpha Matt Turner
2026-09-12 19:55 ` [PATCH 2/3] alpha: add self-extracting compressed kernel boot stub Matt Turner
2026-09-12 19:55 ` [PATCH 3/3] alpha: support the remaining kernel compression formats Matt Turner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®