<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rs-dos/rsnix/src/sched.rs, 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-11-01T16:09:59Z</updated>
<entry>
<title>ehci: bound all init waits; stop auto-rescanning; wider boot watchdog</title>
<updated>2026-11-01T16:09:59Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-11-01T16:09:59Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=d99906b48698c1bd722a1fa5f2270b76317ec661'/>
<id>urn:sha1:d99906b48698c1bd722a1fa5f2270b76317ec661</id>
<content type='text'>
Hardware run 3 showed the same PED=0 SETUP halt and then never reached the
prompt.  Two boot-time hazards explain the death:

- reset_port polled PED with a 2,000,000-iteration MMIO loop (seconds on real
  silicon) and the reset retry ran it twice per port, so the port scan alone
  exceeded the boot watchdog window (task 0 in one frame for 7.5 s panics).
- while no HID was found the cursor task re-ran the whole EHCI scan, port
  resets included, every second -- a rate-matching hub never settles.

Changes:
- every EHCI wait is wall-clock bounded: halt/reset/run 500 ms, PED 200 ms
- control-transfer timeout 5 s -&gt; 500 ms
- per-controller 3 s port-scan budget; no automatic re-scan (explicit
  `usb rescan` only)
- 300 ms power-up settle before the reset walk (RMH bring-up)
- boot-phase watchdog 750 -&gt; 2000 ticks (20 s), room for hub bring-up
- xHCI gets the same persistent bottom-row port/device summary
</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>input: total keyboard routing + per-terminal discipline (ADR 0006 ph1)</title>
<updated>2026-08-21T18:13:59Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-21T18:13:59Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=2f4cf666c0c7bd224932fa48973e7334360c1de3'/>
<id>urn:sha1:2f4cf666c0c7bd224932fa48973e7334360c1de3</id>
<content type='text'>
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 -&gt; pump -&gt; 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-&gt;term1-&gt;
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.
</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>USB2/1.1 (EHCI/UHCI) drivers + real-hardware bring-up hardening</title>
<updated>2026-08-17T12:53:52Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-17T12:53:52Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=be868a43185826b02bf6d091019bb779678525bb'/>
<id>urn:sha1:be868a43185826b02bf6d091019bb779678525bb</id>
<content type='text'>
- 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
</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>
<entry>
<title>v0.5.6: fault dumps carry kernel image base + stack backtrace</title>
<updated>2026-08-02T14:06:40Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-02T14:06:40Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=a459dd3fb267bfba24c3fad1e3dc789bf50ee20b'/>
<id>urn:sha1:a459dd3fb267bfba24c3fad1e3dc789bf50ee20b</id>
<content type='text'>
- 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
</content>
</entry>
<entry>
<title>v0.5.5: crash reports go to a dedicated CRASHLOG USB stick</title>
<updated>2026-08-02T13:21:34Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-02T13:21:34Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=c7d92071e1dd11c45999457b16554b4abaa73b28'/>
<id>urn:sha1:c7d92071e1dd11c45999457b16554b4abaa73b28</id>
<content type='text'>
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/&lt;uid&gt;/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
</content>
</entry>
<entry>
<title>rsnix v0.5.3: fix real-hardware scroll wedge — per-word display push</title>
<updated>2026-08-01T21:44:41Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-01T21:44:41Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=fffec0f04dfcc63bef39eb0441cfad7b584da484'/>
<id>urn:sha1:fffec0f04dfcc63bef39eb0441cfad7b584da484</id>
<content type='text'>
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).
</content>
</entry>
<entry>
<title>rsnix v0.5.2: fault diagnostics + real-hardware scroll-crash hardening</title>
<updated>2026-08-01T20:28:34Z</updated>
<author>
<name>salmonik</name>
<email>salmonik@tuta.io</email>
</author>
<published>2026-08-01T20:28:34Z</published>
<link rel='alternate' type='text/html' href='https://git.2137697.xyz/rs-dos/commit/?id=ab7d87bcde31c1681ea09c30534dde840a58d6fa'/>
<id>urn:sha1:ab7d87bcde31c1681ea09c30534dde840a58d6fa</id>
<content type='text'>
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:
  '!!! &lt;kind&gt; 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.
</content>
</entry>
</feed>
