.gitlab-ci.d/buildtest.yml | 24 +++++++++++++--
.gitlab-ci.d/container-cross.yml | 18 +++++++++++-
.gitlab-ci.d/container-template.yml | 4 ++-
MAINTAINERS | 2 +-
configure | 14 ++++++++-
meson.build | 4 +--
...2-cross.docker => emsdk-wasm-cross.docker} | 29 ++++++++++++++-----
7 files changed, 79 insertions(+), 16 deletions(-)
rename tests/docker/dockerfiles/{emsdk-wasm32-cross.docker => emsdk-wasm-cross.docker} (85%)
This patch series enables the TCI of the Wasm build to run 64bit
guests. Unlike the previous series[1], this patch series is implemented by
adding support for WebAssembly's "wasm64" target which enables 64bit
pointers.
In the previous discussion[2], the main challenge of using wasm64 was its
limited adoption, particularly the lack of support in our dependency
(libffi) and some engines such as Safari.
For libffi, I've completed the addition of wasm64 support upstream[3] so it
can be used.
To support wasm32 engines, this patch uses Emscripten's compatibility
feature, -sMEMORY64=2 flag[4]. This flag still enables 64bit pointers in the
C code while Emscripten lowers the output binary to wasm32 and limits the
maximum memory size to 4GB. As a result, QEMU can run on wasm32 engiens
while still supporting 64bit guests.
# Overview of the 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.10
- 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 \
--enable-tcg-interpreter
emmake make -j$(nproc)
If the output needs to run on wasm32 engines, use --wasm64-memory64=2
flag. This flag propagates the value to Emscripten's -sMEMORY64 flag[4].
emconfigure ./configure --cpu=wasm64 --wasm64-memory64=2 \
--static --disable-tools \
--target-list=x86_64-softmmu \
--enable-tcg-interpreter
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 > load.js
This process generates the following files:
- qemu-system-x86_64.data
- load.js
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[5] (tcidev64 branch) provides a complete setup,
including an HTML file that implements a terminal UI.
[1] https://lists.nongnu.org/archive/html/qemu-devel/2025-05/msg05376.html
[2] https://lists.nongnu.org/archive/html/qemu-devel/2025-04/msg01795.html
[3] https://github.com/libffi/libffi/pull/927
[4] https://emscripten.org/docs/tools_reference/settings_reference.html#memory64
[5] https://github.com/ktock/qemu-wasm-sample/tree/tcidev64
Kohei Tokunaga (4):
meson: Add wasm64 support to the --cpu flag
configure: Enable to propagate -sMEMORY64 flag to Emscripten
dockerfiles: Add support for wasm64 to the wasm Dockerfile
.gitlab-ci.d: Add build tests for wasm64
.gitlab-ci.d/buildtest.yml | 24 +++++++++++++--
.gitlab-ci.d/container-cross.yml | 18 +++++++++++-
.gitlab-ci.d/container-template.yml | 4 ++-
MAINTAINERS | 2 +-
configure | 14 ++++++++-
meson.build | 4 +--
...2-cross.docker => emsdk-wasm-cross.docker} | 29 ++++++++++++++-----
7 files changed, 79 insertions(+), 16 deletions(-)
rename tests/docker/dockerfiles/{emsdk-wasm32-cross.docker => emsdk-wasm-cross.docker} (85%)
--
2.43.0
On 8/4/25 5:57 AM, Kohei Tokunaga wrote:
> This patch series enables the TCI of the Wasm build to run 64bit
> guests. Unlike the previous series[1], this patch series is implemented by
> adding support for WebAssembly's "wasm64" target which enables 64bit
> pointers.
>
> In the previous discussion[2], the main challenge of using wasm64 was its
> limited adoption, particularly the lack of support in our dependency
> (libffi) and some engines such as Safari.
>
> For libffi, I've completed the addition of wasm64 support upstream[3] so it
> can be used.
>
> To support wasm32 engines, this patch uses Emscripten's compatibility
> feature, -sMEMORY64=2 flag[4]. This flag still enables 64bit pointers in the
> C code while Emscripten lowers the output binary to wasm32 and limits the
> maximum memory size to 4GB. As a result, QEMU can run on wasm32 engiens
> while still supporting 64bit guests.
>
> # Overview of the 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.10
> - 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 \
> --enable-tcg-interpreter
> emmake make -j$(nproc)
>
> If the output needs to run on wasm32 engines, use --wasm64-memory64=2
> flag. This flag propagates the value to Emscripten's -sMEMORY64 flag[4].
>
> emconfigure ./configure --cpu=wasm64 --wasm64-memory64=2 \
> --static --disable-tools \
> --target-list=x86_64-softmmu \
> --enable-tcg-interpreter
> 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 > load.js
>
> This process generates the following files:
>
> - qemu-system-x86_64.data
> - load.js
>
> 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[5] (tcidev64 branch) provides a complete setup,
> including an HTML file that implements a terminal UI.
>
> [1] https://lists.nongnu.org/archive/html/qemu-devel/2025-05/msg05376.html
> [2] https://lists.nongnu.org/archive/html/qemu-devel/2025-04/msg01795.html
> [3] https://github.com/libffi/libffi/pull/927
> [4] https://emscripten.org/docs/tools_reference/settings_reference.html#memory64
> [5] https://github.com/ktock/qemu-wasm-sample/tree/tcidev64
>
> Kohei Tokunaga (4):
> meson: Add wasm64 support to the --cpu flag
> configure: Enable to propagate -sMEMORY64 flag to Emscripten
> dockerfiles: Add support for wasm64 to the wasm Dockerfile
> .gitlab-ci.d: Add build tests for wasm64
>
> .gitlab-ci.d/buildtest.yml | 24 +++++++++++++--
> .gitlab-ci.d/container-cross.yml | 18 +++++++++++-
> .gitlab-ci.d/container-template.yml | 4 ++-
> MAINTAINERS | 2 +-
> configure | 14 ++++++++-
> meson.build | 4 +--
> ...2-cross.docker => emsdk-wasm-cross.docker} | 29 ++++++++++++++-----
> 7 files changed, 79 insertions(+), 16 deletions(-)
> rename tests/docker/dockerfiles/{emsdk-wasm32-cross.docker => emsdk-wasm-cross.docker} (85%)
>
Excellent, thanks for adding this.
Out of curiosity, and out of the scope of this PR, would that be
possible to make a "universal" build, which can selectively select the
appropriate wasm64 support at runtime, so a single build works on all
browsers out of the box?
As well, what are the limitations of -sMEMORY64 regarding limited
address space? Is it just the maximum size of memory a guest can have,
or does it limit the VA that can be accessed also?
Thanks,
Pierrick
Hi Pierrick, thanks for your review. > Excellent, thanks for adding this. > > Out of curiosity, and out of the scope of this PR, would that be > possible to make a "universal" build, which can selectively select the > appropriate wasm64 support at runtime, so a single build works on all > browsers out of the box? I haven't found an Emscripten feature for the universal build but a possible approach would be to compile both variants (-sMEMORY64=1 and 2) and provide a wrapper JS script that selects one at runtime depending on the engine's pointer size. If the user can accept the 4GB memory size limit, -sMEMORY64=2 can be used as a universal binary as it runs on wasm32 engines. > As well, what are the limitations of -sMEMORY64 regarding limited > address space? Is it just the maximum size of memory a guest can have, > or does it limit the VA that can be accessed also? -sMEMORY64=2 limits the maximum memory size a guest can use but still enables 64bit pointers so TCI is compiled with TCG_TARGET_REG_BITS=64 without restricting the guest's virtual address space. Regards, Kohei
© 2016 - 2025 Red Hat, Inc.