File: Readme.md
or #v86 on irc.libera.chat
v86 emulates an x86-compatible CPU and hardware. Machine code is translated to
WebAssembly modules at runtime in order to achieve decent performance. Here's a
list of emulated hardware:
- An x86-compatible CPU. The instruction set is around Pentium 4 level,
including full SSE3 support. Some features are missing, in particular:- Task gates, far calls in protected mode
- Some 16 bit protected mode features
- Single stepping (trap flag, debug registers)
- Some exceptions, especially floating point and SSE
- Multicore
- 64-bit extensions
- A floating point unit (FPU). Calculations are done using the Berkeley
SoftFloat library and therefore should be precise (but slow). Trigonometric
and log functions are emulated using 64-bit floats and may be less precise.
Not all FPU exceptions are supported. - A floppy disk controller (8272A).
- An 8042 Keyboard Controller, PS2. With mouse support.
- An 8254 Programmable Interval Timer (PIT).
- An 8259 Programmable Interrupt Controller (PIC).
- Partial APIC support.
- A CMOS Real Time Clock (RTC).
- A generic VGA card with SVGA support and Bochs VBE Extensions.
- A PCI bus. This one is partly incomplete and not used by every device.
- An IDE disk controller.
- A built-in ISO 9660 CD-ROM generator.
- An NE2000 (RTL8390) PCI network card.
- Various virtio devices: Filesystem, network and balloon.
- A SoundBlaster 16 sound card.
- A hayes-compatible dial-up Modem.
Demos
9front โ
Arch Linux โ
Android-x86 1.6-r2 โ
Android-x86 4.4-r2 โ
BasicLinux โ
Buildroot Linux โ
Damn Small Linux โ
ELKS โ
FreeDOS โ
FreeBSD โ
FiwixOS โ
Haiku โ
SkiffOS โ
ReactOS โ
Windows 2000 โ
Windows 98 โ
Windows 95 โ
Windows 1.01 โ
MS-DOS 6.22 โ
OpenBSD โ
Oberon โ
KolibriOS โ
SkiftOS โ
QNX
Documentation
How it works โ
Networking โ
Dial-up modem networking โ
Alpine Linux guest setup โ
Arch Linux guest setup โ
MS-DOS/FreeDOS guest setup โ
Windows 3.1x guest setup โ
Windows 9x guest setup โ
Windows NT guest setup โ
9p filesystem โ
Linux rootfs on 9p โ
Profiling โ
CPU Idling
Compatibility
Here's an overview of the operating systems supported in v86:
- Linux works pretty well. 64-bit kernels are not supported.
- Buildroot can be used to build a minimal image.
humphd/browser-vm and
darin755/browser-buildroot have some useful scripts for building one. - SkiffOS (based on Buildroot) can cross-compile a custom image.
- Ubuntu and other Debian derivatives works up to the latest version that supported i386 (16.04 LTS or 18.04 LTS for some variants).
- Alpine Linux works. An image can be built from a Dockerfile, see tools/docker/alpine/.
- Arch Linux 32 works. See archlinux.md for building an image.
- Buildroot can be used to build a minimal image.
- ReactOS works.
- FreeDOS, Windows 1.01 and MS-DOS run very well.
- KolibriOS works.
- Haiku works.
- Android-x86 has been tested up to 4.4-r2.
- Windows 1, 3.x, 95, 98, ME, NT and 2000 work reasonably well.
- Windows XP, Vista and 8 work under certain conditions (see #86, #208)
- Many hobby operating systems work.
- 9front works.
- Plan 9 doesn't work.
- QNX works.
- OS/2 doesn't work.
- FreeBSD works.
- OpenBSD works with a specific boot configuration. At the
boot>prompt typeboot -c, then at theUKC>promptdisable mpbiosandexit. - NetBSD works only with a custom kernel, see #350.
- SerenityOS works (only 32-bit versions).
- SkiftOS works.
You can get some information on the disk images here: https://github.com/copy/images.
How to build, run and embed?
You need:
- make
- Rust with the wasm32-unknown-unknown target
- A version of clang compatible with Rust
- java (for Closure Compiler, not necessary when using
debug.html) - nodejs (a recent version is required, v24.16 is known to be working)
- To run tests: nasm, gdb, qemu-system, gcc, libc-i386 and rustfmt
See tools/docker/test-image/Dockerfile
for a full setup on Debian or
WSL.
Run
maketo build the debug build (atdebug.html).Run
make allto build the optimized build (atindex.html).ROM and disk images are loaded via XHR, so if you want to try out
index.html
locally, make sure to serve it from a local webserver. You can usemake run
to serve the files using Python's http module.If you only want to embed v86 in a webpage you can use
libv86.js. For usage,
check out the examples. You can download it from the release section.For bundler-based setups (Vite/React/Next/Webpack), there is also an official npm package:
https://www.npmjs.com/package/v86This package was originally maintained by @giulioz (bundler-optimized fork) and was made "official" for this repo by @basicer with the author's permission.
It is published automatically from this repository via GitHub Actions (.github/workflows/ci.yml, Upload release job) on pushes tomasterand usesnpm publish --provenance.Install:
npm install v86
Alternatively, to build using Docker
- If you have Docker installed, you can run the whole system inside a container.
- See
tools/docker/execto find the Dockerfile required for this. - You can run
docker build -f tools/docker/exec/Dockerfile -t v86:alpine-3.19 .from the root directory to generate docker image. - Then you can simply run
docker run -it -p 8000:8000 v86:alpine-3.19to start the server. - Check
localhost:8000for hosted server.
Running via Dev Container
- If you are using an IDE that supports Dev Containers, such as GitHub Codespaces, the Visual Studio Code Remote Container extension, or possibly others such as Jetbrains' IntelliJ IDEA, you can setup the development environment in a Dev Container.
- Follow the instructions from your development environment to setup the container.
- Run the Task "Fetch images" in order to download images for testing.
Testing
The disk images for testing are not included in this repository. You can
download them directly from the website using:
curl --compressed --output-dir images/ --remote-name-all https://i.copy.sh/{linux.iso,linux3.iso,linux4.iso,buildroot-bzimage68.bin,TinyCore-11.0.iso,oberon.img,msdos.img,openbsd-floppy.img,kolibri.img,windows101.img,os8.img,freedos722.img,mobius-fd-release5.img,msdos622.img}
Run integration tests: make tests
Run all tests: make jshint rustfmt kvm-unit-test nasmtests nasmtests-force-jit expect-tests jitpagingtests qemutests rust-test tests
See tests/Readme.md for more information.
API examples
- Basic
- Programatically using the serial terminal
- A Lua interpreter
- Two instances in one window
- Networking between browser windows/tabs using the Broadcast Channel API
- TCP Terminal (fetch-based networking)
- Saving and restoring emulator state
Using v86 for your own purposes is as easy as:
var emulator = new V86({
screen_container: document.getElementById("screen_container"),
bios: {
url: "../../bios/seabios.bin",
},
vga_bios: {
url: "../../bios/vgabios.bin",
},
cdrom: {
url: "../../images/linux.iso",
},
autostart: true,
});See v86.d.ts for TypeScript definitions. You can use make doc (TypeDoc) or make denodoc (Deno) to generate HTML documentation in ./docs/api/.
Generative AI
At this time, v86 does not accept pull requests or issues written partially or entirely by generative AI tools.
Exceptions may be made on a case-by-case basis.
License
v86 is distributed under the terms of the Simplified BSD License, see
LICENSE. The following third-party dependencies are included in the
repository under their own licenses:
lib/softfloat/softfloat.clib/zstd/zstddeclib.ctests/kvm-unit-tests/tests/qemutests/src/floppy.js/contains parts ported from qemu under the MIT license, see LICENSE.MIT.
Credits
- CPU test cases via QEMU
- More tests via kvm-unit-tests
- zstd support is included for better compression of state images
- Berkeley SoftFloat is included to precisely emulate 80-bit floating point numbers
- The jor1k project for 9p, filesystem and uart drivers
- WinWorld sources of some old operating systems
- OS/2 Museum sources of some old operating systems
- ArchiveOS sources of several operating systems
More questions?
Shoot me an email to [email protected]. Please report bugs on GitHub.
File: docs/archlinux.md
See Alpine setup for a more reliable and
faster way to automatically build Linux images for v86.
(This document partly also applies to other Linuxes)
Choosing an installer ISO
Download Arch Linux 32 from https://archlinux32.org.
Basic installation using QEMU
Installing Arch Linux with these instructions will result in a raw disk image that can be booted by v86.
# fetch archlinux32 installer
wget https://mirror.archlinux32.org/archisos/archlinux32-2021.12.01-i686.iso
# Create a 10 gigabyte disk image. If you intend to pacstrap only 'base' then 1.5G should be fine also.
qemu-img create arch.img 10G
# Follow the normal installation process (you can add accel=kvm if your system supports it to speed up the installation)
qemu-system-x86_64 -m 256 -drive file=arch.img,format=raw -cdrom archlinux32-2021.12.01-i686.isoFor keyboard support, it is necessary to open /etc/mkinitcpio.conf and edit the following line:
MODULES="atkbd i8042"For the changes to take effect, you need to regenerate the initial ramdisk with mkinitcpio -p linux
The resulting arch.img file is a bootable disk image for v86.
Scripting image creation for v86
Installing the ISO by hand takes a long time if you intend to recreate the image many times. There are various reasons why you might want to do this more than once. For example: because the emulator is slow you might want to compile any new software release in QEMU which is much faster and then use the resulting image in v86 instead of making the emulator compile the software. Another reason is that the build progress potentially takes long and if you want to do automated builds in parallel to find out what configurations do and don't work you can just throw more computing power at the problem in order to solve it. This example requires that you have packer, qemu and kpartx installed.
Creating a packer template
Packer is a tool that lets you boot an ISO in any of multiple emulators (so QEMU in our case) and send pre-scripted keystrokes to bootstrap an SSH server. Once the SSH connection is established a script can be started for further provisioning.
Create a template for automating the base installation:
mkdir -p packer
cat > packer/template.json << 'EOF'
{
"provisioners": [
{
"type": "shell",
"override": {
"qemu": {
"scripts": ["scripts/provision.sh"]
}
}
}
],
"builders": [
{
"accelerator": "kvm",
"type": "qemu",
"boot_command": [
"<enter><wait30><enteropenssl passwd help<wait10>",
"dhcpcd<enter><wait5>",
"echo root:root | chpasswd<enter><wait5>",
"systemctl start sshd<enter>"
],
"headless": true,
"boot_wait": "10s",
"disk_size": 1500,
"disk_interface": "ide",
"iso_url": "https://mirror.archlinux32.org/archisos/archlinux32-2021.12.01-i686.iso",
"iso_checksum": "90c6f5aecb095d5578f6c9970539da7c5e9324ec",
"iso_checksum_type": "sha1",
"ssh_wait_timeout": "120s",
"ssh_pty": true,
"ssh_username": "root",
"ssh_password": "root",
"ssh_port": 22,
"format": "raw",
"vm_name": "archlinux",
"disk_detect_zeroes": "unmap",
"memory": 2048,
"vnc_bind_address": "0.0.0.0"
}
]
}
EOFYou can tweak the options a bit to match your situation. For debugging, you can set headless to false. That will show you the VNC connection instead of running the boot_command in the background. For a base pacstrap, using a 2 GB disk image should be sufficient. The raw disk format is important. v86 does not read qcow2 images, only raw disk images. If your system does not support KVM (the default accelerator), you can change "accelerator": "none" to the settings, in macos you may use "accelerator": "hvf". Other accelerator options can be found here.
After gaining SSH connectivity to the VM, packer will run the scripts/provisioning.sh script in the guest.
Creating the Arch Linux installation script
Create a script for your Arch Linux installation. This runs in the live Arch Linux environment, so you need to partition the disk, do a pacstrap, and install a bootloader.
mkdir -p packer/scripts
### Write your own or copy paste the example below
vim packer/scripts/provision.shAn example script to install Arch Linux with the root mounted using the 9p network filesystem:
/* Detailed source-code truncated for AI context efficiency. */With the packer template and the script you have enough to create an image that can be booted by v86. But because this example script installs an Arch Linux that wants to mount root over the network with 9p, we need to host that filesystem first. If you do not want to use 9p, you can just run (cd packer && packer build -force template.json) to build the image.
Creating the 9p filesystem
Now that we have an image that contains a filesystem, we can convert that filesystem into something we can host on the webserver together with the v86 library.
To do so, we need to mount the image once and create a json mapping of the filesystem. The following script shows how to map the filesystem in an automated fashion.
Create a script to builds the image and then creates v86 compatible artifacts:
vim build.shExample script:
#!/bin/sh
SRC=packer
TARGET=output
# build the boxfile from the iso
(cd $SRC && sudo PACKER_LOG=1 PACKER_LOG_PATH="./packer.log" packer build -force template.json)
# test if there is a boxfile where we expected it
if [ ! -f $SRC/output-qemu/archlinux ]; then
echo "Looks like something went wrong building the image, maybe try again?"
exit 1
fi;
# clean up any previous loops and mounts
echo "Making sure mountpoint is empty"
LOOP_DEV=$(sudo losetup -f)
sudo umount diskmount -f || /bin/true
sudo kpartx -d $LOOP_DEV || /bin/true
sudo losetup -d $LOOP_DEV || /bin/true
# mount the generated raw image, we do that so we can create
# a json mapping of it and copy it to host on the webserver
mkdir -p diskmount
echo "Mounting the created image so we can convert it to a p9 image"
sudo losetup $LOOP_DEV $SRC/output-qemu/archlinux
sudo kpartx -a $LOOP_DEV
sudo mount /dev/mapper/$(basename $LOOP_DEV)p1 diskmount
# make images dir
mkdir -p $TARGET
mkdir -p $TARGET/images
mkdir -p $TARGET/images/arch
# map the filesystem to json with fs2json
sudo ./tools/fs2json.py --out $TARGET/images/fs.json diskmount
sudo ./tools/copy-to-sha256.py diskmount $TARGET/images/arch
# copy the filesystem and chown to nonroot user
echo "Copying the filesystem to $TARGET/arch"
mkdir $TARGET/arch -p
sudo rsync -q -av diskmount/ $TARGET/arch
sudo chown -R $(whoami):$(whoami) $TARGET/arch
# clean up mount
echo "Cleaning up mounts"
sudo umount diskmount -f
sudo kpartx -d $LOOP_DEV
sudo losetup -d $LOOP_DEV
# Move the image to the images dir
sudo mv $SRC/output-qemu/archlinux $TARGET/images/arch.imgGiven that the packer template and provision.sh is rooted at packer (adjust the value of $SRC otherwise), run the build.sh at root of your v86 repo:
chmod +x build.sh
./build.shGenerated artifacts are now available for serving from output.
Using the created artifacts in v86
Now that we have everything we need to host a server that serves an Arch Linux environment over the network.
Create a checkout of v86 and run make build/libv86.js.
We can then edit examples/arch.html, we have two options:
- Boot Arch Linux from the 9p filesystem (generated .bin artifacts at
/output/images/arch):
filesystem: {
baseurl: "../output/images/arch/",
basefs: "../output/images/fs.json",
},
bzimage_initrd_from_filesystem: true,
cmdline: [
"rw",
"root=host9p rootfstype=9p rootflags=trans=virtio,cache=loose",
].join(" "),
acpi: false,
autostart: true,- Boot the Arch Linux from the qemu raw disk image:
hda: {
url: "../output/images/arch.img",
# set to true if you want to load it asynchrously during runtime (for this option we need to run a webserver that supports the Range header)
# NOTE: async: false is slow but proved to be more realiable
async: false,
# This needs to be the size of the raw disk.
size: 1.5 * 1024 * 1024 * 1024,
# See the `disk_size` item in the packer template.
},
acpi: false,
autostart: true,Next, we need a webserver that supports the Range header. For example this extension of the SimpleHTTPServer. At your v86 root, run:
wget https://raw.githubusercontent.com/smgoller/rangehttpserver/master/RangeHTTPServer.py
python2 RangeHTTPServer.pyNow that the webserver is running, point your browser to http://localhost:8000/examples/arch.html. Wait for the Linux to boot. When the system is up, click 'Save state to file'. Your browser will download a v86state.bin file. Copy that file to /your/v86/dir/images. You can then edit examples/arch.html again and add a 'state' key to the V86 array.
initial_state: {
"url": "http://localhost:8000/images/v86state.bin",
},If you refresh http://localhost:8000/examples/arch.html you will see that the state is restored instantly and all required files are loaded over the network on the fly.
Networking
The emulator can emulate a network card. For more information look at the networking documentation. To set up networking in the VM, add the following item to the V86 array in the examples/arch.html file:
network_relay_url: "ws://localhost:8080/",This will make the emulator try to connect to a WebSockets proxy. Running the proxy is very easy if you use the Docker container.
sudo docker run --privileged -p 8080:80 --name relay bennottelling/websockproxyNOTE: original benjamincburns/jor1k-relay:latest has throttling built-in by default which will degrade the networking. bennottelling/websockproxy has this throttling removed via websockproxy/issues/4#issuecomment-317255890.
You can check if the relay is running correctly by going to http://localhost:8080/ in your browser. There you should see a message that reads Can "Upgrade" only to "Websocket"..
Now you should be able to get network connectivity in the virtual machine. If you are restoring from a saved state, you might need to first run:
ip link set enp0s5 down
rmmod ne2k-pciTo bring the network up, run:
modprobe ne2k-pci
dhcpcd -w4 enp0s5It might take a while for a carrier to become available on the interface. If the dhcpcd command fails shortly after booting, wait a bit and try again a bit later. If you are using the 9p network filesystem you can use the developer tools networking tab (in chrome) to get a sense of what is going on by looking at the files that are being downloaded.
When the network is up you should be able to curl a website. To check, run curl icanhazip.com. There you should see the public IP of the machine running the proxy.
You can't do inbound traffic into the VM with the websockproxy Docker container because it uses a basic NAT. To SSH into the VM running in the browser, you can create a reverse SSH tunnel to expose the SSH port of the sshd in the VM to the outside world. You may need to start sshd first, it may also be reasonable to change root password:
passwd root
systemctl start sshdthen create a reverse SSH tunnel:
# This will create a port 1122 on the example.com server
# which forwards to the SSH in the VM
ssh [email protected] -R 1122:localhost:22Now on the example.com server you should be able to SSH into your browser tab by running ssh root@localhost -p 1122.
File: docs/cpu-idling.md
Some operating systems don't support hlt instruction, because of this, the CPU spin loops instead of idling.
Here are some solutions for different OSes:
MS-DOS (using DOSIdle)
- Download
DOSID251.zipfrom https://www.vogons.org/viewtopic.php?p=438763#p438763 - Unzip DOSIDLE.EXE from archive in any location (recommended to root of C:).
- Run
edit C:\autoexec.bat - Add to file:
C:\path\to\dosidle.exe - Save changes (press Alt + F and x) and restart the VM.
Note: To hide output when starting DOSIdle, change C:\path\to\dosidle.exe to C:\path\to\dosidle.exe > nul on step โ4.
FreeDOS ([source](https://narkive.com/UGrcO8wU.2))
- Run
edit C:\fdconfig.sys(oredit C:\config.sys) - Add to file:
IDLEHALT=1 - Save changes (press Alt + F and x) and restart FreeDOS.
Windows 9x (using AmnHLT)
- Download
amnhltm.zipfrom http://toogam.com/software/archive/drivers/cpu/cpuidle/amnhltm.zip (mirror) - Unzip the archive in any location.
- Note: If you have installed VBE9x, restart Windows, press F8 on boot, select Command prompt only, run
cd C:\path\to\amnhlt\, and follow to the next step. - Run
AMNHLT.BAT - Restart Windows, and AmnHLT will start automatically on next boot (you can safely delete archive and unpacked folder).
Windows 98+ and Unix-like
These systems are already supports hlt, no further action is required.
File: docs/filesystem.md
A 9p filesystem is supported by v86, using a virtio transport. There are several
ways it can be set up.
Guest mount
In all cases, the filesystem is mounted in the guest system using the 9p
filesystem type and the host9p device tag. Typically you want to be specific
with the version and transport options:
mount -t 9p -o trans=virtio,version=9p2000.L host9p /mnt/9p/Here are kernel arguments you can use to boot directly off the 9p filesystem:
rw root=host9p rootfstype=9p rootflags=trans=virtio,version=9p2000.LThe aname option can be used to pick the directory from 9p to mount. The rw
argument makes this a read-write root filesystem.
JSON/HTTP Filesystem
This is the standard way to setup the 9p filesystem. It loads files over
HTTP on-demand into an in-memory filesystem in JS. This allows files to be
exchanged with the guest OS. See create_file and read_file instarter.js.
This mode is enabled by passing the following options to V86:
filesystem: {
basefs: "../9p/fs.json",
baseurl: "../9p/base/",
}Here, basefs is a json file created using
fs2json.py and the baseurl directory is created using
copy-to-sha256.py.
If basefs and baseurl are omitted, an empty 9p filesystem is created. Unless
you configure one of the alternative modes.
Function Handler
You can handle 9p messages directly in JavaScript yourself by providing a
function as handle9p under filesystem:
filesystem: {
handle9p: async (reqBuf, reply) => {
// reqBuf is a Uint8Array of the entire request frame.
// you can parse these bytes using a library or reading the 9p spec.
// once you formulate a response, you send the reply frame as a
// Uint8Array by passing it to reply: reply(respBuf)
}
}This allows you to implement a 9p server or custom proxy in JS. However, this
filesystem will not be cached (unless cached in the guest OS), functions likecreate_file and read_file will not be available, and you will be responsible
for keeping its state in sync with any machine save states.
WebSocket Proxy
You can also back the 9p virtio filesystem with a 9p server over WebSocket by
providing a WS proxy URL:
filesystem: {
proxy_url: "ws://localhost:8080/"
}Simlar to using handle9p, this filesystem will not be available in JS and
will need to be re-mounted after restoring state.
The WS proxy just needs to hand off messages with a connection to a normal 9p
server. Each binary WebSocket message is the full buffer of a request or a
reply.
To implement, request message bytes can just be sent directly to the 9p
connection, but the 9p reply stream needs to be buffered into a single binary
WebSocket message. The proxy must at least parse the first 4 bytes to get the
message size and use it to buffer a full message before sending over WebSocket.
The wanix CLI has a serve command that
not only serves a directory over HTTP, but also over 9P via WebSocket. You can
see how it implements a proxy in Go.
File: docs/how-it-works.md
Here's an overview of v86's workings. For details, check the
source.
The major limitations of WebAssembly are (for the purpose of making emulators with jit):
- structured control flow (no arbitrary jumps)
- no control over registers (you can't keep hardware registers in wasm locals across functions)
- no mmap (paging needs to be fully emulated)
- no patching
- module generation is fairly slow, but at least it's asynchronous, so other things can keep running
- there is some memory overhead per module, so you can't generate more than a few thousand
v86 has an interpreted mode, which collects entry points (targets of function
calls and indirect jumps). It also measures the hotness per page, so that
compilation is focused on code that is often executed. Once a page is
considered hot, code is generated for the entire page and up to MAX_PAGES
that are directly reachable from it.
v86 generates a single function with a big switch statement (brtable), to
ensure that all functions and targets of indirect jumps are reachable from
other modules. The remaining control flow is handled using the "stackifier"
algorithm (well-explained in
this blog post).
At the moment, there is no linking of wasm modules. The current module is
exited, and the main loop detects if a new module can be entered.
In practice, I found that browsers don't handle this structure (deep brtables,
with locals being used across the entire function) very well, and MAX_PAGES
has to be set to fairly low, otherwise memory usage blows up. It's likely that
improvements are possible (generating fewer entry points, splitting code across
multiple functions).
Code-generation happens in two passes. The first pass finds all basic block
boundaries, the second generates code for each basic block. Instruction
decoding is generated by a set of
scripts from a table of
instructions. It's
also used to generate
tests.
To handle paging, v86 generates code similar to this (see gen_safe_read):
entry <- tlb[addr >> 12 << 2]
if entry & MASK == TLB_VALID && (addr & 0xFFF) <= 0xFFC - bytes: goto fast
entry <- safe_read_jit_slow(addr, instruction_pointer)
if page_fault: goto exit-with-pagefault
fast: mem[(entry & ~0xFFF) ^ addr]There is a 4 MB cache that acts like a tlb. It contains the physical address,
read-only bit, whether the page contains code (in order to invalidate it on
write) and whether the page points to mmio. Any of those cases are handled in
the slow path (safe_read_jit_slow), as well as walking the page tables and
triggering page faults. The fast path is taken in the vast majority of times.
The remaining code generation is mostly a straight-forward, 1-to-1 translation
of x86 to wasm. The only analysis done is to optimise generation of condional
jumps immediately after arithmetic instructions, e.g.:
cmp eax, 52
setb eaxbecomes:
... // code for cmp
eax <- eax < 52A lazy flag mechanism is used to speed arithmetic (applies to both jit and
interpreted mode, seearith.rs andmisc_instr.rs).
There's a wip that tries to elide most lazy-flags updates:
https://github.com/copy/v86/pull/466
FPU instructions are emulated using softfloat (very slow, but unfortunately
some code relies on 80 bit floats).
File: docs/linux-9p-image.md
In order to create a Linux image that can mount the 9p file system, add the following lines to the kernel configuration:
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_NET_9P_DEBUG=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI=y
CONFIG_9P_FS=y
CONFIG_9P_FSCACHE=y
CONFIG_9P_FS_POSIX_ACL=yA Dockerfile for this build is here: https://github.com/ysangkok/build-v86-9p-linux
Using initcpio
This allows you to remount the root file system using 9p. No changes are necessary if you only want to mount a 9p filesystem after booting.
Add the following files:
/etc/initcpio/hooks/9p_root
#!/usr/bin/bash
run_hook() {
mount_handler="mount_9p_root"
}
mount_9p_root() {
msg ":: mounting '$root' on real root (9p)"
if ! mount -t 9p host9p "$1"; then
echo "You are now being dropped into an emergency shell."
launch_interactive_shell
msg "Trying to continue (this will most likely fail) ..."
fi
}/etc/initcpio/install/9p_root
#!/bin/bash
build() {
add_runscript
}Change the following options in /etc/mkinitcpio.conf:
MODULES="virtio_pci 9p 9pnet 9pnet_virtio"
HOOKS="base udev autodetect modconf block filesystems keyboard fsck 9p_root" # appended 9p_rootFile: docs/networking.md
v86 networking
User guide to networking in v86.
Introduction
On the most basic level, networking in v86 is comprised of two components:
- an emulation of the guest's Network Interface Controller (NIC), and
- a network backend which passes ethernet frames between the NIC and a virtual and/or physical ethernet network.
There are two NIC emulations supported by v86 to chose from, either ne2k (NE2000/RTL8390-compatible NIC) or virtio (VirtIO-compatible device). The right choice simply depends on the driver support in the guest OS, older OSes like FreeDOS only support NE2000, more modern ones usually support VirtIO. In case both are supported by the guest OS it's recommended to try VirtIO first and only fall back to NE2000 if that fails. In some cases it will also be necessary to manually load a driver or similar to activate the NIC and/or networking in the guest OS, yet modern systems usually auto-detect an available NIC during installation and when booting.
There are also several network backends to chose from which emulate the network that the virtual NIC is connected to, they differ in their requirements and in the degree of network access and services provided to guests. Some provide only limited network access, others full access to a physical network which may include a gateway to the Internet. Backends may require a specific type of proxy server to operate.
Backend URL schemes
The active network backend is configured through a user-specified backend URL. Each backend has at least one distinct URL scheme as specified below, where PROXY is the DNS hostname or IP address of a compatible proxy server, PORT its optional TCP port number (and its default), and QUERY is some HTTP query field fragment:
| Backend | Backend URL scheme(s) | Example(s) |
|---|---|---|
| inbrowser | inbrowser |
inbrowser |
| wsproxy | "ws://" PROXY [":" PORT=80] ["/" ...]``"wss://" PROXY [":" PORT=443] ["/" ...] |
wss://relay.widgetry.org/ |
| wisp | "wisp://" PROXY [":" PORT=80] ["/" ...]``"wisps://" PROXY [":" PORT=443] ["/" ...] |
wisp://localhost:12345 |
| fetch | "fetch" [ "://" PROXY [":" PORT] ["/" QUERY] ] |
fetch``fetch://localhost:1234/?url= |
Note that wss:// and wisps:// are the TLS-secured transports of ws:// and wisp://, respectively.
[!TIP]
Since public proxy servers provide only limited bandwidth it is recommended to install and use a local, private proxy server for best results. All proxy servers allow to be executed on the local machine, in a VM running on the local machine, in a local network or even publicly on the Internet (which is generally not recommended, of course). Many proxy servers are distributed as Docker containers which is the recommended way of installing them, otherwise install into a VM.
Network setup
Web interface setup
Network setup in the v86 web interface at https://copy.sh/v86/ is straightforward, simply copy the backend URL into the text box named Networking proxy or select one of the presets to configure the network backend. The guest's NIC emulation (NE2000 or VirtIO) is automatically configured when selecting the guest image in the web interface.
Embedded v86 setup
JavaScript applications that do not use the v86 web interface (but instead embed V86 into their architecture) setup their network by using the common config object that they pass to the V86 constructor. Network settings are members of the object config.net_device, all settings are optional except for relay_url, see v86.d.ts.
Example `net_device` settings
Example 1: Provide an emulated NE2000 NIC to the guest OS and use the
wsproxybackend with a secure wsproxy server at public hostrelay.widgetry.orglistening at default TLS port 443:javascriptlet example_1 = new V86({ net_device: { relay_url: "wss://relay.widgetry.org/" }, // ... });Example 2: Provide a VirtIO NIC to the guest OS and use the
fetchbackend with a CORS proxy server at the local machine listening at port number 23456:javascriptlet example_2 = new V86({ net_device: { type: "virtio", relay_url: "fetch", cors_proxy: "https://localhost:23456/?url=" }, // ... });
Network backends
One way to compare the different network backends is how they operate on different layers of the TCP/IP Model (see Wikipedia for a comparison to the OSI model), approximately:
Network Peer Backend v86 Guest
[ Application ] <---- fetch ----> +-----+ [ Application ]
[ Transport ] <---- wisp -----> | v86 | [ Transport ]
[ Network ] | | [ Network ]
[ Access ] <--- wsproxy ---> +-----+ <---> [ Access ]
and inbrowser
Fig. 1: Network backends in v86v86 guests strictly expect to exchange raw ethernet frames with their (emulated) network card, hence the higher the layer that a v86 network backend operates on the more virtualized the network becomes and the more work has to be done by the backend to fill in for the missing layers.
In order to facilitate this for backend implementations, v86 provides helper functions to encode/decode ethernet frames, ARP and IPv4 packets, UDP datagrams, TCP streams and HTTP requests/responses. v86 can also provide minimal but sufficient ARP, ICMP-echo, DHCP, DNS (including DoH) and NTP services to guests.
The v86 architecture is open for additional network backend implementations, for a basic example see examples/two_instances.html.
The `inbrowser` backend
This backend provides raw ethernet services for multiple v86 guests running within the same browser process (meaning within the same web page and/or in separate browser tabs). It works standalone without a proxy server, but it also does not provide any access to external networks.
The inbrowser backend is implemented using the browser-internal BroadcastChannel API, due to its simplicity it is the most efficient backend, however all VMs have to share the same browser resources.
The `wsproxy` backend
A backend based on a proxy server that provides raw ethernet services to guests using the WebSocket protocol for transport. It depends on the specific proxy server what kind of network configuration it presents to guests, but usually a separate IP subnet with DHCP and DNS services and optional access to the server's physical network and possibly Internet are provided.
Since this backend (including its proxy server) only forwards unmodified ethernet frames it is inherently efficient while providing full physical network emulation to guests.
Proxy server
- websockproxy -- one TAP device for all clients, integrates dnsmasq for DHCP/DNS, no TLS, original server by benjamincburns
- Docker container
benjamincburns/jor1k-relayis throttled, see this comment - Docker container
bellenottelling/websockproxyis unthrottled - See here for step-by-step instructions on how to unthrottle websockproxy manually.
- Docker container
- go-websockproxy -- one TAP device for all clients, written in Go, without integraded DHCP but with integrated TLS support
- node-relay -- like websockproxy but written for NodeJS (dnsmasq/no TLS), see New websocket ethernet switch built using Node.js #777
- wsnic -- uses a single bridge and one TAP device per client, integrates dnsmasq for DHCP/DNS and stunnel for TLS
- RootlessRelay -- uses its own network stack that doesn't require TUN/TAP devices, has a built-in reverse proxy and admin interface, see RootlessRelay #1442
See here for a benchmark comparing the download performance of these proxy servers.
The `wisp` backend
The wisp backend implements the client side of the WISP protocol. WISP is a client/server protocol designed to exchange messages containing UDP and TCP payloads between a WebSocket client and a WISP-compatible proxy server. Note that WISP transports only the packet payloads, not the raw UDP or TCP packets.
This backend monitors outbound traffic from guests and wraps/unwraps TCP payload data in WISP messages. A TCP state machine is included to terminate the guest's TCP stream. In addition to the TCP stream, virtual replies to ARP, DHCP, DNS, NTP, ICMP-Ping and UDP-Echo requests from guests are generated (to a certain degree). See PR #1097 for additional information about this backend.
v86 guests are isolated from each other when using the wisp backend.
WISP-compatible proxy server
[!NOTE]
The WISP protocol only supports UDP and TCP client sockets in the v86 guest, any server sockets listening in the guest are not supported.
[!NOTE]
This WISP implementation does not support UDP, only TCP. Once UDP is added, regular DNS over UDP will become the default (instead of DoH), and the builtin NTP and UDP-Echo servers will be removed.
The `fetch` backend
The fetch backend uses the browser's fetch() API to allow guests to send HTTP requests to external HTTP servers and to receive related HTTP responses. This is however complicated by the fact that browsers add CORS headers to HTTP requests initiated by fetch(), and that they check the CORS headers of related HTTP responses to block access to external web resources not authorized to fetch() in the given context.
This backend is efficient and very useful in cases where CORS is not in the way, otherwise (and in general) a CORS proxy server must be used to provide access to HTTP servers on the open Internet.
Like the wisp backend, the fetch backend handles DHCP and ARP requests from guests internally, and additionally monitors the guest's outbound traffic for HTTP requests which it translates into calls to fetch(). NTP, ICMP pings and UDP echo packets are handled to a certain degree. Note that fetch() performs the DNS lookup using the browser's internal DNS client. See PR #1061 for additional technical details.
Starting with PR #1233, the TCP guest listener can be accessed from JS API, see the examples/tcp_terminal.html example.
v86 guests are isolated from each other when using the fetch backend.
v86 guests have HTTP access to the host's localhost using the URL http://.external (e.g. 1234.external -> localhost:1234).
CORS proxy server
- cors-anywhere -- NodeJS
- uncors -- A simple PHP-based CORS proxy server for Apache2.
[!TIP]
You can pass the following flags to chromium to allow browsing without restrictions when using the fetch backend:text--disable-web-security --user-data-dir=/tmp/testNOTE: This turns off the same-origin policy and should only be used temporarily!
Related topics
v86 run-time state images
v86 supports saving and restoring the guest's and emulator's run-time state in state image files.
When restoring a state image, v86 randomises the restored guest's MAC address to make sure that multiple VMs restored from the same state image use different MAC addresses. However, the restored guest OS is unaware that its NIC's MAC address has changed which prevents it from sending and receiving packets correctly. There are several workarounds:
- Unload the network driver before saving the state. On Linux, unloading can be
done usingrmmod ne2k-pciorecho 0000:00:05.0 > /sys/bus/pci/drivers/ne2k-pci/unbindand loading (after the state has been
loaded) usingmodprobe ne2k-pciorecho 0000:00:05.0 > /sys/bus/pci/drivers/ne2k-pci/bind - Pass
preserve_mac_from_state_image: trueto the V86 constructor. This
causes MAC addresses to be shared between all VMs with the same state image. - Pass
mac_address_translation: trueto the V86 constructor. This causes v86
to present the old MAC address to the guest OS, but translate it to a
randomised MAC address in outgoing packets (and vice-versa for incoming
packets). This mechanism currently only supports the ethernet, ipv4, dhcp and
arp protcols. Seetranslate_mac_addressinsrc/ne2k.js. This is
currently used in Windows, ReactOS and SerenityOS profiles. - Some OSes don't cache the MAC address when the driver loads and therefore
don't need any of the above workarounds. This seems to be the case for Haiku,
OpenBSD and FreeBSD.
Note that the same applies to IP addresses, so a DHCP client should only be run
after the state has been loaded.
NodeJS
Network backends wsproxy and wisp depend on a browser-compatible WebSocket constructor being present which is the case since NodeJS v22, backends inbrowser and fetch should work straightaway.
Links
examples/two_instances.html, example code that shows how to connect two VMs in a web page with a virtual ethernet crossover cable.examples/broadcast-network.html, example code that shows the raw packet API.examples/tcp_terminal.html, example code that shows how to communicate with a guest TCP port on thefetchbackend.- DC through windows OS for experimental lab #1195, demonstrates how to setup a Domain Controller for two Windows VMs (XP and Server 2003) using a virtual crossover cable.
- Working on a new cross-platform network relay that is a full virtualized network #1064 (used in env86 #1085)
File: docs/profiling.md
v86 has a built-in profiler, which instruments generated code to count certain
events and types of instructions. It can be used by building with make debug-with-profiler and opening debug.html.
For debugging networking, packet logging is available in the UI in both debug
and release builds. The resulting traffic.hex file can be loaded in Wireshark
using file -> import from hex -> tick direction indication, timestamp %s.%f.
File: docs/windows-9x.md
Installing using QEMU
Recommended versions:
- Windows 95 OSR2(.5)
- Windows 98 Second Edition (SE)
- Create a disk image (up to 2 GB):
qemu-img create -f raw hdd.img <size in megabytes>M- Run QEMU with the following settings:
qemu-system-i386 -m 128 -M pc,acpi=off -drive file=hdd.img,format=raw- add
-cdrom /path/to/installCD.iso, if you use a CD version. - add
-fda /path/to/boot_floppy.img -boot a, if you use a floppy version or your install CD is non-bootable. - (optionally) add
-device sb16to enable sound - (optionally) add
-nic user,model=ne2k_pcior-device ne2k_pci,netdev=<...>to enable networking
For Windows 98: select "Start Windows 98 Setup from CD-ROM". For Windows 95: select "Load NEC IDE CDROM driver" and run
fdiskto create partition, restart emulator, runformat c:andD:\WIN95\SETUP.To change floppy disk, press Ctrl+Alt+2 to switch to the QEMU Monitor, run
change floppy0 /path/to/new_floppy_imageand press Ctrl+Alt+1 to switch to VGA.Follow the installation guide on the screen.
[!TIP]
For transfer files from host to guest, use genisoimage (UltraISO and PowerISO for Windows and Mac) for creating CD-ISO image or dosfstools (WinImage for Windows) for creating floppy disk images, then mount the created image to QEMU.
Troubleshooting
"Windows protection" errors during startup
"VFBACKUP could no load VFD.VXD" on startup (Windows 95)
Workaround #1:
Source: #1185
- Mount the installation CD (or
Disk 3for the RTM version on floppy disks). - Open the "MS-DOS prompt" and run:
For the CD version:
extract /a /l C:\Windows\System <cd-rom letter>:\WIN95\WIN95_02.CAB vfd.vxdFor the floppy version:
extract /a /l C:\Windows\System <floppy drive letter>:\WIN95_03.CAB vfd.vxdWorkaround #2:
Source: #289
- Open the Start menu, click on "Run" and run
sysedit. - Find
C:\AUTOEXEC.BATand addsmartdrvto the top of the file. - Press File -> Save.
Floppy disk support
Currently, the floppy drive in v86 works only with MS-DOS compatibility mode.
To check this: open the Start menu, click on "Control Panel" and "System", select "Performance" tab.
If it says "Drive A is using MS-DOS compatibility mode file system", the floppy drive should work properly in v86. If not, try this solution:
- Click on "Device Manager" in "System Properties".
- Open "Floppy disk controllers", select "Standard Floppy Disk Controller" and press "Remove" at the bottom.
- Restart Windows.
Enabling True Color (32 bpp)
The default VGA display driver only supports 640x480x4 video mode, to fix this, you can install Universal VBE9x Video Display Driver or VMDisp9x.
Universal VBE9x Video Display Driver
[!WARNING]
After installing, DOS Mode (and other programs and games that require it) may not work properly.
This is a problem in VBE9x, not v86, see #110.
Also, this driver doesn't support DirectX, DirectDraw and OpenGL.
- Download driver from https://bearwindows.zcm.com.au/vbe9x.htm and unpack into Windows.
- Right-click on the Desktop, click on "Properties".
- Click "Advanced" > "Adapter" > "Change".
- Press "Next", select "Display a of all the drivers in a specific location..." and press again "Next".
- Press "Have Disk...", click "Browse" and go to folder with unpacked driver. Inside the folder with driver, should be folders like
032mb,064mb,128mb. Choose a version based on needed video memory size (for example,032mb), then selectvbemp.infinside. - Select "VBE Miniport" adapter, press "OK" and "Next".
- After installing, restart Windows.
VMDisp9x (Windows 95)
[!WARNING]
This driver can run DOS Mode with some graphical glitches. However, DirectX and/or DirectDraw may not work properly with this driver.
Also, this driver doesn't support OpenGL.
- Download
vmdisp9x-<...>-driver-2d.imgfrom https://github.com/JHRobotics/vmdisp9x/releases. - Mount as floppy image, right-click on the Desktop, click on "Properties".
- Click "Advanced" > "Adapter" > "Change".
- Press "Have Disk...", click "Browse" and go to the floppy.
- Select "VESA ISA" adapter and press "OK".
- After installing, restart Windows.
Enabling absolute mouse positioning (VBMOUSE)
v86 emulates the VMware absolute pointing device. With an absolute mouse driver installed in the guest, the guest cursor follows the host cursor directly, without having to lock the mouse.
VBADOS provides VBMOUSE, an open-source DOS mouse driver with VMware mouse support, together with a 16-bit Windows mouse driver on top of it that Windows 9x can use.
- Download vbados.flp and mount it as a floppy image (or copy its contents into the guest in some other way).
- Copy
VBMOUSE.EXEfrom the floppy to the hard disk (for example toC:\VBADOS) andVBMOUSE.DRVtoC:\WINDOWS\SYSTEM. - Add
C:\VBADOS\VBMOUSE.EXEtoC:\AUTOEXEC.BAT, so the DOS part of the driver is loaded before Windows starts. - In
C:\WINDOWS\SYSTEM.INI, change themouse.drvline in the[boot]section tomouse.drv=vbmouse.drv. - Restart Windows.
CPU idling on Windows 95
See about installing AmnHLT.
Enabling networking on Windows 95 (requires install CD)
- Open the Start menu, click on "Control Panel" and "Add New Hardware".
- Press "Next", select "No" and select next options:
| Option | Value |
|---|---|
| Hardware type | Network adapters |
| Manufacturers | Novell |
| Models | NE2000 Compatible |
- Press "Next" and restart Windows.
- After restarting, right-click on "My computer", select "Propeties".
- Open "Device Manager" tab, select "NE2000 Compatible" (in "Network adapters") and press "Properties"
- Open "Resources", change values by selecting the properties and click on "Change Setting":
| Option | Value |
|---|---|
| Interrupt Request | 10 |
| Input/Output Range | 0300 - 031F |
- In "Control Panel", open "Network", click on "Add", choose "Protocol" and select the following options:
| Option | Value |
|---|---|
| Manufacturers | Microsoft |
| Network Protocols | TCP/IP |
- (optionally) Set "Primary Network Logon" to
Windows Logon.
Enabling sound manually
[!NOTE]
If you don't have an install CD, use the Sound Blaster 16 driver from https://web.archive.org/web/20210814023225/https://www.claunia.com/qemu/drivers/index.html (unpacksbw9xup.exeas a zip archive).
- Open "Start" menu, click on "Control Panel" and "Add New Hardware".
- Press "Next", select "No" and select the following options:
| Option | Value |
|---|---|
| Hardware type | Sound, video and game cotrollers |
| Manufacturers | Creative Labs |
| Models | Creative Labs Sound Blaster 16 or AWE-32 |
- Restart Windows.
File: docs/windows-nt.md
Windows NT 3.1
Installing using QEMU
- Install MS-DOS and Oak CD-ROM Driver.
- Create 4 blank floppy disk images:
- run
qemu-img create -f raw floppy.img 1440K - mount (
-fda floppy.img) and runformat A:in a VM
- Run QEMU with the following settings for installation:
qemu-system-i386 -m 64 -drive file=hdd.img,format=raw -cpu pentium -M pc,acpi=off -cdrom InstallCD.iso- Run
xcopy /v <CD-ROM letter>:\I386\ C:\install\in a VM to copy all files, disable the CD-ROM driver. - Run QEMU with the following settings:
qemu-system-i386 -m 64 -drive file=hdd.img,format=raw -cpu pentium -M pc,acpi=off- Run
C:\install\winnt /F /Cin a VM. - Follow the setup instructions. To change floppy disk, press Ctrl+Alt+2 to switch to the QEMU Monitor, run
change floppy0 /path/to/new_floppy_imageand press Ctrl+Alt+1 to switch to VGA.
Windows NT 3.51
Installing
[!NOTE]
In newer versions of QEMU, the Windows Setup may not work, you can use an older version of QEMU, PCem, 86Box or PCBox instead.
- If you install via MS-DOS, install the Oak CD-ROM Driver and run
<CD-ROM letter>:\I386\WINNT /B. - Follow the setup instructions.
- After installing, download NT 3.51 SuperPack (here or here), unpack the archive into a Windows and copy files from
FAT32(SYS\FAT32) andRENEW(SYS\RENEW) folders inC:\WINNT35\system32\driverswith replacing.
Enabling networking
- Open "Control Panel" > "Network", install Windows NT Networking (installation CD required).
- In "Network Adapter Card Detection", press Continue three times, set
Network Adapter Card: Novell NE2000 Compatible Adapter. - Set the following settings and click Continue:
IRQ Level: 10
I/O Port Address: 0x300- In "Bus Location", press OK. Check the boxes "TCP/IP Transport" and "Enable Automatic DHCP Configuration" in the next window.
- In "TCP/IP Configuration", check the box "Enable Automatic DHCP Configuration".
- Restart the VM.
Windows NT 4.0
Recommended version: Windows NT 4.0 SP1
Installing using QEMU
- Run QEMU with the following settings for installation:
qemu-system-i386 -m 64 -drive file=hdd.img,format=raw -cdrom InstallCD.iso -cpu pentium -M pc,acpi=off- On setup startup, press F5 and select "Standard PC".
- Follow the setup instructions.
Running in v86
Due to a problem with CPUID, you need to add cpuid_level: 2 and acpi: false to the V86 constructor (not supported in the UI):
var emulator = new V86({
...
cpuid_level: 2,
acpi: false
});Enable True Color
Source: https://computernewb.com/wiki/QEMU/Guests/Windows_NT_4.0
- Download driver (version
2010.07.09) from https://bearwindows.zcm.com.au/vbemp.htm and unpack into Windows. - Right-click on the Desktop, click on "Properties".
- Click "Settings" > "Display Type" > "Change".
- Press "Have disk", click "Browse" and go to folder with unpacked driver. Go to
VBE20\NT4, then selectvbemp4.infinside. - Select "AnaPa Corp VBE Miniport" adapter, press "Yes" and "OK".
- After installing, restart the VM.
Enabling absolute mouse positioning
- Download VMware Tools 6.0 and mount the ISO to the VM.
- Open Start menu, select "Settings" -> "Control Panel".
- Open "Mouse", press "General" -> "Change"
- Press "Have disk" and "Browse". Go to
<CD letter>:\program files\VMware\VMware Tools\Drivers\mouse\winntand selectvmmouse.inf. - Press "OK" and restart the VM.
Windows 2000/XP
Installing using QEMU
- Run QEMU with the following settings for installation:
qemu-system-i386 -m 512 -drive file=hdd.img,format=raw -cdrom InstallCD.isoOptional:
- add
-device sb16to enable sound - add
-nic user,model=ne2k_pcior-device ne2k_pci,netdev=<...>to enable networking
- Follow the setup instructions.
- This step fixes the error
Uncaught RangeError: Maximum call stack size exceededin Chromium during Windows 2000/XP startup in v86.
After installation, change the computer type to "Standard PC" as described here:
- Open Start menu, right-click on "My Computer", select "Manage"
- Open Device Manager, open Computer, right-click on "ACPI Uniprocessor PC"
- Select "Update Driver..." > "No, not this time"
- Select "Install from a list or specific location (Advanced)" > Next > "Don't search. I will choose the driver to install."
- Choose "Standard PC", press Next > Finish.
- Restart the VM, follow multiple "Found New Hardware Wizard" dialogs with default options.
Enabling True Color (for Windows 2000)
[!NOTE]
This driver doesn't support DirectX, DirectDraw and OpenGL.
- Download driver from https://bearwindows.zcm.com.au/vbemp.htm and unpack into Windows.
- Open Start menu, right-click on "My Computer", select "Manage"
- Open Device Manager, open Computer and right-click on "Video Controller".
- Press "Properties", select "Driver" tab and press "Update Driver".
- Select "Display a list of the known drivers for this device...", choose "Display adapters".
- Press "Have Disk...", click "Browse" and go to folder with unpacked driver. Go to
VBE20\W2K\PNP, then selectvbemppnp.infinside. - Select "VBE Miniport" adapter, press "Yes" and "Next".
- After installing, restart the VM.
Enabling sound
Source: #1049
- Right-click on "My computer" > "System Properties", select "Hardware" tab, press "Hardware Wizard"
- Press "Next" > "Add/Troubleshoot a device" > "Add a new device"
- Select "No, I want to select the hardware from a list" > "Sound, video and game controllers"
- Select the following options and press "Next":
Hardware type: Sound, video and game cotrollers
Manufacturers: Creative Technology Ltd.
Models: Sound Blaster 16 or AWE32 or compatible (WDM)Windows Vista and newer
Installing using QEMU
- Run QEMU with the following settings for installation:
qemu-system-i386 -m 1024 -drive file=hdd.img,format=raw -cdrom InstallCD.isoOptionally add -accel kvm (for Linux host), -accel whpx (for Windows host) or -accel hvf (for MacOS host) to use hypervisor acceleration.
- Follow the setup instructions.
Running in v86
Enable ACPI and set the memory size to 512 MB or more.
Enabling networking (ne2k)
Source: https://phaq.phunsites.net/2007/05/21/vista-on-xen-using-ne2000-in-favor-to-rtl8139/
- Download https://phaq.phunsites.net/files/2007/05/drivercd.iso_.zip, unpack the archive, mount the ISO to the VM (
-cdrom path/to/drivercd.isoorchange ide1-cd0 path/to/drivercd.isoin QEMU Monitor), unpack the archive from CDROM into Windows. - Open Start Menu > "Control Panel" > "System" > "Device Manager"
- Right-click on "Ethernet Controller" > "Update Driver Software", press "Browse my computer for driver software".
- Click "Browse" and go to folder with unpacked driver, select
WIN2000folder, press "Install this driver software anyway".