Files
SUB-OS/docs/AUTODEV_ROADMAP.md
T
Claude a14a7c79b0 feat(sched): Weave tiered scheduler with real kernel-thread context switching
Replace the state-relabel-only round-robin with the SUB-OS "Weave"
scheduler backed by a genuine callee-saved context switch. Threads now
actually run on their own kernel stacks instead of merely having their
state field rewritten.

What was implemented:
- sub_ctx_switch(): per-arch assembly (arch/x86_64/cpu/switch.asm,
  arch/aarch64/cpu/switch.S, arch/armv8i/cpu/switch.S) that saves/restores
  the callee-saved register set (+ flags on x86_64) on each thread's own
  stack, plus a first-run trampoline (sub_thread_trampoline) that launches
  a freshly forged thread frame with entry/arg in callee-saved registers.
- task_forge_frame(): builds the initial saved-context frame per arch so
  the very first switch into a new thread lands on the trampoline; task_t
  gains a pointer-sized ctx_sp so the same struct works on 64- and 32-bit.
- Weave policy (kernel/sched.c): WEAVE_NLANES priority lanes, always
  dispatch the lowest non-empty lane round-robin; a task that yields
  voluntarily is woven UP a lane (interactive), one preempted after
  burning its quantum is woven DOWN (CPU-bound). Cooperative switching
  (sched_yield / task_exit) is always live; timer-driven preemption is
  gated behind sched_set_preempt() and left disarmed for now.
- task_exit() now switches to the next runnable thread via
  sched_exit_current() instead of spinning/halting.
- Boot-time weave_selftest() (x86_64) and sched_dump() diagnostics.

How it was verified:
- Builds clean for all three targets: x86_64 (CROSS_COMPILE=x86_64-linux-gnu-,
  RUSTC="rustc --target x86_64-unknown-none"), aarch64, armv8i. No new
  warnings; the new x86_64 asm carries a .note.GNU-stack section.
- Booted x86_64 under QEMU (TCG): the self-test runs three cooperative
  kernel threads to completion on separate stacks with the expected
  1->2->3 round-robin interleave, reports "20 real context switches,
  3/3 workers exited", returns cleanly to the boot thread, and boot
  proceeds normally to ring-3 init and the shell. No fault/panic.

Left unverified:
- The aarch64/armv8i sub_ctx_switch frames build and link but are not yet
  boot-tested on their QEMU targets (tracked in docs/AUTODEV_ROADMAP.md).
- Timer preemption path is implemented but disarmed; exited kernel threads
  currently leak their stack (reaper is next in the backlog).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Jk6K69yGS7zYgvoWd6nJxQ
2026-08-25 08:16:37 +00:00

3.9 KiB

SUB-OS Autonomous Development Roadmap

This file is the cross-run memory for the continuous-development effort. Each run: read it, pick the single highest-value NEXT item achievable in one session, implement + verify it, then move it to DONE with a one-line result and refine the backlog.

Known-good build invocations (this host)

  • Toolchain setup: apt-get install -y nasm gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf qemu-system-x86 qemu-system-arm; for Rust: rustup target add x86_64-unknown-none.
  • x86_64: make x86_64_defconfig && make CROSS_COMPILE=x86_64-linux-gnu- CXX=x86_64-linux-gnu-g++ RUSTC="rustc --target x86_64-unknown-none"
  • aarch64: make aarch64_defconfig && make
  • armv8i: make armv8i_defconfig && make
  • Boot (x86_64, headless): qemu-system-x86_64 -drive format=raw,file=SUB-OS.img -m 256M -netdev user,id=net0 -device e1000,netdev=net0 -serial stdio -display none (slow under TCG; the shell waits on input, so a timeout at the prompt is normal).

DONE

  • Weave scheduler + real kernel-thread context switching (2026-08-25): Replaced the state-relabel-only round-robin with the SUB-OS "Weave" tiered scheduler backed by a genuine callee-saved context switch (sub_ctx_switch, per-arch assembly for x86_64/aarch64/armv8i) and a first-run trampoline. Threads run on their own kernel stacks; a task's lane floats on behaviour (voluntary yield → woven up, quantum-burn → woven down). Verified on x86_64 under QEMU: a boot-time self-test runs 3 cooperative kernel threads to completion (20 real context switches, correct 1→2→3 round-robin interleave, clean return to the boot thread, then boot proceeds to ring-3 init + shell). ARM switch asm builds on both targets but is not yet boot-tested.

NEXT (prioritized backlog)

  1. Preemptive Weave scheduling from the timer tick. The plumbing exists (sched_set_preempt, sched_tick charges the quantum). Arm it after boot completes, make the PIT ISR path re-entrancy-safe (switch on IRQ return, not mid-handler), and add a preemption self-test showing a CPU-bound thread being woven down while an interactive one stays in lane 0. Needs an IRQ-context switch (save the full trap frame, not just callee-saved state).
  2. Thread reaping / zombie cleanup. Exited kernel threads currently leak their 16 KB stack + task_t. Add a reaper (per-CPU dead list drained by the idle thread) so task_exit hands the corpse to it instead of leaking.
  3. Boot-test the ARM context switch. Wire a weave_selftest() call into the aarch64/armv8i boot paths and boot under qemu-system-aarch64/-arm to confirm the AArch64/AArch32 sub_ctx_switch frames are correct.
  4. fork/exec/wait for the ring-3 userland. Build on the existing ELF64 loader + per-process page tables so sh can spawn and reap real children, not just the single builtin init.
  5. An original capability-based IPC channel ("sub-ports"): typed, capability-addressed message endpoints distinct from the SysV msg/pipe/shm set already present in ipc/ — leaning into the "object-first" identity.
  6. SMP bring-up (x86_64): AP boot trampoline, per-CPU run lanes, and making the Weave lanes per-CPU with work-stealing between them.
  7. GUI (feat/gui-desktop): compositor damage tracking, a VFS-backed file manager, a text editor, and a settings panel over the toolkit widgets.

Notes / gotchas

  • .S files are run through cpp: no nested /* ... */ comments.
  • printk/vsprintf supports only c s d i u o x X p % — no length modifiers (l, ll) and no field width; cast to int/unsigned/void*.
  • list_del() NULLs both links, so list_empty() is not a reliable "is this node queued?" test after a delete — check the links directly.
  • During subos_modular_core_boot() step 13, hardware interrupts are still masked (enabled at step 14), so cooperative in-boot tests are deterministic.