1.20. Devboot

Devboot is a development convenience that builds on top of the boot override mechanism. It sources a per-user, per-board script from the network and translates it into boot -o arguments, making it easy to redirect any combination of kernel, device tree and initrd to network-hosted files without touching the boot medium.

1.20.1. Boot overrides

Enable CONFIG_BOOT_OVERRIDE to allow partial overrides of boot entries. This is already enabled in multi_v7_defconfig and multi_v8_defconfig.

The boot command then accepts one or more -o flags:

boot -o bootm.image=/mnt/tftp/my-zImage mmc
boot -o bootm.oftree=/mnt/tftp/my-board.dtb mmc
boot -o bootm.initrd=/mnt/tftp/my-initrd mmc

Multiple overrides can be combined in a single invocation:

boot -o bootm.image=/mnt/tftp/zImage \
     -o bootm.oftree=/mnt/tftp/board.dtb \
     -o bootm.initrd=/mnt/tftp/initrd \
     mmc

Overrides are applied after the boot entry has been loaded, so the original entry still selects the boot handler, kernel arguments, etc. Only the specified components are replaced.

1.20.1.1. Override rules

bootm.image

The override file is probed for its type. If it is a FIT image, the FIT configuration is re-opened and all components (kernel, initrd, device tree) are taken from the override FIT. If it is a plain kernel image (zImage, Image, uImage, …), only the OS loadable is replaced.

bootm.oftree

A colon-separated list of files. The first entry is the base device tree; subsequent entries are applied as overlays:

# Use a as the device tree
boot -o bootm.oftree=a mmc

# Use a as the device tree, apply b as overlay
boot -o bootm.oftree=a:b mmc

# Keep the existing device tree, apply b as overlay
boot -o bootm.oftree=:b mmc

# Use a as the device tree, apply b and c as overlays
boot -o bootm.oftree=a:b:c mmc

Setting bootm.oftree to an empty string (bootm.oftree=) discards whatever device tree the boot entry provides. If CONFIG_BOOTM_OFTREE_FALLBACK is enabled (the default), the barebox-internal device tree is passed to the kernel instead. If the option is disabled, no device tree is passed at all.

bootm.initrd

A colon-separated list of initrd/CPIO files. Linux can transparently extract any number of concatenated CPIOs, even if individually compressed. A leading colon appends to the initrd that the boot entry already provides:

# Replace with a single initrd
boot -o bootm.initrd=/mnt/tftp/initrd mmc

# Concatenate two initrds
boot -o bootm.initrd=initrd1:initrd2 mmc

# Append an extra CPIO to the existing initrd
boot -o bootm.initrd=:extra.cpio mmc

Tip

The Linux kernel make cpio-modules-pkg target builds a CPIO archive containing all kernel modules. This is useful for supplementing an existing initramfs with modules without modifying the root filesystem. Combined with initrd concatenation, a devboot script can append it to any boot entry’s initrd:

devboot_initrd=":afa-modules-arm64"

To make use of the modules, the initramfs init will need to make initramfs /modules available to the rootfs, e.g. via a bind mount:

mount -n –bind /lib/modules ${ROOT_MOUNT}/lib/modules

Note

When secure boot is enforced (bootm_signed_images_are_forced()), overrides are silently ignored.

1.20.2. The devboot script

The devboot command (/env/bin/devboot) automates the override workflow for network-based development:

  1. Brings up the network (ifup -a1).

  2. Changes into the fetch directory (global.net.fetchdir, default /mnt/tftp).

  3. Sources a configuration script named ${global.user}-devboot-${global.hostname}. If that file does not exist, it falls back to ${global.user}-devboot-${global.arch}.

  4. Translates the variables set by the script into boot -o arguments.

  5. Passes any extra arguments through to the boot command.

Note

TFTP is not a real file system, e.g., listing of directories is not possible. Keep that in mind if the devboot script does more than just fetch files by name from TFTP.

1.20.2.1. Usage

# Boot from MMC with devboot overrides
devboot mmc

# Boot from the default boot entry
devboot

1.20.2.2. Configuration script

The configuration script lives in the fetch directory and sets up to three variables:

devboot_image

Override for bootm.image. Path is relative to the fetch directory.

devboot_oftree

Override for bootm.oftree. An empty string discards the boot entry’s device tree (see bootm.oftree rules above).

devboot_initrd

Override for bootm.initrd. A leading colon appends to the boot entry’s existing initrd.

Variables that are not set (using [[ -v ... ]]) are left alone, so unset variables do not generate override arguments.

The script can also set arbitrary barebox variables, for example kernel command line fragments:

# /tftpboot/afa-devboot-rock3a
devboot_image=afa-fit-rock3a
devboot_oftree=
devboot_initrd=":afa-rsinit-arm64"

global linux.bootargs.dyn.rsinit="rsinit.bind=/lib/modules"

With this script in place and global.user=afa, global.hostname=rock3a, running devboot mmc on the board expands to:

boot -o bootm.image="afa-fit-rock3a" \
     -o bootm.oftree="" \
     -o bootm.initrd=":afa-rsinit-arm64" \
     mmc

This fetches the FIT image afa-fit-rock3a from the fetch directory, discards the FIT’s device tree (falling back to the barebox-internal one when CONFIG_BOOTM_OFTREE_FALLBACK is enabled), and appends the afa-rsinit-arm64 CPIO archive to whatever initrd the FIT already contains.

1.20.2.3. Setting up the variables

The global.user and global.hostname variables control which script is loaded. Make them persistent with:

nv user=afa
nv hostname=rock3a

global.hostname is typically derived from the device tree, but can be overridden.

1.20.2.4. Forwarding a remote build directory over the internet

If the build server is not reachable from the Device-Under-Test, one possibility is to forward the build artifacts to a local TFTP server via SSHFS:

sshfs -o follow_symlinks,allow_other buildserver:/tftpboot /tftpboot

The local development host can then export /tftpboot via TFTP.

If the TFTP server is not running on the local development host, the dpipe utility can be used to connect a local SFTP server process to an SSH session that runs sshfs in slave mode on the remote machine:

dpipe /usr/lib/openssh/sftp-server = ssh a3f@tftpserver.in-my.lan sshfs -o slave,follow_symlinks,allow_other -o idmap=user -o gid=1001 :/tftpboot /tftpboot

This works as follows:

  • dpipe connects the standard input/output of both sides of =.

  • The left side runs the local SFTP server, giving the remote end access to the local filesystem.

  • The right side runs sshfs on the TFTP server host in slave mode, reading SFTP protocol directly from stdin instead of spawning its own SSH connection.

  • follow_symlinks resolves symlinks on the build host, so the TFTP server sees regular files even if the build tree uses symlinks.

  • allow_other permits the TFTP daemon (which typically runs as a different user) to read the mounted files.

  • idmap=user maps the remote user’s UID to the local user, avoiding permission issues.

  • gid=1001 sets the group ID for all files (adjust to match the group that the TFTP daemon runs as on the server, e.g. tftp or nogroup).

  • The colon prefix in :/tftpboot refers to the root of the local (build host) filesystem as exported by the SFTP server.

The result is that /tftpboot on the remote TFTP server mirrors the /tftpboot directory on the build host. Build output can be symlinked there and the board will fetch it directly over TFTP.

To undo the mount, terminate the dpipe process and run fusermount -u /tftpboot on the TFTP server.

Note

On Debian/Ubuntu, dpipe can be installed via apt install vde2 sshfs and fuse must be installed on the TFTP server. /etc/fuse.conf on the server must have user_allow_other enabled for allow_other to work.