# Systemd initramfs The initial ramdisk is in essence a very small environment (early userspace) whihc loads various kernel modules and sets up necessary things before handing control over to `init` program (systemd). By default, Arch Linux uses a BusyBox+udev based initial ramdisk, generated by `mkinitcpio`. This default initrd is essentially just a small script, that executes other scripts, called hooks. As an alternative to this, it's possible to have systemd run from the very start, during that initial ramdisk phase. With this approach, the tasks ran at this phase are determined by regular systemd unit files. ## Why? Obviously, BusyBox initramfs works just fine, so why would you want to switch? Well, there's a few reasons: - **Consistency across boot phases:** The same systemd process that handles your system after boot can also manage the early userspace during boot, providing consistency in handling services, devices and dependencies throughout the entire boot process. - **Simplified troubleshooting:** The tools and logs available during the boot process will be the same as those used once the system is fully booted, allowing you to troubleshoot problems with familiar tools (`journalctl`, `systemctl`, ...) - **Consistent Unit Files:** Since systemd uses the same unit files in the initramfs as it does in the fully booted system, the configuration for many tasks (like mounting filesystems) is unified, reducing duplication of configuration files. - **TPM Unlocking Support:** Systemd has built-in support for requesting data from TPM, allowing for a setup with TPM auto-unlocking an encrypted root partition, without having to specify the decryption password. - **Parallel Service Startup:** Systemd is known for the ability to start services in parallel, which can potentially **speed up the boot process** compared to sequential script-based approach. - **Integrated Mount Handling:** With systemd, managing complex mount setup (e.g. LVM RAID) can be more seamless, since it natively supports these and can handle them with less custom scripting. That said, it's important to also mention some downsides and reasons why you might not want to use systemd-based initramfs: - **Simplicity:** If you prefer a simple, more minimalistic approach, BusyBox-based initramfs might be sufficient and easier to manage. - **Size:** A systemd-based initramfs might be larger than a minimal BusyBox-based initramfs, which could be a concern on systems with very limited space. - **Compatibility:** If you're running some custom scripts or hooks, they might not work with a systemd-based initramfs. ## Switching to systemd initramfs Open `/etc/mkinitcpio.conf` and find a line that starts with `HOOKS=` - Change `udev` to `systemd` - Change `keymap consolefont` to `sd-vconsole` - Add `sd-encrypt` before `block`, and remove `encrypt` - If you were using `mkinitcpio-numlock`, also remove `numlock`, it doesn't work with systemd (we'll go over how to auto-enable numlock later) Additionally, with systemd initramfs, you shouldn't be specifying `root` nor `cryptdevice` kernel arguments, as systemd can actually pick those up automatically (they'll be discovered by [systemd-cryptsetup-generator] and auto-mounted from initramfs via [systemd-gpt-auto-generator]). We will however still need the `rootflags` argument for selecting the btrfs subvolume (unless your default subvolume is the root partition subvolume). [systemd-cryptsetup-generator]: https://wiki.archlinux.org/title/Dm-crypt/System_configuration#Using_systemd-cryptsetup-generator [systemd-gpt-auto-generator]: https://wiki.archlinux.org/title/Systemd#GPT_partition_automounting So, let's edit our kernel parameters: ```bash echo "rw loglevel=3" > /etc/kernel/cmdline # overwrite the existing cmdline echo "rootflags=subvol=/@" >> /etc/kernel/cmdline ``` You'll also need to modify the `/etc/fstab`, as systemd will not use the `/dev/mapper/cryptfs` name, but rather you'll have a `/dev/gpt-auto-root` (there'll also be `/dev/gpt-auto-root-luks`, which is the encrypted partition). If you prefer using a mapper device, you can also use `/dev/mapper/root`. Alternatively, you can use the label to mount. (if you followed the installation guide, that would be `/dev/disk/by-label/FS`.) ```bash vim /etc/fstab ``` Finally, regenerate the initramfs with: `pacman -S linux` (you could also do `mkinitcpio -P`, however that won't trigger the pacman hook which auto-signs our UKI images for secure boot, so you'd have to re-sign them with `sbctl` manually, if you're using secure-boot) and reboot to check if it worked. ## Activating numlock Since we had to remove `mkinitcpio-numlock`, as that hook isintended for BusyBox based initrd, we'll want to have an alternative available. First though, we should also remove the package: `pacman -R mkinitcpio-numlock`. ### The simple, but imperfect option There is a `systemd-numlockontty` AUR package which creates a systemd service that enables numlock in TTYs after booting (you'll need to enable it), this however doesn't happen in initramfs directly, only afterwards. Depending on what you will need, this may be sufficient. If you are going to be typing a decryption password at this early stage and you wish to have numlock support there, you will need to do some more work. ### The proper solution To enable numlock before you're prompted for the decryption password, we'll need to create a custom initcpio hook, that will return a systemd service which will do the enabling. We'll put this hook into `/usr/lib/initcpio/install/numlock`, with the following content: ```bash #!/bin/bash build() { add_binary /bin/bash add_binary /usr/bin/setleds add_binary /usr/local/bin/numlock cat >"$BUILDROOT/usr/lib/systemd/system/numlock.service" < Running build hook: [base] -> Running build hook: [systemd] -> Running build hook: [autodetect] -> Running build hook: [microcode] -> Running build hook: [modconf] -> Running build hook: [kms] -> Running build hook: [keyboard] -> Running build hook: [sd-vconsole] -> Running build hook: [numlock] # <-- make sure this is present -> Running build hook: [sd-encrypt] -> Running build hook: [block] -> Running build hook: [filesystems] -> Running build hook: [fsck] ``` > [!NOTE] > If you see some warnings there, like: > `==> WARNING: Possibly missing firmware for module: 'xyz'`, you can usually > safely ignore these. Just make sure there's no `==> ERROR: ...` If you didn't see any errors, you can now reboot. > [!IMPORTANT] > In some cases, the numlock led indicator might not turn on immediately, even > though numlock was actually turned on. This may mislead you towards thinking > it is not on, even though it actually is. I'd recommend trying it out by > actually typing something it at this time. > > Note that after this early boot stage, the indicator should light up > eventually.