Initial ramdisk & rootfs

When Linux tries to boot into User Space, it does so by starting the init (PID=1) process from several well-known locations (e..g: /usr/sbin/init, etc.) For this to happen, the kernel first needs to load a root filesystem. The location of this rootfs is specified as part of the kernel's command line arguments:

$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-linux root=/dev/mapper/volgrp0-lv_root rw loglevel=3 quiet

Notice in this example how the root variable is not /dev/sda or /dev/nvme0n1, but instead a Logical Volume (i.e.: an intermediate representational layer that abstracts the backing storage devices – see figure below.) Although the kernel has LVM support, the drivers are likely to be compiled as modules, to be loaded on demand when the user requires them, rather than increasing the size and complexity of the kernel with features that the majority of users do not need. This puts us in an awkward position where we need the LVM drivers to access the root partition but the modules are located on the very same root partition.

Figure 1: Abstraction of storage mediums under LVM.

The solution is to add an initial ramdisk: a disk image that is loaded in RAM at the same time as the kernel. The kernel will view this region in RAM as a storage device, without needing extensive driver support (e.g.: NET_FS). This minimal disk image should contain all kernel modules and tools required to gain access and mount the real rootfs. Once the initramfs is mounted at / and the real rootfs is mounted at another location (e.g.: /mnt/), the init process will use the pivot_root() system call to switch around the two mount points. As a result, the real rootfs will then be mounted at /, making the initramfs safe to unmount from /mnt/ and clear from RAM.

During ARM development, such ramdisks are often used for prototyping purposes. Once we ensure that the Linux kernel successfully boots to User Space, we may consider writing a partition table to the eMMC memory.