| bootstrap | ||
| coreutils | ||
| mjolnob | ||
| staging | ||
| .gitignore | ||
| build.odin | ||
| README.md | ||
This repository contains the fruits of my decision to explore Linux in a barebones environment.
It exists here primarily for redundancy, but you're more than welcome to poke around with it.
See the Current State section at the bottom for an overview of progress.
Here are the big moving parts. I'll briefly cover each in its own section.
- the Linux kernel: I'm using 6.12.63 (LTS) as of the creation of this README; not included in the repo due to size
qemu-system-x86_64: probably available from your package manager; seeMakefilefor flags usedbootstrap: a basic init program for the initramfs environmentminit: a minimal PID 1 init that's started after switching to the persistent rootfstoybox: modern busybox; it does a lot of heavy lifting right now by way of providing shell utilitieslibodin: a WIP quasi-libc thing; mostly for convenience procs/wrappers I want available across programsmusl: used to avoid shipping glibc into the imageroot.img: not included due to size; 2GB image file with an ext4 filesystem on it; passed to qemu as/dev/sda
Linux LTS Kernel
As stated above, I'm using 6.12.63 as it was the latest LTS at the time of writing.
If you want to build this project yourself, it expects the kernel image to live at
$PROJECT_ROOT/linux-6.12.63/arch/x86_64/boot/bzImage, or you can adjust the path in
the Makefile accordingly.
My version is built with the default options. Nothing fancy here.
bootstrap
Bootstrap's job is to serve as a sort of "pre-init" while the system is still operating from the
initial ramdisk image.
It starts by mounting several special filesystems such as devtmpfs, proc, and sysfs.
After that it mounts the root filesystem on /dev/sda1 to /mnt/newroot and copies directories
from the ramdisk to the new root, skipping any existing files.
Once that's done, it performs execve to replace itself with toybox's switch_root command.
This pivots the root filesystem from the ram disk to /dev/sda1.
minit
This is the "real init", aka PID 1. It mounts devpts, then enters a loop.
It forks and opens tty1 before spawning Toybox's login command attached to it.
It then loops forever and reaps any orphaned PIDs.
There is plumbing there for graceful reboots but this does not yet work
inside this environment.
toybox
Toybox is a BusyBox alternative. Mostly chosen because when I tried to go get BusyBox, the site wouldn't load. It provides several standard utilities.
You can read more about it here.
libodin
I'd like to eventually build libodin out into a libc replacement for Odin, but that is currently
outside the scope of this project.
For now its job is to provide reusable procs for various system tasks such as mounting a filesystem,
reading the mounts table, or opening a tty.
musl
It's musl. Not much to say here. Find it here.
root.img
The virtual hard disk I'm using was created manually (because learning is fun). Below is a rough overview (not a tutorial) of the steps I used to create it.
fallocateto create the empty 2GB filefdiskto partition the filefdiskagain to find the byte offset of the start of the first partitionlosetupto attach that partition (unmounted) as a loop devicemkfs.ext4to format the partitionlosetupagain to detach the loop device
After that, you have essentially a bare hard disk image that can be passed to qemu.
Building
This project uses mjolnob as the build system. To build the project from a fresh clone:
odin build build.odin -file -out:nob
This will compile the build system into a binary named nob.
You can choose whatever name you like so long as it does not collide with other files in the project.
Once the build system is compiled, it will automatically detect changes in build.odin and rebuild itself when run.
./nob- This will build all the dependencies and create the initramfs image insidebuild/../nob run- This will rebuild the project (if necessary) and launch withqemu-system-x86_64../nob clean- This can be used to remove build artifacts (excluding the build tool itself).
Current State
As of the time of this readme edit, the system boot flow is this:
- kernel boots
- bootstrap mounts some stuff
- bootstrap does switch_root and hands off to minit
- minit mounts devpts
- minit spawns the service manager
- minit opens a tty and spawns /bin/login
- the service manager spawns klogd
The only account on the system is root. It has no password.