A Simple Menu-based Boot Manager using Kexec (BootMenu)
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:
- global settings
- boot stanza
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:
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 settingdefault 1
).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:
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.root
root
is followed by a Linux block device name (without/dev
), e.g.mmcblk0p1
, which specifies the block device that holds the kernel.kernel
kernel
is followed by a path (within theroot
block device) to the new kernel that is to be loaded . E.g./a10/uImage-3.4
.initrd
(optional)
initrd
is followed by a path (within theroot
block device) to the initrd/initramfs to be loaded. Initrd is optional; if it is not given no initrd will be used.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).dtb
(optional)
dtb
is followed by a path (within theroot
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.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.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, thenroot
andkernel
is not needed.reboot
(optional)
reboot
will reboot the system (just like pressing 'R' key). If this entry is used, thenroot
andkernel
is not needed.poweroff
(optional)
poweroff
will power-off (shutdown) the system (just like pressing 'P' key). If this entry is used, thenroot
andkernel
is not needed.shell
(optional)
shell
will end bootmenu and run a PID 1 shell instead (just like pressing Esc key). If this entry is used, thenroot
andkernel
is not needed.
Download
You can get BootMenu from here. You can get a sample configuration file from here.
Notes:
- 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.
- 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.
- 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).
- 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:
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).