| #!/bin/bash | 
 | # | 
 | # This file is subject to the terms and conditions of the GNU General Public | 
 | # License.  See the file "COPYING" in the main directory of this archive | 
 | # for more details. | 
 | # | 
 | # Copyright (C) 2017 by Changbin Du <changbin.du@intel.com> | 
 | # | 
 | # Adapted from code in arch/x86/boot/Makefile by H. Peter Anvin and others | 
 | # | 
 | # "make fdimage/fdimage144/fdimage288/hdimage/isoimage" | 
 | # script for x86 architecture | 
 | # | 
 | # Arguments: | 
 | #   $1  - fdimage format | 
 | #   $2  - target image file | 
 | #   $3  - kernel bzImage file | 
 | #   $4  - mtools configuration file | 
 | #   $5  - kernel cmdline | 
 | #   $6+ - initrd image file(s) | 
 | # | 
 | # This script requires: | 
 | #   bash | 
 | #   syslinux | 
 | #   genisoimage | 
 | #   mtools (for fdimage* and hdimage) | 
 | #   edk2/OVMF (for hdimage) | 
 | # | 
 | # Otherwise try to stick to POSIX shell commands... | 
 | # | 
 |  | 
 | # Use "make V=1" to debug this script | 
 | case "${KBUILD_VERBOSE}" in | 
 | *1*) | 
 |         set -x | 
 |         ;; | 
 | esac | 
 |  | 
 | # Exit the top-level shell with an error | 
 | topshell=$$ | 
 | trap 'exit 1' USR1 | 
 | die() { | 
 | 	echo ""        1>&2 | 
 | 	echo " *** $*" 1>&2 | 
 | 	echo ""        1>&2 | 
 | 	kill -USR1 $topshell | 
 | } | 
 |  | 
 | # Verify the existence and readability of a file | 
 | verify() { | 
 | 	if [ ! -f "$1" -o ! -r "$1" ]; then | 
 | 		die "Missing file: $1" | 
 | 	fi | 
 | } | 
 |  | 
 | diskfmt="$1" | 
 | FIMAGE="$2" | 
 | FBZIMAGE="$3" | 
 | MTOOLSRC="$4" | 
 | KCMDLINE="$5" | 
 | shift 5				# Remaining arguments = initrd files | 
 |  | 
 | export MTOOLSRC | 
 |  | 
 | # common options for dd | 
 | dd='dd iflag=fullblock' | 
 |  | 
 | # Make sure the files actually exist | 
 | verify "$FBZIMAGE" | 
 |  | 
 | declare -a FDINITRDS | 
 | irdpfx=' initrd=' | 
 | initrdopts_syslinux='' | 
 | initrdopts_efi='' | 
 | for f in "$@"; do | 
 | 	if [ -f "$f" -a -r "$f" ]; then | 
 | 	    FDINITRDS=("${FDINITRDS[@]}" "$f") | 
 | 	    fname="$(basename "$f")" | 
 | 	    initrdopts_syslinux="${initrdopts_syslinux}${irdpfx}${fname}" | 
 | 	    irdpfx=, | 
 | 	    initrdopts_efi="${initrdopts_efi} initrd=${fname}" | 
 | 	fi | 
 | done | 
 |  | 
 | # Read a $3-byte littleendian unsigned value at offset $2 from file $1 | 
 | le() { | 
 | 	local n=0 | 
 | 	local m=1 | 
 | 	for b in $(od -A n -v -j $2 -N $3 -t u1 "$1"); do | 
 | 		n=$((n + b*m)) | 
 | 		m=$((m * 256)) | 
 | 	done | 
 | 	echo $n | 
 | } | 
 |  | 
 | # Get the EFI architecture name such that boot{name}.efi is the default | 
 | # boot file name. Returns false with no output if the file is not an | 
 | # EFI image or otherwise unknown. | 
 | efiarch() { | 
 | 	[ -f "$1" ] || return | 
 | 	[ $(le "$1" 0 2) -eq 23117 ] || return		# MZ magic | 
 | 	peoffs=$(le "$1" 60 4)				# PE header offset | 
 | 	[ $peoffs -ge 64 ] || return | 
 | 	[ $(le "$1" $peoffs 4) -eq 17744 ] || return	# PE magic | 
 | 	case $(le "$1" $((peoffs+4+20)) 2) in		# PE type | 
 | 		267)	;;				# PE32 | 
 | 		523)	;;				# PE32+ | 
 | 		*) return 1 ;;				# Invalid | 
 | 	esac | 
 | 	[ $(le "$1" $((peoffs+4+20+68)) 2) -eq 10 ] || return # EFI app | 
 | 	case $(le "$1" $((peoffs+4)) 2) in		# Machine type | 
 | 		 332)	echo i386	;; | 
 | 		 450)	echo arm	;; | 
 | 		 512)	echo ia64	;; | 
 | 		20530)	echo riscv32	;; | 
 | 		20580)	echo riscv64	;; | 
 | 		20776)	echo riscv128	;; | 
 | 		34404)	echo x64	;; | 
 | 		43620)	echo aa64	;; | 
 | 	esac | 
 | } | 
 |  | 
 | # Get the combined sizes in bytes of the files given, counting sparse | 
 | # files as full length, and padding each file to cluster size | 
 | cluster=16384 | 
 | filesizes() { | 
 | 	local t=0 | 
 | 	local s | 
 | 	for s in $(ls -lnL "$@" 2>/dev/null | awk '/^-/{ print $5; }'); do | 
 | 		t=$((t + ((s+cluster-1)/cluster)*cluster)) | 
 | 	done | 
 | 	echo $t | 
 | } | 
 |  | 
 | # Expand directory names which should be in /usr/share into a list | 
 | # of possible alternatives | 
 | sharedirs() { | 
 | 	local dir file | 
 | 	for dir in /usr/share /usr/lib64 /usr/lib; do | 
 | 		for file; do | 
 | 			echo "$dir/$file" | 
 | 			echo "$dir/${file^^}" | 
 | 		done | 
 | 	done | 
 | } | 
 | efidirs() { | 
 | 	local dir file | 
 | 	for dir in /usr/share /boot /usr/lib64 /usr/lib; do | 
 | 		for file; do | 
 | 			echo "$dir/$file" | 
 | 			echo "$dir/${file^^}" | 
 | 		done | 
 | 	done | 
 | } | 
 |  | 
 | findsyslinux() { | 
 | 	local f="$(find -L $(sharedirs syslinux isolinux) \ | 
 | 		    -name "$1" -readable -type f -print -quit 2>/dev/null)" | 
 | 	if [ ! -f "$f" ]; then | 
 | 		die "Need a $1 file, please install syslinux/isolinux." | 
 | 	fi | 
 | 	echo "$f" | 
 | 	return 0 | 
 | } | 
 |  | 
 | findovmf() { | 
 | 	local arch="$1" | 
 | 	shift | 
 | 	local -a names=(-false) | 
 | 	local name f | 
 | 	for name; do | 
 | 		names=("${names[@]}" -or -iname "$name") | 
 | 	done | 
 | 	for f in $(find -L $(efidirs edk2 ovmf) \ | 
 | 			\( "${names[@]}" \) -readable -type f \ | 
 | 			-print 2>/dev/null); do | 
 | 		if [ "$(efiarch "$f")" = "$arch" ]; then | 
 | 			echo "$f" | 
 | 			return 0 | 
 | 		fi | 
 | 	done | 
 | 	die "Need a $1 file for $arch, please install EDK2/OVMF." | 
 | } | 
 |  | 
 | do_mcopy() { | 
 | 	if [ ${#FDINITRDS[@]} -gt 0 ]; then | 
 | 		mcopy "${FDINITRDS[@]}" "$1" | 
 | 	fi | 
 | 	if [ -n "$efishell" ]; then | 
 | 		mmd "$1"EFI "$1"EFI/Boot | 
 | 		mcopy "$efishell" "$1"EFI/Boot/boot${kefiarch}.efi | 
 | 	fi | 
 | 	if [ -n "$kefiarch" ]; then | 
 | 		echo linux "$KCMDLINE$initrdopts_efi" | \ | 
 | 			mcopy - "$1"startup.nsh | 
 | 	fi | 
 | 	echo default linux "$KCMDLINE$initrdopts_syslinux" | \ | 
 | 		mcopy - "$1"syslinux.cfg | 
 | 	mcopy "$FBZIMAGE" "$1"linux | 
 | } | 
 |  | 
 | genbzdisk() { | 
 | 	verify "$MTOOLSRC" | 
 | 	mformat -v 'LINUX_BOOT' a: | 
 | 	syslinux "$FIMAGE" | 
 | 	do_mcopy a: | 
 | } | 
 |  | 
 | genfdimage144() { | 
 | 	verify "$MTOOLSRC" | 
 | 	$dd if=/dev/zero of="$FIMAGE" bs=1024 count=1440 2>/dev/null | 
 | 	mformat -v 'LINUX_BOOT' v: | 
 | 	syslinux "$FIMAGE" | 
 | 	do_mcopy v: | 
 | } | 
 |  | 
 | genfdimage288() { | 
 | 	verify "$MTOOLSRC" | 
 | 	$dd if=/dev/zero of="$FIMAGE" bs=1024 count=2880 2>/dev/null | 
 | 	mformat -v 'LINUX_BOOT' w: | 
 | 	syslinux "$FIMAGE" | 
 | 	do_mcopy w: | 
 | } | 
 |  | 
 | genhdimage() { | 
 | 	verify "$MTOOLSRC" | 
 | 	mbr="$(findsyslinux mbr.bin)" | 
 | 	kefiarch="$(efiarch "$FBZIMAGE")" | 
 | 	if [ -n "$kefiarch" ]; then | 
 | 		# The efishell provides command line handling | 
 | 		efishell="$(findovmf $kefiarch shell.efi shell${kefiarch}.efi)" | 
 | 		ptype='-T 0xef'	# EFI system partition, no GPT | 
 | 	fi | 
 | 	sizes=$(filesizes "$FBZIMAGE" "${FDINITRDS[@]}" "$efishell") | 
 | 	# Allow 1% + 2 MiB for filesystem and partition table overhead, | 
 | 	# syslinux, and config files; this is probably excessive... | 
 | 	megs=$(((sizes + sizes/100 + 2*1024*1024 - 1)/(1024*1024))) | 
 | 	$dd if=/dev/zero of="$FIMAGE" bs=$((1024*1024)) count=$megs 2>/dev/null | 
 | 	mpartition -I -c -s 32 -h 64 $ptype -b 64 -a p: | 
 | 	$dd if="$mbr" of="$FIMAGE" bs=440 count=1 conv=notrunc 2>/dev/null | 
 | 	mformat -v 'LINUX_BOOT' -s 32 -h 64 -c $((cluster/512)) -t $megs h: | 
 | 	syslinux --offset $((64*512)) "$FIMAGE" | 
 | 	do_mcopy h: | 
 | } | 
 |  | 
 | geniso() { | 
 | 	tmp_dir="$(dirname "$FIMAGE")/isoimage" | 
 | 	rm -rf "$tmp_dir" | 
 | 	mkdir "$tmp_dir" | 
 | 	isolinux=$(findsyslinux isolinux.bin) | 
 | 	ldlinux=$(findsyslinux  ldlinux.c32) | 
 | 	cp "$isolinux" "$ldlinux" "$tmp_dir" | 
 | 	cp "$FBZIMAGE" "$tmp_dir"/linux | 
 | 	echo default linux "$KCMDLINE" > "$tmp_dir"/isolinux.cfg | 
 | 	if [ ${#FDINITRDS[@]} -gt 0 ]; then | 
 | 		cp "${FDINITRDS[@]}" "$tmp_dir"/ | 
 | 	fi | 
 | 	genisoimage -J -r -appid 'LINUX_BOOT' -input-charset=utf-8 \ | 
 | 		    -quiet -o "$FIMAGE" -b isolinux.bin \ | 
 | 		    -c boot.cat -no-emul-boot -boot-load-size 4 \ | 
 | 		    -boot-info-table "$tmp_dir" | 
 | 	isohybrid "$FIMAGE" 2>/dev/null || true | 
 | 	rm -rf "$tmp_dir" | 
 | } | 
 |  | 
 | rm -f "$FIMAGE" | 
 |  | 
 | case "$diskfmt" in | 
 | 	bzdisk)     genbzdisk;; | 
 | 	fdimage144) genfdimage144;; | 
 | 	fdimage288) genfdimage288;; | 
 | 	hdimage)    genhdimage;; | 
 | 	isoimage)   geniso;; | 
 | 	*)          die "Unknown image format: $diskfmt";; | 
 | esac |