<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rs-dos/Cargo.toml, branch qemu</title>
<subtitle>Simple, kernel-only, 64bit OS, early stage.
</subtitle>
<id>https://git.2137697.xyz/rs-dos/atom?h=qemu</id>
<link rel='self' href='https://git.2137697.xyz/rs-dos/atom?h=qemu'/>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/'/>
<updated>2026-08-27T15:23:34Z</updated>
<entry>
<title>GUI: window/event exports, paint binary, event-loop gate</title>
<updated>2026-08-27T15:23:34Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-27T15:23:34Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=ba304898b8e177d90afb58d201b4c3dd3c927c48'/>
<id>urn:sha1:ba304898b8e177d90afb58d201b4c3dd3c927c48</id>
<content type='text'>
rsapi: WmEvent (kind=u8 enum: 0=key, 1=mouse, 2=focus, 3=close),
WmKeyKind (Char/Enter/Backspace/F1-F4/…), WmMouseEvent (x/y/buttons),
WindowInfo (ptr/w/h).  Five new exports: wm_create, wm_buffer,
wm_flush, wm_destroy, wm_recv (non-blocking TaskMsg dispatch → WmEvent).

Shell: abi_wm_* wrappers bridge rsapi types to rsnix::wm and
sched::recv(); wm_recv translates TaskMsg::Key/Mouse/Focus/Close
into flat WmEvent union.

bins/paint: gate binary — create_window + buffer + event loop with
Bresenham line drawing, color select (1-8), clear (c), F4 close.
All via wm_* ABI exports.

Fully migrated: date, mem, pci, cat, ls, mkdir, touch, rm, klog,
info, paint (11 external binaries in /bin/cli/ + 3 gate binaries).
</content>
</entry>
<entry>
<title>tool migration: v2 exports + 10 external CLI binaries</title>
<updated>2026-08-27T15:16:04Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-27T15:16:04Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=8767dbecb45bbe5f748952fb9171b1a96c173f67'/>
<id>urn:sha1:8767dbecb45bbe5f748952fb9171b1a96c173f67</id>
<content type='text'>
rsapi v2: 14 new ABI function pointers appended after v1 — fs_resolve,
fs_dir_next (iterator), fs_create, fs_remove, fs_read, fs_write,
fs_size, fs_close, rtc_now, mem_stats, pci_probe, pci_device,
klog_dump, kernel_version.  New C-repr structs: DirEntry, RtcTime,
MemStats, PciDevice, KernelVersion.  ABI_VERSION bumped to 2.

Shell-side: build_exports() constructs the full table at runtime per
invocation (replaces static const).  14 kernel-side wrapper functions
bridge rsapi types to rsnix kernel APIs; fs_dir_next maintains a
per-handle cache of children() results for iteration.

Tool binaries (10 crates, all linked against rsapi only):
- date: rtc_now → formatted YYYY-MM-DD HH:MM:SS
- mem: heap/pages free/total via mem_stats
- pci: pci_probe + pci_device enumerate all devices
- cat: fs_read paths or get_line stdin; put_line output
- ls: fs_resolve + fs_dir_next iteration; trailing / for dirs
- mkdir: fs_create(path, true)
- touch: fs_create(path, false)
- rm: fs_remove(path)
- klog: klog_dump 2048 bytes → put_line
- info: rtc_now + kernel_version (minimal; mem/pci deferred)

Gate verified: date prints RTC; pci lists all 4 QEMU devices
(8086:29c0, 1234:1111, 8086:10d3, 8086:2918); hello/boom/count
still work; test-disk PASS; poweroff clean.
</content>
</entry>
<entry>
<title>streams: per-invocation channel, pumping mode, filter pipeline wiring</title>
<updated>2026-08-27T14:58:31Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-27T14:58:31Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=300c0acbd7ab3fae8596ff839c39d9a17c70c68d'/>
<id>urn:sha1:300c0acbd7ab3fae8596ff839c39d9a17c70c68d</id>
<content type='text'>
exec: LineChannel bounded ring (cap=16) with abort/eof/marker fields.
Shell 'pumping mode' assembles canonical lines from its queue into the
channel while the command runs; ^C marks the channel aborted.

Shell-side grammar: USE/TIL pre-drain into the channel before spawn;
&lt;cmd&gt; &lt;path&gt; TIL &lt;marker&gt; sugar drains paths until the marker line.
Interactive TIL: pump_key checks each submitted line against the marker
and closes the channel when it matches.

Exports callbacks run in the command task but touch shell-owned state:
this is safe by construction — the shell blocks in exec_external until
the command completes.  put_line feeds Pipeline::line directly;
get_line pops from the channel (yield-poll when empty).

load: drop NX from image mapping (single-privilege kernel, NX bit 63
reserved when EFER.NXE is set by OVMF); compute image span from section
RVAs not file size.

bins/count: gate binary — reads lines via get_line, reports count via
put_line.  Verified: count USE file → 6; count &lt;path&gt; TIL END → 2;
interactive count TIL DONE → 3; -h filter across task boundary;
^C abort.

v1 stream exports: put_line → Pipeline, get_line ← channel, log_line
→ klog append, exit → abort_current.

Accounting: print_one_line → pipe.line() returns false (head kill /
pager ^C) → the binary should wrap up promptly; accepted: binary does
not check the return value in v1 (phase 3 simplification).
</content>
</entry>
<entry>
<title>exec: PE32+ loader, versioned ABI, first external binaries (v0.6.0)</title>
<updated>2026-08-21T19:17:44Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-21T19:17:44Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=71b6445b048456bf198d8b622570db95f4665cb9'/>
<id>urn:sha1:71b6445b048456bf198d8b622570db95f4665cb9</id>
<content type='text'>
rsapi: the kernel&lt;-&gt;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 -&gt; /disk/&lt;UID&gt;/bin/&lt;kind&gt;/&lt;name&gt;.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(&amp;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.
</content>
</entry>
<entry>
<title>v0.5.11: fix terminal focus — toggle ACTIVE on Focus messages</title>
<updated>2026-08-21T01:30:35Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-21T01:30:35Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=b418c26050870b900ff56d5a47f32209795aaf4a'/>
<id>urn:sha1:b418c26050870b900ff56d5a47f32209795aaf4a</id>
<content type='text'>
- tty: read_line_from_queue() now takes &amp;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.
</content>
</entry>
<entry>
<title>Windowed GUI: wm module, input routing, and the paint app</title>
<updated>2026-08-17T16:56:04Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-17T16:56:04Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=5558e3509d020a0e021a77f0617044497b2f2aee'/>
<id>urn:sha1:5558e3509d020a0e021a77f0617044497b2f2aee</id>
<content type='text'>
- 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
</content>
</entry>
<entry>
<title>v0.5.10: USB HID mouse via polled xHCI (rsnix/src/usb.rs)</title>
<updated>2026-08-04T01:06:06Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-04T01:06:06Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=5e1bdc12bd298a9751da4285b7e93c68b1314332'/>
<id>urn:sha1:5e1bdc12bd298a9751da4285b7e93c68b1314332</id>
<content type='text'>
Polled xHCI driver (mouse-only): controller bring-up, port reset,
enable-slot -&gt; address-device -&gt; config-descriptor walk -&gt; 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.
</content>
</entry>
<entry>
<title>v0.5.9: fix OptiPlex heap crash — EBS retry must not rebuild the free list</title>
<updated>2026-08-03T23:44:05Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-03T23:44:05Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=3e2261d83176752f3ea21e0c97f330b4c1757437'/>
<id>urn:sha1:3e2261d83176752f3ea21e0c97f330b4c1757437</id>
<content type='text'>
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 -&gt; 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 -&gt; 0.5.9.
</content>
</entry>
<entry>
<title>v0.5.8: heap-free QR encoder + crash-dump QR on framebuffer</title>
<updated>2026-08-03T00:23:35Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-03T00:23:35Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=9fde94d068f87b34e0bc6bfa48388d89bb54f1e4'/>
<id>urn:sha1:9fde94d068f87b34e0bc6bfa48388d89bb54f1e4</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>v0.5.7: allocator corruption guard + full register dump for real-hardware repro</title>
<updated>2026-08-02T19:47:18Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-02T19:47:18Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=0187b802113a10a9ee99af48b811cd332c660a13'/>
<id>urn:sha1:0187b802113a10a9ee99af48b811cd332c660a13</id>
<content type='text'>
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.
</content>
</entry>
</feed>
