2014-12-04

Abstract

This article describes the overall features and principles of the Extended Firmware Interface (EFI), including why you might want to use it, how EFI boots and what types of boot loaders you might use with it to enable non-Windows 8 OSes to boot on an EFI computer. The next three parts of this series will describe how to prepare for the installation of an EFI environment on an Intel-based computer, how to perform the installation and how to manage the computer once it’s up and running.

EFI is very different from a PC BIOS, as it offers a wide range of functionality even before the OS starts loading. It is modular (you can add custom code or drivers), runs on various platforms and applications, its drivers can be written in C instead of assembler making them more portable, etc. Besides the native CPU code, EFI supports custom byte code, so drivers can be compiled so that they are portable between CPU architectures without the need for recompilation.

Introduction

Once upon a time, the first IBM PC 5150 was shipped in 1981 with a new 16-bit processor, made by Intel Corporation, and bundled with a firmware known as the Basic Input Output System (BIOS). The BIOS was the interface between all hardware devices and the Operating System (OS). At the beginning, there was no problem with this approach, but when hard disk and RAM memory prices slowed down, many features supposed a handicap:

No more than four primary partitions are allowed

Booting process requires 16-bit real mode

Boot process starts by loading 512-bytes of data (Master Boot Record, MBR)

Disks over 2 TB are not supported by BIOS approach

BIOS is unable to access any disk file system and therefore cannot load any executable image file such as OS kernels

The i386 compatibility architecture was based on keeping the initial bootstrapping process used since 1981. It did not take advantage of protected mode and 32-bit register addressing provided by 80386 and later Intel microprocessors.  It was not modified until 2005 at which time the Extensible Firmware Interface (EFI) was developed to provide a more versatile and updated boot process based on the ability to load and execute ELF images directly from the initialization code.

In reference to hard disk devices, BIOS-based computers could only handle up to 232 sectors using 512-byte sectors. This leads to a 2 TB limit on storage capacity. Besides, the special partition managed by EFI and termed EFI Special Partition (ESP) can use both FAT-32 file system, as encouraged by EFI Standard, and FAT-16. It can even use HFS+ for Mac OSx computers. This ESP has the partition code 0xEF00, which allows a quick identification.

As the BIOS cannot access a file system on a disk and therefore is unable to load an executable image file such as OS kernels, every OS must have its own boot loader using the BIOS approach, which constitutes a huge source of problems. A way to avoid the use of separate boot loaders for each OS installed, is to use Multi-boot Specification (MS) which will be covered in another article.

Considering the historical background explained above, the Extensive Firmware Interface (EFI) has its roots in 1998 with the Intel Boot Initiative (IBI) program. Hence, the EFI specification, which has been developed and supported by a consortium integrated by Intel and Microsoft, among other companies, defines an API and data structures to handle generic firmware in a wide variety of platforms in order to provide OS loaders, EFI device drivers, and diagnostics by means of an EFI command interpreter or EFI Shell.

The first EFI specification was EFI 1.02 released in 2000. Due to legal issues, it was re-released two years later under the denomination EFI 1.10 and restricted to Itanium microprocessors. In order to avoid undesirable scattering, the Unified EFI Forum was created, including companies such as Intel, AMD, AMI, Apple, Dell, HP, IBM, Phoenix and, of course, Microsoft, among others. This initiative led to Universal EFI (UEFI) standardization. Later on, AMD created its own 64-bit architecture, AMD64, which was backward compatible with IA32. The AMD64 architecture is equivalent to Intel’s EM64T architecture and it was eventually supported in UEFI 2.0 standard. Nowadays, the latter standard is UEFI 2.1 which includes a few changes regarding its predecessor.



Figure 1. Comparison between BIOS and UEFI approach

Last but not least, EFI can boot a computer faster than BIOS-based booting. On average, the EFI booting process is more than 20 seconds faster than using BIOS boot mode.

EFI has its drawbacks too, of course. The most important of these is the fact that it’s new. This means that old boot loaders don’t work with it and users are unfamiliar with it. Another  significant problem is that the EFI boot process assumes the OS will run in the same bit depth as the EFI. Because all UEFI-based PCs and most EFI-based Macs use 64-bit firmware, this means that 64-bit OSes work best with these computers. (The earliest Intel-based Macs used 32-bit EFIs though). Installing a 32-bit version of Linux on a computer with a 64-bit EFI is possible, but you’ll give up runtime EFI interfaces. This makes boot loader maintenance harder, since the efibootmgr utility (which will be described in part three of this series) relies on such interfaces. For this reason, I recommend installing a 64-bit distribution if your firmware is 64-bit.

GUID Partition Table (GPT)

The GUID Partition Table (GPT) is a new standard for disk partitioning providing a set of advanced features such as:

Modern logical block addressing (LBA)

64-bit LBA pointers to manage partitions up to 8 ZB

Support for non-512 byte sector size disks

Up to 128 partitions per disk

Inclusion of backup partition table

Although NetBSD can access GPT disks by using dkwedges, it is not possible to boot off a GPT disk in a straightforward manner and the current strategy to boot is similar to EFI bootstrapping:

BIOS → LBA0 → PBR on EFI syspart → /boot → NetBSD kernel

Secure Boot and Microsoft Legacy

One of the most controversial features of EFI is Secure Boot. This feature was originally intended to improve security by ensuring that only boot loaders signed with a crypto key can run. In such a way, malware code cannot be executed as it is not signed with this key. However, Microsoft requires Secure Boot enabled for Windows 8 use in desktop and laptop computers and as a practical matter, Microsoft’s keys are included in the vast majority of new computers with UEFI support.  No other company/organization has the power to guarantee that their keys are also included.

The only way to bypass this inconvenience is through the use of Microsoft’s signing service. Otherwise, the only way to avoid any issues with non-Windows OSes is to disable Secure Boot, which is perfectly possible if you do not want to use MS Windows 8.

A Tour on EFI Shell

Before introducing the main topic, it is important to take a preliminary approach on UEFI usage so that readers can see the main differences between the former BIOS and the new paradigm for new 64-bit Intel computers. There are many possibilities.



Figure 2. BIOS and UEFI End-User Interface

End-User EFI Commands

Whenever a new Intel-based computer is started, the UEFI program starts its execution to get into a shell as follows:

fs0:\> ver

EFI Specification Revision : 1.10

EFI Vendor : INTEL

EFI Revision : 14.62

fs0:\> ls

fs0:\> devices -b

fs0:\> dh -b

fs0:\> cd apps

fs0:\apps> ls

fs0:\apps> load tcpipv4.efi

fs0:\apps> ifconfig -a

fs0:\apps> ifconfig lo0 inet 127.0.0.1 up

For MacOS X computer’s owners, the following command is useful to examine GPT hard disk.

fs0:\diskutils> diskpart

Eventually, if you need some help, issue the following command to display commands one screen at a time:

help -b

Programming EFI

If you are an experienced programmer, it is possible to develop and evaluate your own EFI applications even using an IA-32 computer. To get the true flavor of EFI, you need two different environments:

Runtime Environment

To explore EFI on IA-64 or in IA32 computers by using a BIOS32 boot floppy provided by Intel to boot into a real EFI environment running x86 with legacy BIOS.

Development Environment

To develop EFI programs, such as device drivers, boot loaders and so on, consisting of:

A host operating system.

GNU CC toolchain

Intel EFI Application Toolkit

Intel EFI Application Toolkit is provided by TianoCore project and is available under BSD licenses in < www.tianocore.org >. Alternatively, there is a GNU EFI development port but it is not mature enough yet.



Figure 3. BIOS vs. UEFI API Program Development

In order to compare the main differences between BIOS and UEFI, be aware that UEFI offers a complete API to support low-level firmware development.

EFI Boot-Loaders

In comparison with BIOS boot loaders, EFI boot loaders are still under heavy development as follows:

ELILO : one of the most reliable bootloaders for GNU/Linux systems but it requires the kernel to be loaded from ESP and does not allow other locations.

GRUB-2 : supports both BIOS/EFI booting but requires installing an EFI-capable package such as grub-efi. Regarding its predecessor, GRUB Legacy does not support the EFI booting process. GRUB-2 is sometimes very complex to handle.

rEFIt : is not capable of booting a kernel directly and requires a chainload to make it possible.

My only experience at the moment with Linux kernels is that work is being done to embed EFI boot loader support to load the kernel directly without using a third-part EFI boot loader. To sum up, have a look at the following table:

Boot loader

Load Linux

Kernel location

Chain load

ELILO

Y

ESP

N

GRUB-2

Y

any

Y

rEFIt

N

N/A

Y

Linux kernel

Y

ESP

N

And just to conclude this section, one of our favorite UEFI boot loaders, and our recommended choice for Mac OS X fans, is rEFIt, which supports graphical output as shown:

Figure 4. rEFIt UEFI bootloader main screen

No matter which UEFI boot loader you choose, have a clear understanding about the implications of using it, especially if you have to coexist with Microsoft™ Windows OS on your computer.

NetBSD/EFI in I386 Architectures

The NetBSD/i386 boot process uses a two-stage boot loader where the first stage is installed in a well-known physical location (the first sector of the disk MBR) and this stage provides the necessary information to start with the second stage boot loader placed on the root file system and transfer the control to it.

Once the second stage boot loader has taken control, it swaps the processor into the protected mode with a full 32/64-bit addressing and no segmented memory as in 16-bit real mode.

NetBSD and GPT Awareness

It’s possible to boot NetBSD from the GPT partitioned disk when using a PC BIOS computer. The approach is quite similar to the NetBSD MBR boot loader and is comprised of three parts:

“mbr_gpt/mbr_gpt_com0” is an LBA0 loader intended to be used by a BIOS-based computer, whose main aim is to find a bootable GUID partition.

“bootxx_fat16” is a PBR loader which can be executed by either MBR loader or BIOS. The mission of this function is to load the NetBSD boot(8) kernel program and put the loader into an ESP FAT16 partition, which can be a source of trouble, due to the recommendation of using ESP FAT32-formatted partitions.

“NetBSD boot(8) kernel loader” is in charge of loading and running the NetBSD kernel from either a GUID or disklabel partition.

At the moment of writing this article, an effort is being done to get an EFI boot loader for NetBSD systems in order to get rid of the former GRUB-based approach. It will be available by the end of this year, I hope. Anyway, if you are not using MS Windows 8 in your computer, you can safely following the instructions to minimize the impact of new EFI-based computers.

Installation Procedure of NetBSD

To build and install the NetBSD loader, you should have the following software:

Current NetBSD kernel sources as distributed in syssrc package.

sbin/gpt and usr.sbin/installboot loader installation tools.

Ensure you have the latest GPT bootloader patch available at < http://www.netbsd.org/~mishka/gptboot/gptboot.patch >

The following steps describe what you’d need to build a NetBSD loader:

Download all the sources above

Prepare src tree for patching by making directories missing. See the list of the directories inside the patchfile:

$ awk ‘/^WARNING:/ {print $(NF)}’ gptboot.patch

Apply the patch

Build GPT loaders and tools at the following directories:

sys/arch/i386/stand/mbr/mbr_gpt

sys/arch/i386/stand/fatboot/fat16

sys/arch/i386/stand/boot/biosboot

sbin/gpt

usr.sbin/installboot

All of above builds just fine on NetBSD 5.0 (including amd64) without cross compilation. The install boot may require passing -DSMALLPROG to make [1] to exclude extra stuff and simplify the build process. Also, new sys/sys/bootblock.h has to be used in place of /usr/include/sys/bootblock.h.

Loader Installation

First of all, you should prepare your disk. The disk should be GPT partitioned and have at least two partitions, one for NetBSD, and one for boot loader as follows:

# gpt create sd0

# gpt add -s 65536 -t efi sd0

# gpt add -t ffs sd0

# gpt show

then issue a set of dkctl addwedge commands or reattach the disk to configure dk wedges automatically:

NB     :  Wedges are not supported on vnd(4) devices

Next   :  Format partitions accordingly:

# newfs_msdos -F 16 /dev/dk0

# newfs /dev/dk1

Please note that newfs_msdos seems to have a bug and can incorrectly determine file system size (check number of file sectors reported by newfs_msdos; it must be less or equal to partition size). If it appears, please reformat file system explicitly specifying correct fs size via newfs_msdos -s option.

To install the loaders, issue the following commands:

# …/gpt biosboot -c $NETBSDSRC_DIR/sys/arch/i386/stand/mbr/mbr_gpt/mbr_gpt sd0

# …/installboot /dev/rdk0 $NETBSDSRC_DIR/sys/arch/i386/stand/fatboot/fat16/bootxx_fat16

# mount -t msdos /dev/dk0 /mnt

# cp $NETBSDSRC_DIR/sys/arch/i386/stand/boot/biosboot/boot /mnt

# echo “menu=Boot NetBSD:boot hd0b:netbsd” > /mnt/boot.cfg

# umount /mnt

The gpt(8) will automatically find the EFI system partition on sd1 and instruct mbr_gpt where to load PBR from. But rest loaders should be installed on dk wedges. If you’re confused about the names, you may use gpt(8) on a wedge, but in this case mbr_gpt will load PBR from the specified wedge:

# …/gpt biosboot -c $NETBSDSRC_DIR/sys/arch/i386/stand/mbr/mbr_gpt/mbr_gpt dk0

Then, install kernel and base system files through:

# mount /dev/dk1 /mnt

# cp /netbsd /mnt

Then, create the usual NetBSD hierarchy: /dev, /etc, /sbin, etc… and specify the root partition as it will be enumerated by DKWEDGE_AUTODISCOVER:

# echo “/dev/dk1 / ffs rw 1 1″ > /etc/fstab

# umount /mnt

Please note the disk names on previous steps. It might be somewhat confusing, so here is an explanation:

gpt biosboot … sd0: LBA0 means installation in the very first sector of the physical disk, so we should specify the parent device of our GPT wedges. A dk device can also be used. In that case, mbr_gpt will look for a GUID partition matching the dk device at the moment of installation.

install boot /dev/dk0 …: bootxx_fat16 should be installed onto the EFI System Partition. See gpt add commands earlier. mount -t msdos /dev/dk0 …: the boot(8) should be stored on the EFI System Partition as well.

echo “menu=Boot NetBSD: boot hd0b:netbsd” …: the hd0b means the second partition, which matches dk1 after boot. Please see the to-do list about that. The resting commands refer to dk1 which is the NetBSD FFS partition.

Now! Reboot and Have fun.

The Easy Way, Using another OS boot-Loader to Start the BSDthe  OS

The fastest and safest way to start a BSD OS like NetBSD is to use another operating system with full EFI support such as GNU/Linux in order to use its own boot loader GRUB as our boot loader for a wide variety of non-Microsoft Windows OSes.

Install an EFI-compliant GNU/Linux Distribution for x86-64 bits. I strongly recommend GNU Debian 7.5 IA64.

Ensure that GNU Debian has its own ESP. By default, this ESP is 200 MB size.

Power on the UEFI-compliant computer by pressing down the key “Supr” to stop the default booting process.

Enter and execute the grubx64.efi EFI application using the built-in UEFI shell.

Select the desired OS bootloader in the GRUB-2 menu.

That is all. If you do not want or are not happy with dealing with complexity, this is the best alternative to take advantage of the new UEFI PC architectures and to get rid of the BIOS the old-fashioned way.

Dealing with the SecureBoot Feature (SHIM boot Loader)

In this sense, despite Microsoft’s efforts to make our lives more difficult by means of the SecureBoot feature, thanks to the work of … a functional version of an EFI boot loader named SHIM which is available for download at < http://www.codon.org.uk/~mjg59/shim-signed/ >. The procedure to use it cannot be simpler than the following steps:

Rename “shim.efi” to “bootx64.efi”.

Put this file into ‘/boot/EFI directory’.

Now, generate a certificate and put the public half as a binary DER file somewhere on your install media. On boot, the end-user will be prompted with a 10-second countdown and a menu. Choose “Enroll key from disk” and then browse the file system to select the key and follow the enrolment prompts. Any boot loader signed with that key will then be trusted by shim, so you probably want to make sure that your grubx64.efi image is signed with it.

This design has been borrowed from Suse’s boot loader developers and requires that the boot loader itself has its own key database, distinct from the one provided by UEFI specification. In such a way, as the boot loader is in charge of its own key enrolment, the boot loader has the freedom to manage its own policy.

Testing UEFI

In order to avoid any damage to a real computer, we strongly recommend you use a virtualized environment to test any UEFI features before moving on to the real computer as follows:

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

qemu-system-x86_64 -serial stdio -bios OVMF.fd -cdrom <path to ISO image>

Also, FreeBSD developers have documented the way of creating UEFI media for testing purposes. To wrap up, let us describe the way of creating a USB HD and CD-ROM UEFI capable media:

CD-ROM with UEFI support media generation

gpart create -s gpt da0

gpart add -t efi -s 800K da0

gpart add -t freebsd-ufs da0

dd if=/boot/boot1.efifat of=/dev/da0p1

newfs /dev/da0p2

Then, 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

USB HD with UEFI support media generation

> 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

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

Remember

The boot directory must contain the EFI executables required

Conclusions and Remarks

If you are wondering why the BIOS approach was kept for decades, a justification for such longevity may be found in the fact that MS-DOS for PC was built on top of the BIOS and MS-DOS programs called BIOS routines through software interrupts. Hence, the BIOS disk I/O routine corresponds to INT 13h. In order to preserve compatibility, this approach survived an unexpectedly long time, despite its technical weaknesses and limitations.

What’s more, EFI was originally designed for Itanium 64-bit processors although nowadays, IA-32 may support EFI-based firmware and there are some companies shelling IA-32 computers with full EFI support, such as Inside Software.

Furthermore, the BIOS depends on VGA which is a legacy standard and does not allow defining new boot devices unless they’ve already been included in BIOS routines. The current approach for graphics support is UGA, which is provided by EFI too. In such a way, the UEFI approach constitutes a true extensible firmware management system.

References

[1] Official UEFI documentation, < www.uefi.org >

[2] Official ELILO, < elilo.sourceforge.net >

[3] rEFIt boot loader, < refit.sourceforge.net >

Acronyms and Abbreviations

MBR

Master Boot Record

MS

Multi Boot Specification

ESP

EFI System Partition

EFI

Extended Firmware Interface

IBI

Intel Boot Initiative

UEFI

Universal Extended Firmware Interface

GPT

GUID Partition Table

VGA

Video Graphics Adapter

UGA

Universal Graphics Interface

Show more