Converting FreeBSD from bios / mbr to UEFI / GPT

Converting an existing bios/mbr installation to UEFI/GPT is a mechanistic exercise, requiring a spare disk and some expertise in gpart disk management tool. My example is virtual but the same basic process would also work with a physical machine.

Converting FreeBSD from bios / mbr to UEFI / GPT

BIOS / MBR based disks layout in FreeBSD is messy as historically this created a single  Partition and then the FreeBSD UFS files systems was embedded inside this. To convert your machine to UEFI/GPT based one you will need to make sure you have FreeBSD 7 or greater (to get GPT support) and be able to use the FreeBSD command line disk partitioning tools.

Status: 16 Sept 2020 / Late Dec 2020 - Writing up so as not to forget


I have a number of FreeBSD VMs that were build on older FreeBSD versions  with MBR based disks. To help move these across to newer FreeBSD versions I needed to first move the disk to GPT and change them from bios to UEFI bootable.

Here is the process:

  1. Add new disk to your machine
  2. Boot from CDROM
  3. Create new GPT partition on the new disk
  4. Add FAT partition for UFI boot
  5. If you old disk is slit up into individual partitions then decide if you want to bring everything together under a single root partition
  6. Create new UFS partition/s on new disk
  7. Copy partitions from old to new disk
  8. Setup UEFI
  9. Update /etc/fstab to reflect new layout

NOTE #1: I have only done this sucessfully with 64 bit FreeBSD versions. I have had no success with 32 bit FreeBSD and UEFI boot.

NOTE #2: For 32 bit (i386) machines with GPT support (> FreeBSD 7), you can convert fro mbr -> GPT but will need to create a "freebsd-boot" partition which holds special boot record to allow bios boot from GPT.  See section: "Legacy BIOS machine option, use gptboot" below for information on this.


List disks & get partition information

In FreeBSD you can find disk by looking at the /dev tree for ad, cd, da and other disk device name or list the "geometry class device" (from the day of spinning disk): "geom disk list" and the partition information via "df"  and reviewing "/etc/fstab" & /dev file system:

---
--- show the attached disk
---
# geom disk list
Geom name: da0
Providers:
1. Name: da0
   Mediasize: 10737418240 (10G)
   Sectorsize: 512
   Mode: r5w5e14
   fwsectors: 63
   fwheads: 255

---
--- show the partition type
---
# gpart show da0
=>      63  20971440  da0  MBR  (10G)      <<=== 0 1 2 63 6678 20964762 20964825 mbr freebsd [active] (10g) - free (3.3m) --- do ls of dev da0* to see partitions dispute-db# da0 da0s1a da0s1d da0s1f da0s1 da0s1b da0s1e note: the partitioning show each as letter with gpt are given numbers... which partition associated df and look at fstab # -h filesystem size used avail capacity mounted on 1.9g 213m 1.6g 12% devfs 1.0k 0b 100% 989m 64k 910m 0% tmp 2.9g 2.1g 590m 78% usr 113m 1.7g 6% var missing from report is swap seen via cat etc device mountpoint fstype options dump pass# none sw ufs rw acd0 cdrom cd9660 ro,noauto ok now we have all information partitioned file-system ---< code>

Create GPT Disk with EFI Partition

Having found the details of your disk (see "List disks & get partition information" above) you can now determine which disk partitions are available to mount.

In my case I had two disks:

da0 - orginal FreeBSD with MBR partitioning using entire disk and connected via QEMU lsi1068 SCSI controller.

ad8 - the target SATA connected disk that will be GPT partitioned. I partitioned this as follows:

  • efi (fat16) - this is UEFI boot partition which is formatted as FAT16 and will contain the replacement for the MBR boot record
  • freebsd-ufs - create a single UFS partition and copy all the previously seperate: / (root), /usr, /var & /tmp partitions contents to this, so that it consolidates under single partition, as having physical seperation is not required in virtual environment.
  • freebsd-swap - use remaining space for swap

NOTE: The following example uses tiny disk for illustrative purposes.

To create new GPT / EFI ready disk use gpart to: create GPT partitioned disk and then add the 3 partitions as above:

---
--- 1. Create GPT partition
--
# gpart create -s GPT ad8
ad8 created
# gpart show ad8
=>     34  4194237  ad8  GPT  (2.0G)
       34  4194237       - free -  (2.0G)

---
--- 2. Now add 200M efi boot partition
---
dispute-db# gpart add -t efi -s 200M -i 1 ad8
ad8p1 added
# gpart show ad8
=>     34  4194237  ad8  GPT  (2.0G)
       34   409600    1  efi  (200M)
   409634  3784637       - free -  (1.8G)

---
--- 3. Add the ufs file-system partition
---
# gpart add -t freebsd-ufs -s 1G -i 2 ad8
ad8p2 added
# gpart show ad8
=>     34  4194237  ad8  GPT  (2.0G)
       34   409600    1  efi  (200M)
   409634  2097152    2  freebsd-ufs  (1.0G)
  2506786  1687485       - free -  (824M)

---
--- 4. Use the remaining space for SWAP, this is optional
---
dispute-db# gpart add -t freebsd-swap -i 3 ad8
ad8p3 added
dispute-db# gpart show ad8
=>     34  4194237  ad8  GPT  (2.0G)
       34   409600    1  efi  (200M)
   409634  2097152    2  freebsd-ufs  (1.0G)
  2506786  1687485    3  freebsd-swap  (824M)

---
--- 5. Create file systems
---
--- 5a. First the dos fs
---
# newfs_msdos /dev/ad8p1
newfs_msdos: trim 37 sectors to adjust to a multiple of 63
/dev/ad8p1: 409328 sectors in 25583 FAT16 clusters (8192 bytes/cluster)
BytesPerSec=512 SecPerClust=16 ResSectors=1 FATs=2 RootDirEnts=512 Media=0xf0 FATsecs=100 SecPerTrack=63 Heads=16 HiddenSecs=0 HugeSectors=409563
---
--- 5b. Second the ufs fs
---
# newfs /dev/ad8p2
/dev/ad8p2: 1024.0MB (2097152 sectors) block size 16384, fragment size 2048
	using 6 cylinder groups of 183.77MB, 11761 blks, 23552 inodes.
super-block backups (for fsck -b #) at:
 160, 376512, 752864, 1129216, 1505568, 1881920
---
--- 6. Next need to copy from old MBR file contents to new GPT / UEFI disk
---     (see - "Clone the disk contents" below)
---

NOTE: The "/dev" file system disk naming is dependent on the disk driver being used the most common ones are:

  • ada - SATA on newer FreeBSD
  • da - SCSI
  • ad - ATA/SATA on older FreeBSD
  • vda - VirtIO driver

Use the "geom disk list" to get right device name for you machine.


Clone the disk contents

Having created GPT disk, next you need to copy contents from old disk to new disk.

This can be done with tar or rsync, which you use if personal preference. I have successfully used tar with no issues. With tar the important thing it is to backup of the entire containing directory not from within the containing directory.

The process is:

  1. Reboot from Live CD
  2. Mount each of the source and target directories
  3. Clone the source directory to target
  4. Copy EFI boot directory contents
  5. Update "/etc/fstab" to be consistent with new disk driver (and naming)

Here is sample run on machine booted via install CD and selecting "Live CD" startup:

---
--- Following on from previous example, mount the directorys
---   NOTE: This is all done via root login
---
# cd /tmp
# mkdir OLD_ROOT OLD_VAR OLD_TMP OLD_USR NEW_ROOT
# mount -t ufs /dev/da0s1a /tmp/OLD_ROOT
# mount -t ufs /dev/da0s1d /tmp/OLD_TMP
# mount -t ufs /dev/da0s1f /tmp/OLD_USR
# mount -t ufs /dev/da0s1e /tmp/OLD_VAR
# mount -t ufs /dev/ad8s2 /tmp/NEW_ROOT   <<=== s2 as s1 is for efi --- copy the directory contents using tar or rsync this example uses (if you are expert use that...) # cf - old_root | (cd tmp new_root; xvf --strip-components 1) old_var new_root var; old_tmp tmp; old_usr usr; 1)< code>

NOTE: The tar works as it takes a copy of the entire directory tree, so when we restore, we need to strip off the initial directory path, hence "--strip-components 1" option.

Having copied all the contents from the 4 seperate partitions into single root partition. We now need to copy EFI files into the EFI (FAT32) partition. These are on the CD in the directory /boot. With FreeBSD 11.x there is an image of the FAT16 boot partition in: "/boot/boot1.efifat".

This can be mounted and the contents copied over to the new EFI FAT16 partition. Doing mount and copy is better options than doing dd overwrite with image (boot1.efifat), as your EFI partition may not have same size of that of image. The alternative is to simply mount the EFI partition from existing FreeBSD disk of right version and copy this,.

This example does mount of CDROM image and then copies content across:

---
--- Mount the two EFI partitions
---
# cd tmp
# mkdir CDROM IN-EFI OUT-EFI
---
--- Mount FreeBSD DVD
---   Note: not required if booted into Live CD environment
---
# mount -t cd9660 /dev/cd0 /tmp/CDROM
---
--- Do loop mount of efi fs image from CD
---
# mdconfig -a -t vnode -f CDROM/boot/boot1.efifat
md0       <<== the dev node created by mdconfig # mount -t msdosfs -o ro md0 tmp in-efi <<="=" older freebsd uses "-t msdos" --- or if you are in live cd environment: -a vnode -f boot boot1.efifat target efi fat16 partition ada1s1 out-efi now copy files: bootx64.efi + startup.nsh cp -r * .. out-efi< code>

The last thing is to check the newly cloned  "/etc/fstab" file under the NEW_ROOT and ensure it refers to the correct / (root) mount and /dev/<FILE>.

NOTE: mount now uses "-t msdosfs" rather than plain "-t msdos"


Change VM / Machine to UEFI (OVMF) boot

The new disk you have now created is only suitable for UEFI booting. So if you are running this as VM, then you will need to update the VM descriptor to use UEFI boot.

On physical machine this is typically done via initial boot systems setup screen (pressing F1 or F10 or some other key at boot) and changing the boot mode.


Legacy BIOS machine option, use gptboot

For very old i368 machines you can convert to GPT with legacy bios boot by creating a disk partion with dedicated freebsd-boot partition. Here is an example on SATA controller on i386 FreeBSD 8.4:

# gpart show ad4
=>       40  115343280  ad4  GPT  (55G)
         40       1024    1  freebsd-boot  (512k)
       1064  100663296    2  freebsd-ufs  (48G)
  100664360   12288000    3  freebsd-swap  (5.9G)
  112952360    2390960       - free -  (1.1G)

Again via gpart you can instal gptboot into the freebad-boot partition: "gpart bootcode -p /boot/gptboot -i 1 ada0"

Do "man gptboot" and "man gpart" for details.

A lazy way is to:

  1. do a GPT install on legacy bios machine on a clean disk and
  2. then verify this boots up ok then
  3. clear out the root partition of this disk by simply doing "newfs" to clobber the root install and
  4. then copying old mbr system over as per the "Clone Disk Contents" section above.

Moving to gptboot has some advantages as you can have single big partition and migrate from there to newer i368 FreeBSD (this stops at 11.4)


References & Links:

gpart - the FreeBSD command line disk partitioning tool

BSD Handbook - "17.2 Adding Disks" section provide some initial starter tips, but you will quickly need more information

rsync - to copy the content of old disk to new disk, while preserving all the attributes

tar - another way to copy the contents from old disk to new disk, while preserving the attributes

FreeBSD UEFI Boot - is well described in the man page: uefi

Install UEFI via "gpart bootcode ..." - as outlined in FreeBSD forums, this essentially does equivalent of dd of the "/boot/boot1.efidat" to target efi partition, that I explicitly mounted and copied in my example

For not UEFI (ie legacy bios) you need to install gptboot, into dedicated freebsd_boot partition (first partition)