aboutsummaryrefslogtreecommitdiff
path: root/tools/boot
diff options
context:
space:
mode:
authorRebecca Cran <bcran@FreeBSD.org>2018-12-20 19:39:37 +0000
committerRebecca Cran <bcran@FreeBSD.org>2018-12-20 19:39:37 +0000
commitdb8b56134506840832bec2d1ce07b9e00d4d6d71 (patch)
tree242e3d5aea577a1691fc784b6b35da9690e23d5c /tools/boot
parentd5cee48f3e65662051e15c85e4fc1841d72977fe (diff)
Notes
Diffstat (limited to 'tools/boot')
-rwxr-xr-xtools/boot/install-boot.sh205
-rwxr-xr-xtools/boot/rootgen.sh54
2 files changed, 198 insertions, 61 deletions
diff --git a/tools/boot/install-boot.sh b/tools/boot/install-boot.sh
index 54eb6bec97603..cf82ff056fe2f 100755
--- a/tools/boot/install-boot.sh
+++ b/tools/boot/install-boot.sh
@@ -10,6 +10,10 @@
# insert code here to guess what you have -- yikes!
+# Minimum size of FAT filesystems, in KB.
+fat32min=33292
+fat16min=2100
+
die() {
echo $*
exit 1
@@ -27,19 +31,150 @@ find-part() {
gpart show $dev | tail +2 | awk '$4 == "'$part'" { print $3; }'
}
-make_esp() {
- local dev dst mntpt
+get_uefi_bootname() {
+
+ case ${TARGET:-$(uname -m)} in
+ amd64) echo bootx64 ;;
+ arm64) echo bootaa64 ;;
+ i386) echo bootia32 ;;
+ arm) echo bootarm ;;
+ *) die "machine type $(uname -m) doesn't support UEFI" ;;
+ esac
+}
+
+make_esp_file() {
+ local file sizekb loader device mntpt fatbits efibootname
+
+ file=$1
+ sizekb=$2
+ loader=$3
+
+ if [ "$sizekb" -ge "$fat32min" ]; then
+ fatbits=32
+ elif [ "$sizekb" -ge "$fat16min" ]; then
+ fatbits=16
+ else
+ fatbits=12
+ fi
+
+ dd if=/dev/zero of="${file}" bs=1k count="${sizekb}"
+ device=$(mdconfig -a -t vnode -f "${file}")
+ newfs_msdos -F "${fatbits}" -c 1 -L EFISYS "/dev/${device}" > /dev/null 2>&1
+ mntpt=$(mktemp -d /tmp/stand-test.XXXXXX)
+ mount -t msdosfs "/dev/${device}" "${mntpt}"
+ mkdir -p "${mntpt}/EFI/BOOT"
+ efibootname=$(get_uefi_bootname)
+ cp "${loader}" "${mntpt}/EFI/BOOT/${efibootname}.efi"
+ umount "${mntpt}"
+ rmdir "${mntpt}"
+ mdconfig -d -u "${device}"
+}
+make_esp_device() {
+ local dev file mntpt fstype efibootname kbfree loadersize efibootfile
+ local isboot1 existingbootentryloaderfile bootorder bootentry
+
+ # ESP device node
dev=$1
- dst=$2
+ file=$2
- newfs_msdos -a 32 ${dev}
mntpt=$(mktemp -d /tmp/stand-test.XXXXXX)
- mount -t msdos ${dev} ${mntpt}
- mkdir -p ${mntpt}/efi/boot
- cp ${dst}/boot/loader.efi ${mntpt}/efi/boot/bootx64.efi
- umount ${mntpt}
- rmdir ${mntpt}
+
+ # See if we're using an existing (formatted) ESP
+ fstype=$(fstyp "${dev}")
+
+ if [ "${fstype}" != "msdosfs" ]; then
+ newfs_msdos -F 32 -c 1 -L EFISYS "${dev}" > /dev/null 2>&1
+ fi
+
+ mount -t msdosfs "${dev}" "${mntpt}"
+ if [ $? -ne 0 ]; then
+ die "Failed to mount ${dev} as an msdosfs filesystem"
+ fi
+
+ echo "Mounted ESP ${dev} on ${mntpt}"
+
+ efibootname=$(get_uefi_bootname)
+ kbfree=$(df -k "${mntpt}" | tail -1 | cut -w -f 4)
+ loadersize=$(stat -f %z "${file}")
+ loadersize=$((loadersize / 1024))
+
+ # Check if /EFI/BOOT/BOOTxx.EFI is the FreeBSD boot1.efi
+ # If it is, remove it to avoid leaving stale files around
+ efibootfile="${mntpt}/EFI/BOOT/${efibootname}.efi"
+ if [ -f "${efibootfile}" ]; then
+ isboot1=$(strings "${efibootfile}" | grep "FreeBSD EFI boot block")
+
+ if [ -n "${isboot1}" ] && [ "$kbfree" -lt "${loadersize}" ]; then
+ echo "Only ${kbfree}KB space remaining: removing old FreeBSD boot1.efi file /EFI/BOOT/${efibootname}.efi"
+ rm "${efibootfile}"
+ rmdir "${mntpt}/EFI/BOOT"
+ else
+ echo "${kbfree}KB space remaining on ESP: renaming old boot1.efi file /EFI/BOOT/${efibootname}.efi /EFI/BOOT/${efibootname}-old.efi"
+ mv "${efibootfile}" "${mntpt}/EFI/BOOT/${efibootname}-old.efi"
+ fi
+ fi
+
+ if [ ! -f "${mntpt}/EFI/freebsd/loader.efi" ] && [ "$kbfree" -lt "$loadersize" ]; then
+ umount "${mntpt}"
+ rmdir "${mntpt}"
+ echo "Failed to update the EFI System Partition ${dev}"
+ echo "Insufficient space remaining for ${file}"
+ echo "Run e.g \"mount -t msdosfs ${dev} /mnt\" to inspect it for files that can be removed."
+ die
+ fi
+
+ mkdir -p "${mntpt}/EFI/freebsd"
+
+ # Keep a copy of the existing loader.efi in case there's a problem with the new one
+ if [ -f "${mntpt}/EFI/freebsd/loader.efi" ] && [ "$kbfree" -gt "$((loadersize * 2))" ]; then
+ cp "${mntpt}/EFI/freebsd/loader.efi" "${mntpt}/EFI/freebsd/loader-old.efi"
+ fi
+
+ echo "Copying loader to /EFI/freebsd on ESP"
+ cp "${file}" "${mntpt}/EFI/freebsd/loader.efi"
+
+ existingbootentryloaderfile=$(efibootmgr -v | grep "${mntpt}//EFI/freebsd/loader.efi")
+
+ if [ -z "$existingbootentryloaderfile" ]; then
+ # Try again without the double forward-slash in the path
+ existingbootentryloaderfile=$(efibootmgr -v | grep "${mntpt}/EFI/freebsd/loader.efi")
+ fi
+
+ if [ -z "$existingbootentryloaderfile" ]; then
+ echo "Creating UEFI boot entry for FreeBSD"
+ efibootmgr --create --label FreeBSD --loader "${mntpt}/EFI/freebsd/loader.efi" > /dev/null
+ if [ $? -ne 0 ]; then
+ die "Failed to create new boot entry"
+ fi
+
+ # When creating new entries, efibootmgr doesn't mark them active, so we need to
+ # do so. It doesn't make it easy to find which entry it just added, so rely on
+ # the fact that it places the new entry first in BootOrder.
+ bootorder=$(efivar --name 8be4df61-93ca-11d2-aa0d-00e098032b8c-BootOrder --print --no-name --hex | head -1)
+ bootentry=$(echo "${bootorder}" | cut -w -f 3)$(echo "${bootorder}" | cut -w -f 2)
+ echo "Marking UEFI boot entry ${bootentry} active"
+ efibootmgr --activate "${bootentry}" > /dev/null
+ else
+ echo "Existing UEFI FreeBSD boot entry found: not creating a new one"
+ fi
+
+ umount "${mntpt}"
+ rmdir "${mntpt}"
+ echo "Finished updating ESP"
+}
+
+make_esp() {
+ local file loaderfile
+
+ file=$1
+ loaderfile=$2
+
+ if [ -f "$file" ]; then
+ make_esp_file ${file} ${fat32min} ${loaderfile}
+ else
+ make_esp_device ${file} ${loaderfile}
+ fi
}
make_esp_mbr() {
@@ -53,7 +188,7 @@ make_esp_mbr() {
die "No ESP slice found"
fi
fi
- make_esp /dev/${dev}s${s} ${dst}
+ make_esp /dev/${dev}s${s} ${dst}/boot/loader.efi
}
make_esp_gpt() {
@@ -64,7 +199,7 @@ make_esp_gpt() {
if [ -z "$idx" ] ; then
die "No ESP partition found"
fi
- make_esp /dev/${dev}p${idx} ${dst}
+ make_esp /dev/${dev}p${idx} ${dst}/boot/loader.efi
}
boot_nogeli_gpt_ufs_legacy() {
@@ -218,18 +353,32 @@ boot_nogeli_vtoc8_ufs_ofw() {
doit gpart bootcode -p ${vtoc8} ${dev}
}
-DESTDIR=/
+usage() {
+ printf 'Usage: %s -b bios [-d destdir] -f fs [-g geli] [-h] [-o optargs] -s scheme <bootdev>\n' "$0"
+ printf 'Options:\n'
+ printf ' bootdev device to install the boot code on\n'
+ printf ' -b bios bios type: legacy, uefi or both\n'
+ printf ' -d destdir destination filesystem root\n'
+ printf ' -f fs filesystem type: ufs or zfs\n'
+ printf ' -g geli yes or no\n'
+ printf ' -h this help/usage text\n'
+ printf ' -o optargs optional arguments\n'
+ printf ' -s scheme mbr or gpt\n'
+ exit 0
+}
+
+srcroot=/
# Note: we really don't support geli boot in this script yet.
geli=nogeli
-while getopts "b:d:f:g:o:s:" opt; do
+while getopts "b:d:f:g:ho:s:" opt; do
case "$opt" in
b)
bios=${OPTARG}
;;
d)
- DESTDIR=${OPTARG}
+ srcroot=${OPTARG}
;;
f)
fs=${OPTARG}
@@ -246,25 +395,35 @@ while getopts "b:d:f:g:o:s:" opt; do
s)
scheme=${OPTARG}
;;
+
+ ?|h)
+ usage
+ ;;
esac
done
-shift $((OPTIND-1))
-dev=$1
+if [ -n "${scheme}" ] && [ -n "${fs}" ] && [ -n "${bios}" ]; then
+ shift $((OPTIND-1))
+ dev=$1
+fi
# For gpt, we need to install pmbr as the primary boot loader
# it knows about
-gpt0=${DESTDIR}/boot/pmbr
-gpt2=${DESTDIR}/boot/gptboot
-gptzfs2=${DESTDIR}/boot/gptzfsboot
+gpt0=${srcroot}/boot/pmbr
+gpt2=${srcroot}/boot/gptboot
+gptzfs2=${srcroot}/boot/gptzfsboot
# For MBR, we have lots of choices, but select mbr, boot0 has issues with UEFI
-mbr0=${DESTDIR}/boot/mbr
-mbr2=${DESTDIR}/boot/boot
+mbr0=${srcroot}/boot/mbr
+mbr2=${srcroot}/boot/boot
# VTOC8
-vtoc8=${DESTDIR}/boot/boot1
+vtoc8=${srcroot}/boot/boot1
# sanity check here
-eval boot_${geli}_${scheme}_${fs}_${bios} $dev $DESTDIR $opts || echo "Unsupported boot env: ${geli}-${scheme}-${fs}-${bios}"
+# Check if we've been given arguments. If not, this script is probably being
+# sourced, so we shouldn't run anything.
+if [ -n "${dev}" ]; then
+ eval boot_${geli}_${scheme}_${fs}_${bios} $dev $srcroot $opts || echo "Unsupported boot env: ${geli}-${scheme}-${fs}-${bios}"
+fi
diff --git a/tools/boot/rootgen.sh b/tools/boot/rootgen.sh
index 87b541bdf4b09..4faf9335ca717 100755
--- a/tools/boot/rootgen.sh
+++ b/tools/boot/rootgen.sh
@@ -5,7 +5,8 @@
passphrase=passphrase
iterations=50000
-do_boot1_efi=0
+# The smallest FAT32 filesystem is 33292 KB
+espsize=33292
#
# Builds all the bat-shit crazy combinations we support booting from,
@@ -16,13 +17,13 @@ do_boot1_efi=0
# Sad panda sez: this runs as root, but could be userland if someone
# creates userland geli and zfs tools.
#
-# This assumes an external prograam install-boot.sh which will install
+# This assumes an external program install-boot.sh which will install
# the appropriate boot files in the appropriate locations.
#
# These images assume ada0 will be the root image. We should likely
# use labels, but we don't.
#
-# ASsumes you've already rebuilt... maybe bad? Also maybe bad: the env
+# Assumes you've already rebuilt... maybe bad? Also maybe bad: the env
# vars should likely be conditionally set to allow better automation.
#
@@ -34,29 +35,6 @@ cpsys() {
(cd $src ; tar cf - .) | (cd $dst; tar xf -)
}
-make_esp()
-{
- local src dst md mntpt
- src=$1
- dst=$2
-
- if [ "${do_boot1_efi}" -eq 1 ]; then
- cp ${src}/boot/boot1.efifat ${dst}
- else
- dd if=/dev/zero of=${dst} count=1 seek=$((100 * 1024 * 1024 / 512))
- md=$(mdconfig -f ${dst})
- newfs_msdos -a 32 /dev/${md}
- mntpt=$(mktemp -d /tmp/stand-test.XXXXXX)
- mount -t msdos /dev/${md} ${mntpt}
-# mkdir -p ${mntpt}/efi/freebsd # not yet
- mkdir -p ${mntpt}/efi/boot
- cp ${src}/boot/loader.efi ${mntpt}/efi/boot/bootx64.efi
- umount ${mntpt}
- rmdir ${mntpt}
- mdconfig -d -u ${md}
- fi
-}
-
mk_nogeli_gpt_ufs_legacy() {
src=$1
img=$2
@@ -78,7 +56,7 @@ mk_nogeli_gpt_ufs_uefi() {
cat > ${src}/etc/fstab <<EOF
/dev/ada0p2 / ufs rw 1 1
EOF
- make_esp ${src} ${img}.p1
+ make_esp_file ${img}.p1 ${espsize} ${src}
makefs -t ffs -B little -s 200m ${img}.p2 ${src}
mkimg -s gpt \
-p efi:=${img}.p1 \
@@ -93,7 +71,7 @@ mk_nogeli_gpt_ufs_both() {
cat > ${src}/etc/fstab <<EOF
/dev/ada0p3 / ufs rw 1 1
EOF
- make_esp ${src} ${img}.p1
+ make_esp_file ${img}.p1 ${espsize} ${src}
makefs -t ffs -B little -s 200m ${img}.p3 ${src}
# p1 is boot for uefi, p2 is boot for gpt, p3 is /
mkimg -b ${src}/boot/pmbr -s gpt \
@@ -155,7 +133,7 @@ mk_nogeli_gpt_zfs_uefi() {
dd if=/dev/zero of=${img} count=1 seek=$((200 * 1024 * 1024 / 512))
md=$(mdconfig -f ${img})
gpart create -s gpt ${md}
- gpart add -t efi -s 800k -a 4k ${md}
+ gpart add -t efi -s ${espsize}k -a 4k ${md}
gpart add -t freebsd-zfs -l root $md
# install-boot will make this bootable
zpool create -O mountpoint=none -R ${mntpt} ${pool} ${md}p2
@@ -193,7 +171,7 @@ mk_nogeli_gpt_zfs_both() {
dd if=/dev/zero of=${img} count=1 seek=$((200 * 1024 * 1024 / 512))
md=$(mdconfig -f ${img})
gpart create -s gpt ${md}
- gpart add -t efi -s 800k -a 4k ${md}
+ gpart add -t efi -s ${espsize}k -a 4k ${md}
gpart add -t freebsd-boot -s 400k -a 4k ${md} # <= ~540k
gpart add -t freebsd-zfs -l root $md
# install-boot will make this bootable
@@ -239,7 +217,7 @@ mk_nogeli_mbr_ufs_uefi() {
cat > ${src}/etc/fstab <<EOF
/dev/ada0s2a / ufs rw 1 1
EOF
- make_esp ${src} ${img}.s1
+ make_esp_file ${img}.s1 ${espsize} ${src}
makefs -t ffs -B little -s 200m ${img}.s2a ${src}
mkimg -s bsd -p freebsd-ufs:=${img}.s2a -o ${img}.s2
mkimg -a 1 -s mbr -p efi:=${img}.s1 -p freebsd:=${img}.s2 -o ${img}
@@ -253,7 +231,7 @@ mk_nogeli_mbr_ufs_both() {
cat > ${src}/etc/fstab <<EOF
/dev/ada0s2a / ufs rw 1 1
EOF
- make_esp ${src} ${img}.s1
+ make_esp_file ${img}.s1 ${espsize} ${src}
makefs -t ffs -B little -s 200m ${img}.s2a ${src}
mkimg -s bsd -b ${src}/boot/boot -p freebsd-ufs:=${img}.s2a -o ${img}.s2
mkimg -a 2 -s mbr -b ${src}/boot/mbr -p efi:=${img}.s1 -p freebsd:=${img}.s2 -o ${img}
@@ -313,7 +291,7 @@ mk_nogeli_mbr_zfs_uefi() {
dd if=/dev/zero of=${img} count=1 seek=$((200 * 1024 * 1024 / 512))
md=$(mdconfig -f ${img})
gpart create -s mbr ${md}
- gpart add -t \!239 -s 800k ${md}
+ gpart add -t efi -s ${espsize}k ${md}
gpart add -t freebsd ${md}
gpart set -a active -i 2 ${md}
gpart create -s bsd ${md}s2
@@ -354,7 +332,7 @@ mk_nogeli_mbr_zfs_both() {
dd if=/dev/zero of=${img} count=1 seek=$((200 * 1024 * 1024 / 512))
md=$(mdconfig -f ${img})
gpart create -s mbr ${md}
- gpart add -t \!239 -s 800k ${md}
+ gpart add -t efi -s ${espsize}k ${md}
gpart add -t freebsd ${md}
gpart set -a active -i 2 ${md}
gpart create -s bsd ${md}s2
@@ -430,7 +408,7 @@ mk_geli_gpt_ufs_uefi() {
dd if=/dev/zero of=${img} count=1 seek=$(( 200 * 1024 * 1024 / 512 ))
md=$(mdconfig -f ${img})
gpart create -s gpt ${md}
- gpart add -t efi -s 800k -a 4k ${md}
+ gpart add -t efi -s ${espsize}k -a 4k ${md}
gpart add -t freebsd-ufs -l root $md
# install-boot will make this bootable
echo ${passphrase} | geli init -bg -e AES-XTS -i ${iterations} -J - -l 256 -s 4096 ${md}p2
@@ -466,7 +444,7 @@ mk_geli_gpt_ufs_both() {
dd if=/dev/zero of=${img} count=1 seek=$(( 200 * 1024 * 1024 / 512 ))
md=$(mdconfig -f ${img})
gpart create -s gpt ${md}
- gpart add -t efi -s 800k -a 4k ${md}
+ gpart add -t efi -s ${espsize}k -a 4k ${md}
gpart add -t freebsd-boot -s 400k -a 4k ${md} # <= ~540k
gpart add -t freebsd-ufs -l root $md
# install-boot will make this bootable
@@ -547,7 +525,7 @@ mk_geli_gpt_zfs_uefi() {
dd if=/dev/zero of=${img} count=1 seek=$(( 200 * 1024 * 1024 / 512 ))
md=$(mdconfig -f ${img})
gpart create -s gpt ${md}
- gpart add -t efi -s 800k -a 4k ${md}
+ gpart add -t efi -s ${espsize}k -a 4k ${md}
gpart add -t freebsd-zfs -l root $md
# install-boot will make this bootable
echo ${passphrase} | geli init -bg -e AES-XTS -i ${iterations} -J - -l 256 -s 4096 ${md}p2
@@ -590,7 +568,7 @@ mk_geli_gpt_zfs_both() {
dd if=/dev/zero of=${img} count=1 seek=$(( 200 * 1024 * 1024 / 512 ))
md=$(mdconfig -f ${img})
gpart create -s gpt ${md}
- gpart add -t efi -s 800k -a 4k ${md}
+ gpart add -t efi -s ${espsize}k -a 4k ${md}
gpart add -t freebsd-boot -s 400k -a 4k ${md} # <= ~540k
gpart add -t freebsd-zfs -l root $md
# install-boot will make this bootable