Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F136769100
D19588.id55146.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D19588.id55146.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D19588: Add a new efi-update-loader script and associated man page
Attached
Detach File
Event Timeline
Log In to Comment