UEFI

This page is dedicated to the FreeBSD Foundation-sponsored project to support booting FreeBSD under UEFI.

Abstract

This project aims to allow FreeBSD to boot under UEFI on the amd64 platform. This primarily involves adding code to build a version of loader that can run as an EFI application and removing any dependencies on BIOS presence and patterns from the kernel. Additional work will be done to add the ability to create UEFI-bootable CD/DVD images. Lastly, some groundwork will be done to permit further work to allow FreeBSD to boot with UEFI Secure Boot enabled.

Support for loading and booting i386 kernels was removed from the initial infrastructure project as the preponderance of systems that require UEFI support will be 64-bit. i386 support will be implemented at a later time.

UEFI arm64 support is under development in a subversion projects branch; this is not part of the FreeBSD Foundation-sponsored project, but Foundation-sponsored work should accommodate / support the arm64 project where possible.

Repository

The code was merged to FreeBSD-HEAD in r264095. Development was originally done in the projects/uefi branch of the Subversion repository.

Virtualised Development Environment

If you wish to test this code under a virtual environment, UEFI firmware images are available for qemu. Assuming you have a version of qemu greater than 0.9.1, you can download the OVMF images from here. Once I've downloaded the images and unpacked them, I run:

> cp OVMF.fd bios.bin
> cp CirrusLogic5446.rom vgabios-cirrus.bin

Note: The default firmware filename in later QEMU versions is bios-256k.bin instead.

Then to test the code, I run:

> qemu-system-x86_64 -serial stdio -L . -hda fat:<path to boot directory>

Alternatively, to test UEFI CD support:

> qemu-system-x86_64 -serial stdio -L . -cdrom <path to ISO image>

The boot directory contains my built loader.efi as well as any kernel I want to boot.

Real Hardware Gotchas

These are some issues I have run into when using real hardware (ie, not qemu).

Bootable UEFI memory stick

To test UEFI booting on a memory stick, create a GPT partition table with a small EFI partition and the rest of the space dedicated to a FreeBSD UFS partition:

gpart create -s gpt da0
gpart add -t efi -s 32M da0
gpart add -t freebsd-ufs da0
newfs_msdos /dev/da0p1
newfs /dev/da0p2

Perform the install to the UFS partition, as usual:

mount /dev/da0p2 /mnt
make DESTDIR=/mnt installkernel installworld distribution
echo "/dev/da0p2 / ufs rw 1 1" >> /mnt/etc/fstab
umount /mnt

TODO: Use a label for the root fs instead

Mount the EFI system partition on /mnt and create required directories:

mount -t msdosfs /dev/da0p1 /mnt
mkdir -p /mnt/efi/boot /mnt/boot

Copy the first-stage loader to the EFI system partition:

cp <objdir path>/sys/boot/amd64/boot1.efi/boot1.efi /mnt/efi/boot/BOOTx64.efi

Set up loader.conf:

echo 'beastie_disable="YES"' > /mnt/boot/loader.conf

Create etc/fstab.

umount /mnt                                                                     

CD/DVD Boot under UEFI

The approach for creating a bootable CD/DVD image for UEFI is to create a FAT filesystem image containing your loader code as it would be laid out in an EFI System Partition. This image is then attached to the CD/DVD image as a non-emulation El Torito boot image. To make an image that is bootable under both legacy BIOS and UEFI, the BIOS image is placed first and the UEFI image is placed as an alternate. More information can be found here.

A sample boot ISO can be created using the following steps.

Create a FAT filesystem image and place our loader in it in the default path that UEFI will look for:

> dd if=/dev/zero of=efiboot.img bs=4k count=100
> mdconfig -a -t vnode -f efiboot.img
> newfs_msdos -F 12 -m 0xf8 /dev/md0
> mount -t msdosfs /dev/md0 /mnt
> mkdir -p /mnt/efi/boot
> cp loader.efi /mnt/efi/boot/bootx64.efi
> umount /mnt
> mdconfig -d -u 0

We now have our UEFI boot image. The next step is to make the ISO image. We assume that you have a directory called image containing the file structure you want in your ISO.

> makefs -t cd9660 -o bootimage='i386;efiboot.img' -o no-emul-boot -o rockridge -o label="UEFItest" -o publisher="test" uefi-test.iso image

You should now have an ISO image in uefitest.iso that will boot the loader. Unfortunately there is currently an issue which prevents this loader from seeing the filesystem on the CD. This is due to overzealous filtering of available partitions. This is being looked in to.

The version that will most likely end up in the distribution build will be slightly different, in that it will have multiple boot images attached in order to support BIOS and UEFI. This one will look something like this:

> makefs -t cd9660 -o 'bootimage=i386;efiboot.img' -o no-emul-boot -o 'bootimage=i386;/boot/cdboot' -o no-emul-boot -o rockridge -o label="UEFItest" -o publisher="test" uefi-test.iso image

Secure Boot

Thankfully, Matthew Garrett's shim loader is under a license that appears to be compatible with the BSDL. This means we can use this as a first-stage loader that can then load a signed version of our EFI loader and so on. The primary issue is building up a signing infrastructure and adding the ability to check signatures to loader and the module loader inside kernel. Secondarily, some interfaces such as /dev/mem may need to be modified or removed under secure boot.

More detail is on the SecureBoot page.

Console

Since there's no BIOS, there's no VGA BIOS and thus syscons has a hard time setting up a console on an attached monitor. Serial console appears to work fine under qemu. EFI's Graphics Output Protocol gets us the details of the video adapter's linear frame buffer and this can be used as the basis of a framebuffer driver similar to the one used by OpenFirmware. This is working barring a non-critical issue where the screen does not get cleared before we start to use it. Integration of the Newcons project will clean up the UEFI console.

Tasks

64-bit UEFI loader

Make libstand build natively as 64-bit on amd64.

Complete

Adjust non-EFI boot code to use /usr/lib32/libstand.a.

Complete

Add bits to build 64-bit loader.efi.

Complete

Make sure that loader.efi can actually load a kernel and hand off to it.

Complete

Pass ACPI table information to kernel via hints.

Complete

Clean up loader.efi to propery exit UEFI.

Complete

Clean up loader.efi to allocate memory properly.

Complete

Test that the other boot code still actually works.

Complete

Boot amd64 kernel

Work out how to pass the memory map from EFI to the kernel.

Complete

Work out why syscons isn't working.

Complete

Write an EFI framebuffer driver.

Complete

Integrate EFI framebuffer with vt(9).

In progress

Work out why kernel hand-off doesn't work work on systems with >1GB of RAM.

Complete

UEFI-compatible install media

Work out how exactly CD/DVD boot under UEFI works.

Complete

Create a UEFI boot image and attach it to an ISO image.

Complete

Allow loader to see CD filesystem once booted from CD.

Complete

Glue UEFI boot logic into the distribution build.

In progress

Integration into FreeBSD HEAD

Make libstand build natively as 64-bit on amd64.

Complete

Adjust non-EFI boot code to use 32-bit libstand.a.

Complete

Build 64-bit loader.efi

Complete

Kernel parses memory map created by loader

Complete (r263822)

Outstanding tasks were discussed at the BSDCan DevSummit.

Test Results

The amd64 UEFI loader has successfully booted on the following devices:

The UEFI loader failed on:

Known Issues

UEFI (last edited 2014-04-17 20:27:58 by EdMaste)