summaryrefslogtreecommitdiffstats
path: root/CONTEXT.md (follow)
Commit message (Collapse)AuthorAgeFilesLines
* docs: ADR 0006 (executable binaries) + implementation plan + glossary termssalmonik2026-08-211-0/+35
| | | | | | | | | | | | | | ADR 0006: PE32+ loader in rsnix, versioned exports-table ABI constructed per invocation, task-per-binary, single dd-able system image with /bin/cli and /bin/gui, shell-owned grammar with injected line streams, per-terminal input discipline as prerequisite phase, frozen built-in core, 0.6.0 at first exec. Plan: five phases (image → input discipline → loader/exec → streams + migration → GUI binaries), each with a QEMU verification gate. Glossary: Binary, Loader, Exports table, System image; kind = launch surface.
* Terminal-app design (ADR 0005) + disk-write controllersalmonik2026-08-171-3/+11
| | | | | | | | | - ADR 0005: persistent home terminal (full-screen, chrome-less, bottom-pinned), F1 terminal windows, per-instance vt/tty/shell, queue-based input for all terminals, and the disk controller - Glossary: add the Terminal term; update Task/App for the new model - Add a re-entrant disk lock (DiskGuard over the preemption-depth counter) and wrap all fs/fat mutating operations per-call
* Windowed GUI: wm module, input routing, and the paint appsalmonik2026-08-171-0/+52
| | | | | | | | | | | | | | - Add the wm window-manager facility per ADR 0004: overlapping pixel-surface windows, damage-rectangle compositing, WM-drawn title bar, focus/minimize/close, and F1-F4 keybindings - Add gop shadow compositing primitives and vt::repaint_region so the console stays layer 0 beneath windows - Route mouse (absolute coords, press/release edges) and keyboard (focus-aware input pump) to the focused window - Add the rspaint drawing-program crate (pen, 8 colors, clear) and shell draw/windows/restore commands - Extend TaskMsg with AppMouse/Focus/Close and document the design in CONTEXT.md + ADR 0004
* docs: CONTEXT.md versioning — 0.5.6 backtrace dumps + 0.5.7 allocator guardsalmonik2026-08-021-1/+12
|
* v0.5.5: visible boot progress + panic-on-screen for real hardwaresalmonik2026-08-021-2/+9
| | | | | | | | | | | | | | | | | | | | Real hardware has no serial console: a pre-shell panic was a silent blank screen (the panic handler only wrote to serial, then cli;hlt). v0.5.4's shadow change made this window reachable — if the fb-aware page allocation or the heap fallback failed on hardware, the kernel halted before the shell banner with zero screen output. - gop::boot_marker(): every boot stage now draws straight to the framebuffer (row 0, white-on-black). The last marker visible before a hang identifies where the kernel died. - Panic handler: pre-shell panics now draw a white-on-red '*** PANIC *** <msg> at file:line' band via gop::dump_lines. - init_shadow(): heap fallback is panic-proof (try_reserve_exact + resize instead of vec![0; words] which aborts on OOM); page-alloc result defensively re-checked against the fb region; any failure degrades to no-shadow mode with a visible warning band. - Verified: full chain (rsboot -> kernel) boots with markers, shell banner renders, all 5 test suites pass.
* v0.5.4: shadow backbuffer can no longer alias the framebuffersalmonik2026-08-021-9/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Real-hardware scroll freeze (no exception, QEMU-clean) — the per-word push (0.5.3) did not fix it, so the wedge is upstream of the push. A QEMU slow-display simulation (new DISPLAY_STALL knob + shell 'stall' command busy-waits per display store, mimicking an uncached real-GPU framebuffer) proved the per-word push and shadow memmove are slow but finite — the shell keeps ticking, scrolls eventually complete. The freeze mechanism QEMU cannot exhibit is the shadow *landing on the framebuffer*: the heap free list spans the fb hole, so the 1.9 MB heap shadow can alias the display on machines where firmware reports the fb as ConventionalMemory — every scroll then becomes an MMIO->MMIO memcpy on an uncached framebuffer, which wedges real hardware (a stall, no fault, hence no dump). Fix: - gop::init_shadow(): allocate the shadow from the fb-aware page allocator (init_page_allocator marks fb pages used per-page), so it can never overlap the display; heap allocation kept only as a fallback with an explicit overlap rejection. Boot log now prints 'gop: shadow @ <addr> ... origin=page-alloc|heap|none'. - Scroll shadow memmove converted to per-word stores (belt and suspenders — immune to any future fb-aliased shadow). - Verified on QEMU: shadow @ 0x100000 vs fb 0x80000000..0x801d5000, overlap=false; all 5 test suites pass; scroll completes even under the stalled-display simulation.
* rsnix v0.5.3: fix real-hardware scroll wedge — per-word display pushsalmonik2026-08-011-5/+14
| | | | | | | | | | | | | | | | | | | | The real-hardware crash (2 lines of white + freeze, no CPU exception even with the 0.5.2 fault dumps) pointed away from a fault and at a stall: the scroll's full-frame push used one 1.92 MB rep-movsb to the framebuffer. On QEMU the framebuffer is RAM, so it flies; on a real GPU the framebuffer is uncached MMIO and the CPU's fast-string burst path can stall forever — the shell wedges mid-instruction, the cursor task's own writes wedge too, no exception fires (MMIO writes don't fault), and the screen shows the torn partial push (the white bands). The boot-time clear() always worked on the same hardware and uses per-word volatile stores, so the scroll push now uses the identical pattern: shadow reads (cached RAM, cheap) + individually-posted display stores. Interruptible between stores, never a bulk burst, and functionally identical on QEMU (all 5 suites re-pass). Also converts the no-shadow fallback shift to the same per-word pattern. CONTEXT.md updated (scroll-cost note + versioning).
* rsnix v0.5.2: fault diagnostics + real-hardware scroll-crash hardeningsalmonik2026-08-011-4/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The real-hardware scroll crash (white bands + instant freeze, QEMU-clean) was invisible because the only trace was a single serial line on machines with no serial console. This makes every crash self-identifying and hardens the real-hardware failure surfaces: - Every CPU exception vector 0-31 now has an IDT entry (macro-generated stubs; 8/14 keep their IST stacks). A fault in the shell prints a white-on-red band to the framebuffer via gop::dump_lines (raw fb writes bypassing the vt, fully clamped) plus a parseable serial line: '!!! <kind> vec=N err=… rip=… cr2=… rsp=… rflags=… task=N "name"', then halts — instead of converging to a cryptic double fault. Background-task faults abort the task as before. - Boot log now reports the authoritative post-SetMode geometry: 'gop: fb base=… size=… pitch=… WxH bpp=… bgr=…', so the next real machine's report identifies whether pitch*height exceeds the mapping. - Framebuffer writes (clear, push_rect, shift_up_n bulk push, cursor overlay) are clamped to the firmware's framebuffer_size: a pitch- padded mode degrades to a truncated view instead of faulting past the mapping. - The GOP framebuffer region is excluded from the page allocator (and subtracted from the heap's conventional-region pick) even when the firmware lists it as ConventionalMemory — kernel allocations can never overwrite the display again. The GOP protocol is located and peeked before the memory map is captured so the exclusion is known at heap-init time. - Shell gains a hidden 'fault' command (deliberate unmapped write) and 'make test-fault' verifies the dump: vec=14, cr2=0x400000000000, task=0, halt — no triple fault. All other suites re-pass. - CONTEXT.md: fault-dump format documented for real-hardware reports.
* rsnix v0.5.1: force the GUI canvas to 800x600 via GOP SetModesalmonik2026-08-011-4/+12
| | | | | | | | | | | | | | | | | | | The kernel used to inherit whatever GOP mode the firmware picked (QEMU/OVMF gave 1280x800). Now every surface derives from a fixed 800x600 canvas: - uefi: typed EfiGopQueryMode/SetMode/GetMode fn pointers in GraphicsOutputProtocol (were raw *mut c_void, never called). - gop::select_gop_mode: scan the mode list for an exact 800x600 (32-bit BGR/RGB only, the driver assumes 4 Bpp), SetMode it; fall back to the smallest mode that fits the canvas, then to the firmware's choice. SetMode may move both the mode info pointer and the framebuffer base, so both are re-read after the switch. Boot log: 'gop: mode 3 selected — 800x600 (was 1280x800)'. - tests: relative assertions are resolution-agnostic; test-gfx and test-mouse had a boot-log race (shell line prints before the cursor task line) — now wait for the cursor line instead of grepping once. All four suites pass at 800x600. 0 build warnings.
* rsnix v0.5.0: graphics layer + cursor compositorsalmonik2026-08-011-14/+60
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The first visible GUI surface: real rect primitives, a single shadow→display push path, and an on-screen mouse cursor that can never race the text surface. gop: - fill_rect + push_rect(x,y,w,h): every raster op rasterises into the RAM shadow, then push_rect copies the rect to the display (write-only, still never read) and composites the cursor on top. blit_glyph and scroll shifts now route through it. - cursor overlay: 12x16 pointer (const-fn built from column lists) drawn white with a black offset outline; position in one AtomicU64 (x:high 32, y:low 32) — unpack masks the low word (a bare 'as usize' cast is a no-op on 64-bit). The cursor never enters the shadow, so erasing is just a shadow push of the old rect. - cursor_redraw after scroll shifts and once at spawn (the vt diff never re-blits idle cells). cursor task (task 2, spawned at boot when a mouse is present): - owns the PS/2 ring; polls every 10 ms, moves the cursor (clamped), tracks buttons, and forwards every event to a task's queue when 'mouse <id>' armed it (the window-manager input path). - /dev/mouse is now a position device (x/y/buttons snapshot); 'mouse' watches the cursor live (prints on change); 'cursor' prints one-shot state; 'gfx' draws a status-bar demo; 'gfx check' is an in-kernel pixel self-test (shadow readback, display readback, cursor overlay purity) — PASS/FAIL per stage. Tests (headless QEMU + monitor injection): - make test-gfx (new): all four compositor checks PASS. - make test-mouse (rewritten): cursor tracks mouse_move deltas, buttons ride along, /dev/mouse snapshot, live watch, real-event queue routing. - make test-msg: task numbering shifted (cursor is task 2; msgrecv is task 3) — updated, still PASS. - make test-disk regression re-passes. 0 build warnings.
* rsnix v0.4.0: GUI input foundation — PS/2 mouse + scheduler message queuessalmonik2026-08-011-1/+72
| | | | | | | | | | | | | | 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 <id>` routes real IRQ12 events into a task's queue, jobs shows q=. `make test-msg` + `make test-disk` regression pass.
* rsnix: preemptive kernel tasks (ADR 0003) — sched, IST fault stacks, ↵salmonik2026-08-011-0/+45
| | | | | | | | | | | | | | | | | | 176-byte frames - sched: 16-slot static table, shell=task 0, idle=task 1, spawn with guard page + 8 KiB stack, RR on the 100 Hz tick, int 0x60 yield, sleep_ms, lazy reap, jobs/bg/sleep/kill shell commands - gdt: own GDT mirroring UEFI selectors + TSS with IST1/IST2 (guard-page overflows die gracefully instead of triple-faulting) - interrupts: isr_dispatch returns next frame in rax; IntFrame grows rsp/ss fields — QEMU's 64-bit iretq always pops all five slots from a 176-byte frame, so synthetic task frames must carry rsp=top+ss (a 160-byte frame made the first iretq pop rsp/ss from the unmapped page beyond the frame) - panic handler: task panics abort the task, shell keeps running - main: sched::init moved after page allocator + adopted tables (the idle's stack+guard need both; it was silently not spawning)
* CONTEXT.md: versioning policy (a.b.c — overhaul/feature/fix)salmonik2026-08-011-0/+14
|
* docs: ADR 0003 (preemptive kernel tasks) + task glossary termssalmonik2026-08-011-1/+16
| | | | | | | | - ADR 0003: preemptive round-robin kernel tasks on the 100 Hz tick, shared address space, guard pages + page-fault handler, graceful task panics, safe-builtin spawn surface, only-shell-touches-I/O invariant - CONTEXT.md: new 'Task' glossary entry; 'Paging strategy' now says guard pages exist on task stacks
* CONTEXT.md: runtime device detection milestone + QEMU hotplug testability notessalmonik2026-08-011-0/+36
|
* klog: [ssss.mmm] millisecond timestamps from the PITsalmonik2026-08-011-1/+12
| | | | | | | | | | | | | | | | | | | | - interrupts::uptime_ms(): monotonic ms since boot — the 100 Hz PIT tick (10 ms) plus interpolation from the PIT's live 1.19 MHz down-counter (read twice around the tick load; a count jump means a tick fired between reads) for true sub-ms resolution. TICKS widened AtomicU16 -> AtomicU64 (u16 wrapped after ~11 min). - PIT_READY gates interpolation until interrupts::init configures the timer, so early-boot lines are deterministically [0000.000] instead of uninitialised-PIT noise; klog clamps timestamps monotonic. - The CMOS RTC cannot provide milliseconds (1 Hz BCD device, seconds only) — millis come from the PIT. - klog stores ms per line at append time; dump format is now '[0000.123] 000000 === rsnix boot ===' (user-specified format). Verified in QEMU: first line [0000.000], Phase-2 lines show real monotonic ms (fs: vfs ready at [0000.519], self-test [0000.524]), per-dump monotonicity, boot.log persists timestamps, test-disk round trip fsck-clean.
* klog: kernel log ring + /dev/klog + klog shell commandsalmonik2026-08-011-8/+28
| | | | | | | | | | | | | | | | | | | | | | | - rsnix/src/klog.rs: RAM ring of the last 128 serial log lines (128 chars each), fed by serial_println! so every boot/low-level message is captured for free. Sequence numbers per line, wrap/drop accounting; the ring never allocates (const-constructible static). - /dev/klog char device; shell 'klog' is a thin alias for cat /dev/klog with the same filters/redirection, so 'klog -t 5', 'klog -g fat' and 'klog WRITING /disk/.../boot.log' all work. klog rejects positional args (usage) and input keywords. - Shell user-facing output (banner, prompt, term_print/term_println, pipeline sink, halt/poweroff) now writes to serial directly instead of through serial_println!, keeping echo/cat output out of the boot log (a streaming cat /dev/mem would otherwise wrap the ring). - serial_println! macro hooks klog::append_fmt via format_args! (no alloc at call sites); klog::dump formats the log for the device. Verified in QEMU: 28 boot lines captured (seq 0..27), shell output absent from the ring, klog WRITING persists a boot log (mtype-checked), wrap verified with a temporary 140-line boot loop (128 kept / 40 dropped, seq 40..167, oldest-live correct; loop reverted); full test-disk round trip still fsck-clean.
* shell: cat <path> TIL <marker> sugar + precise ordering errorssalmonik2026-08-011-6/+35
| | | | | | | | | | | | | | | | | | - `cat/hexdump <path> TIL <marker>` is now sugar for `USE <path> TIL <marker>`: the paths are the input source, truncated at the first marker line across the combined stream. Path args + USE stays a syntax error (two input sources), now with a message that says so. - The parser's `trailing` flag conflated filters with the output keyword, so `cat f TO out TIL m` blamed the filters. USE/TIL now distinguish "before the filters" from "before the output keyword", and filters after the output keyword (`TO out -h 2`) are now rejected instead of silently accepted. - cat_file_until/hexdump_file_until return a tri-state (Done/Marker/ Aborted) so multi-path TIL truncation stops at the first marker. Verified in QEMU (10 checks): truncation, combined-stream marker, filters after the sugar, heredoc round trip, all four ordering-error messages, USE-with-paths ambiguity, fsck clean.
* shell: keyword redirection + post-filter flags (ADR 0002)salmonik2026-08-011-4/+204
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Implement the shell experience redesign: one canonical grammar for every command — 'cmd args [USE src] [TIL marker] [filters...] [output kw dst]'. - Keyword redirection (uppercase-only, aliases valid, fully reserved): WRITING/WRITE overwrite, TO append, USE/USING input source, TIL/UNTIL heredoc/terminator (exact full-line marker). > >> < << are removed; '>' is plain text. - Post-filter stages applied left to right over a line stream, each repeatable: -h N (head kills the upstream), -t N (tail holds a rolling window, flushes at EOF/^C), -g PAT (smart-case literal substring), -p (screenful pager, terminal only). A file sink replaces the screen; -p is a no-op with one. - C-style quoting: "..." groups and literalizes, \x escapes one char; quoted/escaped text is never an operator, never split. - Input consumers: cat/hexdump, path-less only (stdin until ^D, USE f, TIL m heredoc, USE f TIL m truncation). Other commands reject input keywords; paths + input keyword is a syntax error. - ^D is EOF everywhere and never powers off; poweroff/exit are the only shutdown verbs. - help rewritten; test-disk.sh and sendkeys.py use the keyword syntax. Verified in QEMU: 26 grammar checks on fresh and reused disks, disk round trip, pager pacing, -h stopping /dev/mem at N lines, ^C flushing a -t window. Two bugs found during verification and fixed: 1. WRITING over an existing file wrote after stale NUL padding — fs::size() is stale after set_len(0); the sink writes at offset 0 after truncation. 2. USE f TIL m leaked the post-marker remainder — the final partial-line emit ran after the marker break; guarded with a stopped flag.
* Clean up warnings, fix FAT32 multi-cluster dirs, prep for edition 2024salmonik2026-08-011-12/+27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Warning cleanup (cargo check + clippy now 0 across the workspace): - Migrate all 21 static_mut_refs sites to &raw mut accessors (fat, gop, ps2, vt, ahci, interrupts, memory) so edition 2024 won't deny them - panic = "abort" profiles: bare cargo check/build now works without nightly/-Zbuild-std - Wire TICKS in the timer ISR (it was never incremented, so the vt scroll batching trigger was dead code) - Clippy: efi_main becomes unsafe extern "efiapi" with a # Safety doc, KeyBuf::new uses inline-const array repeat (no interior-mutable const), editor main loop is a while-let, PIT control byte regrouped - [workspace.lints.clippy] allows result_unit_err + needless_range_loop (deliberate kernel style); large_enum_variant allowed on LineInput - Drop now-stale static_mut_refs allow from the rsdos bin FAT32 correctness fixes (both pre-existing, exposed by the SFN fix): - Unique 8.3 short names: to_8_3() never disambiguated collisions, so files sharing a long-name prefix got identical SFNs and fsck reported duplicate directory entries. Add dir_short_names() + unique_short_name() (~N tails, Windows-style) and force LFN when the SFN changes. - Multi-cluster directories: scan_dir/dir_short_names stopped at the first 0x00 slot, hiding every entry written into a chained cluster (writes failed with 'cannot write', duplicate SFNs accumulated); add_dir_entry now packs the cluster (0xE5 deleted-markers) before extending so other FAT readers (mtools, Windows) see the continuation too. Other: delete dead fields (Disk.fis, Volume.fat_count), drop timer_irq/ keyboard_irq/rendered, refresh_and_exit is a documented unsafe fn, CONTEXT .md corrected (stable toolchain, IRQ input, 4-crate layout), .gitignore excludes .pi-subagents artifacts. Validated: cargo check/clippy/fmt clean, make test-disk PASS on fresh and reused images (incl. two directory-chain extensions and ~10 SFN tails), editor round-trip smoke test PASS.
* CONTEXT.md: record pending decisions (klog ring, disk-recognition scope)salmonik2026-08-011-0/+16
|
* fat: mount every FAT32 volume under /disk/<UID>/, fix multi-entry LFNsalmonik2026-08-011-13/+21
| | | | | | | | | | | | | | | | | | | | | | | | | - fat.rs: VOL: Option<Volume> → VOLS: Vec<Volume>; try_mount() returns a Volume per disk and init() mounts every valid FAT32 volume found. Volume UID = sanitized uppercase label + 8-hex volume serial (e.g. RSDOS-5BD1E55F): unique per format, stable across reboots, human-recognizable, machine-parseable (^[A-Z0-9_]+-[0-9A-F]{8}$); cloned volumes get a -N suffix. Public ops take a vol index and select it (select_vol also picks the backing AHCI disk), matching the ahci::select pattern - fs.rs: /disk is now a plain directory whose children are one Disk node per mounted volume, named by UID; DiskInfo carries vol - LFN fix: entries are stored last-first on disk — both the writer (head-entry first) and reader (append in disk order) were reversed and cancelled out for ≤13-char names; multi-entry names (>13 chars) read back mangled (e.g. 'from-kernel.txt' as 'xt'). Writer now places seq=1 closest to the SFN and seq=N|0x40 first; reader places chunks by sequence number and trims at the first NUL. Verified with a 25-char filename round trip: kernel ls/cat correct, mtools shows the full LFN, fsck clean on both volumes - test-disk.sh: test file renamed to disk-test-.txt (>13 chars, exercises multi-entry LFN); UID discovered from the boot log; QEMU stdio redirected to a log file + EXIT trap so an orphaned QEMU can never hang a piped caller (it previously did, 400s)
* scripts: automate the data-disk workflow (mkdisk / sendkeys / test-disk)salmonik2026-08-011-2/+19
| | | | | | | | | | | | | | | | | | | | | - scripts/mkdisk.sh: create the FAT32 disk with mkfs.fat -C (the flag that actually creates the file — plain mkfs.fat fails on a missing path), accept M/G/K sizes, seed seed/ files via mtools; --fresh re-formats, --no-seed skips seeding - scripts/sendkeys.py: type lines into the guest via the QEMU monitor (US layout). Punctuation must use QEMU's named keys (minus, slash, dot, ...) — bare '-', '.', '/' are not valid sendkey names, and '-' is the modifier separator, so they were silently dropped before - scripts/test-disk.sh: full automated round trip — build, deploy, ensure image, boot headless QEMU, drive the shell (ls /disk, mkdir, echo >, cat, poweroff), then verify with fsck.fat (must be clean) and mtype (file content must have survived poweroff) - Makefile: make disk / disk-fresh / inspect / test-disk; run, run-gui and debug now auto-create a missing DISK_IMG; fix the stale comment (mkfs.fat without -C) - scripts/boot.sh: auto-create a missing DISK_IMG via mkdisk.sh - seed/: motd.txt + lines.txt seeded onto fresh images - Verified end to end: ./scripts/test-disk.sh --fresh passes
* ahci: scan all ports; fat: mount first valid FAT32 disksalmonik2026-07-311-1/+5
| | | | | | | | | | | | | | | | | The kernel previously started only AHCI port 0, so any launch where the firmware/QEMU put something else on port 0 (e.g. the ESP from an implicit -drive file=fat:rw:esp) left the real disk unnoticed: 'unsupported sector size 0' and no mount. - ahci.rs: enumerate CAP.NP/PI ports, start every port that links up (empty ports settle at DET=0 and are skipped quickly), keep up to 8 disks, and expose disk_count()/select() for the filesystem - fat.rs: try each disk in port order and mount the first valid FAT32 volume; non-FAT disks are logged and skipped - scripts/boot.sh: attach the data disk on ide.0 and the ESP on ide.1 (DISK_IMG env var, default /tmp/disk.img), matching the Makefile - Verified with the disk on port 0 (Makefile style), port 5 (old-style command line), and with the ESP on port 0; fsck.fat stays clean
* ahci: SATA driver + FAT32 persistent disk mounted at /disksalmonik2026-07-311-4/+37
| | | | | | | | | | | | | | | | | | - ahci.rs: polling AHCI on PCI class 1/6/1, bus mastering + ABAR map, port 0 up, IDENTIFY + READ/WRITE DMA EXT through one 4KiB DMA buffer - fat.rs: BPB parse, whole-FAT RAM cache with write-back to both copies, LFN read/write, dirs, multi-cluster files, FSInfo free-count sync, space-padded dot entries ('..' = cluster 0 under root), fsck-clean - fs.rs: /disk mount node + 24-slot ephemeral node pool; ls/cat/hexdump/ echo/mkdir/touch/rm/edit all work on disk paths unchanged - QEMU: explicit bus assignment (disk=ide.0, ESP=ide.1); the implicit fat:rw:esp drive was stealing AHCI port 0 - Debugged against QEMU source: header DW0 is CFL in bits 4:0 / PRDTL in bits 31:16 (Linux libahci layout), FIS count at bytes 12-13, device at byte 7; QEMU rejects H2D FIS flags bits 6:4, so direction is the header W bit only - Verified: full shell round-trip on /disk, reboot persistence (poweroff then mdir/mtype and a fresh boot), fsck.fat clean
* vt: defer scrolls and batch framebuffer pushessalmonik2026-07-311-8/+16
| | | | | | | | | | | | | | | | | | | | | | | | Streaming output scrolled one framebuffer push per line (each a ~3-8 MB write-only copy). The vt now scrolls the logical grid instantly in RAM and defers the display shift: N pending scrolls are pushed together as one shift_up_n — one push regardless of batch size. - vt: PENDING_SCROLLS counter; scroll_up shifts CELLS only; flush renders nothing while pending (the diff would otherwise re-rasterise the whole screen per line); sync_scroll() does one gop::shift_up_n + RENDERED mirror + normal diff flush (which re-blits just the newly exposed rows and the cursor). - Sync triggers: batch of 16 rows, ~40 ms of stream pause (100 Hz TICKS), any CSI sequence (full-screen apps like the editor render immediately), clear_all/set_cursor_visible, interactive input (tty read_line/read_byte), and the shell before each prompt. - gop: shift_up → shift_up_n(n) (one shadow memcpy + one push). Verified in QEMU: mmap/hexdump streaming renders in coherent batches with the prompt syncing at the end; clear wipes clean; the editor scrolls and redraws immediately (45-line file, gutter + status bar intact, cursor correct); save/exit/cat round-trip unchanged. Release and dev builds pass.
* gop: RAM backbuffer — scrolling never reads the framebuffersalmonik2026-07-311-5/+9
| | | | | | | | | | | | | | | | | | | | | | Real-hardware GOP framebuffers are typically uncacheable or write-combining (firmware MTRR/PAT), so the scroll shift's full-screen memcpy *read* ~4-8 MB through uncached memory — a bus round-trip per cache line. That made scroll printing crawl on real hardware while plain printing (a few glyph writes) stayed instant. - gop keeps a RAM shadow copy of the whole framebuffer (same pitch layout), allocated at init. - Every raster write (glyph blits, clear) goes to both the display and the shadow. - shift_up becomes: cached shadow memcpy up one row + clear exposed bottom row in the shadow + one write-only push shadow→display via copy_nonoverlapping (64-byte bursts that coalesce on WC memory) — the display is never read. - Fallback to the old direct shift if the shadow allocation is null. Verified in QEMU: mmap output scrolls ~100 lines with coherent rows and a clean bottom row, clear wipes the screen, cursor tracks the prompt, editor paths untouched. Release + dev builds pass.
* vt: don't strand stale inverse cursor cells on scroll/clearsalmonik2026-07-311-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | The cursor was blitted as an inverse-video cell directly onto the framebuffer, but that inversion was never recorded. RENDERED (the diff grid) only stored the logical cell, so when scrolling shifted the raw pixels up (gop::shift_up), the stale inverse block rode along while the grids said 'blank' — and blank-vs-blank never re-blits. Result: a cursor-shaped block at the end of every scrolled line, surviving even 'clear'. - flush() now mirrors the inverse colours into RENDERED when drawing the cursor (and restores RENDERED when erasing it), and the diff loop skips the visible cursor cell (owned by the cursor pass). Any scroll/clear then sees CELLS != RENDERED at a stale-inverse position and repaints it. - memory.rs heap self-test: snapshot heap state before its own allocations and assert the heap returns to that state, instead of asserting it coalesces to a single empty block. The vt cell grids (allocated earlier in boot) made the old 'free_blocks == 1' check fail; the new check is correct regardless of prior live allocations. Verified in QEMU: hexdump /dev/mem streams hundreds of lines, ^C, screendump shows exactly one inverse cell (the live cursor); 'clear' leaves exactly one (the fresh prompt cursor). heap self-test OK again.
* vt: decode UTF-8, render box-drawing/arrow glyphs procedurallysalmonik2026-07-311-1/+3
| | | | | | | | | | | | | | | | | The editor's gutter '│' (U+2502) appeared as '???' — write_bytes fed each UTF-8 byte to the state machine, which mapped every byte >= 0x80 to '?', and the Latin-1 font has no box-drawing glyphs anyway. - vt.write_bytes now decodes UTF-8 sequences; printable non-ASCII dispatches to the glyph path instead of the byte parser. - gop: unicode_glyph_bits() procedurally rasterises box-drawing (U+2500-257F light/heavy/double), arrows (U+2190-2193) and the em dash (U+2014) — pure geometry, no font data needed; blit_glyph falls back to it for ch >= 256. Verified via framebuffer dumps: editor gutter │ renders as a vertical line, help screen ═ separators and ←→↑↓ all render as lines (no '?'). Shell banner em dash renders too.
* tty + vt terminal split, rsdosedit editor (1:1 UNIX console)salmonik2026-07-311-2/+36
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Kernel now has the classic UNIX console split, so full-screen ANSI apps can run in ring 0: - vt.rs: terminal emulator owning the text screen — cell grid (char + fg/bg), logical cursor (inverse-video), scrolling, and a small ANSI CSI parser (cursor position H/f, erase J/K, moves A-D, SGR 16-colour with correct ANSI→VGA mapping, cursor show/hide ?25). Blits only changed cells; scroll shifts cell grids + pixels and re-rasterises only the exposed bottom row. gop_println!/clear_screen now render through the vt; gop.rs is the raw rasteriser (colored glyph blits, pixel shift). - tty.rs: line discipline — canonical read_line (echo, line buffer, ^C cancel, ^D EOF) moved out of the shell, and raw read_byte that translates KeyEvents to the terminal byte protocol (arrows → ESC[A-D, Backspace → 0x7f, ^X → 0x18, Ctrl+arrows → ESC[1;5A-D, Home/End/PgUp/ PgDn/Delete). interrupt_pressed() stays for streaming commands. - ps2: generic Ctrl(char) + CtrlArrow events (was: only CtrlC/CtrlD). - rsdosedit: no_std port of the RNG rsedit editor as the first real app — undo, syntax highlighting (verified green/gray/yellow on the framebuffer), search, word nav, smart indent, ^S save / ^X exit / ^X again to discard. termios → tty raw, stdout → vt, std::fs → VFS (ramfs), SIGWINCH → fixed geometry, force-exit window → key counter. - shell: 'edit <path>' command; read_line/strbuf moved to rsnix. - CONTEXT.md: layout + milestones + known-issue perf notes. Verified in QEMU: full edit → type → arrow-move → insert → save → exit round trip with byte-exact file content; ANSI colors via screendump.
* shell: ^C cancels the line / aborts streams, ^D = EOF → poweroffsalmonik2026-07-311-0/+3
| | | | | | | | | | | | - ps2: Ctrl+C and Ctrl+D are now KeyEvents (ctrl modifier + c/d map); other Ctrl+key combos are swallowed - shell read_line: ^C clears the line and echoes '^C' (bash-style), ^D on an empty line echoes '^D' and shuts down (EOF), ^D with text on the line is ignored - cat/hexdump stream incrementally (was: build whole string then print) and check for ^C between chunks, so a running dump can be aborted - verified in QEMU: line cancel, standalone interrupt, ^C aborts an infinite 'cat /dev/zero' stream, ^D powers off
* vfs: everything is a file — dirs, ramfs, character devicessalmonik2026-07-311-0/+6
| | | | | | | | | | | | | | | | - fs.rs: node-table VFS (root /dev /tmp /etc). Regular files are in-memory ramfs; char devices regenerate content on every read so 'cat /dev/rtc' shows the live time. Nodes are stable handles with tombstone removal; . and .. path resolution. - /dev devices: mem (raw physical RAM, offset = address), rtc, pci, version, meminfo, null, zero, console (write prints to screen+serial), serial. /etc/motd static file. - shell: ls, cat, hexdump (hexdump -C style), mkdir, touch, rm; echo gains '>' overwrite and '>>' append redirection (append bug fixed: first '>' in '>>' was parsed as overwrite) - boot: fs init + self-test (create/read/write/remove) before the shell - QEMU verified: file lifecycle, redirection, console/null writes, mkdir/touch/rm, hexdump /dev/mem and /tmp/x byte-exact
* rtc + pci: CMOS clock with date command, PCI bus enumerationsalmonik2026-07-311-0/+4
| | | | | | | | | | - rtc.rs: read the PC RTC via CMOS ports 0x70/0x71 (UIP wait, BCD/12h normalization, century sanity-check with 2000+ fallback); boot prints the wall clock, shell gains 'date' - pci.rs: legacy config-space access (0xCF8/0xCFC) with full enumeration of buses 0-255; boot reports device count, shell gains 'pci' (lspci style listing with class names) - QEMU q35 verified: Q35 host bridge, stdvga, e1000, ICH9 LPC
* docs: CONTEXT.md — poweroff milestone, power.rs layout entrysalmonik2026-07-311-1/+4
|
* docs: CONTEXT.md — paging adoption, heap growth, shell additionssalmonik2026-07-311-7/+30
| | | | | | | | - paging strategy: adopt_tables() rebuilds the firmware map into the kernel's own tables (UEFI maps its tables read-only) and switches CR3 - physical memory: heap grows into the page allocator on demand - milestones: paging helpers, heap growth, mmap/stress commands - project layout: paging.rs entry
* fix(rsdos): organizational changessalmonik2026-07-311-1/+1
|
* Initial commit: raisernics toy kernelsalmonik2026-07-311-0/+100
- Bare-metal x86_64 UEFI kernel (PE32+, no libc) - GOP framebuffer + 8x16 bitmap font - PS/2 keyboard (polling, scancode set 1) - UART 16550 serial driver (COM1, 115200 8N1) - Bump allocator as #[global_allocator] (alloc::String, Vec, format!) - UEFI memory map capture (static buffer, ADR 0001) - Shell with 7 commands (help, echo, clear, hello, info, mem, halt) - Dual output: GOP framebuffer + serial console - Makefile: run, run-gui, debug, release, image targets - tools/: qemu.sh, boot-image.sh, debug-kernel.py