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".
29 is_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.
36 XZ_VERSION=$($XZ --robot --version) || exit
37 XZ_VERSION=$(printf '%s\n' "$XZ_VERSION" | sed -n 's/^XZ_VERSION=//p')
38 
39 # Assume that no BCJ filter is available.
40 BCJ=
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.
46 case $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 		;;
141 esac
142 
143 # Select the LZMA2 options matching the instruction alignment.
144 case $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 ;;
149 esac
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.
162 exec $XZ --check=crc32 --threads=1 $BCJ --lzma2=$LZMA2OPTS,dict=128MiB
163