BTX halted: migrating a FreeBSD server's boot system from MBR/Legacy to UEFI


Always nice to get cryptic boot errors when you mess up an upgrade

January 2023.
The FreeBSD logo

Introduction

I'm running a small server with a Supermicro X11SCL-F, a Micron SSD, and some hard disks in an encrypted raidz2 ZFS pool.

Hardware:

# geom disk list nvd0
Geom name: nvd0
Providers:
1. Name: nvd0
   Mediasize: 256060514304 (238G)
   Sectorsize: 512
   Mode: r2w2e4
   descr: Micron_2200_MTFDHBA256TCK
   lunid: 000000000000000100a1234567891234
   ident: 123456789123
   rotationrate: 0
   fwsectors: 0
   fwheads: 0

# dmidecode
[...]
Base Board Information
        Manufacturer: Supermicro
        Product Name: X11SCL-F
        Version: 1.01
        Serial Number: V12345678900
        Asset Tag: To be filled by O.E.M.
        Features:
                Board is a hosting board
                Board is replaceable
        Location In Chassis: To be filled by O.E.M.
        Chassis Handle: 0x0003
        Type: Motherboard
        Contained Object Handles: 0

Breaking the server

Let's login to it:

Last login: Mon Jan  9 14:30:49 2023 from myotherserver
FreeBSD 13.0-RELEASE-p7 (GENERIC) #0: Mon Jan 31 18:24:03 UTC 2022

Uh oh. This server is outdated! Let's update it:

# freebsd-update -r 13.1-RELEASE upgrade
Looking up update.FreeBSD.org mirrors... 2 mirrors found.
Fetching metadata signature for 13.0-RELEASE from update2.freebsd.org... done.
Fetching metadata index... done.
Fetching 1 metadata patches. done.
Applying metadata patches... done.
Inspecting system... done.

The following components of FreeBSD seem to be installed:
kernel/generic kernel/generic-dbg src/src world/base world/lib32

The following components of FreeBSD do not seem to be installed:
world/base-dbg world/lib32-dbg

Does this look reasonable (y/n)? y

[...]

To install the downloaded upgrades, run "/usr/sbin/freebsd-update install".
# /usr/sbin/freebsd-update install
Installing updates...
Kernel updates have been installed.  Please reboot and run
"/usr/sbin/freebsd-update install" again to finish installing updates.
# reboot

Oh no! the server is not booting anymore!

BTX Halted
Consoles: internal video/keyboard
[...]
BTX halted

SSHing into a live shell

Let's boot a FreeBSD ISO image and get into the shell:

You can run a shell from the FreeBSD distribution ISOs

Configure the network:

/sbin/dhclient igb0

Mount the system read/write:

/sbin/mount -u /

Edit /etc/ssh/sshd_config to allow root to login (or create a user and add it to the wheel group if you're one of those people who'd rather die than SSH as root)

Set a password:

/usr/bin/passwd

Start SSH:

/usr/sbin/service sshd onestart

Connect to SSH.

Fixing the boot system

Let's look at the partitions of the boot SSD:

# gpart show nvd0
=>       40  500118112  nvd0  GPT  (238G)
         40       1024     1  freebsd-boot  (512K)
       1064        984        - free -  (492K)
       2048   33554432     2  freebsd-swap  (16G)
   33556480  466561024     3  freebsd-zfs  (222G)
  500117504        648        - free -  (324K)

Looks like I forgot to migrate this server to UEFI. It's still in MBR. That's why it couldn't boot.

Let's fix that!

Delete the legacy boot partition:

# /sbin/gpart delete -i 1 nvd0
nvd0p1 deleted

Add an EFI partition instead:

# /sbin/gpart add -t efi -a 4k -l nvme-efi -i 1 nvd0
nvd0p1 added
# gpart show nvd0
=>       40  500118112  nvd0  GPT  (238G)
         40       2008     1  efi  (1.0M)
       2048   33554432     2  freebsd-swap  (16G)
   33556480  466561024     3  freebsd-zfs  (222G)
  500117504        648        - free -  (324K)

Format the EFI partition:

# /sbin/newfs_msdos -F 32 -c 1 /dev/gpt/nvme-efi
newfs_msdos: 1944 clusters too few clusters for FAT32, need 65525

Oops, we don't have enough space on the partition. Let's shrink the swap partition then:

# /sbin/gpart delete -i 1 nvd0
nvd0p1 deleted
# /sbin/gpart delete -i 2 nvd0
nvd0p2 deleted
# /sbin/gpart show nvd0
=>       40  500118112  nvd0  GPT  (238G)
         40   33556440        - free -  (16G)
   33556480  466561024     3  freebsd-zfs  (222G)
  500117504        648        - free -  (324K)

# /sbin/gpart add -t efi -a 4k -s 100M -l nvme-efi -i 1 nvd0
nvd0p1 added
# /sbin/gpart add -t freebsd-swap -i 2 nvd0
nvd0p2 added
# /sbin/gpart show nvd0
=>       40  500118112  nvd0  GPT  (238G)
         40     204800     1  efi  (100M)
     204840   33351640     2  freebsd-swap  (16G)
   33556480  466561024     3  freebsd-zfs  (222G)
  500117504        648        - free -  (324K)

Let's format now:

# /sbin/newfs_msdos -F 32 -c 1 /dev/gpt/nvme-efi
/dev/gpt/nvme-efi: 201616 sectors in 201616 FAT32 clusters (512 bytes/cluster)
BytesPerSec=512 SecPerClust=1 ResSectors=32 FATs=2 Media=0xf0 SecPerTrack=63 Heads=255 HiddenSecs=0 HugeSectors=204800 FATsecs=1576 RootCluster=2 FSInfo=1 Backup=2

Let's mount the partition and copy the EFI boot system into it:

# /bin/mkdir -p /mnt/boot/efi
# /sbin/mount -t msdosfs /dev/gpt/nvme-efi /mnt/boot/efi
# /bin/mkdir -p /mnt/boot/efi/EFI/BOOT
# /bin/cp /boot/loader.efi /mnt/boot/efi/EFI/BOOT/BOOTX64.efi

Reboot:

# /sbin/umount /mnt/boot/
# /sbin/reboot

Configuring the BIOS and booting

Configure the BIOS to boot the UEFI partition we just created

Configuring a SuperMicro BIOS to boot a UEFI hard drive.

Alright, we reached the bootloader. It's a success!

FreeBSD's loader