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.
windows95 builds v86 from source — not from copy.sh. Two small bugfix patches ride along on a fork branch until the upstream PRs land.
| 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.
v86 should be checked out on felixrieseberg/v86:windows95-base.
That branch merges the feature branches tracked in
— keep that table
in sync with this list. Each is upstreamable on its own:
electron-renderer-fs-loader (PR #1540) — src/lib.js uses
require("fs") instead of await import("node:fs/promises"). Dynamic
import of node: URLs doesn't work in an Electron renderer.ide-shared-registers (PR #1541) — src/ide.js writes 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 commit 1b90d2e7 changed those
writes to target only current_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.js implements the VMware
backdoor (port 0x5658): 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 so W95TOOLS.EXE (guest-tools/agent) can sync CF_TEXT with
the host. Consumes mouse-absolute and vmware-clipboard-host bus
events; emits vmware-absolute-mouse and vmware-clipboard-guest.fake-network-copy-tcp-addrs — src/browser/fake_network.js
copies the four address subarrays (hsrc/hdest/psrc/pdest) when a
TCPConnection is 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, and recv() blocks forever.
Exercised by tools/probe-tcp.sh.vga-defer-vbe-disable-v86 — src/vga.js defers dispi[4]=0
written 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.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.
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.
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
or windows95-base lost the commit. Win95 will hang at splash on
disks >535MiB. Check cd ../v86 && git log --oneline windows95-base.tools/parcel-build.js shim needs
updating. Look for module.exports.V86= and window.V86=.tcp-connection event gone → SMB falls back to the old-API theft
hack in src/renderer/smb/index.ts — still works, but surprising.on_tcp_connection gone → old-API fallback is dead. SMB integration
only works via the tcp-connection bus event now. Harmless; update
the comment in index.ts and retire the theft code.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).
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:
tools/update-v86.js default at origin/master (it already
uses ../v86, so just git checkout master there)fork/windows95-baseThe 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.