aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNatasha Moongrave <natasha@256phi.eu>2026-04-08 16:29:35 +0200
committerNatasha Moongrave <natasha@256phi.eu>2026-04-08 16:29:35 +0200
commiteb61ec76367731579eb585f39b251da629beb871 (patch)
tree3c32261feac8ef615db2772cee2715fd0ea169d1
parent0741fe434094aebab684c091e757812bff007a8e (diff)
[Step 0] Add PLAN.md and NOTES.md
PLAN.md: Full 7-phase development roadmap with progress tracker, per-phase tasks, integration test specs, security baseline, and dependency list. NOTES.md: Running developer log for context recovery after session resets. Documents key architecture decisions (GDT segment order, filesystem strategy, heap sizing, syscall ABI). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--NOTES.md78
-rw-r--r--PLAN.md226
2 files changed, 304 insertions, 0 deletions
diff --git a/NOTES.md b/NOTES.md
new file mode 100644
index 0000000..d140620
--- /dev/null
+++ b/NOTES.md
@@ -0,0 +1,78 @@
+# Strix OS β€” Developer Notes
+
+> **READ THIS FIRST after a context reset.** Then read `PLAN.md` for the full roadmap.
+> Updated at every commit.
+
+---
+
+## How to Resume After Context Reset
+
+1. Read this file top-to-bottom
+2. Read `PLAN.md` β€” check the Progress Tracker table for current status
+3. Run `cargo test` from `StrixKernel/` to confirm current build state
+4. Continue from the first `πŸ”² TODO` item in PLAN.md
+
+---
+
+## Current Status
+
+**Branch**: `CLAUDE_TEST`
+**Phase**: Starting Phase 2 β€” User Space Foundation
+**Last commit**: `[Step 0] Add PLAN.md and NOTES.md`
+**Next task**: `[Phase 2.1]` β€” Extend GDT with user space segments
+
+---
+
+## Key Decisions & Rationale
+
+| Decision | Rationale |
+|----------|-----------|
+| ext4 as primary filesystem | Nix requires symlinks, xattrs, POSIX perms; ext4 covers all. Impl as ext2 first |
+| SYSCALL/SYSRET for syscall interface | Faster than int 0x80; Linux ABI compatible |
+| GDT segment order: kcode/kdata/udata/ucode/tss | Required for STAR MSR arithmetic (see Phase 2.1 notes) |
+| Heap 100 KiB β†’ 4 MiB | Process table (256 entries) + 64 KiB kernel stacks needs > 16 MiB; start at 4 MiB |
+| goblin crate for ELF parsing | no_std compatible, well-maintained, handles ELF64 |
+| Embedded busybox initramfs | Self-contained rescue shell; no disk dependency for Phase 3 testing |
+| OpenRC default init, `init=` configurable | Lightweight; swappable without kernel changes |
+| W^X enforced on all mappings | Prevents code injection via data segments |
+| All user pointers validated | Prevents kernel memory disclosure/corruption via syscalls |
+
+---
+
+## Architecture Notes
+
+### GDT Segment Order (Critical for SYSCALL/SYSRET)
+```
+0x00: null
+0x08: kernel code (DPL=0) ← STAR[47:32]
+0x10: kernel data (DPL=0) ← auto: SYSCALL sets SS = 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)
+```
+STAR MSR values: `STAR[47:32]=0x08`, `STAR[63:48]=0x10`
+
+### Heap Layout
+```
+HEAP_START = 0x4444_4444_0000
+HEAP_SIZE = 4 MiB (was 100 KiB)
+```
+
+### Key Virtual Address Constants
+```
+Physical memory offset: 0x0000_2560_0000_0000 (from bootloader)
+Heap start: 0x4444_4444_0000
+User stack top: 0x7fff_f000_0000 (8 MiB stack)
+User address limit: 0x0000_8000_0000_0000 (canonical boundary)
+```
+
+---
+
+## Log
+
+### [Step 0] 2026-04-08 β€” Bootstrap repo docs
+**Done**: Created `PLAN.md` (full roadmap with progress tracker) and `NOTES.md` (this file).
+**Next**: Phase 2.1 β€” Extend GDT.
+**Decisions**: None new.
+
+---
diff --git a/PLAN.md b/PLAN.md
new file mode 100644
index 0000000..932fad6
--- /dev/null
+++ b/PLAN.md
@@ -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"
+```