V4:
- Rebased on the recent tree.
- Removed tcg-target-reg-bits.h as the 32bit support has been removed and
TCG_TARGET_REG_BITS is no longer needed.
- Renamed the tcg/wasm directory to tcg/wasm64, aligning with the names of
other backends.
- Added `scripts/run-emscripten.mjs` for quick testing of the Wasm-compiled
QEMU on Node.js in the terminal. Please see the "Running QEMU on Node.js"
section for usage
V3:
- Fixed init_wasm_js to correctly cast pointers to Numbers when passing the
arguments to the getInt32 and setInt32 methods.
- Lowered the the maximum number of instances (MAX_INSTANCES) to avoid the
out of memory error in recent versions of FireFox.
V2:
- Reorganized commits to implement the backend incrementally from a clean
state.
- Removed the andc, orc, eqv, nand and nor operations to rely on default
expansion.
- Removed the bswap operations to use default expansion.
- Removed the extract and deposit oprations to use default expansion.
- Updated the sextract to emit only when the corresponding Wasm instruction
is available
- Removed the not operation to rely on default expansion.
- Fixed the neg implementation to "ret = 0 - arg"
- Added Wasm implementation of the mb operation using the atomic.fence
instruction.
V1:
This patch series adds a TCG backend for WebAssembly. Unlike eariler
attempts [1], it is implemented using Emscripten's wasm64 target to support
64bit guests.
# New TCG Backend for Browsers
A new TCG backend translates IR instructions into Wasm instructions and runs
them using the browser's WebAssembly APIs (WebAssembly.Module and
WebAssembly.instantiate). To minimize compilation overhead and avoid hitting
the browser's limitation of the number of instances, this backend integrates
a forked TCI. TBs run on TCI by default, with frequently executed TBs
compiled into WebAssembly.
# Overview of build process
To compile QEMU with Emscripten, the following dependencies are required.
The emsdk-wasm-cross.docker environment includes all necessary components
and can be used as the build environment:
- Emscripten SDK (emsdk) v4.0.23
- Libraries cross-compiled with Emscripten (please see also
emsdk-wasm-cross.docker for build steps)
- GLib v2.84.0
- zlib v1.3.1
- libffi v3.5.2
- Pixman v0.44.2
The configure script supports --cpu=wasm64 flag to compile QEMU with 64bit
pointer support.
emconfigure ./configure --cpu=wasm64 \
--static --disable-tools \
--target-list=x86_64-softmmu
emmake make -j$(nproc)
If the output needs to run on wasm32 engines, use
"--enable-wasm64-32bit-address-limit" flag.
emconfigure ./configure --cpu=wasm64 --enable-wasm64-32bit-address-limit \
--static --disable-tools \
--target-list=x86_64-softmmu
emmake make -j$(nproc)
Either of the above commands generates the following files:
- qemu-system-x86_64.js
- qemu-system-x86_64.wasm
Guest images can be packaged using Emscripten's file_packager.py tool.
For example, if the images are stored in a directory named "pack", the
following command packages them, allowing QEMU to access them through
Emscripten's virtual filesystem:
/path/to/file_packager.py qemu-system-x86_64.data \
--preload pack --export-es6 > load.js
This process generates the following files:
- qemu-system-x86_64.data
- load.js
# Running QEMU on Node.js
The Wasm-compiled QEMU can run on Node.js using the `run-emscripten.mjs`
script.
node ./scripts/run-emscripten.mjs --preload ./load.js \
./qemu-system-x86_64.js -- \
-nographic -m 512M \
-L pack/ \
-drive if=virtio,format=raw,file=pack/rootfs.bin \
-kernel pack/bzImage \
-append "earlyprintk=ttyS0 console=ttyS0 root=/dev/vda loglevel=7"
Node.js 24 or newer is needed to run wasm64 binaries. Also note that QEMU's
"quit" monitor command doesn't work as of now because of the Emscripten's
atexit issue [3]. Send SIGINT or SIGTERM to the node process to exit QEMU.
# Running QEMU on browsers
On the browser envronment, emscripten allows passing arguments to the QEMU
command via the Module object in JavaScript:
Module['arguments'] = [
'-nographic', '-m', '512M',
'-L', 'pack/',
'-drive', 'if=virtio,format=raw,file=pack/rootfs.bin',
'-kernel', 'pack/bzImage',
'-append', 'earlyprintk=ttyS0 console=ttyS0 root=/dev/vda loglevel=7',
];
The sample repository [4] (tcgdev64 branch) provides a complete setup,
including an HTML file that implements a terminal UI.
[1] https://patchew.org/QEMU/[email protected]/
[2] https://patchew.org/QEMU/[email protected]/
[3] https://github.com/emscripten-core/emscripten/issues/26040
[4] https://github.com/ktock/qemu-wasm-sample/tree/tcgdev64
Kohei Tokunaga (33):
tcg/wasm64: Add tcg-target.h
tcg/wasm64: Add register-related definitions
tcg/wasm64: Add constraint definitions
tcg/wasm64: Add relocation callbacks
tcg/wasm64: Add and/or/xor instructions
tcg/wasm64: Add add/sub/mul instructions
tcg/wasm64: Add shl/shr/sar instructions
tcg/wasm64: Add setcond/negsetcond/movcond instructions
tcg/wasm64: Add sextract instruction
tcg/wasm64: Add load and store instructions
tcg/wasm64: Add mov/movi instructions
tcg/wasm64: Add ext instructions
tcg/wasm64: Add div/rem instructions
tcg/wasm64: Add neg/ctpop instructions
tcg/wasm64: Add rot/clz/ctz instructions
tcg/wasm64: Add br/brcond instructions
tcg/wasm64: Add exit_tb/goto_tb/goto_ptr instructions
tcg/wasm64: Add call instruction
tcg/wasm64: Add qemu_ld/qemu_st instructions
tcg/wasm64: Add mb instruction
tcg/wasm64: Mark unimplemented instructions
tcg/wasm64: Add initialization of fundamental registers
tcg/wasm64: Write wasm binary to TB
tcg/wasm64: Implement instantiation of Wasm binary
tcg/wasm64: Allow switching coroutine from a helper
tcg/wasm64: Enable instantiation of TBs executed many times
tcg/wasm64: Enable TLB lookup
tcg/wasm64: Add tcg_target_init function
meson.build: enable to build Wasm backend
meson.build: Propagate optimization flag for linking on Emscripten
.gitlab-ci.d: build wasm backend in CI
scripts: Add a script to run the wasm-compiled QEMU on node.js
emsdk-wasm-cross.docker: Bump up emsdk to 4.0.23
.gitlab-ci.d/buildtest.yml | 4 +-
MAINTAINERS | 7 +
configure | 8 +-
include/accel/tcg/getpc.h | 2 +-
include/tcg/helper-info.h | 4 +-
include/tcg/tcg.h | 2 +-
meson.build | 14 +-
meson_options.txt | 3 +
scripts/meson-buildoptions.sh | 5 +
scripts/run-emscripten.mjs | 66 +
tcg/aarch64/tcg-target.c.inc | 11 +
tcg/loongarch64/tcg-target.c.inc | 11 +
tcg/meson.build | 5 +
tcg/mips64/tcg-target.c.inc | 11 +
tcg/ppc64/tcg-target.c.inc | 11 +
tcg/region.c | 10 +-
tcg/riscv64/tcg-target.c.inc | 11 +
tcg/s390x/tcg-target.c.inc | 11 +
tcg/sparc64/tcg-target.c.inc | 11 +
tcg/tcg-op-ldst.c | 2 +-
tcg/tcg.c | 21 +-
tcg/tci/tcg-target.c.inc | 11 +
tcg/wasm64.c | 861 +++++
tcg/wasm64.h | 117 +
tcg/wasm64/tcg-target-con-set.h | 19 +
tcg/wasm64/tcg-target-con-str.h | 14 +
tcg/wasm64/tcg-target-has.h | 14 +
tcg/wasm64/tcg-target-mo.h | 20 +
tcg/wasm64/tcg-target-opc.h.inc | 20 +
tcg/wasm64/tcg-target.c.inc | 2853 +++++++++++++++++
tcg/wasm64/tcg-target.h | 61 +
tcg/x86_64/tcg-target.c.inc | 11 +
.../dockerfiles/emsdk-wasm-cross.docker | 2 +-
33 files changed, 4204 insertions(+), 29 deletions(-)
create mode 100644 scripts/run-emscripten.mjs
create mode 100644 tcg/wasm64.c
create mode 100644 tcg/wasm64.h
create mode 100644 tcg/wasm64/tcg-target-con-set.h
create mode 100644 tcg/wasm64/tcg-target-con-str.h
create mode 100644 tcg/wasm64/tcg-target-has.h
create mode 100644 tcg/wasm64/tcg-target-mo.h
create mode 100644 tcg/wasm64/tcg-target-opc.h.inc
create mode 100644 tcg/wasm64/tcg-target.c.inc
create mode 100644 tcg/wasm64/tcg-target.h
--
2.43.0