Implementing LinuxBoot

The aim of LinuxBoot is to reduce complexity and obscure firmware by moving that functionality into kernel and userspace.

This chapter describes the procedures from a LinuxBoot workshop where an Atomic Pi board with UEFI firmware was converted to run LinuxBoot. The build materials associated with this are found at digitalloggers/atomicpi.

Read the below and consult the Makefile for the details of how it was implemented.

A quick refresher on UEFI

UEFI has three sections:

DXE process is very complex; some systems have 750 DXEs.

LinuxBoot replaces most of the UEFI software with Linux. LinuxBoot has an initramfs provided by u-root.

The above are stored inside a flash filesystem (FFS) inside a region of flash on your motherboard (the BIOS region). Another important region of flash is the ME region.

The Management Engine (ME) is an x86 CPU embedded in the Intel Platform Controller Hub (PCH). It runs the Minix operating system which boots first and enables hardware such as clocks and GPIOs. ME checks the contents of flash memory and is used to implement “BootGuard”. If you reflash and the ME is in “BootGuard” mode, your machine will be unusable. You need to run a tool called me_cleaner on the image to disable BootGuard.

How do you get LinuxBoot on your hardware

Start with a board running standard UEFI and proceed from “zero changes to FLASH” to “max changes” in 4 steps:

One of the challenges in the above is in finding (or reclaiming) enough space in flash to shoehorn your kernel and initrd into.

Tools of the trade

There are two tools you use when you modify the UEFI flash image: utk and me_cleaner.

The ME Cleaner tool:

/usr/bin/python2 -s imagefile.bin

me_cleaner sets the high assurance platform (HAP) bit. HAP provides a way to disable a feature on Intel chips that does not allow us to modify the UEFI image and install LinuxBoot. Setting the bit with me_cleaner disables the “feature”. Note that this does not always work; check with the LinuxBoot community.

When you run me_cleaner:

~/projects/linuxboot/me_cleaner/ -s /tmp/rom.bin

you should see output similar to the following:

Full image detected
Found FPT header at 0x1010
Found 20 partition(s)
Found FTPR header: FTPR partition spans from 0x6f000 to 0xe700
ME/TXE firmware version (generation 2)
Public key match: Intel TXE, firmware versions 2.x.x.x
The AltMeDisable bit is SET
Setting the AltMeDisable bit in PCHSTRP10 to disable Intel ME…
Checking the FTPR RSA signature... VALID
Done! Good luck!

By applying me_cleaner, it has been observed that almost 4M of flash ram can be reclaimed for use. That 4M is enough to store a reasonably full featured compressed initrd image.

The utk tool can:

LinuxBoot Implementation steps

Step 1: boot Linux via netboot / UEFI shell

Working with a system that only has a net interface

If the system only has a net interface, you use Dynamic Host Configuration Protocol (DHCP), using broadcast DISCOVER, and Trivial File Transfer Protocol (TFTP) to get the boot information you need.

Configuration information is provided by REPLY to a DHCP request. The REPLY returns an IP, server, and a configuration file name that provides:

Data is provided by TFTP. HTTP downloading takes a fraction of a second even for 16M kernels. With TFTP it’s very slow and TFTP won’t work with initramfs much large than 32MiB. Most LinuxBoot shops use or are transitioning to HTTP.

Note: Boot images require a kernel(bzImage) + an initramfs + a command line. They can be loaded as three pieces or compiled and loaded as one piece, as described in this section.

Step 2: read & write the flash

There are two main ways to read and write the flash - hardware and software.

Hardware: It is worth buying a Pomona 5250 SOIC Clip adapter to read directly by hardware to have something to roll back to if anything goes wrong. Avoid cheap SOIC clip adapters that don’t allow you to use standard jumper leads. For a good example of using a Raspberry Pi 3/4 to read/write, see Sakaki’s EFI Install Guide/Disabling the Intel Management Engine

Software: With a working boot image, use flashrom to read an image of your flash. To write you may need to disable flash protections (look for “ME Manufacturing mode” jumpers on your motherboard). Figure on generally using software methods for reading & writing flash, but with hardware to drop back to.

Step 3: Familiarise yourself with the flash layout and identify free space

Open your flash image with UEFITool, and locate the filesystem containing the DXE’s (it will have the Shell or Shell_Full in it ). Check how much volume free space is in that filesystem - this will be an initial limit when you come to place your kernel and initramfs in it in step 5.

Step 4: Prepare linux/u-root payload

Start small and work your way up.

Step 5: replace Shell binary section

Step 6a: remove as many DXEs as possible

Step 6b: place your initramfs in me_cleaned region

Step 7: replace closed-source with open source

Final step: reflash the image

The voltage option is required for the Atomic Pi.