Skip to content
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions documentation/content/en/books/handbook/zfs/_index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1331,15 +1331,19 @@ For legacy boot using GPT, use the following command:
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1
....

For systems using EFI to boot, execute the following command:
For systems using EFI to boot, execute the following commands:

[source,shell]
....
# gpart bootcode -p /boot/boot1.efifat -i 1 ada1
# umount /boot/efi
# mount -t msdosfs /dev/ada1p1 /boot/efi
# cp /boot/loader.efi /boot/efi/efi/boot/boot*.efi
Copy link
Copy Markdown
Member

@bsdimp bsdimp Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The '*' here doesn't make sense.
It should be to bootx64.efi.
With a note somewhere saying that's architecture dependent (but ada is primarily a x86 thing) and please refer to this table for the name of other ports. I think that table is in loader.efi, in the examples.

Copy link
Copy Markdown
Author

@msimerson msimerson Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My newer devices present at ndaN because they're NVMe. Disks attached via SAS/SCSI (the CAM layer) present as daN. Disks attached via (S)ATA present at adaN. Some RAID controllers present differently. There's no universal command that'll work there, so perhaps it needs to be:

export BOOT_DEVICE="/dev/{daN | ndaN | adaN}"  # CUSTOMIZE THIS!
mount -t msdosfs "$BOOT_DEVICE" /boot/efi

The copy command with the * works across TIER 1 (and probably all other) supported architectures:

# ls /boot/efi/efi/boot/boot*.efi   
/boot/efi/efi/boot/bootaa64.efi  # uname -p = aarch64
/boot/efi/efi/boot/bootx64.efi   # uname -p = amd64

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there was a reasonable chance of it getting merged, I'd update this PR with this:

# Common EFI: /dev/nda0 (NVMe), /dev/ada0 (SATA), /dev/da0 (USB/SAS/SCSI)
# Note: For mirrored boot drives, update BOTH disks.

# export EFI_PARTITION="/dev/{ndaN | daN | adaN}"  # CUSTOMIZE THIS!
# mount | grep -q /boot/efi && umount /boot/efi
# mount -t msdosfs "$EFI_PARTITION" /boot/efi
# cp /boot/loader.efi /boot/efi/efi/boot/boot*.efi 
# cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
# umount /boot/efi

Copy link
Copy Markdown
Author

@msimerson msimerson Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more robust, and compared the more static commands above:

  • installs when no boot loader exists
  • works with all EFI platforms.
    • ARCH matches the two exceptions to the boot{ARCH}.efi naming convention.
    • other architectures (arm) work by default
  • doesn't require users to figure out partition names
  • improves on my in-house script that relied on an up-to-date /etc/fstab
    • EFI requires gpart partitions
# discover the EFI name for this systems CPU architecture
export ARCH=$(case "$(uname -p)" in aarch64) echo "aa64" ;; amd64) echo "x64" ;; *) echo "$(uname -p)" ;; esac)

for _efi_part in $(gpart show -p | grep ' efi ' | awk '{ print $3 }')
do
  echo; echo "    updating $ARCH EFI boot loader in $_efi_part"

  mount | grep -q 'on /boot/efi ' && umount /boot/efi
  mount -t msdosfs "/dev/$_efi_part" /boot/efi
  mkdir -p /boot/efi/efi/boot /boot/efi/efi/freebsd

  cp /boot/loader.efi "/boot/efi/efi/boot/boot${ARCH}.efi"
  cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi

  umount /boot/efi
done

Sample Output

amd64 (Intel)

    updating x64 EFI boot loader in mmcsd0p1
mount | grep -q /boot/efi && umount /boot/efi
mount -t msdosfs /dev/mmcsd0p1 /boot/efi
cp /boot/loader.efi /boot/efi/efi/boot/bootx64.efi
cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
umount /boot/efi

    updating x64 EFI boot loader in nda0p1
mount | grep -q /boot/efi && umount /boot/efi
mount -t msdosfs /dev/nda0p1 /boot/efi
cp /boot/loader.efi /boot/efi/efi/boot/bootx64.efi
cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
umount /boot/efi

    updating x64 EFI boot loader in nda1p1
mount | grep -q /boot/efi && umount /boot/efi
mount -t msdosfs /dev/nda1p1 /boot/efi
cp /boot/loader.efi /boot/efi/efi/boot/bootx64.efi
cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
umount /boot/efi

    updating x64 EFI boot loader in nda2p1
mount | grep -q /boot/efi && umount /boot/efi
mount -t msdosfs /dev/nda2p1 /boot/efi
cp /boot/loader.efi /boot/efi/efi/boot/bootx64.efi
cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
umount /boot/efi

ARM 64

    updating aa64 EFI boot loader in nda0p1
mount | grep -q /boot/efi && umount /boot/efi
mount -t msdosfs /dev/nda0p1 /boot/efi
cp /boot/loader.efi /boot/efi/efi/boot/bootaa64.efi
cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
umount /boot/efi

# cp /boot/loader.efi /boot/efi/efi/freebsd/loader.efi
# umount /boot/efi
....

Apply the bootcode to all bootable disks in the pool.
See man:gpart[8] for more information.
See man:gpart[8] and man:loader.efi[8] for more information.
====

[[zfs-zpool-history]]
Expand Down