1#!/bin/sh
2# SPDX-License-Identifier: 0BSD
3#
4# This is a wrapper for xz to compress the kernel image using appropriate
5# compression options depending on the architecture.
6#
7# Author: Lasse Collin <lasse.collin@tukaani.org>
8
9# This has specialized settings for the following archs. However,
10# XZ-compressed kernel isn't currently supported on every listed arch.
11#
12#   Arch        Align   Notes
13#   arm          2/4    ARM and ARM-Thumb2
14#   arm64         4
15#   csky          2
16#   loongarch     4
17#   mips         2/4    MicroMIPS is 2-byte aligned
18#   parisc        4
19#   powerpc       4     Uses its own wrapper for compressors instead of this.
20#   riscv        2/4
21#   s390          2
22#   sh            2
23#   sparc         4
24#   x86           1
25
26# A few archs use 2-byte or 4-byte aligned instructions depending on
27# the kernel config. This function is used to check if the relevant
28# config option is set to "y".
29is_enabled()
30{
31	grep -q "^$1=y$" include/config/auto.conf
32}
33
34# XZ_VERSION is needed to disable features that aren't available in
35# old XZ Utils versions.
36XZ_VERSION=$($XZ --robot --version) || exit
37XZ_VERSION=$(printf '%s\n' "$XZ_VERSION" | sed -n 's/^XZ_VERSION=//p')
38
39# Assume that no BCJ filter is available.
40BCJ=
41
42# Set the instruction alignment to 1, 2, or 4 bytes.
43#
44# Set the BCJ filter if one is available.
45# It must match the #ifdef usage in lib/decompress_unxz.c.
46case $SRCARCH in
47	arm)
48		if is_enabled CONFIG_THUMB2_KERNEL; then
49			ALIGN=2
50			BCJ=--armthumb
51		else
52			ALIGN=4
53			BCJ=--arm
54		fi
55		;;
56
57	arm64)
58		ALIGN=4
59
60		# ARM64 filter was added in XZ Utils 5.4.0.
61		if [ "$XZ_VERSION" -ge 50040002 ]; then
62			BCJ=--arm64
63		else
64			echo "$0: Upgrading to xz >= 5.4.0" \
65				"would enable the ARM64 filter" \
66				"for better compression" >&2
67		fi
68		;;
69
70	csky)
71		ALIGN=2
72		;;
73
74	loongarch)
75		ALIGN=4
76		;;
77
78	mips)
79		if is_enabled CONFIG_CPU_MICROMIPS; then
80			ALIGN=2
81		else
82			ALIGN=4
83		fi
84		;;
85
86	parisc)
87		ALIGN=4
88		;;
89
90	powerpc)
91		ALIGN=4
92
93		# The filter is only for big endian instruction encoding.
94		if is_enabled CONFIG_CPU_BIG_ENDIAN; then
95			BCJ=--powerpc
96		fi
97		;;
98
99	riscv)
100		if is_enabled CONFIG_RISCV_ISA_C; then
101			ALIGN=2
102		else
103			ALIGN=4
104		fi
105
106		# RISC-V filter was added in XZ Utils 5.6.0.
107		if [ "$XZ_VERSION" -ge 50060002 ]; then
108			BCJ=--riscv
109		else
110			echo "$0: Upgrading to xz >= 5.6.0" \
111				"would enable the RISC-V filter" \
112				"for better compression" >&2
113		fi
114		;;
115
116	s390)
117		ALIGN=2
118		;;
119
120	sh)
121		ALIGN=2
122		;;
123
124	sparc)
125		ALIGN=4
126		BCJ=--sparc
127		;;
128
129	x86)
130		ALIGN=1
131		BCJ=--x86
132		;;
133
134	*)
135		echo "$0: Arch-specific tuning is missing for '$SRCARCH'" >&2
136
137		# Guess 2-byte-aligned instructions. Guessing too low
138		# should hurt less than guessing too high.
139		ALIGN=2
140		;;
141esac
142
143# Select the LZMA2 options matching the instruction alignment.
144case $ALIGN in
145	1)  LZMA2OPTS= ;;
146	2)  LZMA2OPTS=lp=1 ;;
147	4)  LZMA2OPTS=lp=2,lc=2 ;;
148	*)  echo "$0: ALIGN wrong or missing" >&2; exit 1 ;;
149esac
150
151# Use single-threaded mode because it compresses a little better
152# (and uses less RAM) than multithreaded mode.
153#
154# For the best compression, the dictionary size shouldn't be
155# smaller than the uncompressed kernel. 128 MiB dictionary
156# needs less than 1400 MiB of RAM in single-threaded mode.
157#
158# On the archs that use this script to compress the kernel,
159# decompression in the preboot code is done in single-call mode.
160# Thus the dictionary size doesn't affect the memory requirements
161# of the preboot decompressor at all.
162exec $XZ --check=crc32 --threads=1 $BCJ --lzma2=$LZMA2OPTS,dict=128MiB
163