* Fix guest TCP recv() stalling under concurrent traffic v86's fake_network stores TCPConnection routing fields (hsrc/hdest/ psrc/pdest) as zero-copy subarrays of the SYN frame, which is itself a view into the NE2000 TX ring. Win95's driver uses a 12-slot ring; once it wraps (any concurrent SMB/NBNS/ping while waiting for an upstream reply), pump() emits segments with whatever IP now occupies that slot, the guest RSTs them, and recv() blocks forever. - libv86.js: copy the four address arrays at TCPConnection construction (matches felixrieseberg/v86@dd13099c on fake-network-copy-tcp-addrs, now merged into windows95-base) - tools/probe-tcp.sh + net/tcp-trace.ts + tcp-relay.ts test stub + debug-harness WIN95_PROBE_RUN2: end-to-end regression harness (boot → ping -t → telnet → async write after ring wrap → assert ACK). All env-gated, no production-path change. - docs/v86-patches.md: tracker for all fork patches + upstream PR state - update-v86 SKILL.md: cross-link and new fork-branch entry * Drop checked-in upstream PR description Belongs on the GitHub PR, not in the repo.
6.4 KiB
name, description
| name | description |
|---|---|
| update-v86 | Build and install v86 (wasm + libv86.js + BIOS) into windows95. Use when pulling upstream v86 changes, fixing a broken build, verifying the fork branches are still in sync, or setting up a fresh v86 checkout. |
Updating v86
windows95 builds v86 from source — not from copy.sh. Two small bugfix patches ride along on a fork branch until the upstream PRs land.
Sources
| File | Built from |
|---|---|
src/renderer/lib/libv86.js |
make build/libv86.js in ../v86 |
src/renderer/lib/build/v86.wasm |
make build/v86.wasm |
bios/seabios.bin, bios/vgabios.bin |
copied from ../v86/bios/ |
tools/update-v86.js runs those targets, copies the artifacts, runs 5
sanity checks, and fails loudly if any prerequisite is missing. No
fallbacks, no fetching from copy.sh.
The fork branch
v86 should be checked out on felixrieseberg/v86:windows95-base.
That branch merges the feature branches tracked in
docs/v86-patches.md — keep that table
in sync with this list. Each is upstreamable on its own:
electron-renderer-fs-loader(PR #1540) —src/lib.jsusesrequire("fs")instead ofawait import("node:fs/promises"). Dynamic import ofnode:URLs doesn't work in an Electron renderer.ide-shared-registers(PR #1541) —src/ide.jswrites ATA Command Block registers (Features, Sector Count, LBA Low/Mid/High) to both master and slave. Without this, Win95/98 hang at the splash screen on any disk >~535MiB. Root cause: v86 commit1b90d2e7changed those writes to target onlycurrent_interface, but per ATA spec they're channel-shared (one register file on the IDE cable; both drives latch the same value).vmware-abspointer—src/vmware.jsimplements the VMware backdoor (port0x5658): GETVERSION + ABSPOINTER_* so a guest driver (VBADOS VBMOUSE) can read absolute cursor position and track the host cursor 1:1 without pointer lock, and the legacy text-clipboard commands 6–9 soW95TOOLS.EXE(guest-tools/agent) can syncCF_TEXTwith the host. Consumesmouse-absoluteandvmware-clipboard-hostbus events; emitsvmware-absolute-mouseandvmware-clipboard-guest.fake-network-copy-tcp-addrs—src/browser/fake_network.jscopies the four address subarrays (hsrc/hdest/psrc/pdest) when aTCPConnectionis created from an inbound SYN. Upstream stores them as zero-copy views into the NE2000 TX ring; once the guest's 12-slot TX ring wraps (any concurrent traffic — SMB, NBNS, ping),pump()builds segments with whatever IP now occupies that slot, the guest RSTs them as belonging to no TCB, andrecv()blocks forever. Exercised bytools/probe-tcp.sh.vga-defer-vbe-disable-v86—src/vga.jsdefersdispi[4]=0written from V86 mode until a legacy attribute-mode write reaches the hardware. Win9x's VDD virtualises ports 3B0–3DF for a windowed DOS VM but not 1CE/1CF, so vgabios's VBE-disable leaks through while the rest of its mode-set is captured into the VM's virtual register file — without this the screen turns to planar garbage the moment you open a DOS box.
Prerequisites
rustup target add wasm32-unknown-unknown
brew install openjdk
# one-time: fetch the Closure compiler v86's Makefile pins to
curl -sL https://repo1.maven.org/maven2/com/google/javascript/closure-compiler/v20210601/closure-compiler-v20210601.jar \
-o ../v86/closure-compiler/compiler.jar
Closure must be v20210601 — newer versions hit closure-compiler#3972 on v86's source. The pin is in v86's Makefile.
Steps
cd ../v86
git fetch fork origin
git checkout windows95-base
git rebase fork/windows95-base # in case fork was updated elsewhere
cd ../windows95
node tools/update-v86.js
That's it. Script runs both make targets, copies, verifies.
Sanity-check WARNs
The 5 checks assert invariants src/renderer/smb/index.ts and
tools/parcel-build.js depend on. A WARN means upstream changed
something load-bearing — don't ignore it:
await import("node:...")still present → PR #1540 was reverted or the pattern moved. Electron renderer will fail to load disk images.master.features_reg=missing in minified → PR #1541 was reverted orwindows95-baselost the commit. Win95 will hang at splash on disks >535MiB. Checkcd ../v86 && git log --oneline windows95-base.- Export pattern changed →
tools/parcel-build.jsshim needs updating. Look formodule.exports.V86=andwindow.V86=. tcp-connectionevent gone → SMB falls back to the old-API theft hack insrc/renderer/smb/index.ts— still works, but surprising.on_tcp_connectiongone → old-API fallback is dead. SMB integration only works via thetcp-connectionbus event now. Harmless; update the comment inindex.tsand retire the theft code.
After updating, probe-test
node tools/update-v86.js && tools/probe-boot.sh
Should land SUCCESS in ~40s. If FAIL_SPLASH_HANG, the IDE fix didn't
take — check grep master.features_reg src/renderer/lib/libv86.js. If
FAIL_VXDLINK, retry — sporadic bluescreens are normal (see the
probe-win95 skill).
When a PR merges upstream
Rebase windows95-base to drop the now-redundant commit:
cd ../v86
git fetch origin
git checkout windows95-base
git rebase origin/master # drops the merged commit cleanly
git push fork windows95-base --force-with-lease
If both PRs are upstream, retire the fork branch entirely:
- Point
tools/update-v86.jsdefault atorigin/master(it already uses../v86, so justgit checkout masterthere) - Delete
fork/windows95-base - Remove this skill's "The fork branch" section
- Confirm the 5 sanity checks still pass — they're version-agnostic
Integration contract with SMB
The SMB server sits on top of v86's network adapter. Details in
src/renderer/smb/README.md. Short version: the new path uses the
tcp-connection bus event; the fallback path uses
adapter.on_tcp_connection callback + connection-theft (stealing a
TCPConnection the HTTP probe builds for us). Both use .on_data on
the conn, not .on("data"), because Closure dead-code-eliminates the
event emitter plumbing.
If any v86 update breaks these assumptions, src/renderer/smb/index.ts
needs updating, not just tools/update-v86.js.