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 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
).
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 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:
default
default 1
).
bootdelay
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 the root
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 the root
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 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.
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, then root
and kernel
is not needed.
reboot
(optional) reboot
will reboot the system (just like pressing 'R' key).
If this entry is used, then root
and kernel
is not needed.
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.
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.
You can get BootMenu from here. You can get a sample configuration file from here.
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).