From 9b9758e5ee2564b04685eadf2b9ce23dd1060b86 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sat, 1 Aug 2026 19:34:40 +0200 Subject: rsnix v0.4.0: GUI input foundation — PS/2 mouse + scheduler message queues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mouse (IRQ12, stream mode): ByteRing generalized for both PS/2 devices, ISR routes data-port bytes by the controller's aux bit; mouse_init with bounded-ACK handshake (boots without a mouse); packet decoder with bit-3 resync, screen-relative deltas, buttons. Exposed as /dev/mouse, the `mouse` stream command, and `make test-mouse`. Message queues (ADR 0003's GUI-era primitive): every task gets a static 16-slot TaskMsg ring; send/recv/recv_blocking with direct wake + tick scan safety net for the lost-wakeup race; `msgrecv`/`send` commands, `mouse ` routes real IRQ12 events into a task's queue, jobs shows q=. `make test-msg` + `make test-disk` regression pass. --- CONTEXT.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) (limited to 'CONTEXT.md') diff --git a/CONTEXT.md b/CONTEXT.md index 112b8de..9ceb81d 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -113,7 +113,9 @@ Workspace version is `a.b.c` (single version for all crates): Bump the workspace version in the root `Cargo.toml` when a change of that class lands — do not leave the version to drift. Current: -`0.2.0`; the multitasking work lands as a `b` bump (`0.3.0`). +`0.4.0` — the GUI input foundation (PS/2 mouse + scheduler message +queues) landed as a `b` bump; the GUI era itself is reserved for the +`a` bump (1.0.0). ## Project layout @@ -404,6 +406,75 @@ Workspace of four crates, all built for the `x86_64-unknown-uefi` target: `bg overflow` dies on the guard page with the machine intact; full regression (rescan/til/klog/grammar/pager) re-passes. +✅ **PS/2 mouse** — auxiliary-channel driver on IRQ12, stream mode + (3-byte packets), the GUI's second input device: + +- `interrupts`: the keyboard byte ring is generalised to `ByteRing`; + IRQ12 (vector 44) gets its own ring and stub. Both PS/2 handlers + route each data-port byte by the controller status register's aux + bit (bit 5), so keyboard and mouse never steal each other's bytes + even when both are pending at once. PIC unmask now covers IRQ2 + (cascade) and IRQ12 (slave bit 4). +- `ps2`: `mouse_init()` enables the aux port, sets config bits + IRQ12+aux-clock (preserving the keyboard bit), then `set defaults` + (100 Hz / 4 counts/mm / 1:1) + `enable reporting` via the 0xD4 + channel — each waits for the device ACK with a bounded timeout so + a machine without a mouse boots normally (log: `ps2: mouse not + present`). `try_poll_mouse()` reassembles packets in main + context from the raw byte ring; the packet-start marker (bit 3) + resyncs the stream after any lost byte. Events are **screen- + relative** (`dx` + = right, `dy` + = down — the PS/2 Y-up wire + convention is negated), buttons decoded; 9-bit sign extension via + the packet sign bits. +- `fs`: `/dev/mouse` char device — `cat /dev/mouse` drains up to 32 + pending events (`dx=+N dy=+N buttons=L-R`), reports + `mouse: no PS/2 mouse` / `mouse: no events` otherwise. +- shell: `mouse` command streams live events (10 ms poll via + `sleep_ms`) until ^C. + + Verified in QEMU (`make test-mouse`, headless, via the monitor's + `mouse_move`/`mouse_button` HMP commands): boot line `ps2: mouse + ready`, `/dev/mouse` drains a pre-consumer move (`8,4`), the live + stream decodes `mouse_move 20 7` → `dx=+20 dy=+7 buttons=---`, + `mouse_button 1` → `buttons=L--`, a held-button move + (`-5,-3` while L down) → `dx=-5 dy=-3 buttons=L--`, release, + and ^C stops the stream. `make test-disk` regression re-passes. + +✅ **Scheduler message queues (the GUI-era primitive from ADR 0003)** — + every task gets a static 16-slot ring of `TaskMsg` (4 KB in .bss, + no ISR-time allocation): + +- `TaskMsg` = `Key(KeyEvent)` | `Mouse(MouseEvent)` | `Timer` | + `User(u64)` — input uses the same decoded types the PS/2 drivers + produce, so window input routing is literally "post what the + console would have gotten"; `User(u64)` is the generic escape + hatch. `KeyEvent`/`MouseEvent` derive Copy for ring storage. +- `sched::send(id, msg)` — posts from any context (task, shell, ISR) + under the scheduler lock; wakes a Blocked task straight to Ready; + errors cleanly on a gone task or a full queue (input is lossy + under extreme load by design). `recv()` pops without blocking; + `recv_blocking()` marks the task Blocked and yields. **Lost-wakeup + safety net**: the tick scan also wakes Blocked tasks whose queue is + non-empty, so a task that blocked *after* its message arrived (or + whose poster never woke it) is picked up within one 10 ms tick. +- shell: `msgrecv` spawns a task that blocks on recv and logs every + message to serial (`msgrecv[2]: Key(F3)` …); `send + [args]` posts `user ` / `timer` / `mouse ` + (1=L 2=R 4=M) / `key ` (enter esc tab space bksp arrows + home end pgup pgdn del ctrl-c f1..f12, or a single char); `jobs` + now shows `q=` (pending message count). +- **Real-input routing, proven**: `mouse ` (angle brackets) streams + decoded IRQ12 events into that task's queue instead of the console + — the exact loop the window manager will run. `msgrecv` + `mouse 2` + - `mouse_move 20 7` showed `msgrecv[2]: Mouse(+20,+7 …)` in QEMU. + + Verified in QEMU (`make test-msg`): all six message types delivered + in order (user, timer, key enter/ctrl-c/f3, synthesized mouse), + real routed mouse moves (including a held-button move), the 17th + send against a 16-cap queue reports `queue full` (tested against + the shell's never-consumed queue), and `jobs` shows q=0 + task back + to `blocked` after draining. `make test-disk` regression re-passes. + ## Known issues / perf notes - **Scroll cost** — scrolling still shifts the whole framebuffer (a -- cgit v1.2.3