summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
* exec: PE32+ loader, versioned ABI, first external binaries (v0.6.0)salmonik2026-08-2115-6/+786
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | rsapi: the kernel<->binary ABI crate (no_std, no deps). Versioned Exports table (magic + version header), EntryPoint = extern "C" on x86_64-unknown-uefi (Win64: RCX/RDX/R8), Line/Arg/StreamResult types. Binaries link only this crate. rsnix::load: PE32+ parser — DOS/COFF/optional headers, section copy, BSS zero-fill, .reloc base relocations (DIR64) via rva_to_file mapping (the reloc directory is an RVA, not a file offset). Images are allocated at LOAD_BASE=192MiB inside the page allocator's conventional span and identity-mapped user+writable+nx. rsnix::exec: resolution name -> /disk/<UID>/bin/<kind>/<name>.efi per mounted volume; spawn reserves a sched slot, stores a per-task ExecCtx (exports + argv block + image) before launch_at installs the frame — no adopt race. Trampoline calls entry(&Exports, argc, argv), posts TaskMsg::User(exit_code) to the shell. abort_current notifies the shell with u64::MAX when an exec'd binary dies, so a faulting command cannot leave the shell blocked forever. sched: reserve_slot/launch_at split out of spawn; task_exit made pub. shell: exec_external runs before non-frozen built-ins (ADR 0006 resolution rule); frozen core (help/clear/echo/halt/poweroff/exit/ rescan) is exempt. Exports v1 wires put_line to the terminal and get_line to EOF; stream injection lands in Phase 3. ^C while waiting kills the command task. bins/{hello,boom}: gate binaries. hello prints through the exports table; boom faults on 0x400000000000 to prove containment. The image entry point IS the ABI entry (efi_main carries the Exports signature). Version 0.6.0: exec exists end-to-end. Gates verified in QEMU: 'hello' loads from \\bin\\cli\\hello.efi, calls put_line across the ABI, exits 0, shell unblocks; 'boom' faults, task dies gracefully with full report, shell survives, jobs shows the corpse; built-in fallback works when the file is absent; test-disk PASS.
* input: total keyboard routing + per-terminal discipline (ADR 0006 ph1)salmonik2026-08-215-212/+208
| | | | | | | | | | | | | | | | | | | | | | | | wm: FOCUSED is now a plain window id — window 0 (home terminal) is an ordinary focusable window in the z-order. The CONSOLE sentinel (usize::MAX) and the focused()==0 special cases are gone; focus_console() is an alias for focus(0). Desktop clicks focus window 0. The WM input pump routes every key unconditionally: IRQ ring -> pump -> focused window's owner; nothing polls the scancode rings directly any more. tty: read_line() reads from the calling task's message queue (the old global-ring read_line and the duplicate read_line_from_queue are merged); raw mode (read_byte/try_read_byte) consumes the same queue; interrupt_pressed drains the queue instead of the ring. shell: task 0 owns home terminal window 0 and blocks on its queue like a windowed shell; cat/hexdump stdin paths pass the home terminal handle. sched: watchdog comments updated (shell parks on recv_blocking). Verified in QEMU: F1 spawns terminals, F2 cycles focus home->term1-> term2, keystrokes land only in the focused window, ^C cancels a line, edit runs raw over the queue and exits to a working prompt; test-disk regression PASS.
* image: single dd-able system.img replaces vvfat+data-disk pairsalmonik2026-08-216-238/+226
| | | | | | | | | | | | | | | | | | | | mksystem.sh stages one FAT32 image: \bzImage + \initramfs.cpio.gz (rsbl paths), \EFI\BOOT\BOOTX64.EFI (kernel direct by default, --chain for rsboot), \etc\motd.txt, empty \bin\cli + \bin\gui, seed files at the root. --gpt wraps it in a partition table for real USB dd targets. Makefile: run/run-gui/debug attach only system.img on ide.0 (vvfat lines deleted); stamp-based 'system' target rebuilds only when the kernel is newer, so runtime writes survive reboots; system-fresh wipes; inspect lists via mtools. build-image.sh/mkdisk.sh removed. test-disk.sh boots system.img with a throwaway OVMF varstore — a stale NvVars makes the firmware skip the \EFI\BOOT fallback. sendkeys.py pacing 50ms->250ms/1.5s: keystroke loss under host load corrupted typed lines (guest-side PS/2 ring overflow). Gate: test-disk PASS (fsck clean, file survives poweroff).
* docs: ADR 0006 (executable binaries) + implementation plan + glossary termssalmonik2026-08-213-0/+290
| | | | | | | | | | | | | | 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.
* wm: fix usize underflow in move_window at screen edgessalmonik2026-08-211-3/+4
| | | | | | | | ox.saturating_sub(pad) / oy.saturating_sub(pad) — plain subtraction on usize wraps to usize::MAX when the window sits at x=0 or y=0, causing composite_rect to draw at the far end of the framebuffer instead of near the window. Also broke drag-to-move when stuck against the top or left edge.
* wm: 1px focus-colored border + flush full window on focus changesalmonik2026-08-212-11/+57
| | | | | | | | | | - draw_window_border(): 1px border around every window except the root. Blue (TITLE_BG_FOCUS) when focused, grey (TITLE_BG) when not. - focus() / focus_console(): composite the full window area + border pad on both the old and new focused windows (was title-bar-only before). - flush(): include border pad in the damage rectangle. - move_window(): redraw border area at old and new positions. - Remove redundant term.flush() from tty Focus handler (focus() covers it).
* wm: flush terminal window content on gaining focussalmonik2026-08-212-1/+4
| | | | | | focus() only composites the title bar — the window content stays stale until the next write. Call term.flush() on Focus(true) so the full window is re-composited immediately when switching to it.
* v0.5.11: fix terminal focus — toggle ACTIVE on Focus messagessalmonik2026-08-216-13/+25
| | | | | | | | | | - tty: read_line_from_queue() now takes &mut Terminal and handles TaskMsg::Focus: Focus(true) sets ACTIVE to the terminal, Focus(false) clears it. This fixes the bug where the console shell's gop_print! output was redirected to the soft terminal even after focus switched away from it. - shell: run_windowed() passes the terminal through to read_line_from_queue. - wm: remove noisy per-key debug logging from pump_main.
* wm: F1 spawns a windowed shell — real shell, not a duplicatesalmonik2026-08-205-16/+273
| | | | | | | | | | | | | | | | | Architecture: - vt: ACTIVE terminal redirect — when set, all gop_print!/put_char/write_str go there instead of HOME. Terminal::from_buffer() renders into a WM-owned pixel buffer. - tty: read_line_from_queue() — canonical-mode line input from the task's own message queue (TaskMsg::Key). Returns None on Close. - shell: run_windowed() — same shell as the console but reads from the message queue. Returns on ^D or window close. - wm: F1 calls SPAWN_TERMINAL_CB (set by rsdos). No shell logic in the WM. - rsdos: terminal_task callback + terminal_entry task — creates a 640x400 chrome window, wires up Terminal::from_buffer, sets ACTIVE, runs shell::run_windowed(), cleans up on exit. - shell: 'term' debug command that invokes the callback directly and logs each step to serial.
* wm: integrate home terminal as window 0 + fix console focus after closesalmonik2026-08-193-202/+261
| | | | | | | | | | | | | | | | | | - wm rewrite: chrome flag per window, create_home_window for the console (window 0, chrome-less, bottom-pinned, never closed), composite_rect fills desktop background then blits windows bottom-to-top, draw_window_intersect handles chrome-less windows, hit_test returns Content for chrome-less, destroy/move_window no-op for id 0. - vt: add window_params() so main.rs can wire the Terminal to wm window 0. - main.rs: create home terminal window 0 and attach Terminal after wm::init(). - Focus fix: focus(0) now stores CONSOLE sentinel (not raw 0) so focused() returns None when the home terminal has focus. Without this, closing a GUI window left FOCUSED=0, which tty::poll_key() interpreted as 'a GUI app has focus', spinning forever and swallowing all keyboard input.
* vt → per-instance Terminal rendering into a pixel buffersalmonik2026-08-174-726/+591
| | | | | | | | | | | - Refactor vt.rs into a per-instance Terminal struct (owned cell/rendered grids, cursor, ANSI parser, scroll state), rendering glyphs into a caller-owned pixel buffer with dirty-region blitting - Add gop buffer primitives (buffer_glyph_px, buffer_shift_up) and keep the legacy vt:: API as thin wrappers around the home terminal - Remove the now-obsolete scroll hook and shadow scroll path - Home terminal renders into its own buffer; window_id stays None until the WM integration lands
* Terminal-app design (ADR 0005) + disk-write controllersalmonik2026-08-175-15/+105
| | | | | | | | | - 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
* wm: keep windows in place when the console scrolls beneath themsalmonik2026-08-173-7/+37
| | | | | | | The console's batched scroll (gop::shift_up_n) shifts the whole shared shadow, which dragged any composited window pixels up with it. Add a scroll hook so the window manager re-composites every visible window after a console scroll, restoring them at their fixed positions.
* wm: title-bar drag-to-move; stop delivering title-bar gestures to appssalmonik2026-08-172-22/+108
| | | | | | | | | - Track the active mouse gesture (none / window-move / app-stroke) so a press on the title bar becomes a move drag instead of leaking Move events into the app's content - Add move_window (clamped to the canvas, repaint old + new regions) - Always deliver MouseKind::Release so a stroke that ends outside the window still terminates
* Windowed GUI: wm module, input routing, and the paint appsalmonik2026-08-1717-45/+1152
| | | | | | | | | | | | | | - 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
* USB2/1.1 (EHCI/UHCI) drivers + real-hardware bring-up hardeningsalmonik2026-08-1718-43/+3295
| | | | | | | | | | | | | - Add polled EHCI (USB2) and UHCI (USB1.1) host-controller drivers with HID boot mouse support, wired into cursor polling and the 'usb' shell cmd - Add USB Legacy ownership handoff (claim_usb_legacy) plus config_write_byte - Harden boot: verify the PIT/timer ticks before shell entry, EOI stray interrupts in the LAPIC to stop interrupt storms, bound PS/2 controller waits, and INTx-disable AHCI (polled driver) - Add boot stage markers, klog screen echo, and QR lock; scheduler mark_shell_running; NO_USB stopgap to keep BIOS USB-Legacy input alive - alloc_pages_above for DMA buffers that must avoid low conventional memory - Expand DEBUG_NOTES with EHCI/QEMU bring-up findings
* v0.5.10: change em-dashes to dashessalmonik2026-08-111-84/+112
|
* v0.5.10: USB HID mouse via polled xHCI (rsnix/src/usb.rs)salmonik2026-08-048-7/+1061
| | | | | | | | | | | | | | | Polled xHCI driver (mouse-only): controller bring-up, port reset, enable-slot -> address-device -> config-descriptor walk -> HID boot mouse IN endpoint, one outstanding IN TRB drained on poll. Cursor task polls usb first, PS/2 second. New 'usb'/'usb rescan' shell cmds. Verified in QEMU (q35 + OVMF + qemu-xhci + usb-mouse): movement and all three buttons tracked exactly; heap stays clean. Fixes en route: MaxPorts=HCSPARAMS1[31:24]; operational regs CRCR=0x18 DCBAAP=0x30 CONFIG=0x38; pass input-context ptr in Address-Device; Input Control Context DW0=Drop DW1=Add; HID walker bInterfaceClass at +5; async discovery from cursor task.
* v0.5.9: fix OptiPlex heap crash — EBS retry must not rebuild the free listsalmonik2026-08-048-106/+453
| | | | | | | | | | | | | | | | | | | | | | | Root cause: on real hardware SetMode can invalidate the pre-captured ExitBootServices map key, so EBS fails and the retry refreshed the map via capture_memory_map -> init_heap, which REBUILT the free list from the raw map and wiped the allocation state of every pre-EBS live object (the display shadow and the vt grids). Their spans became free while still live, later allocations carved inside the shadow, and the display writes clobbered them — zeroed back-pointers (family A ptr=0x404443e0 block=0x0) and gray glyph pixels (family B 0xaaaaaa00aaaaaa = 0x00AAAAAA = PALETTE[7] fg-7 text colour, not a firmware scrub). Fix: refresh_and_exit now re-captures the map and returns a fresh EBS key without rebuilding the free list (refresh_map_key); the free list is the authoritative live-allocation state. Verified in QEMU under a forced EBS failure (SIMULATE_EBS_FAILURE test hook): verify ok, probe NOT free, flhead outside the shadow — identical to a clean boot, and the full shell sequence is crash-free. Also: removed the crash-family debug markers from the screen (boot-time heapdbg lines, vt verify marker, shadow marker) — the vt grid self-check stays serial-only. Version 0.5.8 -> 0.5.9.
* v0.5.8: heap-free QR encoder + crash-dump QR on framebuffersalmonik2026-08-0311-5/+1232
| | | | | | | | | | | | | | | | | | | | | | | Real hardware has no serial console, so a kernel crash only leaves a frozen screen. Every dump_lines() report now also renders the crash text as a scannable QR below the white-on-red band (photograph the screen instead of relaying text). - rsnix/src/qr.rs: from-scratch no_std/no_alloc byte-mode QR encoder (EC-L, v1..v40, .bss statics only — safe on the fault path): RS over GF(256), codeword interleave, zigzag placement, 8 masks with N1-N4 penalty auto-selection, format/version info. - gop.rs: dump_qr() joins dump lines into a static buffer, truncates with '...' at the v40-L capacity, encodes, and renders centered black-on-white with a 4-module quiet zone. - tools/qrcheck: host harness (embedds qr.rs) + qrcheck.py cross-check against segno's placement primitives. Verified bit-exact: 12 versions x 8 masks forced, plus auto-mask choice matches segno's penalty evaluation. Caught 3 encoder bugs (multi-block interleave offsets, transposed version info, mask eval ordering). - QEMU e2e: page-fault dump screendump decodes via zbarimg, content matches the serial log line-for-line. - test-msg.sh and test-fault.sh both PASS; debug+release 0 warnings.
* v0.5.7: fix vt verify content check — expect BLANK (0x70020), not zerosalmonik2026-08-033-36/+344
| | | | | | | | | | | | | | | | | | | | | | | The pre-verify 0x70020 'mystery' was a debug artifact, not corruption: BLANK = {ch:32, fg:7, bg:0} = raw 0x70020, and vec![BLANK; n] fills both grids with it at init. The old check compared cells against 0 and its probe loop break-ed on the first non-zero cell, so probes 1-3 stayed at their zero-initialized slots — c=[0x70020,0,0,0] was bogus on every healthy boot. A full-grid dump proves QEMU grids are 100% BLANK at shell entry (nz=3700 blank=3700). Fix: probes compare against blank_raw (0x70020), record all four values (no early break), probe both cells and rendered, and add a full-grid nz/blank summary line. The OptiPlex firmware 0x00AAAAAA scrub remains cleanly distinguishable (scrub != blank). Markers: the shell banner occupies grid rows 0-1 and the prompt row 2 (proven by screendump), and a stale crash.log replays at rows 2+, so the shadow and vt markers moved to the bottom of the screen via the new gop::text_rows()/bottom_row(off) helpers instead of rows 1-2. QEMU verified: verify: ok every boot; test-msg + test-fault PASS; debug and release builds 0 warnings.
* v0.5.7: guard report else-branch initializes all mem lines (fix broken build)salmonik2026-08-031-1/+4
|
* v0.5.7: fix unused-init warning in guard reportsalmonik2026-08-031-1/+1
|
* v0.5.7: guard dumps block-header math + 16-word window; vt content verify; ↵salmonik2026-08-033-43/+117
| | | | | | | | | | | | | | | | | | | shadow marker The klog -t 2 crash drops a 126-byte String (the vt verify klog line) whose data ptr 0x40444970 points into the first-heap-block region whose content is the firmware 0x00AAAAAA scrub — a stale pointer, not a real allocation (back-pointer slot never written). Upgrades so the next real-hardware crash shows the full picture: - guard: explicit candidate block bases (b=ptr-24 / b16=ptr-32) with their size/free fields, plus a 16-word window (mem..mem4) from ptr-0x30 instead of the old 8 words - vt::debug_verify: content probe of the cells grid (must be all-BLANK at shell entry) — catches a stale in-heap cells pointer that passes the range checks - gop: on-screen marker for shadow carved vs NO-SHADOW fallback (the scrub content at the crash ptr suggests the shadow was rejected and its block stayed free + firmware-scrubbed)
* v0.5.7: vt verify also as a boot marker (real hardware has no serial)salmonik2026-08-021-0/+12
|
* v0.5.7: drop test-poison hooks; vt heap-struct verify at shell entrysalmonik2026-08-022-33/+49
| | | | | | | | | | | The OptiPlex's first banner write #GPs when the vt cells VecData holds firmware 0xAA fill instead of a real buffer pointer. The poison/fill test hooks (stack + free-heap + free-page 0x00AAAAAA) were removed from the release image — they changed boot behavior and may walk a corrupt free list over live blocks. Added vt::debug_verify() (cells/rendered ptr/cap/len + in-heap check) at shell entry: the next real-hardware boot shows whether the corruption is present at shell entry or lands during the banner write.
* v0.5.7: guard reports the drop's size/align — identifies the clobbered structsalmonik2026-08-022-14/+102
| | | | | | | | The OptiPlex crashes free garbage (0xaaaaaa, 0xaaaaaa00aaaaaa) whose value is the firmware's 0x00AAAAAA scrub pattern left in stack/heap. The drop size/align (the dealloc layout) now prints on the band, so the next repro shows both the garbage ptr AND the size it was freed with — cap×elem_size pinpoints which struct's fields were clobbered.
* v0.5.7: guard report 4-words-per-line — 16 stack words survive band hand-copysalmonik2026-08-022-24/+89
| | | | | | | | The OptiPlex repro copies are truncated at the ~110-char band width, so the old single-line 'stk:' (12 words, >200 chars) lost the return chain after a few words. Split mem/stk dumps into 4-words-per-line blocks: mem+mem2 (8 words around the corruption) and stk..stk4 (16 words) — the drop caller chain now survives hand transcription.
* v0.5.7: heap range on the boot screen — real-hardware geometry without a crashsalmonik2026-08-021-0/+6
| | | | | | | The OptiPlex heap-corruption repro (guard report) came in hand-copied and garbled; the exact heap start/end was the missing datum. The heap self-test range was serial-only; now it is also a boot marker, so the next boot shows 'rsnix: heap 0x..-0x.. (N MiB) ok' on the framebuffer.
* docs: CONTEXT.md versioning — 0.5.6 backtrace dumps + 0.5.7 allocator guardsalmonik2026-08-021-1/+12
|
* v0.5.7: allocator corruption guard + full register dump for real-hardware reprosalmonik2026-08-025-5/+205
| | | | | | | | | | | | | | | | | | | | The OptiPlex #GP (vec=13 in __rust_dealloc) frees a garbage pointer: the back-pointer at [ptr-8] is clobbered by the time the shell drops its Parsed struct. A blind store to the bogus block header was an opaque #GP — now it is a readable report: - dealloc validates the back-pointer (in-heap block, sane size, in-use) before trusting it; on failure it prints ptr/block/heap range, the memory around the block header, and the live stack chain, writes the crash band + crash.log, and halts (memory.rs: heap_guard_report). - fault dumps now carry the full register set (rax..rdi, rbx, r8..r15) so the next repro shows the exact freed ptr and clobbered value. - new 'corrupt' shell hook deliberately clobbers a live block's back-pointer to prove the guard fires (test-fault-style halt). Verified: test-msg/test-disk/test-fault pass; corrupt hook reports ptr=.. block=0xdeedbeef... with mem dump instead of #GP. rs-dos.img rebuilt with the release kernel.
* v0.5.6: fault dumps carry kernel image base + stack backtracesalmonik2026-08-023-5/+155
| | | | | | | | | | | - fault_dump prints img= (kernel image base) on the serial line and the on-screen band, so a real-hardware repro can be resolved against the PDB without serial - backtrace: rbp-chain walk then a raw scan of the stack above the interrupted rsp; both filter to the .text range (PE-header parse via memory::text_range) so only code addresses are collected - on-screen boot marker shows the kernel image range at every boot - crash.log now records img= + bt= lines alongside rip/rsp
* v0.5.5: on-screen boot markers for disk/fs stagesalmonik2026-08-022-3/+18
| | | | | | | Real hardware has no serial console, and the ahci/fat/fs boot diagnostics were serial-only — a silent fs failure left the user with no way to see where boot stopped. Add boot_marker lines for the AHCI disk count, FAT volume count, and the VFS tree + fs self-test result.
* v0.5.5: crash reports go to a dedicated CRASHLOG USB sticksalmonik2026-08-0212-67/+443
| | | | | | | | | | | | | | | | The fault handler now writes crash.log to the volume labeled CRASHLOG (label-selected via fat::crash_vol), falling back to slot 0. On real hardware the boot USB may be unwritable, so a second stick labeled CRASHLOG survives the write; the shell auto-prints the previous crash report from it at next boot (read_crash_log resolves /disk/<uid>/crash.log through the FAT path, since Disk nodes hold no cached children). - fat.rs: volume_label() + crash_vol() (no allocation) - fs.rs: write_crash_log targets crash_vol(); read_crash_log prefers the CRASHLOG disk node; drop now-unused first_disk() - mkdisk.sh: --label option - test-fault.sh: boots with a dedicated CRASHLOG stick (mkfs -F 32 -n CRASHLOG), verifies crash.log lands there and NOT on the ESP
* v0.5.5: fix real-hardware boot crash — shadow back in heap as first allocationsalmonik2026-08-024-115/+188
| | | | | | | | | | | | | | | | | | | | | | User's machine: boot reached 'rsnix: boot done — shell' then panicked 'len is 0, index 0' at the first cell write — CELLS (the vt grid) was valid at vt::init and empty at the first shell paint, i.e. something stomped the heap between vt::init and the shell banner. The only change in that window vs the working v0.5.3 was the v0.5.4 move of the 1.9 MB display shadow from the heap to the fb-aware page allocator: on this machine's memory layout the page-allocator shadow's fill loop (480K words) clobbered the heap's vt vectors. - Shadow is again the *first* heap allocation, in gop::init before vt::init builds its grids (the v0.5.3 layout that provably boots on the user's hardware) — nothing else in the heap can collide with it. - init_heap now splits the free list at the GOP framebuffer hole instead of subtracting its size from one block that still *spanned* the hole — no heap allocation of any size can land on the display. - Kept the panic-proof try_reserve + fb-overlap rejection + no-shadow warning band; dropped the late init_shadow() call in main.rs. - Verified on QEMU: shadow @ 0x1980020 origin=heap, allocated before vt::init, fb clean at 0x80000000; all 5 suites PASS; 0 warnings.
* v0.5.5: self-diagnosing boot — vt refuses 0x0 geometry, panic band shows ↵salmonik2026-08-023-2/+55
| | | | | | | | | | | | | | | | | | | | | last stage The user's real-hardware boot showed 'PANIC: index out of bounds (len 0, index 0) at vt.rs:146' — the vt grid was created empty because the framebuffer geometry was 0x0 at vt::init (GOP missing or the active mode reporting zero resolution). The v0.5.4 blank screen was the same panic, previously invisible (no screen dump in the panic handler). - vt::init: rows/cols == 0 now halts with a visible white-on-red 'FATAL: no framebuffer geometry — GOP missing or active mode is 0x0' band instead of building an empty grid that panics at the first cell write. - boot_marker records the last boot stage; the panic band appends it as a 4th line so a crash shows exactly how far boot got. - The gop+vt marker now carries the measured geometry ('rsnix: gop 800x600 vt 100x37 ok') so a good boot is self-confirming on the screen. - All 5 test suites pass; build/clippy clean.
* v0.5.5: visible boot progress + panic-on-screen for real hardwaresalmonik2026-08-025-22/+99
| | | | | | | | | | | | | | | | | | | | 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.
* gop: rustfmt collapse in init_shadow warning bandsalmonik2026-08-021-1/+2
|
* v0.5.4: shadow backbuffer can no longer alias the framebuffersalmonik2026-08-026-30/+158
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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-015-22/+49
| | | | | | | | | | | | | | | | | | | | 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-0111-34/+489
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* rsboot: track latest upstream HEAD (92367a8) instead of pinned ee1c85bsalmonik2026-08-012-2/+5
| | | | | | | build-bootloader.sh now uses 'git submodule update --init --remote' so builds fetch and check out the newest rsboot main rather than reverting to the superproject's gitlink commit. Bump the gitlink to 92367a8 (fix(rsboot): naming).
* rsnix v0.5.1: force the GUI canvas to 800x600 via GOP SetModesalmonik2026-08-017-15/+124
| | | | | | | | | | | | | | | | | | | 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-0113-148/+791
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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-0112-25/+1061
| | | | | | | | | | | | | | 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.
* fix pi-lens warnings: unwraps, shell SC2046, dup code ↵salmonik2026-08-0112-170/+152
| | | | | | | | | | | | | | | | | | (fmtbuf/scripts/hexdump/cat/ahci/pci) - memory.rs: self-test Layout::from_size_align no longer panics — the test fails cleanly on an invalid layout - fat.rs: v() no longer unwraps the active-volume slot — invariant violation logs + halts instead of panicking mid-disk-io - strbuf: shared FmtBuf replaces the duplicated PanicBuf/FmtBuf (main.rs + sched.rs) - test-disk.sh: SC2046 — conditional --fresh arg no longer relies on word splitting - scripts: boot.sh/boot-image.sh share lib-boot-args.sh (dup args loop) - shell: cat/hexdump stdin pairs unified with Option<&str> marker; hexdump format_row folded into format_partial - ahci: read/write_sectors unified behind dma_sectors - pci: config_read/write share config_addr
* klog/tty/pager: no more truncated lines — full lines flow, terminal wrapssalmonik2026-08-013-6/+21
| | | | | | | | | | | | - klog: MAX_LINE 128 -> 512 (lens widened u8 -> u16) — long serial_println lines (panics, boot messages) are no longer cut at 128 bytes; they print in full and the terminal wraps them at the screen edge - tty: LINE_BUF_SIZE 256 -> 1024 — typed command lines longer than 256 chars were silently dropped at the buffer limit; now they echo and submit in full (the terminal already wraps the echo mid-typing) - pager (-p): screenfuls now count wrapped rows, not lines — a line wider than the terminal occupies ceil(len/cols) rows, so the pause lands at a real screen boundary instead of overflowing it
* rsnix: preemptive kernel tasks (ADR 0003) — sched, IST fault stacks, ↵salmonik2026-08-0111-53/+1180
| | | | | | | | | | | | | | | | | | 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-012-1/+113
| | | | | | | | - 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