GNU Linux-libre 5.15.137-gnu
[releases.git] / arch / x86 / boot / genimage.sh
1 #!/bin/bash
2 #
3 # This file is subject to the terms and conditions of the GNU General Public
4 # License.  See the file "COPYING" in the main directory of this archive
5 # for more details.
6 #
7 # Copyright (C) 2017 by Changbin Du <changbin.du@intel.com>
8 #
9 # Adapted from code in arch/x86/boot/Makefile by H. Peter Anvin and others
10 #
11 # "make fdimage/fdimage144/fdimage288/hdimage/isoimage"
12 # script for x86 architecture
13 #
14 # Arguments:
15 #   $1  - fdimage format
16 #   $2  - target image file
17 #   $3  - kernel bzImage file
18 #   $4  - mtools configuration file
19 #   $5  - kernel cmdline
20 #   $6+ - initrd image file(s)
21 #
22 # This script requires:
23 #   bash
24 #   syslinux
25 #   mtools (for fdimage* and hdimage)
26 #   edk2/OVMF (for hdimage)
27 #
28 # Otherwise try to stick to POSIX shell commands...
29 #
30
31 # Use "make V=1" to debug this script
32 case "${KBUILD_VERBOSE}" in
33 *1*)
34         set -x
35         ;;
36 esac
37
38 # Exit the top-level shell with an error
39 topshell=$$
40 trap 'exit 1' USR1
41 die() {
42         echo ""        1>&2
43         echo " *** $*" 1>&2
44         echo ""        1>&2
45         kill -USR1 $topshell
46 }
47
48 # Verify the existence and readability of a file
49 verify() {
50         if [ ! -f "$1" -o ! -r "$1" ]; then
51                 die "Missing file: $1"
52         fi
53 }
54
55 diskfmt="$1"
56 FIMAGE="$2"
57 FBZIMAGE="$3"
58 MTOOLSRC="$4"
59 KCMDLINE="$5"
60 shift 5                         # Remaining arguments = initrd files
61
62 export MTOOLSRC
63
64 # common options for dd
65 dd='dd iflag=fullblock'
66
67 # Make sure the files actually exist
68 verify "$FBZIMAGE"
69
70 declare -a FDINITRDS
71 irdpfx=' initrd='
72 initrdopts_syslinux=''
73 initrdopts_efi=''
74 for f in "$@"; do
75         if [ -f "$f" -a -r "$f" ]; then
76             FDINITRDS=("${FDINITRDS[@]}" "$f")
77             fname="$(basename "$f")"
78             initrdopts_syslinux="${initrdopts_syslinux}${irdpfx}${fname}"
79             irdpfx=,
80             initrdopts_efi="${initrdopts_efi} initrd=${fname}"
81         fi
82 done
83
84 # Read a $3-byte littleendian unsigned value at offset $2 from file $1
85 le() {
86         local n=0
87         local m=1
88         for b in $(od -A n -v -j $2 -N $3 -t u1 "$1"); do
89                 n=$((n + b*m))
90                 m=$((m * 256))
91         done
92         echo $n
93 }
94
95 # Get the EFI architecture name such that boot{name}.efi is the default
96 # boot file name. Returns false with no output if the file is not an
97 # EFI image or otherwise unknown.
98 efiarch() {
99         [ -f "$1" ] || return
100         [ $(le "$1" 0 2) -eq 23117 ] || return          # MZ magic
101         peoffs=$(le "$1" 60 4)                          # PE header offset
102         [ $peoffs -ge 64 ] || return
103         [ $(le "$1" $peoffs 4) -eq 17744 ] || return    # PE magic
104         case $(le "$1" $((peoffs+4+20)) 2) in           # PE type
105                 267)    ;;                              # PE32
106                 523)    ;;                              # PE32+
107                 *) return 1 ;;                          # Invalid
108         esac
109         [ $(le "$1" $((peoffs+4+20+68)) 2) -eq 10 ] || return # EFI app
110         case $(le "$1" $((peoffs+4)) 2) in              # Machine type
111                  332)   echo i386       ;;
112                  450)   echo arm        ;;
113                  512)   echo ia64       ;;
114                 20530)  echo riscv32    ;;
115                 20580)  echo riscv64    ;;
116                 20776)  echo riscv128   ;;
117                 34404)  echo x64        ;;
118                 43620)  echo aa64       ;;
119         esac
120 }
121
122 # Get the combined sizes in bytes of the files given, counting sparse
123 # files as full length, and padding each file to a 4K block size
124 filesizes() {
125         local t=0
126         local s
127         for s in $(ls -lnL "$@" 2>/dev/null | awk '/^-/{ print $5; }'); do
128                 t=$((t + ((s+4095)/4096)*4096))
129         done
130         echo $t
131 }
132
133 # Expand directory names which should be in /usr/share into a list
134 # of possible alternatives
135 sharedirs() {
136         local dir file
137         for dir in /usr/share /usr/lib64 /usr/lib; do
138                 for file; do
139                         echo "$dir/$file"
140                         echo "$dir/${file^^}"
141                 done
142         done
143 }
144 efidirs() {
145         local dir file
146         for dir in /usr/share /boot /usr/lib64 /usr/lib; do
147                 for file; do
148                         echo "$dir/$file"
149                         echo "$dir/${file^^}"
150                 done
151         done
152 }
153
154 findsyslinux() {
155         local f="$(find -L $(sharedirs syslinux isolinux) \
156                     -name "$1" -readable -type f -print -quit 2>/dev/null)"
157         if [ ! -f "$f" ]; then
158                 die "Need a $1 file, please install syslinux/isolinux."
159         fi
160         echo "$f"
161         return 0
162 }
163
164 findovmf() {
165         local arch="$1"
166         shift
167         local -a names=(-false)
168         local name f
169         for name; do
170                 names=("${names[@]}" -or -iname "$name")
171         done
172         for f in $(find -L $(efidirs edk2 ovmf) \
173                         \( "${names[@]}" \) -readable -type f \
174                         -print 2>/dev/null); do
175                 if [ "$(efiarch "$f")" = "$arch" ]; then
176                         echo "$f"
177                         return 0
178                 fi
179         done
180         die "Need a $1 file for $arch, please install EDK2/OVMF."
181 }
182
183 do_mcopy() {
184         if [ ${#FDINITRDS[@]} -gt 0 ]; then
185                 mcopy "${FDINITRDS[@]}" "$1"
186         fi
187         if [ -n "$efishell" ]; then
188                 mmd "$1"EFI "$1"EFI/Boot
189                 mcopy "$efishell" "$1"EFI/Boot/boot${kefiarch}.efi
190         fi
191         if [ -n "$kefiarch" ]; then
192                 echo linux "$KCMDLINE$initrdopts_efi" | \
193                         mcopy - "$1"startup.nsh
194         fi
195         echo default linux "$KCMDLINE$initrdopts_syslinux" | \
196                 mcopy - "$1"syslinux.cfg
197         mcopy "$FBZIMAGE" "$1"linux
198 }
199
200 genbzdisk() {
201         verify "$MTOOLSRC"
202         mformat -v 'LINUX_BOOT' a:
203         syslinux "$FIMAGE"
204         do_mcopy a:
205 }
206
207 genfdimage144() {
208         verify "$MTOOLSRC"
209         $dd if=/dev/zero of="$FIMAGE" bs=1024 count=1440 2>/dev/null
210         mformat -v 'LINUX_BOOT' v:
211         syslinux "$FIMAGE"
212         do_mcopy v:
213 }
214
215 genfdimage288() {
216         verify "$MTOOLSRC"
217         $dd if=/dev/zero of="$FIMAGE" bs=1024 count=2880 2>/dev/null
218         mformat -v 'LINUX_BOOT' w:
219         syslinux "$FIMAGE"
220         do_mcopy w:
221 }
222
223 genhdimage() {
224         verify "$MTOOLSRC"
225         mbr="$(findsyslinux mbr.bin)"
226         kefiarch="$(efiarch "$FBZIMAGE")"
227         if [ -n "$kefiarch" ]; then
228                 # The efishell provides command line handling
229                 efishell="$(findovmf $kefiarch shell.efi shell${kefiarch}.efi)"
230                 ptype='-T 0xef' # EFI system partition, no GPT
231         fi
232         sizes=$(filesizes "$FBZIMAGE" "${FDINITRDS[@]}" "$efishell")
233         # Allow 1% + 1 MiB for filesystem and partition table overhead,
234         # syslinux, and config files
235         megs=$(((sizes + sizes/100 + 2*1024*1024 - 1)/(1024*1024)))
236         $dd if=/dev/zero of="$FIMAGE" bs=$((1024*1024)) count=$megs 2>/dev/null
237         mpartition -I -c -s 32 -h 64 -t $megs $ptype -b 512 -a h:
238         $dd if="$mbr" of="$FIMAGE" bs=440 count=1 conv=notrunc 2>/dev/null
239         mformat -v 'LINUX_BOOT' -s 32 -h 64 -t $megs h:
240         syslinux --offset $((512*512)) "$FIMAGE"
241         do_mcopy h:
242 }
243
244 geniso() {
245         tmp_dir="$(dirname "$FIMAGE")/isoimage"
246         rm -rf "$tmp_dir"
247         mkdir "$tmp_dir"
248         isolinux=$(findsyslinux isolinux.bin)
249         ldlinux=$(findsyslinux  ldlinux.c32)
250         cp "$isolinux" "$ldlinux" "$tmp_dir"
251         cp "$FBZIMAGE" "$tmp_dir"/linux
252         echo default linux "$KCMDLINE" > "$tmp_dir"/isolinux.cfg
253         cp "${FDINITRDS[@]}" "$tmp_dir"/
254         genisoimage -J -r -appid 'LINUX_BOOT' -input-charset=utf-8 \
255                     -quiet -o "$FIMAGE" -b isolinux.bin \
256                     -c boot.cat -no-emul-boot -boot-load-size 4 \
257                     -boot-info-table "$tmp_dir"
258         isohybrid "$FIMAGE" 2>/dev/null || true
259         rm -rf "$tmp_dir"
260 }
261
262 rm -f "$FIMAGE"
263
264 case "$diskfmt" in
265         bzdisk)     genbzdisk;;
266         fdimage144) genfdimage144;;
267         fdimage288) genfdimage288;;
268         hdimage)    genhdimage;;
269         isoimage)   geniso;;
270         *)          die "Unknown image format: $diskfmt";;
271 esac