TINYRD(8) System Manager's Manual man.rawnix.org

tinyrd — the rawnix initramfs

tinyrd -o file

tinyrd is one static binary with two roles. Run with -o it writes a cpio archive whose /init is the binary itself; run as /init by the kernel it unlocks an encrypted root if there is one, mounts root, and hands over to the real init.

The archive carries no kernel modules and no configuration, so one image serves every kernel: nothing has to be regenerated when a kernel is installed or removed, and limine-sync(8) refers to it by a name with no version in it. The price is that everything needed before root is mounted must be built into the kernel; see KERNEL REQUIREMENTS.

The package ships the finished image as /boot/tinyrd.img, so building one by hand is only necessary when changing tinyrd itself.

As /init, tinyrd reads the kernel command line and nothing else.

Required: the root filesystem, as /dev/... or UUID=uuid. The UUID form survives the disk being renamed, which /dev/sda2 does not: adding a drive, moving a cable or booting the same image in a virtual machine is enough to change it. With cryptroot= this must be the mapped device, /dev/mapper/name.
Optional: the UUID of the , from cryptsetup luksUUID, not of the filesystem inside it. tinyrd asks for the passphrase and creates the mapping under the name taken from root=. Without this key it mounts root= directly, so the same image boots an unencrypted system.
Default ext4.
Passed to mount(2) as its data argument.
|
Default ro; the last one on the line wins.
Default /sbin/init.

After the switch, the new root sees exactly what the kernel would leave it with no initramfs at all: devtmpfs on /dev, root mounted, nothing else. Stage 1 needs no knowledge of tinyrd.

Because the image carries no modules, the kernel must have built in:

BLK_DEV_INITRD DEVTMPFS
BLK_DEV_DM DM_CRYPT CRYPTO_XTS
CRYPTO_AES_NI_INTEL CRYPTO_SHA256 CRYPTO_HMAC
CRYPTO_USER_API_SKCIPHER CRYPTO_USER_API_HASH

plus the root filesystem itself and whatever the keyboard needs to type a passphrase: i8042 and atkbd on most machines, xhci and usbhid for USB.

libcryptsetup here uses the kernel crypto backend, so every hash goes through AF_ALG. Without CRYPTO_USER_API_HASH the LUKS header will not load and the message is “Cannot initialize crypto backend”.

The rawnix kernels have all of this; a hand-rolled configuration is the place this goes wrong.

/boot/tinyrd.img
The image, staged by the package and copied to the ESP by limine-sync(8).

The tinyrd utility exits 0 on success, and >0 if an error occurs. As /init there is nowhere to return to: on a failure it reports what went wrong and stops, leaving the machine at a point where the message can be read.

Build an image:

$ tinyrd -o tinyrd.img

A command line for an encrypted root, as limine-sync(8) would write it:

cryptroot=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
    root=/dev/mapper/croot ro quiet

and for an unencrypted one:

root=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ro quiet

encryption(7), rawnix(7), cryptsetup(8), limine-sync(8)

zorz <zorz@rawnix.org>

The passphrase is typed before any keyboard layout is loaded, so it is read as if on a US keyboard.

October 3, 2026 tinyrd 0.3