#!/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 # # 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 # 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 cp "${FDINITRDS[@]}" "$tmp_dir"/ 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