rsinit is a minimalistic single binary init for the initramfs for embedded systems. It's main objective is to mount the root filesystem as fast as possible and then hand over to the actual init program.
The main use-case is, to mount root filesystems that cannot be mounted by the Linux kernel directly. But it can also mount just about anything that the kernel can mount directly based on the command-line.
Currently supported root filesystems are:
-
9pfs with USB gadget transport
-
filesystems on a dm-verity device
-
regular devices or anything that requires just specifying the device and mount options
-
nfsroot
-
9pfs with virtio transport (for QEMU)
One important design goal for rsinit is to be as fast as possible. For cases where the kernel can mount the same root filesystem directly, booting with rsinit should be just as fast as booting without it.
To achieve this, the initramfs must be as small as possible. Changes that significantly increase the binary size of rsinit are not acceptable. Crates that wrap external (C) libraries cannot be used.
In general, the binary size should be kept in mind when making any changes.
rsinit itself will only cover the simple use-cases to mount the root filesystem and related generic tasks with minimal runtime and build time configuration.
For more complex use-cases, e.g. to mount additional (overlay) filesystems, rsinit can be used as a crate in a custom rust application. The code is structured in a way that makes it possible to reuse the existing code and add new functionality as needed.
In general, rsinit uses the same parameters that the kernel would use when booting without an initramfs. Currently, the following parameters are interpreted by rsinit:
root=rootfstype=rootflags=ro/rwnfsroot=init=rsinit.bind_modules
With rootfstype=9p and trans=usbg in rootflags=, rsinit does all the
necessary things to boot from a 9pfs over USB.
In this case, root= can be used to specify the USB gadget device.
Otherwise the first gadget device is used.
To boot from USB, the kernel command-line arguments should look like this:
rootfstype=9p rootflags=trans=usbg,cache=loose,uname=root,access=any,dfltuid=0,dfltgid=0,aname=/path/to/the/rootfs
The specified path will depend on where the rootfs is located on the exporting
server and how the 9pfs server exports it.
With diod as 9pfs server and tools/usb/p9_fwd.py from the Linux kernel
source to bridge the 9p traffic from TCP to USB, the path is the absolute path
on the server.
In most cases, specifying the gadget device is not necessary, because there is
only on device.
If necessary something like root=ci_hdrc.0 can be used.
See the Linux kernel documentation
for more details on the mount options and 9pfs server setup.
If the file /verity-params exists in the initramfs then rsinit assumes
that a dm-verity protected rootfs should be mounted.
In this case, rsinit.verity_root= must be used to specific the root
device.
This is used instead of root= because it makes it harder to accidentally
mount the rootfs without dm-verity, e.g. if the initramfs is missing due to
some kind of misconfiguration.
rsinit assumes that the specified root device contains the rootfs and the
dm-verity hash tree.
The following parameters are read from /verity-params as <key>=<value>
lines:
VERITY_DATA_BLOCKS: The number of data blocks on the data device.VERITY_DATA_SECTORS: The number of data sectors on the data device.VERITY_DATA_BLOCK_SIZE: The block size on a data device in bytes.VERITY_HASH_BLOCK_SIZE: The size of a hash block in bytes.VERITY_HASH_ALGORITHM: The cryptographic hash algorithm used for this device.VERITY_SALT: The hexadecimal encoding of the salt value.VERITY_ROOT_HASH: The hexadecimal encoding of the root hash.VERITY_PARAMS: Optional space separated list of additional parameters. Defaults toignore_zero_blocksif not set.
With rsinit.bind_modules rsinit will will attempt to bind-mount
/lib/modules from the initrd at /root/lib/modules, providing them to the
rootfs.
rsinit will warn if the folder /lib/modules does not exist.
rsinit will refuse to bind-mount /lib/modules with an error if:
/lib/modules/<uname --kernel-release>does not exist/lib/modules/contains files or folders which do not match the current kernel release
The project includes a Makefile for easy cross-compilation.
Before building, ensure you have the following tools installed:
cross- Cross-compilation tool for Rustrustup- Rust toolchain managerpodmanordocker- Container runtime for crosscpio- For creating cpio/initramfs archivesgzip- For compressing cpio/initramfs archives- A
nightlyRust toolchain
You can verify all dependencies are installed by running:
make check-toolchainTo see all available make targets and options:
make helpCommon build commands:
# Build binaries and CPIO archives for all default targets
make all
# Build for a specific target only
make aarch64-unknown-linux-musl-build
# Create CPIO archive for a specific target
make aarch64-unknown-linux-musl-cpio
# Build with minimal profile (smaller binary size)
make MINIMAL_BUILD=1 all
# Use Docker instead of Podman
make CROSS_CONTAINER_ENGINE=docker allDefault target architectures:
aarch64-unknown-linux-muslarm-unknown-linux-musleabihfx86_64-unknown-linux-musl
Build artifacts are placed in target/<arch>/<profile>/ directories.