From ac10a681d44665df56bf7f35660719b29654119d Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Fri, 11 Jul 2025 20:28:33 +0900 Subject: [PATCH 1/4] meson: Add wasm64 support to the --cpu flag wasm64 target enables 64bit pointers using Emscripten's -sMEMORY64=1 flag[1]. This enables QEMU to run 64bit guests. Although the configure script uses "uname -m" as the fallback value when "cpu" is empty, this can't be used for Emscripten which targets to Wasm. So, in wasm build, this commit fixes configure to require --cpu flag to be explicitly specified by the user. [1] https://emscripten.org/docs/tools_reference/settings_reference.html#memory64 Signed-off-by: Kohei Tokunaga --- configure | 6 +++++- meson.build | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 825057ebf1551..7f3893a42f21e 100755 --- a/configure +++ b/configure @@ -365,7 +365,6 @@ elif check_define __APPLE__; then host_os=darwin elif check_define EMSCRIPTEN ; then host_os=emscripten - cpu=wasm32 cross_compile="yes" else # This is a fatal error, but don't report it yet, because we @@ -425,6 +424,8 @@ elif check_define __aarch64__ ; then cpu="aarch64" elif check_define __loongarch64 ; then cpu="loongarch64" +elif check_define EMSCRIPTEN ; then + error_exit "wasm32 or wasm64 must be specified to the cpu flag" else # Using uname is really broken, but it is just a fallback for architectures # that are going to use TCI anyway @@ -535,6 +536,9 @@ case "$cpu" in wasm32) CPU_CFLAGS="-m32" ;; + wasm64) + CPU_CFLAGS="-m64 -sMEMORY64=1" + ;; esac if test -n "$host_arch" && { diff --git a/meson.build b/meson.build index e53cd5b413847..291fe3f0d0320 100644 --- a/meson.build +++ b/meson.build @@ -52,7 +52,7 @@ qapi_trace_events = [] bsd_oses = ['gnu/kfreebsd', 'freebsd', 'netbsd', 'openbsd', 'dragonfly', 'darwin'] supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux', 'emscripten'] supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64', - 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64', 'wasm32'] + 'arm', 'aarch64', 'loongarch64', 'mips', 'mips64', 'sparc64', 'wasm32', 'wasm64'] cpu = host_machine.cpu_family() @@ -916,7 +916,7 @@ if have_tcg if not get_option('tcg_interpreter') error('Unsupported CPU @0@, try --enable-tcg-interpreter'.format(cpu)) endif - elif host_arch == 'wasm32' + elif host_arch == 'wasm32' or host_arch == 'wasm64' if not get_option('tcg_interpreter') error('WebAssembly host requires --enable-tcg-interpreter') endif From 9b33355d68c9398990a997ea1b7b9fb552ed562c Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Sat, 12 Jul 2025 14:38:35 +0900 Subject: [PATCH 2/4] configure: Enable to propagate -sMEMORY64 flag to Emscripten Currently there are some engines that don't support wasm64 (e.g. unsupported on Safari[1]). To mitigate this issue, the configure script allows the user to use Emscripten's compatibility feature, "-sMEMORY64=2" flag[2]. Emscripten's "-sMEMORY64=2" flag still enables 64bit pointers in C code. But this flag lowers the output binary into wasm32, with limiting the maximum memory size to 4GB. So QEMU can run on wasm32 engines. This commit adds a flag in the configure script to enable "-sMEMORY64=2" mode. [1] https://webassembly.org/features/ [2] https://emscripten.org/docs/tools_reference/settings_reference.html#memory64 Signed-off-by: Kohei Tokunaga --- configure | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 7f3893a42f21e..0587577da985d 100755 --- a/configure +++ b/configure @@ -182,6 +182,10 @@ EXTRA_CXXFLAGS="" EXTRA_OBJCFLAGS="" EXTRA_LDFLAGS="" +# The value is propagated to Emscripten's "-sMEMORY64" flag. +# https://emscripten.org/docs/tools_reference/settings_reference.html#memory64 +wasm64_memory64=1 + # Default value for a variable defining feature "foo". # * foo="no" feature will only be used if --enable-foo arg is given # * foo="" feature will be searched for, and if found, will be used @@ -239,6 +243,8 @@ for opt do ;; --without-default-features) default_feature="no" ;; + --wasm64-32bit-address-limit) wasm64_memory64="2" + ;; esac done @@ -537,7 +543,7 @@ case "$cpu" in CPU_CFLAGS="-m32" ;; wasm64) - CPU_CFLAGS="-m64 -sMEMORY64=1" + CPU_CFLAGS="-m64 -sMEMORY64=$wasm64_memory64" ;; esac @@ -795,6 +801,8 @@ for opt do ;; --disable-rust) rust=disabled ;; + --wasm64-32bit-address-limit) + ;; # everything else has the same name in configure and meson --*) meson_option_parse "$opt" "$optarg" ;; @@ -920,6 +928,8 @@ Advanced options (experts only): --disable-containers don't use containers for cross-building --container-engine=TYPE which container engine to use [$container_engine] --gdb=GDB-path gdb to use for gdbstub tests [$gdb_bin] + --wasm64-32bit-address-limit Restrict wasm64 address space to 32-bit (default + is to use the whole 64-bit range). EOF meson_options_help cat << EOF From 491206c94d5ff531486f5dda4ec3c545603997d6 Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Fri, 11 Jul 2025 20:32:18 +0900 Subject: [PATCH 3/4] dockerfiles: Add support for wasm64 to the wasm Dockerfile This commit fixes Dockerfile of the wasm build to support both of wasm32 and wasm64 build. Dockerfile takes the following build arguments and use these values for building dependencies. - TARGET_CPU: target wasm arch (wasm32 or wasm64) - WASM64_MEMORY64: target -sMEMORY64 mode (1 or 2) Signed-off-by: Kohei Tokunaga --- MAINTAINERS | 2 +- ...2-cross.docker => emsdk-wasm-cross.docker} | 29 ++++++++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) rename tests/docker/dockerfiles/{emsdk-wasm32-cross.docker => emsdk-wasm-cross.docker} (85%) diff --git a/MAINTAINERS b/MAINTAINERS index 28cea342718db..47b35bae47e5c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -647,7 +647,7 @@ F: include/system/os-wasm.h F: os-wasm.c F: util/coroutine-wasm.c F: configs/meson/emscripten.txt -F: tests/docker/dockerfiles/emsdk-wasm32-cross.docker +F: tests/docker/dockerfiles/emsdk-wasm-cross.docker Alpha Machines -------------- diff --git a/tests/docker/dockerfiles/emsdk-wasm32-cross.docker b/tests/docker/dockerfiles/emsdk-wasm-cross.docker similarity index 85% rename from tests/docker/dockerfiles/emsdk-wasm32-cross.docker rename to tests/docker/dockerfiles/emsdk-wasm-cross.docker index 60a7d02f5613e..4b41be62ab864 100644 --- a/tests/docker/dockerfiles/emsdk-wasm32-cross.docker +++ b/tests/docker/dockerfiles/emsdk-wasm-cross.docker @@ -1,14 +1,17 @@ # syntax = docker/dockerfile:1.5 -ARG EMSDK_VERSION_QEMU=3.1.50 +ARG EMSDK_VERSION_QEMU=4.0.10 ARG ZLIB_VERSION=1.3.1 ARG GLIB_MINOR_VERSION=2.84 ARG GLIB_VERSION=${GLIB_MINOR_VERSION}.0 ARG PIXMAN_VERSION=0.44.2 -ARG FFI_VERSION=v3.4.7 +ARG FFI_VERSION=v3.5.2 ARG MESON_VERSION=1.5.0 +ARG TARGET_CPU=wasm32 +ARG WASM64_MEMORY64=0 -FROM emscripten/emsdk:$EMSDK_VERSION_QEMU AS build-base +FROM emscripten/emsdk:$EMSDK_VERSION_QEMU AS build-base-common +ARG TARGET_CPU ARG MESON_VERSION ENV TARGET=/builddeps/target ENV CPATH="$TARGET/include" @@ -33,8 +36,8 @@ RUN < /cross.meson [host_machine] system = 'emscripten' -cpu_family = 'wasm32' -cpu = 'wasm32' +cpu_family = '${TARGET_CPU}' +cpu = '${TARGET_CPU}' endian = 'little' [binaries] @@ -46,6 +49,16 @@ pkgconfig = ['pkg-config', '--static'] EOT EOF +FROM build-base-common AS build-base-wasm32 + +FROM build-base-common AS build-base-wasm64 +ARG WASM64_MEMORY64 +ENV CFLAGS="$CFLAGS -sMEMORY64=${WASM64_MEMORY64}" +ENV CXXFLAGS="$CXXFLAGS -sMEMORY64=${WASM64_MEMORY64}" +ENV LDFLAGS="$LDFLAGS -sMEMORY64=${WASM64_MEMORY64}" + +FROM build-base-${TARGET_CPU} AS build-base + FROM build-base AS zlib-dev ARG ZLIB_VERSION RUN mkdir -p /zlib @@ -56,17 +69,19 @@ RUN emconfigure ./configure --prefix=$TARGET --static RUN emmake make install -j$(nproc) FROM build-base AS libffi-dev +ARG TARGET_CPU +ARG WASM64_MEMORY64 ARG FFI_VERSION RUN mkdir -p /libffi RUN git clone https://github.com/libffi/libffi /libffi WORKDIR /libffi RUN git checkout $FFI_VERSION RUN autoreconf -fiv -RUN emconfigure ./configure --host=wasm32-unknown-linux \ +RUN emconfigure ./configure --host=${TARGET_CPU}-unknown-linux \ --prefix=$TARGET --enable-static \ --disable-shared --disable-dependency-tracking \ --disable-builddir --disable-multi-os-directory \ - --disable-raw-api --disable-docs + --disable-raw-api --disable-docs WASM64_MEMORY64=${WASM64_MEMORY64} RUN emmake make install SUBDIRS='include' -j$(nproc) FROM build-base AS pixman-dev From bccf41ff6b55e5d7277137ae825ab1650e204c19 Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Fri, 11 Jul 2025 20:33:16 +0900 Subject: [PATCH 4/4] .gitlab-ci.d: Add build tests for wasm64 The wasm builds are tested for 3 targets: wasm32, wasm64(-sMEMORY64=1) and wasm64(-sMEMORY64=2). The CI builds the containers using the same Dockerfile (emsdk-wasm-cross.docker) with different build args. Signed-off-by: Kohei Tokunaga --- .gitlab-ci.d/buildtest.yml | 24 +++++++++++++++++++++--- .gitlab-ci.d/container-cross.yml | 18 +++++++++++++++++- .gitlab-ci.d/container-template.yml | 4 +++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index d888a60063715..0dded0418807b 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -787,11 +787,29 @@ coverity: # Always manual on forks even if $QEMU_CI == "2" - when: manual -build-wasm: +build-wasm32: extends: .wasm_build_job_template timeout: 2h needs: - job: wasm-emsdk-cross-container + job: wasm32-emsdk-cross-container variables: IMAGE: emsdk-wasm32-cross - CONFIGURE_ARGS: --static --disable-tools --enable-debug --enable-tcg-interpreter + CONFIGURE_ARGS: --static --cpu=wasm32 --disable-tools --enable-debug --enable-tcg-interpreter + +build-wasm-wasm64: + extends: .wasm_build_job_template + timeout: 2h + needs: + job: wasm64-emsdk-cross-container + variables: + IMAGE: emsdk-wasm64-cross + CONFIGURE_ARGS: --static --cpu=wasm64 --disable-tools --enable-debug --enable-tcg-interpreter + +build-wasm-wasm64l: + extends: .wasm_build_job_template + timeout: 2h + needs: + job: wasm64l-emsdk-cross-container + variables: + IMAGE: emsdk-wasm64l-cross + CONFIGURE_ARGS: --static --cpu=wasm64 --wasm64-32bit-address-limit --disable-tools --enable-debug --enable-tcg-interpreter diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml index 8d3be53b75b23..1bacaff8188d7 100644 --- a/.gitlab-ci.d/container-cross.yml +++ b/.gitlab-ci.d/container-cross.yml @@ -92,7 +92,23 @@ win64-fedora-cross-container: variables: NAME: fedora-win64-cross -wasm-emsdk-cross-container: +wasm32-emsdk-cross-container: extends: .container_job_template variables: NAME: emsdk-wasm32-cross + BUILD_ARGS: --build-arg TARGET_CPU=wasm32 + DOCKERFILE: emsdk-wasm-cross + +wasm64-emsdk-cross-container: + extends: .container_job_template + variables: + NAME: emsdk-wasm64-cross + BUILD_ARGS: --build-arg TARGET_CPU=wasm64 --build-arg WASM64_MEMORY64=1 + DOCKERFILE: emsdk-wasm-cross + +wasm64l-emsdk-cross-container: + extends: .container_job_template + variables: + NAME: emsdk-wasm64l-cross + BUILD_ARGS: --build-arg TARGET_CPU=wasm64 --build-arg WASM64_MEMORY64=2 + DOCKERFILE: emsdk-wasm-cross diff --git a/.gitlab-ci.d/container-template.yml b/.gitlab-ci.d/container-template.yml index 4eec72f383dd7..01ca8404136fb 100644 --- a/.gitlab-ci.d/container-template.yml +++ b/.gitlab-ci.d/container-template.yml @@ -10,12 +10,14 @@ - export COMMON_TAG="$CI_REGISTRY/qemu-project/qemu/qemu/$NAME:latest" - docker login $CI_REGISTRY -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" - until docker info; do sleep 1; done + - export DOCKERFILE_NAME=${DOCKERFILE:-$NAME} script: - echo "TAG:$TAG" - echo "COMMON_TAG:$COMMON_TAG" - docker build --tag "$TAG" --cache-from "$TAG" --cache-from "$COMMON_TAG" --build-arg BUILDKIT_INLINE_CACHE=1 - -f "tests/docker/dockerfiles/$NAME.docker" "." + $BUILD_ARGS + -f "tests/docker/dockerfiles/$DOCKERFILE_NAME.docker" "." - docker push "$TAG" after_script: - docker logout