summaryrefslogtreecommitdiffstats
path: root/docs/plan-executable-binaries.md
blob: 138b8e049e5e266453c35f9bf4c53228e954398e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# Implementation plan — executable binaries and the /bin tree

Companion to ADR 0006.  Phases are strictly ordered where dependencies
say so; each phase ends with a QEMU verification gate.  Version bumps per
the glossary rules.

---

## Phase 0 — System image (build only, no kernel changes)

The build produces one dd-able FAT32 image instead of the current
two-source setup (vvfat `esp/` directory + separate `/tmp/disk.img`).

- [x] `scripts/mksystem.sh` creates
      `system.img`: `mkfs.fat -C`, then `mcopy` in
      `\bzImage`, `\EFI\` (as rsbl requires), `\etc\*` (motd moves out of
      the `fs.rs` code literal? — optional here), seed content.
- [ ] Stage `\bin\cli\` and `\bin\gui\` directories (empty for now).
- [ ] Makefile: build kernel → stage image; `run`/`run-gui`/`debug`
      attach **only** `system.img` on ide.0 (delete the
      `-drive file=fat:rw:$(ESP_DIR)` vvfat lines).
- [ ] Verify OVMF boots the single image end-to-end.

**Gate:** image boots; `ls /disk/<UID>/` shows `\bin`, `\etc`, seed files;
writes under `/disk/<UID>/` survive poweroff (existing FAT write-back).

---

## Phase 1 — Per-terminal input discipline (prerequisite)

Keyboard routing becomes total; canonical mode becomes per-terminal shell
property.  This is the original "per-instance shell" step, completed.

- [ ] WM pump routes keys unconditionally: IRQ ring → pump → focused
      window's queue.  No task ever polls the global ring directly.
- [ ] Home terminal (window 0) becomes an ordinary focusable window:
      clicking it focuses it; retire the `FOCUSED == CONSOLE` sentinel
      and the `focused() == 0` special cases from commit `09a44f1`.
      `focus_console()` becomes `focus(0)`.
- [ ] Each terminal's shell assembles lines canonically from its own
      queue (`tty::read_line_from_queue` path); delete the global-ring
      path through `tty::poll_key`.
- [ ] Raw-mode consumers that remain built-ins (`edit`, pager) read keys
      via the same focused-window queue, not the ring.
- [ ] Two terminals + home terminal: input always lands in the focused
      one; unfocused terminals keep rendering output from running
      commands.

**Gate:** three terminals open; typing switches cleanly with focus; no
keystroke ever appears in two terminals; `make test-disk` regression
passes (it drives the shell via injected keys).

---

## Phase 2 — Loader, Exports table, first exec (**bump 0.6.0**)

- [ ] New crate `rsapi` (or `rsnix::abi`): the versioned `Exports` struct,
      entry-point signature, ABI event/argv types shared by kernel and
      binaries.  Header carries `version: u32`.
- [ ] `rsnix::load`: PE32+ parser (headers, sections, `.reloc`
      application), alloc-copy-relocate, entry lookup.  ~300–500 lines.
- [ ] Spawn path: load → new task (own stack, guard page) → jump to entry
      with `(&Exports, argc, argv)`; completion message to spawner;
      pages freed on exit.
- [ ] Resolution: name → scan mounted volumes' `\bin\<kind>\<name>` →
      else built-in → else unknown.
- [ ] argv block: shell copies parsed positional args into the binary's
      memory; `argc/argv` C-style.
- [ ] First binary: `hello.efi` in `/bin/cli/` — calls one export
      (`put_line("hello")`) and returns 0.
- [ ] Crash containment check: a `boom.efi` that faults kills only its
      task; shell survives; `jobs` shows the corpse.

**Gate:** `hello` runs from the image, prints via exports, exits;
`boom` crashes gracefully; built-in fallback still works when the file
is absent; **version bump to 0.6.0**.

---

## Phase 3 — Streams, pipeline integration, line-tool migration

- [ ] Per-invocation line channel: bounded queue between owning shell and
      command task; shell pumps its key queue → canonical assembly →
      channel while a command runs (shell main loop gains a "pumping" mode).
- [ ] Exports streams: `get_line() -> {Line, Eof, Abort}`,
      `put_line(line) -> bool` (false = stop).  Shell-side implementations
      feed the filter pipeline / sink / tty exactly as built-ins do today.
- [ ] Grammar translation shell-side: USE/TIL resolve into the injected
      source; `<path> TIL <marker>` sugar strips paths from argv;
      filters/sinks wrap `put_line`.  Binaries never see keywords.
- [ ] ^C semantics: shell sees ^C while pumping → marks channel aborted →
      command's next stream call returns Abort/stop → completion → shell
      flushes `-t` windows.  `-p` pager blocks inside `put_line`.
- [ ] Migrate simple tools to `/bin/cli/`: `echo` stays frozen; migrate
      `ls`, `mem`, `pci`, `date`, `info`, `mkdir`, `touch`, `rm`,
      `hexdump`, `klog`, …  Each keeps its grammar behaviour verbatim.
- [ ] Migrate `cat` last (input consumer of every corner: heredoc, USE,
      TIL sugar, multi-path).

**Gate:** full `scripts/tests/test-disk.sh` grammar suite passes unchanged with
external binaries; `-h/-t/-g/-p` chains work across the task boundary;
^C flushes a tail window on an infinite stream.

---

## Phase 4 — GUI binaries

- [ ] Window/event exports: `create_window(title,w,h) -> id`,
      `window_buffer(id) -> (ptr,w,h)`, `flush(id)`, `destroy(id)`,
      `recv_event(&mut Ev) -> bool` (Ev mirrors Key/AppMouse/Focus/Close).
- [ ] Fire-and-forget spawn: shell returns immediately after spawning;
      exit = destroy window + task done.
- [ ] Migrate paint → `/bin/gui/paint`; `draw` resolves through the
      normal rule (no special case).
- [ ] F1-spawned terminals keep working alongside GUI binaries.

**Gate:** `draw` launches the migrated binary; pen draws; F4/close button
closes it; focus cycle and title-bar drag unaffected.

---

## Frozen built-in core (permanent)

`help`, `clear`, `echo`, `poweroff`/`exit`, `halt`, `rescan`.

Rationale: needed before disks exist, or exist to fix them.  `edit` also
stays built-in until the deferred raw-mode CLI ABI exists.

## Explicitly deferred (non-goals for this rework)

- Raw-mode surface access in the CLI ABI (needed before `edit` migrates).
- FAT shadowing of `/bin` beyond the system image.
- Boot-volume identity / root-path unification (`\etc` at `/etc`).
- Launcher (will simply enumerate `/bin/gui` once Phase 4 lands).
- Fixing compute-bound-binary ^C blindness (accepted policy).

## Version story

- Phases 0–1 land as 0.5.x increments if separate.
- **0.6.0 at Phase 2** — exec exists (glossary class `b`: big feature).