Partition Linux Loader -- a tiny linux kernel boot loader
This code presently fits in three 512B sectors. PLL's minimalist design makes it very robust, and easy to audit. PLL does not need nor use any filesystems, so it cannot be disabled through changes to, or corruption of filesystems. PLL boots by loading a kernel directly out of the selected dedicated partition.
This is my daily boot loader on my desktop, and all of my servers. It was written to address difficulties that emerged periodically with lilo and grub, which were difficult to diagnose, especially with regard to servers running on older hardware.
PLL does not need nor use UEFI; it presumes a GPT for simplicity. I chose GPT because it supports numerous partitions, as well as partition names and UUIDs.
PLL loads and boots a kernel directly from a partition. The partitioun contain only the kernel, no filesystem. (though the kernel can of course contain an initmpfs).
PLL supports a kernel command line in the boot sector, and the ability to boot from an alternative partition “one time only” (reverting to the previous kernel on the next boot), and the ability to select which partition to load the kernel from by holding shift keys down at boot time.
PLL does not load a separate initmpfs file. When one is needed, it must be compiled into the kernel.
PLL compiles to three sectors at present: The boot
sector or Master Boot Record (MBR) (Logical Block Address Zero
[LBA0]), with the remaining two sectors sitting between the GPT
and the physically first partition. Most partition editors provide
this space by default, though I prefer to micro-manage my partiton
locations. The execline install script PLLinstall
will
compile PLL appropriately for your GPT, and write the PLL sectors
to the disk if instructed to do so.
The kernel command line stored in LBA0, is preloaded with
PLL=v.v.v-xx.n
, where v
are version numbers, and xx
is replaced
at boot time with the BIOS number of the boot device. This command
line option must exist and must be first.
One of three possible boot scenarios is selected by which character
follows the xx
in the PLL=
option (.
by default)
The three possible cases are .
, +
, and any other character:
At boot time, the state of the keyboard shift keys determines which partition the kernel will be loaded from:
- no shift keys are down: partition 1 is selected.
- a 'shift' key is down: partition 2 is selected.
- a 'ctrl' key is down: partition 3 is selected.
- an 'alt' key is down: partition 4 is selected.
for each of these cases, the n
in the PLL=
option will be replaced
with the partition number that the kernel was actually loaded from.
The kernel will be loaded from the partion number following the +
(at the n
position) in the PLL=
command option.
The partition number following the character (which replaced the .
)
will be 'xor'ed with 0b00000011 (which is an ASCII 1
xored with an
ASCII 2
) so that a 1
will become a 2
, and vice versa. The kernel
will be loaded from the resulting partition number. Then, the
character in the .
position, will be overwritten with +
on disk
in LBA0. (the number following the +
is unchanged on either the
disk [LBA0], or the command line option) Note that this is the only
condition where PLL will write to disk.
This is effectively a “one time boot”. If the command line is not
subsequently changed, the next boot will revert to the previous
partition number. Applications can look at the PLL option in the
command line in /proc/cmdline
to check this character and determine
if we have booted in a “one time boot” condition.
-
PLL is compiled by nasm.
-
The execline install script uses execlineb from skarnet.org, hexdump (util-linux), dd, and test (core-utils).
-
The easiest way to edit the kernel command line is with hexedit.
- install execline via your package manager
- install nasm via your package manager
- clone PLL from codeberg/github/gitflic into
/usr/src/PLL
or if gentoo, use the ebuild in my overlay - use a partition editor (fdisk, parted, etc) to install a GPT
(GUID partiton table) to your target disk (e.g. /dev/sdb):
$ fdisk /dev/sdb
create at least one partition large enough to contain your kernel. (e.g./dev/sdb1
) - run the PLLinstall script to write the boot sectors:
$ cd /usr/src/PLL
$ ./PLLinstall /dev/sdb
this will read the GPT, compile PLL to fit, and (if invoked with --write) write the sectors to the disk - compile a suitable kernel for your hardware
if an initmpfs is needed, compile it into the kernel - write your kernel into the partiton:
$ dd if=/boot/vmlinuz of=/dev/sdb1
- The disk should now be bootable by a legacy boot BIOS
“enhanced BIOS” calls.
If your BIOS supports enhanced BIOS calls, PLL will detect this and use Logical Block Addresses LBA reading from disk. If not, PLL will use the older “Cylinder/Head/Sector” (CHS) addressing. This later code is currently using only a 16 bit LBA, so only the top 33.5MB of the disk are accessible to load a kernel from. Linux kernels are not usually that big, so this has not been a problem on older hardware with limited RAM. On systems with gigabytes of RAM, loading a kernel with a very large embedded initmpfs could be desirable, but such systems usually support LBA addressing through enhanced BIOS calls. If this limitation becomes a problem, a larger LBA could be supported with more complex code, but it would never achieve the reach of LBA, which is 48bits.