Boot process

Overview
Once you press the power button on your device with a postmarketOS installation, it goes through the following steps:


 * 1) Device specific bootloaders
 * 2) postmarketOS initramfs
 * 3) OpenRC
 * 4) LightDM (if UI is not none, otherwise it stops at OpenRC), or GDM if you chose the GNOME UI
 * 5) User Interface of choice (Plasma Mobile, Phosh, ...)

Device specific bootloaders
There are multiple stages of bootloaders passed before arriving at the postmarketOS initramfs. The first stages are not that relevant to understand the postmarketOS booting process, as they take care of very low level things, such as DRAM calibration. It gets interesting at the last stage of these device specific bootloaders, which is oftentimes some LK derivative, or on more libre or liberated devices, it may be u-boot.

TianoCore/EDK2
This is the open source implementation of UEFI spec. Mainly used for Lumias, popular/high-end ARM platforms (think Raspberry Pi or the expensive ARM servers). Having a framebuffer is a must with the UEFI spec, hence it's trivial to set up a screen console output using this one (earlycon=efifb console=efifb).

LK (Android)
LK (Little Kernel) loads a  file, that was directly written to the Android boot partition of the device (without any partitioning, just the file directly; this is not the postmarketOS boot partition, see partition layout). This file consists of the postmarketOS Linux kernel and initramfs, which we flash to that partition during the installation. Flashing instructions are passed to LK with the  command (abstracted in  ).

Notably LK does not allow to boot a different kernel from an SD card (without hacks like chainloading another bootloader that is stored in, which potentially increases the boot time and is a whole lot of effort to implement). LK is licensed under the MIT license, without copyleft, meaning that vendors are not required to release the source code of their LK bootloader forks. In practice, they end up being proprietary - we don't get the source code and can't make changes.

isorec
Very few Android devices don't expect a  file written to the Android boot partition, but rather just the Linux kernel, with an embedded initramfs. But we want the initramfs packaging to be independent of the kernel (not require a kernel rebuild to change the initramfs!). Therefore we use the so-called "isorec" trick here: the initramfs script built into the kernel is just a very small stub, that loads the real initramfs from the postmarketOS boot partition (example).

u-boot
Das U-Boot is highly configurable. When used with postmarketOS, it usually loads the postmarketOS Linux kernel and initramfs from the postmarketOS boot partition, where they live as dedicated files. The u-boot script is usually packaged in the device specific package.

With u-boot, we can have two separate postmarketOS installations on the device, one on the internal storage (eMMC), and one on the SD card. If that is the case, we set the  and   Linux kernel parameters from u-boot, so our initramfs script knows which root and boot partition we want to use (example).

postmarketOS initramfs
The postmarketOS initramfs consists of busybox, a shell script and very few other command-line programs. Find the source code in the postmarketos-mkinitfs pmaports. generates the initramfs (and packages into a suitable format for the device specific bootloader if necessary, such as a boot.img file) and  is what is actually running in the initramfs.

The initramfs takes care of many things during the early booting phase, such as setting up USB networking, resizing the root partition, displaying a charging UI. Some of the tasks are listed in detail here, for others refer to the source code for now and consider expanding this article. Furthermore, the initramfs supports hooks (which may be used to work around device specific quirks, for example).

Here is a list of the boot process related to initramfs:


 * Enable  if the verbose-initfs hook exists
 * Load deviceinfo data
 * Create busybox symlinks
 * Mount,   and
 * Redirect stdout to  if   isn't present in the kernel cmdline
 * Modprobe modules listed in deviceinfo
 * Enable mdev (busybox replacement for udev)
 * Make kernel detect subpartitions
 * Wait for /dev/fb0 to appear (if not disabled in deviceinfo) and set the framebuffer mode
 * Execute hooks
 * Show loading splash
 * Start networking
 * Find and mount the partition with the  label (or show "Boot partition not found" splash)
 * Unpack initramfs-extra from the boot partition (or show "Initramfs-extra not found" splash)
 * Start charging mode if one of the known charging kernel parameters was found in the cmdline (show battery icon for charging and waits for powerbutton press)
 * Search for a partition with the label  or
 * Try to resize the partition containing the root filesystem to the maximum size
 * Start osk-sdl if the rootfs is a luks partition
 * Resize the root filesystem to match the partition it is in
 * Mount the root filesystem
 * Kill all processes running in the initramfs and pivot root to the real rootfs

Find the boot and root partitions
Due to the various possible partition layouts, the initramfs script has to look in various places for the postmarketOS boot and root partitions.

boot partition:
 * kernel parameter (from the device specific bootloader)
 * Any partition or subpartition with the  label

root partition:
 * kernel parameter (from the device specific bootloader)
 * Any partition or subpartition with the  label
 * Any partition or subpartition that is encrypted

Load initramfs-extra
Some Android devices require a very small initramfs, because otherwise the resulting  file is too big for the Android boot partition. Therefore, we have split the initramfs into two parts, the tiny initramfs that is potentially placed in such a  file (depending on the bootloader). And the initramfs-extra, which can hold bigger binaries, such as the UI to unlock an encrypted root partition (osk-sdl).

Switch root
At the end of the initramfs script, the root partition is mounted at, and the boot partition is mounted at. The latter is done, so OpenRC does not need to figure out the correct boot partition later on. Afterwards, the busybox command  is called to switch over and pass control to OpenRC.