diff --git a/.clang-format b/.clang-format index b10603d..ac1edc7 100644 --- a/.clang-format +++ b/.clang-format @@ -67,4 +67,4 @@ UseTab: ForIndentation PenaltyBreakAssignment: 100 PenaltyBreakBeforeFirstCallParameter: 1000 -PenaltyReturnTypeOnItsOwnLine: 0 \ No newline at end of file +PenaltyReturnTypeOnItsOwnLine: 0 diff --git a/.editorconfig b/.editorconfig index 513d11a..266e01b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,12 @@ # top-most EditorConfig file root = true +[.clang-format] +ignore = true + +[*.yaml] +ignore = true + # Unix-style newlines with a newline ending every file [*] end_of_line = lf diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index a66d3e3..c0e6951 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -3,8 +3,9 @@ name: sledge on: [push, pull_request] env: - LLVM_VERSION: 8 - WASMCEPTION_URL: https://github.com/gwsystems/wasmception/releases/download/v0.2.0/wasmception-linux-x86_64-0.2.0.tar.gz + LLVM_VERSION: 13 + WASI_SDK_URL: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz + WASI_SDK_PATH: /opt/wasi-sdk LANG: C.UTF-8 LANGUAGE: C.UTF-8 LC_ALL: C.UTF-8 @@ -14,13 +15,12 @@ jobs: format: runs-on: ubuntu-latest steps: + - name: Apt Update + run: sudo apt-get update - uses: actions/checkout@v2 - - name: Install clang-format-11 - run: | - sudo apt-get remove -y --no-install-recommends clang-format-10 && sudo apt-get install -y --no-install-recommends clang-format-11 - - name: Update alternatives + - name: Install LLVM run: | - sudo update-alternatives --remove-all clang-format && sudo update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-11" 100 + sudo ./install_llvm.sh $LLVM_VERSION - name: Clang Format run: ./format.sh -d test: @@ -60,6 +60,11 @@ jobs: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \ sh -s -- --default-toolchain stable --component rustfmt --target wasm32-wasi -y echo "/root/.cargo/bin:$PATH" >> $GITHUB_PATH + - name: Get wasi-sdk + run: | + wget $WASI_SDK_URL -O wasi-sdk.tar.gz + mkdir -p $WASI_SDK_PATH + tar xvfz wasi-sdk.tar.gz --strip-components=1 -C $WASI_SDK_PATH - name: Install Test Script Utilities run: | sudo apt-get install -y --no-install-recommends \ @@ -79,30 +84,26 @@ jobs: ~/.cargo/git ./awsm/target key: ${{ runner.os }}-cargo-${{ hashFiles('./awsm/Cargo.lock') }} - - name: Compile sledge - run: | - make build - make rtinit - mkdir bin - mkdir lib - SYS_PREFIX="$(pwd)" ./install.sh - PATH="$(pwd)/bin:$PATH" - echo "$PATH" >> $GITHUB_PATH - LD_LIBRARY_PATH="$(pwd)/lib:$LD_LIBRARY_PATH" - echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> $GITHUB_ENV - make build-validate + - name: Compile aWsm + run: | + make awsm - name: Compile libsledge run: | make libsledge + - name: Compile SLEdge + run: | + make runtime # TODO:Cache assets before being copied to ./runtime/bin - name: Cache gocr uses: actions/cache@v2 with: path: ./runtime/bin/gocr.wasm.so - key: ${{ runner.os }}-gocr2-${{ hashFiles('./applications/Makefile', './applications/wasmception_apps/gocr/**', './runtime/compiletime/**') }} + key: ${{ runner.os }}-gocr2-${{ hashFiles('./applications/Makefile', './applications/wasm_apps/gocr/**', './libsledge/Makefile' , './libsledge/src/**', './libsledge/include/**') }} if: success() || failure() - name: Hyde run: | + echo $WASI_SDK_PATH + ls $WASI_SDK_PATH make -f test.mk gocr__hyde if: success() || failure() - name: Upload Hyde Logs on Failure @@ -136,7 +137,7 @@ jobs: uses: actions/cache@v2 with: path: ./runtime/bin/gps_ekf.wasm.so - key: ${{ runner.os }}-gocr2-${{ hashFiles('./applications/Makefile', './applications/wasmception_apps/TinyEKF/**', './runtime/compiletime/**') }} + key: ${{ runner.os }}-gocr2-${{ hashFiles('./applications/Makefile', './applications/wasm_apps/TinyEKF/**', './libsledge/Makefile' , './libsledge/src/**', './libsledge/include/**') }} if: success() || failure() - name: EKF one iteration run: | diff --git a/.gitmodules b/.gitmodules index ba212eb..52ba595 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,6 +2,7 @@ path = awsm url = https://github.com/gwsystems/aWsm ignore = dirty +branch = sledge-compat [submodule "http-parser"] path = runtime/thirdparty/http-parser url = https://github.com/gwsystems/http-parser.git @@ -11,23 +12,7 @@ url = https://github.com/gwsystems/ck.git [submodule "jsmn"] path = runtime/thirdparty/jsmn url = https://github.com/gwsystems/jsmn.git -[submodule "runtime/tests/gocr"] - path = applications/wasmception_apps/gocr -url = https://github.com/gwsystems/gocr.git -branch = sledge -[submodule "runtime/tests/TinyEKF"] - path = applications/wasmception_apps/TinyEKF -url = https://github.com/gwsystems/TinyEKF.git -branch = sledge -[submodule "runtime/tests/CMSIS_5_NN"] - path = applications/wasmception_apps/CMSIS_5_NN -url = https://github.com/gwsystems/CMSIS_5_NN.git -branch = sledge -[submodule "runtime/tests/sod"] - path = applications/wasmception_apps/sod -url = https://github.com/gwsystems/sod.git -branch = sledge -[submodule "runtime/tests/speechtotext"] - path = applications/wasmception_apps/speechtotext -url = https://github.com/gwsystems/speechtotext.git -branch = sledge +[submodule "wasm_apps"] + path = applications/wasm_apps + url = https://github.com/gwsystems/wasm_apps.git + branch = master diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 451e4d2..e5acd78 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -9,6 +9,7 @@ "${workspaceFolder}/runtime/thirdparty/ck/include/", "${workspaceFolder}/runtime/thirdparty/http-parser/", "${workspaceFolder}/runtime/thirdparty/jsmn/", + "${workspaceFolder}/awsm/runtime/libc/wasi/include/", "${workspaceFolder}/libsledge/include" ], "defines": [ diff --git a/.vscode/settings.json b/.vscode/settings.json index d57a189..5710bac 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -81,7 +81,6 @@ "sandbox_set_as_complete.h": "c", "deque.h": "c", "sandbox_send_response.h": "c", - "sandbox_setup_arguments.h": "c", "worker_thread.h": "c", "sandbox_set_as_error.h": "c", "likely.h": "c", @@ -90,6 +89,9 @@ "sandbox_set_as_running.h": "c", "sandbox_summarize_page_allocations.h": "c", "wasm_types.h": "c", + "wasi_impl.h": "c", + "wasi_backing.h": "c", + "wasi_serdes.h": "c", "atomic": "c", "sandbox_set_as_running_kernel.h": "c", "stdbool.h": "c", @@ -104,7 +106,10 @@ "wasm_module_instance.h": "c", "wasm_stack.h": "c", "wasm_table.h": "c", - "sledge_abi.h": "c" + "wasi_spec.h": "c", + "current_wasm_module_instance.h": "c", + "wasm_memory.h": "c", + "sledge_abi.h": "c", }, "files.exclude": { "**/.git": true, @@ -127,10 +132,12 @@ ], "shellformat.path": "/usr/local/bin/shfmt", "shellformat.flag": "-ln=bash -i 0 -bn -ci -sr -kp", - "terminal.integrated.shell.linux": "bash", "[jsonc]": { "editor.defaultFormatter": "vscode.json-language-features" }, + "[yaml]": { + "editor.formatOnSave": false, + }, "[json]": { "editor.defaultFormatter": "vscode.json-language-features" }, @@ -156,5 +163,12 @@ "*.o": true, "*.bc": true, "*.wasm": true, - } + }, + "C_Cpp.formatting": "clangFormat", + "cSpell.words": [ + "gregs", + "mctx", + "TKILL", + "WASI" + ] } diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index 8dcd749..06a0cf2 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -50,4 +50,6 @@ RUN rustup target add wasm32-wasi RUN cargo install --debug cargo-audit cargo-watch rsign2 -ENV PATH=/opt/sledge/bin:$PATH +ENV PATH=/sledge/runtime/bin:$PATH +ENV PATH=/sledge/awsm/target/release:$PATH +ENV LD_LIBRARY_PATH=/sledge/runtime/bin:$LD_LIBRARY_PATH diff --git a/Dockerfile.x86_64 b/Dockerfile.x86_64 index 0d3b9af..b419363 100644 --- a/Dockerfile.x86_64 +++ b/Dockerfile.x86_64 @@ -3,7 +3,7 @@ FROM ubuntu:focal ARG DEBIAN_FRONTEND=noninteractive ARG HEY_URL=https://hey-release.s3.us-east-2.amazonaws.com/hey_linux_amd64 -ARG WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-8/wasi-sdk_8.0_amd64.deb +ARG WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk_12.0_amd64.deb ARG SHFMT_URL=https://github.com/mvdan/sh/releases/download/v3.2.4/shfmt_v3.2.4_linux_amd64 ARG SHELLCHECK_URL=https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.x86_64.tar.xz @@ -74,14 +74,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ vim \ wabt -ENV LLVM_VERSION=8 +ENV LLVM_VERSION=12 ADD install_llvm.sh /sledge/install_llvm.sh RUN ./sledge/install_llvm.sh $LLVM_VERSION # WASI-SDK -# TODO: Refactor to output as an arch-neutral filename -# RUN curl -sS -L -O $WASI_SDK_URL && dpkg -i wasi-sdk_8.0_amd64.deb && rm -f wasi-sdk_8.0_amd64.deb -# ENV WASI_SDK=/opt/wasi-sdk +RUN curl -sS -L -O $WASI_SDK_URL && dpkg -i wasi-sdk_12.0_amd64.deb && rm -f wasi-sdk_12.0_amd64.deb +ENV WASI_SDK=/opt/wasi-sdk # Create non-root user and add to sudoers ARG USERNAME=dev @@ -100,8 +99,6 @@ USER $USER_UID RUN sudo chown $USER_GID:$USER_GID /sledge ADD fix_root.sh /sledge/fix_root.sh RUN cd sledge && ./fix_root.sh -RUN sudo mkdir /opt/sledge -RUN sudo chown $USER_GID:$USER_GID /opt/sledge ################################ # Final Setup as non-root user # @@ -119,8 +116,6 @@ ENV LANGUAGE C.UTF-8 ENV LC_ALL C.UTF-8 # Update PATH and LD_LIBRARY_PATH -ENV PATH=/opt/sledge/bin:$PATH - -# TODO: Does the build process for the sample applications actually copy here? -# TODO: Should we create a special SLEDGE_MODULE_PATH that is searched for these modules? -ENV LD_LIBRARY_PATH=/opt/sledge/bin:$LD_LIBRARY_PATH +ENV PATH=/sledge/runtime/bin:$PATH +ENV PATH=/sledge/awsm/target/release:$PATH +ENV LD_LIBRARY_PATH=/sledge/runtime/bin:$LD_LIBRARY_PATH diff --git a/Makefile b/Makefile index 9c41637..0e96515 100644 --- a/Makefile +++ b/Makefile @@ -1,57 +1,56 @@ SHELL:=/bin/bash -ARCH:=$(shell arch) - -COMPILER=awsm -ROOT=${ROOT:-$(cd "$(dirname ${BASH_SOURCE:-$0})" && pwd)} -WASMCEPTION_URL=https://github.com/gwsystems/wasmception/releases/download/v0.2.0/wasmception-linux-x86_64-0.2.0.tar.gz - -# TODO: Add ARM release build -.PHONY: build -build: -ifeq ($(ARCH),x86_64) - cd ./awsm/wasmception && wget ${WASMCEPTION_URL} -O wasmception.tar.gz && tar xvfz wasmception.tar.gz && rm wasmception.tar.gz -endif - test -f ./${COMPILER}/wasmception/dist/bin/clang || make -C ${COMPILER}/wasmception - @cd ${COMPILER} && RUSTUP_TOOLCHAIN=stable cargo build --release && cd ${ROOT} - -# Sanity check that the aWsm compiler built and is in our PATH -.PHONY: build-validate -build-validate: - which awsm - awsm --version - -.PHONY: build-dev -build-dev: - test -f ./${COMPILER}/wasmception/dist/bin/clang || make -C ${COMPILER}/wasmception - @echo "Building aWsm compiler (default==debug)" - @cd ${COMPILER} && cargo build && cd ${ROOT} + +.PHONY: all +all: awsm libsledge runtime .PHONY: clean -clean: - @echo "Cleaning aWsm compiler" - @cd ${COMPILER} && cargo clean && cd ${ROOT} - -# wasmception is too slow to recompile, -# so lets not make that part of the "aWsm" cleanup -.PHONY: wclean -wclean: - @echo "Cleaning wasmception toolchain" - @cd ${COMPILER} && make -C wasmception clean && cd ${ROOT} - -.PHONY: rtinit -rtinit: - @echo "Building runtime for the first time!" - make -C runtime init +clean: awsm.clean libsledge.clean runtime.clean -.PHONY: runtime -runtime: - @echo "Building runtime!" - make -C runtime +.PHONY: submodules +submodules: + git submodule update --init --recursive .PHONY: install -install: build rtinit - @./install.sh wasmception +install: submodules all +# aWsm: the WebAssembly to LLVM bitcode compiler +.PHONY: awsm +awsm: + cd awsm && cargo build --release + +.PHONY: awsm.clean +awsm.clean: + cd awsm && cargo clean + +# libsledge: the support library linked with LLVM bitcode emitted by aWsm when building *.so modules .PHONY: libsledge libsledge: - make -C libsledge clean all + make -C libsledge dist/libsledge.a + +.PHONY: libsledge.clean +libsledge.clean: + make -C libsledge clean + +# sledgert: the runtime that executes *.so modules +.PHONY: runtime +runtime: + make -C runtime + + +.PHONY: runtime.clean +runtime.clean: + make -C runtime clean + +# SLEdge Applications +.PHONY: applications +applications: + make -C applications all + +.PHONY: applications.clean +applications.clean: + make -C applications clean + +# Tests +.PHONY: test +test: + make -f test.mk all diff --git a/README.md b/README.md index 4299f8b..246ff44 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,17 @@ ## Setting up the environment +You may either build the application natively on your host or in a Docker environment. + +### Native on Debian Host + +1. Run `install_deb.sh` to install host dependencies +2. Run `make install` to clone submodules and build all components +3. Run `make applications` to build all sample WebAssembly apps for execution on SLEdge +4. Run `make test` to execute end-to-end tests running WebAssembly apps on SLEdge. + +### Docker + **Note: These steps require Docker. Make sure you've got it installed!** We provide a Docker build environment configured with the dependencies and toolchain needed to build the SLEdge runtime and serverless functions. @@ -18,7 +29,7 @@ To setup this environment, run: ./devenv.sh setup ``` -## Using the Docker container to compile your serverless functions +### Using the Docker container to compile your serverless functions To enter the docker environment, run: @@ -54,6 +65,16 @@ To stop the Docker container: ./devenv.sh stop ``` +### Deleting Docker Build Containers + +If you are finished working with the SLEdge runtime and wish to remove it, run the following command to delete our Docker build and runtime images. + +```bash +./devenv.sh rma +``` + +And then simply delete this repository. + ## Running your first serverless function An SLEdge serverless function consists of a shared library (\*.so) and a JSON configuration file that determines how the runtime should execute the serverless function. As an example, here is the configuration file for our sample fibonacci function: @@ -115,18 +136,10 @@ When done, terminal the SLEdge runtime with `Ctrl+c` ## Running Test Workloads -Various synthetic and real-world tests can be found in `runtime/experiments`. Generally, each experiment can be run be executing the `run.sh` script. - -## Removing the SLEdge Runtime - -If you are finished working with the SLEdge runtime and wish to remove it, run the following command to delete our Docker build and runtime images. - -```bash -./devenv.sh rma -``` +Various synthetic and real-world tests can be found in `runtime/tests`. Generally, each experiment can be run by Make rules in the top level `test.mk`. -And then simply delete this repository. +`make -f test.mk all` ## Problems or Feedback? -If you encountered bugs or have feedback, please let us know in our [issue tracker.](https://github.com/phanikishoreg/awsm-Serverless-Framework/issues) +If you encountered bugs or have feedback, please let us know in our [issue tracker.](https://github.com/gwsystems/sledge-serverless-framework/issues) diff --git a/applications/.gitignore b/applications/.gitignore index 8a20b92..a261f29 100644 --- a/applications/.gitignore +++ b/applications/.gitignore @@ -1,3 +1 @@ -*.wasm -*.bc -*.so +dist/* diff --git a/applications/Makefile b/applications/Makefile index c0bcda1..204ebfc 100644 --- a/applications/Makefile +++ b/applications/Makefile @@ -1,5 +1,5 @@ AWSMCC=../awsm/target/release/awsm -CC=clang-8 +CC=clang # Used by aWsm when compiling the *.wasm to *.bc AWSMFLAGS= --inline-constant-globals --runtime-globals @@ -8,34 +8,30 @@ AWSMFLAGS= --inline-constant-globals --runtime-globals # --whole-archive causes the symbols in the listed static archive to be exported from the resulting *.so # https://stackoverflow.com/questions/805555/ld-linker-question-the-whole-archive-option CFLAGS=-O3 -flto -LDFLAGS=-shared -fPIC -Wl,--export-dynamic,--whole-archive -L../libsledge/dist/ -lsledge -Wl,--no-whole-archive -lm +LDFLAGS=-shared -fPIC -Wl,--export-dynamic,--whole-archive -L../libsledge/dist/ -lsledge -Wl,--no-whole-archive # LDFLAGS=-flto -fvisibility=hidden +dist: + mkdir dist .PHONY: all all: \ cifar10.install \ empty.install \ - gps_ekf.install \ fibonacci.install \ gocr.install \ + gps_ekf.install \ license_plate_detection.install \ resize_image.install .PHONY: clean clean: - @make clean -C ./wasmception_apps/fibonacci - @make clean -C ./wasmception_apps/empty - @make clean -C ./wasmception_apps/TinyEKF/extras/c/ -f wasm.mk - @make clean -C ./wasmception_apps/CMSIS_5_NN/ -f Makefile - @make clean -C ./wasmception_apps/gocr/src/ -f wasm.mk - @make clean -C ./wasmception_apps/sod/ - @rm -f *.wasm + @make -C wasm_apps clean @rm -rf dist - @rm -f ../runtime/bin/*.so + @rm -rf ../runtime/bin/*.so -dist: - mkdir -p dist +wasm_apps/dist/%.wasm: + make -C wasm_apps $(addprefix dist/,$(notdir $@)) ../libsledge/dist/: mkdir ../libsledge/dist @@ -43,82 +39,40 @@ dist: ../libsledge/dist/libsledge.a: ../libsledge/dist/ make -C .. libsledge -%.bc: %.wasm dist +dist/%.bc: ./wasm_apps/dist/%.wasm dist ${AWSMCC} ${AWSMFLAGS} $< -o $@ -%.wasm.so: %.bc - mkdir -p dist +dist/%.ll: dist/%.bc + llvm-dis-12 $< -o $@ + +dist/%.wasm.so: dist/%.bc ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ../runtime/bin/%.wasm.so: dist/%.wasm.so cp $^ $@ -# Fibonacci -./wasmception_apps/fibonacci/fibonacci.wasm: - @make fibonacci.wasm -C ./wasmception_apps/fibonacci - -dist/fibonacci.wasm: ./wasmception_apps/fibonacci/fibonacci.wasm dist - @cp ./wasmception_apps/fibonacci/fibonacci.wasm dist/fibonacci.wasm - -.PHONY: fibonacci.install -fibonacci.install: ../runtime/bin/fibonacci.wasm.so - -# Empty -./wasmception_apps/empty/empty.wasm: - @make empty.wasm -C ./wasmception_apps/empty +.PHONY: cifar10.install +cifar10.install: ../runtime/bin/cifar10.wasm.so -dist/empty.wasm: ./wasmception_apps/empty/empty.wasm dist - @cp ./wasmception_apps/empty/empty.wasm dist/empty.wasm +# Echo? .PHONY: empty.install empty.install: ../runtime/bin/empty.wasm.so -# EKF -./wasmception_apps/TinyEKF/extras/c/gps_ekf_fn.wasm: - @make gps_ekf_fn.wasm -C ./wasmception_apps/TinyEKF/extras/c/ -f wasm.mk - -dist/gps_ekf.wasm: ./wasmception_apps/TinyEKF/extras/c/gps_ekf_fn.wasm dist - @cp ./wasmception_apps/TinyEKF/extras/c/gps_ekf_fn.wasm dist/gps_ekf.wasm - -.PHONY: gps_ekf.install -gps_ekf.install: ../runtime/bin/gps_ekf.wasm.so - -# CIFAR10 -./wasmception_apps/CMSIS_5_NN/cifar10.wasm: - @make cifar10.wasm -C ./wasmception_apps/CMSIS_5_NN/ -f Makefile +.PHONY: exit.install +exit.install: ../runtime/bin/exit.wasm.so -dist/cifar10.wasm: ./wasmception_apps/CMSIS_5_NN/cifar10.wasm dist - @cp ./wasmception_apps/CMSIS_5_NN/cifar10.wasm dist/cifar10.wasm - -.PHONY: cifar10.install -cifar10.install: ../runtime/bin/cifar10.wasm.so - -# GOCR -./wasmception_apps/gocr/src/gocr.wasm: - @make gocr.wasm -C ./wasmception_apps/gocr/src/ -f wasm.mk - -dist/gocr.wasm: ./wasmception_apps/gocr/src/gocr.wasm dist - @cp ./wasmception_apps/gocr/src/gocr.wasm dist/gocr.wasm +.PHONY: fibonacci.install +fibonacci.install: ../runtime/bin/fibonacci.wasm.so .PHONY: gocr.install gocr.install: ../runtime/bin/gocr.wasm.so -# LPD -./wasmception_apps/sod/bin/license_plate_detection.wasm: - @make dir license_plate_detection.wasm -C ./wasmception_apps/sod/ +.PHONY: resize_image.install +resize_image.install: ../runtime/bin/resize_image.wasm.so -dist/license_plate_detection.wasm: ./wasmception_apps/sod/bin/license_plate_detection.wasm dist - @cp ./wasmception_apps/sod/bin/license_plate_detection.wasm dist/license_plate_detection.wasm +.PHONY: gps_ekf.install +gps_ekf.install: ../runtime/bin/gps_ekf.wasm.so .PHONY: license_plate_detection.install license_plate_detection.install: ../runtime/bin/license_plate_detection.wasm.so - -# Resize -./wasmception_apps/sod/bin/resize_image.wasm: - @make dir resize_image.wasm -C ./wasmception_apps/sod/ - -dist/resize_image.wasm: ./wasmception_apps/sod/bin/resize_image.wasm dist - @cp ./wasmception_apps/sod/bin/resize_image.wasm dist/resize_image.wasm - -.PHONY: resize_image.install -resize_image.install: ../runtime/bin/resize_image.wasm.so diff --git a/applications/wasm_apps b/applications/wasm_apps new file mode 160000 index 0000000..1125852 --- /dev/null +++ b/applications/wasm_apps @@ -0,0 +1 @@ +Subproject commit 1125852cf199a53bf194f53da880aca97b64c124 diff --git a/applications/wasmception_apps/CMSIS_5_NN b/applications/wasmception_apps/CMSIS_5_NN deleted file mode 160000 index 9e01b5a..0000000 --- a/applications/wasmception_apps/CMSIS_5_NN +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9e01b5a5914d3456c3018b3265d74a01656d10bd diff --git a/applications/wasmception_apps/TinyEKF b/applications/wasmception_apps/TinyEKF deleted file mode 160000 index 8c2654d..0000000 --- a/applications/wasmception_apps/TinyEKF +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8c2654d622e39b0eee84a3fd00174c2cfb5996ee diff --git a/applications/wasmception_apps/empty/Makefile b/applications/wasmception_apps/empty/Makefile deleted file mode 100644 index e5620d9..0000000 --- a/applications/wasmception_apps/empty/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -WASMCC=wasm32-unknown-unknown-wasm-clang -OPTFLAGS=-O3 -flto -WASMLINKFLAGS=-Wl,-z,stack-size=524288,--allow-undefined,--no-threads,--stack-first,--no-entry,--export-all,--export=main,--export=dummy -WASMCFLAGS=${WASMLINKFLAGS} -nostartfiles - -all: empty.wasm - -clean: - rm -rf empty.wasm - -empty.wasm: *.c - ${WASMCC} ${WASMCFLAGS} ${OPTFLAGS} $^ -o $@ diff --git a/applications/wasmception_apps/empty/main.c b/applications/wasmception_apps/empty/main.c deleted file mode 100644 index e86ee47..0000000 --- a/applications/wasmception_apps/empty/main.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -#include - -int -main(int argc, char **argv) -{ - printf("S\n"); - - return 0; -} diff --git a/applications/wasmception_apps/empty/wasmception_hack.c b/applications/wasmception_apps/empty/wasmception_hack.c deleted file mode 100644 index 3045923..0000000 --- a/applications/wasmception_apps/empty/wasmception_hack.c +++ /dev/null @@ -1,15 +0,0 @@ -// !!! HACK ALERT !!! -// We need the __init_libc symbol in the output executable (so the runtime can initialize libc) -// We can't directly export it since it's in a linked library -// Thus we export a dummy function that uses it, forcing it to be included - - -#define IMPORT __attribute__((visibility("default"))) -#define EXPORT __attribute__((visibility("default"))) - -IMPORT void __init_libc(char **, char *); -EXPORT void -dummy() -{ - __init_libc(0, 0); -} diff --git a/applications/wasmception_apps/fibonacci/Makefile b/applications/wasmception_apps/fibonacci/Makefile deleted file mode 100644 index a2ba5b3..0000000 --- a/applications/wasmception_apps/fibonacci/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -WASMCC=wasm32-unknown-unknown-wasm-clang -OPTFLAGS=-O3 -flto -WASMLINKFLAGS=-Wl,-z,stack-size=524288,--allow-undefined,--no-threads,--stack-first,--no-entry,--export=main,--export=dummy,--export=__init_libc -WASMCFLAGS=${WASMLINKFLAGS} -nostartfiles - -all: fibonacci.wasm - -clean: - rm -rf fibonacci.wasm - -fibonacci.wasm: *.c - ${WASMCC} ${WASMCFLAGS} ${OPTFLAGS} $^ -o $@ diff --git a/applications/wasmception_apps/fibonacci/main.c b/applications/wasmception_apps/fibonacci/main.c deleted file mode 100644 index 49b1695..0000000 --- a/applications/wasmception_apps/fibonacci/main.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -uint32_t -fib(uint32_t n) -{ - if (n <= 1) return n; - return fib(n - 1) + fib(n - 2); -} - -int -main(int argc, char **argv) -{ - uint32_t n = 0; - scanf("%u", &n); - - uint32_t result = fib(n); - printf("%u\n", result); - return 0; -} diff --git a/applications/wasmception_apps/fibonacci/wasmception_hack.c b/applications/wasmception_apps/fibonacci/wasmception_hack.c deleted file mode 100644 index 3045923..0000000 --- a/applications/wasmception_apps/fibonacci/wasmception_hack.c +++ /dev/null @@ -1,15 +0,0 @@ -// !!! HACK ALERT !!! -// We need the __init_libc symbol in the output executable (so the runtime can initialize libc) -// We can't directly export it since it's in a linked library -// Thus we export a dummy function that uses it, forcing it to be included - - -#define IMPORT __attribute__((visibility("default"))) -#define EXPORT __attribute__((visibility("default"))) - -IMPORT void __init_libc(char **, char *); -EXPORT void -dummy() -{ - __init_libc(0, 0); -} diff --git a/applications/wasmception_apps/gocr b/applications/wasmception_apps/gocr deleted file mode 160000 index 0976fd0..0000000 --- a/applications/wasmception_apps/gocr +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0976fd036462264f581a588fa6cfa46718c67716 diff --git a/applications/wasmception_apps/sod b/applications/wasmception_apps/sod deleted file mode 160000 index 3bdd8c5..0000000 --- a/applications/wasmception_apps/sod +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3bdd8c58c7f9159dd88ec56e5beefccdd503ad9e diff --git a/applications/wasmception_apps/speechtotext b/applications/wasmception_apps/speechtotext deleted file mode 160000 index 0ef276b..0000000 --- a/applications/wasmception_apps/speechtotext +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0ef276b96503c40bedae5e85453d28e738743f93 diff --git a/format.sh b/format.sh index 6115c93..4aaf5fe 100755 --- a/format.sh +++ b/format.sh @@ -1,7 +1,7 @@ #!/bin/bash validate() { - utility="clang-format" + utility="clang-format-13" utility_version="$("$utility" --version 2> /dev/null)" || { echo "$utility not found in path!" exit 1 @@ -11,7 +11,7 @@ validate() { declare -i major=0 declare -i minor=0 declare -i patch=0 - declare -i required_major=11 + declare -i required_major=13 declare -i required_minor=0 declare -i required_patch=0 @@ -51,8 +51,8 @@ dry_run() { format() { find runtime \ \( -path "runtime/thirdparty" -o -path "applications/gocr" -o -path "applications/TinyEKF" -o -path "applications/CMSIS_5_NN" -o -path "applications/sod" -o -path "applications/**/thirdparty" \) -prune -false -o \ - -type f \( -iname \*.h -o -iname \*.c -o -iname \*.s \) -print \ - | xargs clang-format -i + -type f \( -iname \*.h -o -iname \*.c -o -iname \*.s \) -print0 \ + | xargs --null clang-format -i } case $1 in diff --git a/install.sh b/install.sh deleted file mode 100755 index ce9989f..0000000 --- a/install.sh +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/bash -# This script is responsible for copying, linking, and aliasing all of our build tools such that they are -# in known paths that we can add to PATH and LD_LIBRARY_PATH. The binaries go into "${SYS_PREFIX}/bin" and -# the libraries go into "${SYS_PREFIX}/lib". By default, SYS_PREFIX is `/opt/sledge/`, which means that this -# script is assumed to be executed as root, as in our Docker build container. However, by by setting -# SYS_PREFIX to a directory that the user has access to, this can be avoided. -# -# For example, in the GitHub Actions workflow, SYS_PREFIX is set to the topmost project directory and the -# environment is updated as follows. -# -# SYS_PREFIX="$(pwd)" ./install.sh -# PATH="$(pwd)/bin:$PATH" -# LD_LIBRARY_PATH="$(pwd)/lib:$LD_LIBRARY_PATH" -# -# This is currently executed -# - Indirectly via `make install` in the root Makefile, typically when the sledge-dev build container is built -# - Directly by the GitHub workflow -# -# The script takes either wasmception or wasi as the first argument to install either wasmception or WASI-SDK -# If no argument is provided, wasmception is assumed -# If either wasmception or wasi is provided, an additional `-d` or `--dry-run` flag can be provided to view the commands -# and paths that would be generated. This is helpful for sanity checking when setting SYS_PREFIX and using in a new context - -echo "Setting up toolchain environment" - -for last_arg in "$@"; do :; done - -if [[ $last_arg == "-d" ]] || [[ $last_arg == "--dry-run" ]]; then - DRY_RUN=true -else - DRY_RUN=false -fi - -if $DRY_RUN; then - DRY_RUN_PREFIX=echo -else - DRY_RUN_PREFIX= -fi - -# Get the absolute path of the topmost project directly -# The use of dirname is particular. It seems unneccesary how this script is run -SYS_SRC_PREFIX=${SYS_SRC_PREFIX:-"$( - cd "$(dirname "$(dirname "${0}")")" || exit 1 - pwd -P -)"} -$DRY_RUN && echo SYS_SRC_PREFIX: "$SYS_SRC_PREFIX" - -# And check for the presence of this script to make sure we got it right -if [ ! -x "${SYS_SRC_PREFIX}/install.sh" ]; then - echo "Unable to find the install script" >&2 - exit 1 -fi - -SYS_NAME='sledge' -COMPILER='awsm' -COMPILER_EXECUTABLE=$COMPILER - -# /opt/sledge -SYS_PREFIX=${SYS_PREFIX:-"/opt/${SYS_NAME}"} -$DRY_RUN && echo SYS_PREFIX: "$SYS_PREFIX" - -# /sledge, where the sledge repo is mounted from the host -SYS_SRC_PREFIX=${SYS_SRC_PREFIX:-"/${SYS_NAME}"} -$DRY_RUN && echo SYS_SRC_PREFIX: "$SYS_SRC_PREFIX" - -# The release directory containing the binary of the aWsm compiler -SYS_COMPILER_REL_DIR=${SYS_COMPILER_REL_DIR:-"${SYS_SRC_PREFIX}/${COMPILER}/target/release"} -$DRY_RUN && echo SYS_COMPILER_REL_DIR: "$SYS_COMPILER_REL_DIR" - -# /opt/sledge/bin -SYS_BIN_DIR=${SYS_BIN_DIR:-"${SYS_PREFIX}/bin"} -$DRY_RUN && echo SYS_BIN_DIR: "$SYS_BIN_DIR" - -# /opt/sledge/lib -SYS_LIB_DIR=${SYS_LIB_DIR:-"${SYS_PREFIX}/lib"} -$DRY_RUN && echo SYS_LIB_DIR: "$SYS_LIB_DIR" - -# The first argument can be either wasi or wasmception. This determines the system interface used -# The default is wasmception -# Currently, WASI is not actually supported by the runtime. -if [ $# -eq 0 ] || [ "$1" = "wasmception" ]; then - echo "Setting up for wasmception" - WASM_PREFIX=${WASM_PREFIX:-"${SYS_SRC_PREFIX}/${COMPILER}/wasmception"} - WASM_BIN=${WASM_BIN:-"${WASM_PREFIX}/dist/bin"} - WASM_SYSROOT=${WASM_SYSROOT:-"${WASM_PREFIX}/sysroot"} - WASM_TARGET=${WASM_TARGET:-"wasm32-unknown-unknown-wasm"} - WASM_BIN_PREFIX=${WASM_BIN_PREFIX:-"$WASM_TARGET"} - WASM_TOOLS=(ar) -elif [ "$1" = "wasi" ]; then - echo "Setting up for wasi-sdk" - WASM_PREFIX=${WASM_PREFIX:-${WASM_SDK:-"/opt/wasi-sdk"}} - WASM_BIN=${WASM_BIN:-"${WASM_PREFIX}/bin"} - WASM_SYSROOT=${WASM_SYSROOT:-"${WASM_PREFIX}/share/sysroot"} - WASM_TARGET=${WASM_TARGET:-"wasm32-wasi"} - WASM_BIN_PREFIX=${WASM_BIN_PREFIX:-"$WASM_TARGET"} - WASM_TOOLS=(ar dwarfdump nm ranlib size) -fi -$DRY_RUN && echo WASM_PREFIX: "$WASM_PREFIX" -$DRY_RUN && echo WASM_BIN: "$WASM_BIN" -$DRY_RUN && echo WASM_SYSROOT: "$WASM_SYSROOT" -$DRY_RUN && echo WASM_TARGET: "$WASM_TARGET" -$DRY_RUN && echo WASM_BIN_PREFIX: "$WASM_BIN_PREFIX" -$DRY_RUN && echo WASM_TOOLS: "${WASM_TOOLS[@]}" - -# Delete all existing installations of the binaries -$DRY_RUN_PREFIX rm -f "${SYS_BIN_DIR}"/* - -# And reinstall -$DRY_RUN_PREFIX install -d -v "$SYS_BIN_DIR" || exit 1 - -# Symbolically link the Awsm compiler -# /sledge/awsm/target/release/silverfish /opt/sledge/bin/awsm -$DRY_RUN_PREFIX ln -sfv "${SYS_COMPILER_REL_DIR}/${COMPILER_EXECUTABLE}" "${SYS_BIN_DIR}/${COMPILER_EXECUTABLE}" - -# Generate shell script stubs that act as aliases that automatically set the approproiate target and sysroot -# for either Wasmception or WASI-SDK -# For example, when wasmception is set, calling `wasm32-unknown-unknown-wasm-clang` results in -# `exec "/sledge/awsm/wasmception/dist/bin/clang" --target="wasm32-unknown-unknown-wasm" --sysroot="/sledge/awsm/wasmception/sysroot" "$@"` -for file in clang clang++; do - wrapper_file="$(mktemp)" - cat > "$wrapper_file" << EOT -#! /bin/sh - -exec "${WASM_BIN}/${file}" --target="$WASM_TARGET" --sysroot="$WASM_SYSROOT" "\$@" -EOT - cat "$wrapper_file" - $DRY_RUN_PREFIX install -p -v "$wrapper_file" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}" - $DRY_RUN && echo rm -f "$wrapper_file" - rm -f "$wrapper_file" -done - -# Link the LLVM Tools with the proper prefix -for file in "${WASM_TOOLS[@]}"; do - $DRY_RUN_PREFIX ln -sfv "${WASM_BIN}/llvm-${file}" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}" -done - -# Link any other tools with the proper prefix -OTHER_TOOLS=(ld) -for file in "${OTHER_TOOLS[@]}"; do - $DRY_RUN_PREFIX ln -sfv "${WASM_BIN}/wasm-${file}" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}" -done - -# Link clang as gcc if needed -$DRY_RUN_PREFIX ln -svf "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-clang" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-gcc" -$DRY_RUN_PREFIX ln -svf "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-clang++" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-g++" - -echo "Done!" diff --git a/install_deb.sh b/install_deb.sh new file mode 100755 index 0000000..82abbb7 --- /dev/null +++ b/install_deb.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +HEY_URL=https://hey-release.s3.us-east-2.amazonaws.com/hey_linux_amd64 +LLVM_VERSION=12 +SHELLCHECK_URL=https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.x86_64.tar.xz +SHFMT_URL=https://github.com/mvdan/sh/releases/download/v3.2.4/shfmt_v3.2.4_linux_amd64 +WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk_12.0_amd64.deb + +apt-get update && apt-get install -y --no-install-recommends \ + bc \ + fonts-dejavu \ + fonts-cascadia-code \ + fonts-roboto \ + gnuplot \ + imagemagick \ + jq \ + libz3-4 \ + netpbm \ + pango1.0-tools \ + wamerican + +wget $HEY_URL -O hey && chmod +x hey && sudo mv hey /usr/bin/hey + +wget $SHFMT_URL -O shfmt && chmod +x shfmt && sudo mv shfmt /usr/local/bin/shfmt + +wget $SHELLCHECK_URL -O shellcheck && chmod +x shellcheck && sudo mv shellcheck /usr/local/bin/shellcheck + +./install_llvm.sh $LLVM_VERSION + +curl -sS -L -O $WASI_SDK_URL && dpkg -i wasi-sdk_12.0_amd64.deb && rm -f wasi-sdk_12.0_amd64.deb + +echo "Add WASI_SDK_PATH to your bashrc and resource!" +echo "Example: export WASI_SDK_PATH=/opt/wasi-sdk" diff --git a/install_llvm.sh b/install_llvm.sh index da1e3c5..ad096f5 100755 --- a/install_llvm.sh +++ b/install_llvm.sh @@ -1,39 +1,34 @@ #!/bin/bash # Installs LLVM tooling, delegating the to the LLVM script as much as possible -# We need to shim support for LLVM 8 because the LLVM script only supports 9-12 LLVM_VERSION=$1 echo "Installing LLVM $LLVM_VERSION" # Script Installs clang, lldb, lld, and clangd -if [[ "$LLVM_VERSION" -gt 8 ]]; then - curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm.sh | bash -s -- "$LLVM_VERSION" -else - apt-get install -y --no-install-recommends \ - "clang-$LLVM_VERSION" \ - "lldb-$LLVM_VERSION" \ - "lld-$LLVM_VERSION" \ - "clangd-$LLVM_VERSION" -fi +curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm.sh | bash -s -- "$LLVM_VERSION" apt-get install -y --no-install-recommends \ "libc++-$LLVM_VERSION-dev" \ "libc++abi-$LLVM_VERSION-dev" \ - "libc++1-$LLVM_VERSION" + "libc++1-$LLVM_VERSION" \ + "libunwind-$LLVM_VERSION" \ + "libunwind-$LLVM_VERSION-dev" \ + "clang-tools-$LLVM_VERSION" \ + "clang-tidy-$LLVM_VERSION" \ + "clang-format-$LLVM_VERSION" +sudo update-alternatives --remove-all clang-format +sudo update-alternatives --remove-all clang +sudo update-alternatives --remove-all clang++ +sudo update-alternatives --remove-all llvm-config +sudo update-alternatives --remove-all llvm-objdump +sudo update-alternatives --remove-all llvm-objdump +sudo update-alternatives --remove-all clang-tidy + +update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-$LLVM_VERSION" 100 update-alternatives --install /usr/bin/clang clang "/usr/bin/clang-$LLVM_VERSION" 100 update-alternatives --install /usr/bin/clang++ clang++ "/usr/bin/clang++-$LLVM_VERSION" 100 update-alternatives --install /usr/bin/llvm-config llvm-config "/usr/bin/llvm-config-$LLVM_VERSION" 100 update-alternatives --install /usr/bin/llvm-objdump llvm-objdump "/usr/bin/llvm-objdump-$LLVM_VERSION" 100 - -# Explicitly use at least clang-format-11 to format source because of changes between 10 and 11 -if [[ "$LLVM_VERSION" -ge 11 ]]; then - apt-get install -y --no-install-recommends \ - "clang-format-$LLVM_VERSION" - update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-$LLVM_VERSION" 100 -else - apt-get install -y --no-install-recommends \ - "clang-format-11" - update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-11" 100 -fi +update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-$LLVM_VERSION" 100 diff --git a/libsledge/Makefile b/libsledge/Makefile index ad38039..d5a8e19 100644 --- a/libsledge/Makefile +++ b/libsledge/Makefile @@ -23,22 +23,10 @@ all: dist/libsledge.a dist: mkdir dist -dist/memory_instructions.o: src/memory_instructions.c dist +dist/%.o: src/%.c dist clang ${CFLAGS} -c ${INCLUDES} -o $@ $< -dist/numeric_instructions.o: src/numeric_instructions.c dist - clang ${CFLAGS} -c ${INCLUDES} -o $@ $< - -dist/table_instructions.o: src/table_instructions.c dist - clang ${CFLAGS} -c ${INCLUDES} -o $@ $< - -dist/variable_instructions.o: src/variable_instructions.c dist - clang ${CFLAGS} -c ${INCLUDES} -o $@ $< - -dist/instantiation.o: src/instantiation.c dist - clang ${CFLAGS} -c ${INCLUDES} -o $@ $< - -dist/libsledge.a: dist/memory_instructions.o dist/numeric_instructions.o dist/table_instructions.o dist/variable_instructions.o dist/instantiation.o +dist/libsledge.a: dist/memory_instructions.o dist/numeric_instructions.o dist/table_instructions.o dist/variable_instructions.o dist/instantiation.o dist/wasi_snapshot_preview1.o ar rcs dist/libsledge.a $^ clean: diff --git a/libsledge/README.md b/libsledge/README.md index 2e76709..1fdff5e 100644 --- a/libsledge/README.md +++ b/libsledge/README.md @@ -146,7 +146,6 @@ The path to the JSON file is passed to `module_alloc_from_json`, which uses the `module init` then calls `module.abi.initialize_table`, which populates the indirect function table with the actual functions. This is performed once during module initialization because this table does not actually vary between instances of a module. - # SLEdge \*.so Module Instantiation When `sledgert` receives a request at the registered port specified in the JSON, it performs assorted allocation and initialization steps. The scheduler sets the expected ABI symbols and yields to `current_sandbox_start`, which immediately calls `current_sandbox_init`. This function initializes the associated runtime state and @@ -161,4 +160,3 @@ When `sledgert` receives a request at the registered port specified in the JSON, # Questions: - Should `sledge_abi__current_wasm_module_instance` be turned into a macro defined int the ABI header? -- What happens if the runtime is executing and calls `sledge_abi__current_wasm_module_instance_trap`? diff --git a/libsledge/include/sledge_abi.h b/libsledge/include/sledge_abi.h index dc5b617..c72c87b 100644 --- a/libsledge/include/sledge_abi.h +++ b/libsledge/include/sledge_abi.h @@ -15,7 +15,7 @@ struct sledge_abi__wasm_table_entry { uint32_t type_id; - void * func_pointer; + void *func_pointer; }; struct sledge_abi__wasm_table { @@ -58,7 +58,7 @@ extern int32_t sledge_abi__wasm_globals_set_i64(uint32_t idx, int64_t value, boo extern void sledge_abi__init_globals(void); extern void sledge_abi__init_mem(void); extern void sledge_abi__init_tbl(void); -extern int32_t sledge_abi__entrypoint(int32_t, int32_t); +extern int32_t sledge_abi__entrypoint(void); extern uint32_t sledge_abi__wasm_memory_starting_pages(void); extern uint32_t sledge_abi__wasm_memory_max_pages(void); @@ -71,10 +71,7 @@ typedef void (*sledge_abi__init_mem_fn_t)(void); typedef void (*sledge_abi__init_tbl_fn_t)(void); #define SLEDGE_ABI__INITIALIZE_TABLE "sledge_abi__init_tbl" -typedef void (*sledge_abi__init_libc_fn_t)(int32_t, int32_t); -#define SLEDGE_ABI__INITIALIZE_LIBC "sledge_abi__init_libc" - -typedef int32_t (*sledge_abi__entrypoint_fn_t)(int32_t a, int32_t b); +typedef int32_t (*sledge_abi__entrypoint_fn_t)(void); #define SLEDGE_ABI__ENTRYPOINT "sledge_abi__entrypoint" typedef uint32_t (*sledge_abi__wasm_memory_starting_pages_fn_t)(void); @@ -82,3 +79,158 @@ typedef uint32_t (*sledge_abi__wasm_memory_starting_pages_fn_t)(void); typedef uint32_t (*sledge_abi__wasm_memory_max_pages_fn_t)(void); #define SLEDGE_ABI__MAX_PAGES "sledge_abi__wasm_memory_max_pages" + +typedef uint32_t __wasi_clockid_t; +typedef uint64_t __wasi_dircookie_t; +typedef uint32_t __wasi_exitcode_t; +typedef int32_t __wasi_fd_t; +typedef int64_t __wasi_filedelta_t; +typedef uint64_t __wasi_filesize_t; +typedef uint32_t __wasi_lookupflags_t; +typedef uint64_t __wasi_rights_t; +typedef uint32_t __wasi_size_t; +typedef uint64_t __wasi_timestamp_t; + +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif + + +uint32_t sledge_abi__wasi_snapshot_preview1_args_get(__wasi_size_t argv_retoffset, __wasi_size_t argv_buf_retoffset); + +uint32_t +sledge_abi__wasi_snapshot_preview1_args_sizes_get(__wasi_size_t argc_retoffset, __wasi_size_t argv_buf_len_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_clock_res_get(__wasi_clockid_t id, __wasi_size_t resolution_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, + __wasi_size_t time_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_environ_get(__wasi_size_t env_retoffset, __wasi_size_t env_buf_retoffset); + +uint32_t +sledge_abi__wasi_snapshot_preview1_environ_sizes_get(__wasi_size_t envc_retoffset, __wasi_size_t env_buf_len_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_advise(__wasi_fd_t fd, __wasi_filesize_t file_offset, + __wasi_filesize_t len, uint32_t advice_extended); + +uint32_t +sledge_abi__wasi_snapshot_preview1_fd_allocate(__wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_close(__wasi_fd_t fd); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_datasync(__wasi_fd_t fd); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_fdstat_get(__wasi_fd_t fd, __wasi_size_t fdstat_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_fdstat_set_flags(__wasi_fd_t fd, uint32_t fdflags_extended); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_fdstat_set_rights(__wasi_fd_t fd, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_filestat_get(__wasi_fd_t fd, __wasi_size_t filestat_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_filestat_set_size(__wasi_fd_t fd, __wasi_filesize_t size); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_filestat_set_times(__wasi_fd_t fd, __wasi_timestamp_t atim, + __wasi_timestamp_t mtim, uint32_t fstflags_extended); + +uint32_t +sledge_abi__wasi_snapshot_preview1_fd_pread(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_filesize_t offset, __wasi_size_t nread_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_prestat_get(__wasi_fd_t fd, __wasi_size_t prestat_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_prestat_dir_name(__wasi_fd_t fd, __wasi_size_t dirname_retoffset, + __wasi_size_t dirname_len); + +uint32_t +sledge_abi__wasi_snapshot_preview1_fd_pwrite(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_filesize_t file_offset, __wasi_size_t nwritten_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_read(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, + __wasi_size_t iovs_len, __wasi_size_t nread_retoffset); + +uint32_t +sledge_abi__wasi_snapshot_preview1_fd_readdir(__wasi_fd_t fd, __wasi_size_t buf_baseoffset, __wasi_size_t buf_len, + __wasi_dircookie_t cookie, __wasi_size_t nread_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_renumber(__wasi_fd_t fd, __wasi_fd_t to); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_seek(__wasi_fd_t fd, __wasi_filedelta_t file_offset, + uint32_t whence_extended, __wasi_size_t newoffset_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_sync(__wasi_fd_t fd); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_tell(__wasi_fd_t fd, __wasi_size_t fileoffset_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_fd_write(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, + __wasi_size_t iovs_len, __wasi_size_t nwritten_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_create_directory(__wasi_fd_t fd, __wasi_size_t path_baseoffset, + __wasi_size_t path_len); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_filestat_get(__wasi_fd_t fd, __wasi_lookupflags_t flags, + __wasi_size_t path_baseoffset, __wasi_size_t path_len, + __wasi_size_t filestat_retoffset); + +uint32_t +sledge_abi__wasi_snapshot_preview1_path_filestat_set_times(__wasi_fd_t fd, __wasi_lookupflags_t flags, + __wasi_size_t path_baseoffset, __wasi_size_t path_len, + __wasi_timestamp_t atim, __wasi_timestamp_t mtim, + uint32_t fstflags_extended); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_link(__wasi_fd_t old_fd, __wasi_lookupflags_t old_flags, + __wasi_size_t old_path_baseoffset, __wasi_size_t old_path_len, + __wasi_fd_t new_fd, __wasi_size_t new_path_baseoffset, + __wasi_size_t new_path_len); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_open(__wasi_fd_t dirfd, __wasi_lookupflags_t lookupflags, + __wasi_size_t path_baseoffset, __wasi_size_t path_len, + uint32_t oflags_extended, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, uint32_t fdflags_extended, + __wasi_size_t fd_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_readlink(__wasi_fd_t fd, __wasi_size_t path_baseoffset, + __wasi_size_t path_len, __wasi_size_t buf_baseretoffset, + __wasi_size_t buf_len, __wasi_size_t nread_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_remove_directory(__wasi_fd_t fd, __wasi_size_t path_baseoffset, + __wasi_size_t path_len); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_rename(__wasi_fd_t fd, __wasi_size_t old_path_baseoffset, + __wasi_size_t old_path_len, __wasi_fd_t new_fd, + __wasi_size_t new_path_baseoffset, __wasi_size_t new_path_len); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_symlink(__wasi_size_t old_path_baseoffset, __wasi_size_t old_path_len, + __wasi_fd_t fd, __wasi_size_t new_path_baseoffset, + __wasi_size_t new_path_len); + +uint32_t sledge_abi__wasi_snapshot_preview1_path_unlink_file(__wasi_fd_t fd, __wasi_size_t path_baseoffset, + __wasi_size_t path_len); + +uint32_t sledge_abi__wasi_snapshot_preview1_poll_oneoff(__wasi_size_t in_baseoffset, __wasi_size_t out_baseoffset, + __wasi_size_t nsubscriptions, __wasi_size_t nevents_retoffset); + +void sledge_abi__wasi_snapshot_preview1_proc_exit(__wasi_exitcode_t exitcode); + +uint32_t sledge_abi__wasi_snapshot_preview1_proc_raise(uint32_t sig_extended); + +uint32_t sledge_abi__wasi_snapshot_preview1_random_get(__wasi_size_t buf_baseretoffset, __wasi_size_t buf_len); + +uint32_t sledge_abi__wasi_snapshot_preview1_sched_yield(void); + +uint32_t sledge_abi__wasi_snapshot_preview1_sock_recv(__wasi_fd_t fd, __wasi_size_t ri_data_baseretoffset, + __wasi_size_t ri_data_len, uint32_t ri_flags_extended, + __wasi_size_t ri_data_nbytes_retoffset, + __wasi_size_t message_nbytes_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_sock_send(__wasi_fd_t fd, __wasi_size_t si_data_baseoffset, + __wasi_size_t si_data_len, uint32_t si_flags_extended, + __wasi_size_t nbytes_retoffset); + +uint32_t sledge_abi__wasi_snapshot_preview1_sock_shutdown(__wasi_fd_t fd, uint32_t how); diff --git a/libsledge/src/README.md b/libsledge/src/README.md deleted file mode 100644 index 314fbd8..0000000 --- a/libsledge/src/README.md +++ /dev/null @@ -1,5 +0,0 @@ -A WebAssembly module instance is statically linked with the backing functions implementing the wasm32 ABI, yielding a *.so file that SLEdge can execute. This ensures that the instance is able to aggressively inline and optimize this code. - -They are broken into instruction types as on https://webassembly.github.io/spec/core/exec/instructions.html. They depend on common headers for the WebAssembly types located in the WebAssembly instance struct. These are located in runtime/include/common. - -The stubs correspond to awsm/src/codegen/runtime_stubs.rs diff --git a/libsledge/src/instantiation.c b/libsledge/src/instantiation.c index 624682f..a79bc13 100644 --- a/libsledge/src/instantiation.c +++ b/libsledge/src/instantiation.c @@ -17,8 +17,7 @@ extern void populate_globals(void); extern void populate_memory(void); extern void populate_table(void); extern void populate_table(void); -extern void wasmf___init_libc(int32_t, int32_t); -extern int32_t wasmf_main(int32_t, int32_t); +extern int32_t wasmf__start(void); extern uint32_t starting_pages; extern uint32_t max_pages; @@ -42,17 +41,10 @@ sledge_abi__init_tbl(void) populate_table(); } -// Wasmception Initialization. Unsure what a and b is here -EXPORT void -sledge_abi__init_libc(int32_t envp, int32_t pn) -{ - wasmf___init_libc(envp, pn); -} - EXPORT int32_t -sledge_abi__entrypoint(int32_t argc, int32_t argv) +sledge_abi__entrypoint(void) { - return wasmf_main(argc, argv); + return wasmf__start(); } EXPORT uint32_t diff --git a/libsledge/src/memory_instructions.c b/libsledge/src/memory_instructions.c index c9b7539..6b788ad 100644 --- a/libsledge/src/memory_instructions.c +++ b/libsledge/src/memory_instructions.c @@ -2,8 +2,6 @@ #define INLINE __attribute__((always_inline)) #define WASM_PAGE_SIZE (1024 * 64) /* 64KB */ -#define likely(X) __builtin_expect(!!(X), 1) -#define unlikely(X) __builtin_expect(!!(X), 0) /* This is private and NOT in the sledge_abi.h header because the runtime uses an overlay struct that extends this * symbol with private members */ @@ -12,7 +10,7 @@ extern thread_local struct sledge_abi__wasm_module_instance sledge_abi__current_ INLINE uint32_t instruction_memory_size() { - return (uint32_t)(sledge_abi__current_wasm_module_instance.memory.size / WASM_PAGE_SIZE); + return (uint32_t)(sledge_abi__current_wasm_module_instance.memory.size / (uint64_t)WASM_PAGE_SIZE); } // These functions are equivalent to those in wasm_memory.h, but they minimize pointer dereferencing @@ -20,7 +18,7 @@ INLINE float get_f32(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(float) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(float) <= sledge_abi__current_wasm_module_instance.memory.size); return *(float *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -28,7 +26,7 @@ INLINE double get_f64(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(double) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(double) <= sledge_abi__current_wasm_module_instance.memory.size); return *(double *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -36,7 +34,7 @@ INLINE int8_t get_i8(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(int8_t) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(int8_t) <= sledge_abi__current_wasm_module_instance.memory.size); return *(int8_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -44,7 +42,7 @@ INLINE int16_t get_i16(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(int16_t) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(int16_t) <= sledge_abi__current_wasm_module_instance.memory.size); return *(int16_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -52,7 +50,7 @@ INLINE int32_t get_i32(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(int32_t) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(int32_t) <= sledge_abi__current_wasm_module_instance.memory.size); return *(int32_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -60,7 +58,7 @@ INLINE int64_t get_i64(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(int64_t) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(int64_t) <= sledge_abi__current_wasm_module_instance.memory.size); return *(int64_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -69,7 +67,7 @@ INLINE void set_f32(uint32_t offset, float value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(float) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(float) <= sledge_abi__current_wasm_module_instance.memory.size); *(float *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -77,8 +75,7 @@ INLINE void set_f64(uint32_t offset, double value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(double) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(double) <= sledge_abi__current_wasm_module_instance.memory.size); *(double *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -86,7 +83,7 @@ INLINE void set_i8(uint32_t offset, int8_t value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(int8_t) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(int8_t) <= sledge_abi__current_wasm_module_instance.memory.size); *(int8_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -94,8 +91,7 @@ INLINE void set_i16(uint32_t offset, int16_t value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - - assert(offset + sizeof(int16_t) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(int16_t) <= sledge_abi__current_wasm_module_instance.memory.size); *(int16_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -103,7 +99,7 @@ INLINE void set_i32(uint32_t offset, int32_t value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(int32_t) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(int32_t) <= sledge_abi__current_wasm_module_instance.memory.size); *(int32_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -111,7 +107,7 @@ INLINE void set_i64(uint32_t offset, int64_t value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - assert(offset + sizeof(int64_t) <= sledge_abi__current_wasm_module_instance.memory.size); + assert((uint64_t)offset + sizeof(int64_t) <= sledge_abi__current_wasm_module_instance.memory.size); *(int64_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } diff --git a/libsledge/src/numeric_instructions.c b/libsledge/src/numeric_instructions.c index 3912e5b..73fd6ee 100644 --- a/libsledge/src/numeric_instructions.c +++ b/libsledge/src/numeric_instructions.c @@ -3,9 +3,7 @@ #include "sledge_abi.h" -#define INLINE __attribute__((always_inline)) -#define likely(X) __builtin_expect(!!(X), 1) -#define unlikely(X) __builtin_expect(!!(X), 0) +#define INLINE __attribute__((always_inline)) // ROTL and ROTR helper functions INLINE uint32_t diff --git a/libsledge/src/table_instructions.c b/libsledge/src/table_instructions.c index 703c641..df2938c 100644 --- a/libsledge/src/table_instructions.c +++ b/libsledge/src/table_instructions.c @@ -2,8 +2,6 @@ #define INDIRECT_TABLE_SIZE (1 << 10) #define INLINE __attribute__((always_inline)) -#define likely(X) __builtin_expect(!!(X), 1) -#define unlikely(X) __builtin_expect(!!(X), 0) /* This is private and NOT in the sledge_abi.h header because the runtime uses an overlay struct that extends this * symbol with private members */ @@ -17,9 +15,7 @@ wasm_table_get(struct sledge_abi__wasm_table *wasm_table, uint32_t idx, uint32_t struct sledge_abi__wasm_table_entry f = wasm_table->buffer[idx]; - /* Wasmception-based modules trigger function type mismatches for an unknown reason. - * This should be reenabled when WASI is added */ - // assert(f.type_id != type_id); + assert(f.type_id == type_id); assert(f.func_pointer != NULL); return f.func_pointer; @@ -46,5 +42,14 @@ add_function_to_table(uint32_t idx, uint32_t type_id, char *pointer) INLINE char * get_function_from_table(uint32_t idx, uint32_t type_id) { - return wasm_table_get(sledge_abi__current_wasm_module_instance.table, idx, type_id); + assert(sledge_abi__current_wasm_module_instance.table != NULL); + + assert(idx < sledge_abi__current_wasm_module_instance.table->capacity); + + struct sledge_abi__wasm_table_entry f = sledge_abi__current_wasm_module_instance.table->buffer[idx]; + + assert(f.type_id == type_id); + assert(f.func_pointer != NULL); + + return f.func_pointer; } diff --git a/libsledge/src/variable_instructions.c b/libsledge/src/variable_instructions.c index 1001cae..a895997 100644 --- a/libsledge/src/variable_instructions.c +++ b/libsledge/src/variable_instructions.c @@ -30,21 +30,25 @@ get_global_i64(uint32_t idx) void set_global_i32(uint32_t idx, int32_t value) { - if (idx == 0) sledge_abi__current_wasm_module_instance.wasmg_0 = (uint64_t)value; - - /* aWsm does not currently pass the is_mutable flag, so all runtime globals are assumed to be mutable. - This is true if aWsm uses the flags to inline constant globals */ - int rc = sledge_abi__wasm_globals_set_i32(idx, value, true); - assert(rc == 0); + if (idx == 0) { + sledge_abi__current_wasm_module_instance.wasmg_0 = (uint64_t)value; + } else { + /* aWsm does not currently pass the is_mutable flag, so all runtime globals are assumed to be mutable. + This is true if aWsm uses the flags to inline constant globals */ + int rc = sledge_abi__wasm_globals_set_i32(idx, value, true); + assert(rc == 0); + } } void set_global_i64(uint32_t idx, int64_t value) { - if (idx == 0) sledge_abi__current_wasm_module_instance.wasmg_0 = (uint64_t)value; - - /* aWsm does not currently pass the is_mutable flag, so all runtime globals are assumed to be mutable. - This is true if aWsm uses the flags to inline constant globals */ - int rc = sledge_abi__wasm_globals_set_i64(idx, value, true); - assert(rc == 0); + if (idx == 0) { + sledge_abi__current_wasm_module_instance.wasmg_0 = (uint64_t)value; + } else { + /* aWsm does not currently pass the is_mutable flag, so all runtime globals are assumed to be mutable. + This is true if aWsm uses the flags to inline constant globals */ + int rc = sledge_abi__wasm_globals_set_i64(idx, value, true); + assert(rc == 0); + } } diff --git a/libsledge/src/wasi_snapshot_preview1.c b/libsledge/src/wasi_snapshot_preview1.c new file mode 100644 index 0000000..130db86 --- /dev/null +++ b/libsledge/src/wasi_snapshot_preview1.c @@ -0,0 +1,313 @@ +#include +#include "sledge_abi.h" + +// TODO: Validate uint32_t as return value; + +uint32_t +wasi_snapshot_preview1_args_get(__wasi_size_t argv_retoffset, __wasi_size_t argv_buf_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_args_get(argv_buf_retoffset, argv_buf_retoffset); +} + +uint32_t +wasi_snapshot_preview1_args_sizes_get(__wasi_size_t argc_retoffset, __wasi_size_t argv_buf_len_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_args_sizes_get(argc_retoffset, argv_buf_len_retoffset); +}; + +uint32_t +wasi_snapshot_preview1_clock_res_get(__wasi_clockid_t id, __wasi_size_t resolution_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_clock_res_get(id, resolution_retoffset); +} + +uint32_t +wasi_snapshot_preview1_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, + __wasi_size_t time_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_clock_time_get(clock_id, precision, time_retoffset); +} + +uint32_t +wasi_snapshot_preview1_environ_get(__wasi_size_t env_retoffset, __wasi_size_t env_buf_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_environ_get(env_retoffset, env_buf_retoffset); +} + +uint32_t +wasi_snapshot_preview1_environ_sizes_get(__wasi_size_t envc_retoffset, __wasi_size_t env_buf_len_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_environ_sizes_get(envc_retoffset, env_buf_len_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_advise(__wasi_fd_t fd, __wasi_filesize_t file_offset, __wasi_filesize_t len, + uint32_t advice_extended) +{ + return sledge_abi__wasi_snapshot_preview1_fd_advise(fd, file_offset, len, advice_extended); +} + +uint32_t +wasi_snapshot_preview1_fd_allocate(__wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len) +{ + return sledge_abi__wasi_snapshot_preview1_fd_allocate(fd, offset, len); +} + +uint32_t +wasi_snapshot_preview1_fd_close(__wasi_fd_t fd) +{ + return sledge_abi__wasi_snapshot_preview1_fd_close(fd); +} + +uint32_t +wasi_snapshot_preview1_fd_datasync(__wasi_fd_t fd) +{ + return sledge_abi__wasi_snapshot_preview1_fd_datasync(fd); +} + +uint32_t +wasi_snapshot_preview1_fd_fdstat_get(__wasi_fd_t fd, __wasi_size_t fdstat_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_fdstat_get(fd, fdstat_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_fdstat_set_flags(__wasi_fd_t fd, uint32_t fdflags_extended) +{ + return sledge_abi__wasi_snapshot_preview1_fd_fdstat_set_flags(fd, fdflags_extended); +} + +uint32_t +wasi_snapshot_preview1_fd_fdstat_set_rights(__wasi_fd_t fd, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting) +{ + return sledge_abi__wasi_snapshot_preview1_fd_fdstat_set_rights(fd, fs_rights_base, fs_rights_inheriting); +} + +uint32_t +wasi_snapshot_preview1_fd_filestat_get(__wasi_fd_t fd, __wasi_size_t filestat_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_filestat_get(fd, filestat_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_filestat_set_size(__wasi_fd_t fd, __wasi_filesize_t size) +{ + return sledge_abi__wasi_snapshot_preview1_fd_filestat_set_size(fd, size); +} + +uint32_t +wasi_snapshot_preview1_fd_filestat_set_times(__wasi_fd_t fd, __wasi_timestamp_t atim, __wasi_timestamp_t mtim, + uint32_t fstflags_extended) +{ + return sledge_abi__wasi_snapshot_preview1_fd_filestat_set_times(fd, atim, mtim, fstflags_extended); +} + +uint32_t +wasi_snapshot_preview1_fd_pread(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_filesize_t offset, __wasi_size_t nread_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_pread(fd, iovs_baseoffset, iovs_len, offset, nread_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_prestat_get(__wasi_fd_t fd, __wasi_size_t prestat_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_prestat_get(fd, prestat_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_prestat_dir_name(__wasi_fd_t fd, __wasi_size_t dirname_retoffset, __wasi_size_t dirname_len) +{ + return sledge_abi__wasi_snapshot_preview1_fd_prestat_dir_name(fd, dirname_retoffset, dirname_len); +} + +uint32_t +wasi_snapshot_preview1_fd_pwrite(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_filesize_t file_offset, __wasi_size_t nwritten_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_pwrite(fd, iovs_baseoffset, iovs_len, file_offset, + nwritten_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_read(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_size_t nread_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_read(fd, iovs_baseoffset, iovs_len, nread_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_readdir(__wasi_fd_t fd, __wasi_size_t buf_baseoffset, __wasi_size_t buf_len, + __wasi_dircookie_t cookie, __wasi_size_t nread_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_readdir(fd, buf_baseoffset, buf_len, cookie, nread_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_renumber(__wasi_fd_t fd, __wasi_fd_t to) +{ + return sledge_abi__wasi_snapshot_preview1_fd_renumber(fd, to); +} + +uint32_t +wasi_snapshot_preview1_fd_seek(__wasi_fd_t fd, __wasi_filedelta_t file_offset, uint32_t whence_extended, + __wasi_size_t newoffset_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_seek(fd, file_offset, whence_extended, newoffset_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_sync(__wasi_fd_t fd) +{ + return sledge_abi__wasi_snapshot_preview1_fd_sync(fd); +} + +uint32_t +wasi_snapshot_preview1_fd_tell(__wasi_fd_t fd, __wasi_size_t fileoffset_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_tell(fd, fileoffset_retoffset); +} + +uint32_t +wasi_snapshot_preview1_fd_write(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_size_t nwritten_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_fd_write(fd, iovs_baseoffset, iovs_len, nwritten_retoffset); +} + +uint32_t +wasi_snapshot_preview1_path_create_directory(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len) +{ + return sledge_abi__wasi_snapshot_preview1_path_create_directory(fd, path_baseoffset, path_len); +} + +uint32_t +wasi_snapshot_preview1_path_filestat_get(__wasi_fd_t fd, __wasi_lookupflags_t flags, __wasi_size_t path_baseoffset, + __wasi_size_t path_len, __wasi_size_t filestat_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_path_filestat_get(fd, flags, path_baseoffset, path_len, + filestat_retoffset); +} + +uint32_t +wasi_snapshot_preview1_path_filestat_set_times(__wasi_fd_t fd, __wasi_lookupflags_t flags, + __wasi_size_t path_baseoffset, __wasi_size_t path_len, + __wasi_timestamp_t atim, __wasi_timestamp_t mtim, + uint32_t fstflags_extended) +{ + return sledge_abi__wasi_snapshot_preview1_path_filestat_set_times(fd, flags, path_baseoffset, path_len, atim, + mtim, fstflags_extended); +} + +uint32_t +wasi_snapshot_preview1_path_link(__wasi_fd_t old_fd, __wasi_lookupflags_t old_flags, __wasi_size_t old_path_baseoffset, + __wasi_size_t old_path_len, __wasi_fd_t new_fd, __wasi_size_t new_path_baseoffset, + __wasi_size_t new_path_len) +{ + return sledge_abi__wasi_snapshot_preview1_path_link(old_fd, old_flags, old_path_baseoffset, old_path_len, + new_fd, new_path_baseoffset, new_path_len); +} + +uint32_t +wasi_snapshot_preview1_path_open(__wasi_fd_t dirfd, __wasi_lookupflags_t lookupflags, __wasi_size_t path_baseoffset, + __wasi_size_t path_len, uint32_t oflags_extended, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, uint32_t fdflags_extended, + __wasi_size_t fd_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_path_open(dirfd, lookupflags, path_baseoffset, path_len, + oflags_extended, fs_rights_base, fs_rights_inheriting, + fdflags_extended, fd_retoffset); +} + +uint32_t +wasi_snapshot_preview1_path_readlink(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len, + __wasi_size_t buf_baseretoffset, __wasi_size_t buf_len, + __wasi_size_t nread_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_path_readlink(fd, path_baseoffset, path_len, buf_baseretoffset, + buf_len, nread_retoffset); +} + +uint32_t +wasi_snapshot_preview1_path_remove_directory(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len) +{ + return sledge_abi__wasi_snapshot_preview1_path_remove_directory(fd, path_baseoffset, path_len); +} + +uint32_t +wasi_snapshot_preview1_path_rename(__wasi_fd_t fd, __wasi_size_t old_path_baseoffset, __wasi_size_t old_path_len, + __wasi_fd_t new_fd, __wasi_size_t new_path_baseoffset, __wasi_size_t new_path_len) +{ + return sledge_abi__wasi_snapshot_preview1_path_rename(fd, old_path_baseoffset, old_path_len, new_fd, + new_path_baseoffset, new_path_len); +} + +uint32_t +wasi_snapshot_preview1_path_symlink(__wasi_size_t old_path_baseoffset, __wasi_size_t old_path_len, __wasi_fd_t fd, + __wasi_size_t new_path_baseoffset, __wasi_size_t new_path_len) +{ + return sledge_abi__wasi_snapshot_preview1_path_symlink(old_path_baseoffset, old_path_len, fd, + new_path_baseoffset, new_path_len); +} + +uint32_t +wasi_snapshot_preview1_path_unlink_file(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len) +{ + return sledge_abi__wasi_snapshot_preview1_path_unlink_file(fd, path_baseoffset, path_len); +} + +uint32_t +wasi_snapshot_preview1_poll_oneoff(__wasi_size_t in_baseoffset, __wasi_size_t out_baseoffset, + __wasi_size_t nsubscriptions, __wasi_size_t nevents_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_poll_oneoff(in_baseoffset, out_baseoffset, nsubscriptions, + nevents_retoffset); +} + +void +wasi_snapshot_preview1_proc_exit(__wasi_exitcode_t exitcode) +{ + sledge_abi__wasi_snapshot_preview1_proc_raise(exitcode); +} + +uint32_t +wasi_snapshot_preview1_proc_raise(uint32_t sig_extended) +{ + return sledge_abi__wasi_snapshot_preview1_proc_raise(sig_extended); +} + +uint32_t +wasi_snapshot_preview1_random_get(__wasi_size_t buf_baseretoffset, __wasi_size_t buf_len) +{ + return sledge_abi__wasi_snapshot_preview1_random_get(buf_baseretoffset, buf_len); +} + +uint32_t +wasi_snapshot_preview1_sched_yield(void) +{ + return sledge_abi__wasi_snapshot_preview1_sched_yield(); +} + +uint32_t +wasi_snapshot_preview1_sock_recv(__wasi_fd_t fd, __wasi_size_t ri_data_baseretoffset, __wasi_size_t ri_data_len, + uint32_t ri_flags_extended, __wasi_size_t ri_data_nbytes_retoffset, + __wasi_size_t message_nbytes_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_sock_recv(fd, ri_data_baseretoffset, ri_data_len, ri_flags_extended, + ri_data_nbytes_retoffset, message_nbytes_retoffset); +} + +uint32_t +wasi_snapshot_preview1_sock_send(__wasi_fd_t fd, __wasi_size_t si_data_baseoffset, __wasi_size_t si_data_len, + uint32_t si_flags_extended, __wasi_size_t nbytes_retoffset) +{ + return sledge_abi__wasi_snapshot_preview1_sock_send(fd, si_data_baseoffset, si_data_len, si_flags_extended, + nbytes_retoffset); +} + +uint32_t +wasi_snapshot_preview1_sock_shutdown(__wasi_fd_t fd, uint32_t how) +{ + return sledge_abi__wasi_snapshot_preview1_sock_shutdown(fd, how); +} diff --git a/runtime/Makefile b/runtime/Makefile index 2cd1f7a..7904154 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -11,7 +11,7 @@ CFLAGS=-std=c18 -pthread # We use several non-standard glibc / Linux features: # sched_getcpu, MAP_ANONYMOUS, acceess to 'gregs' in 'mcontext_t', REG_RIP, REG_RSP -CFLAGS+=-D_GNU_SOURCE +CFLAGS+=-D_GNU_SOURCE # Release Flags CFLAGS+=-O3 -flto @@ -42,6 +42,13 @@ BINARY_NAME=sledgert # Debugging Flags +# Enables logs of WASI syscalls +# CFLAGS += -DLOG_WASI + +# Sandbox writes to stdout and stderr are both written to the client socket +# However, when set, stderr is also written to the host stderr to assist with debugging +# CFLAGS += -DLOG_SANDBOX_STDERR + # Strips out calls to assert() and disables debuglog # CFLAGS += -DNDEBUG @@ -56,6 +63,7 @@ BINARY_NAME=sledgert # CFLAGS += -DLOG_MODULE_LOADING # CFLAGS += -DLOG_PREEMPTION # CFLAGS += -DLOG_SANDBOX_ALLOCATION +# CFLAGS += -DLOG_UNSUPPORTED_WASI # Stores and logs extended signal information for each worker # CFLAGS += -DLOG_SOFTWARE_INTERRUPT_COUNTS @@ -144,10 +152,3 @@ thirdparty: .PHONY: thirdparty.clean thirdparty.clean: @make --no-print-directory -C thirdparty clean - -.PHONY: submodules -submodules: - @git submodule update --init --recursive - -.PHONY: init -init: submodules clean thirdparty runtime diff --git a/runtime/include/current_sandbox.h b/runtime/include/current_sandbox.h index 067ab4b..2f1f2c4 100644 --- a/runtime/include/current_sandbox.h +++ b/runtime/include/current_sandbox.h @@ -43,10 +43,13 @@ current_sandbox_set(struct sandbox *sandbox) .table = NULL, .wasmg_0 = 0, }, + /* Private */ + .wasi_context = NULL, }; worker_thread_current_sandbox = NULL; runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX; } else { + sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context; memcpy(&sledge_abi__current_wasm_module_instance.abi.memory, &sandbox->memory->abi, sizeof(struct sledge_abi__wasm_memory)); sledge_abi__current_wasm_module_instance.abi.table = sandbox->module->indirect_table; diff --git a/runtime/include/current_sandbox_send_response.h b/runtime/include/current_sandbox_send_response.h index 38f586c..2fe8c69 100644 --- a/runtime/include/current_sandbox_send_response.h +++ b/runtime/include/current_sandbox_send_response.h @@ -32,7 +32,7 @@ current_sandbox_send_response() /* Determine values to template into our HTTP response */ size_t response_body_size = response->length; - char * module_content_type = sandbox->module->response_content_type; + char *module_content_type = sandbox->module->response_content_type; const char *content_type = strlen(module_content_type) > 0 ? module_content_type : "text/plain"; /* Capture Timekeeping data for end-to-end latency */ diff --git a/runtime/include/http_request.h b/runtime/include/http_request.h index f6ac30c..4e9d936 100644 --- a/runtime/include/http_request.h +++ b/runtime/include/http_request.h @@ -15,7 +15,7 @@ struct http_header { struct http_request { struct http_header headers[HTTP_MAX_HEADER_COUNT]; int header_count; - char * body; + char *body; int body_length; int body_read_length; /* How far we've read */ diff --git a/runtime/include/module.h b/runtime/include/module.h index 74cae97..c18a87c 100644 --- a/runtime/include/module.h +++ b/runtime/include/module.h @@ -13,6 +13,7 @@ #include "pool.h" #include "sledge_abi_symbols.h" #include "types.h" +#include "sledge_abi_symbols.h" #include "wasm_stack.h" #include "wasm_memory.h" #include "wasm_table.h" @@ -131,7 +132,6 @@ module_initialize_table(struct module *module) static inline int module_alloc_table(struct module *module) { - /* WebAssembly Indirect Table */ /* TODO: Should this be part of the module or per-sandbox? */ /* TODO: How should this table be sized? */ module->indirect_table = wasm_table_alloc(INDIRECT_TABLE_SIZE); @@ -150,18 +150,6 @@ module_initialize_pools(struct module *module) } } -/** - * Invoke a module's initialize_libc - * @param module - module whose libc we are initializing - * @param env - address? - * @param arguments - address? - */ -static inline void -module_initialize_libc(struct module *module, int32_t env, int32_t arguments) -{ - module->abi.initialize_libc(env, arguments); -} - /** * Invoke a module's initialize_memory * @param module - the module whose memory we are initializing @@ -180,9 +168,9 @@ module_initialize_memory(struct module *module) * @return return code of module's main function */ static inline int32_t -module_entrypoint(struct module *module, int32_t argc, int32_t argv) +module_entrypoint(struct module *module) { - return module->abi.entrypoint(argc, argv); + return module->abi.entrypoint(); } /** diff --git a/runtime/include/perf_window.h b/runtime/include/perf_window.h index 6bc218f..1a09015 100644 --- a/runtime/include/perf_window.h +++ b/runtime/include/perf_window.h @@ -91,7 +91,7 @@ perf_window_add(struct perf_window *perf_window, uint64_t value) for (int i = 0; i < PERF_WINDOW_BUFFER_SIZE; i++) { perf_window->by_termination[i] = i; perf_window->by_duration[i] = (struct execution_node){ .execution_time = value, - .by_termination_idx = i }; + .by_termination_idx = i }; } perf_window->count = PERF_WINDOW_BUFFER_SIZE; goto done; diff --git a/runtime/include/priority_queue.h b/runtime/include/priority_queue.h index ae7f647..bdf121d 100644 --- a/runtime/include/priority_queue.h +++ b/runtime/include/priority_queue.h @@ -27,7 +27,7 @@ struct priority_queue { uint64_t highest_priority; size_t size; size_t capacity; - void * items[]; + void *items[]; }; /** diff --git a/runtime/include/runtime.h b/runtime/include/runtime.h index 59e0ee3..df9eb4c 100644 --- a/runtime/include/runtime.h +++ b/runtime/include/runtime.h @@ -40,10 +40,10 @@ extern bool runtime_preemption_enabled; extern uint32_t runtime_processor_speed_MHz; extern uint32_t runtime_quantum_us; extern enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler; -extern pthread_t * runtime_worker_threads; +extern pthread_t *runtime_worker_threads; extern uint32_t runtime_worker_threads_count; -extern int * runtime_worker_threads_argument; -extern uint64_t * runtime_worker_threads_deadline; +extern int *runtime_worker_threads_argument; +extern uint64_t *runtime_worker_threads_deadline; extern void runtime_initialize(void); extern void runtime_set_pthread_prio(pthread_t thread, unsigned int nice); diff --git a/runtime/include/sandbox_functions.h b/runtime/include/sandbox_functions.h index 1203b9f..0f79139 100644 --- a/runtime/include/sandbox_functions.h +++ b/runtime/include/sandbox_functions.h @@ -38,7 +38,7 @@ sandbox_free_linear_memory(struct sandbox *sandbox) { assert(sandbox != NULL); assert(sandbox->memory != NULL); - module_free_linear_memory(sandbox->module, sandbox->memory); + module_free_linear_memory(sandbox->module, (struct wasm_memory *)sandbox->memory); sandbox->memory = NULL; } diff --git a/runtime/include/sandbox_receive_request.h b/runtime/include/sandbox_receive_request.h index 507110e..32371f0 100644 --- a/runtime/include/sandbox_receive_request.h +++ b/runtime/include/sandbox_receive_request.h @@ -35,7 +35,7 @@ sandbox_receive_request(struct sandbox *sandbox) /* Read from the Socket */ /* Structured to closely follow usage example at https://github.com/nodejs/http-parser */ - http_parser * parser = &sandbox->http_parser; + http_parser *parser = &sandbox->http_parser; const http_parser_settings *settings = http_parser_settings_get(); size_t request_length = request->length; diff --git a/runtime/include/sandbox_set_as_allocated.h b/runtime/include/sandbox_set_as_allocated.h index 2c0cafd..3bbfc7b 100644 --- a/runtime/include/sandbox_set_as_allocated.h +++ b/runtime/include/sandbox_set_as_allocated.h @@ -23,6 +23,7 @@ sandbox_set_as_allocated(struct sandbox *sandbox) uint64_t now = __getcycles(); /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_init(&sandbox->state_history); sandbox_state_history_append(&sandbox->state_history, SANDBOX_ALLOCATED); diff --git a/runtime/include/sandbox_set_as_asleep.h b/runtime/include/sandbox_set_as_asleep.h index f64d079..2c0bc04 100644 --- a/runtime/include/sandbox_set_as_asleep.h +++ b/runtime/include/sandbox_set_as_asleep.h @@ -36,6 +36,7 @@ sandbox_set_as_asleep(struct sandbox *sandbox, sandbox_state_t last_state) } /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_ASLEEP); diff --git a/runtime/include/sandbox_set_as_complete.h b/runtime/include/sandbox_set_as_complete.h index ce94d8f..5e19c56 100644 --- a/runtime/include/sandbox_set_as_complete.h +++ b/runtime/include/sandbox_set_as_complete.h @@ -39,6 +39,7 @@ sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state) } /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_COMPLETE); diff --git a/runtime/include/sandbox_set_as_error.h b/runtime/include/sandbox_set_as_error.h index 4a684f1..e918e6d 100644 --- a/runtime/include/sandbox_set_as_error.h +++ b/runtime/include/sandbox_set_as_error.h @@ -48,6 +48,7 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state) } /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); uint64_t duration_of_last_state = now - sandbox->timestamp_of.last_state_change; sandbox->duration_of_state[last_state] += duration_of_last_state; sandbox_state_history_append(&sandbox->state_history, SANDBOX_ERROR); diff --git a/runtime/include/sandbox_set_as_initialized.h b/runtime/include/sandbox_set_as_initialized.h index 5f9fecb..dd369e9 100644 --- a/runtime/include/sandbox_set_as_initialized.h +++ b/runtime/include/sandbox_set_as_initialized.h @@ -34,6 +34,7 @@ sandbox_set_as_initialized(struct sandbox *sandbox, sandbox_state_t last_state) } /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_INITIALIZED); diff --git a/runtime/include/sandbox_set_as_interrupted.h b/runtime/include/sandbox_set_as_interrupted.h index 97d5ef9..98a651a 100644 --- a/runtime/include/sandbox_set_as_interrupted.h +++ b/runtime/include/sandbox_set_as_interrupted.h @@ -22,6 +22,7 @@ sandbox_set_as_interrupted(struct sandbox *sandbox, sandbox_state_t last_state) uint64_t now = __getcycles(); /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; /* We do not append SANDBOX_INTERRUPTED to the sandbox_state_history because it would quickly fill the buffer */ diff --git a/runtime/include/sandbox_set_as_preempted.h b/runtime/include/sandbox_set_as_preempted.h index ddd0ebe..5287b84 100644 --- a/runtime/include/sandbox_set_as_preempted.h +++ b/runtime/include/sandbox_set_as_preempted.h @@ -36,6 +36,7 @@ sandbox_set_as_preempted(struct sandbox *sandbox, sandbox_state_t last_state) } /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_PREEMPTED); diff --git a/runtime/include/sandbox_set_as_returned.h b/runtime/include/sandbox_set_as_returned.h index 83e77dd..ae986e2 100644 --- a/runtime/include/sandbox_set_as_returned.h +++ b/runtime/include/sandbox_set_as_returned.h @@ -43,6 +43,7 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) } /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RETURNED); diff --git a/runtime/include/sandbox_set_as_runnable.h b/runtime/include/sandbox_set_as_runnable.h index e4414bc..91820dc 100644 --- a/runtime/include/sandbox_set_as_runnable.h +++ b/runtime/include/sandbox_set_as_runnable.h @@ -43,6 +43,7 @@ sandbox_set_as_runnable(struct sandbox *sandbox, sandbox_state_t last_state) } /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNABLE); diff --git a/runtime/include/sandbox_set_as_running_sys.h b/runtime/include/sandbox_set_as_running_sys.h index 98ecb4d..9c44e34 100644 --- a/runtime/include/sandbox_set_as_running_sys.h +++ b/runtime/include/sandbox_set_as_running_sys.h @@ -38,6 +38,7 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state) } /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_SYS); diff --git a/runtime/include/sandbox_set_as_running_user.h b/runtime/include/sandbox_set_as_running_user.h index 3cab443..0d50ed2 100644 --- a/runtime/include/sandbox_set_as_running_user.h +++ b/runtime/include/sandbox_set_as_running_user.h @@ -34,6 +34,7 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state) /* State Change Bookkeeping */ + assert(now > sandbox->timestamp_of.last_state_change); sandbox->duration_of_state[last_state] += (now - sandbox->timestamp_of.last_state_change); sandbox->timestamp_of.last_state_change = now; sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_USER); diff --git a/runtime/include/sandbox_setup_arguments.h b/runtime/include/sandbox_setup_arguments.h deleted file mode 100644 index 180618d..0000000 --- a/runtime/include/sandbox_setup_arguments.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "sandbox_types.h" - -extern void stub_init(int32_t offset); - -/** - * Takes the arguments from the sandbox struct and writes them into the WebAssembly linear memory - */ -static inline void -sandbox_setup_arguments(struct sandbox *sandbox) -{ - assert(sandbox != NULL); - int32_t argument_count = 0; - - /* Copy arguments into linear memory. It seems like malloc would clobber this, but I think this goes away in - * WASI, so not worth fixing*/ - - sandbox->arguments_offset = wasm_memory_get_size(sandbox->memory); - - /* Assumption: we can fit the arguments in a single wasm page */ - int rc = wasm_memory_expand(sandbox->memory, WASM_PAGE_SIZE); - assert(rc == 0); - - /* We have to update our cache here */ - memcpy(&sledge_abi__current_wasm_module_instance.abi.memory, &sandbox->memory->abi, - sizeof(struct sledge_abi__wasm_memory)); - - stub_init(sandbox->arguments_offset); -} diff --git a/runtime/include/sandbox_types.h b/runtime/include/sandbox_types.h index d000b1a..4c97b66 100644 --- a/runtime/include/sandbox_types.h +++ b/runtime/include/sandbox_types.h @@ -18,10 +18,7 @@ #include "wasm_types.h" #include "wasm_stack.h" #include "wasm_globals.h" - -#ifdef LOG_SANDBOX_MEMORY_PROFILE -#define SANDBOX_PAGE_ALLOCATION_TIMESTAMP_COUNT 1024 -#endif +#include "wasi.h" #define u8 uint8_t VEC(u8) @@ -62,8 +59,8 @@ struct sandbox { /* WebAssembly Instance State */ struct arch_context ctxt; - struct wasm_stack * stack; - struct wasm_memory * memory; + struct wasm_stack *stack; + struct wasm_memory *memory; struct vec_wasm_global_t globals; /* Scheduling and Temporal State */ @@ -76,7 +73,7 @@ struct sandbox { uint64_t total_time; /* Total time from Request to Response */ /* System Interface State */ - int32_t arguments_offset; /* actual placement of arguments in the sandbox. */ - int32_t return_value; + int32_t return_value; + wasi_context_t *wasi_context; } PAGE_ALIGNED; diff --git a/runtime/include/scheduler.h b/runtime/include/scheduler.h index 6d5ad0f..6487b72 100644 --- a/runtime/include/scheduler.h +++ b/runtime/include/scheduler.h @@ -254,6 +254,11 @@ scheduler_preemptive_sched(ucontext_t *interrupted_context) /* Preempt executing sandbox */ scheduler_log_sandbox_switch(interrupted_sandbox, next); sandbox_preempt(interrupted_sandbox); + + // Write back global at idx 0 + wasm_globals_set_i64(&interrupted_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, + true); + arch_context_save_slow(&interrupted_sandbox->ctxt, &interrupted_context->uc_mcontext); scheduler_preemptive_switch_to(interrupted_context, next); } @@ -370,6 +375,9 @@ scheduler_cooperative_sched(bool add_to_completion_queue) scheduler_log_sandbox_switch(exiting_sandbox, next_sandbox); + // Write back global at idx 0 + wasm_globals_set_i64(&exiting_sandbox->globals, 0, sledge_abi__current_wasm_module_instance.abi.wasmg_0, true); + if (add_to_completion_queue) local_completion_queue_add(exiting_sandbox); /* Do not touch sandbox struct after this point! */ diff --git a/runtime/include/scheduler_execute_epoll_loop.h b/runtime/include/scheduler_execute_epoll_loop.h index 1d8a981..2810e6d 100644 --- a/runtime/include/scheduler_execute_epoll_loop.h +++ b/runtime/include/scheduler_execute_epoll_loop.h @@ -23,7 +23,7 @@ scheduler_execute_epoll_loop(void) while (true) { struct epoll_event epoll_events[RUNTIME_MAX_EPOLL_EVENTS]; int descriptor_count = epoll_wait(worker_thread_epoll_file_descriptor, epoll_events, - RUNTIME_MAX_EPOLL_EVENTS, 0); + RUNTIME_MAX_EPOLL_EVENTS, 0); if (descriptor_count < 0) { if (errno == EINTR) continue; diff --git a/runtime/include/sledge_abi_symbols.h b/runtime/include/sledge_abi_symbols.h index 19b886d..091ae17 100644 --- a/runtime/include/sledge_abi_symbols.h +++ b/runtime/include/sledge_abi_symbols.h @@ -9,11 +9,10 @@ #include "sledge_abi.h" struct sledge_abi_symbols { - void * handle; + void *handle; sledge_abi__init_globals_fn_t initialize_globals; sledge_abi__init_mem_fn_t initialize_memory; sledge_abi__init_tbl_fn_t initialize_tables; - sledge_abi__init_libc_fn_t initialize_libc; sledge_abi__entrypoint_fn_t entrypoint; uint32_t starting_pages; uint32_t max_pages; @@ -62,13 +61,6 @@ sledge_abi_symbols_init(struct sledge_abi_symbols *abi, char *path) goto dl_error; }; - abi->initialize_libc = (sledge_abi__init_libc_fn_t)dlsym(abi->handle, SLEDGE_ABI__INITIALIZE_LIBC); - if (abi->initialize_libc == NULL) { - fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", SLEDGE_ABI__INITIALIZE_LIBC, path, - dlerror()); - goto dl_error; - }; - sledge_abi__wasm_memory_starting_pages_fn_t get_starting_pages = dlsym(abi->handle, SLEDGE_ABI__STARTING_PAGES); if (get_starting_pages == NULL) { fprintf(stderr, "Failed to resolve symbol %s in %s with error: %s\n", SLEDGE_ABI__STARTING_PAGES, path, @@ -102,7 +94,6 @@ sledge_abi_symbols_deinit(struct sledge_abi_symbols *abi) abi->initialize_globals = NULL; abi->initialize_memory = NULL; abi->initialize_tables = NULL; - abi->initialize_libc = NULL; int rc = dlclose(abi->handle); if (rc != 0) { diff --git a/runtime/include/vec.h b/runtime/include/vec.h index e441d12..2ec3bc2 100644 --- a/runtime/include/vec.h +++ b/runtime/include/vec.h @@ -8,7 +8,7 @@ struct vec_##TYPE { \ size_t length; \ size_t capacity; \ - TYPE * buffer; /* Backing heap allocation. Different lifetime because realloc might move this */ \ + TYPE *buffer; /* Backing heap allocation. Different lifetime because realloc might move this */ \ }; \ \ static inline int vec_##TYPE##_init(struct vec_##TYPE *vec, size_t capacity); \ diff --git a/runtime/include/wasi.h b/runtime/include/wasi.h new file mode 100644 index 0000000..22a0104 --- /dev/null +++ b/runtime/include/wasi.h @@ -0,0 +1,2216 @@ +#pragma once + +#include +#include +#include +#include +#include + +// TODO: Encoding this in witx. +#define __WASI_DIRCOOKIE_START (UINT64_C(0)) +typedef uint32_t __wasi_size_t; + +_Static_assert(sizeof(__wasi_size_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_size_t) == 4, "witx calculated align"); + +/** + * Non-negative file size or length of a region within a file. + */ +typedef uint64_t __wasi_filesize_t; + +_Static_assert(sizeof(__wasi_filesize_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_filesize_t) == 8, "witx calculated align"); + +/** + * Timestamp in nanoseconds. + */ +typedef uint64_t __wasi_timestamp_t; + +_Static_assert(sizeof(__wasi_timestamp_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_timestamp_t) == 8, "witx calculated align"); + +/** + * Identifiers for clocks. + */ +typedef uint32_t __wasi_clockid_t; + +/** + * The clock measuring real time. Time value zero corresponds with + * 1970-01-01T00:00:00Z. + */ +#define __WASI_CLOCKID_REALTIME (UINT32_C(0)) + +/** + * The store-wide monotonic clock, which is defined as a clock measuring + * real time, whose value cannot be adjusted and which cannot have negative + * clock jumps. The epoch of this clock is undefined. The absolute time + * value of this clock therefore has no meaning. + */ +#define __WASI_CLOCKID_MONOTONIC (UINT32_C(1)) + +/** + * The CPU-time clock associated with the current process. + */ +#define __WASI_CLOCKID_PROCESS_CPUTIME_ID (UINT32_C(2)) + +/** + * The CPU-time clock associated with the current thread. + */ +#define __WASI_CLOCKID_THREAD_CPUTIME_ID (UINT32_C(3)) + +_Static_assert(sizeof(__wasi_clockid_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_clockid_t) == 4, "witx calculated align"); + +/** + * Error codes returned by functions. + * Not all of these error codes are returned by the functions provided by this + * API; some are used in higher-level library layers, and others are provided + * merely for alignment with POSIX. + */ +typedef uint16_t __wasi_errno_t; + +/** + * No error occurred. System call completed successfully. + */ +#define __WASI_ERRNO_SUCCESS (UINT16_C(0)) + +/** + * Argument list too long. + */ +#define __WASI_ERRNO_2BIG (UINT16_C(1)) + +/** + * Permission denied. + */ +#define __WASI_ERRNO_ACCES (UINT16_C(2)) + +/** + * Address in use. + */ +#define __WASI_ERRNO_ADDRINUSE (UINT16_C(3)) + +/** + * Address not available. + */ +#define __WASI_ERRNO_ADDRNOTAVAIL (UINT16_C(4)) + +/** + * Address family not supported. + */ +#define __WASI_ERRNO_AFNOSUPPORT (UINT16_C(5)) + +/** + * Resource unavailable, or operation would block. + */ +#define __WASI_ERRNO_AGAIN (UINT16_C(6)) + +/** + * Connection already in progress. + */ +#define __WASI_ERRNO_ALREADY (UINT16_C(7)) + +/** + * Bad file descriptor. + */ +#define __WASI_ERRNO_BADF (UINT16_C(8)) + +/** + * Bad message. + */ +#define __WASI_ERRNO_BADMSG (UINT16_C(9)) + +/** + * Device or resource busy. + */ +#define __WASI_ERRNO_BUSY (UINT16_C(10)) + +/** + * Operation canceled. + */ +#define __WASI_ERRNO_CANCELED (UINT16_C(11)) + +/** + * No child processes. + */ +#define __WASI_ERRNO_CHILD (UINT16_C(12)) + +/** + * Connection aborted. + */ +#define __WASI_ERRNO_CONNABORTED (UINT16_C(13)) + +/** + * Connection refused. + */ +#define __WASI_ERRNO_CONNREFUSED (UINT16_C(14)) + +/** + * Connection reset. + */ +#define __WASI_ERRNO_CONNRESET (UINT16_C(15)) + +/** + * Resource deadlock would occur. + */ +#define __WASI_ERRNO_DEADLK (UINT16_C(16)) + +/** + * Destination address required. + */ +#define __WASI_ERRNO_DESTADDRREQ (UINT16_C(17)) + +/** + * Mathematics argument out of domain of function. + */ +#define __WASI_ERRNO_DOM (UINT16_C(18)) + +/** + * Reserved. + */ +#define __WASI_ERRNO_DQUOT (UINT16_C(19)) + +/** + * File exists. + */ +#define __WASI_ERRNO_EXIST (UINT16_C(20)) + +/** + * Bad address. + */ +#define __WASI_ERRNO_FAULT (UINT16_C(21)) + +/** + * File too large. + */ +#define __WASI_ERRNO_FBIG (UINT16_C(22)) + +/** + * Host is unreachable. + */ +#define __WASI_ERRNO_HOSTUNREACH (UINT16_C(23)) + +/** + * Identifier removed. + */ +#define __WASI_ERRNO_IDRM (UINT16_C(24)) + +/** + * Illegal byte sequence. + */ +#define __WASI_ERRNO_ILSEQ (UINT16_C(25)) + +/** + * Operation in progress. + */ +#define __WASI_ERRNO_INPROGRESS (UINT16_C(26)) + +/** + * Interrupted function. + */ +#define __WASI_ERRNO_INTR (UINT16_C(27)) + +/** + * Invalid argument. + */ +#define __WASI_ERRNO_INVAL (UINT16_C(28)) + +/** + * I/O error. + */ +#define __WASI_ERRNO_IO (UINT16_C(29)) + +/** + * Socket is connected. + */ +#define __WASI_ERRNO_ISCONN (UINT16_C(30)) + +/** + * Is a directory. + */ +#define __WASI_ERRNO_ISDIR (UINT16_C(31)) + +/** + * Too many levels of symbolic links. + */ +#define __WASI_ERRNO_LOOP (UINT16_C(32)) + +/** + * File descriptor value too large. + */ +#define __WASI_ERRNO_MFILE (UINT16_C(33)) + +/** + * Too many links. + */ +#define __WASI_ERRNO_MLINK (UINT16_C(34)) + +/** + * Message too large. + */ +#define __WASI_ERRNO_MSGSIZE (UINT16_C(35)) + +/** + * Reserved. + */ +#define __WASI_ERRNO_MULTIHOP (UINT16_C(36)) + +/** + * Filename too long. + */ +#define __WASI_ERRNO_NAMETOOLONG (UINT16_C(37)) + +/** + * Network is down. + */ +#define __WASI_ERRNO_NETDOWN (UINT16_C(38)) + +/** + * Connection aborted by network. + */ +#define __WASI_ERRNO_NETRESET (UINT16_C(39)) + +/** + * Network unreachable. + */ +#define __WASI_ERRNO_NETUNREACH (UINT16_C(40)) + +/** + * Too many files open in system. + */ +#define __WASI_ERRNO_NFILE (UINT16_C(41)) + +/** + * No buffer space available. + */ +#define __WASI_ERRNO_NOBUFS (UINT16_C(42)) + +/** + * No such device. + */ +#define __WASI_ERRNO_NODEV (UINT16_C(43)) + +/** + * No such file or directory. + */ +#define __WASI_ERRNO_NOENT (UINT16_C(44)) + +/** + * Executable file format error. + */ +#define __WASI_ERRNO_NOEXEC (UINT16_C(45)) + +/** + * No locks available. + */ +#define __WASI_ERRNO_NOLCK (UINT16_C(46)) + +/** + * Reserved. + */ +#define __WASI_ERRNO_NOLINK (UINT16_C(47)) + +/** + * Not enough space. + */ +#define __WASI_ERRNO_NOMEM (UINT16_C(48)) + +/** + * No message of the desired type. + */ +#define __WASI_ERRNO_NOMSG (UINT16_C(49)) + +/** + * Protocol not available. + */ +#define __WASI_ERRNO_NOPROTOOPT (UINT16_C(50)) + +/** + * No space left on device. + */ +#define __WASI_ERRNO_NOSPC (UINT16_C(51)) + +/** + * Function not supported. + */ +#define __WASI_ERRNO_NOSYS (UINT16_C(52)) + +/** + * The socket is not connected. + */ +#define __WASI_ERRNO_NOTCONN (UINT16_C(53)) + +/** + * Not a directory or a symbolic link to a directory. + */ +#define __WASI_ERRNO_NOTDIR (UINT16_C(54)) + +/** + * Directory not empty. + */ +#define __WASI_ERRNO_NOTEMPTY (UINT16_C(55)) + +/** + * State not recoverable. + */ +#define __WASI_ERRNO_NOTRECOVERABLE (UINT16_C(56)) + +/** + * Not a socket. + */ +#define __WASI_ERRNO_NOTSOCK (UINT16_C(57)) + +/** + * Not supported, or operation not supported on socket. + */ +#define __WASI_ERRNO_NOTSUP (UINT16_C(58)) + +/** + * Inappropriate I/O control operation. + */ +#define __WASI_ERRNO_NOTTY (UINT16_C(59)) + +/** + * No such device or address. + */ +#define __WASI_ERRNO_NXIO (UINT16_C(60)) + +/** + * Value too large to be stored in data type. + */ +#define __WASI_ERRNO_OVERFLOW (UINT16_C(61)) + +/** + * Previous owner died. + */ +#define __WASI_ERRNO_OWNERDEAD (UINT16_C(62)) + +/** + * Operation not permitted. + */ +#define __WASI_ERRNO_PERM (UINT16_C(63)) + +/** + * Broken pipe. + */ +#define __WASI_ERRNO_PIPE (UINT16_C(64)) + +/** + * Protocol error. + */ +#define __WASI_ERRNO_PROTO (UINT16_C(65)) + +/** + * Protocol not supported. + */ +#define __WASI_ERRNO_PROTONOSUPPORT (UINT16_C(66)) + +/** + * Protocol wrong type for socket. + */ +#define __WASI_ERRNO_PROTOTYPE (UINT16_C(67)) + +/** + * Result too large. + */ +#define __WASI_ERRNO_RANGE (UINT16_C(68)) + +/** + * Read-only file system. + */ +#define __WASI_ERRNO_ROFS (UINT16_C(69)) + +/** + * Invalid seek. + */ +#define __WASI_ERRNO_SPIPE (UINT16_C(70)) + +/** + * No such process. + */ +#define __WASI_ERRNO_SRCH (UINT16_C(71)) + +/** + * Reserved. + */ +#define __WASI_ERRNO_STALE (UINT16_C(72)) + +/** + * Connection timed out. + */ +#define __WASI_ERRNO_TIMEDOUT (UINT16_C(73)) + +/** + * Text file busy. + */ +#define __WASI_ERRNO_TXTBSY (UINT16_C(74)) + +/** + * Cross-device link. + */ +#define __WASI_ERRNO_XDEV (UINT16_C(75)) + +/** + * Extension: Capabilities insufficient. + */ +#define __WASI_ERRNO_NOTCAPABLE (UINT16_C(76)) + +_Static_assert(sizeof(__wasi_errno_t) == 2, "witx calculated size"); +_Static_assert(_Alignof(__wasi_errno_t) == 2, "witx calculated align"); + +/** + * File descriptor rights, determining which actions may be performed. + */ +typedef uint64_t __wasi_rights_t; + +/** + * The right to invoke `fd_datasync`. + * If `path_open` is set, includes the right to invoke + * `path_open` with `fdflags::dsync`. + */ +#define __WASI_RIGHTS_FD_DATASYNC ((__wasi_rights_t)(1 << 0)) + +/** + * The right to invoke `fd_read` and `sock_recv`. + * If `rights::fd_seek` is set, includes the right to invoke `fd_pread`. + */ +#define __WASI_RIGHTS_FD_READ ((__wasi_rights_t)(1 << 1)) + +/** + * The right to invoke `fd_seek`. This flag implies `rights::fd_tell`. + */ +#define __WASI_RIGHTS_FD_SEEK ((__wasi_rights_t)(1 << 2)) + +/** + * The right to invoke `fd_fdstat_set_flags`. + */ +#define __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS ((__wasi_rights_t)(1 << 3)) + +/** + * The right to invoke `fd_sync`. + * If `path_open` is set, includes the right to invoke + * `path_open` with `fdflags::rsync` and `fdflags::dsync`. + */ +#define __WASI_RIGHTS_FD_SYNC ((__wasi_rights_t)(1 << 4)) + +/** + * The right to invoke `fd_seek` in such a way that the file offset + * remains unaltered (i.e., `whence::cur` with offset zero), or to + * invoke `fd_tell`. + */ +#define __WASI_RIGHTS_FD_TELL ((__wasi_rights_t)(1 << 5)) + +/** + * The right to invoke `fd_write` and `sock_send`. + * If `rights::fd_seek` is set, includes the right to invoke `fd_pwrite`. + */ +#define __WASI_RIGHTS_FD_WRITE ((__wasi_rights_t)(1 << 6)) + +/** + * The right to invoke `fd_advise`. + */ +#define __WASI_RIGHTS_FD_ADVISE ((__wasi_rights_t)(1 << 7)) + +/** + * The right to invoke `fd_allocate`. + */ +#define __WASI_RIGHTS_FD_ALLOCATE ((__wasi_rights_t)(1 << 8)) + +/** + * The right to invoke `path_create_directory`. + */ +#define __WASI_RIGHTS_PATH_CREATE_DIRECTORY ((__wasi_rights_t)(1 << 9)) + +/** + * If `path_open` is set, the right to invoke `path_open` with `oflags::creat`. + */ +#define __WASI_RIGHTS_PATH_CREATE_FILE ((__wasi_rights_t)(1 << 10)) + +/** + * The right to invoke `path_link` with the file descriptor as the + * source directory. + */ +#define __WASI_RIGHTS_PATH_LINK_SOURCE ((__wasi_rights_t)(1 << 11)) + +/** + * The right to invoke `path_link` with the file descriptor as the + * target directory. + */ +#define __WASI_RIGHTS_PATH_LINK_TARGET ((__wasi_rights_t)(1 << 12)) + +/** + * The right to invoke `path_open`. + */ +#define __WASI_RIGHTS_PATH_OPEN ((__wasi_rights_t)(1 << 13)) + +/** + * The right to invoke `fd_readdir`. + */ +#define __WASI_RIGHTS_FD_READDIR ((__wasi_rights_t)(1 << 14)) + +/** + * The right to invoke `path_readlink`. + */ +#define __WASI_RIGHTS_PATH_READLINK ((__wasi_rights_t)(1 << 15)) + +/** + * The right to invoke `path_rename` with the file descriptor as the source directory. + */ +#define __WASI_RIGHTS_PATH_RENAME_SOURCE ((__wasi_rights_t)(1 << 16)) + +/** + * The right to invoke `path_rename` with the file descriptor as the target directory. + */ +#define __WASI_RIGHTS_PATH_RENAME_TARGET ((__wasi_rights_t)(1 << 17)) + +/** + * The right to invoke `path_filestat_get`. + */ +#define __WASI_RIGHTS_PATH_FILESTAT_GET ((__wasi_rights_t)(1 << 18)) + +/** + * The right to change a file's size (there is no `path_filestat_set_size`). + * If `path_open` is set, includes the right to invoke `path_open` with `oflags::trunc`. + */ +#define __WASI_RIGHTS_PATH_FILESTAT_SET_SIZE ((__wasi_rights_t)(1 << 19)) + +/** + * The right to invoke `path_filestat_set_times`. + */ +#define __WASI_RIGHTS_PATH_FILESTAT_SET_TIMES ((__wasi_rights_t)(1 << 20)) + +/** + * The right to invoke `fd_filestat_get`. + */ +#define __WASI_RIGHTS_FD_FILESTAT_GET ((__wasi_rights_t)(1 << 21)) + +/** + * The right to invoke `fd_filestat_set_size`. + */ +#define __WASI_RIGHTS_FD_FILESTAT_SET_SIZE ((__wasi_rights_t)(1 << 22)) + +/** + * The right to invoke `fd_filestat_set_times`. + */ +#define __WASI_RIGHTS_FD_FILESTAT_SET_TIMES ((__wasi_rights_t)(1 << 23)) + +/** + * The right to invoke `path_symlink`. + */ +#define __WASI_RIGHTS_PATH_SYMLINK ((__wasi_rights_t)(1 << 24)) + +/** + * The right to invoke `path_remove_directory`. + */ +#define __WASI_RIGHTS_PATH_REMOVE_DIRECTORY ((__wasi_rights_t)(1 << 25)) + +/** + * The right to invoke `path_unlink_file`. + */ +#define __WASI_RIGHTS_PATH_UNLINK_FILE ((__wasi_rights_t)(1 << 26)) + +/** + * If `rights::fd_read` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_read`. + * If `rights::fd_write` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_write`. + */ +#define __WASI_RIGHTS_POLL_FD_READWRITE ((__wasi_rights_t)(1 << 27)) + +/** + * The right to invoke `sock_shutdown`. + */ +#define __WASI_RIGHTS_SOCK_SHUTDOWN ((__wasi_rights_t)(1 << 28)) + +/** + * A file descriptor handle. + */ +typedef int __wasi_fd_t; + +_Static_assert(sizeof(__wasi_fd_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_fd_t) == 4, "witx calculated align"); + +/** + * A region of memory for scatter/gather reads. + */ +typedef struct __wasi_iovec_t { + /** + * The address of the buffer to be filled. + */ + uint8_t *buf; + + /** + * The length of the buffer to be filled. + */ + __wasi_size_t buf_len; + +} __wasi_iovec_t; + +// _Static_assert(sizeof(__wasi_iovec_t) == 8, "witx calculated size"); +// _Static_assert(_Alignof(__wasi_iovec_t) == 4, "witx calculated align"); +// _Static_assert(offsetof(__wasi_iovec_t, buf) == 0, "witx calculated offset"); +// _Static_assert(offsetof(__wasi_iovec_t, buf_len) == 4, "witx calculated offset"); + +/** + * A region of memory for scatter/gather writes. + */ +typedef struct __wasi_ciovec_t { + /** + * The address of the buffer to be written. + */ + const uint8_t *buf; + + /** + * The length of the buffer to be written. + */ + __wasi_size_t buf_len; + +} __wasi_ciovec_t; + +// _Static_assert(sizeof(__wasi_ciovec_t) == 8, "witx calculated size"); +// _Static_assert(_Alignof(__wasi_ciovec_t) == 4, "witx calculated align"); +// _Static_assert(offsetof(__wasi_ciovec_t, buf) == 0, "witx calculated offset"); +// _Static_assert(offsetof(__wasi_ciovec_t, buf_len) == 4, "witx calculated offset"); + +/** + * Relative offset within a file. + */ +typedef int64_t __wasi_filedelta_t; + +_Static_assert(sizeof(__wasi_filedelta_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_filedelta_t) == 8, "witx calculated align"); + +/** + * The position relative to which to set the offset of the file descriptor. + */ +typedef uint8_t __wasi_whence_t; + +/** + * Seek relative to start-of-file. + */ +#define __WASI_WHENCE_SET (UINT8_C(0)) + +/** + * Seek relative to current position. + */ +#define __WASI_WHENCE_CUR (UINT8_C(1)) + +/** + * Seek relative to end-of-file. + */ +#define __WASI_WHENCE_END (UINT8_C(2)) + +_Static_assert(sizeof(__wasi_whence_t) == 1, "witx calculated size"); +_Static_assert(_Alignof(__wasi_whence_t) == 1, "witx calculated align"); + +/** + * A reference to the offset of a directory entry. + * + * The value 0 signifies the start of the directory. + */ +typedef uint64_t __wasi_dircookie_t; + +_Static_assert(sizeof(__wasi_dircookie_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_dircookie_t) == 8, "witx calculated align"); + +/** + * The type for the `dirent::d_namlen` field of `dirent` struct. + */ +typedef uint32_t __wasi_dirnamlen_t; + +_Static_assert(sizeof(__wasi_dirnamlen_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_dirnamlen_t) == 4, "witx calculated align"); + +/** + * File serial number that is unique within its file system. + */ +typedef uint64_t __wasi_inode_t; + +_Static_assert(sizeof(__wasi_inode_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_inode_t) == 8, "witx calculated align"); + +/** + * The type of a file descriptor or file. + */ +typedef uint8_t __wasi_filetype_t; + +/** + * The type of the file descriptor or file is unknown or is different from any of the other types specified. + */ +#define __WASI_FILETYPE_UNKNOWN (UINT8_C(0)) + +/** + * The file descriptor or file refers to a block device inode. + */ +#define __WASI_FILETYPE_BLOCK_DEVICE (UINT8_C(1)) + +/** + * The file descriptor or file refers to a character device inode. + */ +#define __WASI_FILETYPE_CHARACTER_DEVICE (UINT8_C(2)) + +/** + * The file descriptor or file refers to a directory inode. + */ +#define __WASI_FILETYPE_DIRECTORY (UINT8_C(3)) + +/** + * The file descriptor or file refers to a regular file inode. + */ +#define __WASI_FILETYPE_REGULAR_FILE (UINT8_C(4)) + +/** + * The file descriptor or file refers to a datagram socket. + */ +#define __WASI_FILETYPE_SOCKET_DGRAM (UINT8_C(5)) + +/** + * The file descriptor or file refers to a byte-stream socket. + */ +#define __WASI_FILETYPE_SOCKET_STREAM (UINT8_C(6)) + +/** + * The file refers to a symbolic link inode. + */ +#define __WASI_FILETYPE_SYMBOLIC_LINK (UINT8_C(7)) + +_Static_assert(sizeof(__wasi_filetype_t) == 1, "witx calculated size"); +_Static_assert(_Alignof(__wasi_filetype_t) == 1, "witx calculated align"); + +/** + * A directory entry. + */ +typedef struct __wasi_dirent_t { + /** + * The offset of the next directory entry stored in this directory. + */ + __wasi_dircookie_t d_next; + + /** + * The serial number of the file referred to by this directory entry. + */ + __wasi_inode_t d_ino; + + /** + * The length of the name of the directory entry. + */ + __wasi_dirnamlen_t d_namlen; + + /** + * The type of the file referred to by this directory entry. + */ + __wasi_filetype_t d_type; + +} __wasi_dirent_t; + +_Static_assert(sizeof(__wasi_dirent_t) == 24, "witx calculated size"); +_Static_assert(_Alignof(__wasi_dirent_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_dirent_t, d_next) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_dirent_t, d_ino) == 8, "witx calculated offset"); +_Static_assert(offsetof(__wasi_dirent_t, d_namlen) == 16, "witx calculated offset"); +_Static_assert(offsetof(__wasi_dirent_t, d_type) == 20, "witx calculated offset"); + +/** + * File or memory access pattern advisory information. + */ +typedef uint8_t __wasi_advice_t; + +/** + * The application has no advice to give on its behavior with respect to the specified data. + */ +#define __WASI_ADVICE_NORMAL (UINT8_C(0)) + +/** + * The application expects to access the specified data sequentially from lower offsets to higher offsets. + */ +#define __WASI_ADVICE_SEQUENTIAL (UINT8_C(1)) + +/** + * The application expects to access the specified data in a random order. + */ +#define __WASI_ADVICE_RANDOM (UINT8_C(2)) + +/** + * The application expects to access the specified data in the near future. + */ +#define __WASI_ADVICE_WILLNEED (UINT8_C(3)) + +/** + * The application expects that it will not access the specified data in the near future. + */ +#define __WASI_ADVICE_DONTNEED (UINT8_C(4)) + +/** + * The application expects to access the specified data once and then not reuse it thereafter. + */ +#define __WASI_ADVICE_NOREUSE (UINT8_C(5)) + +_Static_assert(sizeof(__wasi_advice_t) == 1, "witx calculated size"); +_Static_assert(_Alignof(__wasi_advice_t) == 1, "witx calculated align"); + +/** + * File descriptor flags. + */ +typedef uint16_t __wasi_fdflags_t; + +/** + * Append mode: Data written to the file is always appended to the file's end. + */ +#define __WASI_FDFLAGS_APPEND ((__wasi_fdflags_t)(1 << 0)) + +/** + * Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. + */ +#define __WASI_FDFLAGS_DSYNC ((__wasi_fdflags_t)(1 << 1)) + +/** + * Non-blocking mode. + */ +#define __WASI_FDFLAGS_NONBLOCK ((__wasi_fdflags_t)(1 << 2)) + +/** + * Synchronized read I/O operations. + */ +#define __WASI_FDFLAGS_RSYNC ((__wasi_fdflags_t)(1 << 3)) + +/** + * Write according to synchronized I/O file integrity completion. In + * addition to synchronizing the data stored in the file, the implementation + * may also synchronously update the file's metadata. + */ +#define __WASI_FDFLAGS_SYNC ((__wasi_fdflags_t)(1 << 4)) + +/** + * File descriptor attributes. + */ +typedef struct __wasi_fdstat_t { + /** + * File type. + */ + __wasi_filetype_t fs_filetype; + + /** + * File descriptor flags. + */ + __wasi_fdflags_t fs_flags; + + /** + * Rights that apply to this file descriptor. + */ + __wasi_rights_t fs_rights_base; + + /** + * Maximum set of rights that may be installed on new file descriptors that + * are created through this file descriptor, e.g., through `path_open`. + */ + __wasi_rights_t fs_rights_inheriting; + +} __wasi_fdstat_t; + +_Static_assert(sizeof(__wasi_fdstat_t) == 24, "witx calculated size"); +_Static_assert(_Alignof(__wasi_fdstat_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_fdstat_t, fs_filetype) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_fdstat_t, fs_flags) == 2, "witx calculated offset"); +_Static_assert(offsetof(__wasi_fdstat_t, fs_rights_base) == 8, "witx calculated offset"); +_Static_assert(offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16, "witx calculated offset"); + +/** + * Identifier for a device containing a file system. Can be used in combination + * with `inode` to uniquely identify a file or directory in the filesystem. + */ +typedef uint64_t __wasi_device_t; + +_Static_assert(sizeof(__wasi_device_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_device_t) == 8, "witx calculated align"); + +/** + * Which file time attributes to adjust. + */ +typedef uint16_t __wasi_fstflags_t; + +/** + * Adjust the last data access timestamp to the value stored in `filestat::atim`. + */ +#define __WASI_FSTFLAGS_ATIM ((__wasi_fstflags_t)(1 << 0)) + +/** + * Adjust the last data access timestamp to the time of clock `clockid::realtime`. + */ +#define __WASI_FSTFLAGS_ATIM_NOW ((__wasi_fstflags_t)(1 << 1)) + +/** + * Adjust the last data modification timestamp to the value stored in `filestat::mtim`. + */ +#define __WASI_FSTFLAGS_MTIM ((__wasi_fstflags_t)(1 << 2)) + +/** + * Adjust the last data modification timestamp to the time of clock `clockid::realtime`. + */ +#define __WASI_FSTFLAGS_MTIM_NOW ((__wasi_fstflags_t)(1 << 3)) + +/** + * Flags determining the method of how paths are resolved. + */ +typedef uint32_t __wasi_lookupflags_t; + +/** + * As long as the resolved path corresponds to a symbolic link, it is expanded. + */ +#define __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW ((__wasi_lookupflags_t)(1 << 0)) + +/** + * Open flags used by `path_open`. + */ +typedef uint16_t __wasi_oflags_t; + +/** + * Create file if it does not exist. + */ +#define __WASI_OFLAGS_CREAT ((__wasi_oflags_t)(1 << 0)) + +/** + * Fail if not a directory. + */ +#define __WASI_OFLAGS_DIRECTORY ((__wasi_oflags_t)(1 << 1)) + +/** + * Fail if file already exists. + */ +#define __WASI_OFLAGS_EXCL ((__wasi_oflags_t)(1 << 2)) + +/** + * Truncate file to size 0. + */ +#define __WASI_OFLAGS_TRUNC ((__wasi_oflags_t)(1 << 3)) + +/** + * Number of hard links to an inode. + */ +typedef uint64_t __wasi_linkcount_t; + +_Static_assert(sizeof(__wasi_linkcount_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_linkcount_t) == 8, "witx calculated align"); + +/** + * File attributes. + */ +typedef struct __wasi_filestat_t { + /** + * Device ID of device containing the file. + */ + __wasi_device_t dev; + + /** + * File serial number. + */ + __wasi_inode_t ino; + + /** + * File type. + */ + __wasi_filetype_t filetype; + + /** + * Number of hard links to the file. + */ + __wasi_linkcount_t nlink; + + /** + * For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained + * in the symbolic link. + */ + __wasi_filesize_t size; + + /** + * Last data access timestamp. + */ + __wasi_timestamp_t atim; + + /** + * Last data modification timestamp. + */ + __wasi_timestamp_t mtim; + + /** + * Last file status change timestamp. + */ + __wasi_timestamp_t ctim; + +} __wasi_filestat_t; + +_Static_assert(sizeof(__wasi_filestat_t) == 64, "witx calculated size"); +_Static_assert(_Alignof(__wasi_filestat_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_filestat_t, dev) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_filestat_t, ino) == 8, "witx calculated offset"); +_Static_assert(offsetof(__wasi_filestat_t, filetype) == 16, "witx calculated offset"); +_Static_assert(offsetof(__wasi_filestat_t, nlink) == 24, "witx calculated offset"); +_Static_assert(offsetof(__wasi_filestat_t, size) == 32, "witx calculated offset"); +_Static_assert(offsetof(__wasi_filestat_t, atim) == 40, "witx calculated offset"); +_Static_assert(offsetof(__wasi_filestat_t, mtim) == 48, "witx calculated offset"); +_Static_assert(offsetof(__wasi_filestat_t, ctim) == 56, "witx calculated offset"); + +/** + * User-provided value that may be attached to objects that is retained when + * extracted from the implementation. + */ +typedef uint64_t __wasi_userdata_t; + +_Static_assert(sizeof(__wasi_userdata_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_userdata_t) == 8, "witx calculated align"); + +/** + * Type of a subscription to an event or its occurrence. + */ +typedef uint8_t __wasi_eventtype_t; + +/** + * The time value of clock `subscription_clock::id` has + * reached timestamp `subscription_clock::timeout`. + */ +#define __WASI_EVENTTYPE_CLOCK (UINT8_C(0)) + +/** + * File descriptor `subscription_fd_readwrite::file_descriptor` has data + * available for reading. This event always triggers for regular files. + */ +#define __WASI_EVENTTYPE_FD_READ (UINT8_C(1)) + +/** + * File descriptor `subscription_fd_readwrite::file_descriptor` has capacity + * available for writing. This event always triggers for regular files. + */ +#define __WASI_EVENTTYPE_FD_WRITE (UINT8_C(2)) + +_Static_assert(sizeof(__wasi_eventtype_t) == 1, "witx calculated size"); +_Static_assert(_Alignof(__wasi_eventtype_t) == 1, "witx calculated align"); + +/** + * The state of the file descriptor subscribed to with + * `eventtype::fd_read` or `eventtype::fd_write`. + */ +typedef uint16_t __wasi_eventrwflags_t; + +/** + * The peer of this socket has closed or disconnected. + */ +#define __WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP ((__wasi_eventrwflags_t)(1 << 0)) + +/** + * The contents of an `event` when type is `eventtype::fd_read` or + * `eventtype::fd_write`. + */ +typedef struct __wasi_event_fd_readwrite_t { + /** + * The number of bytes available for reading or writing. + */ + __wasi_filesize_t nbytes; + + /** + * The state of the file descriptor. + */ + __wasi_eventrwflags_t flags; + +} __wasi_event_fd_readwrite_t; + +_Static_assert(sizeof(__wasi_event_fd_readwrite_t) == 16, "witx calculated size"); +_Static_assert(_Alignof(__wasi_event_fd_readwrite_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_event_fd_readwrite_t, nbytes) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_event_fd_readwrite_t, flags) == 8, "witx calculated offset"); + +/** + * An event that occurred. + */ +typedef struct __wasi_event_t { + /** + * User-provided value that got attached to `subscription::userdata`. + */ + __wasi_userdata_t userdata; + + /** + * If non-zero, an error that occurred while processing the subscription request. + */ + __wasi_errno_t error; + + /** + * The type of event that occured + */ + __wasi_eventtype_t type; + + /** + * The contents of the event, if it is an `eventtype::fd_read` or + * `eventtype::fd_write`. `eventtype::clock` events ignore this field. + */ + __wasi_event_fd_readwrite_t fd_readwrite; + +} __wasi_event_t; + +_Static_assert(sizeof(__wasi_event_t) == 32, "witx calculated size"); +_Static_assert(_Alignof(__wasi_event_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_event_t, userdata) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_event_t, error) == 8, "witx calculated offset"); +_Static_assert(offsetof(__wasi_event_t, type) == 10, "witx calculated offset"); +_Static_assert(offsetof(__wasi_event_t, fd_readwrite) == 16, "witx calculated offset"); + +/** + * Flags determining how to interpret the timestamp provided in + * `subscription_clock::timeout`. + */ +typedef uint16_t __wasi_subclockflags_t; + +/** + * If set, treat the timestamp provided in + * `subscription_clock::timeout` as an absolute timestamp of clock + * `subscription_clock::id`. If clear, treat the timestamp + * provided in `subscription_clock::timeout` relative to the + * current time value of clock `subscription_clock::id`. + */ +#define __WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME ((__wasi_subclockflags_t)(1 << 0)) + +/** + * The contents of a `subscription` when type is `eventtype::clock`. + */ +typedef struct __wasi_subscription_clock_t { + /** + * The clock against which to compare the timestamp. + */ + __wasi_clockid_t id; + + /** + * The absolute or relative timestamp. + */ + __wasi_timestamp_t timeout; + + /** + * The amount of time that the implementation may wait additionally + * to coalesce with other events. + */ + __wasi_timestamp_t precision; + + /** + * Flags specifying whether the timeout is absolute or relative + */ + __wasi_subclockflags_t flags; + +} __wasi_subscription_clock_t; + +_Static_assert(sizeof(__wasi_subscription_clock_t) == 32, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_clock_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_clock_t, id) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, timeout) == 8, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, precision) == 16, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_clock_t, flags) == 24, "witx calculated offset"); + +/** + * The contents of a `subscription` when type is type is + * `eventtype::fd_read` or `eventtype::fd_write`. + */ +typedef struct __wasi_subscription_fd_readwrite_t { + /** + * The file descriptor on which to wait for it to become ready for reading or writing. + */ + __wasi_fd_t file_descriptor; + +} __wasi_subscription_fd_readwrite_t; + +_Static_assert(sizeof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_fd_readwrite_t) == 4, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_fd_readwrite_t, file_descriptor) == 0, "witx calculated offset"); + +/** + * The contents of a `subscription`. + */ +typedef union __wasi_subscription_u_u_t { + __wasi_subscription_clock_t clock; + __wasi_subscription_fd_readwrite_t fd_read; + __wasi_subscription_fd_readwrite_t fd_write; +} __wasi_subscription_u_u_t; +typedef struct __wasi_subscription_u_t { + uint8_t tag; + __wasi_subscription_u_u_t u; +} __wasi_subscription_u_t; + +_Static_assert(sizeof(__wasi_subscription_u_t) == 40, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_u_t) == 8, "witx calculated align"); + +/** + * Subscription to an event. + */ +typedef struct __wasi_subscription_t { + /** + * User-provided value that is attached to the subscription in the + * implementation and returned through `event::userdata`. + */ + __wasi_userdata_t userdata; + + /** + * The type of the event to which to subscribe, and its contents + */ + __wasi_subscription_u_t u; + +} __wasi_subscription_t; + +_Static_assert(sizeof(__wasi_subscription_t) == 48, "witx calculated size"); +_Static_assert(_Alignof(__wasi_subscription_t) == 8, "witx calculated align"); +_Static_assert(offsetof(__wasi_subscription_t, userdata) == 0, "witx calculated offset"); +_Static_assert(offsetof(__wasi_subscription_t, u) == 8, "witx calculated offset"); + +/** + * Exit code generated by a process when exiting. + */ +typedef uint32_t __wasi_exitcode_t; + +_Static_assert(sizeof(__wasi_exitcode_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_exitcode_t) == 4, "witx calculated align"); + +/** + * Signal condition. + */ +typedef uint8_t __wasi_signal_t; + +/** + * No signal. Note that POSIX has special semantics for `kill(pid, 0)`, + * so this value is reserved. + */ +#define __WASI_SIGNAL_NONE (UINT8_C(0)) + +/** + * Hangup. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_HUP (UINT8_C(1)) + +/** + * Terminate interrupt signal. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_INT (UINT8_C(2)) + +/** + * Terminal quit signal. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_QUIT (UINT8_C(3)) + +/** + * Illegal instruction. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_ILL (UINT8_C(4)) + +/** + * Trace/breakpoint trap. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_TRAP (UINT8_C(5)) + +/** + * Process abort signal. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_ABRT (UINT8_C(6)) + +/** + * Access to an undefined portion of a memory object. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_BUS (UINT8_C(7)) + +/** + * Erroneous arithmetic operation. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_FPE (UINT8_C(8)) + +/** + * Kill. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_KILL (UINT8_C(9)) + +/** + * User-defined signal 1. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_USR1 (UINT8_C(10)) + +/** + * Invalid memory reference. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_SEGV (UINT8_C(11)) + +/** + * User-defined signal 2. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_USR2 (UINT8_C(12)) + +/** + * Write on a pipe with no one to read it. + * Action: Ignored. + */ +#define __WASI_SIGNAL_PIPE (UINT8_C(13)) + +/** + * Alarm clock. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_ALRM (UINT8_C(14)) + +/** + * Termination signal. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_TERM (UINT8_C(15)) + +/** + * Child process terminated, stopped, or continued. + * Action: Ignored. + */ +#define __WASI_SIGNAL_CHLD (UINT8_C(16)) + +/** + * Continue executing, if stopped. + * Action: Continues executing, if stopped. + */ +#define __WASI_SIGNAL_CONT (UINT8_C(17)) + +/** + * Stop executing. + * Action: Stops executing. + */ +#define __WASI_SIGNAL_STOP (UINT8_C(18)) + +/** + * Terminal stop signal. + * Action: Stops executing. + */ +#define __WASI_SIGNAL_TSTP (UINT8_C(19)) + +/** + * Background process attempting read. + * Action: Stops executing. + */ +#define __WASI_SIGNAL_TTIN (UINT8_C(20)) + +/** + * Background process attempting write. + * Action: Stops executing. + */ +#define __WASI_SIGNAL_TTOU (UINT8_C(21)) + +/** + * High bandwidth data is available at a socket. + * Action: Ignored. + */ +#define __WASI_SIGNAL_URG (UINT8_C(22)) + +/** + * CPU time limit exceeded. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_XCPU (UINT8_C(23)) + +/** + * File size limit exceeded. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_XFSZ (UINT8_C(24)) + +/** + * Virtual timer expired. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_VTALRM (UINT8_C(25)) + +/** + * Profiling timer expired. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_PROF (UINT8_C(26)) + +/** + * Window changed. + * Action: Ignored. + */ +#define __WASI_SIGNAL_WINCH (UINT8_C(27)) + +/** + * I/O possible. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_POLL (UINT8_C(28)) + +/** + * Power failure. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_PWR (UINT8_C(29)) + +/** + * Bad system call. + * Action: Terminates the process. + */ +#define __WASI_SIGNAL_SYS (UINT8_C(30)) + +_Static_assert(sizeof(__wasi_signal_t) == 1, "witx calculated size"); +_Static_assert(_Alignof(__wasi_signal_t) == 1, "witx calculated align"); + +/** + * Flags provided to `sock_recv`. + */ +typedef uint16_t __wasi_riflags_t; + +/** + * Returns the message without removing it from the socket's receive queue. + */ +#define __WASI_RIFLAGS_RECV_PEEK ((__wasi_riflags_t)(1 << 0)) + +/** + * On byte-stream sockets, block until the full amount of data can be returned. + */ +#define __WASI_RIFLAGS_RECV_WAITALL ((__wasi_riflags_t)(1 << 1)) + +/** + * Flags returned by `sock_recv`. + */ +typedef uint16_t __wasi_roflags_t; + +/** + * Returned by `sock_recv`: Message data has been truncated. + */ +#define __WASI_ROFLAGS_RECV_DATA_TRUNCATED ((__wasi_roflags_t)(1 << 0)) + +/** + * Flags provided to `sock_send`. As there are currently no flags + * defined, it must be set to zero. + */ +typedef uint16_t __wasi_siflags_t; + +_Static_assert(sizeof(__wasi_siflags_t) == 2, "witx calculated size"); +_Static_assert(_Alignof(__wasi_siflags_t) == 2, "witx calculated align"); + +/** + * Which channels on a socket to shut down. + */ +typedef uint8_t __wasi_sdflags_t; + +/** + * Disables further receive operations. + */ +#define __WASI_SDFLAGS_RD ((__wasi_sdflags_t)(1 << 0)) + +/** + * Disables further send operations. + */ +#define __WASI_SDFLAGS_WR ((__wasi_sdflags_t)(1 << 1)) + +/** + * Identifiers for preopened capabilities. + */ +typedef uint8_t __wasi_preopentype_t; + +/** + * A pre-opened directory. + */ +#define __WASI_PREOPENTYPE_DIR (UINT8_C(0)) + +_Static_assert(sizeof(__wasi_preopentype_t) == 1, "witx calculated size"); +_Static_assert(_Alignof(__wasi_preopentype_t) == 1, "witx calculated align"); + +/** + * The contents of a $prestat when type is `preopentype::dir`. + */ +typedef struct __wasi_prestat_dir_t { + /** + * The length of the directory name for use with `fd_prestat_dir_name`. + */ + __wasi_size_t pr_name_len; + +} __wasi_prestat_dir_t; + +_Static_assert(sizeof(__wasi_prestat_dir_t) == 4, "witx calculated size"); +_Static_assert(_Alignof(__wasi_prestat_dir_t) == 4, "witx calculated align"); +_Static_assert(offsetof(__wasi_prestat_dir_t, pr_name_len) == 0, "witx calculated offset"); + +/** + * Information about a pre-opened capability. + */ +typedef union __wasi_prestat_u_t { + __wasi_prestat_dir_t dir; +} __wasi_prestat_u_t; + +typedef struct __wasi_prestat_t { + uint8_t tag; + __wasi_prestat_u_t u; +} __wasi_prestat_t; + +_Static_assert(sizeof(__wasi_prestat_t) == 8, "witx calculated size"); +_Static_assert(_Alignof(__wasi_prestat_t) == 4, "witx calculated align"); + +typedef struct wasi_options_s { + __wasi_size_t argc; + const char **argv; + const char **envp; +} wasi_options_t; + +typedef struct wasi_context_s { + __wasi_size_t argc; + char **argv; + char *argv_buf; + __wasi_size_t argv_buf_size; + __wasi_size_t envc; + char **env; + char *env_buf; + __wasi_size_t env_buf_size; +} wasi_context_t; + +/** + * Read command-line argument data. + * The size of the array should match that returned by `args_sizes_get` + */ +__wasi_errno_t wasi_snapshot_preview1_backing_args_get(wasi_context_t *context, char **argv, char *argv_buf) + __attribute__((__warn_unused_result__)); + +/** + * Return command-line argument data sizes. + * @return + * Returns the number of arguments and the size of the argument string + * data, or an error. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_args_sizes_get(wasi_context_t *context, __wasi_size_t *retptr0, __wasi_size_t *retptr1) + __attribute__((__warn_unused_result__)); +/** + * Read environment variable data. + * The sizes of the buffers should match that returned by `environ_sizes_get`. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_environ_get(wasi_context_t *context, char **environ, char *environ_buf) + __attribute__((__warn_unused_result__)); +/** + * Return environment variable data sizes. + * @return + * Returns the number of environment variable arguments and the size of the + * environment variable data. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_environ_sizes_get(wasi_context_t *context, __wasi_size_t *retptr0, + __wasi_size_t *retptr1) __attribute__((__warn_unused_result__)); +/** + * Return the resolution of a clock. + * Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, + * return `errno::inval`. + * Note: This is similar to `clock_getres` in POSIX. + * @return + * The resolution of the clock, or an error if one happened. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_clock_res_get(wasi_context_t *context, + /** + * The clock for which to return the resolution. + */ + __wasi_clockid_t id, __wasi_timestamp_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Return the time value of a clock. + * Note: This is similar to `clock_gettime` in POSIX. + * @return + * The time value of the clock. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_clock_time_get( + wasi_context_t *context, + /** + * The clock for which to return the time. + */ + __wasi_clockid_t id, + /** + * The maximum lag (exclusive) that the returned time value may have, compared to its actual value. + */ + __wasi_timestamp_t precision, __wasi_timestamp_t *retptr0) __attribute__((__warn_unused_result__)); +/** + * Provide file advisory information on a file descriptor. + * Note: This is similar to `posix_fadvise` in POSIX. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_advise(wasi_context_t *context, __wasi_fd_t fd, + /** + * The offset within the file to which the advisory applies. + */ + __wasi_filesize_t offset, + /** + * The length of the region to which the advisory applies. + */ + __wasi_filesize_t len, + /** + * The advice. + */ + __wasi_advice_t advice) __attribute__((__warn_unused_result__)); +/** + * Force the allocation of space in a file. + * Note: This is similar to `posix_fallocate` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_allocate(wasi_context_t *context, __wasi_fd_t fd, + /** + * The offset at which to start the allocation. + */ + __wasi_filesize_t offset, + /** + * The length of the area that is allocated. + */ + __wasi_filesize_t len) __attribute__((__warn_unused_result__)); +/** + * Close a file descriptor. + * Note: This is similar to `close` in POSIX. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_close(wasi_context_t *context, __wasi_fd_t fd) + __attribute__((__warn_unused_result__)); +/** + * Synchronize the data of a file to disk. + * Note: This is similar to `fdatasync` in POSIX. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_datasync(wasi_context_t *context, __wasi_fd_t fd) + __attribute__((__warn_unused_result__)); +/** + * Get the attributes of a file descriptor. + * Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields. + * @return + * The buffer where the file descriptor's attributes are stored. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_fdstat_get(wasi_context_t *context, __wasi_fd_t fd, __wasi_fdstat_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Adjust the flags associated with a file descriptor. + * Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_fdstat_set_flags(wasi_context_t *context, __wasi_fd_t fd, + /** + * The desired values of the file descriptor flags. + */ + __wasi_fdflags_t flags) __attribute__((__warn_unused_result__)); +/** + * Adjust the rights associated with a file descriptor. + * This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add + * rights + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_fdstat_set_rights(wasi_context_t *context, __wasi_fd_t fd, + /** + * The desired rights of the file descriptor. + */ + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting) + __attribute__((__warn_unused_result__)); +/** + * Return the attributes of an open file. + * @return + * The buffer where the file's attributes are stored. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_filestat_get(wasi_context_t *context, __wasi_fd_t fd, __wasi_filestat_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. + * Note: This is similar to `ftruncate` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_filestat_set_size(wasi_context_t *context, __wasi_fd_t fd, + /** + * The desired file size. + */ + __wasi_filesize_t size) __attribute__((__warn_unused_result__)); +/** + * Adjust the timestamps of an open file or directory. + * Note: This is similar to `futimens` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_filestat_set_times(wasi_context_t *context, __wasi_fd_t fd, + /** + * The desired values of the data access timestamp. + */ + __wasi_timestamp_t atim, + /** + * The desired values of the data modification timestamp. + */ + __wasi_timestamp_t mtim, + /** + * A bitmask indicating which timestamps to adjust. + */ + __wasi_fstflags_t fst_flags) + __attribute__((__warn_unused_result__)); +/** + * Read from a file descriptor, without using and updating the file descriptor's offset. + * Note: This is similar to `preadv` in POSIX. + * @return + * The number of bytes read. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_pread(wasi_context_t *context, __wasi_fd_t fd, + /** + * List of scatter/gather vectors in which to store data. + */ + const __wasi_iovec_t *iovs, + /** + * The length of the array pointed to by `iovs`. + */ + size_t iovs_len, + /** + * The offset within the file at which to read. + */ + __wasi_filesize_t offset, __wasi_size_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Return a description of the given preopened file descriptor. + * @return + * The buffer where the description is stored. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_prestat_get(wasi_context_t *context, __wasi_fd_t fd, __wasi_prestat_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Return a description of the given preopened file descriptor. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_prestat_dir_name(wasi_context_t *context, __wasi_fd_t fd, + /** + * A buffer into which to write the preopened directory name. + */ + char *path, __wasi_size_t path_len) + __attribute__((__warn_unused_result__)); +/** + * Write to a file descriptor, without using and updating the file descriptor's offset. + * Note: This is similar to `pwritev` in POSIX. + * @return + * The number of bytes written. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_pwrite(wasi_context_t *context, __wasi_fd_t fd, + /** + * List of scatter/gather vectors from which to retrieve data. + */ + const __wasi_ciovec_t *iovs, + /** + * The length of the array pointed to by `iovs`. + */ + size_t iovs_len, + /** + * The offset within the file at which to write. + */ + __wasi_filesize_t offset, __wasi_size_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Read from a file descriptor. + * Note: This is similar to `readv` in POSIX. + * @return + * The number of bytes read. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_read(wasi_context_t *context, __wasi_fd_t fd, + /** + * List of scatter/gather vectors to which to store data. + */ + const __wasi_iovec_t *iovs, + /** + * The length of the array pointed to by `iovs`. + */ + size_t iovs_len, __wasi_size_t *retptr0) __attribute__((__warn_unused_result__)); +/** + * Read directory entries from a directory. + * When successful, the contents of the output buffer consist of a sequence of + * directory entries. Each directory entry consists of a `dirent` object, + * followed by `dirent::d_namlen` bytes holding the name of the directory + * entry. + * This function fills the output buffer as much as possible, potentially + * truncating the last directory entry. This allows the caller to grow its + * read buffer size in case it's too small to fit a single large directory + * entry, or skip the oversized directory entry. + * @return + * The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has + * been reached. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_readdir(wasi_context_t *context, __wasi_fd_t fd, + /** + * The buffer where directory entries are stored + */ + uint8_t *buf, __wasi_size_t buf_len, + /** + * The location within the directory to start reading + */ + __wasi_dircookie_t cookie, __wasi_size_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Atomically replace a file descriptor by renumbering another file descriptor. + * Due to the strong focus on thread safety, this environment does not provide + * a mechanism to duplicate or renumber a file descriptor to an arbitrary + * number, like `dup2()`. This would be prone to race conditions, as an actual + * file descriptor with the same number could be allocated by a different + * thread at the same time. + * This function provides a way to atomically renumber file descriptors, which + * would disappear if `dup2()` were to be removed entirely. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_renumber(wasi_context_t *context, __wasi_fd_t fd, + /** + * The file descriptor to overwrite. + */ + __wasi_fd_t to) __attribute__((__warn_unused_result__)); +/** + * Move the offset of a file descriptor. + * Note: This is similar to `lseek` in POSIX. + * @return + * The new offset of the file descriptor, relative to the start of the file. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_seek(wasi_context_t *context, __wasi_fd_t fd, + /** + * The number of bytes to move. + */ + __wasi_filedelta_t offset, + /** + * The base from which the offset is relative. + */ + __wasi_whence_t whence, __wasi_filesize_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Synchronize the data and metadata of a file to disk. + * Note: This is similar to `fsync` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_sync(wasi_context_t *context, __wasi_fd_t fd) __attribute__((__warn_unused_result__)); +/** + * Return the current offset of a file descriptor. + * Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. + * @return + * The current offset of the file descriptor, relative to the start of the file. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_tell(wasi_context_t *context, __wasi_fd_t fd, __wasi_filesize_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Write to a file descriptor. + * Note: This is similar to `writev` in POSIX. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_fd_write(wasi_context_t *context, __wasi_fd_t fd, + /** + * List of scatter/gather vectors from which to retrieve data. + */ + const __wasi_ciovec_t *iovs, + /** + * The length of the array pointed to by `iovs`. + */ + size_t iovs_len, __wasi_size_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Create a directory. + * Note: This is similar to `mkdirat` in POSIX. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_path_create_directory(wasi_context_t *context, __wasi_fd_t fd, + /** + * The path at which to create the directory. + */ + const char *path, __wasi_size_t path_len) + __attribute__((__warn_unused_result__)); +/** + * Return the attributes of a file or directory. + * Note: This is similar to `stat` in POSIX. + * @return + * The buffer where the file's attributes are stored. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_filestat_get(wasi_context_t *context, __wasi_fd_t fd, + /** + * Flags determining the method of how the path is resolved. + */ + __wasi_lookupflags_t flags, + /** + * The path of the file or directory to inspect. + */ + const char *path, __wasi_size_t path_len, __wasi_filestat_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Adjust the timestamps of a file or directory. + * Note: This is similar to `utimensat` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_filestat_set_times(wasi_context_t *context, __wasi_fd_t fd, + /** + * Flags determining the method of how the path is resolved. + */ + __wasi_lookupflags_t flags, + /** + * The path of the file or directory to operate on. + */ + const char *path, __wasi_size_t path_len, + /** + * The desired values of the data access timestamp. + */ + __wasi_timestamp_t atim, + /** + * The desired values of the data modification timestamp. + */ + __wasi_timestamp_t mtim, + /** + * A bitmask indicating which timestamps to adjust. + */ + __wasi_fstflags_t fst_flags) + __attribute__((__warn_unused_result__)); +/** + * Create a hard link. + * Note: This is similar to `linkat` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_link(wasi_context_t *context, __wasi_fd_t old_fd, + /** + * Flags determining the method of how the path is resolved. + */ + __wasi_lookupflags_t old_flags, + /** + * The source path from which to link. + */ + const char *old_path, __wasi_size_t old_path_len, + /** + * The working directory at which the resolution of the new path starts. + */ + __wasi_fd_t new_fd, + /** + * The destination path at which to create the hard link. + */ + const char *new_path, __wasi_size_t new_path_len) + __attribute__((__warn_unused_result__)); +/** + * Open a file or directory. + * The returned file descriptor is not guaranteed to be the lowest-numbered + * file descriptor not currently open; it is randomized to prevent + * applications from depending on making assumptions about indexes, since this + * is error-prone in multi-threaded contexts. The returned file descriptor is + * guaranteed to be less than 2**31. + * Note: This is similar to `openat` in POSIX. + * @return + * The file descriptor of the file that has been opened. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_open(wasi_context_t *context, __wasi_fd_t fd, + /** + * Flags determining the method of how the path is resolved. + */ + __wasi_lookupflags_t dirflags, + /** + * The relative path of the file or directory to open, relative to the + * `path_open::fd` directory. + */ + const char *path, __wasi_size_t path_len, + /** + * The method by which to open the file. + */ + __wasi_oflags_t oflags, + /** + * The initial rights of the newly created file descriptor. The + * implementation is allowed to return a file descriptor with fewer rights + * than specified, if and only if those rights do not apply to the type of + * file being opened. + * The *base* rights are rights that will apply to operations using the file + * descriptor itself, while the *inheriting* rights are rights that apply to + * file descriptors derived from it. + */ + __wasi_rights_t fs_rights_base, __wasi_rights_t fs_rights_inheriting, + __wasi_fdflags_t fdflags, __wasi_fd_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Read the contents of a symbolic link. + * Note: This is similar to `readlinkat` in POSIX. + * @return + * The number of bytes placed in the buffer. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_readlink(wasi_context_t *context, __wasi_fd_t fd, + /** + * The path of the symbolic link from which to read. + */ + const char *path, __wasi_size_t path_len, + /** + * The buffer to which to write the contents of the symbolic link. + */ + uint8_t *buf, __wasi_size_t buf_len, __wasi_size_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Remove a directory. + * Return `errno::notempty` if the directory is not empty. + * Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_path_remove_directory(wasi_context_t *context, __wasi_fd_t fd, + /** + * The path to a directory to remove. + */ + const char *path, __wasi_size_t path_len) + __attribute__((__warn_unused_result__)); +/** + * Rename a file or directory. + * Note: This is similar to `renameat` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_rename(wasi_context_t *context, __wasi_fd_t fd, + /** + * The source path of the file or directory to rename. + */ + const char *old_path, __wasi_size_t old_path_len, + /** + * The working directory at which the resolution of the new path starts. + */ + __wasi_fd_t new_fd, + /** + * The destination path to which to rename the file or directory. + */ + const char *new_path, __wasi_size_t new_path_len) + __attribute__((__warn_unused_result__)); +/** + * Create a symbolic link. + * Note: This is similar to `symlinkat` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_symlink(wasi_context_t *context, + /** + * The contents of the symbolic link. + */ + const char *old_path, __wasi_size_t old_path_len, __wasi_fd_t fd, + /** + * The destination path at which to create the symbolic link. + */ + const char *new_path, __wasi_size_t new_path_len) + __attribute__((__warn_unused_result__)); +/** + * Unlink a file. + * Return `errno::isdir` if the path refers to a directory. + * Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_path_unlink_file(wasi_context_t *context, __wasi_fd_t fd, + /** + * The path to a file to unlink. + */ + const char *path, __wasi_size_t path_len) + __attribute__((__warn_unused_result__)); +/** + * Concurrently poll for the occurrence of a set of events. + * @return + * The number of events stored. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_poll_oneoff(wasi_context_t *context, + /** + * The events to which to subscribe. + */ + const __wasi_subscription_t *in, + /** + * The events that have occurred. + */ + __wasi_event_t *out, + /** + * Both the number of subscriptions and events. + */ + __wasi_size_t nsubscriptions, __wasi_size_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Terminate the process normally. An exit code of 0 indicates successful + * termination of the program. The meanings of other values is dependent on + * the environment. + */ +_Noreturn void wasi_snapshot_preview1_backing_proc_exit(wasi_context_t *context, + /** + * The exit code returned by the process. + */ + __wasi_exitcode_t rval); +/** + * Send a signal to the process of the calling thread. + * Note: This is similar to `raise` in POSIX. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_proc_raise(wasi_context_t *context, + /** + * The signal condition to trigger. + */ + __wasi_signal_t sig) __attribute__((__warn_unused_result__)); +/** + * Temporarily yield execution of the calling thread. + * Note: This is similar to `sched_yield` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_sched_yield(wasi_context_t *context) __attribute__((__warn_unused_result__)); +/** + * Write high-quality random data into a buffer. + * This function blocks when the implementation is unable to immediately + * provide sufficient high-quality random data. + * This function may execute slowly, so when large mounts of random data are + * required, it's advisable to use this function to seed a pseudo-random + * number generator, rather than to provide the random data directly. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_random_get(wasi_context_t *context, + /** + * The buffer to fill with random data. + */ + uint8_t *buf, __wasi_size_t buf_len) __attribute__((__warn_unused_result__)); +/** + * Receive a message from a socket. + * Note: This is similar to `recv` in POSIX, though it also supports reading + * the data into multiple buffers in the manner of `readv`. + * @return + * Number of bytes stored in ri_data and message flags. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_sock_recv(wasi_context_t *context, __wasi_fd_t fd, + /** + * List of scatter/gather vectors to which to store data. + */ + const __wasi_iovec_t *ri_data, + /** + * The length of the array pointed to by `ri_data`. + */ + size_t ri_data_len, + /** + * Message flags. + */ + __wasi_riflags_t ri_flags, __wasi_size_t *retptr0, __wasi_roflags_t *retptr1) + __attribute__((__warn_unused_result__)); +/** + * Send a message on a socket. + * Note: This is similar to `send` in POSIX, though it also supports writing + * the data from multiple buffers in the manner of `writev`. + * @return + * Number of bytes transmitted. + */ +__wasi_errno_t wasi_snapshot_preview1_backing_sock_send(wasi_context_t *context, __wasi_fd_t fd, + /** + * List of scatter/gather vectors to which to retrieve data + */ + const __wasi_ciovec_t *si_data, + /** + * The length of the array pointed to by `si_data`. + */ + size_t si_data_len, + /** + * Message flags. + */ + __wasi_siflags_t si_flags, __wasi_size_t *retptr0) + __attribute__((__warn_unused_result__)); +/** + * Shut down socket send and receive channels. + * Note: This is similar to `shutdown` in POSIX. + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_sock_shutdown(wasi_context_t *context, __wasi_fd_t fd, + /** + * Which channels on the socket to shut down. + */ + __wasi_sdflags_t how) __attribute__((__warn_unused_result__)); + + +static inline void +wasi_options_init(wasi_options_t *options) +{ + assert(options != NULL); + + options->argc = 0; + options->argv = NULL; + options->envp = NULL; +} + +void *wasi_context_init(wasi_options_t *options); +void wasi_context_destroy(wasi_context_t *handle); + +static inline __wasi_errno_t +wasi_unsupported_syscall(const char *syscall) +{ +#ifdef LOG_UNSUPPORTED_WASI + fprintf(stderr, "Syscall %s is not supported\n", syscall); +#endif + return __WASI_ERRNO_NOTSUP; +} diff --git a/runtime/include/wasi_serdes.h b/runtime/include/wasi_serdes.h new file mode 100644 index 0000000..6dfd181 --- /dev/null +++ b/runtime/include/wasi_serdes.h @@ -0,0 +1,427 @@ +#ifndef __WASI_SERDES_H__ +#define __WASI_SERDES_H__ + +/* +The serialization/deserialization logic in this file is derived from uvwasi source code +located at the following URL: +https://github.com/nodejs/uvwasi/blob/7523499546c351a1642442e6ec7bd32bcac76e2c/src/wasi_serdes.c + +It retains the the Node.js license as follows: + +MIT License +----------- + +Copyright (c) 2019 Colin Ihrig and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "wasi.h" + +/* Basic uint{8,16,32,64}_t read/write functions. */ + +#define BASIC_TYPE(name, type) \ + static inline void wasi_serdes_write_##name(void *ptr, size_t offset, type value); \ + static inline type wasi_serdes_read_##name(const void *ptr, size_t offset); + +#define BASIC_TYPE_WASI(type) BASIC_TYPE(type, __wasi_##type) + +#define WASI_SERDES_SIZE_uint8_t sizeof(uint8_t) +BASIC_TYPE(uint8_t, uint8_t) +#define WASI_SERDES_SIZE_uint16_t sizeof(uint16_t) +BASIC_TYPE(uint16_t, uint16_t) +#define WASI_SERDES_SIZE_uint32_t sizeof(uint32_t) +BASIC_TYPE(uint32_t, uint32_t) +#define WASI_SERDES_SIZE_uint64_t sizeof(uint64_t) +BASIC_TYPE(uint64_t, uint64_t) + +#define WASI_SERDES_SIZE_advice_t sizeof(__wasi_advice_t) +BASIC_TYPE_WASI(advice_t) +#define WASI_SERDES_SIZE_clockid_t sizeof(__wasi_clockid_t) +BASIC_TYPE_WASI(clockid_t) +#define WASI_SERDES_SIZE_device_t sizeof(__wasi_device_t) +BASIC_TYPE_WASI(device_t) +#define WASI_SERDES_SIZE_dircookie_t sizeof(__wasi_dircookie_t) +BASIC_TYPE_WASI(dircookie_t) +#define WASI_SERDES_SIZE_eventrwflags_t sizeof(__wasi_eventrwflags_t) +BASIC_TYPE_WASI(eventrwflags_t) +#define WASI_SERDES_SIZE_eventtype_t sizeof(__wasi_eventtype_t) +BASIC_TYPE_WASI(eventtype_t) +#define WASI_SERDES_SIZE_exitcode_t sizeof(__wasi_exitcode_t) +BASIC_TYPE_WASI(exitcode_t) +#define WASI_SERDES_SIZE_fd_t sizeof(__wasi_fd_t) +BASIC_TYPE_WASI(fd_t) +#define WASI_SERDES_SIZE_fdflags_t sizeof(__wasi_fdflags_t) +BASIC_TYPE_WASI(fdflags_t) +#define WASI_SERDES_SIZE_filesize_t sizeof(__wasi_filesize_t) +BASIC_TYPE_WASI(filesize_t) +#define WASI_SERDES_SIZE_fstflags_t sizeof(__wasi_fstflags_t) +BASIC_TYPE_WASI(fstflags_t) +#define WASI_SERDES_SIZE_inode_t sizeof(__wasi_inode_t) +BASIC_TYPE_WASI(inode_t) +#define WASI_SERDES_SIZE_linkcount_t sizeof(__wasi_linkcount_t) +BASIC_TYPE_WASI(linkcount_t) +#define WASI_SERDES_SIZE_lookupflags_t sizeof(__wasi_lookupflags_t) +BASIC_TYPE_WASI(lookupflags_t) +#define WASI_SERDES_SIZE_oflags_t sizeof(__wasi_oflags_t) +BASIC_TYPE_WASI(oflags_t) +#define WASI_SERDES_SIZE_preopentype_t sizeof(__wasi_preopentype_t) +BASIC_TYPE_WASI(preopentype_t) +#define WASI_SERDES_SIZE_riflags_t sizeof(__wasi_riflags_t) +BASIC_TYPE_WASI(riflags_t) +#define WASI_SERDES_SIZE_rights_t sizeof(__wasi_rights_t) +BASIC_TYPE_WASI(rights_t) +#define WASI_SERDES_SIZE_roflags_t sizeof(__wasi_roflags_t) +BASIC_TYPE_WASI(roflags_t) +#define WASI_SERDES_SIZE_sdflags_t sizeof(__wasi_sdflags_t) +BASIC_TYPE_WASI(sdflags_t) +#define WASI_SERDES_SIZE_siflags_t sizeof(__wasi_siflags_t) +BASIC_TYPE_WASI(siflags_t) +#define WASI_SERDES_SIZE_size_t sizeof(__wasi_size_t) +BASIC_TYPE_WASI(size_t) +#define WASI_SERDES_SIZE_inode_t sizeof(__wasi_inode_t) +BASIC_TYPE_WASI(inode_t) +#define WASI_SERDES_SIZE_signal_t sizeof(__wasi_signal_t) +BASIC_TYPE_WASI(signal_t) +#define WASI_SERDES_SIZE_subclockflags_t sizeof(__wasi_subclockflags_t) +BASIC_TYPE_WASI(subclockflags_t) +#define WASI_SERDES_SIZE_timestamp_t sizeof(__wasi_timestamp_t) +BASIC_TYPE_WASI(timestamp_t) +#define WASI_SERDES_SIZE_userdata_t sizeof(__wasi_userdata_t) +BASIC_TYPE_WASI(userdata_t) +#define WASI_SERDES_SIZE_whence_t sizeof(__wasi_whence_t) +BASIC_TYPE_WASI(whence_t) + +#undef BASIC_TYPE_WASI +#undef BASIC_TYPE + +/* WASI structure read/write functions. */ + +#define STRUCT(name) \ + void wasi_serdes_write_##name(void *ptr, size_t offset, const __wasi_##name *value); \ + void wasi_serdes_read_##name(const void *ptr, size_t offset, __wasi_##name *value); + +/* iovs currently only need to be read from WASM memory. */ +#define IOVS_STRUCT(name) \ + static inline __wasi_errno_t wasi_serdes_read_##name(const void *ptr, size_t end, size_t offset, \ + __wasi_##name *value); + +#define WASI_SERDES_SIZE_ciovec_t 8 +IOVS_STRUCT(ciovec_t) + +#define WASI_SERDES_SIZE_iovec_t 8 +IOVS_STRUCT(iovec_t) + +#define WASI_SERDES_SIZE_dirent_t 24 +STRUCT(dirent_t) + +#define WASI_SERDES_SIZE_fdstat_t 24 +STRUCT(fdstat_t) + +#define WASI_SERDES_SIZE_filestat_t 64 +STRUCT(filestat_t) + +#define WASI_SERDES_SIZE_prestat_t 8 +STRUCT(prestat_t) + +#define WASI_SERDES_SIZE_event_t 32 +STRUCT(event_t) + +#define WASI_SERDES_SIZE_subscription_t 48 +STRUCT(subscription_t) + +#undef STRUCT +#undef IOVS_STRUCT + +static inline __wasi_errno_t +wasi_serdes_readv_ciovec_t(const void *ptr, size_t end, size_t offset, __wasi_ciovec_t *iovs, __wasi_size_t iovs_len); + +static inline __wasi_errno_t +wasi_serdes_readv_iovec_t(const void *ptr, size_t end, size_t offset, __wasi_iovec_t *iovs, __wasi_size_t iovs_len); + +/* Helper functions for memory bounds checking. */ +static inline int wasi_serdes_check_bounds(size_t offset, size_t end, size_t size); +static inline int wasi_serdes_check_array_bounds(size_t offset, size_t end, size_t size, size_t count); + +static inline int +wasi_serdes_check_bounds(size_t offset, size_t end, size_t size) +{ + return end > offset && size <= (end - offset); +} + +static inline void +wasi_serdes_write_uint64_t(void *ptr, size_t offset, uint64_t value) +{ + wasi_serdes_write_uint32_t(ptr, offset, (uint32_t)value); + wasi_serdes_write_uint32_t(ptr, offset + 4, value >> 32); +} + +static inline void +wasi_serdes_write_uint32_t(void *ptr, size_t offset, uint32_t value) +{ + wasi_serdes_write_uint16_t(ptr, offset, (uint16_t)value); + wasi_serdes_write_uint16_t(ptr, offset + 2, value >> 16); +} + +static inline void +wasi_serdes_write_uint16_t(void *ptr, size_t offset, uint16_t value) +{ + wasi_serdes_write_uint8_t(ptr, offset, (uint8_t)value); + wasi_serdes_write_uint8_t(ptr, offset + 1, value >> 8); +} + +static inline void +wasi_serdes_write_uint8_t(void *ptr, size_t offset, uint8_t value) +{ + ((uint8_t *)ptr)[offset] = value; +} + +static inline uint64_t +wasi_serdes_read_uint64_t(const void *ptr, size_t offset) +{ + uint64_t low = wasi_serdes_read_uint32_t(ptr, offset); + uint64_t high = wasi_serdes_read_uint32_t(ptr, offset + 4); + return low | (high << 32); +} + +static inline uint32_t +wasi_serdes_read_uint32_t(const void *ptr, size_t offset) +{ + uint32_t low = wasi_serdes_read_uint16_t(ptr, offset); + uint32_t high = wasi_serdes_read_uint16_t(ptr, offset + 2); + return low | (high << 16); +} + +static inline uint16_t +wasi_serdes_read_uint16_t(const void *ptr, size_t offset) +{ + uint16_t low = wasi_serdes_read_uint8_t(ptr, offset); + uint16_t high = wasi_serdes_read_uint8_t(ptr, offset + 1); + return low | (high << 8); +} + +static inline uint8_t +wasi_serdes_read_uint8_t(const void *ptr, size_t offset) +{ + return ((const uint8_t *)ptr)[offset]; +} + +#define TYPE_SWITCH switch (value->type) +#define TAG_SWITCH switch (value->u.tag) + +#define ALL_TYPES(STRUCT, FIELD, ALIAS) \ + \ + ALIAS(advice_t, uint8_t) \ + ALIAS(clockid_t, uint32_t) \ + ALIAS(device_t, uint64_t) \ + ALIAS(dircookie_t, uint64_t) \ + ALIAS(errno_t, uint16_t) \ + ALIAS(eventrwflags_t, uint16_t) \ + ALIAS(eventtype_t, uint8_t) \ + ALIAS(exitcode_t, uint32_t) \ + ALIAS(fd_t, uint32_t) \ + ALIAS(fdflags_t, uint16_t) \ + ALIAS(filesize_t, uint64_t) \ + ALIAS(filetype_t, uint8_t) \ + ALIAS(fstflags_t, uint16_t) \ + ALIAS(inode_t, uint64_t) \ + ALIAS(linkcount_t, uint64_t) \ + ALIAS(lookupflags_t, uint32_t) \ + ALIAS(oflags_t, uint16_t) \ + ALIAS(preopentype_t, uint8_t) \ + ALIAS(riflags_t, uint16_t) \ + ALIAS(rights_t, uint64_t) \ + ALIAS(roflags_t, uint16_t) \ + ALIAS(sdflags_t, uint8_t) \ + ALIAS(siflags_t, uint16_t) \ + ALIAS(signal_t, uint8_t) \ + ALIAS(size_t, uint32_t) \ + ALIAS(subclockflags_t, uint16_t) \ + ALIAS(timestamp_t, uint64_t) \ + ALIAS(userdata_t, uint64_t) \ + ALIAS(whence_t, uint8_t) \ + \ + STRUCT(dirent_t) \ + { \ + FIELD(0, dircookie_t, d_next); \ + FIELD(8, inode_t, d_ino); \ + FIELD(16, uint32_t, d_namlen); \ + FIELD(20, filetype_t, d_type); \ + } \ + \ + STRUCT(fdstat_t) \ + { \ + FIELD(0, filetype_t, fs_filetype); \ + FIELD(2, fdflags_t, fs_flags); \ + FIELD(8, rights_t, fs_rights_base); \ + FIELD(16, rights_t, fs_rights_inheriting); \ + } \ + \ + STRUCT(filestat_t) \ + { \ + FIELD(0, device_t, dev); \ + FIELD(8, inode_t, ino); \ + FIELD(16, filetype_t, filetype); \ + FIELD(24, linkcount_t, nlink); \ + FIELD(32, filesize_t, size); \ + FIELD(40, timestamp_t, atim); \ + FIELD(48, timestamp_t, mtim); \ + FIELD(56, timestamp_t, ctim); \ + } \ + \ + STRUCT(prestat_t) \ + { \ + FIELD(0, preopentype_t, tag); \ + FIELD(4, uint32_t, u.dir.pr_name_len); \ + } \ + \ + STRUCT(event_t) \ + { \ + FIELD(0, userdata_t, userdata); \ + FIELD(8, errno_t, error); \ + FIELD(10, eventtype_t, type); \ + TYPE_SWITCH \ + { \ + case __WASI_EVENTTYPE_FD_READ: \ + case __WASI_EVENTTYPE_FD_WRITE: \ + FIELD(16, filesize_t, fd_readwrite.nbytes); \ + FIELD(24, eventrwflags_t, fd_readwrite.flags); \ + } \ + } \ + \ + STRUCT(subscription_t) \ + { \ + FIELD(0, userdata_t, userdata); \ + FIELD(8, eventtype_t, u.tag); \ + TAG_SWITCH \ + { \ + case __WASI_EVENTTYPE_CLOCK: \ + FIELD(16, clockid_t, u.u.clock.id); \ + FIELD(24, timestamp_t, u.u.clock.timeout); \ + FIELD(32, timestamp_t, u.u.clock.precision); \ + FIELD(40, subclockflags_t, u.u.clock.flags); \ + break; \ + case __WASI_EVENTTYPE_FD_READ: \ + FIELD(16, fd_t, u.u.fd_read.file_descriptor); \ + break; \ + case __WASI_EVENTTYPE_FD_WRITE: \ + FIELD(16, fd_t, u.u.fd_write.file_descriptor); \ + break; \ + } \ + } + +#define WRITE_STRUCT(name) void wasi_serdes_write_##name(void *ptr, size_t offset, const __wasi_##name *value) + +#define READ_STRUCT(name) void wasi_serdes_read_##name(const void *ptr, size_t offset, __wasi_##name *value) + +#define WRITE_FIELD(field_offset, type, field) \ + do { \ + wasi_serdes_write_##type(ptr, offset + field_offset, value->field); \ + } while (0) + +#define READ_FIELD(field_offset, type, field) \ + do { \ + value->field = wasi_serdes_read_##type(ptr, offset + field_offset); \ + } while (0) + +#define WRITE_ALIAS(new_name, old_name) \ + void wasi_serdes_write_##new_name(void *ptr, size_t offset, __wasi_##new_name value) \ + { \ + wasi_serdes_write_##old_name(ptr, offset, value); \ + } + +#define READ_ALIAS(new_name, old_name) \ + __wasi_##new_name wasi_serdes_read_##new_name(const void *ptr, size_t offset) \ + { \ + return wasi_serdes_read_##old_name(ptr, offset); \ + } + +ALL_TYPES(WRITE_STRUCT, WRITE_FIELD, WRITE_ALIAS) +ALL_TYPES(READ_STRUCT, READ_FIELD, READ_ALIAS) + + +static inline __wasi_errno_t +wasi_serdes_read_ciovec_t(const void *ptr, size_t end, size_t offset, __wasi_ciovec_t *value) +{ + uint32_t buf_ptr; + + buf_ptr = wasi_serdes_read_uint32_t(ptr, offset); + value->buf_len = wasi_serdes_read_size_t(ptr, offset + 4); + + if (!wasi_serdes_check_bounds(buf_ptr, end, value->buf_len)) return __WASI_ERRNO_OVERFLOW; + + value->buf = ((uint8_t *)ptr + buf_ptr); + return __WASI_ERRNO_SUCCESS; +} + + +static inline __wasi_errno_t +wasi_serdes_read_iovec_t(const void *ptr, size_t end, size_t offset, __wasi_iovec_t *value) +{ + uint32_t buf_ptr; + + buf_ptr = wasi_serdes_read_uint32_t(ptr, offset); + value->buf_len = wasi_serdes_read_size_t(ptr, offset + 4); + + if (!wasi_serdes_check_bounds(buf_ptr, end, value->buf_len)) return __WASI_ERRNO_OVERFLOW; + + value->buf = ((uint8_t *)ptr + buf_ptr); + return __WASI_ERRNO_SUCCESS; +} + + +static inline __wasi_errno_t +wasi_serdes_readv_ciovec_t(const void *ptr, size_t end, size_t offset, __wasi_ciovec_t *iovs, __wasi_size_t iovs_len) +{ + __wasi_errno_t err; + __wasi_size_t i; + + for (i = 0; i < iovs_len; i++) { + err = wasi_serdes_read_ciovec_t(ptr, end, offset, &iovs[i]); + if (err != __WASI_ERRNO_SUCCESS) return err; + offset += WASI_SERDES_SIZE_ciovec_t; + } + + return __WASI_ERRNO_SUCCESS; +} + + +static inline __wasi_errno_t +wasi_serdes_readv_iovec_t(const void *ptr, size_t end, size_t offset, __wasi_iovec_t *iovs, __wasi_size_t iovs_len) +{ + __wasi_errno_t err; + __wasi_size_t i; + + for (i = 0; i < iovs_len; i++) { + err = wasi_serdes_read_iovec_t(ptr, end, offset, &iovs[i]); + if (err != __WASI_ERRNO_SUCCESS) return err; + offset += WASI_SERDES_SIZE_iovec_t; + } + + return __WASI_ERRNO_SUCCESS; +} + +static inline int +wasi_serdes_check_array_bounds(size_t offset, size_t end, size_t size, size_t count) +{ + return end > offset && ((count * size) / size == count) && (count * size <= end - offset); +} + + +#endif /* __WASI_SERDES_H__ */ diff --git a/runtime/include/wasm_memory.h b/runtime/include/wasm_memory.h index d5f6eb3..45e48b1 100644 --- a/runtime/include/wasm_memory.h +++ b/runtime/include/wasm_memory.h @@ -37,7 +37,7 @@ static INLINE uint32_t wasm_memory_get_page_count(struct wasm_memory *wasm_memor /* Reading and writing to wasm_memory */ static INLINE void wasm_memory_initialize_region(struct wasm_memory *wasm_memory, uint32_t offset, uint32_t region_size, uint8_t region[]); -static INLINE void * wasm_memory_get_ptr_void(struct wasm_memory *wasm_memory, uint32_t offset, uint32_t size); +static INLINE void *wasm_memory_get_ptr_void(struct wasm_memory *wasm_memory, uint32_t offset, uint32_t size); static INLINE int8_t wasm_memory_get_i8(struct wasm_memory *wasm_memory, uint32_t offset); static INLINE int16_t wasm_memory_get_i16(struct wasm_memory *wasm_memory, uint32_t offset); static INLINE int32_t wasm_memory_get_i32(struct wasm_memory *wasm_memory, uint32_t offset); @@ -45,7 +45,7 @@ static INLINE int64_t wasm_memory_get_i64(struct wasm_memory *wasm_memory, uint3 static INLINE float wasm_memory_get_f32(struct wasm_memory *wasm_memory, uint32_t offset); static INLINE double wasm_memory_get_f64(struct wasm_memory *wasm_memory, uint32_t offset); static INLINE char wasm_memory_get_char(struct wasm_memory *wasm_memory, uint32_t offset); -static INLINE char * wasm_memory_get_string(struct wasm_memory *wasm_memory, uint32_t offset, uint32_t size); +static INLINE char *wasm_memory_get_string(struct wasm_memory *wasm_memory, uint32_t offset, uint32_t size); static INLINE void wasm_memory_set_i8(struct wasm_memory *wasm_memory, uint32_t offset, int8_t value); static INLINE void wasm_memory_set_i16(struct wasm_memory *wasm_memory, uint32_t offset, int16_t value); static INLINE void wasm_memory_set_i32(struct wasm_memory *wasm_memory, uint32_t offset, int32_t value); diff --git a/runtime/include/wasm_module_instance.h b/runtime/include/wasm_module_instance.h index 67592ba..837ada0 100644 --- a/runtime/include/wasm_module_instance.h +++ b/runtime/include/wasm_module_instance.h @@ -7,7 +7,10 @@ * Currently this is not spec-compliant, as it only supports a single table and a single memory and it excludes many * entities https://webassembly.github.io/spec/core/exec/runtime.html#module-instances */ + struct wasm_module_instance { /* Public */ struct sledge_abi__wasm_module_instance abi; + /* Private */ + void *wasi_context; }; diff --git a/runtime/include/wasm_stack.h b/runtime/include/wasm_stack.h index 5dd5f50..ce07100 100644 --- a/runtime/include/wasm_stack.h +++ b/runtime/include/wasm_stack.h @@ -23,9 +23,9 @@ struct wasm_stack { struct ps_list list; /* Linked List Node used for object pool */ uint64_t capacity; /* Usable capacity. Excludes size of guard page that we need to free */ - uint8_t * high; /* The highest address of the stack. Grows down from here */ - uint8_t * low; /* The address of the lowest useabe address. Above guard page */ - uint8_t * buffer; /* Points base address of backing heap allocation (Guard Page) */ + uint8_t *high; /* The highest address of the stack. Grows down from here */ + uint8_t *low; /* The address of the lowest useabe address. Above guard page */ + uint8_t *buffer; /* Points base address of backing heap allocation (Guard Page) */ }; static struct wasm_stack *wasm_stack_alloc(uint64_t capacity); diff --git a/runtime/include/wasm_table.h b/runtime/include/wasm_table.h index 70f748e..281b93c 100644 --- a/runtime/include/wasm_table.h +++ b/runtime/include/wasm_table.h @@ -4,7 +4,8 @@ #include #include -#include "types.h" +#include "sledge_abi.h" +#include "wasm_types.h" /* memory also provides the table access functions */ #define INDIRECT_TABLE_SIZE (1 << 10) @@ -78,8 +79,7 @@ wasm_table_get(struct sledge_abi__wasm_table *wasm_table, uint32_t idx, uint32_t assert(idx < wasm_table->capacity); struct sledge_abi__wasm_table_entry f = wasm_table->buffer[idx]; - // FIXME: Commented out function type check because of gocr - // assert(f.type_id == type_id); + assert(f.type_id == type_id); assert(f.func_pointer != NULL); diff --git a/runtime/src/admissions_info.c b/runtime/src/admissions_info.c index 4fa6503..ae2279a 100644 --- a/runtime/src/admissions_info.c +++ b/runtime/src/admissions_info.c @@ -47,7 +47,7 @@ admissions_info_update(struct admissions_info *admissions_info, uint64_t executi uint64_t estimated_execution = perf_window_get_percentile(perf_window, admissions_info->percentile, admissions_info->control_index); admissions_info->estimate = admissions_control_calculate_estimate(estimated_execution, - admissions_info->relative_deadline); + admissions_info->relative_deadline); LOCK_UNLOCK(&admissions_info->perf_window.lock); #endif } diff --git a/runtime/src/current_sandbox.c b/runtime/src/current_sandbox.c index f28b279..879720e 100644 --- a/runtime/src/current_sandbox.c +++ b/runtime/src/current_sandbox.c @@ -10,12 +10,16 @@ #include "sandbox_set_as_complete.h" #include "sandbox_set_as_running_user.h" #include "sandbox_set_as_running_sys.h" -#include "sandbox_setup_arguments.h" #include "scheduler.h" #include "software_interrupt.h" +#include "wasi.h" thread_local struct sandbox *worker_thread_current_sandbox = NULL; +// TODO: Propagate arguments from *.json spec file +const int dummy_argc = 1; +const char *dummy_argv[] = { "Test" }; + /** * @brief Switches from an executing sandbox to the worker thread base context * @@ -80,12 +84,14 @@ current_sandbox_init() assert(sandbox != NULL); assert(sandbox->state == SANDBOX_RUNNING_SYS); - int rc = 0; + int rc = 0; + char *error_message = NULL; sandbox_open_http(sandbox); rc = sandbox_receive_request(sandbox); if (rc == -2) { + error_message = "Request size exceeded Buffer\n"; /* Request size exceeded Buffer, send 413 Payload Too Large */ client_socket_send(sandbox->client_socket_descriptor, http_header_build(413), http_header_len(413), current_sandbox_sleep); @@ -100,12 +106,22 @@ current_sandbox_init() struct module *current_module = sandbox_get_module(sandbox); module_initialize_globals(current_module); module_initialize_memory(current_module); - sandbox_setup_arguments(sandbox); + + /* Initialize WASI */ + wasi_options_t options; + wasi_options_init(&options); + options.argc = dummy_argc; + options.argv = dummy_argv; + sandbox->wasi_context = wasi_context_init(&options); + sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context; + assert(sandbox->wasi_context != NULL); + sandbox_return(sandbox); return sandbox; err: + debuglog("%s", error_message); sandbox_close_http(sandbox); generic_thread_dump_lock_overhead(); current_sandbox_exit(); @@ -161,8 +177,7 @@ void current_sandbox_start(void) { struct sandbox *sandbox = current_sandbox_init(); - struct module * current_module = sandbox_get_module(sandbox); - int32_t argument_count = 0; - sandbox->return_value = module_entrypoint(current_module, argument_count, sandbox->arguments_offset); + struct module *current_module = sandbox_get_module(sandbox); + sandbox->return_value = module_entrypoint(current_module); current_sandbox_fini(); } diff --git a/runtime/src/current_wasm_module_instance.c b/runtime/src/current_wasm_module_instance.c index 89fcdf7..5984ff2 100644 --- a/runtime/src/current_wasm_module_instance.c +++ b/runtime/src/current_wasm_module_instance.c @@ -12,6 +12,7 @@ thread_local struct wasm_module_instance sledge_abi__current_wasm_module_instanc .capacity = 0, .buffer = NULL, }, - .abi.table = NULL, - .abi.wasmg_0 = 0xDEADBEEF, + .abi.table = NULL, + .abi.wasmg_0 = 0xDEADBEEF, + .wasi_context = NULL, }; diff --git a/runtime/src/env.c b/runtime/src/env.c deleted file mode 100644 index d8bed3c..0000000 --- a/runtime/src/env.c +++ /dev/null @@ -1,158 +0,0 @@ -#include -#include -#include - -#include "arch/getcycles.h" -#include "worker_thread.h" -#include "current_sandbox.h" - -extern int32_t inner_syscall_handler(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f); - -int32_t -env_syscall_handler(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f) -{ - int32_t i = inner_syscall_handler(n, a, b, c, d, e, f); - - return i; -} - -int32_t -env___syscall(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f) -{ - return env_syscall_handler(n, a, b, c, d, e, f); -} - -void -env___unmapself(uint32_t base, uint32_t size) -{ - /* Just do some no op */ -} - -int32_t -env_a_ctz_64(uint64_t x) -{ - return __builtin_ctzll(x); -} - -INLINE void -env_a_and_64(int32_t p_off, uint64_t v) -{ - uint64_t *p = current_sandbox_get_ptr_void(p_off, sizeof(uint64_t)); - ck_pr_and_64(p, v); -} - -INLINE void -env_a_or_64(int32_t p_off, int64_t v) -{ - assert(sizeof(int64_t) == sizeof(uint64_t)); - uint64_t *p = current_sandbox_get_ptr_void(p_off, sizeof(int64_t)); - ck_pr_or_64(p, v); -} - -int32_t -env_a_cas(int32_t p_off, int32_t t, int32_t s) -{ - assert(sizeof(int32_t) == sizeof(volatile int)); - int *p = current_sandbox_get_ptr_void(p_off, sizeof(int32_t)); - - return ck_pr_cas_int(p, t, s); -} - -void -env_a_or(int32_t p_off, int32_t v) -{ - assert(sizeof(int32_t) == sizeof(volatile int)); - int *p = current_sandbox_get_ptr_void(p_off, sizeof(int32_t)); - ck_pr_or_int(p, v); -} - -int32_t -env_a_swap(int32_t x_off, int32_t v) -{ - assert(sizeof(int32_t) == sizeof(volatile int)); - int *x = current_sandbox_get_ptr_void(x_off, sizeof(int32_t)); - - int p; - do { - p = ck_pr_load_int(x); - } while (!ck_pr_cas_int(x, p, v)); - v = p; - - return v; -} - -int32_t -env_a_fetch_add(int32_t x_off, int32_t v) -{ - assert(sizeof(int32_t) == sizeof(volatile int)); - int *x = current_sandbox_get_ptr_void(x_off, sizeof(int32_t)); - return ck_pr_faa_int(x, v); -} - -void -env_a_inc(int32_t x_off) -{ - assert(sizeof(int32_t) == sizeof(volatile int)); - int *x = current_sandbox_get_ptr_void(x_off, sizeof(int32_t)); - ck_pr_inc_int(x); -} - -void -env_a_dec(int32_t x_off) -{ - assert(sizeof(int32_t) == sizeof(volatile int)); - int *x = (int *)current_sandbox_get_ptr_void(x_off, sizeof(int32_t)); - ck_pr_dec_int(x); -} - -void -env_a_store(int32_t p_off, int32_t x) -{ - assert(sizeof(int32_t) == sizeof(volatile int)); - int *p = (int *)current_sandbox_get_ptr_void(p_off, sizeof(int32_t)); - ck_pr_store_int(p, x); -} - -int -env_a_ctz_32(int32_t x) -{ - return __builtin_ctz(x); -} - -void -env_do_spin(int32_t i) -{ - ck_pr_stall(); -} - -void -env_do_crash(int32_t i) -{ - printf("crashing: %d\n", i); - assert(0); -} - -void -env_do_barrier(int32_t x) -{ - ck_pr_barrier(); -} - -/* Floating point routines */ -INLINE double -env_sin(double d) -{ - return sin(d); -} - -INLINE double -env_cos(double d) -{ - return cos(d); -} - -INLINE unsigned long long -env_getcycles(void) -{ - return __getcycles(); -} diff --git a/runtime/src/http_parser_settings.c b/runtime/src/http_parser_settings.c index 3b708e1..e09f976 100644 --- a/runtime/src/http_parser_settings.c +++ b/runtime/src/http_parser_settings.c @@ -42,7 +42,7 @@ http_parser_settings_on_url(http_parser *parser, const char *at, size_t length) int http_parser_settings_on_message_begin(http_parser *parser) { - struct sandbox * sandbox = (struct sandbox *)parser->data; + struct sandbox *sandbox = (struct sandbox *)parser->data; struct http_request *http_request = &sandbox->http_request; assert(!sandbox->http_request.message_end); @@ -70,7 +70,7 @@ http_parser_settings_on_message_begin(http_parser *parser) int http_parser_settings_on_header_field(http_parser *parser, const char *at, size_t length) { - struct sandbox * sandbox = (struct sandbox *)parser->data; + struct sandbox *sandbox = (struct sandbox *)parser->data; struct http_request *http_request = &sandbox->http_request; #ifdef LOG_HTTP_PARSER @@ -113,7 +113,7 @@ http_parser_settings_on_header_field(http_parser *parser, const char *at, size_t int http_parser_settings_on_header_value(http_parser *parser, const char *at, size_t length) { - struct sandbox * sandbox = (struct sandbox *)parser->data; + struct sandbox *sandbox = (struct sandbox *)parser->data; struct http_request *http_request = &sandbox->http_request; @@ -145,7 +145,7 @@ http_parser_settings_on_header_value(http_parser *parser, const char *at, size_t int http_parser_settings_on_header_end(http_parser *parser) { - struct sandbox * sandbox = (struct sandbox *)parser->data; + struct sandbox *sandbox = (struct sandbox *)parser->data; struct http_request *http_request = &sandbox->http_request; assert(!sandbox->http_request.message_end); @@ -160,7 +160,7 @@ http_parser_settings_on_header_end(http_parser *parser) } const size_t http_methods_len = 8; -const char * http_methods[http_methods_len] = { "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT" }; +const char *http_methods[http_methods_len] = { "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT" }; /** * http-parser callback called for HTTP Bodies @@ -174,7 +174,7 @@ const char * http_methods[http_methods_len] = { "OPTIONS", "GET", "HEAD", "POST" int http_parser_settings_on_body(http_parser *parser, const char *at, size_t length) { - struct sandbox * sandbox = (struct sandbox *)parser->data; + struct sandbox *sandbox = (struct sandbox *)parser->data; struct http_request *http_request = &sandbox->http_request; assert(sandbox->http_request.header_end); @@ -216,7 +216,7 @@ http_parser_settings_on_body(http_parser *parser, const char *at, size_t length) int http_parser_settings_on_msg_end(http_parser *parser) { - struct sandbox * sandbox = (struct sandbox *)parser->data; + struct sandbox *sandbox = (struct sandbox *)parser->data; struct http_request *http_request = &sandbox->http_request; assert(sandbox->http_request.header_end); diff --git a/runtime/src/libc/syscall.c b/runtime/src/libc/syscall.c deleted file mode 100644 index 52ea0a8..0000000 --- a/runtime/src/libc/syscall.c +++ /dev/null @@ -1,454 +0,0 @@ -/* - * This code originally came from the aWsm compiler - * It has since been updated - * https://github.com/gwsystems/aWsm/blob/master/runtime/libc/libc_backing.c - */ -#include -#include -#include -#include -#include -#include - -#include "current_sandbox.h" -#include "scheduler.h" -#include "sandbox_functions.h" -#include "worker_thread.h" -#include "wasm_module_instance.h" - -// What should we tell the child program its UID and GID are? -#define UID 0xFF -#define GID 0xFE - -// Elf auxilary vector values (see google for what those are) -#define AT_PHENT 4 -#define AT_PAGESZ 6 -#define AT_BASE 7 -#define AT_FLAGS 8 -#define AT_ENTRY 9 -#define AT_NOTELF 10 -#define AT_UID 11 -#define AT_EUID 12 -#define AT_GID 13 -#define AT_EGID 14 -#define AT_CLKTCK 17 -#define AT_SECURE 23 -#define AT_BASE_PLATFORM 24 -#define AT_RANDOM 25 - -// offset = a WASM ptr to memory the runtime can use -void -stub_init(int32_t offset) -{ - struct sandbox *current_sandbox = current_sandbox_get(); - // What program name will we put in the auxiliary vectors - char *program_name = current_sandbox->module->name; - // Copy the program name into WASM accessible memory - int32_t program_name_offset = offset; - strcpy(wasm_memory_get_ptr_void(current_sandbox->memory, offset, sizeof(program_name)), program_name); - offset += sizeof(program_name); - - // The construction of this is: - // evn1, env2, ..., NULL, auxv_n1, auxv_1, auxv_n2, auxv_2 ..., NULL - int32_t env_vec[] = { - // Env variables would live here, but we don't supply any - 0, - // We supply only the bare minimum AUX vectors - AT_PAGESZ, - WASM_PAGE_SIZE, - AT_UID, - UID, - AT_EUID, - UID, - AT_GID, - GID, - AT_EGID, - GID, - AT_SECURE, - 0, - AT_RANDOM, - (int32_t)rand(), // It's pretty stupid to use rand here, but w/e - 0, - }; - int32_t env_vec_offset = offset; - memcpy(wasm_memory_get_ptr_void(current_sandbox->memory, env_vec_offset, sizeof(env_vec)), env_vec, - sizeof(env_vec)); - - module_initialize_libc(current_sandbox_get()->module, env_vec_offset, program_name_offset); -} - -// Emulated syscall implementations - -// We define our own syscall numbers, because WASM uses x86_64 values even on systems that are not x86_64 -#define SYS_READ 0 - -/** - * @param filedes to read - * @param buf_offset offset into wasm linear memory - * @param nbyte number of bytes to read - * @returns returns bytes read or -errno - */ -uint32_t -wasm_read(int32_t filedes, int32_t buf_offset, int32_t nbyte) -{ - struct sandbox *current_sandbox = current_sandbox_get(); - - /* Non-blocking copy on stdin */ - if (filedes == 0) { - char * buffer = current_sandbox_get_ptr_void(buf_offset, nbyte); - struct http_request *current_request = ¤t_sandbox->http_request; - if (current_request->body_length <= 0) return 0; - int bytes_to_read = nbyte > current_request->body_length ? current_request->body_length : nbyte; - memcpy(buffer, current_request->body + current_request->body_read_length, bytes_to_read); - current_request->body_read_length += bytes_to_read; - current_request->body_length -= bytes_to_read; - return bytes_to_read; - } - - char *buf = current_sandbox_get_ptr_void(buf_offset, nbyte); - - int32_t res = 0; - while (res < nbyte) { - /* Read from the Socket */ - int32_t length_read = (int32_t)read(filedes, buf, nbyte); - if (length_read < 0) { - if (errno == EAGAIN) - current_sandbox_sleep(); - else { - /* All other errors */ - debuglog("Error reading socket %d - %s\n", filedes, strerror(errno)); - goto err; - } - } - - res += length_read; - } - -done: - return res; -err: - res = -errno; - goto done; -} - -#define SYS_WRITE 1 -int32_t -wasm_write(int32_t fd, int32_t buf_offset, int32_t buf_size) -{ - struct sandbox *s = current_sandbox_get(); - char * buffer = current_sandbox_get_ptr_void(buf_offset, buf_size); - struct vec_u8 * response = &s->response; - - if (fd == STDERR_FILENO) { write(STDERR_FILENO, buffer, buf_size); } - - if (fd == STDOUT_FILENO) { - int buffer_remaining = response->capacity - response->length; - int to_write = buffer_remaining > buf_size ? buf_size : buffer_remaining; - - if (to_write == 0) return 0; - memcpy(&response->buffer[response->length], buffer, to_write); - response->length += to_write; - - return to_write; - } - - int res = ENOTSUP; - -done: - return res; -err: - res = -errno; - goto done; -} - -#define WO_RDONLY 00 -#define WO_WRONLY 01 -#define WO_RDWR 02 -#define WO_CREAT 0100 -#define WO_EXCL 0200 -#define WO_APPEND 02000 -#define WO_RSYNC 04010000 -#define WO_DIRECTORY 0200000 -#define WO_NOFOLLOW 0400000 -#define WO_CLOEXEC 02000000 - - -#define SYS_OPEN 2 -int32_t -wasm_open(int32_t path_off, int32_t flags, int32_t mode) -{ - char *path = current_sandbox_get_string(path_off, MODULE_MAX_PATH_LENGTH); - - int res = ENOTSUP; - - return res; -} - -#define SYS_CLOSE 3 -int32_t -wasm_close(int32_t fd) -{ - // Silently disregard client requests to close STDIN, STDOUT, or STDERR - if (fd <= STDERR_FILENO) return 0; - - int res = ENOTSUP; - - return res; -} - -#define SYS_LSEEK 8 -int32_t -wasm_lseek(int32_t filedes, int32_t file_offset, int32_t whence) -{ - int32_t res = (int32_t)lseek(filedes, file_offset, whence); - - if (res == -1) return -errno; - - return res; -} - -#define SYS_MMAP 9 -uint32_t -wasm_mmap(int32_t addr, int32_t len, int32_t prot, int32_t flags, int32_t fd, int32_t offset) -{ - if (addr != 0) { - printf("parameter void *addr is not supported!\n"); - assert(0); - } - - if (fd != -1) { - printf("file mapping is not supported!\n"); - assert(0); - } - - assert(len % WASM_PAGE_SIZE == 0); - - int32_t result = wasm_memory_get_size( - (struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory); - if (wasm_memory_expand((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory, len) == -1) { - result = (uint32_t)-1; - } - - return result; -} - -#define SYS_MUNMAP 11 - -#define SYS_BRK 12 - -#define SYS_RT_SIGACTION 13 - -#define SYS_RT_SIGPROGMASK 14 - -#define SYS_IOCTL 16 -int32_t -wasm_ioctl(int32_t fd, int32_t request, int32_t data_offet) -{ - // musl libc does some ioctls to stdout, so just allow these to silently go through - // FIXME: The above is idiotic - return 0; -} - -#define SYS_READV 19 -struct wasm_iovec { - int32_t base_offset; - int32_t len; -}; - -int32_t -wasm_readv(int32_t fd, int32_t iov_offset, int32_t iovcnt) -{ - int32_t read = 0; - struct wasm_iovec *iov = current_sandbox_get_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec)); - for (int i = 0; i < iovcnt; i++) { read += wasm_read(fd, iov[i].base_offset, iov[i].len); } - - return read; -} - -#define SYS_WRITEV 20 -int32_t -wasm_writev(int32_t fd, int32_t iov_offset, int32_t iovcnt) -{ - struct sandbox *s = current_sandbox_get(); - if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { - // both 1 and 2 go to client. - int len = 0; - struct wasm_iovec *iov = current_sandbox_get_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec)); - for (int i = 0; i < iovcnt; i++) { len += wasm_write(fd, iov[i].base_offset, iov[i].len); } - - return len; - } - - // TODO: Implement below - assert(0); - - - struct wasm_iovec *iov = current_sandbox_get_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec)); - - // If we aren't on MUSL, pass writev to printf if possible -#if defined(__GLIBC__) - if (fd == 1) { - int sum = 0; - for (int i = 0; i < iovcnt; i++) { - int32_t len = iov[i].len; - void * ptr = current_sandbox_get_ptr_void(iov[i].base_offset, len); - - printf("%.*s", len, (char *)ptr); - sum += len; - } - return sum; - } -#endif - - struct iovec vecs[iovcnt]; - for (int i = 0; i < iovcnt; i++) { - int32_t len = iov[i].len; - void * ptr = current_sandbox_get_ptr_void(iov[i].base_offset, len); - vecs[i] = (struct iovec){ ptr, len }; - } - - int32_t res = (int32_t)writev(fd, vecs, iovcnt); - if (res == -1) return -errno; - - return res; -} - -#define SYS_MREMAP 25 -int32_t -wasm_mremap(int32_t offset, int32_t old_size, int32_t new_size, int32_t flags) -{ - assert(offset >= 0); - assert(offset + old_size <= INT32_MAX); - - // We do not implement compaction yet, so just return immediately if shrinking - if (new_size <= old_size) return offset; - - // If at end of linear memory, just expand and return same address - if (offset + old_size == sledge_abi__current_wasm_module_instance.abi.memory.size) { - int32_t amount_to_expand = new_size - old_size; - wasm_memory_expand((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory, - amount_to_expand); - return offset; - } - - // Otherwise allocate at end of address space and copy - int32_t new_offset = sledge_abi__current_wasm_module_instance.abi.memory.size; - wasm_memory_expand((struct wasm_memory *)&sledge_abi__current_wasm_module_instance.abi.memory, new_size); - - // Get pointer of old offset and pointer of new offset - uint8_t *linear_mem = sledge_abi__current_wasm_module_instance.abi.memory.buffer; - uint8_t *src = &linear_mem[offset]; - uint8_t *dest = &linear_mem[new_offset]; - - // Copy Values. We can use memcpy because we don't overlap - memcpy((void *)dest, (void *)src, old_size); - - return new_offset; -} - -#define SYS_MADVISE 28 - -#define SYS_GETPID 39 -uint32_t -wasm_getpid() -{ - return (uint32_t)getpid(); -} - - -#define WF_SETFD 2 -#define WF_GETSIG 11 -#define WF_SETLK 6 -#define WF_SETLKW 7 -#define SYS_SET_THREAD_AREA 205 -#define SYS_SET_TID_ADDRESS 218 -#define SYS_GET_TIME 228 -struct wasm_time_spec { - uint64_t sec; - uint32_t nanosec; -}; - -int32_t -wasm_get_time(int32_t clock_id, int32_t timespec_off) -{ - clockid_t real_clock; - switch (clock_id) { - case 0: - real_clock = CLOCK_REALTIME; - break; - case 1: - real_clock = CLOCK_MONOTONIC; - break; - case 2: - real_clock = CLOCK_PROCESS_CPUTIME_ID; - break; - default: - assert(0); - } - - struct wasm_time_spec *timespec = current_sandbox_get_ptr_void(timespec_off, sizeof(struct wasm_time_spec)); - - struct timespec native_timespec = { 0, 0 }; - int res = clock_gettime(real_clock, &native_timespec); - if (res == -1) return -errno; - - timespec->sec = native_timespec.tv_sec; - timespec->nanosec = native_timespec.tv_nsec; - - return res; -} - -#define SYS_EXIT 60 -#define SYS_EXIT_GROUP 231 -int32_t -wasm_exit_group(int32_t status) -{ - debuglog("Called wasm_exit_group"); - // I believe that if a sandbox called this, it would cause the runtime to exit - // exit(status); - return 0; -} - -int32_t -inner_syscall_handler(int32_t n, int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, int32_t f) -{ - switch (n) { - case SYS_READ: - return wasm_read(a, b, c); - case SYS_WRITE: - return wasm_write(a, b, c); - case SYS_WRITEV: - return wasm_writev(a, b, c); - case SYS_CLOSE: - return wasm_close(a); - case SYS_LSEEK: - return wasm_lseek(a, b, c); - case SYS_EXIT: - case SYS_EXIT_GROUP: - return wasm_exit_group(a); - case SYS_MMAP: - return wasm_mmap(a, b, c, d, e, f); - case SYS_GET_TIME: - return wasm_get_time(a, b); - case SYS_READV: - return wasm_readv(a, b, c); - case SYS_MUNMAP: - case SYS_IOCTL: - case SYS_SET_THREAD_AREA: - case SYS_SET_TID_ADDRESS: - case SYS_BRK: - case SYS_MREMAP: - return wasm_mremap(a, b, c, b); - case SYS_MADVISE: - /* Note: These are called, but are unimplemented and fail silently */ - return 0; - case SYS_RT_SIGACTION: - case SYS_RT_SIGPROGMASK: - default: - /* This is a general catch all for the other functions below */ - debuglog("Call to unknown or implemented syscall %d\n", n); - debuglog("syscall %d (%d, %d, %d, %d, %d, %d)\n", n, a, b, c, d, e, f); - errno = ENOSYS; - return -1; - } -} diff --git a/runtime/src/libc/wasi_impl_serverless.c b/runtime/src/libc/wasi_impl_serverless.c new file mode 100644 index 0000000..33fb83f --- /dev/null +++ b/runtime/src/libc/wasi_impl_serverless.c @@ -0,0 +1,1200 @@ +/* TODO: Validate header usage */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "current_sandbox.h" +#include "sandbox_types.h" +#include "wasi.h" + +/* Return abstract handle */ +void * +wasi_context_init(wasi_options_t *options) +{ + /* TODO: Add default types */ + assert(options != NULL); + + wasi_context_t *wasi_context = (wasi_context_t *)malloc(sizeof(wasi_context_t)); + + if (options->argc > 0) { + assert(options->argv != NULL); + + /* Strip path from first arg, calculating offset and length */ + size_t first_arg_offset = 0; + size_t first_arg_len = 0; + for (first_arg_offset = strlen(options->argv[0]); first_arg_offset > 0; first_arg_offset--) { + if (options->argv[0][first_arg_offset] == '/') { + first_arg_offset++; + break; + } + } + first_arg_len = strlen(options->argv[0]) - first_arg_offset; + + /* Calculate argument buffer size */ + __wasi_size_t argv_buf_size = 0; + __wasi_size_t argv_buffer_offsets[options->argc + 1]; + for (int i = 0; i < options->argc; i++) { + argv_buffer_offsets[i] = argv_buf_size; + if (i == 0) { + argv_buf_size += first_arg_len + 1; + } else { + argv_buf_size += strlen(options->argv[i]) + 1; + } + } + argv_buffer_offsets[options->argc] = argv_buf_size; + + /* Allocate and copy argument sizes and offsets*/ + wasi_context->argc = options->argc; + wasi_context->argv = calloc(options->argc + 1, sizeof(char *)); + if (wasi_context->argv == NULL) { + fprintf(stderr, "Error allocating argv: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + wasi_context->argv_buf_size = argv_buf_size; + wasi_context->argv_buf = calloc(argv_buf_size, sizeof(char)); + if (wasi_context->argv_buf == NULL) { + fprintf(stderr, "Error allocating argv_buf: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Copy the binary name minux the path as the first arg */ + strncpy(wasi_context->argv_buf, &options->argv[0][first_arg_offset], first_arg_len); + + /* Copy the binary name minux the path as the first arg */ + for (int i = 1; i < options->argc; i++) { + strncpy(&wasi_context->argv_buf[argv_buffer_offsets[i]], options->argv[i], + argv_buffer_offsets[i + 1] - argv_buffer_offsets[i]); + } + + /* Write argv pointers from argv_buffer_offsets */ + for (int i = 0; i < options->argc; i++) { + wasi_context->argv[i] = &(wasi_context->argv_buf[argv_buffer_offsets[i]]); + } + } else { + wasi_context->argc = 0; + wasi_context->argv = NULL; + wasi_context->argv_buf_size = 0; + wasi_context->argv_buf = NULL; + } + + + /* Calculate env sizes */ + __wasi_size_t envc = 0; + __wasi_size_t env_buf_size = 0; + if (options->envp != NULL) { + for (char **environ_cursor = (char **)options->envp; *environ_cursor != NULL; environ_cursor++) { + envc++; + env_buf_size += strlen(*environ_cursor) + 1; + } + } + wasi_context->envc = envc; + + if (envc > 0) { + /* Allocate env and env_buf */ + wasi_context->env = (char **)calloc(envc, sizeof(char **)); + if (wasi_context->env == NULL) { + fprintf(stderr, "Error allocating env: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + wasi_context->env_buf_size = env_buf_size; + wasi_context->env_buf = (char *)calloc(env_buf_size, sizeof(char)); + if (wasi_context->env_buf == NULL) { + fprintf(stderr, "Error allocating env_buf: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Write env and env_buf */ + __wasi_size_t env_buf_written = 0; + for (int i = 0; i < envc; i++) { + wasi_context->env[i] = &(wasi_context->env_buf[env_buf_written]); + strcpy(wasi_context->env[i], options->envp[i]); + env_buf_written += (strlen(options->envp[i]) + 1); + } + } + + /* Seed Random */ + srandom(time(NULL)); + + /* TODO: Preopens */ + + return wasi_context; +} + +void +wasi_context_destroy(wasi_context_t *context) +{ + free(context->argv); + free(context->argv_buf); + free(context->env); + free(context->env_buf); + free(context); +} + +/* WASI API implementations */ + +/** + * @brief Converts POSIX status codes to WASI + * + * @param errno_ + * @return wasi_errno_t + */ +static __wasi_errno_t +wasi_fromerrno(int errno_) +{ + switch (errno_) { + case 0: + return __WASI_ERRNO_SUCCESS; + case E2BIG: + return __WASI_ERRNO_2BIG; + case EACCES: + return __WASI_ERRNO_ACCES; + case EADDRINUSE: + return __WASI_ERRNO_ADDRINUSE; + case EADDRNOTAVAIL: + return __WASI_ERRNO_ADDRNOTAVAIL; + case EAFNOSUPPORT: + return __WASI_ERRNO_AFNOSUPPORT; + case EAGAIN: + return __WASI_ERRNO_AGAIN; + case EALREADY: + return __WASI_ERRNO_ALREADY; + case EBADF: + return __WASI_ERRNO_BADF; + case EBADMSG: + return __WASI_ERRNO_BADMSG; + case EBUSY: + return __WASI_ERRNO_BUSY; + case ECANCELED: + return __WASI_ERRNO_CANCELED; + case ECHILD: + return __WASI_ERRNO_CHILD; + case ECONNABORTED: + return __WASI_ERRNO_CONNABORTED; + case ECONNREFUSED: + return __WASI_ERRNO_CONNREFUSED; + case ECONNRESET: + return __WASI_ERRNO_CONNRESET; + case EDEADLK: + return __WASI_ERRNO_DEADLK; + case EDESTADDRREQ: + return __WASI_ERRNO_DESTADDRREQ; + case EDOM: + return __WASI_ERRNO_DOM; + case EDQUOT: + return __WASI_ERRNO_DQUOT; + case EEXIST: + return __WASI_ERRNO_EXIST; + case EFAULT: + return __WASI_ERRNO_FAULT; + case EFBIG: + return __WASI_ERRNO_FBIG; + case EHOSTUNREACH: + return __WASI_ERRNO_HOSTUNREACH; + case EIDRM: + return __WASI_ERRNO_IDRM; + case EILSEQ: + return __WASI_ERRNO_ILSEQ; + case EINPROGRESS: + return __WASI_ERRNO_INPROGRESS; + case EINTR: + return __WASI_ERRNO_INTR; + case EINVAL: + return __WASI_ERRNO_INVAL; + case EIO: + return __WASI_ERRNO_IO; + case EISCONN: + return __WASI_ERRNO_ISCONN; + case EISDIR: + return __WASI_ERRNO_ISDIR; + case ELOOP: + return __WASI_ERRNO_LOOP; + case EMFILE: + return __WASI_ERRNO_MFILE; + case EMLINK: + return __WASI_ERRNO_MLINK; + case EMSGSIZE: + return __WASI_ERRNO_MSGSIZE; + case EMULTIHOP: + return __WASI_ERRNO_MULTIHOP; + case ENAMETOOLONG: + return __WASI_ERRNO_NAMETOOLONG; + case ENETDOWN: + return __WASI_ERRNO_NETDOWN; + case ENETRESET: + return __WASI_ERRNO_NETRESET; + case ENETUNREACH: + return __WASI_ERRNO_NETUNREACH; + case ENFILE: + return __WASI_ERRNO_NFILE; + case ENOBUFS: + return __WASI_ERRNO_NOBUFS; + case ENODEV: + return __WASI_ERRNO_NODEV; + case ENOENT: + return __WASI_ERRNO_NOENT; + case ENOEXEC: + return __WASI_ERRNO_NOEXEC; + case ENOLCK: + return __WASI_ERRNO_NOLCK; + case ENOLINK: + return __WASI_ERRNO_NOLINK; + case ENOMEM: + return __WASI_ERRNO_NOMEM; + case ENOMSG: + return __WASI_ERRNO_NOMSG; + case ENOPROTOOPT: + return __WASI_ERRNO_NOPROTOOPT; + case ENOSPC: + return __WASI_ERRNO_NOSPC; + case ENOSYS: + return __WASI_ERRNO_NOSYS; + case ENOTCONN: + return __WASI_ERRNO_NOTCONN; + case ENOTDIR: + return __WASI_ERRNO_NOTDIR; + case ENOTEMPTY: + return __WASI_ERRNO_NOTEMPTY; + case ENOTRECOVERABLE: + return __WASI_ERRNO_NOTRECOVERABLE; + case ENOTSOCK: + return __WASI_ERRNO_NOTSOCK; + case ENOTSUP: + return __WASI_ERRNO_NOTSUP; + case ENOTTY: + return __WASI_ERRNO_NOTTY; + case ENXIO: + return __WASI_ERRNO_NXIO; + case EOVERFLOW: + return __WASI_ERRNO_OVERFLOW; + case EOWNERDEAD: + return __WASI_ERRNO_OWNERDEAD; + case EPERM: + return __WASI_ERRNO_PERM; + case EPIPE: + return __WASI_ERRNO_PIPE; + case EPROTO: + return __WASI_ERRNO_PROTO; + case EPROTONOSUPPORT: + return __WASI_ERRNO_PROTONOSUPPORT; + case EPROTOTYPE: + return __WASI_ERRNO_PROTOTYPE; + case ERANGE: + return __WASI_ERRNO_RANGE; + case EROFS: + return __WASI_ERRNO_ROFS; + case ESPIPE: + return __WASI_ERRNO_SPIPE; + case ESRCH: + return __WASI_ERRNO_SRCH; + case ESTALE: + return __WASI_ERRNO_STALE; + case ETIMEDOUT: + return __WASI_ERRNO_TIMEDOUT; + case ETXTBSY: + return __WASI_ERRNO_TXTBSY; + case EXDEV: + return __WASI_ERRNO_XDEV; + default: + fprintf(stderr, "wasi_fromerrno unexpectedly received: %s\n", strerror(errno_)); + fflush(stderr); + } + + assert(0); + return 0; +} + +/** + * @brief Writes argument offsets and buffer into linear memory + * Callers of this syscall only provide the base address of the two buffers because the WASI specification + * assumes that the caller first called args_sizes_get and sized the buffers appropriately. + * + * @param argv_retptr + * @param argv_buf_retptr + * @return __WASI_ERRNO_SUCCESS or WASI_EINVAL + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_args_get(wasi_context_t *context, char **argv, char *argv_buf) +{ + if (context == NULL || argv == NULL || argv_buf == NULL) return __WASI_ERRNO_INVAL; + + if (context->argc > 0) memcpy(argv_buf, context->argv_buf, context->argv_buf_size); + + for (__wasi_size_t i = 0; i < context->argc; i++) { + __wasi_size_t offset = context->argv[i] - context->argv_buf; + argv[i] = &argv_buf[context->argv[i] - context->argv_buf]; + } + + + return __WASI_ERRNO_SUCCESS; +} + +/** + * @brief Writes the argument count and size of the requried argument buffer + * This is called in order to size buffers that are subsequently passed to the WASI args_get syscall + * + * @param argc_retptr linear memory offset where we should write argc + * @param argv_buf_len_retptr linear memory offset where we should write the length of the args buffer + * @return __WASI_ERRNO_SUCCESS + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_args_sizes_get(wasi_context_t *context, __wasi_size_t *argc_retptr, + __wasi_size_t *argv_buf_len_retptr) +{ + if (context == NULL || argc_retptr == NULL || argv_buf_len_retptr == NULL) return __WASI_ERRNO_INVAL; + + // TODO: Delete after refactoring args logic + // fprintf(stderr, "argc: %d\n", wasi_context->argc); + // fprintf(stderr, "argv_buf_size: %d\n", wasi_context->argv_buf_size); + + *argc_retptr = context->argc; + *argv_buf_len_retptr = context->argv_buf_size; + return __WASI_ERRNO_SUCCESS; +} + +/** + * @brief Return the resolution of a clock + * Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, + * return `errno::inval`. + * + * @param id The clock for which to return the resolution. + * @param res_retptr - The resolution of the clock + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_clock_res_get(wasi_context_t *context, __wasi_clockid_t id, + __wasi_timestamp_t *res_retptr) +{ + /* similar to `clock_getres` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return the time value of a clock + * + * @param clock_id The clock for which to return the time. + * @param precision The maximum lag (exclusive) that the returned time value may have, compared to its actual value. + * @param time_retptr The time value of the clock. + * @return __WASI_ERRNO_SUCCESS code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_clock_time_get(wasi_context_t *context, __wasi_clockid_t clock_id, + __wasi_timestamp_t precision, __wasi_timestamp_t *time_retptr) +{ + struct timespec tp; + int rc = clock_gettime(clock_id, &tp); + if (rc == -1) { return wasi_fromerrno(errno); } + + *time_retptr = (uint64_t)tp.tv_sec * 1000000000ULL + (uint64_t)tp.tv_nsec; + + return __WASI_ERRNO_SUCCESS; +} + +/** + * Read environment variable data. + * Callers of this syscall only provide the base address of the two buffers because the WASI specification + * assumes that the caller first called environ_sizes_get and sized the buffers appropriately. + * + * @param environ_baseretptr + * @param environ_buf_baseretptr + * @return __WASI_ERRNO_SUCCESS or WASI_EINVAL + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_environ_get(wasi_context_t *context, char **environ, char *environ_buf) +{ + if (context == NULL || environ == NULL || environ_buf == NULL) return __WASI_ERRNO_INVAL; + + for (__wasi_size_t i = 0; i < context->envc; i++) { + environ[i] = context->env_buf + (context->env[i] - context->env_buf); + } + + memcpy(environ_buf, context->env_buf, context->env_buf_size); + return __WASI_ERRNO_SUCCESS; +} + +/** + * Returns the environment variable count and the buffer size needed to store the environment strings in linear memory. + * This is called in order to size buffers that are subsequently passed to the WASI environ_get syscall + * + * @param environ_len - the pointer where the resulting number of environment variable arguments should be written + * @param environ_buf_len - the pointer where the resulting size of the environment variable data should be + * written + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_environ_sizes_get(wasi_context_t *context, __wasi_size_t *environ_len, + __wasi_size_t *environ_buf_len) +{ + if (context == NULL || environ_len == NULL || environ_buf_len == NULL) return __WASI_ERRNO_INVAL; + + *environ_len = context->envc; + *environ_buf_len = context->env_buf_size; + + return __WASI_ERRNO_SUCCESS; +} + +/** + * Provide file advisory information on a file descriptor. + * + * @param fd + * @param offset The offset within the file to which the advisory applies. + * @param len The length of the region to which the advisory applies. + * @param advice + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_advise(wasi_context_t *context, __wasi_fd_t fd, __wasi_filesize_t offset, + __wasi_filesize_t len, __wasi_advice_t advice) +{ + /* similar to `posix_fadvise` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Force the allocation of space in a file. + * + * @param fd + * @param offset The offset at which to start the allocation. + * @param len The length of the area that is allocated. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_allocate(wasi_context_t *context, __wasi_fd_t fd, __wasi_filesize_t offset, + __wasi_filesize_t len) +{ + /* similar to `posix_fallocate` in POSIX. */ + return wasi_unsupported_syscall(__func__); +}; + +/** + * Close a file descriptor. + * + * @param fd + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_close(wasi_context_t *context, __wasi_fd_t fd) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Synchronize the data of a file to disk. + * + * @param fd + * @return __WASI_ERRNO_SUCCESS, WASI_EBADF, WASI_EIO, WASI_ENOSPC, WASI_EROFS, WASI_EINVAL, WASI_ENOSPC, WASI_EDQUOT + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_datasync(wasi_context_t *context, __wasi_fd_t fd) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Get the attributes of a file descriptor. + * + * @param fd + * @param fdstat_retptr the offset where the resulting wasi_fdstat structure should be written + * @return __WASI_ERRNO_SUCCESS, WASI_EACCES, WASI_EAGAIN, WASI_EBADF, WASI_EFAULT, WASI_EINVAL, WASI_ELOOP, + * WASI_ENAMETOOLONG, WASI_ENOTDIR, WASI_ENOENT, WASI_ENOMEM, or WASI_EOVERFLOW + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_fdstat_get(wasi_context_t *context, __wasi_fd_t fd, __wasi_fdstat_t *fdstat) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the flags associated with a file descriptor + * + * @param fd + * @param fdflags The desired values of the file descriptor flags. + * @return __WASI_ERRNO_SUCCESS, WASI_EACCES, WASI_EAGAIN, WASI_EBADF, WASI_EFAULT, WASI_EINVAL, WASI_ENOENT, or + * WASI_EPERM + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_fdstat_set_flags(wasi_context_t *context, __wasi_fd_t fd, __wasi_fdflags_t fdflags) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the rights associated with a file descriptor. + * This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add + * rights + * + * @param fd + * @param fs_rights_base The desired rights of the file descriptor. + * @param fs_rights_inheriting + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_fdstat_set_rights(wasi_context_t *context, __wasi_fd_t fd, + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return the attributes of an open file. + * + * @param fd + * @param filestat_retptr The buffer where we should store the file's attributes + * @return status code + */ + +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_filestat_get(wasi_context_t *context, __wasi_fd_t fd, __wasi_filestat_t *filestat) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the size of an open file, zeroing extra bytes on increase + * + * @param fd + * @param size The desired file size. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_filestat_set_size(wasi_context_t *context, __wasi_fd_t fd, __wasi_filesize_t size) +{ + /* similar to `ftruncate` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the timestamps of an open file or directory + * + * @param fd + * @param atim The desired values of the data access timestamp. + * @param mtim The desired values of the data modification timestamp. + * @param fst_flags A bitmask indicating which timestamps to adjust. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_filestat_set_times(wasi_context_t *context, __wasi_fd_t fd, __wasi_timestamp_t atim, + __wasi_timestamp_t mtim, __wasi_fstflags_t fst_flags) +{ + /* similar to `futimens` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Read from a file descriptor without updating the descriptor's offset + * + * @param fd + * @param iovs_baseptr List of scatter/gather vectors in which to store data. + * @param iovs_len The length of the array pointed to by `iovs`. + * @param offset The offset within the file at which to read. + * @param nread_retptr The number of bytes read. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_pread(wasi_context_t *context, __wasi_fd_t fd, const __wasi_iovec_t *iovs, + size_t iovs_len, __wasi_filesize_t offset, __wasi_size_t *nread_retptr) +{ + /* similar to `preadv` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return a description of the given preopened file descriptor. + * + * @param fd + * @param prestat_retptr The buffer where the description is stored. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_prestat_get(wasi_context_t *context, __wasi_fd_t fd, __wasi_prestat_t *prestat_retptr) +{ + /* This signals that there are no file descriptors */ + return __WASI_ERRNO_BADF; +} + +/** + * Return a description of the given preopened file descriptor. + * + * @param fd + * @param path_retptr A buffer into which to write the preopened directory name. + * @param path_len The length of the buffer at path_retptr + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_prestat_dir_name(wasi_context_t *context, __wasi_fd_t fd, char *path, + __wasi_size_t path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Write to a file descriptor without updating the descriptor's offset + * + * @param fd + * @param iovs_baseptr List of scatter/gather vectors from which to retrieve data. + * @param iovs_len The length of the array pointed to by `iovs`. + * @param offset The offset within the file at which to write. + * @param nwritten_retptr The number of bytes written. + * @return status code + * + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_pwrite(wasi_context_t *context, __wasi_fd_t fd, const __wasi_ciovec_t *iovs, + size_t iovs_len, __wasi_filesize_t offset, __wasi_size_t *nwritten_retptr) +{ + /* similar to `pwritev` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Read from a file descriptor + * + * @param fd + * @param iovs_baseptr + * @param iovs_len + * @param nwritten_retptr The number of bytes read. + * @return __WASI_ERRNO_SUCCESS, WASI_EAGAIN, WASI_EWOULDBLOCK, WASI_EBADF, WASI_EFAULT, WASI_EINTR, WASI_EIO, + * WASI_EISDIR, or others + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_read(wasi_context_t *context, __wasi_fd_t fd, const __wasi_iovec_t *iovs, + size_t iovs_len, __wasi_size_t *nwritten_retptr) +{ + /* Non-blocking copy on stdin */ + if (fd == STDIN_FILENO) { + struct sandbox *current_sandbox = current_sandbox_get(); + struct http_request *current_request = ¤t_sandbox->http_request; + int old_read = current_request->body_read_length; + int bytes_to_read = current_request->body_length - old_read; + + for (int i = 0; i < iovs_len; i++) { + if (bytes_to_read == 0) goto done; + + int amount_to_copy = iovs[i].buf_len > bytes_to_read ? bytes_to_read : iovs[i].buf_len; + memcpy(iovs[i].buf, current_request->body + current_request->body_read_length, amount_to_copy); + current_request->body_read_length += amount_to_copy; + bytes_to_read = current_request->body_length - current_request->body_read_length; + } + + done: + *nwritten_retptr = current_request->body_read_length - old_read; + return __WASI_ERRNO_SUCCESS; + } + + fprintf(stderr, "Attempted to read from fd %d, but we only support STDIN\n", fd); + return wasi_unsupported_syscall(__func__); +} + +/** + * Read directory entries from a directory. + * When successful, the contents of the output buffer consist of a sequence of + * directory entries. Each directory entry consists of a `dirent` object, + * followed by `dirent::d_namlen` bytes holding the name of the directory entry. + * This function fills the output buffer as much as possible, potentially + * truncating the last directory entry. This allows the caller to grow its + * read buffer size in case it's too small to fit a single large directory + * entry, or skip the oversized directory entry. + * + * @param fd + * @param buf_baseptr The buffer where directory entries are stored + * @param buf_len + * @param cookie The location within the directory to start reading + * @param nwritten_retptr The number of bytes stored in the read buffer. If less than the size of the read buffer, the + * end of the directory has been reached. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_readdir(wasi_context_t *context, __wasi_fd_t fd, uint8_t *buf, __wasi_size_t buf_len, + __wasi_dircookie_t cookie, __wasi_size_t *nwritten_retptr) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Atomically replace a file descriptor by renumbering another file descriptor. + * Due to the strong focus on thread safety, this environment does not provide + * a mechanism to duplicate or renumber a file descriptor to an arbitrary + * number, like `dup2()`. This would be prone to race conditions, as an actual + * file descriptor with the same number could be allocated by a different + * thread at the same time. + * This function provides a way to atomically renumber file descriptors, which + * would disappear if `dup2()` were to be removed entirely. + * + * @param fd + * @param to the file descriptor to overwrite + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_renumber(wasi_context_t *context, __wasi_fd_t fd, __wasi_fd_t to) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Move the offset of a file descriptor + * + * @param fds + * @param file_offset The number of bytes to move. + * @param whence The base from which the offset is relative. + * @param newoffset_retptr The new offset of the file descriptor, relative to the start of the file. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_seek(wasi_context_t *context, __wasi_fd_t fd, __wasi_filedelta_t file_offset, + __wasi_whence_t whence, __wasi_filesize_t *newoffset_retptr) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Synchronize the data and metadata of a file to disk + * + * @param fd + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_sync(wasi_context_t *context, __wasi_fd_t fd) +{ + /* similar to `fsync` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return the current offset of a file descriptor + * + * @param fd + * @param fileoffset_retptr The current offset of the file descriptor, relative to the start of the file. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_tell(wasi_context_t *context, __wasi_fd_t fd, __wasi_filesize_t *fileoffset_retptr) +{ + /* similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Write to a file descriptor + * + * @param fd + * @param iovs_baseptr List of scatter/gather vectors from which to retrieve data. + * @param iovs_len The length of the array pointed to by `iovs`. + * @param nwritten_retptr + * @return __WASI_ERRNO_SUCCESS, WASI_EAGAIN, WASI_EWOULDBLOCK, WASI_EBADF, WASI_EFAULT, + * WASI_EFBIG, WASI_EINTR, WASI_EIO, WASI_ENOSPC, WASI_EPERM, WASI_EPIPE, or others + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_fd_write(wasi_context_t *context, __wasi_fd_t fd, const __wasi_ciovec_t *iovs, + size_t iovs_len, __wasi_size_t *nwritten_retptr) +{ + if (fd == STDOUT_FILENO || fd == STDERR_FILENO) { + struct sandbox *s = current_sandbox_get(); + size_t buffer_remaining = 0; + size_t old_response_len = s->response.length; + __wasi_size_t sum = 0; + + for (size_t i = 0; i < iovs_len; i++) { + buffer_remaining = s->module->max_response_size - s->response.length; + if (buffer_remaining == 0) { + *nwritten_retptr = s->response.length - old_response_len; + return __WASI_ERRNO_FBIG; + } + ssize_t to_write = buffer_remaining > iovs[i].buf_len ? iovs[i].buf_len : buffer_remaining; + memcpy(&s->response.buffer[s->response.length], iovs[i].buf, to_write); +#ifdef LOG_SANDBOX_STDERR + if (fd == STDERR_FILENO) { + debuglog("STDERR from Sandbox:"); + write(2, iovs[i].buf, iovs[i].buf_len); + } +#endif + s->response.length += to_write; + } + *nwritten_retptr = s->response.length - old_response_len; + return __WASI_ERRNO_SUCCESS; + } + + fprintf(stderr, "Attempted to write to fd %d, but we only support STDOUT or STDERR\n", fd); + return wasi_unsupported_syscall(__func__); +} + +/** + * Create a directory + * + * @param fd + * @param path_baseptr + * @param path_len + * @return __WASI_ERRNO_SUCCESS, WASI_EACCES, WASI_EBADF, WASI_EDQUOT, WASI_EEXIST, + * WASI_EFAULT, WASI_EINVAL, WASI_ELOOP, WASI_EMLINK, WASI_ENAMETOOLONG, + * WASI_ENOENT, WASI_ENOMEM, WASI_ENOSPC, WASI_ENOTDIR, WASI_EPERM, or WASI_EROFS + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_create_directory(wasi_context_t *context, __wasi_fd_t fd, const char *path, + __wasi_size_t path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return the attributes of a file or directory + * + * @param fd + * @param flags Flags determining the method of how the path is resolved. + * @param path_baseptr The path of the file or directory to inspect. + * @param filestat_retptr The buffer where the file's attributes are stored. + * @return __WASI_ERRNO_SUCCESS, WASI_EACCES, WASI_EBAD, WASI_EFAUL, WASI_EINVAL, WASI_ELOOP, + * WASI_ENAMETOOLON, WASI_ENOENT, WASI_ENOENT, WASI_ENOMEM, WASI_ENOTDI, or WASI_EOVERFLOW + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_filestat_get(wasi_context_t *context, __wasi_fd_t fd, __wasi_lookupflags_t flags, + const char *path, __wasi_size_t path_len, + __wasi_filestat_t *const filestat) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the timestamps of a file or directory + * + * @param fd + * @param flags Flags determining the method of how the path is resolved. + * @param path_baseptr The path of the file or directory to operate on. + * @param path_len + * @param atim The desired values of the data access timestamp. + * @param mtim The desired values of the data modification timestamp. + * @param fst_flags A bitmask indicating which timestamps to adjust. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_filestat_set_times(wasi_context_t *context, __wasi_fd_t fd, + __wasi_lookupflags_t flags, const char *path, + __wasi_size_t path_len, __wasi_timestamp_t atim, + __wasi_timestamp_t mtim, __wasi_fstflags_t fst_flags) +{ + /* similar to `utimensat` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Create a hard link + * + * @param old_fd + * @param old_flags Flags determining the method of how the path is resolved. + * @param old_path_baseptr The source path from which to link. + * @param old_path_len + * @param new_fd The working directory at which the resolution of the new path starts. + * @param new_path_baseptr The destination path at which to create the hard link. + * @param new_path_len + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_link(wasi_context_t *context, __wasi_fd_t old_fd, __wasi_lookupflags_t old_flags, + const char *old_path, __wasi_size_t old_path_len, __wasi_fd_t new_fd, + const char *new_path, __wasi_size_t new_path_len) +{ + /* similar to `linkat` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Open a file or directory + * The returned file descriptor is not guaranteed to be the lowest-numbered + * file descriptor not currently open; it is randomized to prevent + * applications from depending on making assumptions about indexes, since this + * is error-prone in multi-threaded contexts. The returned file descriptor is + * guaranteed to be less than 2**31. + * + * The initial rights of the newly created file descriptor. The + * implementation is allowed to return a file descriptor with fewer rights + * than specified, if and only if those rights do not apply to the type of + * file being opened. + * The *base* rights are rights that will apply to operations using the file + * descriptor itself, while the *inheriting* rights are rights that apply to + * file descriptors derived from it. + * + * @param dirfd + * @param lookupflags Flags determining the method of how the path is resolved. + * @param path_baseptr path of the file or directory to open relative to the fd directory. + * @param path_len + * @param oflags The method by which to open the file. + * + + * + * @param fs_rights_base + * @param fs_rights_inheriting + * @param fdflags + * @param fd_off The file descriptor of the file that has been opened. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_open(wasi_context_t *context, __wasi_fd_t dirfd, __wasi_lookupflags_t dirflags, + const char *path, __wasi_size_t path_len, __wasi_oflags_t oflags, + + __wasi_rights_t fs_rights_base, __wasi_rights_t fs_rights_inheriting, + __wasi_fdflags_t fdflags, __wasi_fd_t *fd) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Read the contents of a symbolic link + * + * @param fd + * @param path_baseptr The path of the symbolic link from which to read. + * @param path_len + * @param buf_baseretptr The buffer to which to write the contents of the symbolic link. + * @param buf_len + * @param nread_retptr The number of bytes placed in the buffer. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_readlink(wasi_context_t *context, __wasi_fd_t fd, const char *path, + __wasi_size_t path_len, uint8_t *buf, __wasi_size_t buf_len, + __wasi_size_t *nread_retptr) +{ + /* similar to `readlinkat` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Remove a directory + * Return `errno::notempty` if the directory is not empty. + * + * @param fd + * @param path_baseptr The path to a directory to remove. + * @param path_len + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_remove_directory(wasi_context_t *context, __wasi_fd_t fd, const char *path, + __wasi_size_t path_len) +{ + /* similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Rename a file or directory + * + * @param fd + * @param old_path The source path of the file or directory to rename. + * @param new_fd The working directory at which the resolution of the new path starts. + * @param new_path The destination path to which to rename the file or directory. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_rename(wasi_context_t *context, __wasi_fd_t fd, const char *old_path, + __wasi_size_t old_path_len, __wasi_fd_t new_fd, const char *new_path, + __wasi_size_t new_path_len) +{ + /* similar to `renameat` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Create a symbolic link + * + * @param old_path_baseptr The contents of the symbolic link. + * @param old_path_len + * @param fd + * @param new_path_baseptr The path where we want the symbolic link. + * @param new_path_len + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_symlink(wasi_context_t *context, const char *old_path, __wasi_size_t old_path_len, + __wasi_fd_t fd, const char *new_path, __wasi_size_t new_path_len) +{ + /* similar to `symlinkat` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Unlink a file + * Return `errno::isdir` if the path refers to a directory. + * + * @param fd + * @param path_baseptr + * @param path_len + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_path_unlink_file(wasi_context_t *context, __wasi_fd_t fd, const char *path, + __wasi_size_t path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Concurrently poll for the occurrence of a set of events. + * + * @param in The events to which to subscribe. + * @param out The events that have occurred. + * @param nsubscriptions Both the number of subscriptions and events. + * @param retptr The number of events stored. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_poll_oneoff(wasi_context_t *context, const __wasi_subscription_t *in, + __wasi_event_t *out, __wasi_size_t nsubscriptions, __wasi_size_t *retptr0) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Terminate the process normally. An exit code of 0 indicates successful + * termination of the program. The meanings of other values is dependent on + * the environment. + * + * @param exitcode + */ +noreturn void +wasi_snapshot_preview1_backing_proc_exit(wasi_context_t *context, __wasi_exitcode_t exitcode) +{ + assert(0); +} + +/** + * Send a signal to the process of the calling thread. + * + * @param sig The signal condition to trigger. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_proc_raise(wasi_context_t *context, __wasi_signal_t sig) +{ + /* similar to `raise` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} + +/** + * Write high-quality random data into a buffer. + * This function blocks when the implementation is unable to immediately + * provide sufficient high-quality random data. + * This function may execute slowly, so when large mounts of random data are + * required, it's advisable to use this function to seed a pseudo-random + * number generator, rather than to provide the random data directly. + * + * @param buf_baseretptr The buffer to fill with random data. + * @param buf_len The length of the buffer + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_random_get(wasi_context_t *context, uint8_t *buf, __wasi_size_t buf_len) +{ + static bool has_udev = true; + static bool did_seed = false; + int urandom_fd; + ssize_t nread = 0; + + if (!has_udev) goto NO_UDEV; + + urandom_fd = open("/dev/urandom", O_RDONLY); + if (urandom_fd < 0) { + has_udev = false; + goto NO_UDEV; + } + + while (nread < buf_len) { + size_t rc = read(urandom_fd, buf, buf_len); + if (rc < 0) goto ERR_READ; + nread += rc; + } + + close(urandom_fd); + return __WASI_ERRNO_SUCCESS; + +ERR_READ: + close(urandom_fd); + return wasi_fromerrno(errno); +NO_UDEV: + do { + __wasi_size_t buf_cursor = 0; + for (; (buf_len - buf_cursor) >= 4; buf_cursor += 4) { *((int *)(buf + buf_cursor)) = random(); } + for (; buf_cursor < buf_len; buf_cursor += 1) { *(buf + buf_cursor) = random() % UINT8_MAX; } + } while (0); + + return __WASI_ERRNO_SUCCESS; +} + +/** + * Temporarily yield execution of the calling thread similar to `sched_yield` in POSIX. + * This implementation ignores client calls and silently returns RC 0 + * + * @return __WASI_ERRNO_SUCCESS + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_sched_yield(wasi_context_t *context) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Receive a message from a socket. + * Note: This is similar to `recv` in POSIX, though it also supports reading + * the data into multiple buffers in the manner of `readv`. + * + * @param fd + * @param ri_data_baseretptr List of scatter/gather vectors to which to store data. + * @param ri_data_len The length of the array pointed to by `ri_data`. + * @param ri_flags Message flags. + * @param ri_data_nbytes_retptr Number of bytes stored in ri_data flags. + * @param message_nbytes_retptr Number of bytes stored in message flags. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_sock_recv(wasi_context_t *context, __wasi_fd_t fd, const __wasi_iovec_t *ri_data, + size_t ri_data_len, __wasi_riflags_t ri_flags, + __wasi_size_t *ri_data_nbytes_retptr, __wasi_roflags_t *message_nbytes_retptr) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Send a message on a socket. + * Note: This is similar to `send` in POSIX, though it also supports writing + * the data from multiple buffers in the manner of `writev`. + * + * @param fd + * @param si_data_baseptr List of scatter/gather vectors to which to retrieve data + * @param si_data_len The length of the array pointed to by `si_data`. + * @param si_flags Message flags. + * @param nsent_retptr Number of bytes transmitted. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_sock_send(wasi_context_t *context, __wasi_fd_t fd, const __wasi_ciovec_t *si_data, + size_t si_data_len, __wasi_siflags_t si_flags, __wasi_size_t *nsent_retptr) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Shut down socket send and receive channels. + * + * @param fd + * @param how Which channels on the socket to shut down. + * @return status code + */ +__wasi_errno_t +wasi_snapshot_preview1_backing_sock_shutdown(wasi_context_t *context, __wasi_fd_t fd, __wasi_sdflags_t how) +{ + /* similar to `shutdown` in POSIX. */ + return wasi_unsupported_syscall(__func__); +} diff --git a/runtime/src/main.c b/runtime/src/main.c index 15c5fdf..5fbd7f1 100644 --- a/runtime/src/main.c +++ b/runtime/src/main.c @@ -334,6 +334,16 @@ log_compiletime_config() #endif } +void +check_versions() +{ + // Additional functions have become async signal safe over time. Validate latest + static_assert(_POSIX_VERSION >= 200809L, "Requires POSIX 2008 or higher\n"); + // We use C18 features + static_assert(__STDC_VERSION__ >= 201710, "Requires C18 or higher\n"); + static_assert(__linux__ == 1, "Requires epoll, a Linux-only feature"); +} + int main(int argc, char **argv) { @@ -344,6 +354,7 @@ main(int argc, char **argv) printf("Starting the Sledge runtime\n"); + log_compiletime_config(); runtime_process_debug_log_behavior(); diff --git a/runtime/src/runtime.c b/runtime/src/runtime.c index 11ac861..0637b13 100644 --- a/runtime/src/runtime.c +++ b/runtime/src/runtime.c @@ -29,7 +29,7 @@ **************************/ pthread_t *runtime_worker_threads; -int * runtime_worker_threads_argument; +int *runtime_worker_threads_argument; /* The active deadline of the sandbox running on each worker thread */ uint64_t *runtime_worker_threads_deadline; @@ -63,7 +63,7 @@ runtime_set_resource_limits_to_max() char max[uint64_t_max_digits + 1]; uint64_t resources[] = { RLIMIT_DATA, RLIMIT_NOFILE }; - char * resource_names[] = { "RLIMIT_DATA", "RLIMIT_NOFILE" }; + char *resource_names[] = { "RLIMIT_DATA", "RLIMIT_NOFILE" }; for (int i = 0; i < sizeof(resources) / sizeof(resources[0]); i++) { int resource = resources[i]; diff --git a/runtime/src/sandbox.c b/runtime/src/sandbox.c index 42f4d5a..bba061f 100644 --- a/runtime/src/sandbox.c +++ b/runtime/src/sandbox.c @@ -112,7 +112,7 @@ sandbox_prepare_execution_environment(struct sandbox *sandbox) { assert(sandbox != NULL); - char * error_message = ""; + char *error_message = ""; uint64_t now = __getcycles(); int rc; @@ -202,7 +202,8 @@ sandbox_alloc(struct module *module, int socket_descriptor, const struct sockadd { struct sandbox *sandbox = NULL; size_t page_aligned_sandbox_size = round_up_to_page(sizeof(struct sandbox)); - sandbox = calloc(1, page_aligned_sandbox_size); + sandbox = aligned_alloc(PAGE_SIZE, page_aligned_sandbox_size); + memset(sandbox, 0, page_aligned_sandbox_size); if (unlikely(sandbox == NULL)) return NULL; sandbox_set_as_allocated(sandbox); @@ -225,7 +226,6 @@ sandbox_deinit(struct sandbox *sandbox) /* Linear Memory and Guard Page should already have been munmaped and set to NULL */ assert(sandbox->memory == NULL); - /* Free Sandbox Struct*/ if (likely(sandbox->stack != NULL)) sandbox_free_stack(sandbox); if (likely(sandbox->globals.buffer != NULL)) sandbox_free_globals(sandbox); diff --git a/runtime/src/sledge_abi.c b/runtime/src/sledge_abi.c index bde6d3e..51154b1 100644 --- a/runtime/src/sledge_abi.c +++ b/runtime/src/sledge_abi.c @@ -1,14 +1,51 @@ #include "current_sandbox.h" +#include "sandbox_set_as_running_sys.h" +#include "sandbox_set_as_running_user.h" #include "sledge_abi.h" #include "wasm_memory.h" +#include "wasi.h" +#include "wasi_serdes.h" +/** + * @brief Get the memory ptr for runtime object + * + * @param offset base offset of pointer + * @param length length starting at base offset + * @return host address of offset into WebAssembly linear memory + */ +static inline char * +get_memory_ptr_for_runtime(uint32_t offset, uint32_t length) +{ + assert((uint64_t)offset + length < sledge_abi__current_wasm_module_instance.abi.memory.size); + char *mem_as_chars = (char *)sledge_abi__current_wasm_module_instance.abi.memory.buffer; + char *address = &mem_as_chars[offset]; + return address; +} + +static inline void +check_bounds(uint32_t offset, uint32_t bounds_check) +{ + // Due to how we setup memory for x86, the virtual memory mechanism will catch the error, if bounds < + // WASM_PAGE_SIZE + assert(bounds_check < WASM_PAGE_SIZE + || (sledge_abi__current_wasm_module_instance.abi.memory.size > bounds_check + && offset <= sledge_abi__current_wasm_module_instance.abi.memory.size - bounds_check)); +} + +// TODO: Don't need to pass the memory here EXPORT int32_t sledge_abi__wasm_memory_expand(struct sledge_abi__wasm_memory *wasm_memory, uint32_t page_count) { + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); int32_t old_page_count = wasm_memory->size / WASM_PAGE_SIZE; + int rc = wasm_memory_expand((struct wasm_memory *)wasm_memory, page_count * WASM_PAGE_SIZE); - int rc = wasm_memory_expand((struct wasm_memory *)wasm_memory, page_count * WASM_PAGE_SIZE); - if (unlikely(rc == -1)) return -1; + if (unlikely(rc == -1)) { + old_page_count = -1; + goto DONE; + } /* We updated "forked state" in sledge_abi__current_wasm_module_instance.memory. We need to write this back to * the original struct as well */ @@ -25,40 +62,962 @@ sledge_abi__wasm_memory_expand(struct sledge_abi__wasm_memory *wasm_memory, uint } #endif +DONE: + sandbox_return(sandbox); + return old_page_count; } +// TODO: Don't need to pass the memory here EXPORT void sledge_abi__wasm_memory_initialize_region(struct sledge_abi__wasm_memory *wasm_memory, uint32_t offset, uint32_t region_size, uint8_t region[]) { - return wasm_memory_initialize_region((struct wasm_memory *)wasm_memory, offset, region_size, region); + struct sandbox *sandbox = current_sandbox_get(); + assert(sandbox->state == SANDBOX_RUNNING_SYS); + wasm_memory_initialize_region((struct wasm_memory *)wasm_memory, offset, region_size, region); } EXPORT int32_t sledge_abi__wasm_globals_get_i32(uint32_t idx) { - struct sandbox *current = current_sandbox_get(); - return wasm_globals_get_i32(¤t->globals, idx); + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + int32_t value = wasm_globals_get_i32(&sandbox->globals, idx); + sandbox_return(sandbox); + + return value; } EXPORT int64_t sledge_abi__wasm_globals_get_i64(uint32_t idx) { - struct sandbox *current = current_sandbox_get(); - return wasm_globals_get_i64(¤t->globals, idx); + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + int64_t value = wasm_globals_get_i64(&sandbox->globals, idx); + sandbox_return(sandbox); + + return value; } EXPORT int32_t sledge_abi__wasm_globals_set_i32(uint32_t idx, int32_t value, bool is_mutable) { - struct sandbox *current = current_sandbox_get(); - return wasm_globals_set_i32(¤t->globals, idx, value, true); + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + int32_t rc = wasm_globals_set_i32(&sandbox->globals, idx, value, true); + sandbox_return(sandbox); + + return rc; } EXPORT int32_t sledge_abi__wasm_globals_set_i64(uint32_t idx, int64_t value, bool is_mutable) { - struct sandbox *current = current_sandbox_get(); - return wasm_globals_set_i64(¤t->globals, idx, value, true); + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + int32_t rc = wasm_globals_set_i64(&sandbox->globals, idx, value, true); + sandbox_return(sandbox); + + return rc; +} + +/** + * @brief Writes argument offsets and buffer into linear memory + * + * @param argv_retoffset + * @param argv_buf_retoffset + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_args_get(__wasi_size_t argv_retoffset, __wasi_size_t argv_buf_retoffset) +{ + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + + __wasi_size_t rc = 0; + const __wasi_size_t argc = sandbox->wasi_context->argc; + if (unlikely(argc == 0)) { goto done; } + + __wasi_size_t *argv_retptr = (__wasi_size_t *)get_memory_ptr_for_runtime(argv_retoffset, + WASI_SERDES_SIZE_size_t * argc); + const __wasi_size_t argv_buf_size = sandbox->wasi_context->argv_buf_size; + char *argv_buf_retptr = get_memory_ptr_for_runtime(argv_buf_retoffset, argv_buf_size); + + /* args_get backings return a vector of host pointers. We need a host buffer to store this + * temporarily before unswizzling and writing to linear memory */ + char **argv_temp = calloc(sizeof(char *), argc); + if (unlikely(argv_temp == NULL)) { goto done; } + + /* Writes argv_buf to linear memory and argv vector to our temporary buffer */ + rc = wasi_snapshot_preview1_backing_args_get(sandbox->wasi_context, argv_temp, argv_buf_retptr); + + + if (unlikely(rc != __WASI_ERRNO_SUCCESS)) { goto done; } + + /* Unswizzle argv */ + for (int i = 0; i < argc; i++) { + argv_retptr[i] = argv_buf_retoffset + (uint32_t)(argv_temp[i] - argv_temp[0]); + } + +done: + if (likely(argv_temp != NULL)) { + free(argv_temp); + argv_temp = NULL; + } + sandbox_return(sandbox); + + return (uint32_t)rc; +} + +/** + * @brief Used by a WASI module to determine the argument count and size of the requried + * argument buffer + * + * @param argc_retoffset linear memory offset where we should write argc + * @param argv_buf_len_retoffset linear memory offset where we should write the length of the args buffer + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_args_sizes_get(__wasi_size_t argc_retoffset, __wasi_size_t argv_buf_len_retoffset) +{ + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + __wasi_size_t *argc_retptr = (__wasi_size_t *)get_memory_ptr_for_runtime(argc_retoffset, + WASI_SERDES_SIZE_size_t); + __wasi_size_t *argv_buf_len_retptr = (__wasi_size_t *)get_memory_ptr_for_runtime(argv_buf_len_retoffset, + WASI_SERDES_SIZE_size_t); + + uint32_t rc = wasi_snapshot_preview1_backing_args_sizes_get(sandbox->wasi_context, argc_retptr, + argv_buf_len_retptr); + sandbox_return(sandbox); + + return rc; +} + +/** + * @brief Return the resolution of a clock + * Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, + * return `errno::inval`. + * + * @param id The clock for which to return the resolution. + * @param resolution_retoffset - The resolution of the clock + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_clock_res_get(__wasi_clockid_t id, __wasi_size_t resolution_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return the time value of a clock + * + * @param clock_id The clock for which to return the time. + * @param precision The maximum lag (exclusive) that the returned time value may have, compared to its actual value. + * @param time_retoffset The time value of the clock. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_clock_time_get(__wasi_clockid_t clock_id, __wasi_timestamp_t precision, + __wasi_size_t time_retoffset) +{ + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + __wasi_timestamp_t *time_retptr = (__wasi_timestamp_t *) + get_memory_ptr_for_runtime(time_retoffset, WASI_SERDES_SIZE_timestamp_t); + + uint32_t rc = wasi_snapshot_preview1_backing_clock_time_get(sandbox->wasi_context, clock_id, precision, + time_retptr); + sandbox_return(sandbox); + + return rc; +} + +/** + * Read environment variable data. + * The sizes of the buffers should match that returned by `environ_sizes_get`. + * + * @param environ_retoffset + * @param environ_buf_retoffset + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_environ_get(__wasi_size_t env_retoffset, __wasi_size_t env_buf_retoffset) +{ + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + __wasi_errno_t rc = 0; + + const __wasi_size_t envc = sandbox->wasi_context->envc; + if (envc == 0) { goto done; } + + const __wasi_size_t env_buf_size = sandbox->wasi_context->env_buf_size; + assert(env_buf_size > envc); + + /* wasi_snapshot_preview1_backing_environ_get returns a vector of host pointers. We write + * these results to environ_temp temporarily before converting to offsets and writing to + * linear memory. We could technically write this to linear memory and then do a "fix up," + * but this would leak host information and constitue a security issue */ + char **env_temp = calloc(sizeof(char *), envc); + if (unlikely(env_temp == NULL)) { goto done; } + + __wasi_size_t *env_retptr = (__wasi_size_t *)get_memory_ptr_for_runtime(env_retoffset, + WASI_SERDES_SIZE_size_t * envc); + char *env_buf_retptr = get_memory_ptr_for_runtime(env_buf_retoffset, env_buf_size); + + rc = wasi_snapshot_preview1_backing_environ_get(sandbox->wasi_context, env_temp, env_buf_retptr); + if (unlikely(rc != __WASI_ERRNO_SUCCESS)) { goto done; } + + /* Unswizzle env and write to linear memory */ + for (int i = 0; i < envc; i++) { env_retptr[i] = env_buf_retoffset + (uint32_t)(env_temp[i] - env_temp[0]); } + +done: + if (likely(env_temp != NULL)) { + free(env_temp); + env_temp = NULL; + } + + sandbox_return(sandbox); + return (uint32_t)rc; +} + +/** + * Returns the number of environment variable arguments and the size of the environment variable data. + * + * @param envc_retoffset - the offset where the resulting number of environment variable arguments should be written + * @param env_buf_len_retoffset - the offset where the resulting size of the environment variable data should be + * written + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_environ_sizes_get(__wasi_size_t envc_retoffset, __wasi_size_t env_buf_len_retoffset) +{ + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + __wasi_size_t *envc_retptr = (__wasi_size_t *)get_memory_ptr_for_runtime(envc_retoffset, + WASI_SERDES_SIZE_size_t); + __wasi_size_t *env_buf_len_retptr = (__wasi_size_t *)get_memory_ptr_for_runtime(env_buf_len_retoffset, + WASI_SERDES_SIZE_size_t); + + uint32_t rc = wasi_snapshot_preview1_backing_environ_sizes_get(sandbox->wasi_context, envc_retptr, + env_buf_len_retptr); + + sandbox_return(sandbox); + + return rc; +} + +/** + * Provide file advisory information on a file descriptor. + * Note: similar to `posix_fadvise` in POSIX + * + * @param fd + * @param file_offset The offset within the file to which the advisory applies. + * @param len The length of the region to which the advisory applies. + * @param advice + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_advise(__wasi_fd_t fd, __wasi_filesize_t file_offset, __wasi_filesize_t len, + uint32_t advice_extended) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Force the allocation of space in a file. + * + * @param fd + * @param offset The offset at which to start the allocation. + * @param len The length of the area that is allocated. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_allocate(__wasi_fd_t fd, __wasi_filesize_t offset, __wasi_filesize_t len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Close a file descriptor. + * + * @param fd + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_close(__wasi_fd_t fd) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Synchronize the data of a file to disk. + * + * @param fd + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_datasync(__wasi_fd_t fd) +{ + return wasi_unsupported_syscall(__func__); +} + + +/** + * Get the attributes of a file descriptor. + * + * @param fd + * @param fdstat_retoffset return param of resulting wasi_fdstat structure + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_fdstat_get(__wasi_fd_t fd, __wasi_size_t fdstat_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the flags associated with a file descriptor + * + * @param fd + * @param fdflags_extended The desired values of the file descriptor flags, zero extended to 32-bits + * @return WASI_ESUCCESS, WASI_EACCES, WASI_EAGAIN, WASI_EBADF, WASI_EFAULT, WASI_EINVAL, WASI_ENOENT, or WASI_EPERM + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_fdstat_set_flags(__wasi_fd_t fd, uint32_t fdflags_extended) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the rights associated with a file descriptor. + * This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add + * rights + * + * @param fd + * @param fs_rights_base The desired rights of the file descriptor. + * @param fs_rights_inheriting + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_fdstat_set_rights(__wasi_fd_t fd, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return the attributes of an open file. + * + * @param fd + * @param filestat_retoffset The buffer where we should store the file's attributes + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_filestat_get(__wasi_fd_t fd, __wasi_size_t filestat_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the size of an open file, zeroing extra bytes on increase + * + * @param fd + * @param size The desired file size. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_filestat_set_size(__wasi_fd_t fd, __wasi_filesize_t size) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the timestamps of an open file or directory + * + * @param fd + * @param atim The desired values of the data access timestamp. + * @param mtim The desired values of the data modification timestamp. + * @param fstflags A bitmask indicating which timestamps to adjust. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_filestat_set_times(__wasi_fd_t fd, __wasi_timestamp_t atim, + __wasi_timestamp_t mtim, uint32_t fstflags_extended) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Read from a file descriptor without updating the descriptor's offset + * + * @param fd + * @param iovs_baseoffset List of scatter/gather vectors in which to store data. + * @param iovs_len The length of the iovs vector + * @param offset The offset within the file at which to read. + * @param nread_retoffset The number of bytes read. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_pread(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_filesize_t offset, __wasi_size_t nread_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return a description of the given preopened file descriptor. + * + * @param fd + * @param prestat_retoffset The buffer where the description is stored. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_prestat_get(__wasi_fd_t fd, __wasi_size_t prestat_retoffset) +{ + /* This signals that there are no file descriptors */ + return __WASI_ERRNO_BADF; +} + +/** + * Return a description of the given preopened file descriptor. + * + * @param fd + * @param dirname_retoffset A buffer into which to write the preopened directory name. + * @param dirname_len The length of the buffer at path_retptr + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_prestat_dir_name(__wasi_fd_t fd, __wasi_size_t dirname_retoffset, + __wasi_size_t dirname_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Write to a file descriptor without updating the descriptor's offset + * + * @param fd + * @param iovs_baseoffset List of scatter/gather vectors from which to retrieve data. + * @param iovs_len The length of the array pointed to by `iovs`. + * @param offset The offset within the file at which to write. + * @param nwritten_retoffset The number of bytes written. + * @return status code + * + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_pwrite(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_filesize_t file_offset, __wasi_size_t nwritten_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Read from a file descriptor + * + * @param fd + * @param iovs_baseptr + * @param iovs_len + * @param nread_retoffset The number of bytes read. + * @return WASI_ESUCCESS, WASI_EAGAIN, WASI_EWOULDBLOCK, WASI_EBADF, WASI_EFAULT, WASI_EINTR, WASI_EIO, WASI_EISDIR, or + * others + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_read(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_size_t nread_retoffset) +{ + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + __wasi_errno_t rc = 0; + __wasi_size_t *nread_retptr = (__wasi_size_t *)get_memory_ptr_for_runtime(nread_retoffset, + WASI_SERDES_SIZE_size_t); + + /* Swizzle iovs, writting to temp buffer */ + check_bounds(iovs_baseoffset, WASI_SERDES_SIZE_iovec_t * iovs_len); + __wasi_iovec_t *iovs_baseptr = calloc(iovs_len, sizeof(__wasi_iovec_t)); + if (unlikely(iovs_baseptr == NULL)) { goto done; } + rc = wasi_serdes_readv_iovec_t(sandbox->memory->abi.buffer, sandbox->memory->abi.size, iovs_baseoffset, + iovs_baseptr, iovs_len); + if (unlikely(rc != __WASI_ERRNO_SUCCESS)) { goto done; } + + rc = wasi_snapshot_preview1_backing_fd_read(sandbox->wasi_context, fd, iovs_baseptr, iovs_len, nread_retptr); + +done: + if (likely(iovs_baseptr != NULL)) { + free(iovs_baseptr); + iovs_baseptr = NULL; + } + + sandbox_return(sandbox); + return (uint32_t)rc; +} + +/** + * Atomically replace a file descriptor by renumbering another file descriptor. + * Due to the strong focus on thread safety, this environment does not provide + * a mechanism to duplicate or renumber a file descriptor to an arbitrary + * number, like `dup2()`. This would be prone to race conditions, as an actual + * file descriptor with the same number could be allocated by a different + * thread at the same time. + * This function provides a way to atomically renumber file descriptors, which + * would disappear if `dup2()` were to be removed entirely. + * + * @param fd + * @param to the file descriptor to overwrite + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_readdir(__wasi_fd_t fd, __wasi_size_t buf_baseoffset, __wasi_size_t buf_len, + __wasi_dircookie_t cookie, __wasi_size_t nread_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Atomically replace a file descriptor by renumbering another file descriptor. + * Due to the strong focus on thread safety, this environment does not provide + * a mechanism to duplicate or renumber a file descriptor to an arbitrary + * number, like `dup2()`. This would be prone to race conditions, as an actual + * file descriptor with the same number could be allocated by a different + * thread at the same time. + * This function provides a way to atomically renumber file descriptors, which + * would disappear if `dup2()` were to be removed entirely. + * + * @param fd + * @param to the file descriptor to overwrite + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_renumber(__wasi_fd_t fd, __wasi_fd_t to) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Move the offset of a file descriptor + * + * @param fd + * @param file_offset The number of bytes to move. + * @param whence_extended The base from which the offset is relative. + * @param newoffset_retoffset The new offset of the file descriptor, relative to the start of the file. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_seek(__wasi_fd_t fd, __wasi_filedelta_t file_offset, uint32_t whence_extended, + __wasi_size_t newoffset_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Synchronize the data and metadata of a file to disk + * + * @param fd + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_sync(__wasi_fd_t fd) +{ + return wasi_unsupported_syscall(__func__); +} + + +/** + * Return the current offset of a file descriptor + * + * @param fd + * @param fileoffset_retoffset The current offset of the file descriptor, relative to the start of the file. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_tell(__wasi_fd_t fd, __wasi_size_t fileoffset_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Write to a file descriptor + * + * @param fd + * @param iovs_baseoffset List of scatter/gather vectors from which to retrieve data. + * @param iovs_len The length of the array pointed to by `iovs`. + * @param nwritten_retoffset + * @return WASI_ESUCCESS, WASI_EAGAIN, WASI_EWOULDBLOCK, WASI_EBADF, WASI_EFAULT, + * WASI_EFBIG, WASI_EINTR, WASI_EIO, WASI_ENOSPC, WASI_EPERM, WASI_EPIPE, or others + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_fd_write(__wasi_fd_t fd, __wasi_size_t iovs_baseoffset, __wasi_size_t iovs_len, + __wasi_size_t nwritten_retoffset) +{ + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + __wasi_errno_t rc = 0; + __wasi_size_t *nwritten_retptr = (__wasi_size_t *)get_memory_ptr_for_runtime(nwritten_retoffset, + WASI_SERDES_SIZE_size_t); + + /* Swizzle iovs, writting to temporary buffer */ + check_bounds(iovs_baseoffset, WASI_SERDES_SIZE_ciovec_t * iovs_len); + __wasi_ciovec_t *iovs_baseptr = calloc(iovs_len, sizeof(__wasi_ciovec_t)); + if (unlikely(iovs_baseptr == NULL)) { goto done; } + rc = wasi_serdes_readv_ciovec_t(sandbox->memory->abi.buffer, sandbox->memory->abi.size, iovs_baseoffset, + iovs_baseptr, iovs_len); + if (unlikely(rc != __WASI_ERRNO_SUCCESS)) { goto done; } + + rc = wasi_snapshot_preview1_backing_fd_write(sandbox->wasi_context, fd, iovs_baseptr, iovs_len, + nwritten_retptr); + +done: + sandbox_return(sandbox); + if (likely(iovs_baseptr != NULL)) { + free(iovs_baseptr); + iovs_baseptr = NULL; + } + + return (uint32_t)rc; +} + +/** + * Create a directory + * + * @param fd + * @param path_baseoffset + * @param path_len + * @return WASI_ESUCCESS, WASI_EACCES, WASI_EBADF, WASI_EDQUOT, WASI_EEXIST, + * WASI_EFAULT, WASI_EINVAL, WASI_ELOOP, WASI_EMLINK, WASI_ENAMETOOLONG, + * WASI_ENOENT, WASI_ENOMEM, WASI_ENOSPC, WASI_ENOTDIR, WASI_EPERM, or WASI_EROFS + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_create_directory(__wasi_fd_t fd, __wasi_size_t path_baseoffset, + __wasi_size_t path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Return the attributes of a file or directory + * + * @param fd + * @param flags Flags determining the method of how the path is resolved. + * @param path_baseoffset The path of the file or directory to inspect. + * @param filestat_retoffset The buffer where the file's attributes are stored. + * @return WASI_ESUCCESS, WASI_EACCES, WASI_EBAD, WASI_EFAUL, WASI_EINVAL, WASI_ELOOP, + * WASI_ENAMETOOLON, WASI_ENOENT, WASI_ENOENT, WASI_ENOMEM, WASI_ENOTDI, or WASI_EOVERFLOW + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_filestat_get(__wasi_fd_t fd, __wasi_lookupflags_t flags, + __wasi_size_t path_baseoffset, __wasi_size_t path_len, + __wasi_size_t filestat_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Adjust the timestamps of a file or directory + * + * @param fd + * @param flags Flags determining the method of how the path is resolved. + * @param path_baseoffset The path of the file or directory to operate on. + * @param path_len + * @param atim The desired values of the data access timestamp. + * @param mtim The desired values of the data modification timestamp. + * @param fstflags_extended A bitmask indicating which timestamps to adjust. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_filestat_set_times(__wasi_fd_t fd, __wasi_lookupflags_t flags, + __wasi_size_t path_baseoffset, __wasi_size_t path_len, + __wasi_timestamp_t atim, __wasi_timestamp_t mtim, + uint32_t fstflags_extended) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Create a hard link + * + * @param old_fd + * @param old_flags Flags determining the method of how the path is resolved. + * @param old_path_baseoffset The source path from which to link. + * @param old_path_len + * @param new_fd The working directory at which the resolution of the new path starts. + * @param new_path_baseoffset The destination path at which to create the hard link. + * @param new_path_len + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_link(__wasi_fd_t old_fd, __wasi_lookupflags_t old_flags, + __wasi_size_t old_path_baseoffset, __wasi_size_t old_path_len, + __wasi_fd_t new_fd, __wasi_size_t new_path_baseoffset, + __wasi_size_t new_path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Open a file or directory + * The returned file descriptor is not guaranteed to be the lowest-numbered + * file descriptor not currently open; it is randomized to prevent + * applications from depending on making assumptions about indexes, since this + * is error-prone in multi-threaded contexts. The returned file descriptor is + * guaranteed to be less than 2**31. + * + * @param dirfd + * @param lookupflags + * @param path_baseoffset + * @param path_len + * @param oflags + * @param fs_rights_base + * @param fs_rights_inheriting + * @param fdflags + * @param fd_retoffset The file descriptor of the file that has been opened. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_open(__wasi_fd_t dirfd, __wasi_lookupflags_t lookupflags, + __wasi_size_t path_baseoffset, __wasi_size_t path_len, + uint32_t oflags_extended, __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inheriting, uint32_t fdflags_extended, + __wasi_size_t fd_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Remove a directory + * Return `errno::notempty` if the directory is not empty. + * + * @param fd + * @param path_baseoffset The path to a directory to remove. + * @param path_len + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_readlink(__wasi_fd_t fd, __wasi_size_t path_baseoffset, __wasi_size_t path_len, + __wasi_size_t buf_baseretoffset, __wasi_size_t buf_len, + __wasi_size_t nread_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Remove a directory + * Return `errno::notempty` if the directory is not empty. + * + * @param fd + * @param path_baseoffset The path to a directory to remove. + * @param path_len + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_remove_directory(__wasi_fd_t fd, __wasi_size_t path_baseoffset, + __wasi_size_t path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Rename a file or directory + * + * @param fd + * @param old_path The source path of the file or directory to rename. + * @param new_fd The working directory at which the resolution of the new path starts. + * @param new_path The destination path to which to rename the file or directory. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_rename(__wasi_fd_t fd, __wasi_size_t old_path_baseoffset, + __wasi_size_t old_path_len, __wasi_fd_t new_fd, + __wasi_size_t new_path_baseoffset, __wasi_size_t new_path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Create a symbolic link + * + * @param old_path_baseoffset The contents of the symbolic link. + * @param old_path_len + * @param fd + * @param new_path_baseoffset The path where we want the symbolic link. + * @param new_path_len + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_symlink(__wasi_size_t old_path_baseoffset, __wasi_size_t old_path_len, + __wasi_fd_t fd, __wasi_size_t new_path_baseoffset, + __wasi_size_t new_path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Unlink a file + * Return `errno::isdir` if the path refers to a directory. + * + * @param fd + * @param path_baseoffset + * @param path_len + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_path_unlink_file(__wasi_fd_t fd, __wasi_size_t path_baseoffset, + __wasi_size_t path_len) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Concurrently poll for the occurrence of a set of events. + * + * @param in The events to which to subscribe. + * @param out The events that have occurred. + * @param nsubscriptions Both the number of subscriptions and events. + * @param retptr The number of events stored. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_poll_oneoff(__wasi_size_t in_baseoffset, __wasi_size_t out_baseoffset, + __wasi_size_t nsubscriptions, __wasi_size_t nevents_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Terminate the process normally. An exit code of 0 indicates successful + * termination of the program. The meanings of other values is dependent on + * the environment. + * + * @param exitcode + */ +EXPORT void +sledge_abi__wasi_snapshot_preview1_proc_exit(__wasi_exitcode_t exitcode) +{ + wasi_unsupported_syscall(__func__); +} + +/** + * Send a signal to the process of the calling thread. + * + * @param sig_extended The signal condition to trigger. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_proc_raise(uint32_t sig_extended) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Write high-quality random data into a buffer. + * This function blocks when the implementation is unable to immediately + * provide sufficient high-quality random data. + * This function may execute slowly, so when large mounts of random data are + * required, it's advisable to use this function to seed a pseudo-random + * number generator, rather than to provide the random data directly. + * + * @param buf_baseretoffset The buffer to fill with random data. + * @param buf_len The length of the buffer + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_random_get(__wasi_size_t buf_baseretoffset, __wasi_size_t buf_len) +{ + struct sandbox *sandbox = current_sandbox_get(); + + sandbox_syscall(sandbox); + uint8_t *buf_baseretptr = (uint8_t *)get_memory_ptr_for_runtime(buf_baseretoffset, buf_len); + + uint32_t rc = (uint32_t)wasi_snapshot_preview1_backing_random_get(sandbox->wasi_context, buf_baseretptr, + buf_len); + sandbox_return(sandbox); + + return rc; +} + +/** + * Temporarily yield execution of the calling thread similar to `sched_yield` in POSIX. + * This implementation ignores client calls and silently returns RC 0 + * + * @return WASI_ESUCCESS + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_sched_yield(void) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Receive a message from a socket. + * Note: This WASI syscall is in flux pending a decision on whether WASI + * should only support fd_read and fd_write + * See: https://github.com/WebAssembly/WASI/issues/4 + * Note: This is similar to `recv` in POSIX, though it also supports reading + * the data into multiple buffers in the manner of `readv`. + * + * @param fd + * @param ri_data_baseretoffset List of scatter/gather vectors to which to store data. + * @param ri_data_len The length of the array pointed to by `ri_data`. + * @param ri_flags Message flags. + * @param ri_data_nbytes_retoffset Number of bytes stored in ri_data flags. + * @param message_nbytes_retoffset Number of bytes stored in message flags. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_sock_recv(__wasi_fd_t fd, __wasi_size_t ri_data_baseretoffset, + __wasi_size_t ri_data_len, uint32_t ri_flags_extended, + __wasi_size_t ri_data_nbytes_retoffset, + __wasi_size_t message_nbytes_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Send a message on a socket. + * Note: This WASI syscall is in flux pending a decision on whether WASI + * should only support fd_read and fd_write + * See: https://github.com/WebAssembly/WASI/issues/4 + * Note: This is similar to `send` in POSIX, though it also supports writing + * the data from multiple buffers in the manner of `writev`. + * + * @param fd + * @param si_data_baseoffset List of scatter/gather vectors to which to retrieve data + * @param si_data_len The length of the array pointed to by `si_data`. + * @param si_flags Message flags. + * @param nbytes_retoffset Number of bytes transmitted. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_sock_send(__wasi_fd_t fd, __wasi_size_t si_data_baseoffset, + __wasi_size_t si_data_len, uint32_t si_flags_extended, + __wasi_size_t nbytes_retoffset) +{ + return wasi_unsupported_syscall(__func__); +} + +/** + * Shut down socket send and receive channels. + * Note: This WASI syscall is in flux pending a decision on whether WASI + * should only support fd_read and fd_write + * See: https://github.com/WebAssembly/WASI/issues/4 + * + * @param fd + * @param how Which channels on the socket to shut down. + * @return status code + */ +EXPORT uint32_t +sledge_abi__wasi_snapshot_preview1_sock_shutdown(__wasi_fd_t fd, uint32_t how) +{ + return wasi_unsupported_syscall(__func__); } diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 19ac897..519d11a 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -110,7 +110,7 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void assert(handler_depth == 0); atomic_fetch_add(&handler_depth, 1); - ucontext_t * interrupted_context = (ucontext_t *)interrupted_context_raw; + ucontext_t *interrupted_context = (ucontext_t *)interrupted_context_raw; struct sandbox *current_sandbox = current_sandbox_get(); switch (signal_type) { @@ -128,10 +128,8 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void /* We transition the sandbox to an interrupted state to exclude time propagating signals and * running the scheduler from per-sandbox accounting */ sandbox_state_t interrupted_state = current_sandbox->state; - sandbox_interrupt(current_sandbox); propagate_sigalrm(signal_info); atomic_fetch_add(&deferred_sigalrm, 1); - sandbox_interrupt_return(current_sandbox, interrupted_state); } break; diff --git a/test.mk b/test.mk old mode 100644 new mode 100755 diff --git a/tests/CMSIS_5_NN/imageclassification/run.sh b/tests/CMSIS_5_NN/imageclassification/run.sh index 5eb0b61..4dc22b4 100755 --- a/tests/CMSIS_5_NN/imageclassification/run.sh +++ b/tests/CMSIS_5_NN/imageclassification/run.sh @@ -133,6 +133,6 @@ declare -Ar port=( ) # Sort the images by the number of labeled plates -declare -a cifar10_images=(./images/bmp/*) +declare -a cifar10_images=(../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/*) framework_init "$@" diff --git a/tests/TinyEKF/one_iteration/run.sh b/tests/TinyEKF/one_iteration/run.sh index 0dc4160..d0218c6 100755 --- a/tests/TinyEKF/one_iteration/run.sh +++ b/tests/TinyEKF/one_iteration/run.sh @@ -53,7 +53,7 @@ experiment_client() { # Copy data if not here if [[ ! -f "$__run_sh__base_path/initial_state.dat" ]]; then pushd "$__run_sh__base_path" || exit 1 - pushd "../../../applications/wasmception_apps/TinyEKF/extras/c/" || exit 1 + pushd "../../../applications/wasm_apps/TinyEKF/extras/c/" || exit 1 cp ekf_raw.dat "$__run_sh__base_path/initial_state.dat" || exit 1 popd || exit 1 popd || exit 1 diff --git a/tests/sod/image_resize/test/run.sh b/tests/sod/image_resize/test/run.sh index a766555..cdedbcf 100755 --- a/tests/sod/image_resize/test/run.sh +++ b/tests/sod/image_resize/test/run.sh @@ -56,7 +56,7 @@ validate_dependencies curl compare # Copy Flower Image if not here if [[ ! -f "./flower.jpg" ]]; then - cp "$__run_sh__project_base_absolute_path/applications/wasmception_apps/sod/samples/flower.jpg" ./flower.jpg + cp "$__run_sh__project_base_absolute_path/applications/wasm_apps/sod/samples/flower.jpg" ./flower.jpg fi framework_init "$@" diff --git a/tests/sod/lpd/by_plate_count/Makefile b/tests/sod/lpd/by_plate_count/Makefile index 67dfc15..1659147 100644 --- a/tests/sod/lpd/by_plate_count/Makefile +++ b/tests/sod/lpd/by_plate_count/Makefile @@ -1,7 +1,7 @@ RUNTIME_DIR=../../../../runtime/ SLEDGE_BINARY_DIR=${RUNTIME_DIR}/bin HOSTNAME=localhost -IMAGE=./images/Cars0.png +IMAGE=../../../../applications/wasm_apps/sod/samples/plates/Cars0.png .PHONY: all all: run diff --git a/tests/sod/lpd/by_plate_count/run.sh b/tests/sod/lpd/by_plate_count/run.sh index 8ef3377..89f2f08 100755 --- a/tests/sod/lpd/by_plate_count/run.sh +++ b/tests/sod/lpd/by_plate_count/run.sh @@ -148,6 +148,6 @@ while IFS= read -r image_data; do 4) lpd4_images+=("$image_file") ;; *) panic "Unexpected number of plates" ;; esac -done < <(ls ./images/*.csv) +done < <(ls ../../../../applications/wasm_apps/sod/samples/plates/*.csv) framework_init "$@"