Skip to content
mikecubedPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

335 Commits

Folders and files

Repository files navigation

m³OS

A serious, still-maturing bootable operating system written in Rust, targeting x86_64 with UEFI boot and a microkernel-inspired architecture. Built for learning and experimentation, it runs a real ring-3 userspace with multi-user login, an IPv4 TCP/UDP + AF_UNIX network stack, SSH/telnet remote administration, IOMMU-routed ring-3 block drivers (NVMe and AHCI/SATA, ext2 root) and NIC drivers (Intel e1000/e1000e/igb/igc and Realtek r8169/RTL8125) on a VirtIO baseline, a MediaTek mt792x Wi-Fi driver, a USB host stack with HID keyboard/mouse input, and a screenshot-validated graphical session (ring-3 display server + compositor clients + term + HDA/AC'97 audio). The recommended administration path is SSH-first / headless; the local graphical session is a supported workflow. See the 1.0 release gate for the authoritative support matrix — what is supported, on which targets, and what is explicitly out of scope.

Current kernel version: v0.83.0 — phase-tracked (0.NN.0 = Phase NN). Note "1.0" is a quality-bar milestone, not a SemVer 1.0.0 commitment: no public syscall/userspace ABI is frozen yet. See the 1.0 release gate.

Quick Start

Host prerequisites

Required for the supported headless/reference path:

  • Rust — nightly toolchain (pinned via rust-toolchain.toml). Install via rustup.
  • QEMU — qemu-system-x86_64 plus qemu-img
  • OVMF — UEFI firmware for QEMU
  • e2fsprogs — mkfs.ext2 and debugfs (used to build the ext2 data disk)

Optional, each unlocks an additional build target or workflow:

  • musl cross-compiler — required for the C userspace and musl-linked Rust demos
  • rustup target add x86_64-unknown-linux-musl — required for the Rust std demo crates
  • curl, tar, sha256sum — required to refresh the Lua/zlib port cache in target/ports-src/
  • sbsigntool (sbsign/sbverify) — required for cargo xtask image --sign (Secure Boot)

Missing optional tools are skipped with warnings rather than blocking the build.

Install on Ubuntu / Debian (including WSL)

sudo apt install qemu-system-x86 qemu-utils ovmf e2fsprogs \
                 musl-tools sbsigntool curl build-essential

Install on Arch Linux (including Omarchy)

sudo pacman -S qemu-base edk2-ovmf e2fsprogs sbsigntools curl
# Optional: GUI mode (`cargo xtask run-gui`) needs the SDL display plugin
# plus its OpenGL companion (`ui-sdl.so` has unresolved `egl_fb_*` symbols
# that live in `qemu-ui-opengl`). Skip both if you only ever run headless.
sudo pacman -S qemu-ui-sdl qemu-ui-opengl
# musl cross-compiler comes from the AUR:
yay -S musl-gcc-cross-bin

The xtask build system auto-detects both Debian/Ubuntu toolchain names (x86_64-linux-musl-gcc) and Arch cross-compiler names (x86_64-unknown-linux-musl1.2-gcc), and searches the OVMF paths for both distros. Minimal/static-only musl cross builds (e.g. a hand-installed musl-cross-make / raiden toolchain under /opt/) are missing the empty libdl.a / libpthread.a / librt.a stubs that ports like TCC expect; install the distro package (musl-tools on Debian/Ubuntu, musl-gcc-cross-bin on Arch) instead of relying on a minimal toolchain for the full-fat Phase 31 build.

Install Rust

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add x86_64-unknown-linux-musl   # for Rust std demos

First-time setup

After cloning, install the git hooks so quality gates run before each commit/push:

./setup.sh

Build and run

# Build and run in headless QEMU (serial only)
cargo xtask run

# Recreate the ext2 data disk, then run headless
cargo xtask run --fresh

# Build and run in QEMU with a framebuffer window + keyboard input
cargo xtask run-gui

# Build a bootable disk image (UEFI raw + VHDX for Hyper-V)
cargo xtask image

# Lint, format-check, run host-side kernel-core tests
cargo xtask check

The default pre-push hook runs cargo xtask check, cargo xtask smoke-test, and cargo xtask regression. Set M3OS_E1000_REGRESSION=1 before git push to also add the Phase 55c cargo xtask ssh-e1000-banner-check e1000 SSH-banner regression gate.

cargo xtask run is the primary supported workflow. It builds target/x86_64-unknown-none/release/boot-uefi-m3os.img, keeps the companion ext2 data disk at target/x86_64-unknown-none/release/disk.img, and also emits target/x86_64-unknown-none/release/boot-uefi-m3os.vhdx. run-gui is available for framebuffer debugging, but the headless serial path is the reference system.

run-gui launches QEMU with an SDL window so the guest PS/2 keyboard can be used. Click the QEMU window to grab input, then press Ctrl+Alt+G to release it. On Wayland-based desktops, if keyboard input feels unresponsive, prefix the command with SDL_VIDEODRIVER=x11 to force SDL through XWayland.

Debugging

Enabling kernel debug feature flags

Kernel debug features live behind cargo features in kernel/Cargo.toml so they add zero overhead to the default build. Enable one or more by passing them through the M3OS_KERNEL_FEATURES environment variable; xtask forwards them to cargo build --features kernel/... when it builds the kernel.

# Enable a single feature
M3OS_KERNEL_FEATURES=exec-trace cargo xtask run-gui --fresh

# Enable several at once (comma-separated)
M3OS_KERNEL_FEATURES=exec-trace,sched-trace cargo xtask run --fresh

Currently available debug features:

Feature Output When to use
exec-trace All [exec-trace] ... log lines: scheduler fork-task-spawn, process fork-child trampoline-enter and entering ring 3, syscall-return syscall-return-preempt (budgeted), every dup2 call, every execve attempt + outcome (incl. EFAULT / EACCES / read failures), and every close fd=F (skipped for pid=1). See kernel/Cargo.toml for the full emit list. Diagnosing a fork-child that never reaches userspace, a syscall return that fails to preempt when it should, an execve that fails silently, or any "process spawned but never observed" symptom.
sched-trace Per-block / wake / scan structured [TRACE] [sched] ... entries in the trace ring (see kernel/src/task/sched_trace.rs) Diagnosing scheduler fairness, IPC wake latency, or preemption-discipline bugs. Currently the rings are dumped on panic; a future control-socket hook (see dump_sched_trace_rings) would let you sample them on demand.

The [exec-trace] and [TRACE] [sched] emit sites are gated on #[cfg(feature = "...")] so default builds compile them out entirely. They are intentionally retained between debugging sessions so the next investigation can re-enable a focused subset without re-deriving the log shapes.

Always-on operational logs

A handful of structured log lines are emitted unconditionally because they are the canonical bring-up sentinels and the per-component liveness counters. None of them are feature-gated; default builds emit them at log::info! or via direct write_str to stdout/serial.

Source Pattern Meaning
term term: iter=N events=E composes=C pty_bytes=B (every 1000 iterations) Main-loop liveness counter. pty_bytes plateauing at 158 after /bin/PROMPT execs is the documented prompt-ready steady state.
term TERM_SMOKE:ready then later TERM_SMOKE:prompt-ready Service-registration ready, then prompt-readiness gate after the PTY proves the prompt path is alive.
audio_server AUDIO_SMOKE:server:READY AC'97 driver bound and the audio service is registered.
session_manager session_manager: session.boot: state=running (or text-fallback / recovering) Phase 57 supervised boot sequence reached its terminal state.
display_server display_server: compose#N <ok0|okN|err> writes=W ... (first 5 + every 60th) Compose-loop liveness counter. okN means non-zero framebuffer writes; ok0 means compose ran but had no surface damage; err means compose returned an error.
display_server display_server: AttachSharedBuffer ok shm_id=I va=... / ... shm_map failed shm_id=I SHM transport binding outcome for the term surface.
display_server display_server: client protocol violation reason=R label=L bulk_len=N body_len=B opcode=O Fatal protocol error decoded; the client is being disconnected. The discriminator fields are the next root-cause hook for burst-time CommitSurface failures.
syslogd / sshd <service>: prompt-ready gate open / ... timed out Phase 57d follow-up — these daemons block on the term.prompt-ready service before write-heavy setup so they cannot race the first graphical prompt with disk writes.
kernel [virtio-blk] completion poll + queue notify after request timeout owner_pid=P type=T sector=S completed=B Bounded no-yield timeout recovery on the single-flight virtio-blk request slot. Recoverable; not a graphical-boot blocker on its own.

The "Reading the boot log" table below covers the additional kernel-side fixed-format markers that differential triage hangs off of (fork:, framebuffer_mmap, etc.).

Capturing a clean serial transcript

cargo xtask run and run-gui always emit serial output through QEMU's -serial stdio, so the easiest way to capture a transcript is to redirect stdout to a file:

M3OS_KERNEL_FEATURES=exec-trace cargo xtask run-gui --fresh 2>&1 | tee m3os.log

For headless reproductions, cargo xtask run emits the same transcript without the SDL window, which is usually faster to iterate on:

cargo xtask run --fresh 2>&1 | tee m3os.log

Reading the boot log

The boot transcript contains a few well-known fixed-format lines you can grep for to triage common problems:

Pattern Meaning
[INFO] [proc] execve: pid=N path=... A privileged binary execed (only emitted for "interactive debug" paths like /bin/term, /bin/login, etc., to keep noise low).
[INFO] [proc] fork: parent_pid=... child_pid=... A parent forked. If the matching [exec-trace] pid=<child> ... line never appears under exec-trace, the child is stuck before its first syscall.
[INFO] [framebuffer_mmap] pid=N mapped ... display_server claimed the framebuffer. After this point the kernel framebuffer console can no longer write to the screen — output is serial-only until a graphical client paints.
display_server: registered as 'display.input-owner' ... The first Toplevel surface mapped, so stdin_feeder has handed PS/2 ownership over to the focus dispatcher. Absent ⇒ no graphical client mapped a Toplevel; PS/2 still goes through stdin_feeder to the kernel TTY.
TERM_SMOKE:ready term registered its IPC service and entered its main event loop. The shell child is exec-ing in parallel; expect an [exec-trace] ... execve OK path="/bin/ion" shortly after if exec-trace is on.

QEMU keyboard / display tips

  • Click the QEMU window to grab keyboard, Ctrl+Alt+G to release.
  • Headless (cargo xtask run) directs typed bytes to COM1 via -serial stdio, not to PS/2. PS/2 is only meaningful in run-gui.
  • Slow keyboard echo on run-gui was Phase 56-era chunked-pixel-upload overhead per glyph. The Phase 57d follow-up replaced the chunked transport entirely: term now allocates a shared-memory region, hands its ShmId to display_server via AttachSharedBuffer, and per-frame updates degenerate to a small DamageSurface + CommitSurface verb pair with no pixel transport. Compose is still throttled to ~60 Hz so PTY echo bursts coalesce.

Project Layout

kernel/     — The microkernel (boots, runs in ring 0)
xtask/      — Build tooling (run, image, test)
docs/       — Architecture docs and learning roadmap

Documentation

Full documentation lives in docs/:

Design Principles

  • Minimal TCB — The kernel does as little as possible.
  • Safety by default — unsafe only at hardware boundaries, always wrapped.
  • Incremental — Each phase produces a runnable artifact.
  • Self-contained — No large third-party runtimes.

Headless/Reference System

m3OS targets a headless/reference baseline as its primary supported configuration: cargo xtask run boots target/x86_64-unknown-none/release/boot-uefi-m3os.img together with target/x86_64-unknown-none/release/disk.img in QEMU, and cargo xtask image builds the same artifacts without launching QEMU. The supported workflow is to boot, log in, inspect services, verify storage and logging, compile bounded software, diagnose failures, and shut down cleanly over the serial/headless path. SSH is the default remote-admin path; telnet is available only with an explicit opt-in build flag.

The supported Rust std reference demos are hello-rust, sysinfo-rust, httpd-rust, calc-rust, and todo-rust. They are shipped as manual validation surfaces for the headless/reference image rather than part of the mandatory smoke bundle. The ports baseline always ships /usr/bin/port and the in-repo ports tree; ports that depend on host-fetched Lua/zlib sources require that cache to be present when the image is built.

See docs/53-headless-hardening.md for the learner-facing overview, and docs/roadmap/53-headless-hardening.md for the exact supported workflow, validation gate bundle, and support boundary. GUI, broad hardware certification, and large runtime ecosystems are later work.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages