forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
6.4 KiB
271 lines
6.4 KiB
#!/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 <[email protected]> |
|
# |
|
# 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 a 4K block size |
|
filesizes() { |
|
local t=0 |
|
local s |
|
for s in $(ls -lnL "$@" 2>/dev/null | awk '/^-/{ print $5; }'); do |
|
t=$((t + ((s+4095)/4096)*4096)) |
|
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% + 1 MiB for filesystem and partition table overhead, |
|
# syslinux, and config files |
|
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 -t $megs $ptype -b 512 -a h: |
|
$dd if="$mbr" of="$FIMAGE" bs=440 count=1 conv=notrunc 2>/dev/null |
|
mformat -v 'LINUX_BOOT' -s 32 -h 64 -t $megs h: |
|
syslinux --offset $((512*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
|
|
|