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