diff options
Diffstat (limited to 'PLAN.md')
| -rw-r--r-- | PLAN.md | 226 |
1 files changed, 226 insertions, 0 deletions
@@ -0,0 +1,226 @@ +# Strix OS — Full Development Plan + +> This file is the authoritative development roadmap. Update the **Status** column as phases complete. +> See `NOTES.md` for the running developer log (context recovery after resets). + +## Filesystem Strategy + +| Filesystem | Role | Phase | +|-----------|------|-------| +| **ext4** | Persistent root, Nix store | ext2 read-only (4) → ext4 xattrs (5) → write+journal (7) | +| **ramfs/tmpfs** | Initramfs root, /tmp | Phase 4 | +| **devfs** | /dev | Phase 4 | +| **procfs** | /proc | Phase 4 | +| **sysfs** | /sys skeleton | Phase 6 | +| **overlayfs** | Nix profile layering | Phase 6 | + +## Branch & Commit Policy + +- Work on `CLAUDE_TEST` or `CLAUDE_`-prefixed branches only +- Commit format: `[PhaseX.Y] description` +- Commit after each sub-task when all tests pass +- Update `NOTES.md` with every commit + +--- + +## Progress Tracker + +| Phase | Status | Description | +|-------|--------|-------------| +| Phase 1 | ✅ DONE | Memory management (GDT/IDT/PIC/heap) | +| Step 0 | ✅ DONE | Repo docs (PLAN.md, NOTES.md) | +| Phase 2.1 | 🔲 TODO | GDT user space segments | +| Phase 2.2 | 🔲 TODO | SYSCALL/SYSRET MSR setup | +| Phase 2.3 | 🔲 TODO | Syscall dispatcher | +| Phase 2.4 | 🔲 TODO | Process structure | +| Phase 2.5 | 🔲 TODO | Round-robin scheduler | +| Phase 2.6 | 🔲 TODO | Ring 3 jump (iretq) | +| Phase 3.1 | 🔲 TODO | ELF64 parser | +| Phase 3.2 | 🔲 TODO | Per-process page tables | +| Phase 3.3 | 🔲 TODO | User stack setup | +| Phase 3.4 | 🔲 TODO | execve syscall | +| Phase 3.5 | 🔲 TODO | Busybox embedded initramfs | +| Phase 4.1 | 🔲 TODO | VFS core abstractions | +| Phase 4.2 | 🔲 TODO | File descriptor table | +| Phase 4.3 | 🔲 TODO | ramfs/tmpfs | +| Phase 4.4 | 🔲 TODO | Initramfs unpacking | +| Phase 4.5 | 🔲 TODO | devfs | +| Phase 4.6 | 🔲 TODO | procfs | +| Phase 4.7 | 🔲 TODO | ATA driver + ext2 read-only | +| Phase 5.1 | 🔲 TODO | fork/clone | +| Phase 5.2 | 🔲 TODO | wait/waitpid | +| Phase 5.3 | 🔲 TODO | Signals | +| Phase 5.4 | 🔲 TODO | Pipes | +| Phase 5.5 | 🔲 TODO | Shell syscalls (stat/chdir/symlink/mmap/etc.) | +| Phase 6.1 | 🔲 TODO | TTY/PTY subsystem | +| Phase 6.2 | 🔲 TODO | mount/umount/pivot_root/chroot | +| Phase 6.3 | 🔲 TODO | Init launch (init= param, PID 1) | +| Phase 6.4 | 🔲 TODO | Mount namespaces (CLONE_NEWNS) | +| Phase 6.5 | 🔲 TODO | overlayfs | +| Phase 7.1 | 🔲 TODO | Dynamic linker (PT_INTERP) | +| Phase 7.2 | 🔲 TODO | File-backed mmap | +| Phase 7.3 | 🔲 TODO | ext4 write + journal | + +--- + +## Phase 2 — User Space Foundation + +**Goal**: Hello World from Ring 3 via SYSCALL. + +### 2.1 GDT Extension +**File**: `StrixKernel/src/gdt.rs` +- GDT order (required for SYSCALL/SYSRET ABI): + - `0x08`: kernel code (DPL=0) ← `STAR[47:32]` + - `0x10`: kernel data (DPL=0) ← auto-selected by SYSCALL as CS+8 + - `0x18`: user data (DPL=3) ← `SYSRET SS = STAR[63:48]+8` + - `0x20`: user code (DPL=3) ← `SYSRET CS = STAR[63:48]+16` + - `0x28/0x30`: TSS (128-bit) +- Add `TSS.privilege_stack_table[0]` = 8 KiB static stack (RSP0 for Ring3→Ring0) +- Expose `Selectors` struct fields as `pub` +- Add `set_kernel_stack(VirtAddr)` for scheduler to update RSP0 + +### 2.2 SYSCALL/SYSRET MSR Setup +**File**: `StrixKernel/src/syscall/mod.rs` (new) +- `STAR[47:32]` = kernel CS (0x08), `STAR[63:48]` = 0x10 (→ user SS=0x18, user CS=0x20) +- `LSTAR` = address of `syscall_entry` stub +- `SFMASK` = clear IF (disable interrupts on SYSCALL entry) +- Entry stub: save rax/rcx/rdx/rsi/rdi/r8-r11 to kernel stack; call `syscall_handler` +- ABI: syscall# in rax, args in rdi/rsi/rdx/r10/r8/r9; return in rax; negative = errno +- Security: ALL user pointers validated to be in range `0..0x0000_8000_0000_0000` + +### 2.3 Syscall Dispatcher +**File**: `StrixKernel/src/syscall/dispatch.rs` (new) +- `write` (1): fd=1/2 → VGA/serial (no VFS yet) +- `exit` (60) / `exit_group` (231): mark process exited, schedule next +- All unknown → return `-ENOSYS` (not halt/panic) + +### 2.4 Process Structure +**File**: `StrixKernel/src/task/process.rs` (new) +- `ProcessState`: Running, Ready, Zombie +- `Process`: pid, state, page_table, kernel_stack_top, saved_regs (callee-save) +- `PROCESS_TABLE`: `spin::Mutex<[Option<Process>; 256]>`; PID 0 = idle, PID 1 = init + +### 2.5 Scheduler +**File**: `StrixKernel/src/task/scheduler.rs` (new) +- Timer IRQ → `schedule()` → round-robin PROCESS_TABLE +- `switch_to(next)`: save current callee-saves to current Process, restore next's +- Before returning to user: `gdt::set_kernel_stack(next.kernel_stack_top)` +- Grow heap: `HEAP_SIZE` 100 KiB → 4 MiB + +### 2.6 Ring 3 Jump +**File**: `StrixKernel/src/task/spawn.rs` (new) +- `spawn_user_task(entry: u64, user_stack: u64)` via `iretq` +- iretq frame: `[user_ss, user_rsp, rflags (IF=1), user_cs, entry_rip]` + +### Phase 2 Integration Tests +- `tests/userspace_syscall.rs`: Ring 3 stub → `write` → serial "RING3" → `exit(0)` +- `tests/scheduler.rs`: 3 tasks, atomic counter, confirm all run in 1000 ticks +- `tests/syscall_invalid.rs`: unknown# → `-ENOSYS`; kernel pointer → `-EFAULT` + +--- + +## Phase 3 — ELF Loading & execve + +**Goal**: Execute static ELF binaries; embed busybox as rescue shell. + +### 3.1 ELF64 Parser +**File**: `StrixKernel/src/loader/elf.rs` (new) +**Dep**: `goblin = { version = "0.7", default-features = false, features = ["elf64"] }` +- Validate magic, e_type; enumerate PT_LOAD; map R/W/X per flags +- Security: W^X enforced; segment offset/size bounds-checked + +### 3.2 Per-Process Page Tables +**File**: `StrixKernel/src/memory/address_space.rs` (new) +- `AddressSpace::new()`: new L4, copy kernel high-half +- `map_range(vaddr, size, flags)`; `switch()` → CR3; frame tracking for cleanup + +### 3.3 User Stack Setup +**File**: `StrixKernel/src/loader/stack.rs` (new) +- Stack at `0x7fff_f000_0000` (8 MiB) +- Writes: argc, argv[], envp[], AT_* aux vector (in correct order for musl/glibc) + +### 3.4 execve (#59) +**File**: `StrixKernel/src/syscall/exec.rs` (new) +- Validate path + argv/envp in user range +- ELF parse → new address space → stack setup → enter Ring 3 +- PT_INTERP handling: load interpreter binary, pass aux vector + +### 3.5 Embedded Busybox +**Files**: `StrixKernel/build.rs` (new), `StrixKernel/initramfs/` +- `build.rs` packs `initramfs/` into cpio → `include_bytes!` +- Applets via symlinks: `sh`, `ls`, `cat`, `echo`, `mv`, `cp`, `rm`, `mkdir`, `pwd`, `mount`, `ln`, `stat`, `env`, `kill` + +### Phase 3 Integration Tests +- `tests/elf_static.rs`: hand-crafted ELF → exit(42) → confirm +- `tests/elf_wxcheck.rs`: W+X segment → `Err(WxViolation)` +- `tests/elf_bounds.rs`: out-of-bounds segment → `Err(InvalidSegment)` +- `tests/address_space.rs`: two spaces, same vaddr → isolation confirmed + +--- + +## Phase 4 — Virtual File System + +### 4.1–4.7 (VFS, ramfs, initramfs, devfs, procfs, ext2) + +See full plan in `/home/mun/.claude/plans/synthetic-drifting-globe.md`. + +### Phase 4 Integration Tests +- `tests/vfs_ramfs.rs`, `tests/vfs_devnull.rs`, `tests/vfs_procfs.rs` +- `tests/initramfs_unpack.rs`, `tests/ext2_read.rs`, `tests/fd_table.rs` + +--- + +## Phase 5 — POSIX Essentials + +### 5.1–5.5 (fork, wait, signals, pipes, shell syscalls) + +### Phase 5 Integration Tests +- `tests/fork_basic.rs`, `tests/fork_isolation.rs` +- `tests/signals_basic.rs`, `tests/pipe_basic.rs`, `tests/pipe_shell_pipeline.rs` +- `tests/symlink.rs`, `tests/ext4_xattr.rs` + +--- + +## Phase 6 — Init System Agnosticism + +### 6.1–6.5 (TTY, mount syscalls, init= param, namespaces, overlayfs) + +**Init is configurable**: `init=` kernel param; default `/sbin/init`; fallback `/bin/sh` + +### Phase 6 Integration Tests +- `tests/tty_canonical.rs`, `tests/mount_remount.rs`, `tests/pivot_root.rs` +- `tests/chroot_isolation.rs`, `tests/overlayfs_cow.rs`, `tests/mount_namespace.rs` + +--- + +## Phase 7 — Dynamic Linking & Nix + +### 7.1–7.3 (PT_INTERP, file mmap, ext4 write) + +### Phase 7 Integration Tests +- `tests/mmap_file.rs`, `tests/mmap_wx_rejected.rs` +- `tests/dynamic_elf.rs`, `tests/ext4_write.rs` + +--- + +## Security Baseline (always enforced) + +| Rule | Location | +|------|----------| +| User pointers validated `0..0x0000_8000_0000_0000` | Every syscall with ptr arg | +| W^X: no WRITE+EXEC mapping | ELF loader, mmap | +| No kernel addresses in userspace | procfs output, aux vector | +| No `unwrap()` in kernel paths | Everywhere — use `?` or explicit match | +| Signal handler ptr validated | signal.rs | +| ELF segment bounds checked | elf.rs | +| ext4 on-disk values validated | ext4.rs | +| chroot path escape prevention | mount.rs path resolver | + +--- + +## New Dependencies to Add + +```toml +goblin = { version = "0.7", default-features = false, features = ["elf64"] } +bitflags = "2.4" +``` |
