A Simple Menu-based Boot Manager using Kexec (BootMenu)

This article explains BootMenu, a simple menu-based boot manager to enable users to choose different settings and configurations (including different kernels) with which to start the system.

Background

In PC platforms, there are many capable and versatile boot loaders like syslinux, Grub, Grub2, Grub4dos, and many others. One of the features that many of these bootloaders share is the ability to pre-configure many different settings for booting the PC, including this kernel and which operating systems to boot. These settings is then made available for selection to the user when the PC is started, either through commands or through a menu system.

In the ARM platforms, the situation is a bit different. U-Boot, the most popular bootloader, does support multiple-configuration booting but lacks a menu-system or otherwise easy selection of different boot configurations. In addition, U-Boot usually runs before the display is initialised, thus the only way a user can interact with it is using the serial console attached to a serial terminal (usually another computer). For many devices to get the serial console running, one has to open the device's case and attach a special serial cable (containing serial-to-USB board) to an obscure point on the device's motherboard ... not a prospect that many are prepared for.

The reason for discrepancy is simple. PC, from day one, as designed as a general purpose machine, thus it is designed to be versatile. ARM, however, (apart from its original incarnation in RiscOS machines), are used more of an embedded platform; or single purpose device. Thus once installed, there is no need to choose or edit the configuration of the bootloader and the OS again until the next firmware update; the flexibility of the bootloader is only needed during system design (in which serial console is acceptable).

However as more and more ARM devices are coming to take their part in the general purpose computing, there is a need to have a flexible boot manager that provides facilities to hold multiple configuration of the system as well as some sort of mechanism to allow the user to choose one of these configurations at boot time, when needed.

BootMenu

BootMenu is a simple text-based (suitable for Linux console) boot manager providing menu-based user interface that reads a configuration file containing various boot settings, and presents them to the user as a menu. The user can then choose the boot settings that he/she prefers (using UP/DOWN keys), and then boot them (by pressing ENTER), or edit the entire configuration file (by pressing TAB or E). In addition, the user can drop to PID 1 shell, reboot, shutdown, or exec /init using various keys and/or as setup in configuration file.

BootMenu is implemented as a shell script, and it requires busybox (the usual applets such as mount, umount, awk, sed, ash, vi, etc), kexec-tools, and evtest (for input). It is designed for inclusion in initramfs, and to be executed as the PID 1 init by adding kernel command line

rdinit=/sbin/bootmenu

(assuming you put BootMenu in /sbin).

Operation

BootMenu starts up by looking for its configuration file, bootmenu.cfg. It does this by scanning the root directory of all block devices that it can find and mount (some block devices are excluded, see the script itself for details). The first one will be used and the search stops; this config file is then copied to a temporary location.

Alternatively, bootmenu=dev can be passed on the kernel command line to force BootMenu to only look at specifid device for its configuration file (e.g., bootmenu=mmcblk0p1). If no configuration file is found, BootMenu will attempt to execute /init (this is what the kernel would do if the rdinit parameter was not used) to start the system directly. Failure to do exec /init will result in kernel panic.

In addition, BootMenu also honours waitdev parameter (which is used by FatdogArm and Fatdog64 to delay boot process so that slow devices have time to initialisation process and make themselves known to the kernel).

Once the configuration is loaded, BootMenu will enter an event loop to allow the user to choose the configurations and perhaps edit the configuration file using vi. Configuration file that gets edited is the temporary copy of the configuration file, never the original, thus changes are not permanent. If you want to make permanent changes you will have to edit the file yourself when the operating system is already up (or do it on another computer, etc).

If a configuration is chosen, BootMenu will attempt to load the kernel (and initrd/initramfs, if any) and launch if if the kernel is found. Otherwise it will return an error and stays in the event loop. It will stay on event loop until a valid kernel can be loaded, or until the user chooses one of the shutdown / exit-to-shell / run /init functions.

BootMenu configuration file

BootMenu menu configuration file is a simple text file, to be located at the root directory of a filesystem that can be found by BootMenu. The format is similar to syslinux/Grub but not identical.

The configuration file consist of two parts:

All configuration items must start at the beginning of line (no spaces or tabs allowed), otherwise they are ignored. Blank lines are ignored, and a line preceded by a hash (#) symbol is a comment and will be ignored too.

A configuration file must contain at least one boot stanza, otherwise the file is considered invalid.

Global settings are settings that will affect BootMenu as a whole. Currently there are two settings:

  1. default
    Followed by a number, this sets the boot stanza entry that will be booted off by default, if the user doesn't choose anything (autoboot). The entry numbering starts from 1 (one). If this is not specified BootMenu will boot the first entry (ie., it is the same as setting default 1).

  2. bootdelay
    Followed a number, this sets the number of seconds before BootMenu will automatically boot the default entry. If not specified, the delay is 10 (ten) seconds. You can disable autoboot entirely by specifying 0 (zero) as the delay value.

Boot stanza are settings that define a particular boot configuration. You can have multiple stanzas in the configuration file, each stanza defines a particular boot settings (combination of kernel, initrd, kernel parameters, etc). Each stanza is delimited by its title line; a new title starts a new stanza and closes the preceding one.

A boot stanza can contain the following keywords:

  1. title
    title can be followed by a short string; this string will be displayed in the menu. It also marks the beginning of a new stanza.

  2. root
    root is followed by a Linux block device name (without /dev), e.g. mmcblk0p1, which specifies the block device that holds the kernel.

  3. kernel
    kernel is followed by a path (within the root block device) to the new kernel that is to be loaded . E.g. /a10/uImage-3.4.

  4. initrd (optional)
    initrd is followed by a path (within the root block device) to the initrd/initramfs to be loaded. Initrd is optional; if it is not given no initrd will be used.

  5. append (optional)
    append is followed by kernel command line parameters to pass to the new kernel. Append is optional, if it is not given then nothing will be passed to the kernel (and therefore the kernel must be compiled with the right boot parameters, otherwise it won't work).

  6. dtb (optional)
    dtb is followed by a path (within the root block device) to the compiled device tree blobs to load and passed to the new kernel. Dtb is optional, if not given BootMenu assumes that the kernel will boot using --atags instead.

  7. comment (optional)
    comment is followed by a string which will be displayed at the bottom of the menu screen. You can put longer string here (the menu system reserves two lines to display the comment) but all of them must be on one line. If not given, the comment line will be left blank.

  8. init (optional)
    init will launch /init, thus booting the system as if bootmenu is never used (just like pressing 'I' key). If this entry is used, then root and kernel is not needed.

  9. reboot (optional)
    reboot will reboot the system (just like pressing 'R' key). If this entry is used, then root and kernel is not needed.

  10. poweroff (optional)
    poweroff will power-off (shutdown) the system (just like pressing 'P' key). If this entry is used, then root and kernel is not needed.

  11. shell (optional)
    shell will end bootmenu and run a PID 1 shell instead (just like pressing Esc key). If this entry is used, then root and kernel is not needed.

Download

You can get BootMenu from here. You can get a sample configuration file from here.

Notes:

  1. BootMenu uses the Linux kernel itself as the bootloader. For this to work, the kernel that runs BootMenu (ie, the first kernel that boots up) needs to compiled with support for kexec system call. The other kernels that would be loaded by BootMenu does not need this support.

  2. BootMenu operates by hot-loading a new kernel on top of the existing (the currently-running) one. This assumes that all the devices can be re-initialised by the new kernel. This is not generally true, and on some platforms devices can only be initialised once and then locked out until subsequent hardware reset. BootMenu will not work on these platforms simply because the new kernel will not know what to do with these locked-out devices.

  3. BootMenu doesn't currently recognise touch gestures. To use BootMenu in a tablet platform, the platform must provide some sort of hardware buttons (and the BootMenu script needs to be modified to recognise them).

  4. Other menu-based Boot Managers using kexec system call

    When the idea first came to me, I did a google search in case there was something that I can re-use. And indeed, there are existing implementations:

  5. But none of those meet my needs. Petitboot is client-server design and needs a server to work, so that is immediately out. Kexecboot is pretty, with icons and configurable menus too, but it is missing a few functions and have others that I don't need. I can't recall why I didn't go with kexec-loader.

    Thus BootMenu was born. BootMenu is a simpler implementation of the same idea in shell script, using only busybox, kexec-tools, and evtest (for input), and should be very easy to adapt for other platforms (e.g. tablets, which has different key mapping from standard PC keyboards, etc).