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: 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: 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

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.

Subscribe via GNU Social
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.