Page MenuHomeFreeBSD

D19588.id55146.diff
No OneTemporary

D19588.id55146.diff

Index: usr.sbin/efi-update-loader/efi-update-loader.8
===================================================================
--- /dev/null
+++ usr.sbin/efi-update-loader/efi-update-loader.8
@@ -0,0 +1,71 @@
+\"
+.\" Copyright (c) 2019 Rebecca Cran <bcran@freebsd.org>.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 16, 2019
+.Dt EFI-UPDATE-LOADER 8
+.Os
+.Sh NAME
+.Nm efi-update-loader
+.Nd Update an EFI System Partition with a FreeBSD loader
+.Sh SYNOPSIS
+.Nm
+.Op Fl d Ar device
+.Op Fl l Ar loader
+.Op Fl v
+.Sh DESCRIPTION
+This program updates the
+.Dq Unified Extensible Firmware Interface
+.Pq UEFI
+.Dq EFI System Partition
+.Pq ESP
+with a new FreeBSD loader.efi file.
+
+The ESP is a FAT12, FAT16 or FAT32 filesystem that is used by the UEFI system
+firmware to load and run OS boot loaders that are compiled as
+.Dq Portable Executable
+.Pq PE
+binaries. The UEFI Boot Manager, which can be configured with the
+.Xr efibootmgr 8
+utility, contains entries which point to the location of the boot loader
+within the ESP.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl d Ar device
+Specify the device to use as the ESP.
+.It Fl l Ar loader
+Specify the file to install as the FreeBSD boot loader. This should normally
+be /boot/loader.efi, but could also for example be /boot/loader_4th.efi etc.
+.It Fl v
+Enable verbose output
+.Sh SEE ALSO
+.Xr efibootmgr 8 ,
+.Xr efivar 8
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 13.0
Index: usr.sbin/efi-update-loader/efi-update-loader.sh
===================================================================
--- /dev/null
+++ usr.sbin/efi-update-loader/efi-update-loader.sh
@@ -0,0 +1,277 @@
+#!/bin/sh
+#
+# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+#
+# Copyright (c) 2019 Rebecca Cran <bcran@FreeBSD.org>.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+set -e
+
+vout() {
+ if [ -n "${verbose}" ]; then
+ echo "$@"
+ fi
+}
+
+
+# Find the name of the default boot loader on the current architecture.
+# This file is in the /EFI/BOOT directory on the ESP.
+get_uefi_bootname() {
+
+ case ${TARGET:-$(uname -m)} in
+ amd64) echo bootx64 ;;
+ arm64) echo bootaa64 ;;
+ i386) echo bootia32 ;;
+ arm) echo bootarm ;;
+ *)
+ echo "machine type $(uname -m) doesn't support UEFI"
+ exit 1
+ ;;
+ esac
+}
+
+
+clean_up() {
+ if [ -z "${mntpt}" ]; then
+ exit 1
+ fi
+
+ if mount | grep -q "${mntpt}" ; then
+ umount "${mntpt}"
+ fi
+
+ if [ -d "${mntpt}" ]; then
+ rmdir "${mntpt}"
+ fi
+}
+
+
+# Determine whether /EFI/BOOT/BOOTxxx.efi is the FreeBSD boot1.efi executable.
+bootefi_is_freebsd() {
+
+ efibootname=$(get_uefi_bootname)
+
+ if [ -f "${mntpt}/EFI/BOOT/${efibootname}.efi" ]; then
+ boot1asbootefi=$(grep "FreeBSD EFI boot block" "${mntpt}/EFI/BOOT/${efibootname}.efi") || true
+
+ if [ -n "${boot1asbootefi}" ]; then
+ echo "true"
+ fi
+ fi
+}
+
+
+# Find all ESPs on the same disk(s) as the root filesystem.
+detect_esps() {
+ mnt=/
+ fsname=$(df "${mnt}" | tail -1 | cut -d ' ' -f 1)
+ fstype=
+
+ if df -t ufs "${mnt}" > /dev/null ; then
+ fstype=ufs
+ elif df -t zfs "${mnt}" > /dev/null ; then
+ fstype=zfs
+ fi
+
+ if [ "${fstype}" = "zfs" ]; then
+ fslabel=$(df "${mnt}" | tail -1 | awk -F '[ /]' '{print $1}')
+ zpool=$(zpool list -Hv "${fslabel}")
+ totallines=$(echo "${zpool}" | wc -l)
+ devlines=$(echo "${zpool}" | tail -$((totallines - 1)))
+ label=$(echo "${devlines}" | awk '{print $1}')
+ elif [ "${fstype}" = "ufs" ]; then
+ label=$(echo "${fsname}" | cut -c 6-256)
+
+ for class in mirror raid raid3 vinum stripe virstor; do
+ label=$(g${class} status -s 2> /dev/null | grep "${label}" | awk '{print $3}') || true
+ if [ -n "${label}" ]; then
+ break
+ fi
+ done
+ fi
+
+ for l in ${label}; do
+ dev=$(geom label status -s | grep "${l}" | awk '{print $3}')
+ if [ -n "${dev}" ]; then
+ d="${dev}"
+ else
+ d="${l}"
+ fi
+
+ disk="${disk} $(echo "${d}" | awk -F '[ps]+[0-9]+' '{print $1}')"
+ done
+
+ for d in ${disk}; do
+ idx=$(gpart show "${d}" 2> /dev/null | grep efi | awk '{print $3}')
+ if [ -n "${idx}" ]; then
+ if [ -e "/dev/${d}p${idx}" ]; then
+ esps="${esps} /dev/${d}p${idx}"
+ elif [ -e "/dev/${d}s${idx}" ]; then
+ esps="${esps} /dev/${d}s${idx}"
+ fi
+ fi
+ done
+
+ if [ -n "${verbose}" ]; then
+ echo -n "Found ESP(S): "
+ for esp in ${esps}; do
+ echo -n "${esp} "
+ done
+ echo
+ fi
+}
+
+
+# Return the free disk space, in KB, on the mounted ESP.
+get_freespace_on_esp() {
+ df -k "${mntpt}" | tail -1 | awk '{print $4}'
+}
+
+
+copyloader() {
+ mntpt=$(mktemp -d /tmp/esp.XXXXXX)
+ espdev=$1
+
+ mount -t msdosfs "${espdev}" "${mntpt}"
+
+ ldrsize=$(stat -f %z "${loader}")
+ # Convert to KB
+ ldrsize=$((ldrsize / 1024))
+
+ efibootname=$(get_uefi_bootname)
+
+ if [ ! -d "${mntpt}/EFI" ]; then
+ mkdir "${mntpt}/EFI"
+ fi
+
+ if [ ! -d "${mntpt}/EFI/FreeBSD" ]; then
+ mkdir "${mntpt}/EFI/FreeBSD"
+ fi
+
+ # If /EFI/BOOT/BOOTxxx.efi is the FreeBSD boot1.efi, we need to move it out
+ # of the way so we can subsequently boot from /EFI/FreeBSD/loader.efi
+ if [ -n "$(bootefi_is_freebsd)" ]; then
+ echo "Moving FreeBSD bootx64.efi to /EFI/FreeBSD/${efibootname}-old.efi"
+ mv "${mntpt}/EFI/BOOT/${efibootname}.efi" "${mntpt}/EFI/FreeBSD/${efibootname}-old.efi"
+ fi
+
+ # If we already have /EFI/FreeBSD/loader.efi, we need to fetch its file size
+ # to calculate if we have enough space left to back it up.
+ if [ -f "${mntpt}/EFI/FreeBSD/loader.efi" ]; then
+ existing_ldr_size=$(stat -f %z "${mntpt}/EFI/FreeBSD/loader.efi")
+ existing_ldr_size=$((existing_ldr_size / 1024))
+ fi
+
+ # Now, we decide if we need to, or can, back up the existing loader.efi
+ # We'll back it up if we have enough space left, and it's difference from
+ # the new loader.efi
+ if [ -f "${mntpt}/EFI/FreeBSD/loader.efi" ] && ! cmp -sz "${loader}" "${mntpt}/EFI/FreeBSD/loader.efi"; then
+ # Check we have enough free space
+ if [ ! -e "${mntpt}/EFI/FreeBSD/loader-old.efi" ] && [ $(($(get_freespace_on_esp))) -lt ${existing_ldr_size} ] ; then
+ echo "Insufficient space on ESP to back up loader.efi; skipping backup"
+ else
+ eval vout "Backing up /EFI/FreeBSD/loader.efi to /EFI/FreeBSD/loader-old.efi"
+ cp "${mntpt}/EFI/FreeBSD/loader.efi" "${mntpt}/EFI/FreeBSD/loader-old.efi"
+ fi
+ fi
+
+ if [ -e "${mntpt}/EFI/FreeBSD/loader.efi" ]; then
+ spaceneeded=$((existing_ldr_size - ldrsize))
+ else
+ spaceneeded=${ldrsize}
+ fi
+
+ if [ $(($(get_freespace_on_esp))) -lt ${spaceneeded} ]; then
+ echo "Error: Insufficient space on ESP ${espdev} to install ${loader}."
+ eval clean_up
+ exit 1
+ fi
+
+ eval vout "Copying ${loader} to /EFI/FreeBSD/loader.efi"
+ cp "${loader}" "${mntpt}/EFI/FreeBSD/loader.efi"
+
+ if ! efibootmgr -v | grep -qi "EFI/FreeBSD/loader.efi" ; then
+ echo "Boot Option for FreeBSD doesn't exist: it's recommended to run efibootmgr. e.g.:"
+ echo " efibootmgr -c -a -L FreeBSD -l /mnt/EFI/FreeBSD/loader.efi"
+ fi
+
+ umount "${mntpt}"
+ rmdir "${mntpt}"
+}
+
+
+usage() {
+ printf 'usage: %s -d [espdev] -l [loader]\n' "${progname}"
+ printf '\t-d ESP device\n'
+ printf '\t-l FreeBSD EFI loader\n'
+ printf '\t-v Verbose output\n'
+ exit 0
+}
+
+
+progname=$0
+loader=/boot/loader.efi
+
+while getopts "vd:l:h" opt; do
+ case "$opt" in
+ d)
+ esps=${OPTARG}
+ ;;
+ l)
+ loader=${OPTARG}
+ ;;
+ v)
+ verbose=1
+ ;;
+ ?)
+ usage
+ ;;
+ esac
+done
+
+trap clean_up 1 2 15 EXIT
+
+# If the user didn't specify a device to update, look for any ESPs on the same
+# disk(s) as the root filesystem.
+if [ -z "${espdev}" ]; then
+
+ eval detect_esps
+
+ if [ -z "${esps}" ]; then
+ echo "Error: could not detect ESP containing FreeBSD loader to update"
+ exit 1
+ fi
+fi
+
+if [ -z "${esps}" ]; then
+ eval usage
+ exit 1
+fi
+
+for esp in ${esps}; do
+ eval copyloader "${esp}" "${loader}"
+done
+
+trap 1 2 15 EXIT

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 20, 9:57 AM (11 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25720132
Default Alt Text
D19588.id55146.diff (10 KB)

Event Timeline