Boot
UraniumOS boots on UEFI machines. The firmware starts limine from the EFI System Partition, limine loads the kernel and an initramfs, and the initramfs finds the root, applies pending changes from scram, mounts the root and starts busybox init, which runs /etc/rc and runsvdir (see services). The kernel has no module support. BIOS and Secure Boot are not supported.
The boot partition
The partition has the label URANIUMESP, is FAT32 and is mounted on /boot with umask=0077,nodev,nosuid,noexec. scram boot writes everything on it except what the firmware needs to find limine:
/boot/EFI/BOOT/BOOTX64.EFI limine, copied from the profile
/boot/limine.conf the menu
/boot/uranium/vmlinuz the kernel of the profile
/boot/uranium/initrd the initramfs of the profile
/boot/uranium/k-HASH/vmlinuz a kernel kept for older frames
/boot/uranium/k-HASH/initrd
The firmware has to start EFI/BOOT/BOOTX64.EFI, the path UEFI uses for removable media. Nothing in UraniumOS writes a boot entry into the firmware, so if the firmware does not start from this path, add an entry in its setup.
The partition is not part of any frame. To rebuild it, run scram boot from the installed system, or from a live medium with the root mounted. It copies the kernel, the initramfs and limine again and writes the menu. See manual install for the chroot.
The boot menu
scram boot [N] writes limine.conf and the files above. The menu is also rewritten by every scram frame when /boot/limine.conf exists, and after every successful rod +i, +r, +u and +a. Those automatic runs list all frames and hide errors, so run scram boot to see one. The initramfs never writes to the partition, so frames it takes (pre-commit, pre-flash, pre-revert) show in the menu only after the next run.
timeout: 3
serial: yes
/UraniumOS
protocol: linux
path: boot():/uranium/vmlinuz
module_path: boot():/uranium/initrd
cmdline: root=LABEL=uranium rw console=tty0 console=ttyS0,115200 slab_nomerge vsyscall=none debugfs=off randomize_kstack_offset=on
/Frame 20261029-030000-auto
protocol: linux
path: boot():/uranium/vmlinuz
module_path: boot():/uranium/initrd
cmdline: root=LABEL=uranium rw console=tty0 console=ttyS0,115200 slab_nomerge vsyscall=none debugfs=off randomize_kstack_offset=on uranium.frame=20261029-030000-auto
/Frame 20261029-010000-auto
protocol: linux
path: boot():/uranium/k-aaaaaaaaaaaa/vmlinuz
module_path: boot():/uranium/k-aaaaaaaaaaaa/initrd
cmdline: root=LABEL=uranium rw console=tty0 console=ttyS0,115200 slab_nomerge vsyscall=none debugfs=off randomize_kstack_offset=on uranium.frame=20261029-010000-auto
/Rescue shell
protocol: linux
path: boot():/uranium/vmlinuz
module_path: boot():/uranium/initrd
cmdline: root=LABEL=uranium rw console=tty0 console=ttyS0,115200 slab_nomerge vsyscall=none debugfs=off randomize_kstack_offset=on uranium.shell
This is scram boot output, shortened. The second frame was taken with another kernel.
timeout: 3,serial: yes- limine waits three seconds and then starts the first entry. The menu also shows on the serial port, so a VM or a headless machine can pick an entry there. The kernel console is
console=tty0 console=ttyS0,115200. UraniumOS- The system as it is. It is first, so it is the default.
Frame ID- One entry per frame, newest first. The entry adds
uranium.frame=IDto the command line, and the initramfs boots writable copies of the frame, see below.scram boot 20lists only the newest twenty, but the next automatic run lists all frames again. Only automatic frames are pruned, so the menu grows. Rescue shell- Adds
uranium.shell. The initramfs opens a shell before it touches the root.
The command line of each entry is root=LABEL=uranium rw console=tty0 console=ttyS0,115200, then the contents of /etc/cmdline (keep it to one line), then the argument of the entry. The label comes from SCRAM_LABEL. The stage ships /etc/cmdline with slab_nomerge vsyscall=none debugfs=off randomize_kstack_offset=on, see kernel. Run scram boot after editing the file. Press e in the menu to change one boot without saving it.
Kernels in frames
A frame stores the kernel and initramfs of the profile when it was taken, and an id that is a hash of both. scram boot compares that hash with the current kernel. A frame with a different kernel boots from /boot/uranium/k-HASH/. Each kernel is copied there once, and at most three are kept (SCRAM_KERNELS). A frame that would need a fourth boots with the current kernel, and so does a frame without a stored kernel, such as frames taken by the initramfs or received with scram receive. A k-HASH directory that no frame uses is deleted.
After a flash, a commit or a revert the partition still holds the earlier kernel. scram doctor warns about it and scram boot fixes it. A new kernel from rod +u reaches the partition at the next scram boot, which is the next frame or rod operation, or in an hour at the latest through autoframe. geiger warns when the running kernel differs from the one in the profile.
Kernel arguments
The initramfs reads these from /proc/cmdline. Other arguments go to the kernel.
root=SPEC | The btrfs filesystem. SPEC is LABEL=, UUID=, PARTUUID= or PARTLABEL= with a value, or the path of a block device. The initramfs waits up to 20 seconds for it. |
init=PATH | The program to start after switch_root. Default /rod/init/bin/init. |
uranium.frame=ID | Boot writable copies of the frame ID. Use the full directory name. |
uranium.shell | Open a shell in the initramfs before anything else. exit continues the boot. |
uranium.luks=DEVICE | Unlock an encrypted device first, see storage. |
uranium.luks.key=FILE | Unlock with this key file and ask no passphrase. |
uranium.live | Start from the ISO. The live medium sets it. |
The initramfs
The initramfs is the package initramfs-uranium: a gzip-compressed cpio archive with uranium-init.sh as /init, btrfs and cryptsetup, and some busybox applets. It has no scram, rsync or cp. The steps, in order:
- Mount
/proc,/sysand/devand read the command line. Withuranium.shell, say that a shell is starting and run it. - With
uranium.live, find the medium (below) and stop here. - With
uranium.luks, unlock the device asuranium-root. - Wait up to 20 seconds for the root device and mount its top level (subvolume 5) on
/top. - Unless a frame boot was asked for, revert an update that was not confirmed.
- Carry out the action in
.scram/boot-action. - With
uranium.frame, make writable copies of the frame. - Mount the root subvolume (and for a frame boot the home copy on
/home), move the top level to/run/scram/topin the new root, unmount/proc,/sysand/devand runswitch_root.
When a step fails, the initramfs reports what failed, says that it is dropping to a shell, and runs the shell. These are the causes:
The initramfs stops and drops to a shell when the root device does not appear within 20 seconds, when a device or the root subvolume cannot be mounted, when the frame named in uranium.frame= does not exist, when the encrypted device is missing or cannot be unlocked, or when the live medium or its image cannot be found or mounted.
The shell is busybox sh. To look at the filesystem from it, run mount -t btrfs -o subvolid=5 /dev/DEVICE /top. Leaving the shell with exit after a failure ends init and the kernel panics.
Live medium
The ISO has its own limine menu with the entries "UraniumOS live" and "UraniumOS live, shell in the initramfs", both with uranium.live. The initramfs looks for an ISO 9660 filesystem with /live/root.squashfs on every /dev/sr*, /dev/vd*, /dev/sd* and /dev/nvme*n* for up to 30 seconds. It mounts the image through a loop device, puts a tmpfs of 75% of the memory on top with an overlay, moves the mounts to /run/live and starts init. Changes in the live system stay in memory.
Booting a frame
The initramfs snapshots .scram/ID/@ and @home into .scram/live/@ and @home, replacing the copies of an earlier frame boot, and mounts them as root and as /home. It tells you that it is booting the frame and that changes are dropped at the next frame boot. The frame itself is not touched, so nothing on disk changes except .scram/live, which uses some space until the next frame boot replaces it. Everything done in a frame boot, including packages, files and home directories, is lost at the next frame boot. To keep the state of a frame, boot it and run scram flash FRAME or scram flash --boot FRAME from there.
A frame boot does not revert an update on trial and does not count as a boot for it.
Changes at boot
The root subvolume cannot be replaced while it is mounted, so scram commit --boot and scram flash --boot write one line to .scram/boot-action and the initramfs carries it out. scram status shows it while it is waiting, and scram cancel deletes it. The initramfs deletes the file after it acts, whatever the result.
commit | If .scram/try/@ exists: take a frame labelled pre-commit, replace @ with the copy, delete .scram/try, write the id of pre-commit to .scram/trial and create .scram/trial-boot. It tells you that the update was committed on trial and which frame undoes it. With no copy, it does nothing. |
flash ID, flash ID @ | If the frame exists: take a frame labelled pre-flash, replace @ and @home (or only @) with copies of the frame, and tell you which frame it flashed and how to undo it. A frame that does not exist is skipped without a message. |
Replacing a subvolume moves it's left-out subvolumes into the new copy, deletes the old one and moves the new one into its place. Frames taken by the initramfs have two snapshots and nothing else, no note and no kernel copy.
Trial boots and the revert
A commit at boot leaves the system on trial. Two files in .scram describe it, trial with the id of the pre-commit frame and an empty trial-boot. The initramfs applies these rules in order:
- At a normal boot, when
trialexists: iftrial-bootalso exists and thepre-commitframe still has its@, take apre-revertframe, replace@with a copy ofpre-commitand tell you that the update was not confirmed and was reverted. Then delete both files. Home directories are not changed. - The
commitaction, if scheduled, runs after that and starts a new trial. - Booting a frame skips the first rule and leaves the files for the next normal boot.
An update survives one boot unless scram confirm removes trial-boot before the next normal boot. The trial service does that by running scram verify at every boot. It waits five minutes, runs geiger up to three times and confirms on a pass. If geiger still fails, verify reboots and the initramfs reverts. If the system cannot start at all, the next reset boots into the revert. scram lists verify and its variables.
# rod +u
updating in a copy of the system
...
update ok, pending: commit with scram commit --boot
# scram commit --boot
commit scheduled for the next boot, it reverts unless you run scram confirm or the system stays healthy
# reboot
...
update committed on trial, undo with frame 20261102-165517-pre-commit
The same update, not confirmed:
# reboot
...
update was not confirmed, reverted to frame 20261102-165517-pre-commit, undo with frame 20261102-165524-pre-revert
The ids are examples. To undo a revert, flash the pre-revert frame. To undo a confirmed commit, flash the pre-commit frame.
The revert replaces @ and not @home, it applies only at the first normal boot after a commit, and it needs a normal boot to be possible. If limine, the kernel or the partition is broken, choose a frame in the menu or use the live medium.
After the initramfs
The init program is busybox init with this /etc/inittab:
::sysinit:/etc/rc
::respawn:/rod/profile/bin/runsvdir -P /etc/service
::ctrlaltdel:/rod/init/bin/reboot
::shutdown:/etc/rc.shutdown
/etc/rc mounts /proc, /sys, /dev, /dev/pts, /dev/shm, /tmp and /run, keeps /run/scram/top across the new tmpfs, remounts the root read-write and runs mount -a. Then it sets the hostname, loads the keymap, /etc/sysctl.conf and /etc/nftables.conf if they exist, sets up zram swap, brings up lo and runs /etc/rc.local. runsvdir starts the services in /etc/service. /etc/rc.shutdown runs sync and umount -a -r.
When it does not boot
- Choose a
Frameentry from before the change. It changes nothing on disk. If it works, runscram flash FRAMEto keep it, see scram. - If no menu appears the firmware did not start limine from the boot partition. If the partition is empty or damaged, boot the live medium, mount the root and the partition as in the manual install, and run
scram bootin the chroot. - If the initramfs stops in a shell, read the message above it. If it says that no root device was found, the label is not
uranium, or the disk is not visible. - The
Rescue shellentry gives a shell in the initramfs.
More is in troubleshooting.