Creating a Custom Initramfs
Creating a Custom Initramfs
The initramfs (Initial RAM Filesystem) is a compressed CPIO archive containing a complete, tiny userspace environment that the bootloader loads into physical RAM alongside the kernel image.
+-----------------------------------------------------------+
| Inside the initramfs Archive |
| |
| /init (Executable shell script or binary)|
| /bin/busybox (Single static binary: sh, mount) |
| /lib/modules/.../*.ko (Storage & filesystem drivers) |
| /dev/console, /dev/null |
| /newroot (Mount point for real root disk) |
+-----------------------------------------------------------+
Why an Initramfs is Necessary
In a simple development setup, the kernel could mount /dev/sda1 directly if its driver was compiled statically (=y). But in real-world systems, mounting the root filesystem requires complex userspace logic: - The disk might be an encrypted LUKS volume requiring a password prompt or TPM2 key unsealing. - The root might be an LVM logical volume or mdadm software RAID requiring scanning and activation. - The root might be on an NFS share or iSCSI SAN requiring DHCP lease acquisition. - Hardware device nodes are dynamic and require udev or mdev to settle.
The kernel delegates all this complexity to an early userspace script: /init.
Building a Minimal Initramfs by Hand
To truly understand how early boot works, we will construct a custom initramfs using BusyBox:
Step 1: Create the Directory Tree
$ mkdir -p initramfs-root/{bin,sbin,etc,proc,sys,dev,newroot}Step 2: Install BusyBox
Copy a statically linked busybox binary and create symlinks:
$ cp /bin/busybox initramfs-root/bin/
$ cd initramfs-root/bin
$ ln -s busybox sh
$ ln -s busybox mount
$ ln -s busybox umount
$ ln -s busybox switch_root
$ ln -s busybox sleep
$ cd ../..Step 3: Write the /init Script
Create an executable script at initramfs-root/init:
#!/bin/sh
# /init — BYOL Early Userspace Boot Script
echo "========================================="
echo " Welcome to BYOL Linux (Early Boot) "
echo "========================================="
# 1. Mount virtual kernel filesystems
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev
# 2. Parse kernel command line for root= parameter
ROOT_DEV=""
for param in $(cat /proc/cmdline); do
case "$param" in
root=*) ROOT_DEV="${param#root=}" ;;
esac
done
echo "[initramfs] Mounting real root: $ROOT_DEV to /newroot..."
# Wait for storage devices to settle
sleep 1
# 3. Mount real root disk
mount -o ro "$ROOT_DEV" /newroot
if [ $? -ne 0 ]; then
echo "[initramfs] FATAL: Failed to mount root filesystem!"
echo "[initramfs] Dropping into rescue emergency shell..."
exec /bin/sh
fi
# 4. Clean up mounts before switch_root
umount /proc
umount /sys
umount /dev
# 5. Pivot into permanent rootfs and invoke real PID 1
echo "[initramfs] Handing execution over to /sbin/init..."
exec switch_root /newroot /sbin/initEnsure the script has executable permissions:
$ chmod +x initramfs-root/initStep 4: Pack into a Compressed CPIO Archive
The kernel expects the archive in standard newc CPIO format:
$ cd initramfs-root
$ find . -print0 | cpio --null --create --format=newc | gzip -9 > ../initramfs.imgIn under 2 megabytes, you have engineered a fully functional early boot environment!