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 32case "${KBUILD_VERBOSE}" in 33*1*) 34 set -x 35 ;; 36esac 37 38# Exit the top-level shell with an error 39topshell=$$ 40trap 'exit 1' USR1 41die() { 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 49verify() { 50 if [ ! -f "$1" -o ! -r "$1" ]; then 51 die "Missing file: $1" 52 fi 53} 54 55diskfmt="$1" 56FIMAGE="$2" 57FBZIMAGE="$3" 58MTOOLSRC="$4" 59KCMDLINE="$5" 60shift 5 # Remaining arguments = initrd files 61 62export MTOOLSRC 63 64# common options for dd 65dd='dd iflag=fullblock' 66 67# Make sure the files actually exist 68verify "$FBZIMAGE" 69 70declare -a FDINITRDS 71irdpfx=' initrd=' 72initrdopts_syslinux='' 73initrdopts_efi='' 74for 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 82done 83 84# Read a $3-byte littleendian unsigned value at offset $2 from file $1 85le() { 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. 98efiarch() { 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 124filesizes() { 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 135sharedirs() { 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} 144efidirs() { 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 154findsyslinux() { 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 164findovmf() { 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 183do_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 200genbzdisk() { 201 verify "$MTOOLSRC" 202 mformat -v 'LINUX_BOOT' a: 203 syslinux "$FIMAGE" 204 do_mcopy a: 205} 206 207genfdimage144() { 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 215genfdimage288() { 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 223genhdimage() { 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 244geniso() { 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 262rm -f "$FIMAGE" 263 264case "$diskfmt" in 265 bzdisk) genbzdisk;; 266 fdimage144) genfdimage144;; 267 fdimage288) genfdimage288;; 268 hdimage) genhdimage;; 269 isoimage) geniso;; 270 *) die "Unknown image format: $diskfmt";; 271esac 272