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 2010 - Writing up so as not to forget


I have a number of FreeBSD VMs that were build on old FreeBSD version  with MBR based disks. To help move these across to newer FreeBSD version I need 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: I have done this with 64 bit FreeBSD versions succesfully only. I had not had success with 32 bit FreeBSD and UEFI boot.


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)      <<=== MBR
        63  20964762    1  freebsd  [active]  (10G)
  20964825      6678       - free -  (3.3M)


---
--- do ls of /dev/da0* to see partitions
---
dispute-db# ls /dev/da0*
/dev/da0	/dev/da0s1a	/dev/da0s1d	/dev/da0s1f
/dev/da0s1	/dev/da0s1b	/dev/da0s1e

---
--- NOTE: The MBR partitioning show the each of the partitions as letter
---          With GPT partitions are given numbers...
---          To see which partition are associated with which dev
---            do df and look at fstab
---
# df -h
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/da0s1a    1.9G    213M    1.6G    12%    /
devfs          1.0K    1.0K      0B   100%    /dev
/dev/da0s1d    989M     64K    910M     0%    /tmp
/dev/da0s1f    2.9G    2.1G    590M    78%    /usr
/dev/da0s1e    1.9G    113M    1.7G     6%    /var
---
--- The missing partition from report is /dev/da0s1b which is swap
---    as is seen via fstab
---
# cat /etc/fstab
# Device		Mountpoint	FStype	Options		Dump	Pass#
/dev/da0s1b		none		swap	sw		0	0
/dev/da0s1a		/		ufs	rw		1	1
/dev/da0s1d		/tmp		ufs	rw		2	2
/dev/da0s1f		/usr		ufs	rw		2	2
/dev/da0s1e		/var		ufs	rw		2	2
/dev/acd0		/cdrom		cd9660	ro,noauto	0	0
---
--- Ok now we have all the informaiton on MBR partitioned file-system
---

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 can available to mount.

In my case I had 2 disk:

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 and in this case I will partition 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 content 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
---
# 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
# 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 to new GPT / UEFI
---

NOTE: The /dev disk naming is dependent on the disk driver being used the most common once are:

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

Hence you should use the "geom drive list" to get right name for you machine.


Clone the disk contents

Having created GPT disk to copy contents to the next thing is to copy content 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 from 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

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 with 
---
# 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 tar (if you are rsync expert use that...
---
# tar cf - OLD_ROOT | (cd /tmp/NEW_ROOT; tar xvf - --strip-components 1)
# tar cf - OLD_VAR | (cd /NEW_ROOT/var; tar xvf - --strip-components 1)
# tar cf - OLD_TMP | (cd /NEW_ROOT/tmp; tar xvf - --strip-components 1)
# tar cf - OLD_USR | (cd /NEW_ROOT/usr; tar xvf - --strip-components 1)

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.

This has cloned 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 on on the CD in the directory /boot. With FreeBSD 11.4 there is an image of the FAT16 boot partition ub: "/boot/boot1.efidat".

This can be mounted and the contents copied over to the new EFI FAT16 partition. (which is copied to efi/boot/BOOTx64.efi). So you can either create the EFI directory by copying from the CD into the EFI partition. The alternative is to simply mount the EFI partition from existing FreeBSD 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
---
# mount -t cd9660 /dev/cd0 /tmp/CDROM
---
--- Do loop mount of efi fs image from CD
---
# mdconfig -a -t vnode -f CDROM/boot/boot1.efidat
md0       <<== The /dev node created by mdconfig
# mount -t msdosfs -o ro /dev/md0 /tmp/IN-EFI  <<== older FreeBSD uses "-t msdos"
---
--- Mount target efi FAT16 partition
---
# mount -t msdosfs /dev/ada1s1 /tmp/OUT-EFI
---
--- Now copy the files: efi/boot/BOOTx64.efi + efi/boot/startup.nsh
---
# cd IN-EFI
# cp -R * ../OUT-EFI

The last thing is to check what will be the new "/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 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).


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