Skip to content

Commit

Permalink
Mount the EFI system partition (ESP) on newly-installed systems.
Browse files Browse the repository at this point in the history
Per hier(7), the ESP will be mounted at /boot/efi. On UFS systems,
any existing ESP will be reused and mounted there; otherwise, a new one
will be made. On ZFS systems, space for an ESP is allocated on all disks
in the root pool, but only the partition actually used to boot is set up
and mounted.

This makes future upgrades of the EFI loader easier (upgrade scripts can
just change /boot/efi) and also greatly simplifies the parts of the
installer involved in initialization of the ESP. It also makes the
installer's behavior correspond to the documentation in hier(7).

Reviewed by:		imp, tsoome
MFC after:		1 week
Relnotes:		yes
Differential Revision:	https://reviews.freebsd.org/D28897
  • Loading branch information
nwhitehorn committed Feb 23, 2021
1 parent ba6e37e commit 0b7472b
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 138 deletions.
12 changes: 1 addition & 11 deletions usr.sbin/bsdinstall/partedit/gpart_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -707,18 +707,8 @@ set_default_part_metadata(const char *name, const char *scheme,
if (strcmp(type, "freebsd-swap") == 0)
mountpoint = "none";
if (strcmp(type, bootpart_type(scheme, &default_bootmount)) == 0) {
if (default_bootmount == NULL) {

int fd = openat(tmpdfd, "bsdinstall-esps",
O_CREAT | O_WRONLY | O_APPEND, 0600);
if (fd > 0) {
write(fd, md->name, strlen(md->name));
write(fd, "\n", 1);
close(fd);
}

if (default_bootmount == NULL)
md->bootcode = 1;
}
else if (mountpoint == NULL || strlen(mountpoint) == 0)
mountpoint = default_bootmount;
}
Expand Down
1 change: 1 addition & 0 deletions usr.sbin/bsdinstall/partedit/partedit_efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ bootpart_type(const char *scheme, const char **mountpoint)
{

/* Only EFI is supported as boot partition */
*mountpoint = "/boot/efi";
return ("efi");
}

Expand Down
4 changes: 3 additions & 1 deletion usr.sbin/bsdinstall/partedit/partedit_x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,10 @@ const char *
bootpart_type(const char *scheme, const char **mountpoint)
{

if (strcmp(x86_bootmethod(), "UEFI") == 0)
if (strcmp(x86_bootmethod(), "UEFI") == 0) {
*mountpoint = "/boot/efi";
return ("efi");
}

return ("freebsd-boot");
}
Expand Down
150 changes: 26 additions & 124 deletions usr.sbin/bsdinstall/scripts/bootconfig
Original file line number Diff line number Diff line change
Expand Up @@ -46,84 +46,8 @@ if [ `uname -m` == powerpc ]; then
fi
fi

# Update the ESP (EFI System Partition) with the new bootloader
if [ "$(uname -m)" = "amd64" ] || [ "$(uname -m)" = "i386" ]; then
X86_BOOTMETHOD=$(sysctl -n machdep.bootmethod)
fi

if [ "$(uname -m)" = "arm64" ] || [ "$(uname -m)" = "riscv" ] || [ "$X86_BOOTMETHOD" = "UEFI" ]; then
UFSBOOT_ESPS=$(cat $TMPDIR/bsdinstall-esps 2>/dev/null)
ZFSBOOT_DISKS=$(cat $TMPDIR/bsdinstall-zfsboot 2>/dev/null)
num_esps=0

if [ -n "$ZFSBOOT_DISKS" ]; then
# We're in a ZFS install environment
for disk in $ZFSBOOT_DISKS; do
index=$(gpart show "$disk" | cut -w -f 4,5 | grep "efi" | cut -w -f 1)
# Check that $index is an integer
[ -n "$index" ] && [ "$index" -eq "$index" ] && [ "$index" -ge 0 ] 2> /dev/null
if [ $? -ne 0 ]; then
continue
fi

if [ -e "/dev/${disk}p${index}" ]; then
ESPS="$ESPS ${disk}p${index}"
elif [ -e "/dev/${disk}s${index}" ]; then
ESPS="$ESPS ${disk}s${index}"
else
continue
fi

num_esps=$((num_esps + 1))
done
fi

if [ -n "$UFSBOOT_ESPS" ]; then
# We're in a UFS install environment
for partition in $UFSBOOT_ESPS; do
ESPS="$ESPS $partition"
num_esps=$((num_esps + 1))
done
fi

if [ -z "$ESPS" ]; then
# The installer hasn't given us any ESPs to use.
# Try and figure out which to use by looking for an
# unformatted efi partition

for geom in $(gpart status -sg | awk '{print $1}'); do
hasfreebsd=$(gpart show "${geom}" | cut -w -f 4,5 | grep "freebsd")
if [ -n "$hasfreebsd" ]; then
index=$(gpart show "${geom}" | cut -w -f 4,5 | grep "efi" | cut -w -f 1)
# Check that $index is a valid integer
[ -n "$index" ] && [ "$index" -eq "$index" ] && [ "$index" -ge 0 ] 2> /dev/null
if [ $? -ne 0 ]; then
continue
fi

mntpt=$(mktemp -d $TMPDIR/stand-test.XXXXXX)
if [ -e "/dev/${geom}p${index}" ]; then
dev=${geom}p${index}
elif [ -e "/dev/${geom}s${index}" ]; then
dev=/${geom}s${index}
else
continue
fi

# Try and mount it. If it fails, assume it's
# unformatted and should be used.
mount -t msdosfs -o ro "/dev/${dev}" "${mntpt}"
if [ $? -ne 0 ]; then
ESPS="$ESPS ${dev}"
num_esps=$((num_esps + 1))
else
umount "${mntpt}"
fi
rmdir "${mntpt}"
fi
done
fi

# Update the ESP (EFI System Partition) with the new bootloader if we have an ESP
if [ -d "$BSDINSTALL_CHROOT/boot/efi" ]; then
case $(uname -m) in
arm64) ARCHBOOTNAME=aa64 ;;
amd64) ARCHBOOTNAME=x64 ;;
Expand All @@ -136,55 +60,33 @@ if [ "$(uname -m)" = "arm64" ] || [ "$(uname -m)" = "riscv" ] || [ "$X86_BOOTMET
BOOTNAME="${BOOTDIR}/boot${ARCHBOOTNAME}.efi"
FREEBSD_BOOTDIR="/efi/freebsd"
FREEBSD_BOOTNAME="${FREEBSD_BOOTDIR}/loader.efi"
mntpt="$BSDINSTALL_CHROOT/boot/efi"

f_dprintf "Installing loader.efi onto ESP"
mkdir -p "${mntpt}/${FREEBSD_BOOTDIR}" "${mntpt}/${BOOTDIR}"
cp "$BSDINSTALL_CHROOT/boot/loader.efi" "${mntpt}/${FREEBSD_BOOTNAME}"

#
# The following shouldn't be necessary. UEFI defines a way to
# specifically select what to boot (which we do via
# efibootmgr). However, virtual environments often times lack
# support for the NV variables efibootmgr sets. In addition,
# some UEFI implementations have features that interfere with
# the setting of these variables. To combat that, we install the
# default removable media boot file as a fallback if it doesn't
# exist. We don't install it all the time since that can
# interfere with other installations on the drive (like rEFInd).
#
if [ ! -f "${mntpt}/${BOOTNAME}" ]; then
cp "$BSDINSTALL_CHROOT/boot/loader.efi" "${mntpt}/${BOOTNAME}"
fi

for esp in $ESPS; do
f_dprintf "Formatting /dev/${esp} as FAT32"
newfs_msdos -F 32 -c 1 -L EFISYS "/dev/$esp" > /dev/null 2>&1
if [ $? -ne 0 ]; then
die "Failed to format ESP $esp as FAT32"
fi

mntpt=$(mktemp -d $TMPDIR/stand-test.XXXXXX)
f_dprintf "Mounting ESP /dev/${esp}"
mount -t msdosfs "/dev/${esp}" "${mntpt}"
if [ $? -ne 0 ]; then
die "Failed to mount ESP ${dev} on ${mntpt}"
fi

f_dprintf "Installing loader.efi onto ESP"
mkdir -p "${mntpt}/${FREEBSD_BOOTDIR}" "${mntpt}/${BOOTDIR}"
cp "$BSDINSTALL_CHROOT/boot/loader.efi" "${mntpt}/${FREEBSD_BOOTNAME}"

#
# The following shouldn't be necessary. UEFI defines a way to
# specifically select what to boot (which we do via
# efibootmgr). However, virtual environments often times lack
# support for the NV variables efibootmgr sets. In addition,
# some UEFI implementations have features that interfere with
# the setting of these variables. To combat that, we install the
# default removable media boot file as a fallback if it doesn't
# exist. We don't install it all the time since that can
# interfere with other installations on the drive (like rEFInd).
#
if [ ! -f "${mntpt}/${BOOTNAME}" ]; then
cp "$BSDINSTALL_CHROOT/boot/loader.efi" "${mntpt}/${BOOTNAME}"
fi

if [ "$num_esps" -gt 1 ]; then
bootlabel="FreeBSD (${esp})"
else
bootlabel="FreeBSD"
fi

f_dprintf "Creating UEFI boot entry"
efibootmgr --create --activate --label "$bootlabel" --loader "${mntpt}/${FREEBSD_BOOTNAME}" > /dev/null
bootlabel="FreeBSD"

f_dprintf "Unmounting ESP"
umount "${mntpt}"
rmdir "${mntpt}"
f_dprintf "Creating UEFI boot entry"
efibootmgr --create --activate --label "$bootlabel" --loader "${mntpt}/${FREEBSD_BOOTNAME}" > /dev/null

f_dprintf "Finished configuring /dev/${esp} as ESP"
done
f_dprintf "Finished configuring ESP"
fi

# Add boot0cfg for MBR BIOS booting?
19 changes: 17 additions & 2 deletions usr.sbin/bsdinstall/scripts/zfsboot
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ KLDLOAD='kldload %s'
LN_SF='ln -sf "%s" "%s"'
MKDIR_P='mkdir -p "%s"'
MOUNT_TYPE='mount -t %s "%s" "%s"'
NEWFS_ESP='newfs_msdos "%s"'
PRINTF_CONF="printf '%s=\"%%s\"\\\n' %s >> \"%s\""
PRINTF_FSTAB='printf "$FSTAB_FMT" "%s" "%s" "%s" "%s" "%s" "%s" >> "%s"'
SHELL_TRUNCATE=':> "%s"'
Expand Down Expand Up @@ -845,12 +846,25 @@ zfs_create_diskpart()
if [ "$ZFSBOOT_BOOT_TYPE" = "UEFI" -o \
"$ZFSBOOT_BOOT_TYPE" = "BIOS+UEFI" ]
then
f_eval_catch $funcname gpart \
f_eval_catch -k justaddedpart $funcname gpart \
"$GPART_ADD_ALIGN_LABEL_WITH_SIZE" \
"$align_small" efiboot$index efi 200M \
"$align_small" efiboot$index efi 260M \
$disk || return $FAILURE

# We'll configure the ESP in bootconfig
if [ -z "$efibootpart" ]; then
efibootpart="/dev/$(echo $justaddedpart | cut -f 1 -d ' ')"
f_dprintf "$funcname: configuring ESP at [%s]" \
"${efibootpart}"

f_eval_catch $funcname newfs_msdos "$NEWFS_ESP"\
"$efibootpart" \
|| return $FAILURE
f_eval_catch $funcname printf "$PRINTF_FSTAB" \
$efibootpart /boot/efi msdosfs \
rw 2 2 "$BSDINSTALL_TMPETC/fstab" \
|| return $FAILURE
fi
fi

if [ "$ZFSBOOT_BOOT_TYPE" = "BIOS" -o \
Expand Down Expand Up @@ -1066,6 +1080,7 @@ zfs_create_boot()
local isswapmirror
local bootpart targetpart swappart # Set by zfs_create_diskpart() below
local create_options
local efibootpart

#
# Pedantic checks; should never be seen
Expand Down

0 comments on commit 0b7472b

Please sign in to comment.