Creating firmware images with petitboot and coreboot
This document is part of Raptor Engineering's Open Firmware How-To series
Last update: 08/12/2016
What is petitboot?
Petitboot is a flexible bootloader built around the
Linux kexec functionality. It offers a user-friendly GUI, can boot from a wide variety of media and sources, and offers strong lockdown options. While competing bootloaders such as
GRUB and
SeaBIOS are small, they can be limited or difficult to set up and use. For example, SeaBIOS is fairly easy to use, but is locked to the x86 architecture by design and offers no signed boot options. GRUB is more flexible but is difficult to configure correctly, has known security deficits, and suffers from limited boot source options.
Because petitboot executes from within a minimal Linux initial RAM disk environment, it inherits full support for complex peripherals directly from the underlying Linux kernel. This enables configurations that are otherwise impractical to set up and maintain. Examples include booting from LSI SAS adapters without relying on x86-specific binaries embedded in the vendor's option ROM, or booting directly from a remote fibre channel or IPoIB (Infiniband) source. Also, by taking advantage of petitboot's kernel signature support, you can be assured that only kernels authorized by you or your organization are utilized, even when booting over an untrusted network layer or from untrustworthy physical media. Finally, if the kernel or initramfs in question contain sensitive data such as Kerberos keytab files or SSH keys, the kernel and initramfs can be encrypted at the source, then decrypted and verified by petitboot prior to execution.
Where can I install it?
Petitboot as a low-level boot solution is currently only recommended for systems that allow the machine owner to take full control of the machine's hardware. Examples include:
- OpenPOWER (POWER8 or higher) machines, such as our Talos™ system
- Certain older x86 machines with coreboot support, such as the ASUS KGPE-D16, ASUS KCMA-D8, and the Lenovo T400 / T500 laptops
- Specific ARM machines, particularly ARM chromebooks such as the ASUS C201
- QEMU virtual machines
While it is
possible to use a petitboot-enabled image chainloaded from a vendor-supplied UEFI environment or other proprietary system, there is very little benefit in doing so. In most cases, you will simply be lengthening the time from power on to system boot with no additional security or media-reduction benefits. In general, we strongly recommend migrating away from machines that do not allow you to replace their boot firmware with an open alternative, especially if the non-replaceable firmware is network-enabled or is being used to authenticate / authorize the next stages of the boot process.
Image build process
Overview
A fully functional firmware image incorporating petitboot consists of several separate components:
- The low-level boot firmware (coreboot, skiboot, or u-boot)
- A minimal Linux kernel customized for the destination hardware
- An initial RAM disk (initramfs), containing petitboot, busybox, and several helper utilities
This particular tutorial will guide you through creating a QEMU x86 ROM image. These instructions have also been verified to work on the ASUS KGPE-D16, although a replacement 16MB Flash ROM must be sourced as the factory-installed 2MB ROM is too small.
NOTE: Because large capacity DIP-8 Flash ROMs can be difficult to source, we are pleased to offer "plug and play" 16MB Flash ROMs with petitboot preinstalled for both the ASUS KGPE-D16 and KCMA-D8. These Flash ROMs, like the vendor-supplied Flash ROMs, may be reprogrammed with custom firmware image(s) at your own risk using flashrom under Linux. If you are interested in this option, please contact us at sales@raptorengineering.com for more information.
Prerequisites
- At least 5GB of free disk space on a local filesystem
- Identical userspace architecture to the target system
- Debian Stretch or higher, though Ubuntu Wily or higher may also work
- The following packages
- Installed build dependencies for the following packages:
- Initial, known-working target system configuration files for:
- Working knowledge of either external firmware flashing for the target device or QEMU boot arguments, depending on your application
Initial Setup
Create a new directory, petitboot, in which all source and build files will be stored, and open a new terminal session from within that directory.
Dependency Build
Download and build systemd
petitboot uses udev to detect disks, network interfaces, and related devices. Unfortunately, udev has been fully integrated into systemd and is not available as a standalone source tree. As a result, most of systemd must be built to obtain the required udev libraries and applications.
mkdir systemd
cd systemd
git clone git://anongit.freedesktop.org/systemd/systemd
cd systemd
./autogen.sh
mkdir build
cd build
../configure --prefix=/usr --enable-blkid --disable-seccomp --disable-libcurl --disable-pam --disable-kmod
make -j`nproc`
cd ../..
NOTE: The "-j`nproc`" argument used throughout this tutorial sets number of cores used to build the firmware to the core count of the build system. It can be adjusted to a different value, or even omitted entirely at the expense of a slower build on multicore systems. |
Download and build kexec userspace utilities
mkdir kexec
cd kexec
git clone git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git
cd kexec-tools
./bootstrap
./configure --prefix=/usr
make -j`nproc`
cd ../..
Petitboot / Busybox Build
Download and build twin
mkdir petitboot
cd petitboot
git clone git://git.kernel.org/pub/scm/linux/kernel/git/geoff/libtwin.git
cd libtwin
./autogen
make
make install
cd ../..
Download and build petitboot
cd petitboot
git clone https://github.com/madscientist159/petitboot.git
cd petitboot
./bootstrap
CPPFLAGS="-I../../systemd/systemd/src/libudev/" LDFLAGS="-L../../systemd/systemd/build/.libs/" \
./configure --prefix=/usr --enable-static --disable-shared --enable-busybox --with-ncurses --without-twin-x11 \
--without-twin-fbdev --with-signed-boot
make -j`nproc`
cd ../..
Download and build busybox
mkdir busybox
cd busybox
git clone git://git.busybox.net/busybox
cd busybox
make defconfig
LDFLAGS=--static make -j`nproc`
cd ../..
Initramfs Build
Now that the helper applications have been built, a minimal initramfs can be assembled.
The following commands assume you are building the firmware image on a 64-bit x86 system for a 64-bit x86 target. Please replace "x86_64-linux-gnu" with the correct architecture tuple as needed. As an example, on a ppc64el system the "powerpc64le-linux-gnu" tuple would be used instead.
Prepare the skeleton directory structure
mkdir initramfs
mkdir -p initramfs/{bin,sbin,etc,lib,proc,sys,newroot,usr,usr/bin,usr/sbin,var,var/log,run,run/udev,tmp}
mkdir initramfs/var/log/petitboot
touch initramfs/etc/mdev.conf
cp -Rp /lib/terminfo initramfs/lib/
cp -Rp busybox/busybox/busybox initramfs/bin/
ln -s busybox initramfs/bin/sh
Copy core libraries to the new initramfs
mkdir -p initramfs/lib/x86_64-linux-gnu
cp -L /lib/x86_64-linux-gnu/libc.so.* initramfs/lib/x86_64-linux-gnu/
cp -L /lib/x86_64-linux-gnu/libm.so.* initramfs/lib/x86_64-linux-gnu/
cp -L /lib/x86_64-linux-gnu/libdl.so.* initramfs/lib/x86_64-linux-gnu/
cp -L /lib/x86_64-linux-gnu/librt.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libacl.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libcap.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libattr.so.* initramfs/lib/x86_64-linux-gnu/
cp -L /lib/x86_64-linux-gnu/libpthread.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libncurses.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libtinfo.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libpcre.so.* initramfs/lib/x86_64-linux-gnu/
cp -L /lib/x86_64-linux-gnu/libresolv.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libselinux.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libreadline.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libgcc_s.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libblkid.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libkmod.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libuuid.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libusb-0.1.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libdevmapper.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libz.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/liblzma.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libbz2.so.* initramfs/lib/x86_64-linux-gnu/
cp -R /lib/x86_64-linux-gnu/libgpg-error.so.* initramfs/lib/x86_64-linux-gnu/
cp -L /lib/x86_64-linux-gnu/libnss_files.so.* initramfs/lib/x86_64-linux-gnu/
mkdir -p initramfs/lib64/
cp -L /lib64/ld-linux-x86-64.so.* initramfs/lib64/
mkdir -p initramfs/usr/lib/x86_64-linux-gnu/
cp -R /usr/lib/x86_64-linux-gnu/libform.so.* initramfs/usr/lib/x86_64-linux-gnu/
cp -R /usr/lib/x86_64-linux-gnu/libmenu.so.* initramfs/usr/lib/x86_64-linux-gnu/
cp -L /usr/lib/x86_64-linux-gnu/libelf.so.* initramfs/usr/lib/x86_64-linux-gnu/
cp -L /usr/lib/x86_64-linux-gnu/libdw.so.* initramfs/usr/lib/x86_64-linux-gnu/
cp -R /usr/lib/x86_64-linux-gnu/libgpgme.so.* initramfs/usr/lib/x86_64-linux-gnu/
cp -R /usr/lib/x86_64-linux-gnu/libassuan.so.* initramfs/usr/lib/x86_64-linux-gnu/
Copy helper binaries to the new initramfs
cp -Rp /usr/bin/gpg initramfs/usr/bin/
cp systemd/systemd/build/.libs/libudev.so.* initramfs/lib/x86_64-linux-gnu/
cp -Rp systemd/systemd/build/systemd-udevd initramfs/sbin/
cp -Rp systemd/systemd/build/udevadm initramfs/sbin/
mkdir -p initramfs/usr/lib/udev
cp -Rp systemd/systemd/build/*_id initramfs/usr/lib/udev
cp -Rp kexec/kexec-tools/build/sbin/kexec initramfs/sbin/
Install petitboot itself to the initramfs
cd petitboot/petitboot
make DESTDIR=`realpath ../../initramfs/` install
cd ../..
Copy udev rules to the new initramfs
mkdir -p initramfs/usr/lib/udev/rules.d
cp -Rp systemd/systemd/rules/* initramfs/usr/lib/udev/rules.d/
cp -Rp systemd/systemd/build/rules/* initramfs/usr/lib/udev/rules.d/
rm -f initramfs/usr/lib/udev/rules.d/*-drivers.rules
Set up udhcp helper scripts
mkdir -p initramfs/usr/share/udhcpc/
cp -Rp busybox/busybox/examples/udhcp/simple.script initramfs/usr/share/udhcpc/simple.script
chmod 755 initramfs/usr/share/udhcpc/simple.script
sed -i '/should be called from udhcpc/d' initramfs/usr/share/udhcpc/simple.script
cat << EOF > initramfs/usr/share/udhcpc/default.script
#!/bin/sh
/usr/share/udhcpc/simple.script "\$@"
/usr/sbin/pb-udhcpc "\$@"
EOF
chmod 755 initramfs/usr/share/udhcpc/default.script
Set up nsswitch
touch initramfs/etc/nsswitch.conf
cat << EOF > initramfs/etc/nsswitch.conf
passwd: files
group: files
shadow: files
hosts: files
networks: files
protocols: files
services: files
ethers: files
rpc: files
netgroup: files
EOF
Add basic groups
touch initramfs/etc/group
cat << EOF > initramfs/etc/group
root:x:0:
daemon:x:1:
tty:x:5:
disk:x:6:
lp:x:7:
kmem:x:15:
dialout:x:20:
cdrom:x:24:
tape:x:26:
audio:x:29:
video:x:44:
input:x:122:
EOF
Create boot script
The following script is automatically used on every system start to mount needed special directories, start udev, and finally launch petitboot. It can be customized as required for your particular application.
touch initramfs/init
cat << EOF > initramfs/init
#!/bin/sh
/bin/busybox --install -s
CURRENT_TIMESTAMP=\$(date '+%s')
if [ \$CURRENT_TIMESTAMP -lt `date '+%s'` ]; then
date -s "@`date '+%s'`"
fi
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
echo 0 > /proc/sys/kernel/printk
clear
systemd-udevd &
udevadm hwdb --update
udevadm trigger
pb-discover &
petitboot-nc
if [ -e /etc/pb-lockdown ]; then
echo "Failed to launch petitboot, rebooting!"
echo 1 > /proc/sys/kernel/sysrq
echo b > /proc/sysrq-trigger
else
echo "Failed to launch petitboot, dropping to a shell"
exec sh
fi
EOF
chmod +x initramfs/init
OPTIONAL: Set up GPG keyring for signed or encrypted boot
If you are setting up GPG signature checking or encryption, you will need to export the public key of your GPG kernel signer account, in ASCII format, to the file "public_key.txt". For encrypted kernels, you will also need to export the machine's private key in ASCII format to the file "private_key.txt". The machine private key is a specific, dedicated GPG account that should be created only for a single machine; encrypted kernels will use this GPG account as the recipient and the kernel signer as the source GPG account. Both files should be placed in the petitboot build root directory, and the private key (if present) should be chmod 600 (read/write by owner only).
WARNING: DO NOT export your personal private key, the private key of the kernel signer, or any other private keys from your GPG keyring! They are not needed by the build process.
|
mkdir initramfs/etc/gpg
gpg --homedir=initramfs/etc/gpg --import public_key.txt
gpg --homedir=initramfs/etc/gpg --import private_key.txt
echo "`gpg --homedir=initramfs/etc/gpg --fingerprint | grep "Key fingerprint" | sed 's/.*Key fingerprint = //g' \
| sed 's/ //g'`:6:" | gpg --homedir=initramfs/etc/gpg --import-ownertrust
chown -R root initramfs/etc/gpg
chgrp -R root initramfs/etc/gpg
chmod -R 400 initramfs/etc/gpg
To only boot signed kernels, execute the following commands:
echo "`gpg --homedir=initramfs/etc/gpg --fingerprint | grep "Key fingerprint" | sed 's/.*Key fingerprint = //g' \
| sed 's/ //g'`" >> initramfs/etc/pb-lockdown
To only boot kernels that have been both encrypted and signed, execute the following commands:
echo "ENCRYPTED" > initramfs/etc/pb-lockdown
echo "`gpg --homedir=initramfs/etc/gpg --fingerprint | grep "Key fingerprint" | sed 's/.*Key fingerprint = //g' \
| sed 's/ //g'`" >> initramfs/etc/pb-lockdown
Strip debug symbols from files installed in the initramfs
This step is crucial to reduce the initramfs size down to a range that will fit on a typical Flash ROM. Leaving unstripped binaries with debug symbols intact can more than double the size of the compressed initramfs!
strip initramfs/sbin/*
strip initramfs/usr/sbin/*
strip initramfs/lib/x86_64-linux-gnu/*
strip initramfs/usr/lib/x86_64-linux-gnu/*
strip initramfs/usr/lib/udev/*_id
CPIO creation and image compression
cd initramfs
find . | cpio -H newc -o > ../initramfs.cpio
cd ..
cat initramfs.cpio | lzma > initramfs.igz
First and Second Stage Firmware Build
Download and build the Linux kernel
mkdir linux
cd linux
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
git reset --hard 2dcd0af568b0cf583645c8a317dd12e344b1c72a
Copy a known-working Linux configuration file for your hardware to .config. Then, customize your kernel using the menuconfig tool, eliminating unnecessary options to reduce size. Please note that only built-in options ([*]) will be available, modules ([M]) will not be included.
Recommended settings for common options are shown below:
make menuconfig
Processor type and features --->
[*] kexec file based system call
[ ] Verify kernel signature during kexec_file_load() syscall
Device Drivers --->
Generic Driver Options --->
[ ] Include in-kernel firmware blobs in kernel binary
HID support --->
{*} HID bus support
<*> Generic HID driver
USB HID support --->
<*> USB HID transport layer
[*] USB support --->
<*> xHCI HCD (USB 3.0) support
{*} Generic xHCI driver for a platform device
<*> EHCI HCD (USB 2.0) support
<*> OHCI HCD (USB 1.1) support
<*> OHCI support for PCI-bus USB controllers
{*} Generic OHCI driver for a platform device
<*> UHCI HCD (most Intel and VIA) support
<*> USB Mass Storage support
<Enable all options in this category as kernel builtins except verbose debug>
Kernel hacking --->
Compile-time checks and compiler options --->
[ ] Compile the kernel with debug info
[ ] KGDB: kernel debugger ----
[ ] Enable verbose x86 bootup info messages
[ ] Early printk
[ ] Early printk via EHCI debug port
[ ] Early printk via the EFI framebuffer
File systems --->
-*- Native language support --->
General setup --->
Compiler optimization level (Optimize for size) --->
Compile the kernel
make -j`nproc` bzImage
cd ../..
Download and build coreboot
mkdir coreboot
cd coreboot
git clone http://review.coreboot.org/p/coreboot
cd coreboot
Build the coreboot toolchain and helper utilities
make crossgcc CPUS=`nproc`
make iasl CPUS=`nproc`
NOTE: Similar to the "-j`nproc`" argument mentioned earlier, the "CPUS=`nproc`" parameter sets the number of cores to use for parallel build. It can be omitted entirely at the expense of a slower build on multicore systems. |
Copy a known-working coreboot configuration file for your hardware to .config. Then, customize coreboot if desired using the menuconfig tool.
Recommended settings for common options are shown below:
make menuconfig
General setup --->
[ ] Build the ramstage to be relocatable in 32-bit address space.
Mainboard --->
ROM chip size (16384 KB (16 MB)) --->
(0x1000000) Size of CBFS filesystem in ROM
Payload --->
Add a payload (A Linux payload) --->
(X) A Linux payload
Linux path and filename
../../linux/linux/arch/x86_64/boot/bzImage
Linux initrd
../../initramfs.igz
Linux command line
console=ttyS0,115200n8 console=tty0 panic=60 softlockup_panic=60 nmi_watchdog=1 quiet rw
Build coreboot
make -j`nproc`
cd ../..
Congratulations! You now have a bootable ROM image with petitboot installed in coreboot/coreboot/build/coreboot.rom.
Testing
QEMU
If you built a QEMU image, testing is relatively simple. Pass the coreboot.rom file to QEMU via the -bios option, for example:
qemu-system-x86_64 -m 1G -M q35 -serial stdio -bios coreboot/coreboot/build/coreboot.rom
If all went well, after a short delay (less than 10 seconds on modern computers) you should see the petitboot TUI (Text-mode User Interface). Try passing disks, CDROMs, and network interfaces to QEMU via the QEMU command line to see the full power and flexibility that petitboot offers.
All data and information provided on this page is for informational purposes only. Raptor Engineering makes no representations as to accuracy, completeness, currentness, suitability, or validity of any information on this page and will not be liable for any errors, omissions, or delays in this information or any losses, injuries, or damages arising from its display or use. All information is provided on an as-is basis. All product names, logos, and brands are property of their respective owners. All company, product and service names used in this page are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.
Design and contents copyright
© 2009 - 2024 Raptor Engineering, LLC.
All rights reserved.
No pages or files may be distributed without express written permission.
This website makes minimal use of cookies.
Use of this site constitutes acceptance of this policy.