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