webboot offers tools to let a u-root instance boot signed live distro images over the web.
The webboot bootloader works as follows:
- fetch an OS distro release ISO from the web
- copy the ISO to memory
- mount the ISO and copy out the kernel and initrd
- load the extracted kernel with the initrd
- kexec that kernel with
memmapparameters to retain the ISO
The key point lies in preserving the respective ISO file without further storage
throughout the kexec. That is achieved by using a persistent memory driver,
which creates a pmem device at
/dev/pmem[N] when booting Linux with the
The caveat is that both our webboot kernel as well as the kernel we kexec into need support for pmem. See below for details on OS distribution support and how the kernel needs to be configured.
The second issue is with carefully choosing size options. The Linux system started first needs enough memory to work with, and the pmem device needs to be large enough to hold the ISO.
For reference, webboot developers should familiarize themselves with:
Build initramfs with added webboot commands
go run buildimage.go in the source directory of webboot to build the
This runs u-root under the hood. To pass
extra options, such as to include extra files, use the
-u switch, e.g.,
go run buildimage.go -u "-files path/to/bzImage:bzImage" to add a custom
kernel which can be used to test whether kexec works in a small setup. That
saves a lot of time, because a full webboot flow would always need to download
large ISO files, copy them, mount and decompress.
For convenience, you can
- skip the inclusion of Wi-Fi tools by passing
- add a custom kernel for within the initramfs via
- add an ISO file to the initramfs via
- boot that ISO via
webboot -dhcp4=false -dhcp6-false locallater, which requires passing a pmem-enabled kernel via
-bzImageas described above
- boot that ISO via
You can optionally compress the initramfs with
lzma or any other compression
method you configure your kernel for.
lzma -f /tmp/initramfs.linux_amd64.cpio
Refer to u-root's documentation for more details on compression.
buildimage.go utility is really just a helper tool. Instead of using it,
you can build a custom u-root image as you like and add the
webboot binary to
Refer to u-root's usage documentation
Building a kernel for webboot
webboot uses a standard Linux kernel which should be fairly portable, based on a Long Term Stable (LTS) release. It has worked on every Chromebook we tried.
This kernel is built using a config originally from NiChromeOS. If we are building a bootable USB stick formatted with vfat, we don't have the space constraints of NiChrome, so we expect this to diverge over time.
Nevertheless, to keep it all simple, we build it as a non-modular kernel with Wi-fi firmware built-in. We no longer build the initramfs into the kernel, as that's not needed.
To build, first, be sure you're in a directory you want to be in!
You can actually do the work in the webboot root directory because the
.gitignore file ignores the two directories you create when following the
You need to have the following packages installed if on Ubuntu:
sudo apt install libssl-dev build-essential
Fetching, configuring and compiling the kernel
git clone --depth 1 -b v4.12.7 \ git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git linux git clone \ git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/linux-firmware.git cp config-4.12.7 linux/.config (cd linux && make bzImage) go run .
Testing in QEMU
Tip: Don't use the
-nographic option for u-root in QEMU as you want to boot
into a graphical interface.
If you have KVM in your host system, you can add
-enable-kvm for speedup.
qemu-system-x86_64 \ -enable-kvm \ -m 20G \ -kernel linux/arch/x86/boot/bzImage \ -append 'console=ttyS0 console=tty1 memmap=1G!1G' \ -initrd /tmp/initramfs.linux_amd64.cpio \ -device virtio-rng-pci
memmap kernel parameter for webboot. It is crucial for the kernel
to have pmem enabled to create a block device in memory to mount the ISO of the
next OS to boot into, and for that second OS's kernel to know about it as well
so that it knows where the ISO resides in RAM such that it can pick it up and
load additional files from it, i.e., its root filesystem. The size for
needs to be chosen such that the ISO fits into it and it is sufficiently
smaller then the memory assigned to the VM so that the first system has enough
for itself to run.
Refer to u-root's documentation for more details on virtualization.
distribution argument defines a supported operating system distribution.
webboot tinycore perfoms a webboot of the TinyCore Linux distribution.
Ethernet / QEMU
If you have no Wi-fi but ethernet instead, or you are trying webboot in QEMU
with an emulated ethernet card, you will need to tell webboot to use the
correct interface, e.g.,
webboot -interface eth0 [distribution]
Supported Operating Systems
- Arch Linux
- TinyCore Linux (reusing the webboot kernel for it)
Issue: ISO structure
The respective ISOs of the following distros have pmem as a module in their
lib/modules/*/kernel/drivers/nvdimm/). They would need to either
have the module in their initramfs already or even built into their kernel.
Otherwise, when we kexec into the respective kernel, we lose the ISO.
The following table lists how the distros structure the ISOs.
For more details, see distros.md.
As a hackaround, we could mount the squashfs within webboot already, copy out the pmem modules, recreate the initramfs with the pmem modules in addition, and then boot into that.
A much easier way would be to ask the distributors to include the modules for pmem support already in their initramfs, i.e., the nvdimm drivers, or build them into the kernel. For the latter, their config would need to include the following:
CONFIG_X86_PMEM_LEGACY_DEVICE=y CONFIG_X86_PMEM_LEGACY=y CONFIG_BLK_DEV_PMEM=y CONFIG_ARCH_HAS_PMEM_API=y
- A third option would be rebuilding the respective distro's kernel on our side with the options as listed above as a PoC to show them that it works. Then we could upstream patches.
For a start, the first iteration is a remastered ISO for TinyCore, with a modified kernel as per 3). The result is stored in a separate repository.