diff --git a/.github/workflows/build-and-test-macos.yaml b/.github/workflows/build-and-test-macos.yaml deleted file mode 100644 index 6738be264a..0000000000 --- a/.github/workflows/build-and-test-macos.yaml +++ /dev/null @@ -1,293 +0,0 @@ -# -# Copyright 2017-2022 Davide Bettio -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: Build and Test on macOS - -on: - push: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - pull_request: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - build-and-test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: ["macos-14", "macos-15", "macos-15-intel", "macos-26"] - otp: ["26", "27", "28"] - mbedtls: ["mbedtls@3"] - cmake_opts_other: [""] - - include: - - os: "macos-15-intel" - otp: "28" - mbedtls: "mbedtls@3" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF" - - - os: "macos-14" - otp: "28" - mbedtls: "mbedtls@3" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF" - - - os: "macos-15" - otp: "28" - mbedtls: "mbedtls@3" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF" - - # JIT + DWARF build (macOS aarch64) - - os: "macos-26" - otp: "28" - mbedtls: "mbedtls@3" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF" - - steps: - # Setup - - name: "Checkout repo" - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - - uses: erlef/setup-beam@v1 - with: - otp-version: ${{ matrix.otp }} - rebar3-version: ${{ fromJSON('{"26":"3.25.1","27":"3.25.1","28":"3.26"}')[matrix.otp] || '3' }} - gleam-version: "1.15.2" - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: "Install deps" - run: brew update && HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install coreutils gperf doxygen socat ${{ matrix.mbedtls }} - - - name: "Workaround for nxdomain random issues" - run: | - # https://github.com/actions/runner-images/issues/8649#issuecomment-2231240347 - for host in "$(hostname)" "$(hostname -f)"; do - echo -e "$(ipconfig getifaddr en0) $(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts - dscacheutil -q host -a name $(hostname -f) - done - - - name: "Setup mbedtls@3 environment" - if: matrix.mbedtls == 'mbedtls@3' - run: | - # Detect Homebrew prefix (Apple Silicon vs Intel) - if [ -d "/opt/homebrew/opt/mbedtls@3" ]; then - MBEDTLS_PREFIX="/opt/homebrew/opt/mbedtls@3" - elif [ -d "/usr/local/opt/mbedtls@3" ]; then - MBEDTLS_PREFIX="/usr/local/opt/mbedtls@3" - else - echo "Error: mbedtls@3 not found in expected locations" - exit 1 - fi - echo "MBEDTLS_PREFIX=${MBEDTLS_PREFIX}" >> $GITHUB_ENV - echo "LDFLAGS=-L${MBEDTLS_PREFIX}/lib" >> $GITHUB_ENV - echo "CPPFLAGS=-I${MBEDTLS_PREFIX}/include" >> $GITHUB_ENV - echo "PKG_CONFIG_PATH=${MBEDTLS_PREFIX}/lib/pkgconfig" >> $GITHUB_ENV - - # Builder info - - name: "System info" - run: | - echo "**uname:**" - uname -a - echo "**C Compiler version:**" - clang --version - clang++ --version - echo "**CMake version:**" - cmake --version - - # Build - - name: "Build: create build dir" - run: mkdir build - - - name: "Build: run cmake" - working-directory: build - run: | - cmake -DAVM_WARNINGS_ARE_ERRORS=ON ${MBEDTLS_PREFIX:+-DCMAKE_PREFIX_PATH="$MBEDTLS_PREFIX"} ${{ matrix.cmake_opts_other }} -G Ninja .. - - - name: "Build: run ninja" - working-directory: build - run: ninja - - - name: "Build: run dialyzer" - working-directory: build - run: ninja dialyzer - - # Test - - name: "Test: test-erlang" - timeout-minutes: 10 - working-directory: build - run: | - ./tests/test-erlang - - - name: "Test: dwarf (test_executable_line)" - if: matrix.cmake_opts_other == '-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF' - timeout-minutes: 4 - working-directory: build - env: - # Apple lldb < 2100 hangs forever resolving pending source-line - # breakpoints against JIT-emitted DWARF on macOS 26 (the active - # Xcode 26.2 lldb is 1703.x). The CommandLineTools lldb is at - # 2100 and works. - LLDB: /Library/Developer/CommandLineTools/usr/bin/lldb - run: | - [ -x "$LLDB" ] || { echo "FAIL: $LLDB not executable"; exit 1; } - echo "## using $LLDB" - "$LLDB" --version | head -2 - LOG=/tmp/lldb-test_executable_line.log - set +e - gtimeout --foreground -k 30 120 "$LLDB" -b \ - -o "log enable -f /tmp/lldb-jit-loader.log lldb jit" \ - -o "log enable -f /tmp/lldb-gdb-test.log gdb-remote packets" \ - -o "settings set plugin.jit-loader.gdb.enable on" \ - -o "breakpoint set -f test_executable_line.erl -l 49" \ - -o "breakpoint set -f test_executable_line.erl -l 52" \ - -o "run" \ - -o "print term_to_int(ctx->x[0])" \ - -o "c" \ - -o "print term_to_int(ctx->x[0])" \ - -o "quit" \ - -- ./tests/test-erlang test_executable_line 2>&1 | tee "$LOG" - LLDB_RC=${PIPESTATUS[0]} - set -e - if [ "$LLDB_RC" -eq 124 ] || [ "$LLDB_RC" -eq 137 ]; then - echo "FAIL: lldb timed out (rc=$LLDB_RC)" - [ -f /tmp/lldb-jit-loader.log ] && { echo "## jit log"; head -200 /tmp/lldb-jit-loader.log; } - [ -f /tmp/lldb-gdb-test.log ] && { echo "## gdb-remote packets (tail)"; tail -120 /tmp/lldb-gdb-test.log; } - exit 1 - fi - VALUES=$(sed -n 's/^(\(avm_int_t\)) \(-\{0,1\}[0-9][0-9]*\).*/\2/p' "$LOG") - FIRST=$(echo "$VALUES" | sed -n '1p') - SECOND=$(echo "$VALUES" | sed -n '2p') - if [ "$FIRST" != "42" ]; then - echo "FAIL: expected 42 at line 49, got '$FIRST'" - exit 1 - fi - if [ "$SECOND" != "2" ]; then - echo "FAIL: expected 2 at line 52, got '$SECOND'" - exit 1 - fi - echo "PASS: test_executable_line dwarf test" - - - name: "Test: dwarf (test_debug_line)" - if: matrix.cmake_opts_other == '-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF' - timeout-minutes: 6 - working-directory: build - env: - LLDB: /Library/Developer/CommandLineTools/usr/bin/lldb - run: | - [ -x "$LLDB" ] || { echo "FAIL: $LLDB not executable"; exit 1; } - LOG=/tmp/lldb-test_debug_line.log - set +e - gtimeout --foreground -k 30 240 "$LLDB" -b \ - -o "settings set plugin.jit-loader.gdb.enable on" \ - -o "breakpoint set -f test_debug_line.erl -l 49" \ - -o "breakpoint set -f test_debug_line.erl -l 52" \ - -o "run" \ - -o "print term_to_int(N)" \ - -o "c" \ - -o "print term_to_int(Z)" \ - -o "quit" \ - -- ./tests/test-erlang test_debug_line 2>&1 | tee "$LOG" - LLDB_RC=${PIPESTATUS[0]} - set -e - if [ "$LLDB_RC" -eq 124 ] || [ "$LLDB_RC" -eq 137 ]; then - echo "FAIL: lldb timed out (rc=$LLDB_RC)" - exit 1 - fi - VALUES=$(sed -n 's/^(\(avm_int_t\)) \(-\{0,1\}[0-9][0-9]*\).*/\2/p' "$LOG") - FIRST=$(echo "$VALUES" | sed -n '1p') - SECOND=$(echo "$VALUES" | sed -n '2p') - if [ "$FIRST" != "42" ]; then - echo "FAIL: expected 42 at line 49, got '$FIRST'" - exit 1 - fi - if [ "$SECOND" != "2" ]; then - echo "FAIL: expected 2 at line 52, got '$SECOND'" - exit 1 - fi - echo "PASS: test_debug_line dwarf test" - - - name: "Test: test-enif" - working-directory: build - run: | - ./tests/test-enif - - - name: "Test: test-heap" - working-directory: build - run: | - ./tests/test-heap - - - name: "Test: test-mailbox" - working-directory: build - run: | - ./tests/test-mailbox - - - name: "Test: test-structs" - timeout-minutes: 10 - working-directory: build - run: | - ./tests/test-structs - - - name: "Test: test_etest.avm" - timeout-minutes: 5 - working-directory: build - run: | - ./src/AtomVM ./tests/libs/etest/test_etest.avm - - - name: "Test: test_estdlib.avm" - timeout-minutes: 20 - working-directory: build - run: | - ./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm - - - name: "Test: test_eavmlib.avm" - timeout-minutes: 10 - working-directory: build - run: | - ./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm - - - name: "Test: test_jit.avm" - timeout-minutes: 20 - working-directory: build - run: | - ./src/AtomVM tests/libs/jit/test_jit.avm - - - name: "Test: test_alisp.avm" - timeout-minutes: 10 - working-directory: build - run: | - ./src/AtomVM ./tests/libs/alisp/test_alisp.avm - - - name: "Install and smoke test" - working-directory: build - run: | - sudo ninja install - atomvm examples/erlang/hello_world.avm - atomvm -v - atomvm -h diff --git a/.github/workflows/build-and-test-on-freebsd.yaml b/.github/workflows/build-and-test-on-freebsd.yaml deleted file mode 100644 index f22718ecc2..0000000000 --- a/.github/workflows/build-and-test-on-freebsd.yaml +++ /dev/null @@ -1,203 +0,0 @@ -# -# Copyright 2023 Fred Dushin -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: build-and-test-on-freebsd - -on: - push: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - pull_request: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - build-and-test-on-freebsd: - runs-on: ubuntu-24.04 - name: Build and test AtomVM on FreeBSD - env: - ATOMVM_EXAMPLE: "atomvm-example" - - strategy: - fail-fast: false - - matrix: - os_release: ["13.5", "14.3", "15.0"] - - steps: - - - uses: actions/checkout@v4 - - - name: Build and Test on FreeBSD - id: build-and-test-on-freebsd - uses: vmactions/freebsd-vm@v1 - timeout-minutes: 20 - with: - release: ${{ matrix.os_release }} - envs: 'ATOMVM_EXAMPLE' - usesh: true - sync: rsync - copyback: false - - - name: "Install deps" - shell: freebsd {0} - run: | - pkg install -y curl cmake gperf erlang elixir rebar3 mbedtls3 ninja socat - - - name: "Add hostname to /etc/hosts for distribution tests" - shell: freebsd {0} - run: | - echo "127.0.0.1 $(hostname)" >> /etc/hosts - - - name: "System info" - shell: freebsd {0} - run: | - set -e - echo "%%" - echo "%% System Info" - echo "%%" - echo "**freebsd-version:**" - freebsd-version - echo "**uname:**" - uname -a - echo "**C Compiler version:**" - clang --version - clang++ --version - echo "**CMake version:**" - cmake --version - echo "**hw.ncpu:**" - sysctl -n hw.ncpu - - - name: Disable eavmlib's test_http_server - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - sed -i '' 's/test_http_server/%test_http_server/g' tests/libs/eavmlib/tests.erl - - - name: "Build: create build dir" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - mkdir build - - - name: "Build: run cmake" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - cmake .. -DMBEDTLS_ROOT_DIR=/usr/local -DAVM_WARNINGS_ARE_ERRORS=ON - - - name: "Build: compile" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - cmake --build . - - - name: "Build: run dialyzer" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - cmake --build . -t dialyzer - - - name: "Test: test-erlang" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./tests/test-erlang - - - name: "Test: test-enif" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./tests/test-enif - - - name: "Test: test-heap" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./tests/test-heap - - - name: "Test: test-mailbox" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./tests/test-mailbox - - - name: "Test: test-structs" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./tests/test-structs - - - name: "Test: test_etest.avm" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./src/AtomVM tests/libs/etest/test_etest.avm - - - name: "Test: test_estdlib.avm" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./src/AtomVM tests/libs/estdlib/test_estdlib.avm - - - name: "Test: test_eavmlib.avm" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./src/AtomVM tests/libs/eavmlib/test_eavmlib.avm - - - name: "Test: test_alisp.avm" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./src/AtomVM tests/libs/alisp/test_alisp.avm - - - name: "Test: Tests.avm (Elixir)" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - ./src/AtomVM ./tests/libs/exavmlib/Tests.avm - - - name: "Install and smoke test" - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - cmake --build . -t install - atomvm examples/erlang/hello_world.avm - atomvm -v - atomvm -h diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml deleted file mode 100644 index f487ea0cf3..0000000000 --- a/.github/workflows/build-and-test.yaml +++ /dev/null @@ -1,1017 +0,0 @@ -# -# Copyright 2017-2022 Davide Bettio -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: Build and Test - -on: - push: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - pull_request: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -env: - DEFAULT_OTP_VERSION: "28" - DEFAULT_ELIXIR_VERSION: "1.19" - DEFAULT_REBAR3_VERSION: "3.25.1" - DEFAULT_GLEAM_VERSION: "1.11.1" - DEFAULT_CFLAGS: "-O3" - DEFAULT_CMAKE_OPTS_OTHER: "-DAVM_WARNINGS_ARE_ERRORS=ON" - -jobs: - build-and-test: - runs-on: ${{ matrix.os || 'ubuntu-24.04' }} - container: ${{ matrix.container }} - strategy: - - fail-fast: false - - matrix: - # Ubuntu 20.04 has gcc from 7 to 10 ("gcc" is gcc-9) - # Ubuntu 22.04 has gcc from 9 to 12 ("gcc" is gcc-11) - # Ubuntu 24.04 has gcc from 9 to 14 ("gcc" is gcc-13) - # Ubuntu 20.04 has clang 10 and 12 to ("clang" is 10) - # Ubuntu 22.04 has clang from 12 to 15 ("clang" is 14) - # Ubuntu 24.04 has clang from 14 to 18 ("clang" is 18) - # We want to test every compiler but don't need to test every OS - # We only test several OTP versions with default compilers for supported OSes (gcc 11, gcc 13, clang 14, clang 18) - cc: ["gcc-11", "gcc-13", "clang-14", "clang-18"] - otp: ["26", "27", "28"] - - include: - ### gcc - # erlef/setup-beam officially supports ubuntu 22 and 24, we are getting - # warnings for gcc 7 and 8 that require ubuntu 20. - - cc: "gcc-7" - cxx: "g++-7" - compiler_pkgs: "gcc-7 g++-7" - container: "ubuntu:20.04" - cmake_opts_other: " " - - cc: "gcc-8" - cxx: "g++-8" - compiler_pkgs: "gcc-8 g++-8" - container: "ubuntu:20.04" - # from gcc 9 we can use ubuntu 24. - - cc: "gcc-9" - cxx: "g++-9" - compiler_pkgs: "gcc-9 g++-9" - - cc: "gcc-10" - cxx: "g++-10" - compiler_pkgs: "gcc-10 g++-10" - - cc: "gcc-11" - cxx: "g++-11" - compiler_pkgs: "gcc-11 g++-11" - # otp: all - - cc: "gcc-12" - cxx: "g++-12" - compiler_pkgs: "gcc-12 g++-12" - - cc: "gcc-13" - cxx: "g++-13" - compiler_pkgs: "gcc-13 g++-13" - # otp: all - - cc: "gcc-14" - cxx: "g++-14" - compiler_pkgs: "gcc-14 g++-14" - - ### clang - - cc: "clang-10" - cxx: "clang++-10" - compiler_pkgs: "clang-10" - container: "ubuntu:20.04" - - cc: "clang-11" - cxx: "clang++-11" - compiler_pkgs: "clang-11" - container: "ubuntu:20.04" - - # from clang 12 we can use ubuntu 22 - - cc: "clang-12" - cxx: "clang++-12" - compiler_pkgs: "clang-12" - os: "ubuntu-22.04" - - cc: "clang-13" - cxx: "clang++-13" - compiler_pkgs: "clang-13" - os: "ubuntu-22.04" - - cc: "clang-14" - cxx: "clang++-14" - compiler_pkgs: "clang-14" - # otp: all - - cc: "clang-15" - cxx: "clang++-15" - compiler_pkgs: "clang-15" - - cc: "clang-16" - cxx: "clang++-16" - compiler_pkgs: "clang-16" - - cc: "clang-17" - cxx: "clang++-17" - compiler_pkgs: "clang-17" - - cc: "clang-18" - cxx: "clang++-18" - compiler_pkgs: "clang-18" - # otp: all - - # Additional runs with older elixir - - cc: "cc" - cxx: "c++" - otp: "27" - elixir_version: "1.18" - - - cc: "cc" - cxx: "c++" - otp: "27" - elixir_version: "1.17" - - - cc: "cc" - cxx: "c++" - otp: "26" - elixir_version: "1.18" - - - cc: "cc" - cxx: "c++" - otp: "26" - elixir_version: "1.17" - - # Additional run with OTP master and default compiler - - cc: "cc" - cxx: "c++" - otp: "master" - elixir_version: "main" - - # Additional latest & -Os compiler builds - - cc: "gcc-14" - cxx: "g++-14" - cflags: "-Os" - compiler_pkgs: "gcc-14 g++-14" - - - cc: "clang-18" - cxx: "clang++-18" - cflags: "-Os" - compiler_pkgs: "clang-18" - - # Additional build with 32 bits floats - - cc: "cc" - cxx: "c++" - cmake_opts_other: "-DAVM_USE_32BIT_FLOAT=ON -DAVM_WARNINGS_ARE_ERRORS=ON" - - # Additional run with comma-decimal locale (de_DE) - - cc: "cc" - cxx: "c++" - locale: "de_DE.UTF-8" - - # Additional run with -DAVM_CREATE_STACKTRACES=off - - cc: "cc" - cxx: "c++" - cmake_opts_other: "-DAVM_CREATE_STACKTRACES=off -DAVM_WARNINGS_ARE_ERRORS=ON" - - # JIT build - - cc: "cc" - cxx: "c++" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF" - jit_target_arch: "x86_64" - - # Additional 32 bits build - - container: "ubuntu:20.04" - cc: "gcc-10" - cxx: "g++-10" - cflags: "-m32 -O3" - cmake_opts_other: "-DAVM_CREATE_STACKTRACES=off -DAVM_WARNINGS_ARE_ERRORS=ON" - arch: "i386" - compiler_pkgs: "gcc-10 g++-10 gcc-10-multilib g++-10-multilib libc6-dev-i386 - libc6-dbg:i386 zlib1g-dev:i386 libmbedtls-dev:i386" - - # JIT build with OTP-28 - - os: "ubuntu-24.04" - cc: "cc" - cxx: "c++" - cflags: "" - otp: "28" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF" - jit_target_arch: "x86_64" - - # JIT build with OTP-29.0 - - os: "ubuntu-24.04" - cc: "cc" - cxx: "c++" - cflags: "" - otp: "29.0" - version_type: "strict" - elixir_version: "1.19.5" - rebar3_version: "3.27.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF" - jit_target_arch: "x86_64" - - # JIT + DWARF build (x86_64) - - os: "ubuntu-24.04" - cc: "cc" - cxx: "c++" - cflags: "" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF" - jit_target_arch: "x86_64" - - # arm64 builds - - os: "ubuntu-24.04-arm" - cc: "cc" - cxx: "c++" - - - os: "ubuntu-24.04-arm" - cc: "cc" - cxx: "c++" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF" - jit_target_arch: "aarch64" - - # JIT + DWARF build (aarch64) - - os: "ubuntu-24.04-arm" - cc: "cc" - cxx: "c++" - cflags: "" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF" - jit_target_arch: "aarch64" - - # armhf builds - - cc: "arm-linux-gnueabihf-gcc" - cxx: "arm-linux-gnueabihf-g++" - # -D_FILE_OFFSET_BITS=64 is required for making atomvm:posix_readdir/1 test work - # otherwise readdir will fail due to 64 bits inode numbers with 32 bit ino_t - cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O3 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64" - cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support" - arch: "armhf" - library-arch: arm-linux-gnueabihf - - # JIT armv6m build (Thumb-1 only JIT code) - - cc: "arm-linux-gnueabihf-gcc" - cxx: "arm-linux-gnueabihf-g++" - cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O3 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=armv6m -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support" - arch: "armhf" - library-arch: arm-linux-gnueabihf - jit_target_arch: "armv6m" - - # JIT armv6m+thumb2 build (Thumb-2 JIT code) - - cc: "arm-linux-gnueabihf-gcc" - cxx: "arm-linux-gnueabihf-g++" - cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O3 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=armv6m+thumb2 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support" - arch: "armhf" - library-arch: arm-linux-gnueabihf - jit_target_arch: "armv6m+thumb2" - - # JIT ARM32 (ARM mode) build - - cc: "arm-linux-gnueabihf-gcc" - cxx: "arm-linux-gnueabihf-g++" - cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O3 -marm -D_FILE_OFFSET_BITS=64" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=arm32 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support" - arch: "armhf" - library-arch: arm-linux-gnueabihf - jit_target_arch: "arm32" - - # JIT + DWARF build (armv6m) - - os: "ubuntu-24.04" - cc: "arm-linux-gnueabihf-gcc" - cxx: "arm-linux-gnueabihf-g++" - cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O2 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=armv6m -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support" - arch: "armhf" - library-arch: arm-linux-gnueabihf - jit_target_arch: "armv6m" - - # JIT + DWARF build (armv6m+thumb2) - - os: "ubuntu-24.04" - cc: "arm-linux-gnueabihf-gcc" - cxx: "arm-linux-gnueabihf-g++" - cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O2 -mthumb -mthumb-interwork -D_FILE_OFFSET_BITS=64" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=armv6m+thumb2 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support" - arch: "armhf" - library-arch: arm-linux-gnueabihf - jit_target_arch: "armv6m+thumb2" - - # JIT + DWARF build (arm32) - - os: "ubuntu-24.04" - cc: "arm-linux-gnueabihf-gcc" - cxx: "arm-linux-gnueabihf-g++" - cflags: "-mcpu=cortex-a7 -mfloat-abi=hard -O2 -marm -D_FILE_OFFSET_BITS=64" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=arm32 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/armhf_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-armhf libc6-dbg:armhf zlib1g-dev:armhf libmbedtls-dev:armhf qemu-user qemu-user-binfmt binfmt-support" - arch: "armhf" - library-arch: arm-linux-gnueabihf - jit_target_arch: "arm32" - - # s390x build - - cc: "s390x-linux-gnu-gcc" - cxx: "s390x-linux-gnu-g++" - cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/s390x_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-s390x libc6-dbg:s390x zlib1g-dev:s390x libmbedtls-dev:s390x qemu-user qemu-user-binfmt binfmt-support" - arch: "s390x" - library-arch: s390x-linux-gnu - - # riscv64 build - - os: "ubuntu-24.04" - cc: "riscv64-linux-gnu-gcc" - cxx: "riscv64-linux-gnu-g++" - cflags: "-O2" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv64_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-riscv64 libc6-dbg:riscv64 zlib1g-dev:riscv64 libmbedtls-dev:riscv64 qemu-user qemu-user-binfmt binfmt-support" - arch: "riscv64" - library-arch: riscv64-linux-gnu - - # riscv64 build + jit - - os: "ubuntu-24.04" - cc: "riscv64-linux-gnu-gcc" - cxx: "riscv64-linux-gnu-g++" - cflags: "-O2" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=riscv64 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv64_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-riscv64 libc6-dbg:riscv64 zlib1g-dev:riscv64 libmbedtls-dev:riscv64 qemu-user qemu-user-binfmt binfmt-support" - arch: "riscv64" - library-arch: riscv64-linux-gnu - jit_target_arch: "riscv64" - - # JIT + DWARF build (riscv64) - - os: "ubuntu-24.04" - cc: "riscv64-linux-gnu-gcc" - cxx: "riscv64-linux-gnu-g++" - cflags: "-O2" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=riscv64 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv64_toolchain.cmake" - compiler_pkgs: "crossbuild-essential-riscv64 libc6-dbg:riscv64 zlib1g-dev:riscv64 libmbedtls-dev:riscv64 qemu-user qemu-user-binfmt binfmt-support" - arch: "riscv64" - library-arch: riscv64-linux-gnu - jit_target_arch: "riscv64" - - # riscv32-ilp32 build - - os: "ubuntu-24.04" - cc: "riscv32-unknown-linux-gnu-gcc" - cxx: "riscv32-unknown-linux-gnu-g++" - cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv32_ilp32_toolchain.cmake" - compiler_pkgs: "qemu-user qemu-user-binfmt binfmt-support" - arch: "riscv32" - library-arch: riscv32-linux-gnu-ilp32 - - # riscv32-ilp32 build + jit - - os: "ubuntu-24.04" - cc: "riscv32-unknown-linux-gnu-gcc" - cxx: "riscv32-unknown-linux-gnu-g++" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=riscv32 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv32_ilp32_toolchain.cmake" - compiler_pkgs: "qemu-user qemu-user-binfmt binfmt-support" - arch: "riscv32" - library-arch: riscv32-linux-gnu-ilp32 - jit_target_arch: "riscv32" - - # xtensa build (esp32, lx6) - - os: "ubuntu-24.04" - cc: "xtensa-lx6-linux-gnu-gcc" - cxx: "xtensa-lx6-linux-gnu-g++" - cflags: "-O2" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_WARNINGS_ARE_ERRORS=ON -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/xtensa_toolchain.cmake" - compiler_pkgs: "" - arch: "xtensa" - library-arch: xtensa-lx6-linux-gnu - - # xtensa build + jit (esp32, lx6) - - os: "ubuntu-24.04" - cc: "xtensa-lx6-linux-gnu-gcc" - cxx: "xtensa-lx6-linux-gnu-g++" - cflags: "-O2" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=xtensa -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/xtensa_toolchain.cmake" - compiler_pkgs: "" - arch: "xtensa" - library-arch: xtensa-lx6-linux-gnu - jit_target_arch: "xtensa" - - # JIT + DWARF build (xtensa, esp32, lx6) - - os: "ubuntu-24.04" - cc: "xtensa-lx6-linux-gnu-gcc" - cxx: "xtensa-lx6-linux-gnu-g++" - cflags: "-O2" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=xtensa -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/xtensa_toolchain.cmake" - compiler_pkgs: "" - arch: "xtensa" - library-arch: xtensa-lx6-linux-gnu - jit_target_arch: "xtensa" - - # libsodium enabled build - - os: "ubuntu-24.04" - cc: "cc" - cxx: "c++" - cflags: "" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_USE_LIBSODIUM=ON" - compiler_pkgs: "libsodium-dev" - - # JIT + DWARF build (riscv32) - - os: "ubuntu-24.04" - cc: "riscv32-unknown-linux-gnu-gcc" - cxx: "riscv32-unknown-linux-gnu-g++" - cflags: "-O2" - otp: "28" - elixir_version: "1.17" - rebar3_version: "3.24.0" - cmake_opts_other: "-DAVM_DISABLE_JIT=OFF -DAVM_DISABLE_JIT_DWARF=OFF -DAVM_JIT_TARGET_ARCH=riscv32 -DCMAKE_TOOLCHAIN_FILE=${RUNNER_TEMP}/riscv32_ilp32_toolchain.cmake" - compiler_pkgs: "qemu-user qemu-user-binfmt binfmt-support" - arch: "riscv32" - library-arch: riscv32-linux-gnu-ilp32 - jit_target_arch: "riscv32" - - env: - ImageOS: ${{ matrix.container == 'ubuntu:20.04' && 'ubuntu20' || matrix.os == 'ubuntu-20.04' && 'ubuntu20' || matrix.os == 'ubuntu-22.04' && 'ubuntu22' || matrix.os == 'ubuntu-24.04' && 'ubuntu24' || 'ubuntu24' }} - CC: ${{ matrix.cc }} - CXX: ${{ matrix.cxx }} - CFLAGS: ${{ matrix.cflags }} - CXXFLAGS: ${{ matrix.cflags }} - DEBIAN_FRONTEND: noninteractive - TZ: "Etc/UTC" - - steps: - # Setup - - name: "Set CFLAGS" - run: | - if [ $"CFLAGS" = "" ]; then - echo "CFLAGS=$DEFAULT_CFLAGS" >> $GITHUB_ENV - echo "CXXFLAGS=$DEFAULT_CFLAGS" >> $GITHUB_ENV - fi - - - name: "Install deps for containers" - if: matrix.container != '' - run: apt-get update && apt-get install -y --no-install-recommends sudo unzip git tzdata - - - name: "Add i386 architecture" - if: matrix.arch == 'i386' - run: sudo dpkg --add-architecture i386 - - - name: "Setup cross compilation architecture" - if: matrix.library-arch != '' && matrix.library-arch != 'riscv32-linux-gnu-ilp32' && matrix.library-arch != 'xtensa-lx6-linux-gnu' - run: | - # Replace Azure mirrors with official Ubuntu repositories - sudo sed -i 's|azure\.||g' /etc/apt/sources.list - sudo sed -i 's|azure\.||g' /etc/apt/sources.list.d/*.list 2>/dev/null || true - - # Handle new DEB822 format - if [ -f /etc/apt/apt-mirrors.txt ]; then - sudo sed -i 's|azure\.||g' /etc/apt/apt-mirrors.txt - fi - - sudo dpkg --add-architecture ${{ matrix.arch }} - cat > ${RUNNER_TEMP}/cross-compile-sources.list < ${RUNNER_TEMP}/${{ matrix.arch }}_toolchain.cmake <> $GITHUB_PATH - - # Install the libs - sudo dpkg -i libc6-ilp32_2.39-0ubuntu1_riscv32.deb - sudo dpkg -i libc6-dev-ilp32_2.39-0ubuntu1_riscv32.deb - sudo dpkg -i libc6-dbg-ilp32_2.39-0ubuntu1_riscv32.deb - - sudo dpkg -i zlib1g-ilp32_1.3.1-0ubuntu1_riscv32.deb - sudo dpkg -i zlib1g-dev-ilp32_1.3.1-0ubuntu1_riscv32.deb - - # Install mbedtls runtime packages first (in dependency order) - sudo dpkg -i libmbedcrypto7-ilp32_2.28.8-0ubuntu1_riscv32.deb - sudo dpkg -i libmbedx509-1-ilp32_2.28.8-0ubuntu1_riscv32.deb - sudo dpkg -i libmbedtls14-ilp32_2.28.8-0ubuntu1_riscv32.deb - # Then install the dev package - sudo dpkg -i libmbedtls-dev-ilp32_2.28.8-0ubuntu1_riscv32.deb - - sudo sed -i '/Types: deb/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources - - cat > ${RUNNER_TEMP}/riscv32_ilp32_toolchain.cmake <<'EOF' - # Toolchain file for RISC-V32 ILP32 (RV32-IMAC) cross-compilation - set(CMAKE_SYSTEM_NAME Linux) - set(CMAKE_SYSTEM_PROCESSOR riscv32) - set(CMAKE_C_LIBRARY_ARCHITECTURE riscv32-linux-gnu-ilp32) - - # Specify the cross compiler - set(CMAKE_C_COMPILER riscv32-unknown-linux-gnu-gcc) - set(CMAKE_CXX_COMPILER riscv32-unknown-linux-gnu-g++) - - # Specify the target architecture - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=rv32imac -mabi=ilp32" CACHE STRING "" FORCE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=rv32imac -mabi=ilp32" CACHE STRING "" FORCE) - - # Set up paths for cross-compiled libraries - set(ZLIB_LIBRARY /usr/lib/riscv32-linux-gnu-ilp32/libz.so CACHE FILEPATH "") - set(ZLIB_INCLUDE_DIR /usr/include/riscv32-linux-gnu CACHE PATH "") - set(ZLIB_FOUND TRUE CACHE BOOL "") - - # MbedTLS configuration - set(MBEDTLS_ROOT_DIR /usr) - set(MBEDTLS_LIBRARIES_DIR /usr/lib/riscv32-linux-gnu-ilp32) - - # Add cross-compilation include path to compiler flags - include_directories(SYSTEM /usr/include/riscv32-linux-gnu) - - # Search for programs in the build host directories - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - - # Search for libraries and headers in the target directories - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - EOF - - # Set up qemu-user binfmt to find libraries - sudo ln -s /opt/riscv32-ilp32/sysroot/lib/ld-linux-riscv32-ilp32.so.1 /lib/ld-linux-riscv32-ilp32.so.1 - sudo mkdir -p /usr/gnemul - sudo ln -s /opt/riscv32-ilp32/sysroot /usr/gnemul/qemu-riscv32 - - # Copy cross-compiled libraries to sysroot for qemu-user - sudo cp /usr/lib/${{ matrix.library-arch }}/libz.so.1* /opt/riscv32-ilp32/sysroot/lib/ - sudo cp /usr/lib/${{ matrix.library-arch }}/libmbedtls.so.14 /opt/riscv32-ilp32/sysroot/lib/ - sudo cp /usr/lib/${{ matrix.library-arch }}/libmbedcrypto.so.7 /opt/riscv32-ilp32/sysroot/lib/ - sudo cp /usr/lib/${{ matrix.library-arch }}/libmbedx509.so.1 /opt/riscv32-ilp32/sysroot/lib/ - - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: "Setup cross compilation architecture (xtensa)" - if: matrix.library-arch == 'xtensa-lx6-linux-gnu' - run: | - sudo dpkg --add-architecture ${{ matrix.arch }} - - # Download packages from pguyot/crossbuild-essential-xtensa - gh release download xtensa-toolchain-14.2.0.20260515 \ - -R pguyot/crossbuild-essential-xtensa \ - --pattern 'qemu-xtensa-esp_*.deb' \ - --pattern 'xtensa-lx6-linux-gnu-toolchain_*.deb' \ - --pattern 'libc6-lx6_*.deb' \ - --pattern 'libc6-dev-lx6_*.deb' \ - --pattern 'libc6-dbg-lx6_*.deb' \ - --pattern 'zlib1g-lx6_*.deb' \ - --pattern 'zlib1g-dev-lx6_*.deb' \ - --pattern 'libmbedcrypto7-lx6_*.deb' \ - --pattern 'libmbedx509-1-lx6_*.deb' \ - --pattern 'libmbedtls14-lx6_*.deb' \ - --pattern 'libmbedtls-dev-lx6_*.deb' - - # Install QEMU with binfmt support (activates automatically on systemd) - sudo dpkg -i qemu-xtensa-esp_*.deb - - # Install toolchain and add to PATH - sudo dpkg -i xtensa-lx6-linux-gnu-toolchain_*.deb - echo "/opt/xtensa-lx6/bin" >> $GITHUB_PATH - - # Install runtime libraries - sudo dpkg -i libc6-lx6_*.deb - sudo dpkg -i libc6-dev-lx6_*.deb - sudo dpkg -i libc6-dbg-lx6_*.deb - sudo dpkg -i zlib1g-lx6_*.deb - sudo dpkg -i zlib1g-dev-lx6_*.deb - sudo dpkg -i libmbedcrypto7-lx6_*.deb - sudo dpkg -i libmbedx509-1-lx6_*.deb - sudo dpkg -i libmbedtls14-lx6_*.deb - sudo dpkg -i libmbedtls-dev-lx6_*.deb - - # Create CMake toolchain file - cat > ${RUNNER_TEMP}/xtensa_toolchain.cmake <<'EOF' - set(CMAKE_SYSTEM_NAME Linux) - set(CMAKE_SYSTEM_PROCESSOR xtensa) - - set(CMAKE_C_COMPILER /opt/xtensa-lx6/bin/xtensa-lx6-linux-gnu-gcc) - set(CMAKE_CXX_COMPILER /opt/xtensa-lx6/bin/xtensa-lx6-linux-gnu-g++) - - set(CMAKE_SYSROOT /opt/xtensa-lx6/xtensa-lx6-linux-gnu/sysroot) - list(APPEND CMAKE_FIND_ROOT_PATH /usr) - set(CMAKE_C_LIBRARY_ARCHITECTURE xtensa-lx6-linux-gnu) - - include_directories(SYSTEM /usr/xtensa-lx6-linux-gnu/include) - - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - - set(ZLIB_LIBRARY /usr/xtensa-lx6-linux-gnu/lib/libz.so) - set(MBEDTLS_ROOT_DIR /usr) - set(MBEDTLS_LIBRARIES_DIR /usr/xtensa-lx6-linux-gnu/lib) - EOF - - # Register binfmt if not activated automatically - if [ ! -f /proc/sys/fs/binfmt_misc/qemu-xtensa-esp32 ]; then - echo ':qemu-xtensa-esp32:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x5e\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-xtensa:' | sudo tee /proc/sys/fs/binfmt_misc/register || true - fi - - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: "APT update" - run: sudo apt update -y - - - name: "Install deps" - if: matrix.container != '' - run: sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen valgrind libmbedtls-dev socat - - - name: "Install deps" - if: matrix.container == '' - run: | - sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen libmbedtls-dev libc6-dbg socat - # Get a more recent valgrind - sudo snap install valgrind --classic - - - name: "Checkout repo" - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - # There is no working arm64 binary for gleam - # https://github.com/erlef/setup-beam/issues/398 - - uses: erlef/setup-beam@v1 - if: matrix.os != 'ubuntu-24.04-arm' - with: - version-type: ${{ matrix.version_type || 'loose' }} - otp-version: ${{ matrix.otp || env.DEFAULT_OTP_VERSION }} - elixir-version: ${{ matrix.elixir_version || env.DEFAULT_ELIXIR_VERSION }} - rebar3-version: ${{ matrix.rebar3_version || env.DEFAULT_REBAR3_VERSION }} - gleam-version: ${{ matrix.gleam_version || env.DEFAULT_GLEAM_VERSION }} - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - uses: erlef/setup-beam@v1 - if: matrix.os == 'ubuntu-24.04-arm' - with: - version-type: ${{ matrix.version_type || 'loose' }} - otp-version: ${{ matrix.otp || env.DEFAULT_OTP_VERSION }} - elixir-version: ${{ matrix.elixir_version || env.DEFAULT_ELIXIR_VERSION }} - rebar3-version: ${{ matrix.rebar3_version || env.DEFAULT_REBAR3_VERSION }} - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - # Builder info - - name: "System info" - run: | - echo "**uname:**" - uname -a - echo "**libc version:**" - ldd --version - echo "**C Compiler version:**" - $CC --version - $CXX --version - echo "**CFLAGS:**" - echo $CFLAGS - echo "**Linker version:**" - ld --version - echo "**CMake version:**" - cmake --version - echo "**OTP version:**" - cat $(dirname $(which erlc))/../releases/RELEASES || true - - - name: "Setup locale" - if: matrix.locale != '' - run: | - echo "${{ matrix.locale }} UTF-8" | sudo tee -a /etc/locale.gen - sudo locale-gen - echo "LC_NUMERIC=${{ matrix.locale }}" >> $GITHUB_ENV - - # Build - - name: "Build: create build dir" - run: mkdir build - - - uses: actions/cache@v4 - id: cache - with: - path: 'build/tests/**/*.beam' - key: ${{ matrix.otp || env.DEFAULT_OTP_VERSION }}-${{ hashFiles('**/build-and-test.yaml', 'tests/**/*.erl', 'tests/**/*.hrl', 'tests/**/*.ex') }}-${{ matrix.jit_target_arch || 'nojit' }}-${{ contains(matrix.cmake_opts_other, 'AVM_DISABLE_JIT_DWARF=OFF') && 'dwarf' || 'nodwarf' }} - - - name: "Build: run cmake" - working-directory: build - run: | - cmake ${{ matrix.cmake_opts_fp }} ${{ matrix.cmake_opts_smp }} ${{ matrix.cmake_opts_other || env.DEFAULT_CMAKE_OPTS_OTHER }} .. - # git clone will use more recent timestamps than cached beam files - # touch them so we can benefit from the cache and avoid costly beam file rebuild. - find . -name '*.beam' -exec touch {} \; - - - name: "Build: run make" - working-directory: build - run: make -j3 - - - name: "Build: run dialyzer" - working-directory: build - run: make dialyzer - - # Test - - name: "Test: test-erlang with valgrind" - if: matrix.library-arch == '' - timeout-minutes: 30 - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./tests/test-erlang -s prime_smp - - - name: "Test: test-erlang" - timeout-minutes: 10 - working-directory: build - run: | - ulimit -c unlimited - ./tests/test-erlang -s prime_smp - - - name: "Test: test-enif with valgrind" - if: matrix.library-arch == '' - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./tests/test-enif - - - name: "Test: test-enif" - working-directory: build - run: | - ulimit -c unlimited - ./tests/test-enif - - - name: "Test: test-heap with valgrind" - if: matrix.library-arch == '' - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./tests/test-heap - - - name: "Test: test-heap" - working-directory: build - run: | - ulimit -c unlimited - ./tests/test-heap - - - name: "Test: test-jit_stream_flash with valgrind" - if: matrix.library-arch == '' - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./tests/test-jit_stream_flash - - - name: "Test: test-jit_stream_flash" - working-directory: build - run: | - ulimit -c unlimited - ./tests/test-jit_stream_flash - - - name: "Test: test-mailbox with valgrind" - if: matrix.library-arch == '' - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./tests/test-mailbox - - - name: "Test: test-mailbox" - working-directory: build - run: | - ulimit -c unlimited - ./tests/test-mailbox - - - name: "Test: test-structs with valgrind" - if: matrix.library-arch == '' - timeout-minutes: 10 - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./tests/test-structs - - - name: "Test: test-structs" - timeout-minutes: 10 - working-directory: build - run: | - ulimit -c unlimited - ./tests/test-structs - - - name: "Test: test_etest.avm with valgrind" - if: matrix.library-arch == '' - timeout-minutes: 5 - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/etest/test_etest.avm - - - name: "Test: test_etest.avm" - timeout-minutes: 5 - working-directory: build - run: | - ulimit -c unlimited - ./src/AtomVM ./tests/libs/etest/test_etest.avm - - - name: "Test: test_estdlib.avm with valgrind" - if: matrix.library-arch == '' && !contains(matrix.cmake_opts_other, '-DAVM_DISABLE_JIT=OFF') - timeout-minutes: 45 - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm - - - name: "Test: test_estdlib.avm" - timeout-minutes: 20 - working-directory: build - run: | - ulimit -c unlimited - ./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm - - - name: "Test: test_eavmlib.avm with valgrind" - if: matrix.library-arch == '' - timeout-minutes: 10 - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm - - - name: "Test: test_eavmlib.avm" - timeout-minutes: 10 - working-directory: build - run: | - ulimit -c unlimited - ./src/AtomVM ./tests/libs/eavmlib/test_eavmlib.avm - - - name: "Test: test_jit.avm with valgrind" - if: matrix.library-arch == '' && !contains(matrix.cmake_opts_other, '-DAVM_DISABLE_JIT=OFF') - timeout-minutes: 60 - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./src/AtomVM tests/libs/jit/test_jit.avm - - - name: "Test: test_jit.avm" - timeout-minutes: 120 - working-directory: build - run: | - ulimit -c unlimited - ./src/AtomVM tests/libs/jit/test_jit.avm - - - name: "Test: test_alisp.avm with valgrind" - if: matrix.library-arch == '' - timeout-minutes: 20 - working-directory: build - run: | - ulimit -c unlimited - valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/alisp/test_alisp.avm - - - name: "Test: test_alisp.avm" - timeout-minutes: 10 - working-directory: build - run: | - ulimit -c unlimited - ./src/AtomVM ./tests/libs/alisp/test_alisp.avm - - - name: "Test: Tests.avm (Elixir) with valgrind" - if: matrix.library-arch == '' - timeout-minutes: 20 - working-directory: build - run: | - ulimit -c unlimited - if command -v elixirc >/dev/null 2>&1 && command -v elixir >/dev/null 2>&1 - then - valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/exavmlib/Tests.avm - else - echo "Elixir not installed, skipping Elixir tests" - fi - - - name: "Test: Tests.avm (Elixir)" - timeout-minutes: 10 - working-directory: build - run: | - ulimit -c unlimited - if command -v elixirc >/dev/null 2>&1 && command -v elixir >/dev/null 2>&1 - then - ./src/AtomVM ./tests/libs/exavmlib/Tests.avm - else - echo "Elixir not installed, skipping Elixir tests" - fi - - - name: "Install and smoke test" - working-directory: build - run: | - ulimit -c unlimited - sudo PATH=${PATH} make install - atomvm examples/erlang/hello_world.avm - atomvm -v - atomvm -h - - - name: "Run coredumpctl info" - if: ${{ failure() }} - run: | - # Wait until systemd-coredump finished - while ps x | grep -cE 'systemd-[c]oredump'; do - echo systemd-coredump is still running - sleep 1 - done - # info works on all versions of ubuntu - coredumpctl info || true - # The following only works on recent versions of ubuntu - coredumpctl debug --debugger-arguments="-batch -ex 'info all-registers'" || true - coredumpctl debug --debugger-arguments="-batch -ex 'info threads'" || true - coredumpctl debug --debugger-arguments="-batch -ex 'thread apply all bt full'" || true - coredumpctl debug --debugger-arguments='-batch -ex "display /10i $pc"' || true - coredumpctl dump -o core.dump || true - if [ -e core.dump ]; then - mkdir core - mv core.dump core/ - cp build/src/AtomVM core/ - cp build/tests/test-* core/ - fi - - - name: "Upload any dumped core" - uses: actions/upload-artifact@v4 - if: ${{ failure() }} - with: - name: core-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.otp || env.DEFAULT_OTP_VERSION }}-${{ github.run_id }}-${{ github.run_attempt }} - path: | - core/* - retention-days: 5 diff --git a/.github/workflows/build-docs.yaml b/.github/workflows/build-docs.yaml deleted file mode 100644 index 2e4a098ada..0000000000 --- a/.github/workflows/build-docs.yaml +++ /dev/null @@ -1,127 +0,0 @@ -# -# Copyright 2023 Winford (Uncle Grumpy) -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# -# This is a workflow for atomvm/AtomVM to Publish API documentation and other content from the `doc` directory to -# doc.atomvm.org hosted on GitHub Pages - -name: Build Docs - -# Controls when the workflow will run -on: - # Triggers the workflow on push request and tag events on main branch - pull_request: - tags: - - '**' - branches: - - 'main' - - 'release-**' - paths: - - '.github/workflows/**' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'doc/**' - - 'libs/**' - - 'src/libAtomVM/**' - - 'UPDATING.md' - - 'CONTRIBUTING.md' - - 'CHANGELOG.md' - - 'CODE_OF_CONDUCT.md' - push: - repositories: - - '!atomvm/AtomVM' - paths: - - '.github/workflows/**' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'doc/**' - - 'libs/**' - - 'src/libAtomVM/**' - - 'UPDATING.md' - - 'CONTRIBUTING.md' - - 'CHANGELOG.md' - - 'CODE_OF_CONDUCT.md' - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - - strategy: - fail-fast: false - ## don't add more than one OS to matrix, this is only to retrieve the full os-name for keeping cache in sync - matrix: - os: [ ubuntu-24.04 ] - # The type of runner that the job will run on - runs-on: ${{ matrix.os }} - container: erlang:28.1 - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - name: Install Deps - run: | - apt update -y - DEBIAN_FRONTEND=noninteractive apt install -y git cmake doxygen graphviz python3-pip python3-virtualenv python3-setuptools python3-stemmer wget - - - uses: actions/cache@v4 - id: sphinx-cache - with: - path: /home/runner/python-env/sphinx - key: ${{ matrix.os }}-${{ job.container.id }}-sphinx-install - - - name: Install Sphinx - if: ${{ steps.sphinx-cache.outputs.cache-hit != 'true' }} - run: | - virtualenv /home/runner/python-env/sphinx - . /home/runner/python-env/sphinx/bin/activate - python3 -m pip install sphinx - python3 -m pip install myst-parser - python3 -m pip install sphinx-rtd-theme - python3 -m pip install rinohtype - python3 -m pip install pillow - python3 -m pip install gitpython - python3 -m pip install breathe - python3 -m pip install pygments - - - name: Set docs target name - shell: bash - run: | - if [[ ${{ github.ref_name }} == *"/merge" ]]; then - echo "AVM_DOCS_NAME=${{ github.event.pull_request.base.ref }}" | tr '/' '-' >> "$GITHUB_ENV"; - else - echo "AVM_DOCS_NAME=${{ github.ref_name }}" | tr '/' '-' >> "$GITHUB_ENV"; - fi - - - uses: actions/checkout@v4 - with: - repository: ${{ vars.GITHUB_REPOSITORY }} - fetch-depth: 0 - - - name: Track all branches - shell: bash - run: | - git config --global --add safe.directory /__w/AtomVM/AtomVM - for branch in `git branch -a | grep "remotes/origin" | grep -v HEAD | grep -v "${{ github.ref_name }}"`; do - git branch --track ${branch#remotes/origin/} $branch - done - - - name: Build Site - id: build - shell: bash - run: | - . /home/runner/python-env/sphinx/bin/activate - git config --global --add safe.directory ${PWD} - mkdir build - cd build - cmake .. - cd doc - make GitHub_CI_Publish_Docs diff --git a/.github/workflows/build-libraries.yaml b/.github/workflows/build-libraries.yaml deleted file mode 100644 index b18158c7fa..0000000000 --- a/.github/workflows/build-libraries.yaml +++ /dev/null @@ -1,149 +0,0 @@ -# -# Copyright 2017-2023 Davide Bettio -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: Build Libraries - -on: - push: - tags: - - '**' - -permissions: - contents: write - -jobs: - build-libraries: - runs-on: "ubuntu-24.04" - strategy: - fail-fast: false - - steps: - - name: "Checkout repo" - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - - uses: erlef/setup-beam@v1 - with: - otp-version: "28" - elixir-version: "1.19" - rebar3-version: "3.25.1" - gleam-version: "1.15.2" - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: "APT update" - run: sudo apt update -y - - - name: "Install deps" - run: | - sudo apt install -y build-essential cmake gperf zlib1g-dev libmbedtls-dev - # Get a more recent valgrind - sudo snap install valgrind --classic - - # Builder info - - name: "System info" - run: | - echo "**uname:**" - uname -a - echo "**libc version:**" - ldd --version - echo "**C Compiler version:**" - cc --version - c++ --version - echo "**Linker version:**" - ld --version - echo "**CMake version:**" - cmake --version - echo "**OTP version:**" - cat $(dirname $(which erlc))/../releases/RELEASES || true - - # Build - - name: "Build: create build dir" - run: mkdir build - - - name: "Build: run cmake" - working-directory: build - run: | - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. - - - name: "Build: run make" - working-directory: build - run: make - - - name: "Build: run dialyzer" - working-directory: build - run: make dialyzer - - - name: "Test: test_alisp.avm with valgrind" - timeout-minutes: 5 - working-directory: build - run: | - valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/etest/test_alisp.avm - - - name: "Test: test_alisp.avm" - timeout-minutes: 5 - working-directory: build - run: | - ./src/AtomVM ./tests/libs/etest/test_alisp.avm - - - name: "Test: test_etest.avm with valgrind" - timeout-minutes: 5 - working-directory: build - run: | - valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/etest/test_etest.avm - - - name: "Test: test_etest.avm" - timeout-minutes: 5 - working-directory: build - run: | - ./src/AtomVM ./tests/libs/etest/test_etest.avm - - - name: "Test: test_estdlib.avm with valgrind" - timeout-minutes: 10 - working-directory: build - run: | - valgrind --error-exitcode=1 ./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm - - - name: "Test: test_estdlib.avm" - timeout-minutes: 10 - working-directory: build - run: | - ./src/AtomVM ./tests/libs/estdlib/test_estdlib.avm - - - name: "Rename and write sha256sum" - working-directory: build - run: | - for variant in atomvmlib atomvmlib-esp32 atomvmlib-rp2 atomvmlib-stm32 atomvmlib-emscripten; do - VARIANT_FILE="${variant}-${{ github.ref_name }}.avm" - mv "libs/${variant}.avm" "libs/${VARIANT_FILE}" && - sha256sum "libs/${VARIANT_FILE}" > "libs/${VARIANT_FILE}.sha256" - done - HELLO_WORLD_FILE=hello_world-${{ github.ref_name }}.avm - mv examples/erlang/hello_world.avm "examples/erlang/${HELLO_WORLD_FILE}" - sha256sum "examples/erlang/${HELLO_WORLD_FILE}" > "examples/erlang/${HELLO_WORLD_FILE}.sha256" - - - name: Release - uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') - with: - draft: true - fail_on_unmatched_files: true - files: | - build/libs/atomvmlib-${{ github.ref_name }}.avm - build/libs/atomvmlib-${{ github.ref_name }}.avm.sha256 - build/libs/atomvmlib-esp32-${{ github.ref_name }}.avm - build/libs/atomvmlib-esp32-${{ github.ref_name }}.avm.sha256 - build/libs/atomvmlib-rp2-${{ github.ref_name }}.avm - build/libs/atomvmlib-rp2-${{ github.ref_name }}.avm.sha256 - build/libs/atomvmlib-stm32-${{ github.ref_name }}.avm - build/libs/atomvmlib-stm32-${{ github.ref_name }}.avm.sha256 - build/libs/atomvmlib-emscripten-${{ github.ref_name }}.avm - build/libs/atomvmlib-emscripten-${{ github.ref_name }}.avm.sha256 - build/examples/erlang/hello_world-${{ github.ref_name }}.avm - build/examples/erlang/hello_world-${{ github.ref_name }}.avm.sha256 diff --git a/.github/workflows/build-linux-artifacts.yaml b/.github/workflows/build-linux-artifacts.yaml deleted file mode 100644 index ff9018cc70..0000000000 --- a/.github/workflows/build-linux-artifacts.yaml +++ /dev/null @@ -1,265 +0,0 @@ -# -# Copyright 2022 Davide Bettio -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: Build Linux Artifacts - -on: - push: - tags: - - '**' - -permissions: - contents: write - -env: - otp_version: 28 - elixir_version: 1.19 - rebar3_version: 3.25.1 - -jobs: - compile_tests: - runs-on: ubuntu-24.04 - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - uses: erlef/setup-beam@v1 - with: - otp-version: ${{ env.otp_version }} - elixir-version: ${{ env.elixir_version }} - rebar3-version: ${{ env.rebar3_version }} - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: apt update - run: sudo apt update - - - name: Install required packages - run: sudo apt install -y gperf - - - name: Compile test modules - run: | - set -e - mkdir build_tests - cd build_tests - cmake .. - make erlang_test_modules - make test_etest - make test_estdlib - make test_eavmlib - make test_alisp - - - name: Upload test modules - uses: actions/upload-artifact@v4 - with: - name: test-modules - path: | - build_tests/**/*.avm - build_tests/**/*.beam - build_tests/**/*.hrl - retention-days: 1 - - build-and-test-other: - needs: compile_tests - runs-on: ubuntu-22.04 - - strategy: - fail-fast: false - matrix: - include: - - arch: "arm32v5" - build_name: "linux-arm32v5" - docker_image: "arm32v5/debian" - platform: "arm/v5" - cflags: "-mthumb -mthumb-interwork -march=armv4t" - cmake_opts: "-DAVM_DISABLE_SMP=On -DAVM_DISABLE_TASK_DRIVER=On" - tag: "stretch" - sources: | - deb [trusted=yes] http://archive.debian.org/debian/ stretch-backports main - deb [trusted=yes] http://archive.debian.org/debian/ stretch-backports-sloppy main - deb [trusted=yes] http://archive.debian.org/debian-security/ stretch/updates main - deb-src [trusted=yes] http://archive.debian.org/debian-security/ stretch/updates main - deb [trusted=yes] http://archive.debian.org/debian/ stretch main - deb-src [trusted=yes] http://archive.debian.org/debian/ stretch main - # Workaround from https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=954852 - install_deps: | - apt update && - apt install -y -t stretch-backports-sloppy libarchive13 && - apt install -y -t stretch-backports cmake && - apt install -y file gcc g++ binutils make doxygen gperf zlib1g-dev libmbedtls-dev tzdata - - - arch: "arm32v7" - build_name: "linux-arm32v7thl" - docker_image: "arm32v7/debian" - platform: "arm/v7" - tag: "stretch" - cflags: "-mfloat-abi=hard -mthumb -mthumb-interwork" - sources: | - deb [trusted=yes] http://archive.debian.org/debian/ stretch-backports main - deb [trusted=yes] http://archive.debian.org/debian/ stretch-backports-sloppy main - deb [trusted=yes] http://archive.debian.org/debian-security/ stretch/updates main - deb-src [trusted=yes] http://archive.debian.org/debian-security/ stretch/updates main - deb [trusted=yes] http://archive.debian.org/debian/ stretch main - deb-src [trusted=yes] http://archive.debian.org/debian/ stretch main - # Workaround from https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=954852 - install_deps: | - apt update && - apt install -y -t stretch-backports-sloppy libarchive13 && - apt install -y -t stretch-backports cmake && - apt install -y file gcc g++ binutils make doxygen gperf zlib1g-dev libmbedtls-dev tzdata - - - arch: "arm64v8" - build_name: "linux-arm64v8" - docker_image: "arm64v8/ubuntu" - platform: "arm64/v8" - tag: "22.04" - cflags: "" - - - arch: "riscv64" - build_name: "linux-riscv64" - docker_image: "riscv64/ubuntu" - platform: "riscv64" - tag: "22.04" - cflags: "" - - - arch: "x86_64" - build_name: "linux-x86_64-static-mbedtls" - docker_image: "ubuntu" - platform: "amd64" - tag: "18.04" - cflags: "" - cmake_opts: "-DAVM_STATIC_MBEDTLS=ON" - install_deps: | - apt update && - apt install -y file gcc g++ binutils make doxygen gperf zlib1g-dev libmbedtls-dev wget tzdata && - apt purge -y cmake && - wget https://cmake.org/files/v3.13/cmake-3.13.5-Linux-x86_64.tar.gz && - tar xf cmake-3.13.5-Linux-x86_64.tar.gz && - mv cmake-3.13.5-Linux-x86_64 /opt/cmake-3.13.5 && - ln -sf /opt/cmake-3.13.5/bin/* /usr/bin/ - - - arch: "x86_64" - build_name: "linux-x86_64" - docker_image: "ubuntu" - platform: "amd64" - tag: "18.04" - cflags: "" - install_deps: | - apt update && - apt install -y file gcc g++ binutils make doxygen gperf zlib1g-dev libmbedtls-dev wget tzdata && - apt purge -y cmake && - wget https://cmake.org/files/v3.13/cmake-3.13.5-Linux-x86_64.tar.gz && - tar xf cmake-3.13.5-Linux-x86_64.tar.gz && - mv cmake-3.13.5-Linux-x86_64 /opt/cmake-3.13.5 && - ln -sf /opt/cmake-3.13.5/bin/* /usr/bin/ - - - arch: "i386" - build_name: "linux-i386" - docker_image: "i386/debian" - platform: "386" - cflags: "" - tag: "stretch" - sources: | - deb [trusted=yes] http://archive.debian.org/debian/ stretch-backports main - deb [trusted=yes] http://archive.debian.org/debian/ stretch-backports-sloppy main - deb [trusted=yes] http://archive.debian.org/debian-security/ stretch/updates main - deb-src [trusted=yes] http://archive.debian.org/debian-security/ stretch/updates main - deb [trusted=yes] http://archive.debian.org/debian/ stretch main - deb-src [trusted=yes] http://archive.debian.org/debian/ stretch main - # Workaround from https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=954852 - install_deps: | - apt update && - apt install -y -t stretch-backports-sloppy libarchive13 && - apt install -y -t stretch-backports cmake && - apt install -y file gcc g++ binutils make doxygen gperf zlib1g-dev libmbedtls-dev - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: apt update - run: sudo apt update - - - name: Install required packages - run: sudo apt install -y debootstrap - - - name: Download test modules - uses: actions/download-artifact@v4 - with: - name: test-modules - path: build_tests - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Build AtomVM using docker - timeout-minutes: 15 - run: | - docker run --platform linux/${{ matrix.platform }} --rm -v $PWD:/atomvm -w /atomvm \ - -e CFLAGS="${{ matrix.cflags }}" -e CXXFLAGS="${{ matrix.cflags }}" \ - ${{ matrix.docker_image }}:${{ matrix.tag }} /bin/bash -c ' - ([ -n "${{ matrix.sources }}" ] && echo "${{ matrix.sources }}" > /etc/apt/sources.list || true) && - cat /etc/apt/sources.list && - if test -n "${{ matrix.install_deps }}"; then - echo - ${{ matrix.install_deps }} - else - apt update && - apt install -y file gcc g++ binutils cmake make doxygen gperf zlib1g-dev libmbedtls-dev tzdata - fi && - file /bin/bash && - uname -a && - cc --version && - ld --version && - ldd --version && - echo $CFLAGS && - echo $CXXFLAGS && - cmake --version && - mkdir -p build && - cd build && - cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo ${{ matrix.cmake_opts }} && - cp ../build_tests/tests/erlang_tests/*.beam tests/erlang_tests/ && - cp ../build_tests/tests/erlang_tests/code_load/*.{avm,beam,hrl} tests/erlang_tests/code_load/ && - mkdir -p tests/erlang_tests/code_load/beams/ && - cp ../build_tests/tests/erlang_tests/code_load/beams/*.beam tests/erlang_tests/code_load/beams/ && - cp ../build_tests/tests/libs/estdlib/*.avm tests/libs/estdlib/ && - cp ../build_tests/tests/libs/eavmlib/*.avm tests/libs/eavmlib/ && - cp ../build_tests/tests/libs/alisp/*.avm tests/libs/alisp/ && - VERBOSE=1 make AtomVM && - make test-erlang && - make test-enif && - make test-heap && - make test-mailbox && - make test-structs && - file ./tests/test-erlang && - ./tests/test-erlang -s prime_smp && - file ./tests/test-enif && - ./tests/test-enif && - file ./tests/test-heap && - ./tests/test-heap && - file ./tests/test-mailbox && - ./tests/test-mailbox && - file ./tests/test-structs && - ./tests/test-structs && - file ./src/AtomVM && - ./src/AtomVM tests/libs/etest/test_etest.avm && - ./src/AtomVM tests/libs/estdlib/test_estdlib.avm && - ./src/AtomVM tests/libs/eavmlib/test_eavmlib.avm && - ./src/AtomVM tests/libs/alisp/test_alisp.avm && - cp ./src/AtomVM ./AtomVM-${{ matrix.build_name }}-${{ github.ref_name }} && - sha256sum ./src/AtomVM > ./AtomVM-${{ matrix.build_name }}-${{ github.ref_name }}.sha256 - ' - - - name: Release - uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') - with: - draft: true - fail_on_unmatched_files: true - files: | - build/AtomVM* diff --git a/.github/workflows/check-formatting.yaml b/.github/workflows/check-formatting.yaml deleted file mode 100644 index 79a67f96b1..0000000000 --- a/.github/workflows/check-formatting.yaml +++ /dev/null @@ -1,81 +0,0 @@ -# -# Copyright 2022 Davide Bettio -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: "Check formatting" - -on: - push: - paths: - - '.github/workflows/**' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'src/**' - - 'tests/**' - - '**/*.erl' - pull_request: - paths: - - '.github/workflows/**' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'src/**' - - 'tests/**' - - '**/*.erl' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - clang-format-prettier-check: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4 - - - name: "Install run-clang-format" - run: | - wget -q -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-16 main" | sudo tee -a /etc/apt/sources.list - echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-16 main" | sudo tee -a /etc/apt/sources.list - sudo apt-get update - sudo apt-get install -y clang-format-16 - curl -sSfL https://raw.githubusercontent.com/Sarcasm/run-clang-format/master/run-clang-format.py -o run-clang-format - chmod +x run-clang-format - - - name: "Check formatting with clang-format" - run: | - ./run-clang-format --style=file --clang-format-executable=clang-format-16 -r src/ tests/ - - - name: "Check formatting with prettier" - if: success() || failure() - run: | - npm install prettier - find ../src/platforms/emscripten/ ../examples/emscripten/ -name "*.js" -o -name "*.html" | xargs npx prettier -c - - erlfmt-check: - runs-on: ubuntu-24.04 - container: erlang:28 - steps: - - uses: actions/checkout@v4 - - - name: "Check formatting with Erlang fmt" - run: | - cd .. - git clone --depth 1 -b v1.7.0 https://github.com/WhatsApp/erlfmt.git - cd erlfmt - rebar3 as release escriptize - cd ../AtomVM - find . -name *.erl | xargs ../erlfmt/_build/release/bin/erlfmt -c - - mix-format-check: - runs-on: ubuntu-24.04 - container: elixir:1.17.1 - steps: - - uses: actions/checkout@v4 - - - name: "Check formatting with Elixir mix format" - run: | - cd libs/exavmlib/ - mix format --check-formatted diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml deleted file mode 100644 index 5b2e08f45b..0000000000 --- a/.github/workflows/codeql-analysis.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# -# Copyright 2022 Davide Bettio -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: "CodeQL" - -on: - push: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'libs/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - pull_request: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'libs/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - schedule: - - cron: '45 18 * * 5' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-24.04 - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'cpp' ] - - steps: - - name: "APT update" - run: sudo apt update -y - - - name: "Install deps" - run: sudo apt install -y cmake gperf zlib1g-dev ninja-build - - - uses: erlef/setup-beam@v1 - with: - otp-version: "28" - elixir-version: "1.19" - rebar3-version: "3.25.1" - gleam-version: "1.11.1" - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: "Checkout repository" - uses: actions/checkout@v4 - - - name: "Initialize CodeQL" - uses: github/codeql-action/init@v4 - with: - languages: ${{ matrix.language }} - build-mode: manual - queries: +./code-queries/term-to-non-term-func.ql,./code-queries/non-term-to-term-func.ql,./code-queries/mismatched-atom-string-length.ql,./code-queries/mismatched-free-type.ql,./code-queries/term-use-after-gc.ql,./code-queries/allocations-exceeding-ensure-free.ql,./code-queries/allocations-without-ensure-free.ql - - - name: "Build" - run: | - mkdir build - cd build - cmake .. -G Ninja - ninja - - - name: "Perform CodeQL Analysis" - uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/esp32-build.yaml b/.github/workflows/esp32-build.yaml deleted file mode 100644 index 35e32d685e..0000000000 --- a/.github/workflows/esp32-build.yaml +++ /dev/null @@ -1,317 +0,0 @@ -# -# Copyright 2022 Davide Bettio -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: ESP32 Builds - -on: - push: - paths: - - '.github/workflows/esp32-build.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'libs/**' - - 'src/platforms/esp32/**' - - 'src/platforms/esp32/**/**' - - 'src/libAtomVM/**' - - 'tools/packbeam/**' - pull_request: - paths: - - '.github/workflows/esp32-build.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'libs/**' - - 'src/platforms/esp32/**' - - 'src/platforms/esp32/**/**' - - 'src/libAtomVM/**' - - 'tools/packbeam/**' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - esp-idf: - runs-on: ubuntu-24.04 - container: espressif/idf:${{ matrix.idf-version }} - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - - matrix: - esp-idf-target: ["esp32", "esp32c3"] - idf-version: - - 'v5.2.7' - - 'v5.3.5' - - 'v5.4.4' - - 'v5.5.4' - jit: [false] - - include: - - esp-idf-target: "esp32p4" - idf-version: 'v5.4.4' - jit: false - - esp-idf-target: "esp32p4" - idf-version: 'v5.5.4' - jit: false - - esp-idf-target: "esp32s3" - idf-version: 'v5.5.4' - jit: false - - esp-idf-target: "esp32s3" - idf-version: 'v5.5.4' - usb-serial: 'ON' - jit: false - - esp-idf-target: "esp32s3" - idf-version: 'v5.5.4' - usb-cdc: 'ON' - jit: false - - esp-idf-target: "esp32" - idf-version: 'v5.4.4' - libsodium: 'ON' - jit: false - # JIT builds (v5.5.4 only) - - esp-idf-target: "esp32c3" - idf-version: 'v5.5.4' - jit: true - - esp-idf-target: "esp32" - idf-version: 'v5.5.4' - jit: true - - esp-idf-target: "esp32s3" - idf-version: 'v5.5.4' - jit: true - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: "Git config safe.directory for codeql" - run: git config --global --add safe.directory /__w/AtomVM/AtomVM - - - name: "Initialize CodeQL" - uses: github/codeql-action/init@v4 - with: - languages: "cpp" - build-mode: manual - queries: +./code-queries/term-to-non-term-func.ql,./code-queries/non-term-to-term-func.ql,./code-queries/mismatched-atom-string-length.ql,./code-queries/mismatched-free-type.ql,./code-queries/term-use-after-gc.ql,./code-queries/allocations-exceeding-ensure-free.ql,./code-queries/allocations-without-ensure-free.ql - - - name: Add libsodium dependency - if: matrix.libsodium == 'ON' - working-directory: ./src/platforms/esp32/ - run: | - . $IDF_PATH/export.sh - idf.py add-dependency "espressif/libsodium^1.0.20~4" - - - name: Add ESP TinyUSB dependency - if: matrix.usb-serial == 'ON' || matrix.usb-cdc == 'ON' - working-directory: ./src/platforms/esp32/ - run: | - . $IDF_PATH/export.sh - idf.py add-dependency "espressif/esp_tinyusb^2.0.0" - - - name: Build with idf.py - shell: bash - working-directory: ./src/platforms/esp32/ - env: - USB_SERIAL: ${{ matrix.usb-serial || 'OFF' }} - USB_CDC: ${{ matrix.usb-cdc || 'OFF' }} - run: | - . $IDF_PATH/export.sh - if [[ "${USB_SERIAL}" == "ON" ]]; then - echo 'CONFIG_USE_USB_SERIAL=y' >> sdkconfig.defaults.in - fi - if [[ "${USB_CDC}" == "ON" ]]; then - printf '%s\n' \ - 'CONFIG_TINYUSB_CDC_ENABLED=y' \ - 'CONFIG_AVM_ENABLE_USB_CDC_PORT_DRIVER=y' \ - >> sdkconfig.defaults.in - fi - export IDF_TARGET=${{matrix.esp-idf-target}} - if [ "${{ matrix.jit }}" = "true" ]; then - SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.jit" idf.py set-target ${{matrix.esp-idf-target}} - SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.jit" idf.py build - else - idf.py set-target ${{matrix.esp-idf-target}} - idf.py ${{ matrix.libsodium == 'ON' && '-DAVM_USE_LIBSODIUM=ON' || '' }} build - fi - - - name: Print size info with idf.py - if: matrix.idf-version != 'v5.2.7' - shell: bash - working-directory: ./src/platforms/esp32/ - run: | - . $IDF_PATH/export.sh - idf.py size - idf.py size-components - - - name: "Perform CodeQL Analysis" - uses: github/codeql-action/analyze@v4 - - - name: Install dependencies to build host AtomVM and run qemu - run: | - set -eu - apt update - DEBIAN_FRONTEND=noninteractive apt install -y -q \ - doxygen libglib2.0-0 libpixman-1-0 \ - gcc g++ zlib1g-dev libsdl2-2.0-0 libslirp0 libmbedtls-dev - - - name: "Set ImageOS for erlef/setup-beam" - run: | - sed -n -E -e 's|VERSION_ID="(.+)\..+"|ImageOS=ubuntu\1|p' /etc/os-release >> ${GITHUB_ENV} - - - uses: erlef/setup-beam@v1 - with: - otp-version: "28" - elixir-version: "1.19" - rebar3-version: "3.25.1" - gleam-version: "1.11.1" - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: Install qemu binary from espressif/qemu esp32 - if: runner.arch != 'ARM64' && runner.os == 'Linux' && (matrix.esp-idf-target == 'esp32' || matrix.esp-idf-target == 'esp32s3') - run: | - set -eu - QEMU_VER=esp-develop-9.2.2-20250817 - QEMU_XTENSA_DIST=qemu-xtensa-softmmu-esp_develop_9.2.2_20250817-x86_64-linux-gnu.tar.xz - QEMU_XTENSA_SHA256=588bfaccd0f929650655d10a580f020c6ba9c131712d8fa519280081b8d126eb - wget --no-verbose https://github.com/espressif/qemu/releases/download/${QEMU_VER}/${QEMU_XTENSA_DIST} - echo "${QEMU_XTENSA_SHA256} *${QEMU_XTENSA_DIST}" | sha256sum --check --strict - - tar -xf ${QEMU_XTENSA_DIST} -C /opt && rm ${QEMU_XTENSA_DIST} - - - name: Install qemu binary from espressif/qemu esp32c3 - if: runner.arch != 'ARM64' && runner.os == 'Linux' && matrix.esp-idf-target == 'esp32c3' - run: | - set -eu - QEMU_VER=esp-develop-9.2.2-20250817 - QEMU_RISCV32_DIST=qemu-riscv32-softmmu-esp_develop_9.2.2_20250817-x86_64-linux-gnu.tar.xz - QEMU_RISCV32_SHA256=373b37a68bae3ef441ead24a7bfc950fcbfc274cbdd2b628fc6915f179eb1d8e - wget --no-verbose https://github.com/espressif/qemu/releases/download/${QEMU_VER}/${QEMU_RISCV32_DIST} - echo "${QEMU_RISCV32_SHA256} *${QEMU_RISCV32_DIST}" | sha256sum --check --strict - - tar -xf ${QEMU_RISCV32_DIST} -C /opt && rm ${QEMU_RISCV32_DIST} - - - name: Install qemu binary from espressif/qemu ARM64 esp32 - if: runner.arch == 'ARM64' && runner.os == 'Linux' && (matrix.esp-idf-target == 'esp32' || matrix.esp-idf-target == 'esp32s3') - run: | - set -eu - QEMU_VER=esp-develop-9.2.2-20250817 - QEMU_XTENSA_DIST=qemu-xtensa-softmmu-esp_develop_9.2.2_20250817-aarch64-linux-gnu.tar.xz - QEMU_XTENSA_SHA256=317f6e0fd1dba0886d8110709823d909593ef29438822a14f81ebe19d72ce7cd - wget --no-verbose https://github.com/espressif/qemu/releases/download/${QEMU_VER}/${QEMU_XTENSA_DIST} - echo "${QEMU_XTENSA_SHA256} *${QEMU_XTENSA_DIST}" | sha256sum --check --strict - - tar -xf ${QEMU_XTENSA_DIST} -C /opt && rm ${QEMU_XTENSA_DIST} - - - name: Install qemu binary from espressif/qemu ARM64 esp32c3 - if: runner.arch == 'ARM64' && runner.os == 'Linux' && matrix.esp-idf-target == 'esp32c3' - run: | - set -eu - QEMU_VER=esp-develop-9.2.2-20250817 - QEMU_RISCV32_DIST=qemu-riscv32-softmmu-esp_develop_9.2.2_20250817-aarch64-linux-gnu.tar.xz - QEMU_RISCV32_SHA256=f907a54313058f8a9681d2f48257d518950ff98bcd5a319194b4bee7c10cf223 - wget --no-verbose https://github.com/espressif/qemu/releases/download/${QEMU_VER}/${QEMU_RISCV32_DIST} - echo "${QEMU_RISCV32_SHA256} *${QEMU_RISCV32_DIST}" | sha256sum --check --strict - - tar -xf ${QEMU_RISCV32_DIST} -C /opt && rm ${QEMU_RISCV32_DIST} - - - name: Install pytest and pytest-embedded plugins - # ESP32P4 is not currently supported by espressif/qemu, but an issue has been opened - # (https://github.com/espressif/qemu/issues/127) and marked as "todo" status, but no - # expected timeline is available yet. - # TODO: remove the following exclusion when ESP32P4 support is added to espressif/qemu - if: matrix.esp-idf-target != 'esp32p4' - run: | - set -e - . $IDF_PATH/export.sh - pip install pytest==8.3.3 \ - esptool==5.2.0 \ - pytest-embedded==2.7.0 \ - pytest-embedded-serial-esp==2.7.0 \ - pytest-embedded-idf==2.7.0 \ - pytest-embedded-qemu==2.7.0 - - - name: Build ESP32 tests using idf.py with memory checks - # TODO: remove the following exclusion when ESP32P4 support is added to espressif/qemu - if: matrix.esp-idf-target != 'esp32p4' - working-directory: ./src/platforms/esp32/test/ - run: | - set -e - export PATH=${PATH}:${HOME}/.cache/rebar3/bin - cp sdkconfig.defaults sdkconfig.defaults.backup - echo "CONFIG_COMPILER_STACK_CHECK_MODE_ALL=y" >> sdkconfig.defaults - echo "CONFIG_COMPILER_STACK_CHECK=y" >> sdkconfig.defaults - echo "CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y" >> sdkconfig.defaults - echo "CONFIG_HEAP_POISONING_COMPREHENSIVE=y" >> sdkconfig.defaults - echo "CONFIG_ESP_WIFI_IRAM_OPT=n" >> sdkconfig.defaults - echo "CONFIG_ESP_WIFI_RX_IRAM_OPT=n" >> sdkconfig.defaults - if [ "${{ matrix.jit }}" = "true" ]; then - echo "CONFIG_JIT_ENABLED=y" >> sdkconfig.defaults - fi - . $IDF_PATH/export.sh - export IDF_TARGET=${{matrix.esp-idf-target}} - idf.py set-target ${{matrix.esp-idf-target}} - idf.py build - - - name: Run ESP32 tests using qemu with memory checks build - # TODO: remove the following exclusion when ESP32P4 support is added to espressif/qemu - if: matrix.esp-idf-target != 'esp32p4' - working-directory: ./src/platforms/esp32/test/ - timeout-minutes: 10 - run: | - set -e - . $IDF_PATH/export.sh - export PATH=/opt/qemu/bin:${PATH} - pytest --target=${{matrix.esp-idf-target}} --embedded-services=idf,qemu -s - idf.py clean - cp sdkconfig.defaults.backup sdkconfig.defaults - - - name: Upload ESP32 tests ELF artifact with memory checks build - # TODO: remove the following exclusion when ESP32P4 support is added to espressif/qemu - if: failure() && matrix.esp-idf-target != 'esp32p4' - uses: actions/upload-artifact@v4 - with: - name: atomvm-esp32-test-${{ matrix.esp-idf-target }}-${{ matrix.idf-version }}${{ matrix.jit && '-jit' || '' }}-memcheck.elf - path: ./src/platforms/esp32/test/build/atomvm-esp32-test.elf - if-no-files-found: error - - - name: Build ESP32 tests using idf.py - # TODO: remove the following exclusion when ESP32P4 support is added to espressif/qemu - if: matrix.esp-idf-target != 'esp32p4' - working-directory: ./src/platforms/esp32/test/ - run: | - set -e - . $IDF_PATH/export.sh - export IDF_TARGET=${{matrix.esp-idf-target}} - export PATH=${PATH}:${HOME}/.cache/rebar3/bin - cp sdkconfig.defaults sdkconfig.defaults.backup - if [ "${{ matrix.jit }}" = "true" ]; then - echo "CONFIG_JIT_ENABLED=y" >> sdkconfig.defaults - fi - idf.py set-target ${{matrix.esp-idf-target}} - idf.py build - - - name: Run ESP32 tests using qemu - # TODO: remove the following exclusion when ESP32P4 support is added to espressif/qemu - if: matrix.esp-idf-target != 'esp32p4' - working-directory: ./src/platforms/esp32/test/ - timeout-minutes: 10 - run: | - set -e - . $IDF_PATH/export.sh - export PATH=/opt/qemu/bin:${PATH} - pytest --target=${{matrix.esp-idf-target}} --embedded-services=idf,qemu -s - cp sdkconfig.defaults.backup sdkconfig.defaults - - - name: Upload ESP32 tests ELF artifact - # TODO: remove the following exclusion when ESP32P4 support is added to espressif/qemu - if: failure() && matrix.esp-idf-target != 'esp32p4' - uses: actions/upload-artifact@v4 - with: - name: atomvm-esp32-test-${{ matrix.esp-idf-target }}-${{ matrix.idf-version }}${{ matrix.jit && '-jit' || '' }}.elf - path: ./src/platforms/esp32/test/build/atomvm-esp32-test.elf - if-no-files-found: error diff --git a/.github/workflows/esp32-mkimage.yaml b/.github/workflows/esp32-mkimage.yaml deleted file mode 100644 index 8f3093923e..0000000000 --- a/.github/workflows/esp32-mkimage.yaml +++ /dev/null @@ -1,195 +0,0 @@ -# -# Copyright 2022 Fred Dushin -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: esp32-mkimage - -on: - push: - paths: - - '.github/workflows/esp32-mkimage.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'libs/**' - - 'src/platforms/esp32/**' - - 'src/platforms/esp32/**/**' - - 'src/libAtomVM/**' - - 'tools/packbeam/**' - pull_request: - paths: - - '.github/workflows/esp32-mkimage.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'libs/**' - - 'src/platforms/esp32/**' - - 'src/platforms/esp32/**/**' - - 'src/libAtomVM/**' - - 'tools/packbeam/**' - -permissions: - contents: write - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - esp32-release: - runs-on: ubuntu-24.04 - container: espressif/idf:v${{ matrix.idf-version }} - - strategy: - matrix: - idf-version: ["5.5.4"] - cc: ["clang-14"] - cxx: ["clang++-14"] - cflags: ["-O3"] - otp: ["28"] - elixir_version: ["1.19"] - rebar3_version: ["3.25.1"] - compiler_pkgs: ["clang-14"] - soc: ["esp32", "esp32c2", "esp32c3", "esp32s2", "esp32s3", "esp32c5", "esp32c6", "esp32c61", "esp32h2", "esp32p4", "esp32p4_pre", "esp32p4_c6", "esp32p4_pre_c6"] - flavor: ["", "-elixir"] - - env: - CC: ${{ matrix.cc }} - CXX: ${{ matrix.cxx }} - CFLAGS: ${{ matrix.cflags }} - CXXFLAGS: ${{ matrix.cflags }} - ImageOS: "ubuntu24" - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - uses: erlef/setup-beam@v1 - with: - otp-version: ${{ matrix.otp }} - elixir-version: ${{ matrix.elixir_version }} - rebar3-version: ${{ matrix.rebar3_version }} - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: "APT update" - run: apt update -y - - - name: "Install deps" - run: DEBIAN_FRONTEND=noninteractive apt install -y ${{ matrix.compiler_pkgs}} git cmake gperf zlib1g-dev - - # needed for generating AtomVM version when running in a docker container - - name: "Configure Git" - run: | - git config --global --add safe.directory /__w/AtomVM/AtomVM - echo -n "git rev-parse: " - git rev-parse --short HEAD - - # Builder info - - name: "System info" - run: | - echo "**uname:**" - uname -a - echo "**libc version:**" - ldd --version - echo "**C Compiler version:**" - $CC --version - $CXX --version - echo "**Linker version:**" - ld --version - echo "**CMake version:**" - cmake --version - echo "**OTP version:**" - cat $(dirname $(which erlc))/../releases/RELEASES || true - - - name: "Build: create build dir" - run: mkdir build - - - name: "Build: run cmake" - working-directory: build - run: | - cmake .. - # git clone will use more recent timestamps than cached beam files - # touch them so we can benefit from the cache and avoid costly beam file rebuild. - find . -name '*.beam' -exec touch {} \; - - - name: "Build erlang and Elixir libs" - working-directory: build/libs - run: | - make - - - name: "Set SOC target" - run: echo "SOC_TARGET=${{ startsWith(matrix.soc, 'esp32p4') && 'esp32p4' || matrix.soc }}" >> $GITHUB_ENV - - - name: "Use release defaults" - if: startsWith(github.ref, 'refs/tags/') - shell: bash - working-directory: ./src/platforms/esp32/ - run: | - cp sdkconfig.release-defaults.in sdkconfig.defaults.in - - - name: "Handle esp32p4 variants sdkconfig" - if: startsWith(matrix.soc, 'esp32p4') && matrix.soc != 'esp32p4' - shell: bash - working-directory: ./src/platforms/esp32/ - run: | - cp sdkconfig.defaults.${{ matrix.soc }} sdkconfig.defaults.esp32p4 - - - name: "Handle esp32p4 c6 variants - add wifi_remote component" - if: matrix.soc == 'esp32p4_c6' || matrix.soc == 'esp32p4_pre_c6' - shell: bash - working-directory: ./src/platforms/esp32/components/avm_builtins - run: | - cp idf_component.yml.esp32p4_wifi_remote idf_component.yml - - - name: "Build ${{ matrix.soc }}${{ matrix.flavor }} with idf.py" - shell: bash - working-directory: ./src/platforms/esp32/ - run: | - rm -rf build - . $IDF_PATH/export.sh - if [ "${{ matrix.flavor }}" = "-elixir" ] - then - idf.py -DATOMVM_ELIXIR_SUPPORT=on set-target ${{ env.SOC_TARGET }} - else - idf.py -DATOMVM_ELIXIR_SUPPORT=off set-target ${{ env.SOC_TARGET }} - fi - idf.py reconfigure - idf.py build - - - name: "Create a ${{ matrix.soc }}${{ matrix.flavor }} image" - working-directory: ./src/platforms/esp32/build - run: | - ./mkimage.sh - if [ "${{ matrix.soc }}" != "${{ env.SOC_TARGET }}" ]; then - mv atomvm-${{ env.SOC_TARGET }}${{ matrix.flavor }}.img atomvm-${{ matrix.soc }}${{ matrix.flavor }}.img - fi - ls -l *.img - - - name: "Upload ${{ matrix.soc }} artifacts" - uses: actions/upload-artifact@v4 - with: - name: atomvm-${{ matrix.soc }}${{ matrix.flavor }}-image - path: ./src/platforms/esp32/build/atomvm-${{ matrix.soc }}${{ matrix.flavor }}.img - if-no-files-found: error - - - name: "Rename and write sha256sum" - if: startsWith(github.ref, 'refs/tags/') - shell: bash - working-directory: src/platforms/esp32/build - run: | - ATOMVM_IMG="AtomVM-${{ matrix.soc }}${{ matrix.flavor }}-${{ github.ref_name }}.img" - mv atomvm-${{ matrix.soc }}${{ matrix.flavor }}.img "${ATOMVM_IMG}" - sha256sum "${ATOMVM_IMG}" > "${ATOMVM_IMG}.sha256" - - - name: Release - uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') - with: - draft: true - fail_on_unmatched_files: true - files: | - src/platforms/esp32/build/AtomVM-${{ matrix.soc }}${{ matrix.flavor }}-${{ github.ref_name }}.img - src/platforms/esp32/build/AtomVM-${{ matrix.soc }}${{ matrix.flavor }}-${{ github.ref_name }}.img.sha256 diff --git a/.github/workflows/esp32-simtest.yaml b/.github/workflows/esp32-simtest.yaml index e0f2241157..b7459ac4ea 100644 --- a/.github/workflows/esp32-simtest.yaml +++ b/.github/workflows/esp32-simtest.yaml @@ -12,7 +12,7 @@ on: paths: - ".github/workflows/esp32-simtest.yaml" - "CMakeLists.txt" - - 'CMakeModules/**' + - "CMakeModules/**" - "libs/**" - "src/platforms/esp32/**" - "src/platforms/esp32/**/**" @@ -22,7 +22,7 @@ on: paths: - ".github/workflows/esp32-simtest.yaml" - "CMakeLists.txt" - - 'CMakeModules/**' + - "CMakeModules/**" - "libs/**" - "src/platforms/esp32/**" - "src/platforms/esp32/**/**" @@ -78,9 +78,9 @@ jobs: "esp32c3", "esp32c5", "esp32c6", - "esp32h2" + "esp32h2", ] - idf-version: ${{ ((contains(github.event.head_commit.message, 'full_sim_test')||contains(github.event.pull_request.title, 'full_sim_test')) && fromJSON('["v5.2.7", "v5.3.5", "v5.4.4", "v5.5.4"]')) || fromJSON('["v5.5.4"]') }} + idf-version: ${{ ((contains(github.event.head_commit.message, 'full_sim_test')||contains(github.event.pull_request.title, 'full_sim_test')) && fromJSON('["v5.2.7", "v5.3.5", "v5.4.4", "v5.5.4"]')) || fromJSON('["release-v6.1"]') }} exclude: - esp-idf-target: "esp32p4" idf-version: "v5.2.7" @@ -95,9 +95,13 @@ jobs: # CI now uses chip revision 3 that is currently only available since 5.5.2 include: - esp-idf-target: "esp32p4" - idf-version: "v5.5.4" + idf-version: "release-v6.1" - esp-idf-target: "esp32c61" - idf-version: "v5.5.4" + idf-version: "release-v6.1" + # - esp-idf-target: "esp32" + # idf-version: "v6.0.1" + # - esp-idf-target: "esp32s3" + # idf-version: "v6.0.1" steps: - name: Checkout repo diff --git a/.github/workflows/pico-build.yaml b/.github/workflows/pico-build.yaml deleted file mode 100644 index a97c47fae9..0000000000 --- a/.github/workflows/pico-build.yaml +++ /dev/null @@ -1,284 +0,0 @@ -# -# Copyright 2022 Paul Guyot -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: Pico Build - -on: - push: - paths: - - '.github/workflows/pico-build.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'libs/**' - - 'src/platforms/rp2/**' - - 'src/platforms/esp32/test/main/test_erl_sources/test_crypto.erl' - - 'src/libAtomVM/**' - pull_request: - paths: - - '.github/workflows/pico-build.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'libs/**' - - 'src/platforms/rp2/**' - - 'src/platforms/esp32/test/main/test_erl_sources/test_crypto.erl' - - 'src/libAtomVM/**' - -permissions: - actions: read - contents: write - security-events: write - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - build-atomvmlib: - runs-on: ubuntu-24.04 - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: "apt update" - run: sudo apt update - - - name: "Install deps" - run: | - sudo apt install -y \ - cmake doxygen gperf ninja-build - - - uses: erlef/setup-beam@v1 - with: - otp-version: "28" - rebar3-version: "3.25.1" - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: Build atomvmlib-rp2-pico.uf2/atomvmlib-rp2-pico2.uf2 - shell: bash - run: | - set -euo pipefail - mkdir build - cd build - cmake .. -G Ninja - cmake --build . -t atomvmlib-rp2 - - - name: Upload atomvmlib artifacts - uses: actions/upload-artifact@v4 - with: - name: atomvmlib-uf2-files - path: build/libs/*.uf2 - - - name: Upload uf2tool artifact - uses: actions/upload-artifact@v4 - with: - name: uf2tool - path: build/tools/uf2tool/uf2tool - - pico: - runs-on: ubuntu-24.04 - needs: build-atomvmlib - strategy: - fail-fast: false - matrix: - board: ["pico", "pico_w", "pico2", "pico2_w"] - platform: [""] - jit: ["", "-DAVM_DISABLE_JIT=OFF"] - include: - - board: "pico2" - platform: "-DPICO_PLATFORM=rp2350-riscv" - jit: "" - - - board: "pico2" - platform: "-DPICO_PLATFORM=rp2350-riscv" - jit: "-DAVM_DISABLE_JIT=OFF" - - - board: "pico2_w" - platform: "-DPICO_PLATFORM=rp2350-riscv" - jit: "" - - - board: "pico2_w" - platform: "-DPICO_PLATFORM=rp2350-riscv" - jit: "-DAVM_DISABLE_JIT=OFF" - - - board: "pico" - platform: "" - jit: "" - usb-cdc: "ON" - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - uses: erlef/setup-beam@v1 - with: - otp-version: "28" - rebar3-version: "3.25.1" - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: Set and escape ref name - shell: bash - run: | - echo "AVM_REF_NAME=${{ github.ref_name }}" | tr '/' '-' >> "$GITHUB_ENV"; - - - name: Download atomvmlib artifacts - uses: actions/download-artifact@v4 - with: - name: atomvmlib-uf2-files - path: build/libs/ - - - name: Download uf2tool artifact - uses: actions/download-artifact@v4 - with: - name: uf2tool - path: . - - - name: "apt update" - run: sudo apt update - - - name: "Install deps" - run: | - sudo apt install -y \ - cmake doxygen gperf ninja-build gcc-arm-none-eabi \ - libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib - - - name: Install riscv32 toolchain - if: matrix.platform == '-DPICO_PLATFORM=rp2350-riscv' - run: | - sudo mkdir -p /opt/riscv32-toolchain - cd /opt/riscv32-toolchain - sudo wget -q https://github.com/raspberrypi/pico-sdk-tools/releases/download/v2.2.0-3/riscv-toolchain-15-x86_64-lin.tar.gz - sudo tar xzf riscv-toolchain-15-x86_64-lin.tar.gz - sudo rm riscv-toolchain-15-x86_64-lin.tar.gz - echo "/opt/riscv32-toolchain/bin" >> $GITHUB_PATH - - - name: "Git config safe.directory for codeql" - run: git config --global --add safe.directory /__w/AtomVM/AtomVM - - - name: "Initialize CodeQL" - uses: github/codeql-action/init@v4 - with: - languages: "cpp" - build-mode: manual - queries: +./code-queries/term-to-non-term-func.ql,./code-queries/non-term-to-term-func.ql,./code-queries/mismatched-atom-string-length.ql,./code-queries/mismatched-free-type.ql,./code-queries/term-use-after-gc.ql,./code-queries/allocations-exceeding-ensure-free.ql,./code-queries/allocations-without-ensure-free.ql - - - name: Build - shell: bash - working-directory: ./src/platforms/rp2/ - run: | - set -euo pipefail - mkdir build - cd build - cmake .. -G Ninja -DPICO_BOARD=${{ matrix.board }} ${{ matrix.platform }} ${{ matrix.jit }} ${{ matrix.usb-cdc == 'ON' && '-DAVM_USB_CDC_PORT_DRIVER_ENABLED=ON' || '' }} - cmake --build . --target=AtomVM - - - name: "Perform CodeQL Analysis" - uses: github/codeql-action/analyze@v4 - - - name: Install nvm and nodejs 20 - if: matrix.board != 'pico2' && matrix.board != 'pico2_w' - run: | - set -euo pipefail - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash - source $HOME/.nvm/nvm.sh - nvm install 24 - - - name: Build tests (without SMP) - if: matrix.board != 'pico2' && matrix.board != 'pico2_w' && matrix.usb-cdc != 'ON' - shell: bash - working-directory: ./src/platforms/rp2/ - run: | - set -euo pipefail - mkdir build.nosmp - cd build.nosmp - # TODO: fix all warnings and enable -DAVM_WARNINGS_ARE_ERRORS=ON - cmake .. -G Ninja -DPICO_BOARD=${{ matrix.board }} ${{ matrix.jit }} -DAVM_DISABLE_SMP=1 - cmake --build . --target=rp2_tests - - - name: Run tests with rp2040js - if: matrix.board != 'pico2' && matrix.board != 'pico2_w' && matrix.usb-cdc != 'ON' - shell: bash - working-directory: ./src/platforms/rp2/tests - run: | - set -euo pipefail - source $HOME/.nvm/nvm.sh - nvm use node - npm install - npx tsx run-tests.ts ../build.nosmp/tests/rp2_tests.uf2 ../build.nosmp/tests/test_erl_sources/rp2_test_modules.uf2 - - - name: Rename AtomVM and write sha256sum - if: matrix.platform == '' && matrix.jit == '' && matrix.usb-cdc != 'ON' - shell: bash - run: | - pushd src/platforms/rp2/build - ATOMVM_UF2=AtomVM-${{ matrix.board }}-${{env.AVM_REF_NAME}}.uf2 - mv src/AtomVM.uf2 "src/${ATOMVM_UF2}" - sha256sum "src/${ATOMVM_UF2}" > "src/${ATOMVM_UF2}.sha256" - popd - - - name: Upload AtomVM artifact - if: matrix.platform == '' && matrix.jit == '' && matrix.usb-cdc != 'ON' - uses: actions/upload-artifact@v4 - with: - name: AtomVM-${{ matrix.board }}-${{env.AVM_REF_NAME}}.uf2 - path: src/platforms/rp2/build/src/AtomVM-${{ matrix.board }}-*.uf2 - - - name: Rename atomvmlib-rp2 and write sha256sum - if: matrix.platform == '' && matrix.jit == '' && matrix.usb-cdc != 'ON' - shell: bash - run: | - pushd build/libs - ATOMVMLIB_FILE=atomvmlib-rp2-${{ matrix.board }}-${{env.AVM_REF_NAME}}.uf2 - mv atomvmlib-rp2-${{matrix.board == 'pico_w' && 'pico' || matrix.board == 'pico2_w' && 'pico2' || matrix.board}}.uf2 "${ATOMVMLIB_FILE}" - sha256sum "${ATOMVMLIB_FILE}" > "${ATOMVMLIB_FILE}.sha256" - popd - - - name: Combine uf2 using uf2tool - if: matrix.platform == '' && matrix.jit == '' && matrix.usb-cdc != 'ON' - shell: bash - run: | - ATOMVM_COMBINED_FILE=AtomVM-${{ matrix.board }}-combined-${{env.AVM_REF_NAME}}.uf2 - ./uf2tool join -o "${ATOMVM_COMBINED_FILE}" src/platforms/rp2/build/src/AtomVM-${{ matrix.board }}-${{env.AVM_REF_NAME}}.uf2 build/libs/atomvmlib-rp2-${{ matrix.board }}-${{env.AVM_REF_NAME}}.uf2 - sha256sum "${ATOMVM_COMBINED_FILE}" > "${ATOMVM_COMBINED_FILE}.sha256" - echo "ATOMVM_COMBINED_FILE=${ATOMVM_COMBINED_FILE}" >> $GITHUB_ENV - - - name: Upload combined AtomVM artifact - if: matrix.platform == '' && matrix.jit == '' && matrix.usb-cdc != 'ON' - uses: actions/upload-artifact@v4 - with: - name: ${{ env.ATOMVM_COMBINED_FILE }} - path: ${{ env.ATOMVM_COMBINED_FILE }} - - - name: Release (Pico & Pico2) - uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') && matrix.board != 'pico_w' && matrix.board != 'pico2_w' && matrix.platform == '' && matrix.jit == '' && matrix.usb-cdc != 'ON' - with: - draft: true - fail_on_unmatched_files: true - files: | - src/platforms/rp2/build/src/AtomVM-${{ matrix.board }}-${{ github.ref_name }}.uf2 - src/platforms/rp2/build/src/AtomVM-${{ matrix.board }}-${{ github.ref_name }}.uf2.sha256 - build/libs/atomvmlib-rp2-${{ matrix.board }}-${{ github.ref_name }}.uf2 - build/libs/atomvmlib-rp2-${{ matrix.board }}-${{ github.ref_name }}.uf2.sha256 - ${{ env.ATOMVM_COMBINED_FILE }} - ${{ env.ATOMVM_COMBINED_FILE }}.sha256 - - - name: Release (PicoW & Pico2W) - uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') && (matrix.board == 'pico_w' || matrix.board == 'pico2_w') && matrix.platform == '' && matrix.jit == '' && matrix.usb-cdc != 'ON' - with: - draft: true - fail_on_unmatched_files: true - files: | - src/platforms/rp2/build/src/AtomVM-${{ matrix.board }}-${{ github.ref_name }}.uf2 - src/platforms/rp2/build/src/AtomVM-${{ matrix.board }}-${{ github.ref_name }}.uf2.sha256 - ${{ env.ATOMVM_COMBINED_FILE }} - ${{ env.ATOMVM_COMBINED_FILE }}.sha256 diff --git a/.github/workflows/publish-docs.yaml b/.github/workflows/publish-docs.yaml deleted file mode 100644 index 6438ec9afd..0000000000 --- a/.github/workflows/publish-docs.yaml +++ /dev/null @@ -1,148 +0,0 @@ -# -# Copyright 2023 Winford (Uncle Grumpy) -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# -# This is a workflow for atomvm/AtomVM to Publish API documentation and other content from the `doc` directory to -# doc.atomvm.org hosted on GitHub Pages - -name: Publish Docs - -# Controls when the workflow will run -on: - # Triggers the workflow on pull request, tag events and pushes on main - push: - tags: - - '**' - branches: - - 'main' - - 'release-**' - paths: - - '.github/workflows/publish-docs.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'doc/**' - - 'libs/**' - - 'src/libAtomVM/**' - - 'UPDATING.md' - - 'CONTRIBUTING.md' - - 'CHANGELOG.md' - - 'CODE_OF_CONDUCT.md' - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref_name }} - cancel-in-progress: false - -env: - AVM_DOCS_NAME: ${{ github.ref_name }} - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - strategy: - ## don't add more than one OS to matrix, this is only to retrieve the full os-name for keeping cache in sync - matrix: - os: [ ubuntu-24.04 ] - # The type of runner that the job will run on - runs-on: ${{ matrix.os }} - container: erlang:28.1 - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - - name: Install Deps - run: | - apt update -y - DEBIAN_FRONTEND=noninteractive apt install -y git cmake doxygen graphviz python3-pip python3-virtualenv python3-setuptools python3-stemmer wget - - - uses: actions/cache@v4 - id: sphinx-cache - with: - path: /home/runner/python-env/sphinx - key: ${{ matrix.os }}-${{ job.container.id }}-sphinx-install - - - name: Install Sphinx - if: ${{ steps.sphinx-cache.outputs.cache-hit != 'true' }} - run: | - virtualenv /home/runner/python-env/sphinx - . /home/runner/python-env/sphinx/bin/activate - python3 -m pip install sphinx - python3 -m pip install myst-parser - python3 -m pip install sphinx-rtd-theme - python3 -m pip install rinohtype - python3 -m pip install pillow - python3 -m pip install gitpython - python3 -m pip install breathe - python3 -m pip install pygments - - - name: Install rebar3 - working-directory: /tmp - run: | - wget https://s3.amazonaws.com/rebar3/rebar3 && chmod +x rebar3 - ./rebar3 local install - echo "/home/runner/.cache/rebar3/bin" >> ${GITHUB_PATH} - - - uses: actions/checkout@v4 - with: - repository: ${{ vars.GITHUB_REPOSITORY }} - fetch-depth: 0 - - - uses: actions/checkout@v4 - id: checkout-production - with: - repository: atomvm/doc.atomvm.org - ref: main - path: /home/runner/work/AtomVM/AtomVM/www - - - name: Track all branches - shell: bash - run: | - git config --global --add safe.directory /__w/AtomVM/AtomVM - for branch in `git branch -a | grep "remotes/origin" | grep -v HEAD | grep -v "${{ github.ref_name }}" `; do - git branch --track ${branch#remotes/origin/} $branch - done - - - name: Build Site - shell: bash - run: | - . /home/runner/python-env/sphinx/bin/activate - mkdir build - cd build - cmake .. - cd doc - make GitHub_CI_Publish_Docs - rm -frv "/__w/AtomVM/AtomVM/www/${{ github.ref_name }}" - cp -av html "/__w/AtomVM/AtomVM/www/${{ github.ref_name }}" - - name: Commit files - id: commit_files - if: github.repository == 'atomvm/AtomVM' - working-directory: /home/runner/work/AtomVM/AtomVM/www - run: | - git config --local user.email "atomvm-doc-bot@users.noreply.github.com" - git config --local user.name "AtomVM Doc Bot" - git status "${{ github.ref_name }}" - git add "${{ github.ref_name }}" - git add . - git diff --exit-code main || echo "Going to commit" - git diff --exit-code main || git commit -m "Update Documentation for ${{ github.ref_name }}" - git log -1 - - name: Push changes - if: github.repository == 'atomvm/AtomVM' - working-directory: /home/runner/work/AtomVM/AtomVM/www - run: | - export GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no" - eval `ssh-agent -t 60 -s` - echo "${{ secrets.PUBLISH_ACTION_KEY }}" | ssh-add - - mkdir -p ~/.ssh/ - echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl" > ~/.ssh/known_hosts - echo "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=" >> ~/.ssh/known_hosts - echo "github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" >> ~/.ssh/known_hosts - git remote add push_dest "git@github.com:atomvm/doc.atomvm.org.git" - git fetch push_dest - git diff --exit-code push_dest/main || echo "Going to push" - git diff --exit-code push_dest/main || git push --set-upstream push_dest main diff --git a/.github/workflows/reuse-lint.yaml b/.github/workflows/reuse-lint.yaml deleted file mode 100644 index cf5e72a318..0000000000 --- a/.github/workflows/reuse-lint.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-FileCopyrightText: 2022 Free Software Foundation Europe e.V. -# -# SPDX-License-Identifier: CC0-1.0 - -name: REUSE Compliance Check - -on: [push, pull_request] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - test: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4 - - name: REUSE Compliance Check - uses: fsfe/reuse-action@v1 diff --git a/.github/workflows/run-tests-with-beam.yaml b/.github/workflows/run-tests-with-beam.yaml deleted file mode 100644 index 80c30263e2..0000000000 --- a/.github/workflows/run-tests-with-beam.yaml +++ /dev/null @@ -1,187 +0,0 @@ -# -# Copyright 2022 Paul Guyot -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: Run tests with BEAM - -on: - push: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - pull_request: - paths-ignore: - - 'src/platforms/emscripten/**' - - 'src/platforms/esp32/**' - - 'src/platforms/rp2/**' - - 'src/platforms/stm32/**' - - 'doc/**' - - 'LICENSES/**' - - '*.Md' - - '*.md' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - run-tests: - runs-on: ${{ matrix.os }} - container: ${{ matrix.container }} - strategy: - fail-fast: false - matrix: - include: - - os: "ubuntu-24.04" - test_erlang_opts: "-s prime_smp" - otp: "26" - container: erlang:26 - - - os: "ubuntu-24.04" - test_erlang_opts: "-s prime_smp" - otp: "27" - container: erlang:27 - - - os: "ubuntu-24.04" - test_erlang_opts: "-s prime_smp" - otp: "28" - container: erlang:28 - - - os: "ubuntu-24.04" - test_erlang_opts: "-s prime_smp" - otp: "29" - container: erlang:29 - - # This is ARM64 - - os: "macos-15" - otp: "26" - - - os: "macos-15" - otp: "27" - - - os: "macos-15" - otp: "28" - steps: - # Setup - - name: "Checkout repo" - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - - name: "Git config safe.directory" - if: matrix.container - run: git config --global --add safe.directory /__w/AtomVM/AtomVM - - - name: "Switch to archive.debian.org" - if: matrix.archive == 'true' - run: | - sed -i 's|deb\.debian\.org|archive.debian.org/debian-archive|g' /etc/apt/sources.list - - - name: "Install deps (container)" - if: runner.os == 'Linux' - run: | - apt update -y - apt install -y cmake gperf zlib1g-dev ninja-build \ - binutils-aarch64-linux-gnu \ - binutils-arm-linux-gnueabihf \ - binutils-riscv64-linux-gnu \ - wabt - - - name: "Normalize ImageOS for setup-beam" - if: matrix.os == 'macos-26' - run: echo "ImageOS=macos15" >> "$GITHUB_ENV" - - - uses: erlef/setup-beam@v1 - if: runner.os == 'macOS' - with: - otp-version: ${{ matrix.otp }} - rebar3-version: ${{ fromJSON('{"26":"3.25.1","27":"3.25.1","28":"3.26"}')[matrix.otp] || '3' }} - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: "Install deps (macOS)" - if: runner.os == 'macOS' - run: brew update && HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install gperf mbedtls@3 aarch64-elf-binutils arm-none-eabi-binutils riscv64-elf-binutils wabt - - - name: "macOS setup mbedtls@3 environment" - if: runner.os == 'macOS' - run: | - # Detect Homebrew prefix (Apple Silicon vs Intel) - if [ -d "/opt/homebrew/opt/mbedtls@3" ]; then - MBEDTLS_PREFIX="/opt/homebrew/opt/mbedtls@3" - elif [ -d "/usr/local/opt/mbedtls@3" ]; then - MBEDTLS_PREFIX="/usr/local/opt/mbedtls@3" - else - echo "Error: mbedtls@3 not found in expected locations" - exit 1 - fi - echo "MBEDTLS_PREFIX=${MBEDTLS_PREFIX}" >> $GITHUB_ENV - echo "LDFLAGS=-L${MBEDTLS_PREFIX}/lib" >> $GITHUB_ENV - echo "CPPFLAGS=-I${MBEDTLS_PREFIX}/include" >> $GITHUB_ENV - echo "PKG_CONFIG_PATH=${MBEDTLS_PREFIX}/lib/pkgconfig" >> $GITHUB_ENV - - # Build - - name: "Build: create build dir" - run: mkdir build - - - uses: actions/cache@v4 - id: cache - with: - path: 'build/tests/**/*.beam' - key: ${{ matrix.otp }}-${{ hashFiles('**/run-tests-with-beam.yaml', 'tests/**/*.erl') }} - - - name: "Build: run cmake" - working-directory: build - run: | - cmake -G Ninja ${MBEDTLS_PREFIX:+-DCMAKE_PREFIX_PATH="$MBEDTLS_PREFIX"} ${{ matrix.cmake_opts }} .. - - - name: "Touch files to benefit from cache" - working-directory: build - run: | - # git clone will use more recent timestamps than cached beam files - # touch them so we can benefit from the cache and avoid costly beam file rebuild. - find . -name '*.beam' -exec touch {} \; - - - name: "Build: run ninja" - working-directory: build - run: | - ninja - - # Test - - name: "Test: test-erlang with BEAM" - timeout-minutes: 10 - working-directory: build - run: | - ./tests/test-erlang -b ${{ matrix.test_erlang_opts }} - - # Test - - name: "Test: estdlib/ with BEAM" - timeout-minutes: 10 - working-directory: build - run: | - erl -pa tests/libs/estdlib/ -pa tests/libs/estdlib/beams/ -pa tests/libs/estdlib/beam_beams/ -pa libs/etest/src/beams -pa libs/eavmlib/src/beams -pa libs/avm_network/src/beams -s tests -s init stop -noshell - - # Test - - name: "Run tests/libs/etest/test_eunit with OTP eunit" - timeout-minutes: 10 - working-directory: build - run: | - erl -pa tests/libs/etest/beams -s test_eunit test -s init stop -noshell - - # Test - - name: "Test: jit/ with BEAM" - timeout-minutes: 10 - working-directory: build - if: matrix.otp != '21' && matrix.otp != '22' - run: | - erl -pa tests/libs/jit/beams/ libs/jit/src/beams/ libs/etest/src/beams -noshell -s tests -s init stop -noshell diff --git a/.github/workflows/stm32-build.yaml b/.github/workflows/stm32-build.yaml deleted file mode 100644 index 7dc9109eb5..0000000000 --- a/.github/workflows/stm32-build.yaml +++ /dev/null @@ -1,229 +0,0 @@ -# -# Copyright 2022 Paul Guyot -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: STM32 Build - -on: - push: - paths: - - '.github/workflows/stm32-build.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'src/platforms/stm32/**' - - 'src/libAtomVM/**' - - 'libs/**' - pull_request: - paths: - - '.github/workflows/stm32-build.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'src/platforms/stm32/**' - - 'src/libAtomVM/**' - - 'libs/**' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - stm32: - runs-on: ubuntu-24.04 - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - device: - - stm32f407vgt6 - - stm32f411ceu6 - - stm32f429zit6 - - stm32h743vit6 - - stm32h743zit6 - - stm32u585ait6q - - stm32wb55rg - - stm32h562rgt6 - - stm32f746zgt6 - - stm32g474ret6 - - stm32l476rgt6 - - stm32l562qei6 - - stm32f207zgt6 - - stm32u375rgt6 - - stm32g0b1ret6 - include: - - device: stm32f407vgt6 - max_size: 524288 - renode_platform: stm32f4.repl - avm_address: "0x08080000" - # Renode's STM32F4_I2C model has a bug: it never calls - # FinishTransmission() on the I2C slave when a STOP condition - # occurs, causing the BME280 sensor to get stuck in Reading - # state and ignore subsequent writes. - tests: "boot gpio spi crypto uart" - - device: stm32f411ceu6 - max_size: 393216 - renode_platform: stm32f4.repl - avm_address: "0x08060000" - # No RNG peripheral on F411, so the firmware has no crypto NIFs - # (mbedTLS is excluded by STM32_HAS_RNG in CMake). - tests: "boot gpio spi uart" - - device: stm32f429zit6 - max_size: 524288 - - device: stm32h743vit6 - max_size: 524288 - renode_platform: stm32h743.repl - avm_address: "0x08080000" - tests: "boot gpio i2c spi crypto uart" - - device: stm32h743zit6 - max_size: 524288 - - device: stm32u585ait6q - max_size: 524288 - - device: stm32wb55rg - max_size: 524288 - - device: stm32h562rgt6 - max_size: 524288 - usb-cdc: "OFF" - - device: stm32h562rgt6 - max_size: 524288 - usb-cdc: "ON" - - device: stm32f746zgt6 - max_size: 524288 - renode_platform: stm32f746.repl - avm_address: "0x08080000" - tests: "boot gpio i2c spi crypto uart" - - device: stm32g474ret6 - max_size: 393216 - - device: stm32l476rgt6 - max_size: 524288 - - device: stm32l562qei6 - max_size: 393216 - renode_platform: stm32l562.repl - avm_address: "0x08060000" - # Renode's built-in stm32l552.repl uses STM32F4_I2C (legacy I2C - # register layout) but the L5 HAL uses the newer I2C registers - # (TIMINGR, ISR, etc.), causing a complete register mismatch. - # 512 KB flash with avm_address=0x08060000 leaves only 128 KB, - # but the crypto AVM is 207 KB and gets truncated. - tests: "boot gpio spi uart" - - device: stm32f207zgt6 - max_size: 524288 - - device: stm32u375rgt6 - max_size: 524288 - - device: stm32g0b1ret6 - max_size: 393216 - renode_platform: stm32g0b1.repl - avm_address: "0x08060000" - # No RNG peripheral on G0B1 (only G041/G061/G081/G0C1 have one), - # so the firmware has no crypto NIFs (mbedTLS is excluded by - # STM32_HAS_RNG in CMake). - tests: "boot gpio i2c spi uart" - - steps: - - uses: erlef/setup-beam@v1 - with: - otp-version: "28" - rebar3-version: "3.25.1" - hexpm-mirrors: | - https://builds.hex.pm - https://repo.hex.pm - https://cdn.jsdelivr.net/hex - - - name: "apt update" - run: sudo apt update - - - name: "Install deps" - run: sudo apt install -y cmake ninja-build gperf python3-pip && pip3 install meson - - - name: "Install ARM GNU Toolchain" - run: | - wget -q https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi.tar.xz - tar xJf arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi.tar.xz -C /opt - echo "/opt/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/bin" >> $GITHUB_PATH - - - name: Checkout repo - uses: actions/checkout@v4 - - - name: "Git config safe.directory for codeql" - run: git config --global --add safe.directory /__w/AtomVM/AtomVM - - - name: "Initialize CodeQL" - if: matrix.device == 'stm32f407vgt6' - uses: github/codeql-action/init@v4 - with: - languages: 'cpp' - build-mode: manual - queries: +./code-queries/term-to-non-term-func.ql,./code-queries/non-term-to-term-func.ql,./code-queries/mismatched-atom-string-length.ql,./code-queries/mismatched-free-type.ql,./code-queries/term-use-after-gc.ql,./code-queries/allocations-exceeding-ensure-free.ql,./code-queries/allocations-without-ensure-free.ql - - - name: "Build for ${{ matrix.device }}" - shell: bash - working-directory: ./src/platforms/stm32/ - run: | - set -euo pipefail - mkdir build - cd build - cmake .. -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/arm-toolchain.cmake -DDEVICE=${{ matrix.device }} ${{ matrix.usb-cdc == 'ON' && '-DAVM_USB_CDC_PORT_DRIVER_ENABLED=ON' || '' }} - cmake --build . - - - name: "Perform CodeQL Analysis" - if: matrix.device == 'stm32f407vgt6' - uses: github/codeql-action/analyze@v4 - - - name: "Check firmware size for ${{ matrix.device }}" - shell: bash - working-directory: ./src/platforms/stm32/build - run: | - set -euo pipefail - ELF="AtomVM-${{ matrix.device }}.elf" - SIZES=$(arm-none-eabi-size "$ELF" | tail -1) - TEXT=$(echo "$SIZES" | awk '{print $1}') - DATA=$(echo "$SIZES" | awk '{print $2}') - FLASH_USED=$((TEXT + DATA)) - MAX=${{ matrix.max_size }} - echo "Firmware flash usage: ${FLASH_USED} bytes ($(( FLASH_USED / 1024 )) KB)" - echo "Flash limit: ${MAX} bytes ($(( MAX / 1024 )) KB)" - if [ "$FLASH_USED" -gt "$MAX" ]; then - echo "::error::Firmware too large: ${FLASH_USED} bytes exceeds ${MAX} byte limit for ${{ matrix.device }}" - exit 1 - fi - echo "OK: ${FLASH_USED} / ${MAX} bytes ($(( FLASH_USED * 100 / MAX ))% used)" - - - name: Build host AtomVM and test AVMs - if: matrix.renode_platform - run: | - set -euo pipefail - mkdir build-host - cd build-host - cmake .. -G Ninja - cmake --build . -t stm32_boot_test stm32_gpio_test stm32_i2c_test stm32_spi_test stm32_crypto_test stm32_uart_test - - - name: Install Renode - if: matrix.renode_platform - run: | - set -euo pipefail - mkdir -p renode-portable - wget -qO- https://github.com/renode/renode/releases/download/v1.16.1/renode-1.16.1.linux-portable.tar.gz \ - | tar -xzf - -C renode-portable --strip-components=1 - echo "$PWD/renode-portable" >> $GITHUB_PATH - pip install -r renode-portable/tests/requirements.txt - - - name: Run Renode tests - if: matrix.renode_platform - run: | - LOCAL_REPL="src/platforms/stm32/tests/renode/${{ matrix.renode_platform }}" - if [ -f "$LOCAL_REPL" ]; then - PLATFORM="@$PWD/$LOCAL_REPL" - else - PLATFORM="@platforms/cpus/${{ matrix.renode_platform }}" - fi - for TEST in ${{ matrix.tests }}; do - renode-test "src/platforms/stm32/tests/renode/stm32_${TEST}_test.robot" \ - --variable ELF:@$PWD/src/platforms/stm32/build/AtomVM-${{ matrix.device }}.elf \ - --variable AVM:@$PWD/build-host/src/platforms/stm32/tests/test_erl_sources/stm32_${TEST}_test.avm \ - --variable AVM_ADDRESS:${{ matrix.avm_address }} \ - --variable PLATFORM:$PLATFORM - done diff --git a/.github/workflows/wasm-build.yaml b/.github/workflows/wasm-build.yaml deleted file mode 100644 index c5b75101a8..0000000000 --- a/.github/workflows/wasm-build.yaml +++ /dev/null @@ -1,361 +0,0 @@ -# -# Copyright 2023 Paul Guyot -# -# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -# - -name: Wasm Build - -on: - push: - paths: - - '.github/workflows/wasm-build.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'libs/**' - - 'src/platforms/emscripten/**' - - 'src/libAtomVM/**' - pull_request: - paths: - - '.github/workflows/wasm-build.yaml' - - 'CMakeLists.txt' - - 'CMakeModules/**' - - 'libs/**' - - 'src/platforms/emscripten/**' - - 'src/libAtomVM/**' - -permissions: - contents: write - -concurrency: - group: ${{ github.workflow }}-${{ github.ref != 'refs/heads/main' && github.ref || github.run_id }} - cancel-in-progress: true - -jobs: - - compile_tests: - - runs-on: ubuntu-24.04 - container: erlang:28 - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ["c-cpp"] - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Install required packages - run: apt update && apt install -y gperf zlib1g-dev cmake ninja-build - - - name: "Git config safe.directory for codeql" - run: git config --global --add safe.directory /__w/AtomVM/AtomVM - - - name: "Initialize CodeQL" - uses: github/codeql-action/init@v4 - with: - languages: ${{matrix.language}} - build-mode: manual - queries: +./code-queries/term-to-non-term-func.ql,./code-queries/non-term-to-term-func.ql,./code-queries/mismatched-atom-string-length.ql,./code-queries/mismatched-free-type.ql,./code-queries/term-use-after-gc.ql,./code-queries/allocations-exceeding-ensure-free.ql,./code-queries/allocations-without-ensure-free.ql - - - name: Compile AtomVM and test modules - run: | - set -e - mkdir build - cd build - cmake .. -G Ninja -DAVM_WARNINGS_ARE_ERRORS=ON - # test_eavmlib does not work with wasm due to http + ssl test - ninja AtomVM atomvmlib atomvmlib-emscripten erlang_test_modules test_etest test_alisp test_estdlib hello_world run_script call_cast html5_events wasm_webserver - - - name: "Perform CodeQL Analysis" - uses: github/codeql-action/analyze@v4 - - - name: Upload AtomVM and test modules - uses: actions/upload-artifact@v4 - with: - name: atomvm-and-test-modules - path: | - build/**/*.avm - build/**/*.beam - build/src/AtomVM - retention-days: 1 - - - name: Compile emscripten test modules - run: | - set -e - cd src/platforms/emscripten - mkdir -p build/tests/src/ - cd build/tests/src - cmake ../../../tests/src -G Ninja - ninja emscripten_erlang_test_modules - - - name: Upload emscripten test modules - uses: actions/upload-artifact@v4 - with: - name: emscripten-test-modules - path: | - src/platforms/emscripten/build/**/*.beam - retention-days: 1 - - compile_tests_jit: - - runs-on: ubuntu-24.04 - container: erlang:28 - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Install required packages - run: apt update && apt install -y gperf zlib1g-dev cmake ninja-build - - - name: Compile AtomVM and test modules with JIT for wasm32 - run: | - set -e - mkdir build - cd build - cmake .. -G Ninja -DAVM_DISABLE_JIT=OFF -DAVM_JIT_TARGET_ARCH=wasm32 -DAVM_PRECOMPILED_TARGETS=wasm32 - # test_eavmlib does not work with wasm due to http + ssl test - ninja atomvmlib-emscripten erlang_test_modules test_etest test_alisp test_estdlib hello_world test_jit - - - name: Run JIT eunit tests - run: | - cd build - erl -pa tests/libs/jit/beams/ libs/jit/src/beams/ libs/etest/src/beams \ - -noshell -s tests -s init stop - - - name: Upload JIT test modules - uses: actions/upload-artifact@v4 - with: - name: atomvm-and-test-modules-jit - path: | - build/**/*.avm - build/**/*.beam - retention-days: 1 - - wasm_build_and_test_node: - needs: [compile_tests, compile_tests_jit] - runs-on: ubuntu-24.04 - container: emscripten/emsdk - - strategy: - fail-fast: false - matrix: - jit: ["", "-DAVM_DISABLE_JIT=OFF"] - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: "Install deps" - run: sudo apt update -y && sudo apt install -y cmake gperf - - - name: Build - shell: bash - working-directory: ./src/platforms/emscripten/ - run: | - set -euo pipefail - mkdir build - cd build - emcmake cmake .. ${{ matrix.jit }} - emmake make -j - - - name: Download AtomVM and test modules (non-JIT) - if: matrix.jit == '' - uses: actions/download-artifact@v4 - with: - name: atomvm-and-test-modules - path: build - - - name: Download AtomVM and test modules (JIT) - if: matrix.jit != '' - uses: actions/download-artifact@v4 - with: - name: atomvm-and-test-modules-jit - path: build - - - name: Test (non-JIT) - if: matrix.jit == '' - shell: bash - working-directory: ./src/platforms/emscripten/build - run: | - set -euxo pipefail - # Test compressed beams - node src/AtomVM.mjs ../../../../build/examples/erlang/hello_world.beam ../../../../build/libs/eavmlib/src/eavmlib.avm - # Run tests that pass - node src/AtomVM.mjs ../../../../build/tests/libs/alisp/test_alisp.avm - node src/AtomVM.mjs ../../../../build/tests/libs/estdlib/test_estdlib.avm - # test_eavmlib does not work with wasm due to http + ssl test - # node src/AtomVM.mjs ../../../../build/tests/libs/eavmlib/test_eavmlib.avm - node src/AtomVM.mjs ../../../../build/tests/libs/etest/test_etest.avm - node src/AtomVM.mjs ../../../../build/tests/erlang_tests/test_crypto.beam - - - name: Test (JIT) - if: matrix.jit != '' - shell: bash - working-directory: ./src/platforms/emscripten/build - run: | - set -euxo pipefail - # Test hello_world with JIT compiler (runtime JIT compilation) - node src/AtomVM.mjs ../../../../build/examples/erlang/hello_world.beam ../../../../build/libs/atomvmlib-emscripten-wasm32.avm - # Library tests with JIT compiler (jit-wasm32.avm included in test avms via pack_test) - node src/AtomVM.mjs ../../../../build/tests/libs/alisp/test_alisp.avm - node src/AtomVM.mjs ../../../../build/tests/libs/estdlib/test_estdlib.avm - node src/AtomVM.mjs ../../../../build/tests/libs/etest/test_etest.avm - - - name: "Rename and write sha256sum (node)" - if: startsWith(github.ref, 'refs/tags/') && matrix.jit == '' - shell: bash - working-directory: src/platforms/emscripten/build/src - run: | - ATOMVM_JS=AtomVM-node-${{ github.ref_name }}.mjs - mv AtomVM.mjs "${ATOMVM_JS}" - sha256sum "${ATOMVM_JS}" > "${ATOMVM_JS}.sha256" - ATOMVM_WASM=AtomVM-node-${{ github.ref_name }}.wasm - mv AtomVM.wasm "${ATOMVM_WASM}" - sha256sum "${ATOMVM_WASM}" > "${ATOMVM_WASM}.sha256" - - - name: "Release (node)" - uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') && matrix.jit == '' - with: - draft: true - fail_on_unmatched_files: true - files: | - src/platforms/emscripten/build/src/AtomVM-node-${{ github.ref_name }}.mjs - src/platforms/emscripten/build/src/AtomVM-node-${{ github.ref_name }}.mjs.sha256 - src/platforms/emscripten/build/src/AtomVM-node-${{ github.ref_name }}.wasm - src/platforms/emscripten/build/src/AtomVM-node-${{ github.ref_name }}.wasm.sha256 - - wasm_build_web: - runs-on: ubuntu-24.04 - container: emscripten/emsdk - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - jit: ["", "-DAVM_DISABLE_JIT=OFF"] - language: ["javascript-typescript"] - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: "Install deps" - run: sudo apt update -y && sudo apt install -y cmake gperf - - - name: "Initialize CodeQL" - if: matrix.jit == '' - uses: github/codeql-action/init@v3 - with: - languages: ${{matrix.language}} - build-mode: none - db-location: '${{ github.runner_temp }}/codeql_js_database' - - - name: Build wasm build for web - shell: bash - working-directory: ./src/platforms/emscripten/ - run: | - set -euo pipefail - mkdir build - cd build - emcmake cmake .. -DAVM_EMSCRIPTEN_ENV=web ${{ matrix.jit }} - emmake make -j - - - name: "Perform CodeQL Analysis" - if: matrix.jit == '' - uses: github/codeql-action/analyze@v3 - - - name: Upload wasm build for web - if: matrix.jit == '' - uses: actions/upload-artifact@v4 - with: - name: atomvm-js-web - path: | - src/platforms/emscripten/build/**/*.wasm - src/platforms/emscripten/build/**/*.mjs - retention-days: 1 - - wasm_test_web: - needs: [compile_tests, wasm_build_web] - runs-on: ubuntu-24.04 - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Download AtomVM and test modules - uses: actions/download-artifact@v4 - with: - name: atomvm-and-test-modules - path: build - - - name: Download wasm build for web - uses: actions/download-artifact@v4 - with: - name: atomvm-js-web - path: src/platforms/emscripten/build - - - name: Download emscripten test modules - uses: actions/download-artifact@v4 - with: - name: emscripten-test-modules - path: src/platforms/emscripten/build - - - name: Start Docker echo server for CI - run: | - docker run -d --name echo-server -p 9090:8080 jmalloc/echo-server - sleep 5 - - - name: Test using cypress - shell: bash - run: | - set -euxo pipefail - cd build - chmod +x ./src/AtomVM - ./src/AtomVM examples/emscripten/wasm_webserver.avm & - cd ../src/platforms/emscripten/tests/ - docker run --network host -v $PWD:/mnt -w /mnt -e CYPRESS_CI=true cypress/included:12.17.1 --browser chrome - killall AtomVM - - - name: "Publish screenshots of failures" - if: failure() - uses: actions/upload-artifact@v4 - with: - name: cypress-screenshots - path: | - src/platforms/emscripten/tests/cypress/screenshots/**/*.png - retention-days: 7 - - - name: "Rename and write sha256sum (web)" - if: startsWith(github.ref, 'refs/tags/') - shell: bash - working-directory: src/platforms/emscripten/build/src - run: | - ATOMVM_JS=AtomVM-web-${{ github.ref_name }}.mjs - mv AtomVM.mjs "${ATOMVM_JS}" - sha256sum "${ATOMVM_JS}" > "${ATOMVM_JS}.sha256" - ATOMVM_WASM=AtomVM-web-${{ github.ref_name }}.wasm - mv AtomVM.wasm "${ATOMVM_WASM}" - sha256sum "${ATOMVM_WASM}" > "${ATOMVM_WASM}.sha256" - - - name: "Release (web)" - uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') - with: - draft: true - fail_on_unmatched_files: true - files: | - src/platforms/emscripten/build/src/AtomVM-web-${{ github.ref_name }}.mjs - src/platforms/emscripten/build/src/AtomVM-web-${{ github.ref_name }}.mjs.sha256 - src/platforms/emscripten/build/src/AtomVM-web-${{ github.ref_name }}.wasm - src/platforms/emscripten/build/src/AtomVM-web-${{ github.ref_name }}.wasm.sha256 diff --git a/CMakeModules/FetchMbedTLS.cmake b/CMakeModules/FetchMbedTLS.cmake index 81154b4b86..c53405b8f0 100644 --- a/CMakeModules/FetchMbedTLS.cmake +++ b/CMakeModules/FetchMbedTLS.cmake @@ -20,10 +20,12 @@ include(FetchContent) +set(AVM_FETCH_MBEDTLS_GIT_TAG "v3.6.3.1" CACHE STRING "MbedTLS git tag to fetch for Emscripten builds") + FetchContent_Declare( mbedtls GIT_REPOSITORY http://github.com/mbed-TLS/mbedtls.git - GIT_TAG v3.6.3.1 + GIT_TAG ${AVM_FETCH_MBEDTLS_GIT_TAG} GIT_SHALLOW 1 ) diff --git a/doc/src/programmers-guide.md b/doc/src/programmers-guide.md index 7d282e1127..28148ef294 100644 --- a/doc/src/programmers-guide.md +++ b/doc/src/programmers-guide.md @@ -1432,7 +1432,7 @@ Use the [`esp:deep_sleep/1`](./apidocs/erlang/eavmlib/esp.md#deep_sleep1) functi esp:deep_sleep(60*1000). ``` -Use the [`esp:sleep_get_wakeup_cause/0`](./apidocs/erlang/eavmlib/esp.md#sleep_get_wakeup_cause0) function to inspect the reason for a wakeup. Possible return values include: +For ESP-IDF 5.5 compatibility, use [`esp:sleep_get_wakeup_cause/0`](./apidocs/erlang/eavmlib/esp.md#sleep_get_wakeup_cause0) to inspect a single wakeup reason. Possible values include: * `sleep_wakeup_ext0` * `sleep_wakeup_ext1` @@ -1443,7 +1443,7 @@ Use the [`esp:sleep_get_wakeup_cause/0`](./apidocs/erlang/eavmlib/esp.md#sleep_g * `sleep_wakeup_uart` * `sleep_wakeup_wifi` * `sleep_wakeup_cocpu` -* `sleep_wakeup_cocpu_trag_trig` +* `sleep_wakeup_cocpu_trap_trig` * `sleep_wakeup_bt` * `undefined` (no sleep wakeup) * `error` (unknown other reason) @@ -1463,6 +1463,20 @@ case esp:sleep_get_wakeup_cause() of end. ``` +For ESP-IDF 6+, use [`esp:sleep_get_wakeup_causes/0`](./apidocs/erlang/eavmlib/esp.md#sleep_get_wakeup_causes0) to inspect all wakeup reasons. This function returns a list, since a wakeup may have multiple causes. + +The values match the semantics of [`esp_sleep_get_wakeup_causes`](https://docs.espressif.com/projects/esp-idf/en/release-v6.0/esp32/api-reference/system/sleep_modes.html). + +```erlang +WakeupCauses = esp:sleep_get_wakeup_causes(), +case WakeupCauses of + [] -> + io:format("No wakeup cause available~n"); + _ -> + io:format("Wakeup causes: ~p~n", [WakeupCauses]) +end. +``` + Use the [`esp:sleep_enable_ext0_wakeup/2`](./apidocs/erlang/eavmlib/esp.md#sleep_enable_ext0_wakeup2) and [`esp:sleep_enable_ext1_wakeup/2`](./apidocs/erlang/eavmlib/esp.md#sleep_enable_ext1_wakeup2) functions to configure ext0 and ext1 wakeup mechanisms. They follow the semantics of [`esp_sleep_enable_ext0_wakeup`](https://docs.espressif.com/projects/esp-idf/en/release-v5.5/esp32/api-reference/system/sleep_modes.html#_CPPv428esp_sleep_enable_ext0_wakeup10gpio_num_ti) and [`esp_sleep_enable_ext1_wakeup`](https://docs.espressif.com/projects/esp-idf/en/release-v5.5/esp32/api-reference/system/sleep_modes.html#_CPPv428esp_sleep_enable_ext1_wakeup8uint64_t28esp_sleep_ext1_wakeup_mode_t). ```erlang diff --git a/libs/avm_esp32/src/esp.erl b/libs/avm_esp32/src/esp.erl index fbc2468ec5..58e77e5e87 100644 --- a/libs/avm_esp32/src/esp.erl +++ b/libs/avm_esp32/src/esp.erl @@ -30,6 +30,7 @@ restart/0, reset_reason/0, sleep_get_wakeup_cause/0, + sleep_get_wakeup_causes/0, sleep_enable_ext0_wakeup/2, sleep_enable_ext1_wakeup/2, sleep_enable_ext1_wakeup_io/2, @@ -193,6 +194,15 @@ reset_reason() -> sleep_get_wakeup_cause() -> erlang:nif_error(undefined). +%%----------------------------------------------------------------------------- +%% @returns wakeup causes for the previous sleep operation +%% @doc Returns all causes for the wakeup +%% @end +%%----------------------------------------------------------------------------- +-spec sleep_get_wakeup_causes() -> [esp_wakeup_cause()]. +sleep_get_wakeup_causes() -> + erlang:nif_error(undefined). + %%----------------------------------------------------------------------------- %% @doc Configure gpio wakeup from deep sleep. %% Implemented for SOCs that support it (ESP32, ESP32S2, ESP32S3) diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index 224c93a432..c18b766c46 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -32,6 +32,8 @@ #include #include +#include +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #include #include #include @@ -40,21 +42,21 @@ #include #include #include +#endif #if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000) #include #else #include #endif -#ifdef MBEDTLS_VERSION_C -#include -#endif #ifdef HAVE_PSA_CRYPTO #include +#endif +#if defined(HAVE_PSA_CRYPTO) || MBEDTLS_VERSION_NUMBER >= 0x04000000 #include #endif -#ifdef MBEDTLS_PKCS5_C +#if MBEDTLS_VERSION_NUMBER < 0x04000000 && defined(MBEDTLS_PKCS5_C) #include #include #endif @@ -63,17 +65,21 @@ #include #endif +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 || defined(MBEDTLS_PKCS5_C) +#define AVM_HAVE_PBKDF2_HMAC 1 +#endif + // mbedtls_ct_memcmp is available in 2.28.x+ and 3.1.x+ (absent in 3.0.x) #if (MBEDTLS_VERSION_NUMBER >= 0x021C0000 && MBEDTLS_VERSION_NUMBER < 0x03000000) \ || MBEDTLS_VERSION_NUMBER >= 0x03010000 #include #define AVM_HAVE_MBEDTLS_CT_MEMCMP 1 #endif - // #define ENABLE_TRACE #include "trace.h" -#if MBEDTLS_VERSION_NUMBER > 0x03060100 +// mbedtls_ecdsa_{raw_to,der_to}_der are available in 3.6.1+ and 4.x. +#if MBEDTLS_VERSION_NUMBER >= 0x03060100 #define HAVE_MBEDTLS_ECDSA_RAW_TO_DER 1 #define HAVE_MBEDTLS_ECDSA_DER_TO_RAW 1 #endif @@ -90,6 +96,15 @@ #define MAX_MD_SIZE 64 +#if defined(HAVE_PSA_CRYPTO) || MBEDTLS_VERSION_NUMBER >= 0x04000000 +static void do_psa_init(void) +{ + if (UNLIKELY(psa_crypto_init() != PSA_SUCCESS)) { + abort(); + } +} +#endif + enum crypto_algorithm { CryptoInvalidAlgorithm = 0, @@ -101,6 +116,7 @@ enum crypto_algorithm CryptoSha512 }; +#if MBEDTLS_VERSION_NUMBER < 0x04000000 static const AtomStringIntPair crypto_algorithm_table[] = { { ATOM_STR("\x3", "md5"), CryptoMd5 }, { ATOM_STR("\x3", "sha"), CryptoSha1 }, @@ -110,6 +126,7 @@ static const AtomStringIntPair crypto_algorithm_table[] = { { ATOM_STR("\x6", "sha512"), CryptoSha512 }, SELECT_INT_DEFAULT(CryptoInvalidAlgorithm) }; +#endif #define DEFINE_HASH_FOLD(ALGORITHM, SUFFIX) \ static InteropFunctionResult ALGORITHM##_hash_fold_fun(term t, void *accum) \ @@ -225,6 +242,7 @@ static const AtomStringIntPair crypto_algorithm_table[] = { return true; \ } +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #if MBEDTLS_VERSION_NUMBER >= 0x03000000 // 3.x API: functions return an int that represents errors @@ -270,6 +288,47 @@ DEFINE_HASH_FOLD_NORET(sha512, ) DEFINE_DO_HASH_NORET_IS_OTHER(sha512, , true) DEFINE_DO_HASH_NORET_IS_OTHER(sha512, , false) +#endif +#endif + +#if defined(HAVE_PSA_CRYPTO) || MBEDTLS_VERSION_NUMBER >= 0x04000000 +static const AtomStringIntPair psa_hash_algorithm_table[] = { + { ATOM_STR("\x3", "sha"), PSA_ALG_SHA_1 }, + { ATOM_STR("\x6", "sha224"), PSA_ALG_SHA_224 }, + { ATOM_STR("\x6", "sha256"), PSA_ALG_SHA_256 }, + { ATOM_STR("\x6", "sha384"), PSA_ALG_SHA_384 }, + { ATOM_STR("\x6", "sha512"), PSA_ALG_SHA_512 }, + { ATOM_STR("\x8", "sha3_224"), PSA_ALG_SHA3_224 }, + { ATOM_STR("\x8", "sha3_256"), PSA_ALG_SHA3_256 }, + { ATOM_STR("\x8", "sha3_384"), PSA_ALG_SHA3_384 }, + { ATOM_STR("\x8", "sha3_512"), PSA_ALG_SHA3_512 }, + { ATOM_STR("\x3", "md5"), PSA_ALG_MD5 }, + { ATOM_STR("\x9", "ripemd160"), PSA_ALG_RIPEMD160 }, + + SELECT_INT_DEFAULT(PSA_ALG_NONE) +}; +#endif + +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 +static InteropFunctionResult psa_hash_fold_fun(term t, void *accum) +{ + psa_hash_operation_t *operation = accum; + if (term_is_integer(t)) { + avm_int64_t tmp = term_maybe_unbox_int64(t); + if (tmp < 0 || tmp > 255) { + return InteropBadArg; + } + uint8_t val = (uint8_t) tmp; + if (UNLIKELY(psa_hash_update(operation, &val, 1) != PSA_SUCCESS)) { + return InteropBadArg; + } + } else /* term_is_binary(t) */ { + if (UNLIKELY(psa_hash_update(operation, (const uint8_t *) term_binary_data(t), term_binary_size(t)) != PSA_SUCCESS)) { + return InteropBadArg; + } + } + return InteropOk; +} #endif static term nif_crypto_hash(Context *ctx, int argc, term argv[]) @@ -282,6 +341,34 @@ static term nif_crypto_hash(Context *ctx, int argc, term argv[]) unsigned char digest[MAX_MD_SIZE]; size_t digest_len = 0; +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + do_psa_init(); + psa_algorithm_t alg = interop_atom_term_select_int(psa_hash_algorithm_table, type, ctx->global); + if (alg == PSA_ALG_NONE) { + TRACE("crypto:hash unknown algorithm\n"); + RAISE_ERROR(BADARG_ATOM); + } + digest_len = PSA_HASH_LENGTH(alg); + + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + psa_status_t status = psa_hash_setup(&operation, alg); + if (UNLIKELY(status != PSA_SUCCESS)) { + TRACE("crypto:hash psa_hash_setup failed with status %d for alg 0x%08lx\n", (int) status, (unsigned long) alg); + RAISE_ERROR(BADARG_ATOM); + } + + InteropFunctionResult result = interop_chardata_fold(data, psa_hash_fold_fun, NULL, (void *) &operation); + if (UNLIKELY(result != InteropOk)) { + psa_hash_abort(&operation); + RAISE_ERROR(BADARG_ATOM); + } + + status = psa_hash_finish(&operation, digest, sizeof(digest), &digest_len); + if (UNLIKELY(status != PSA_SUCCESS)) { + psa_hash_abort(&operation); + RAISE_ERROR(BADARG_ATOM); + } +#else enum crypto_algorithm algo = interop_atom_term_select_int(crypto_algorithm_table, type, ctx->global); switch (algo) { case CryptoMd5: { @@ -329,6 +416,7 @@ static term nif_crypto_hash(Context *ctx, int argc, term argv[]) default: RAISE_ERROR(BADARG_ATOM); } +#endif if (UNLIKELY(memory_ensure_free(ctx, term_binary_heap_size(digest_len)) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); @@ -336,6 +424,7 @@ static term nif_crypto_hash(Context *ctx, int argc, term argv[]) return term_from_literal_binary(digest, digest_len, &ctx->heap, ctx->global); } +#if MBEDTLS_VERSION_NUMBER < 0x04000000 static const AtomStringIntPair cipher_table[] = { { ATOM_STR("\xB", "aes_128_ecb"), MBEDTLS_CIPHER_AES_128_ECB }, { ATOM_STR("\xB", "aes_192_ecb"), MBEDTLS_CIPHER_AES_192_ECB }, @@ -357,6 +446,7 @@ static const AtomStringIntPair padding_table[] = { { ATOM_STR("\xC", "pkcs_padding"), MBEDTLS_PADDING_PKCS7 }, SELECT_INT_DEFAULT(-1) }; +#endif static void secure_free(void *buf, size_t len) { @@ -384,7 +474,7 @@ static term handle_iodata(term iodata, const void **data, size_t *len, void **al case InteropBadArg: return BADARG_ATOM; } - void *allocated_buf = malloc(*len); + void *allocated_buf = malloc(*len ? *len : 1); if (IS_NULL_PTR(allocated_buf)) { return OUT_OF_MEMORY_ATOM; } @@ -407,6 +497,7 @@ static term handle_iodata(term iodata, const void **data, size_t *len, void **al } } +#if MBEDTLS_VERSION_NUMBER < 0x04000000 static bool bool_to_mbedtls_operation(term encrypt_flag, mbedtls_operation_t *operation) { switch (encrypt_flag) { @@ -420,6 +511,55 @@ static bool bool_to_mbedtls_operation(term encrypt_flag, mbedtls_operation_t *op return false; } } +#endif + +#if defined(HAVE_PSA_CRYPTO) || MBEDTLS_VERSION_NUMBER >= 0x04000000 +struct PsaCipherParams +{ + const char *atom_str; + psa_key_type_t key_type; + psa_algorithm_t algorithm; + uint16_t key_bits; + uint8_t block_size; + uint8_t iv_len; +}; + +static const struct PsaCipherParams psa_cipher_table[] = { + // ECB modes - block cipher, no IV + { ATOM_STR("\xB", "aes_128_ecb"), PSA_KEY_TYPE_AES, PSA_ALG_ECB_NO_PADDING, 128, 16, 0 }, + { ATOM_STR("\xB", "aes_192_ecb"), PSA_KEY_TYPE_AES, PSA_ALG_ECB_NO_PADDING, 192, 16, 0 }, + { ATOM_STR("\xB", "aes_256_ecb"), PSA_KEY_TYPE_AES, PSA_ALG_ECB_NO_PADDING, 256, 16, 0 }, + // CBC modes - block cipher, with IV + { ATOM_STR("\xB", "aes_128_cbc"), PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, 128, 16, 16 }, + { ATOM_STR("\xB", "aes_192_cbc"), PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, 192, 16, 16 }, + { ATOM_STR("\xB", "aes_256_cbc"), PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, 256, 16, 16 }, + // CFB128 modes - stream-like, with IV + { ATOM_STR("\xE", "aes_128_cfb128"), PSA_KEY_TYPE_AES, PSA_ALG_CFB, 128, 0, 16 }, + { ATOM_STR("\xE", "aes_192_cfb128"), PSA_KEY_TYPE_AES, PSA_ALG_CFB, 192, 0, 16 }, + { ATOM_STR("\xE", "aes_256_cfb128"), PSA_KEY_TYPE_AES, PSA_ALG_CFB, 256, 0, 16 }, + // CTR modes - stream cipher, with IV + { ATOM_STR("\xB", "aes_128_ctr"), PSA_KEY_TYPE_AES, PSA_ALG_CTR, 128, 0, 16 }, + { ATOM_STR("\xB", "aes_192_ctr"), PSA_KEY_TYPE_AES, PSA_ALG_CTR, 192, 0, 16 }, + { ATOM_STR("\xB", "aes_256_ctr"), PSA_KEY_TYPE_AES, PSA_ALG_CTR, 256, 0, 16 }, + // OFB modes - stream-like, with IV + { ATOM_STR("\xB", "aes_128_ofb"), PSA_KEY_TYPE_AES, PSA_ALG_OFB, 128, 0, 16 }, + { ATOM_STR("\xB", "aes_192_ofb"), PSA_KEY_TYPE_AES, PSA_ALG_OFB, 192, 0, 16 }, + { ATOM_STR("\xB", "aes_256_ofb"), PSA_KEY_TYPE_AES, PSA_ALG_OFB, 256, 0, 16 }, +}; + +#define PSA_CIPHER_TABLE_LEN (sizeof(psa_cipher_table) / sizeof(psa_cipher_table[0])) + +static const struct PsaCipherParams *psa_cipher_table_lookup(GlobalContext *glb, term cipher_atom) +{ + for (size_t i = 0; i < PSA_CIPHER_TABLE_LEN; i++) { + AtomString atom_str = (AtomString) psa_cipher_table[i].atom_str; + if (globalcontext_is_term_equal_to_atom_string(glb, cipher_atom, atom_str)) { + return &psa_cipher_table[i]; + } + } + return NULL; +} +#endif static term make_crypto_error_tag( const char *file, int line, const char *message, term tag, Context *ctx) @@ -470,11 +610,23 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) } term cipher_term = argv[0]; + +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + do_psa_init(); + const struct PsaCipherParams *cipher_params = psa_cipher_table_lookup(ctx->global, cipher_term); + if (IS_NULL_PTR(cipher_params)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unknown cipher", ctx)); + } + psa_key_type_t key_type = cipher_params->key_type; + size_t key_bits = cipher_params->key_bits; + psa_algorithm_t alg = cipher_params->algorithm; +#else mbedtls_cipher_type_t cipher = interop_atom_term_select_int(cipher_table, cipher_term, ctx->global); if (UNLIKELY(cipher == MBEDTLS_CIPHER_NONE)) { RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unknown cipher", ctx)); } +#endif // from this point onward use `goto raise_error` in order to raise and free all buffers term error_atom = UNDEFINED_ATOM; @@ -508,6 +660,171 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) goto raise_error; } +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + bool encrypt = true; + bool padding_pkcs7 = false; + psa_key_id_t key_id = 0; + size_t output_size = 0; + void *temp_buf = NULL; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + + if (term_is_list(flag_or_options)) { + term encrypt_flag = interop_kv_get_value_default( + flag_or_options, ATOM_STR("\x7", "encrypt"), UNDEFINED_ATOM, ctx->global); + if (encrypt_flag == FALSE_ATOM) { + encrypt = false; + } else if (encrypt_flag != TRUE_ATOM && encrypt_flag != UNDEFINED_ATOM) { + error_atom = BADARG_ATOM; + goto raise_error; + } + + term padding_term = interop_kv_get_value_default( + flag_or_options, ATOM_STR("\x7", "padding"), UNDEFINED_ATOM, ctx->global); + + if (padding_term != UNDEFINED_ATOM) { + if (padding_term == globalcontext_make_atom(ctx->global, ATOM_STR("\xC", "pkcs_padding"))) { + padding_pkcs7 = true; + } else if (padding_term != globalcontext_make_atom(ctx->global, ATOM_STR("\x4", "none"))) { + error_atom = BADARG_ATOM; + goto raise_error; + } + } + + } else { + if (flag_or_options == FALSE_ATOM) { + encrypt = false; + } else if (flag_or_options != TRUE_ATOM) { + error_atom = make_crypto_error( + __FILE__, __LINE__, "Options are not a boolean or a proper list", ctx); + goto raise_error; + } + } + + if (padding_pkcs7) { + if (alg == PSA_ALG_CBC_NO_PADDING) { + alg = PSA_ALG_CBC_PKCS7; + } else if (alg == PSA_ALG_ECB_NO_PADDING) { + // PSA does not support PKCS7 padding with ECB mode + error_atom = BADARG_ATOM; + goto raise_error; + } + } + + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_set_key_usage_flags(&attributes, encrypt ? PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attributes, alg); + psa_set_key_type(&attributes, key_type); + psa_set_key_bits(&attributes, key_bits); + + psa_status_t status = psa_import_key(&attributes, key_data, key_len, &key_id); + psa_reset_key_attributes(&attributes); + if (UNLIKELY(status != PSA_SUCCESS)) { + char err_msg[48]; + snprintf(err_msg, sizeof(err_msg), "key import err %d", (int) status); + error_atom = make_crypto_error(__FILE__, __LINE__, err_msg, ctx); + goto psa_error; + } + + output_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(key_type, alg, data_size); + if (!encrypt) { + output_size = PSA_CIPHER_DECRYPT_OUTPUT_SIZE(key_type, alg, data_size); + } + temp_buf = malloc(output_size ? output_size : 1); + if (IS_NULL_PTR(temp_buf)) { + error_atom = OUT_OF_MEMORY_ATOM; + goto psa_error; + } + + size_t output_len; + if (encrypt) { + status = psa_cipher_encrypt_setup(&operation, key_id, alg); + } else { + status = psa_cipher_decrypt_setup(&operation, key_id, alg); + } + if (UNLIKELY(status != PSA_SUCCESS)) { + char err_msg[48]; + snprintf(err_msg, sizeof(err_msg), "cipher setup err %d", (int) status); + error_atom = make_crypto_error(__FILE__, __LINE__, err_msg, ctx); + goto psa_error; + } + + // PSA rejects IVs for ECB; ignore IV to preserve legacy behavior. + if (iv_len > 0 && alg != PSA_ALG_ECB_NO_PADDING) { + status = psa_cipher_set_iv(&operation, iv_data, iv_len); + if (UNLIKELY(status != PSA_SUCCESS)) { + char err_msg[24]; + snprintf(err_msg, sizeof(err_msg), "IV err %d", (int) status); + error_atom = make_crypto_error(__FILE__, __LINE__, err_msg, ctx); + goto psa_error; + } + } + + // For CBC/ECB with no padding, PSA requires block-aligned input. + // The legacy mbedtls behavior was to process only complete blocks, + // so we truncate the input to the nearest block boundary for these modes. + size_t block_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type); + size_t process_size = data_size; + if (alg == PSA_ALG_CBC_NO_PADDING || alg == PSA_ALG_ECB_NO_PADDING) { + process_size = (data_size / block_size) * block_size; + if (process_size == 0) { + // No complete blocks to process + psa_cipher_abort(&operation); + psa_destroy_key(key_id); + secure_free(temp_buf, output_size); + secure_free(allocated_key_data, key_len); + secure_free(allocated_iv_data, iv_len); + secure_free(allocated_data_data, data_size); + // Return empty binary + if (UNLIKELY(memory_ensure_free(ctx, term_binary_heap_size(0)) != MEMORY_GC_OK)) { + RAISE_ERROR(OUT_OF_MEMORY_ATOM); + } + return term_from_literal_binary("", 0, &ctx->heap, ctx->global); + } + } + + size_t update_len = 0; + status = psa_cipher_update(&operation, data_data, process_size, temp_buf, output_size, &update_len); + if (UNLIKELY(status != PSA_SUCCESS)) { + char err_msg[24]; + snprintf(err_msg, sizeof(err_msg), "update err %d", (int) status); + error_atom = make_crypto_error(__FILE__, __LINE__, err_msg, ctx); + goto psa_error; + } + + size_t finish_len = 0; + status = psa_cipher_finish(&operation, (uint8_t *) temp_buf + update_len, output_size - update_len, &finish_len); + if (UNLIKELY(status != PSA_SUCCESS)) { + char err_msg[24]; + snprintf(err_msg, sizeof(err_msg), "finish err %d", (int) status); + error_atom = make_crypto_error(__FILE__, __LINE__, err_msg, ctx); + goto psa_error; + } + output_len = update_len + finish_len; + + psa_destroy_key(key_id); + + secure_free(allocated_key_data, key_len); + secure_free(allocated_iv_data, iv_len); + secure_free(allocated_data_data, data_size); + + int ensure_size = term_binary_heap_size(output_len); + if (UNLIKELY(memory_ensure_free(ctx, ensure_size) != MEMORY_GC_OK)) { + secure_free(temp_buf, output_size); + RAISE_ERROR(OUT_OF_MEMORY_ATOM); + } + + term out = term_from_literal_binary(temp_buf, output_len, &ctx->heap, ctx->global); + secure_free(temp_buf, output_size); + return out; + +psa_error: + psa_cipher_abort(&operation); + if (key_id != 0) { + psa_destroy_key(key_id); + } + secure_free(temp_buf, output_size); + goto raise_error; +#else mbedtls_operation_t operation; mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_NONE; bool padding_has_been_set = false; @@ -625,6 +942,15 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) char err_msg[24]; snprintf(err_msg, sizeof(err_msg), "Error %x", -result); RAISE_ERROR(make_crypto_error(__FILE__, source_line, err_msg, ctx)); +#endif + +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 +raise_error: + secure_free(allocated_key_data, key_len); + secure_free(allocated_iv_data, iv_len); + secure_free(allocated_data_data, data_size); + RAISE_ERROR(error_atom); +#endif } #ifdef HAVE_PSA_CRYPTO @@ -712,13 +1038,6 @@ static const struct PsaEccCurveParams *psa_ecc_curve_table_lookup(enum pk_param_ return NULL; } -static void do_psa_init(void) -{ - if (UNLIKELY(psa_crypto_init() != PSA_SUCCESS)) { - abort(); - } -} - // TODO: MbedTLS PSA Crypto API is expected to add Ed25519/X25519 support in a future version. // Once that version is widely adopted, we may be able to replace the libsodium backend with // pure PSA API calls. @@ -1255,22 +1574,6 @@ static term nif_crypto_compute_key(Context *ctx, int argc, term argv[]) return result; } -static const AtomStringIntPair psa_hash_algorithm_table[] = { - { ATOM_STR("\x3", "sha"), PSA_ALG_SHA_1 }, - { ATOM_STR("\x6", "sha224"), PSA_ALG_SHA_224 }, - { ATOM_STR("\x6", "sha256"), PSA_ALG_SHA_256 }, - { ATOM_STR("\x6", "sha384"), PSA_ALG_SHA_384 }, - { ATOM_STR("\x6", "sha512"), PSA_ALG_SHA_512 }, - { ATOM_STR("\x8", "sha3_224"), PSA_ALG_SHA3_224 }, - { ATOM_STR("\x8", "sha3_256"), PSA_ALG_SHA3_256 }, - { ATOM_STR("\x8", "sha3_384"), PSA_ALG_SHA3_384 }, - { ATOM_STR("\x8", "sha3_512"), PSA_ALG_SHA3_512 }, - { ATOM_STR("\x3", "md5"), PSA_ALG_MD5 }, - { ATOM_STR("\x9", "ripemd160"), PSA_ALG_RIPEMD160 }, - - SELECT_INT_DEFAULT(PSA_ALG_NONE) -}; - #ifdef CRYPTO_SIGN_AVAILABLE static term nif_crypto_sign(Context *ctx, int argc, term argv[]) @@ -1369,7 +1672,11 @@ static term nif_crypto_sign(Context *ctx, int argc, term argv[]) size_t sig_raw_size = PSA_ECDSA_SIGNATURE_SIZE(psa_key_bits); uint8_t *sig_raw = NULL; +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + size_t sig_der_size = MBEDTLS_ECDSA_DER_MAX_SIG_LEN(psa_key_bits); +#else size_t sig_der_size = MBEDTLS_ECDSA_MAX_SIG_LEN(psa_key_bits); +#endif void *sig_der = NULL; void *maybe_allocated_data = NULL; @@ -1377,7 +1684,7 @@ static term nif_crypto_sign(Context *ctx, int argc, term argv[]) term data_term = argv[2]; const void *data; - size_t data_len; + size_t data_len = 0; term iodata_handle_result = handle_iodata(data_term, &data, &data_len, &maybe_allocated_data); if (UNLIKELY(iodata_handle_result != OK_ATOM)) { result = make_crypto_error(__FILE__, __LINE__, "Expected a binary or a list", ctx); @@ -1432,9 +1739,9 @@ static term nif_crypto_sign(Context *ctx, int argc, term argv[]) cleanup: psa_destroy_key(key_id); - free(maybe_allocated_data); - free(sig_raw); - free(sig_der); + secure_free(maybe_allocated_data, data_len); + secure_free(sig_raw, sig_raw_size); + secure_free(sig_der, sig_der_size); if (UNLIKELY(!success)) { RAISE_ERROR(result); @@ -1554,7 +1861,7 @@ static term nif_crypto_verify(Context *ctx, int argc, term argv[]) term data_term = argv[2]; const void *data; - size_t data_len; + size_t data_len = 0; term iodata_handle_result = handle_iodata(data_term, &data, &data_len, &maybe_allocated_data); if (UNLIKELY(iodata_handle_result != OK_ATOM)) { result = make_crypto_error(__FILE__, __LINE__, "Expected a binary or a list", ctx); @@ -1601,8 +1908,8 @@ static term nif_crypto_verify(Context *ctx, int argc, term argv[]) cleanup: psa_destroy_key(key_id); - free(maybe_allocated_data); - free(sig_raw); + secure_free(maybe_allocated_data, data_len); + secure_free(sig_raw, sig_raw_size); if (UNLIKELY(!success)) { RAISE_ERROR(result); @@ -1655,6 +1962,8 @@ static term nif_crypto_mac(Context *ctx, int argc, term argv[]) void *maybe_allocated_key = NULL; size_t key_len = 0; void *maybe_allocated_data = NULL; + const void *data = NULL; + size_t data_len = 0; size_t mac_out_size = 0; void *mac_out = NULL; @@ -1722,8 +2031,6 @@ static term nif_crypto_mac(Context *ctx, int argc, term argv[]) } term data_term = argv[3]; - const void *data; - size_t data_len; iodata_handle_result = handle_iodata(data_term, &data, &data_len, &maybe_allocated_data); if (UNLIKELY(iodata_handle_result != OK_ATOM)) { result = make_crypto_error(__FILE__, __LINE__, "Expected a binary or a list", ctx); @@ -1762,7 +2069,7 @@ static term nif_crypto_mac(Context *ctx, int argc, term argv[]) psa_destroy_key(key_id); secure_free(mac_out, mac_out_size); secure_free(maybe_allocated_key, key_len); - free(maybe_allocated_data); + secure_free(maybe_allocated_data, data_len); if (UNLIKELY(!success)) { RAISE_ERROR(result); @@ -1797,6 +2104,7 @@ struct MacState psa_algorithm_t psa_algo; psa_key_type_t psa_key_type; size_t key_bit_size; + bool finalized; #ifndef AVM_NO_SMP Mutex *mutex; #endif @@ -1808,7 +2116,10 @@ static void psa_mac_op_dtor(ErlNifEnv *caller_env, void *obj) struct MacState *mac_state = (struct MacState *) obj; psa_mac_abort(&mac_state->psa_op); - psa_destroy_key(mac_state->key_id); + if (mac_state->key_id != 0) { + psa_destroy_key(mac_state->key_id); + mac_state->key_id = 0; + } #ifndef AVM_NO_SMP if (mac_state->mutex) { smp_mutex_destroy(mac_state->mutex); @@ -1964,23 +2275,33 @@ static term nif_crypto_mac_update(Context *ctx, int argc, term argv[]) } struct MacState *mac_state = (struct MacState *) psa_mac_obj_ptr; + if (UNLIKELY(mac_state->finalized)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "MAC already finalized", ctx)); + } + void *maybe_allocated_data = NULL; - size_t data_len; + size_t data_len = 0; term data_term = argv[1]; const void *data; term iodata_handle_result = handle_iodata(data_term, &data, &data_len, &maybe_allocated_data); if (UNLIKELY(iodata_handle_result != OK_ATOM)) { - free(maybe_allocated_data); + secure_free(maybe_allocated_data, data_len); RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Bad text", ctx)); } SMP_MUTEX_LOCK(mac_state->mutex); psa_status_t status = psa_mac_update(&mac_state->psa_op, data, data_len); - SMP_MUTEX_UNLOCK(mac_state->mutex); - free(maybe_allocated_data); if (UNLIKELY(status != PSA_SUCCESS)) { + psa_mac_abort(&mac_state->psa_op); + psa_destroy_key(mac_state->key_id); + mac_state->key_id = 0; + mac_state->finalized = true; + SMP_MUTEX_UNLOCK(mac_state->mutex); + secure_free(maybe_allocated_data, data_len); RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unexpected error", ctx)); } + SMP_MUTEX_UNLOCK(mac_state->mutex); + secure_free(maybe_allocated_data, data_len); return argv[0]; } @@ -2000,6 +2321,10 @@ static term nif_crypto_mac_final(Context *ctx, int argc, term argv[]) } struct MacState *mac_state = (struct MacState *) psa_mac_obj_ptr; + if (UNLIKELY(mac_state->finalized)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "MAC already finalized", ctx)); + } + bool success = false; term result = ERROR_ATOM; @@ -2017,6 +2342,9 @@ static term nif_crypto_mac_final(Context *ctx, int argc, term argv[]) size_t mac_len = 0; SMP_MUTEX_LOCK(mac_state->mutex); psa_status_t status = psa_mac_sign_finish(&mac_state->psa_op, mac_buf, mac_size, &mac_len); + psa_destroy_key(mac_state->key_id); + mac_state->key_id = 0; + mac_state->finalized = true; SMP_MUTEX_UNLOCK(mac_state->mutex); if (UNLIKELY(status != PSA_SUCCESS)) { result = make_crypto_error(__FILE__, __LINE__, "Unexpected error", ctx); @@ -2049,6 +2377,10 @@ static term nif_crypto_mac_finalN(Context *ctx, int argc, term argv[]) } struct MacState *mac_state = (struct MacState *) psa_mac_obj_ptr; + if (UNLIKELY(mac_state->finalized)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "MAC already finalized", ctx)); + } + avm_int_t requested_len; if (UNLIKELY(!term_is_integer(argv[1]))) { RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Bad length", ctx)); @@ -2076,6 +2408,9 @@ static term nif_crypto_mac_finalN(Context *ctx, int argc, term argv[]) size_t mac_len = 0; SMP_MUTEX_LOCK(mac_state->mutex); psa_status_t status = psa_mac_sign_finish(&mac_state->psa_op, mac_buf, mac_size, &mac_len); + psa_destroy_key(mac_state->key_id); + mac_state->key_id = 0; + mac_state->finalized = true; SMP_MUTEX_UNLOCK(mac_state->mutex); if (UNLIKELY(status != PSA_SUCCESS)) { result = make_crypto_error(__FILE__, __LINE__, "Unexpected error", ctx); @@ -2304,7 +2639,10 @@ static void psa_cipher_op_dtor(ErlNifEnv *caller_env, void *obj) struct CipherState *cipher_state = (struct CipherState *) obj; psa_cipher_abort(&cipher_state->psa_op); - psa_destroy_key(cipher_state->key_id); + if (cipher_state->key_id != 0) { + psa_destroy_key(cipher_state->key_id); + cipher_state->key_id = 0; + } #ifndef AVM_NO_SMP if (cipher_state->mutex) { smp_mutex_destroy(cipher_state->mutex); @@ -2317,52 +2655,6 @@ const ErlNifResourceTypeInit psa_cipher_op_resource_type_init = { .dtor = psa_cipher_op_dtor }; -struct PsaCipherParams -{ - const char *atom_str; - psa_key_type_t key_type; - psa_algorithm_t algorithm; - uint16_t key_bits; - uint8_t block_size; - uint8_t iv_len; -}; - -static const struct PsaCipherParams psa_cipher_table[] = { - // ECB modes - block cipher, no IV - { ATOM_STR("\xB", "aes_128_ecb"), PSA_KEY_TYPE_AES, PSA_ALG_ECB_NO_PADDING, 128, 16, 0 }, - { ATOM_STR("\xB", "aes_192_ecb"), PSA_KEY_TYPE_AES, PSA_ALG_ECB_NO_PADDING, 192, 16, 0 }, - { ATOM_STR("\xB", "aes_256_ecb"), PSA_KEY_TYPE_AES, PSA_ALG_ECB_NO_PADDING, 256, 16, 0 }, - // CBC modes - block cipher, with IV - { ATOM_STR("\xB", "aes_128_cbc"), PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, 128, 16, 16 }, - { ATOM_STR("\xB", "aes_192_cbc"), PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, 192, 16, 16 }, - { ATOM_STR("\xB", "aes_256_cbc"), PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, 256, 16, 16 }, - // CFB128 modes - stream-like, with IV - { ATOM_STR("\xE", "aes_128_cfb128"), PSA_KEY_TYPE_AES, PSA_ALG_CFB, 128, 0, 16 }, - { ATOM_STR("\xE", "aes_192_cfb128"), PSA_KEY_TYPE_AES, PSA_ALG_CFB, 192, 0, 16 }, - { ATOM_STR("\xE", "aes_256_cfb128"), PSA_KEY_TYPE_AES, PSA_ALG_CFB, 256, 0, 16 }, - // CTR modes - stream cipher, with IV - { ATOM_STR("\xB", "aes_128_ctr"), PSA_KEY_TYPE_AES, PSA_ALG_CTR, 128, 0, 16 }, - { ATOM_STR("\xB", "aes_192_ctr"), PSA_KEY_TYPE_AES, PSA_ALG_CTR, 192, 0, 16 }, - { ATOM_STR("\xB", "aes_256_ctr"), PSA_KEY_TYPE_AES, PSA_ALG_CTR, 256, 0, 16 }, - // OFB modes - stream-like, with IV - { ATOM_STR("\xB", "aes_128_ofb"), PSA_KEY_TYPE_AES, PSA_ALG_OFB, 128, 0, 16 }, - { ATOM_STR("\xB", "aes_192_ofb"), PSA_KEY_TYPE_AES, PSA_ALG_OFB, 192, 0, 16 }, - { ATOM_STR("\xB", "aes_256_ofb"), PSA_KEY_TYPE_AES, PSA_ALG_OFB, 256, 0, 16 }, -}; - -#define PSA_CIPHER_TABLE_LEN (sizeof(psa_cipher_table) / sizeof(psa_cipher_table[0])) - -static const struct PsaCipherParams *psa_cipher_table_lookup(GlobalContext *glb, term cipher_atom) -{ - for (size_t i = 0; i < PSA_CIPHER_TABLE_LEN; i++) { - AtomString atom_str = (AtomString) psa_cipher_table[i].atom_str; - if (globalcontext_is_term_equal_to_atom_string(glb, cipher_atom, atom_str)) { - return &psa_cipher_table[i]; - } - } - return NULL; -} - /* * Accepts: * - true / false (boolean shorthand for {encrypt, true/false}) @@ -2611,12 +2903,13 @@ static term nif_crypto_crypto_update(Context *ctx, int argc, term argv[]) void *maybe_allocated_data = NULL; void *out_buf = NULL; + size_t data_len = 0; + size_t out_size = 0; // from this point onward use `goto cleanup` in order to raise and free all buffers /* 2. Handle iodata input */ const void *data; - size_t data_len; term iodata_result = handle_iodata(argv[1], &data, &data_len, &maybe_allocated_data); if (UNLIKELY(iodata_result == BADARG_ATOM)) { SMP_MUTEX_UNLOCK(cipher_state->mutex); @@ -2630,7 +2923,7 @@ static term nif_crypto_crypto_update(Context *ctx, int argc, term argv[]) } /* 3. Encrypt/decrypt via PSA - PSA handles internal block buffering */ - size_t out_size = PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE(data_len); + out_size = PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE(data_len); if (out_size == 0) { out_size = 1; /* ensure valid malloc even for zero-length input */ } @@ -2644,11 +2937,16 @@ static term nif_crypto_crypto_update(Context *ctx, int argc, term argv[]) size_t out_len = 0; psa_status_t status = psa_cipher_update(&cipher_state->psa_op, data, data_len, out_buf, out_size, &out_len); - SMP_MUTEX_UNLOCK(cipher_state->mutex); if (UNLIKELY(status != PSA_SUCCESS)) { + psa_cipher_abort(&cipher_state->psa_op); + psa_destroy_key(cipher_state->key_id); + cipher_state->key_id = 0; + cipher_state->finalized = true; + SMP_MUTEX_UNLOCK(cipher_state->mutex); result = make_crypto_error(__FILE__, __LINE__, "Unexpected error", ctx); goto cleanup; } + SMP_MUTEX_UNLOCK(cipher_state->mutex); if (UNLIKELY(memory_ensure_free(ctx, TERM_BINARY_HEAP_SIZE(out_len)) != MEMORY_GC_OK)) { result = OUT_OF_MEMORY_ATOM; @@ -2659,8 +2957,8 @@ static term nif_crypto_crypto_update(Context *ctx, int argc, term argv[]) result = term_from_literal_binary(out_buf, out_len, &ctx->heap, glb); cleanup: - free(maybe_allocated_data); - free(out_buf); + secure_free(maybe_allocated_data, data_len); + secure_free(out_buf, out_size); if (UNLIKELY(!success)) { RAISE_ERROR(result); @@ -2714,6 +3012,8 @@ static term nif_crypto_crypto_final(Context *ctx, int argc, term argv[]) size_t out_len = 0; psa_status_t status = psa_cipher_finish(&cipher_state->psa_op, out_buf, out_size, &out_len); cipher_state->finalized = true; + psa_destroy_key(cipher_state->key_id); + cipher_state->key_id = 0; SMP_MUTEX_UNLOCK(cipher_state->mutex); if (status == PSA_SUCCESS) { @@ -2760,7 +3060,7 @@ static term nif_crypto_crypto_final(Context *ctx, int argc, term argv[]) } cleanup: - free(out_buf); + secure_free(out_buf, out_size); if (UNLIKELY(!success)) { RAISE_ERROR(result); @@ -2841,6 +3141,10 @@ static term nif_crypto_crypto_one_time_aead(Context *ctx, int argc, term argv[]) RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "EncFlag must be a boolean", ctx)); } + if (UNLIKELY(!encrypting && argc == 6)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Tag is required for AEAD decryption", ctx)); + } + size_t tag_len = aead_params->default_tag_len; const void *tag_data = NULL; size_t tag_data_len = 0; @@ -2916,19 +3220,19 @@ static term nif_crypto_crypto_one_time_aead(Context *ctx, int argc, term argv[]) void *maybe_allocated_aad = NULL; void *out_buf = NULL; size_t out_buf_size = 0; + const void *intext_data = NULL; + size_t intext_len = 0; + const void *aad_data = NULL; + size_t aad_len = 0; // from this point onward use `goto cleanup` in order to raise and free all buffers - const void *intext_data; - size_t intext_len; term iodata_result = handle_iodata(argv[3], &intext_data, &intext_len, &maybe_allocated_intext); if (UNLIKELY(iodata_result != OK_ATOM)) { result = make_crypto_error(__FILE__, __LINE__, "Expected a binary or a list", ctx); goto cleanup; } - const void *aad_data; - size_t aad_len; iodata_result = handle_iodata(argv[4], &aad_data, &aad_len, &maybe_allocated_aad); if (UNLIKELY(iodata_result != OK_ATOM)) { result = make_crypto_error(__FILE__, __LINE__, "Expected a binary or a list", ctx); @@ -2996,7 +3300,7 @@ static term nif_crypto_crypto_one_time_aead(Context *ctx, int argc, term argv[]) out_buf_size = pt_size + 1; out_buf = malloc(out_buf_size); // +1 to ensure valid malloc even for 0 if (IS_NULL_PTR(out_buf)) { - free(combined_buf); + secure_free(combined_buf, combined_len); result = OUT_OF_MEMORY_ATOM; goto cleanup; } @@ -3004,7 +3308,7 @@ static term nif_crypto_crypto_one_time_aead(Context *ctx, int argc, term argv[]) size_t pt_len = 0; status = psa_aead_decrypt(key_id, psa_algo, iv_data, iv_len, aad_data, aad_len, combined_buf, combined_len, out_buf, pt_size, &pt_len); - free(combined_buf); + secure_free(combined_buf, combined_len); switch (status) { case PSA_SUCCESS: @@ -3037,8 +3341,8 @@ static term nif_crypto_crypto_one_time_aead(Context *ctx, int argc, term argv[]) cleanup: psa_destroy_key(key_id); - free(maybe_allocated_intext); - free(maybe_allocated_aad); + secure_free(maybe_allocated_intext, intext_len); + secure_free(maybe_allocated_aad, aad_len); secure_free(out_buf, out_buf_size); if (UNLIKELY(!success)) { @@ -3091,7 +3395,8 @@ static term nif_crypto_hash_equals(Context *ctx, int argc, term argv[]) return cmp == 0 ? TRUE_ATOM : FALSE_ATOM; } -#ifdef MBEDTLS_PKCS5_C +#ifdef AVM_HAVE_PBKDF2_HMAC +#if MBEDTLS_VERSION_NUMBER < 0x04000000 static const AtomStringIntPair md_hash_algorithm_table[] = { { ATOM_STR("\x3", "sha"), MBEDTLS_MD_SHA1 }, { ATOM_STR("\x6", "sha224"), MBEDTLS_MD_SHA224 }, @@ -3103,6 +3408,7 @@ static const AtomStringIntPair md_hash_algorithm_table[] = { SELECT_INT_DEFAULT(MBEDTLS_MD_NONE) }; +#endif static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) { @@ -3113,12 +3419,6 @@ static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) term digest_type_term = argv[0]; // argv[1] is password, argv[2] is salt, argv[3] is iterations, argv[4] is key_len - mbedtls_md_type_t md_type - = interop_atom_term_select_int(md_hash_algorithm_table, digest_type_term, glb); - if (UNLIKELY(md_type == MBEDTLS_MD_NONE)) { - RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unknown digest type", ctx)); - } - bool success = false; term result = ERROR_ATOM; @@ -3129,6 +3429,19 @@ static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) void *derived_key = NULL; avm_int_t derived_key_len = 0; +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + psa_algorithm_t hash_alg = interop_atom_term_select_int(psa_hash_algorithm_table, digest_type_term, glb); + if (UNLIKELY(hash_alg == PSA_ALG_NONE)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unknown digest type", ctx)); + } +#else + mbedtls_md_type_t md_type + = interop_atom_term_select_int(md_hash_algorithm_table, digest_type_term, glb); + if (UNLIKELY(md_type == MBEDTLS_MD_NONE)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unknown digest type", ctx)); + } +#endif + term password_term = argv[1]; const void *password; term iodata_handle_result @@ -3154,6 +3467,11 @@ static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) goto cleanup; } uint32_t iterations = term_to_uint32(iterations_term); + if (UNLIKELY(iterations == 0)) { + result + = make_crypto_error(__FILE__, __LINE__, "Iterations must be a positive integer", ctx); + goto cleanup; + } term key_len_term = argv[4]; if (UNLIKELY(!term_is_pos_int(key_len_term))) { @@ -3168,6 +3486,48 @@ static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) goto cleanup; } +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + do_psa_init(); + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + + psa_status_t status = psa_key_derivation_setup(&operation, PSA_ALG_PBKDF2_HMAC(hash_alg)); + if (UNLIKELY(status != PSA_SUCCESS)) { + psa_key_derivation_abort(&operation); + result = make_crypto_error(__FILE__, __LINE__, "Key derivation failed", ctx); + goto cleanup; + } + + status = psa_key_derivation_input_integer( + &operation, PSA_KEY_DERIVATION_INPUT_COST, iterations); + if (UNLIKELY(status != PSA_SUCCESS)) { + psa_key_derivation_abort(&operation); + result = make_crypto_error(__FILE__, __LINE__, "Key derivation failed", ctx); + goto cleanup; + } + + status = psa_key_derivation_input_bytes( + &operation, PSA_KEY_DERIVATION_INPUT_SALT, salt, salt_len); + if (UNLIKELY(status != PSA_SUCCESS)) { + psa_key_derivation_abort(&operation); + result = make_crypto_error(__FILE__, __LINE__, "Key derivation failed", ctx); + goto cleanup; + } + + status = psa_key_derivation_input_bytes( + &operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, password, password_len); + if (UNLIKELY(status != PSA_SUCCESS)) { + psa_key_derivation_abort(&operation); + result = make_crypto_error(__FILE__, __LINE__, "Key derivation failed", ctx); + goto cleanup; + } + + status = psa_key_derivation_output_bytes(&operation, derived_key, derived_key_len); + psa_key_derivation_abort(&operation); + if (UNLIKELY(status != PSA_SUCCESS)) { + result = make_crypto_error(__FILE__, __LINE__, "Key derivation failed", ctx); + goto cleanup; + } +#else #if MBEDTLS_VERSION_NUMBER >= 0x03030000 // mbedtls_pkcs5_pbkdf2_hmac_ext is available since 3.3.0 int ret = mbedtls_pkcs5_pbkdf2_hmac_ext( @@ -3192,6 +3552,7 @@ static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) result = make_crypto_error(__FILE__, __LINE__, "Key derivation failed", ctx); goto cleanup; } +#endif if (UNLIKELY(memory_ensure_free(ctx, TERM_BINARY_HEAP_SIZE(derived_key_len)) != MEMORY_GC_OK)) { result = OUT_OF_MEMORY_ATOM; @@ -3231,6 +3592,18 @@ term nif_crypto_strong_rand_bytes(Context *ctx, int argc, term argv[]) RAISE_ERROR(OUT_OF_MEMORY_ATOM); } +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + do_psa_init(); + term out_bin = term_create_uninitialized_binary(out_len, &ctx->heap, ctx->global); + unsigned char *out = (unsigned char *) term_binary_data(out_bin); + + psa_status_t status = psa_generate_random(out, out_len); + if (UNLIKELY(status != PSA_SUCCESS)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Failed random", ctx)); + } + + return out_bin; +#else mbedtls_ctr_drbg_context *rnd_ctx = sys_mbedtls_get_ctr_drbg_context_lock(ctx->global); if (IS_NULL_PTR(rnd_ctx)) { RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Failed CTR_DRBG init", ctx)); @@ -3246,6 +3619,7 @@ term nif_crypto_strong_rand_bytes(Context *ctx, int argc, term argv[]) } return out_bin; +#endif } static const char *get_mbedtls_version_string_full(char *buf, size_t buf_size) @@ -3420,7 +3794,7 @@ static const struct Nif crypto_crypto_one_time_aead_nif = { .nif_ptr = nif_crypto_crypto_one_time_aead }; #endif -#ifdef MBEDTLS_PKCS5_C +#ifdef AVM_HAVE_PBKDF2_HMAC static const struct Nif crypto_pbkdf2_hmac_nif = { .base.type = NIFFunctionType, .nif_ptr = nif_crypto_pbkdf2_hmac @@ -3533,7 +3907,7 @@ const struct Nif *otp_crypto_nif_get_nif(const char *nifname) return &crypto_crypto_one_time_aead_nif; } #endif -#ifdef MBEDTLS_PKCS5_C +#ifdef AVM_HAVE_PBKDF2_HMAC if (strcmp("pbkdf2_hmac/5", rest) == 0) { TRACE("Resolved platform nif %s ...\n", nifname); return &crypto_pbkdf2_hmac_nif; diff --git a/src/libAtomVM/otp_ssl.c b/src/libAtomVM/otp_ssl.c index b74d2cb8af..5bdf1a337f 100644 --- a/src/libAtomVM/otp_ssl.c +++ b/src/libAtomVM/otp_ssl.c @@ -35,11 +35,14 @@ #include +#include +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #include #include +#endif #include -#if defined(HAVE_PSA_CRYPTO) +#if defined(HAVE_PSA_CRYPTO) || defined(MBEDTLS_PSA_CRYPTO_C) || MBEDTLS_VERSION_NUMBER >= 0x04000000 #include #endif @@ -75,12 +78,20 @@ static void mbedtls_debug_cb(void *ctx, int level, const char *filename, int lin struct EntropyContextResource { +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_entropy_context context; +#else + char dummy; +#endif }; struct CtrDrbgResource { +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_ctr_drbg_context context; +#else + char dummy; +#endif }; struct SSLContextResource @@ -98,7 +109,11 @@ static void entropycontext_dtor(ErlNifEnv *caller_env, void *obj) UNUSED(caller_env); struct EntropyContextResource *rsrc_obj = (struct EntropyContextResource *) obj; +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_entropy_free(&rsrc_obj->context); +#else + UNUSED(rsrc_obj); +#endif } static void ctrdrbg_dtor(ErlNifEnv *caller_env, void *obj) @@ -107,6 +122,7 @@ static void ctrdrbg_dtor(ErlNifEnv *caller_env, void *obj) UNUSED(caller_env); struct CtrDrbgResource *rsrc_obj = (struct CtrDrbgResource *) obj; +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_entropy_context *entropy_context = rsrc_obj->context.MBEDTLS_PRIVATE(p_entropy); // Release the drbg first mbedtls_ctr_drbg_free(&rsrc_obj->context); @@ -116,6 +132,9 @@ static void ctrdrbg_dtor(ErlNifEnv *caller_env, void *obj) struct RefcBinary *entropy_refc = refc_binary_from_data(entropy_obj); refc_binary_decrement_refcount(entropy_refc, caller_env->global); } +#else + UNUSED(rsrc_obj); +#endif } static void sslcontext_dtor(ErlNifEnv *caller_env, void *obj) @@ -141,15 +160,19 @@ static void sslconfig_dtor(ErlNifEnv *caller_env, void *obj) UNUSED(caller_env); struct SSLConfigResource *rsrc_obj = (struct SSLConfigResource *) obj; +#if MBEDTLS_VERSION_NUMBER < 0x04000000 const mbedtls_ctr_drbg_context *ctr_drbg_context = rsrc_obj->config.MBEDTLS_PRIVATE(p_rng); +#endif mbedtls_ssl_config_free(&rsrc_obj->config); +#if MBEDTLS_VERSION_NUMBER < 0x04000000 // Eventually release the ctrdrbg if (ctr_drbg_context) { struct CtrDrbgResource *rng_obj = CONTAINER_OF(ctr_drbg_context, struct CtrDrbgResource, context); struct RefcBinary *config_refc = refc_binary_from_data(rng_obj); refc_binary_decrement_refcount(config_refc, caller_env->global); } +#endif } static const ErlNifResourceTypeInit EntropyContextResourceTypeInit = { @@ -238,7 +261,9 @@ static term nif_ssl_entropy_init(Context *ctx, int argc, term argv[]) term obj = term_from_resource(rsrc_obj, &ctx->heap); enif_release_resource(rsrc_obj); // decrement refcount after enif_alloc_resource +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_entropy_init(&rsrc_obj->context); +#endif return obj; } @@ -261,7 +286,9 @@ static term nif_ssl_ctr_drbg_init(Context *ctx, int argc, term argv[]) term obj = term_from_resource(rsrc_obj, &ctx->heap); enif_release_resource(rsrc_obj); // decrement refcount after enif_alloc_resource +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_ctr_drbg_init(&rsrc_obj->context); +#endif return obj; } @@ -277,11 +304,14 @@ static term nif_ssl_ctr_drbg_seed(Context *ctx, int argc, term argv[]) if (UNLIKELY(!enif_get_resource(erl_nif_env_from_context(ctx), argv[0], ctrdrbg_resource_type, &rsrc_obj_ptr))) { RAISE_ERROR(BADARG_ATOM); } +#if MBEDTLS_VERSION_NUMBER < 0x04000000 struct CtrDrbgResource *ctrdrbg_obj = (struct CtrDrbgResource *) rsrc_obj_ptr; +#endif if (UNLIKELY(!enif_get_resource(erl_nif_env_from_context(ctx), argv[1], entropycontext_resource_type, &rsrc_obj_ptr))) { RAISE_ERROR(BADARG_ATOM); } +#if MBEDTLS_VERSION_NUMBER < 0x04000000 struct EntropyContextResource *entropy_obj = (struct EntropyContextResource *) rsrc_obj_ptr; int err = mbedtls_ctr_drbg_seed(&ctrdrbg_obj->context, mbedtls_entropy_func, &entropy_obj->context, (const unsigned char *) term_binary_data(argv[2]), term_binary_size(argv[2])); @@ -291,6 +321,7 @@ static term nif_ssl_ctr_drbg_seed(Context *ctx, int argc, term argv[]) struct RefcBinary *entropy_refc = refc_binary_from_data(entropy_obj); refc_binary_increment_refcount(entropy_refc); +#endif return OK_ATOM; } @@ -315,7 +346,7 @@ static term nif_ssl_init(Context *ctx, int argc, term argv[]) mbedtls_ssl_init(&rsrc_obj->context); -#if defined(HAVE_PSA_CRYPTO) +#if defined(HAVE_PSA_CRYPTO) || defined(MBEDTLS_PSA_CRYPTO_C) || MBEDTLS_VERSION_NUMBER >= 0x04000000 psa_status_t status = psa_crypto_init(); if (UNLIKELY(status != PSA_SUCCESS)) { AVM_LOGW(TAG, "Failed to initialize PSA %s:%i.\n", __FILE__, __LINE__); @@ -484,10 +515,16 @@ static term nif_ssl_conf_rng(Context *ctx, int argc, term argv[]) } struct CtrDrbgResource *ctr_drbg_obj = (struct CtrDrbgResource *) rsrc_obj_ptr; +#if MBEDTLS_VERSION_NUMBER < 0x04000000 struct RefcBinary *ctr_drbg_refc = refc_binary_from_data(ctr_drbg_obj); refc_binary_increment_refcount(ctr_drbg_refc); mbedtls_ssl_conf_rng(&conf_obj->config, mbedtls_ctr_drbg_random, &ctr_drbg_obj->context); +#else + // mbedtls 4.x uses PSA for randomness; no explicit RNG configuration needed. + UNUSED(conf_obj); + UNUSED(ctr_drbg_obj); +#endif return OK_ATOM; } diff --git a/src/libAtomVM/sys_mbedtls.h b/src/libAtomVM/sys_mbedtls.h index 51eb59f64a..7d51ea1107 100644 --- a/src/libAtomVM/sys_mbedtls.h +++ b/src/libAtomVM/sys_mbedtls.h @@ -21,8 +21,15 @@ #ifndef _SYS_MBEDTLS_H_ #define _SYS_MBEDTLS_H_ +// Include version.h to get MBEDTLS_VERSION_NUMBER (available in all versions) +#include + +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 +#include +#else #include #include +#endif #ifdef __cplusplus extern "C" { @@ -36,6 +43,7 @@ extern "C" { // On non-SMP builds, we don't need any lock because all calls we make to // mbedtls_ctr_drbg* functions are done from the scheduler thread itself. +#if MBEDTLS_VERSION_NUMBER < 0x04000000 /** * @brief get and acquire lock on mbedtls_entropy_context. * @details this function must be called from a scheduler thread (nif, @@ -60,7 +68,9 @@ void sys_mbedtls_entropy_context_unlock(GlobalContext *global); * the entropy mutex to call `mbedtls_entropy_func`. */ int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size); +#endif +#if MBEDTLS_VERSION_NUMBER < 0x04000000 /** * @brief get and acquire lock on mbedtls_ctr_drbg_context. * @details this function must be called from a scheduler thread (nif, @@ -78,6 +88,7 @@ mbedtls_ctr_drbg_context *sys_mbedtls_get_ctr_drbg_context_lock(GlobalContext *g * @param global the global context */ void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global); +#endif #ifdef __cplusplus } diff --git a/src/platforms/emscripten/src/lib/CMakeLists.txt b/src/platforms/emscripten/src/lib/CMakeLists.txt index d4cc232f38..a9c26f9b24 100644 --- a/src/platforms/emscripten/src/lib/CMakeLists.txt +++ b/src/platforms/emscripten/src/lib/CMakeLists.txt @@ -52,19 +52,24 @@ target_compile_features(libAtomVM${PLATFORM_LIB_SUFFIX} PUBLIC c_std_11) target_link_libraries(libAtomVM${PLATFORM_LIB_SUFFIX} PUBLIC libAtomVM) target_compile_definitions(libAtomVM${PLATFORM_LIB_SUFFIX} PUBLIC ATOMVM_HAS_MBEDTLS) -target_link_libraries(libAtomVM${PLATFORM_LIB_SUFFIX} PUBLIC MbedTLS::mbedcrypto) +target_link_libraries(libAtomVM${PLATFORM_LIB_SUFFIX} PUBLIC MbedTLS::mbedtls) include(CheckCSourceCompiles) -get_target_property(_mbedcrypto_includes MbedTLS::mbedcrypto INTERFACE_INCLUDE_DIRECTORIES) -set(CMAKE_REQUIRED_INCLUDES ${_mbedcrypto_includes}) +get_target_property(_mbedtls_includes MbedTLS::mbedtls INTERFACE_INCLUDE_DIRECTORIES) +set(CMAKE_REQUIRED_INCLUDES ${_mbedtls_includes}) +set(_avm_try_compile_target_type ${CMAKE_TRY_COMPILE_TARGET_TYPE}) +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) check_c_source_compiles(" #include #ifndef MBEDTLS_PSA_CRYPTO_C #error PSA Crypto not available #endif + #include int main(void) { return 0; } " HAVE_PSA_CRYPTO) +set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_avm_try_compile_target_type}) unset(CMAKE_REQUIRED_INCLUDES) -unset(_mbedcrypto_includes) +unset(_avm_try_compile_target_type) +unset(_mbedtls_includes) if (HAVE_PSA_CRYPTO) target_compile_definitions(libAtomVM${PLATFORM_LIB_SUFFIX} PUBLIC HAVE_PSA_CRYPTO) endif() diff --git a/src/platforms/emscripten/src/lib/emscripten_sys.h b/src/platforms/emscripten/src/lib/emscripten_sys.h index 1889b2ab97..68555d7050 100644 --- a/src/platforms/emscripten/src/lib/emscripten_sys.h +++ b/src/platforms/emscripten/src/lib/emscripten_sys.h @@ -33,17 +33,14 @@ #include #include +#include "sys_mbedtls.h" +#include + +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #include #include - -#if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000) -#include -#else -#include #endif -#include "sys_mbedtls.h" - struct PromiseResource { em_promise_t promise; @@ -117,6 +114,7 @@ struct EmscriptenPlatformData ErlNifResourceType *htmlevent_user_data_resource_type; ErlNifResourceType *websocket_resource_type; +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #ifndef AVM_NO_SMP Mutex *entropy_mutex; #endif @@ -128,6 +126,7 @@ struct EmscriptenPlatformData #endif mbedtls_ctr_drbg_context random_ctx; bool random_is_initialized; +#endif }; void sys_enqueue_emscripten_cast_message(GlobalContext *glb, const char *target, const char *message); diff --git a/src/platforms/emscripten/src/lib/sys.c b/src/platforms/emscripten/src/lib/sys.c index 1a234c9cee..b44ca0aea3 100644 --- a/src/platforms/emscripten/src/lib/sys.c +++ b/src/platforms/emscripten/src/lib/sys.c @@ -176,6 +176,14 @@ void sys_init_platform(GlobalContext *glb) AVM_ABORT(); } +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + psa_status_t status = psa_crypto_init(); + if (UNLIKELY(status != PSA_SUCCESS)) { + AVM_ABORT(); + } +#endif + +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #ifndef AVM_NO_SMP platform->entropy_mutex = smp_mutex_create(); if (IS_NULL_PTR(platform->entropy_mutex)) { @@ -188,6 +196,7 @@ void sys_init_platform(GlobalContext *glb) #endif platform->entropy_is_initialized = false; platform->random_is_initialized = false; +#endif glb->platform_data = platform; } @@ -197,12 +206,14 @@ void sys_free_platform(GlobalContext *glb) struct EmscriptenPlatformData *platform = glb->platform_data; pthread_cond_destroy(&platform->poll_cond); pthread_mutex_destroy(&platform->poll_mutex); +#if MBEDTLS_VERSION_NUMBER < 0x04000000 if (platform->random_is_initialized) { mbedtls_ctr_drbg_free(&platform->random_ctx); } if (platform->entropy_is_initialized) { mbedtls_entropy_free(&platform->entropy_ctx); } +#endif free(platform); } @@ -760,6 +771,8 @@ term sys_get_info(Context *ctx, term key) return UNDEFINED_ATOM; } +#ifdef ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER < 0x04000000 int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size) { #ifndef MBEDTLS_THREADING_C @@ -826,3 +839,6 @@ void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global) struct EmscriptenPlatformData *platform = global->platform_data; SMP_MUTEX_UNLOCK(platform->random_mutex); } +#endif + +#endif diff --git a/src/platforms/esp32/components/avm_builtins/CMakeLists.txt b/src/platforms/esp32/components/avm_builtins/CMakeLists.txt index aad06d9767..34cdd6fb39 100644 --- a/src/platforms/esp32/components/avm_builtins/CMakeLists.txt +++ b/src/platforms/esp32/components/avm_builtins/CMakeLists.txt @@ -39,7 +39,7 @@ set(AVM_BUILTIN_COMPONENT_SRCS ) if (IDF_VERSION_MAJOR GREATER_EQUAL 5) - set(ADDITIONAL_PRIV_REQUIRES "esp_hw_support" "efuse" "esp_adc") + set(ADDITIONAL_PRIV_REQUIRES "esp_hw_support" "efuse" "esp_adc" "esp_ringbuf") set(AVM_BUILTIN_COMPONENT_SRCS "adc_driver.c" ${AVM_BUILTIN_COMPONENT_SRCS}) else() set(ADDITIONAL_PRIV_REQUIRES "") @@ -74,6 +74,12 @@ if(CONFIG_AVM_ENABLE_USB_CDC_PORT_DRIVER) endif() endif() +if(CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED) + if(IDF_VERSION_MAJOR GREATER_EQUAL 6 OR (IDF_VERSION_MAJOR EQUAL 5 AND IDF_VERSION_MINOR GREATER_EQUAL 3)) + target_link_libraries(${COMPONENT_LIB} PRIVATE idf::esp_driver_usb_serial_jtag) + endif() +endif() + if (IDF_VERSION_MAJOR EQUAL 4) idf_build_set_property( LINK_OPTIONS "-Wl,--whole-archive ${CMAKE_CURRENT_BINARY_DIR}/lib${COMPONENT_NAME}.a -Wl,--no-whole-archive" diff --git a/src/platforms/esp32/components/avm_builtins/network_driver.c b/src/platforms/esp32/components/avm_builtins/network_driver.c index ad0f3e924b..100a8c5999 100644 --- a/src/platforms/esp32/components/avm_builtins/network_driver.c +++ b/src/platforms/esp32/components/avm_builtins/network_driver.c @@ -74,6 +74,14 @@ #define SSID_MAX_SIZE 33 #define BSSID_SIZE 6 +#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)) +#define AVM_IP_EVENT_AP_STAIPASSIGNED IP_EVENT_ASSIGNED_IP_TO_CLIENT +#define AVM_IP_EVENT_AP_STAIPASSIGNED_T ip_event_assigned_ip_to_client_t +#else +#define AVM_IP_EVENT_AP_STAIPASSIGNED IP_EVENT_AP_STAIPASSIGNED +#define AVM_IP_EVENT_AP_STAIPASSIGNED_T ip_event_ap_staipassigned_t +#endif + #define TAG "network_driver" #define PORT_REPLY_SIZE (TUPLE_SIZE(2) + REF_SIZE) @@ -215,7 +223,7 @@ static inline term authmode_to_atom_term(GlobalContext *global, wifi_auth_mode_t #endif #endif #endif -#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)) +#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) && ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0) ) case WIFI_AUTH_WPA3_EXT_PSK: authmode = globalcontext_existing_term_from_atom_string(global, ATOM_STR("\xC", "wpa3_ext_psk")); break; @@ -242,6 +250,8 @@ static inline term authmode_to_atom_term(GlobalContext *global, wifi_auth_mode_t case WIFI_AUTH_MAX: authmode = ERROR_ATOM; break; + default: + break; } return authmode; } @@ -836,8 +846,8 @@ static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_ break; } - case IP_EVENT_AP_STAIPASSIGNED: { - ip_event_ap_staipassigned_t *event = (ip_event_ap_staipassigned_t *) event_data; + case AVM_IP_EVENT_AP_STAIPASSIGNED: { + AVM_IP_EVENT_AP_STAIPASSIGNED_T *event = (AVM_IP_EVENT_AP_STAIPASSIGNED_T *) event_data; ESP_LOGI(TAG, "IP_EVENT_AP_STAIPASSIGNED: %s", inet_ntoa(event->ip)); send_ap_sta_ip_assigned(data, (esp_ip4_addr_t *) &event->ip); break; @@ -1278,7 +1288,7 @@ static void start_network(Context *ctx, term pid, term ref, term config) port_send_reply(ctx, pid, ref, error); goto cleanup; } - if ((err = esp_event_handler_register(IP_EVENT, IP_EVENT_AP_STAIPASSIGNED, &event_handler, data)) != ESP_OK) { + if ((err = esp_event_handler_register(IP_EVENT, AVM_IP_EVENT_AP_STAIPASSIGNED, &event_handler, data)) != ESP_OK) { ESP_LOGE(TAG, "Failed to register staipassigned event handler"); term error = port_create_error_tuple(ctx, term_from_int(err)); port_send_reply(ctx, pid, ref, error); @@ -1387,7 +1397,7 @@ static void stop_network(Context *ctx) // Stop unregister event callbacks so they dont trigger during shutdown. esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler); esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler); - esp_event_handler_unregister(IP_EVENT, IP_EVENT_AP_STAIPASSIGNED, &event_handler); + esp_event_handler_unregister(IP_EVENT, AVM_IP_EVENT_AP_STAIPASSIGNED, &event_handler); esp_event_handler_unregister(sntp_event_base, SNTP_EVENT_BASE_SYNC, &event_handler); esp_netif_t *sta_wifi_interface = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); @@ -1513,7 +1523,7 @@ static void sta_connect(Context *ctx, term pid, term ref, term config) // // Set up STA mode // - if ((err = esp_wifi_set_config(ESP_IF_WIFI_STA, sta_wifi_config)) != ESP_OK) { + if ((err = esp_wifi_set_config(WIFI_IF_STA, sta_wifi_config)) != ESP_OK) { ESP_LOGE(TAG, "Error setting STA mode config %d", err); free(sta_wifi_config); port_ensure_available(ctx, tuple_reply_size); diff --git a/src/platforms/esp32/components/avm_sys/CMakeLists.txt b/src/platforms/esp32/components/avm_sys/CMakeLists.txt index 7c3bae1e5c..5e07820107 100644 --- a/src/platforms/esp32/components/avm_sys/CMakeLists.txt +++ b/src/platforms/esp32/components/avm_sys/CMakeLists.txt @@ -117,7 +117,7 @@ if(HAVE_SOC_CPU_CORES_NUM) endif() check_c_source_compiles(" - #include + #include #ifndef MBEDTLS_PSA_CRYPTO_C #error PSA Crypto not available #endif diff --git a/src/platforms/esp32/components/avm_sys/include/esp32_sys.h b/src/platforms/esp32/components/avm_sys/include/esp32_sys.h index e38368d3db..becb45e1c9 100644 --- a/src/platforms/esp32/components/avm_sys/include/esp32_sys.h +++ b/src/platforms/esp32/components/avm_sys/include/esp32_sys.h @@ -30,8 +30,15 @@ #include #endif +// Include version.h to get MBEDTLS_VERSION_NUMBER (available in all versions) +#include +#if defined(MBEDTLS_PSA_CRYPTO_C) || MBEDTLS_VERSION_NUMBER >= 0x04000000 +#include +#endif +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #include #include +#endif #include #include @@ -72,13 +79,17 @@ struct ESP32PlatformData #ifndef AVM_NO_SMP Mutex *entropy_mutex; #endif +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_entropy_context entropy_ctx; +#endif bool entropy_is_initialized; #ifndef AVM_NO_SMP Mutex *random_mutex; #endif +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_ctr_drbg_context random_ctx; +#endif bool random_is_initialized; #ifdef CONFIG_AVM_ENABLE_STORAGE_NIFS diff --git a/src/platforms/esp32/components/avm_sys/platform_nifs.c b/src/platforms/esp32/components/avm_sys/platform_nifs.c index 1c4f410cd8..fb303da947 100644 --- a/src/platforms/esp32/components/avm_sys/platform_nifs.c +++ b/src/platforms/esp32/components/avm_sys/platform_nifs.c @@ -42,11 +42,17 @@ #include #include +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #include #include #include #include #include +#endif +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 +#include +#endif + #include #include @@ -492,6 +498,61 @@ static term nif_esp_sleep_get_wakeup_cause(Context *ctx, int argc, term argv[]) UNUSED(argc); UNUSED(argv); +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0) + uint32_t causes = esp_sleep_get_wakeup_causes(); + + if (causes == 0) { + return UNDEFINED_ATOM; + } +#if SOC_PM_SUPPORT_EXT_WAKEUP || SOC_PM_SUPPORT_EXT0_WAKEUP + if (causes & BIT(ESP_SLEEP_WAKEUP_EXT0)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_ext0_atom); + } +#endif +#if SOC_PM_SUPPORT_EXT_WAKEUP || SOC_PM_SUPPORT_EXT1_WAKEUP + if (causes & BIT(ESP_SLEEP_WAKEUP_EXT1)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_ext1_atom); + } +#endif + if (causes & BIT(ESP_SLEEP_WAKEUP_TIMER)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_timer_atom); + } + if (causes & BIT(ESP_SLEEP_WAKEUP_TOUCHPAD)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_touchpad_atom); + } +#if SOC_ULP_SUPPORTED + if (causes & BIT(ESP_SLEEP_WAKEUP_ULP)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_ulp_atom); + } +#endif + if (causes & BIT(ESP_SLEEP_WAKEUP_GPIO)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_gpio_atom); + } + if (causes & BIT(ESP_SLEEP_WAKEUP_UART)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_uart_atom); + } +#ifdef ESP_SLEEP_WAKEUP_WIFI + if (causes & BIT(ESP_SLEEP_WAKEUP_WIFI)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_wifi_atom); + } +#endif +#ifdef ESP_SLEEP_WAKEUP_COCPU + if (causes & BIT(ESP_SLEEP_WAKEUP_COCPU)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_cocpu_atom); + } +#endif +#ifdef ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG + if (causes & BIT(ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_cocpu_trap_trig_atom); + } +#endif +#ifdef ESP_SLEEP_WAKEUP_BT + if (causes & BIT(ESP_SLEEP_WAKEUP_BT)) { + return globalcontext_make_atom(ctx->global, sleep_wakeup_bt_atom); + } +#endif + return ERROR_ATOM; +#else esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); switch (cause) { @@ -536,6 +597,82 @@ static term nif_esp_sleep_get_wakeup_cause(Context *ctx, int argc, term argv[]) default: return ERROR_ATOM; } +#endif +} + +static term nif_esp_sleep_get_wakeup_causes(Context *ctx, int argc, term argv[]) +{ + UNUSED(argc); + UNUSED(argv); + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0) + uint32_t causes = esp_sleep_get_wakeup_causes(); +#else + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + if (cause == ESP_SLEEP_WAKEUP_UNDEFINED) { + return term_nil(); + } + uint32_t causes = BIT(cause); +#endif + + if (causes == 0) { + return term_nil(); + } + + if (UNLIKELY(memory_ensure_free(ctx, CONS_SIZE * 11) != MEMORY_GC_OK)) { + RAISE_ERROR(OUT_OF_MEMORY_ATOM); + } + + term causes_list = term_nil(); +#ifdef ESP_SLEEP_WAKEUP_BT + if (causes & BIT(ESP_SLEEP_WAKEUP_BT)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_bt_atom), causes_list, &ctx->heap); + } +#endif +#ifdef ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG + if (causes & BIT(ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_cocpu_trap_trig_atom), causes_list, &ctx->heap); + } +#endif +#ifdef ESP_SLEEP_WAKEUP_COCPU + if (causes & BIT(ESP_SLEEP_WAKEUP_COCPU)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_cocpu_atom), causes_list, &ctx->heap); + } +#endif +#ifdef ESP_SLEEP_WAKEUP_WIFI + if (causes & BIT(ESP_SLEEP_WAKEUP_WIFI)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_wifi_atom), causes_list, &ctx->heap); + } +#endif + if (causes & BIT(ESP_SLEEP_WAKEUP_UART)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_uart_atom), causes_list, &ctx->heap); + } + if (causes & BIT(ESP_SLEEP_WAKEUP_GPIO)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_gpio_atom), causes_list, &ctx->heap); + } +#if SOC_ULP_SUPPORTED + if (causes & BIT(ESP_SLEEP_WAKEUP_ULP)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_ulp_atom), causes_list, &ctx->heap); + } +#endif + if (causes & BIT(ESP_SLEEP_WAKEUP_TOUCHPAD)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_touchpad_atom), causes_list, &ctx->heap); + } + if (causes & BIT(ESP_SLEEP_WAKEUP_TIMER)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_timer_atom), causes_list, &ctx->heap); + } +#if SOC_PM_SUPPORT_EXT_WAKEUP || SOC_PM_SUPPORT_EXT1_WAKEUP + if (causes & BIT(ESP_SLEEP_WAKEUP_EXT1)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_ext1_atom), causes_list, &ctx->heap); + } +#endif +#if SOC_PM_SUPPORT_EXT_WAKEUP || SOC_PM_SUPPORT_EXT0_WAKEUP + if (causes & BIT(ESP_SLEEP_WAKEUP_EXT0)) { + causes_list = term_list_prepend(globalcontext_make_atom(ctx->global, sleep_wakeup_ext0_atom), causes_list, &ctx->heap); + } +#endif + + return causes_list; } #if SOC_PM_SUPPORT_EXT_WAKEUP || SOC_PM_SUPPORT_EXT0_WAKEUP @@ -622,8 +759,13 @@ static term nif_esp_deep_sleep_enable_gpio_wakeup(Context *ctx, int argc, term a VALIDATE_VALUE(argv[0], term_is_any_integer); VALIDATE_VALUE(argv[1], term_is_integer); avm_int64_t mask = term_maybe_unbox_int64(argv[0]); +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0) + esp_sleep_gpio_wake_up_mode_t mode = term_to_int(argv[1]); + esp_err_t err = esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(mask, mode); +#else esp_deepsleep_gpio_wake_up_mode_t mode = term_to_int(argv[1]); esp_err_t err = esp_deep_sleep_enable_gpio_wakeup(mask, mode); +#endif if (UNLIKELY(err == ESP_ERR_INVALID_ARG)) { RAISE_ERROR(BADARG_ATOM); } @@ -1023,6 +1165,11 @@ static const struct Nif esp_sleep_get_wakeup_cause_nif = .base.type = NIFFunctionType, .nif_ptr = nif_esp_sleep_get_wakeup_cause }; +static const struct Nif esp_sleep_get_wakeup_causes_nif = +{ + .base.type = NIFFunctionType, + .nif_ptr = nif_esp_sleep_get_wakeup_causes +}; #if SOC_PM_SUPPORT_EXT_WAKEUP || SOC_PM_SUPPORT_EXT0_WAKEUP static const struct Nif esp_sleep_enable_ext0_wakeup_nif = { @@ -1189,6 +1336,10 @@ const struct Nif *platform_nifs_get_nif(const char *nifname) TRACE("Resolved platform nif %s ...\n", nifname); return &esp_sleep_get_wakeup_cause_nif; } + if (strcmp("esp:sleep_get_wakeup_causes/0", nifname) == 0) { + TRACE("Resolved platform nif %s ...\n", nifname); + return &esp_sleep_get_wakeup_causes_nif; + } #if SOC_PM_SUPPORT_EXT_WAKEUP || SOC_PM_SUPPORT_EXT0_WAKEUP if (strcmp("esp:sleep_enable_ext0_wakeup/2", nifname) == 0) { TRACE("Resolved platform nif %s ...\n", nifname); diff --git a/src/platforms/esp32/components/avm_sys/sys.c b/src/platforms/esp32/components/avm_sys/sys.c index 42786b6c8e..430cec9cb9 100644 --- a/src/platforms/esp32/components/avm_sys/sys.c +++ b/src/platforms/esp32/components/avm_sys/sys.c @@ -29,6 +29,8 @@ #include "otp_socket.h" #include "scheduler.h" #include "utils.h" +#include +#include // #define ENABLE_TRACE #include "trace.h" @@ -58,11 +60,7 @@ #include "soc/soc_caps.h" #endif -#if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000) -#include -#else -#include -#endif +#include // Platform uses listeners #include "listeners.h" @@ -286,6 +284,13 @@ void sys_init_platform(GlobalContext *glb) platform->entropy_is_initialized = false; platform->random_is_initialized = false; +#if defined(MBEDTLS_PSA_CRYPTO_C) || MBEDTLS_VERSION_NUMBER >= 0x04000000 + psa_status_t status = psa_crypto_init(); + if (UNLIKELY(status != PSA_SUCCESS)) { + AVM_ABORT(); + } +#endif + ErlNifResourceFlags flags; ErlNifEnv env; erl_nif_env_partial_init_from_globalcontext(&env, glb); @@ -311,7 +316,7 @@ void sys_free_platform(GlobalContext *glb) AVM_ABORT(); } } - +#if MBEDTLS_VERSION_NUMBER < 0x04000000 if (platform->random_is_initialized) { mbedtls_ctr_drbg_free(&platform->random_ctx); } @@ -319,6 +324,7 @@ void sys_free_platform(GlobalContext *glb) if (platform->entropy_is_initialized) { mbedtls_entropy_free(&platform->entropy_ctx); } +#endif #ifndef AVM_NO_SMP smp_mutex_destroy(platform->entropy_mutex); @@ -361,7 +367,7 @@ const void *esp32_sys_mmap_partition(const char *partition_name, spi_flash_mmap_ ESP_LOGE(TAG, "Failed to map BEAM partition for %s", partition_name); return NULL; } - ESP_LOGI(TAG, "Loaded BEAM partition %s at address 0x%"PRIx32" (size=%"PRIu32" bytes)", + ESP_LOGI(TAG, "Loaded BEAM partition %s at address 0x%" PRIx32 " (size=%" PRIu32 " bytes)", partition_name, partition->address, partition->size); #ifndef CONFIG_IDF_TARGET_ARCH_RISCV @@ -827,6 +833,7 @@ term esp_err_to_term(GlobalContext *glb, esp_err_t status) } } +#if MBEDTLS_VERSION_NUMBER < 0x04000000 int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size) { #if !defined(MBEDTLS_THREADING_C) && !defined(AVM_NO_SMP) @@ -912,6 +919,7 @@ void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global) UNUSED(global); #endif } +#endif #ifndef AVM_NO_JIT #include diff --git a/src/platforms/esp32/test/main/idf_component.yml b/src/platforms/esp32/test/main/idf_component.yml index b52c73ee5f..3fa6a53fdf 100644 --- a/src/platforms/esp32/test/main/idf_component.yml +++ b/src/platforms/esp32/test/main/idf_component.yml @@ -1,7 +1,7 @@ dependencies: "espressif/dp83848": - version: "~1.0.0" - rules: - - if: "idf_version >=6.0" - - if: target in ["esp32", "esp32p4"] - - if: "$CONFIG{ETH_USE_OPENETH} == True" + version: "~1.0.0" + rules: + - if: "idf_version >=6.0" + - if: target in ["esp32", "esp32p4", "esp32c3"] + - if: "$CONFIG{ETH_USE_OPENETH} == True" diff --git a/src/platforms/generic_unix/lib/CMakeLists.txt b/src/platforms/generic_unix/lib/CMakeLists.txt index 4ec0e9e527..e28de8de12 100644 --- a/src/platforms/generic_unix/lib/CMakeLists.txt +++ b/src/platforms/generic_unix/lib/CMakeLists.txt @@ -87,7 +87,7 @@ if (MbedTLS_FOUND) set(CMAKE_REQUIRED_INCLUDES "${MBEDTLS_ROOT_DIR}/include") endif() include(CheckCSourceCompiles) - set(CMAKE_REQUIRED_LIBRARIES MbedTLS::mbedcrypto) + set(CMAKE_REQUIRED_LIBRARIES MbedTLS::mbedtls) check_c_source_compiles(" #include #ifndef MBEDTLS_PSA_CRYPTO_C diff --git a/src/platforms/generic_unix/lib/sys.c b/src/platforms/generic_unix/lib/sys.c index ce6a032fc9..780aac3871 100644 --- a/src/platforms/generic_unix/lib/sys.c +++ b/src/platforms/generic_unix/lib/sys.c @@ -32,13 +32,10 @@ #include "utils.h" #if ATOMVM_HAS_MBEDTLS +#include +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #include #include - -#if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000) -#include -#else -#include #endif #include "otp_ssl.h" @@ -114,6 +111,7 @@ struct GenericUnixPlatformData #endif #ifdef ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #ifndef AVM_NO_SMP Mutex *entropy_mutex; #endif @@ -126,6 +124,7 @@ struct GenericUnixPlatformData mbedtls_ctr_drbg_context random_ctx; bool random_is_initialized; #endif +#endif }; static void mapped_file_avm_pack_destructor(struct AVMPackData *obj, GlobalContext *global); @@ -579,6 +578,12 @@ void sys_init_platform(GlobalContext *global) otp_net_init(global); otp_socket_init(global); #if ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + psa_status_t status = psa_crypto_init(); + if (UNLIKELY(status != PSA_SUCCESS)) { + AVM_ABORT(); + } +#else #ifndef AVM_NO_SMP platform->entropy_mutex = smp_mutex_create(); if (IS_NULL_PTR(platform->entropy_mutex)) { @@ -591,6 +596,7 @@ void sys_init_platform(GlobalContext *global) #endif platform->entropy_is_initialized = false; platform->random_is_initialized = false; +#endif otp_ssl_init(global); #endif #ifndef AVM_NO_JIT @@ -624,11 +630,14 @@ void sys_free_platform(GlobalContext *global) #endif #if !defined(AVM_NO_SMP) && ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER < 0x04000000 smp_mutex_destroy(platform->entropy_mutex); smp_mutex_destroy(platform->random_mutex); #endif +#endif #if ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER < 0x04000000 if (platform->random_is_initialized) { mbedtls_ctr_drbg_free(&platform->random_ctx); } @@ -636,6 +645,7 @@ void sys_free_platform(GlobalContext *global) if (platform->entropy_is_initialized) { mbedtls_entropy_free(&platform->entropy_ctx); } +#endif #endif free(platform); @@ -745,6 +755,7 @@ bool event_listener_is_event(EventListener *listener, listener_event_t event) } #ifdef ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER < 0x04000000 int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size) { #ifndef MBEDTLS_THREADING_C @@ -811,6 +822,7 @@ void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global) struct GenericUnixPlatformData *platform = global->platform_data; SMP_MUTEX_UNLOCK(platform->random_mutex); } +#endif #endif diff --git a/src/platforms/rp2/src/lib/rp2_sys.h b/src/platforms/rp2/src/lib/rp2_sys.h index 77b2918c88..f3042bed22 100644 --- a/src/platforms/rp2/src/lib/rp2_sys.h +++ b/src/platforms/rp2/src/lib/rp2_sys.h @@ -30,8 +30,11 @@ #include #include +#include +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #include #include +#endif #pragma GCC diagnostic pop @@ -86,6 +89,7 @@ struct RP2PlatformData mutex_t tinyusb_mutex; #endif +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #ifndef AVM_NO_SMP Mutex *entropy_mutex; #endif @@ -97,6 +101,7 @@ struct RP2PlatformData #endif mbedtls_ctr_drbg_context random_ctx; bool random_is_initialized; +#endif }; #ifdef AVM_USB_CDC_PORT_DRIVER_ENABLED diff --git a/src/platforms/rp2/src/lib/sys.c b/src/platforms/rp2/src/lib/sys.c index 0894d0bf1d..7d26f81b8e 100644 --- a/src/platforms/rp2/src/lib/sys.c +++ b/src/platforms/rp2/src/lib/sys.c @@ -47,10 +47,9 @@ #include #endif -#if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000) -#include -#else -#include +#include +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 +#include #endif // libAtomVM @@ -100,6 +99,14 @@ void sys_init_platform(GlobalContext *glb) otp_socket_init(glb); #endif +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + psa_status_t status = psa_crypto_init(); + if (UNLIKELY(status != PSA_SUCCESS)) { + AVM_ABORT(); + } +#endif + +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #ifndef AVM_NO_SMP platform->entropy_mutex = smp_mutex_create(); if (IS_NULL_PTR(platform->entropy_mutex)) { @@ -113,6 +120,7 @@ void sys_init_platform(GlobalContext *glb) platform->entropy_is_initialized = false; platform->random_is_initialized = false; +#endif } void sys_free_platform(GlobalContext *glb) @@ -124,6 +132,7 @@ void sys_free_platform(GlobalContext *glb) struct RP2PlatformData *platform = glb->platform_data; queue_free(&platform->event_queue); +#if MBEDTLS_VERSION_NUMBER < 0x04000000 if (platform->random_is_initialized) { mbedtls_ctr_drbg_free(&platform->random_ctx); } @@ -135,6 +144,7 @@ void sys_free_platform(GlobalContext *glb) #ifndef AVM_NO_SMP smp_mutex_destroy(platform->entropy_mutex); smp_mutex_destroy(platform->random_mutex); +#endif #endif free(platform); @@ -445,6 +455,7 @@ void sys_tinyusb_unlock(GlobalContext *global) // TODO: enable mbedtls threading support by defining MBEDTLS_THREADING_ALT // and remove this function. +#if MBEDTLS_VERSION_NUMBER < 0x04000000 int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size) { #ifndef MBEDTLS_THREADING_C @@ -511,6 +522,7 @@ void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global) struct RP2PlatformData *platform = global->platform_data; SMP_MUTEX_UNLOCK(platform->random_mutex); } +#endif #ifndef AVM_NO_JIT ModuleNativeEntryPoint sys_map_native_code(const uint8_t *code, size_t code_size) diff --git a/src/platforms/stm32/src/lib/mbedtls_stm32_user_config.h b/src/platforms/stm32/src/lib/mbedtls_stm32_user_config.h index 22842ff201..0617f677bc 100644 --- a/src/platforms/stm32/src/lib/mbedtls_stm32_user_config.h +++ b/src/platforms/stm32/src/lib/mbedtls_stm32_user_config.h @@ -21,18 +21,21 @@ #ifndef MBEDTLS_STM32_USER_CONFIG_H #define MBEDTLS_STM32_USER_CONFIG_H -#define MBEDTLS_NO_PLATFORM_ENTROPY #define MBEDTLS_PLATFORM_MS_TIME_ALT #undef MBEDTLS_HAVE_TIME_DATE #undef MBEDTLS_TIMING_C +#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x04000000 +#define MBEDTLS_NO_PLATFORM_ENTROPY + #undef MBEDTLS_PSA_CRYPTO_C #undef MBEDTLS_PSA_CRYPTO_STORAGE_C #undef MBEDTLS_PSA_ITS_FILE_C #undef MBEDTLS_PSA_CRYPTO_CLIENT #undef MBEDTLS_PSA_INJECT_ENTROPY #undef MBEDTLS_LMS_C +#endif #undef MBEDTLS_FS_IO diff --git a/src/platforms/stm32/src/lib/stm_sys.h b/src/platforms/stm32/src/lib/stm_sys.h index 0b297d0f21..f0013348bb 100644 --- a/src/platforms/stm32/src/lib/stm_sys.h +++ b/src/platforms/stm32/src/lib/stm_sys.h @@ -27,9 +27,12 @@ #include "stm32_hal_platform.h" #ifdef ATOMVM_HAS_MBEDTLS +#include +#if MBEDTLS_VERSION_NUMBER < 0x04000000 #include #include #endif +#endif #define STM32_ATOM globalcontext_make_atom(ctx->global, ATOM_STR("\x5", "stm32")) @@ -53,11 +56,13 @@ struct STM32PlatformData struct ListHead locked_pins; #ifdef ATOMVM_HAS_MBEDTLS RNG_HandleTypeDef rng; +#if MBEDTLS_VERSION_NUMBER < 0x04000000 mbedtls_entropy_context entropy_ctx; mbedtls_ctr_drbg_context random_ctx; bool entropy_is_initialized; bool random_is_initialized; #endif +#endif }; void sys_init_icache(void); diff --git a/src/platforms/stm32/src/lib/sys.c b/src/platforms/stm32/src/lib/sys.c index 5f60c6eeb0..9e30ebde32 100644 --- a/src/platforms/stm32/src/lib/sys.c +++ b/src/platforms/stm32/src/lib/sys.c @@ -32,11 +32,13 @@ #include #include +#if MBEDTLS_VERSION_NUMBER < 0x04000000 /* Minimum bytes the entropy pool collects from a hardware source before * it's considered seeded. mbedTLS defines this as MBEDTLS_ENTROPY_MIN_HARDWARE * in the private library/entropy_poll.h header; use the same value. */ #define STM32_ENTROPY_MIN_HARDWARE 32 #endif +#endif // #define ENABLE_TRACE #include @@ -223,11 +225,21 @@ void sys_init_platform(GlobalContext *glb) AVM_LOGE(TAG, "Out of memory!"); AVM_ABORT(); } +#ifdef ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + psa_status_t status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + AVM_ABORT(); + } +#endif +#endif glb->platform_data = platform; list_init(&platform->locked_pins); #ifdef ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER < 0x04000000 platform->entropy_is_initialized = false; platform->random_is_initialized = false; +#endif if (stm32_rng_hw_init(platform) != 0) { AVM_LOGE(TAG, "Failed to initialize RNG peripheral"); AVM_ABORT(); @@ -239,12 +251,14 @@ void sys_free_platform(GlobalContext *glb) { struct STM32PlatformData *platform = glb->platform_data; #ifdef ATOMVM_HAS_MBEDTLS +#if MBEDTLS_VERSION_NUMBER < 0x04000000 if (platform->random_is_initialized) { mbedtls_ctr_drbg_free(&platform->random_ctx); } if (platform->entropy_is_initialized) { mbedtls_entropy_free(&platform->entropy_ctx); } +#endif // HAL_RNG_Init succeeded in stm32_rng_hw_init or we aborted HAL_RNG_DeInit(&platform->rng); #endif @@ -475,6 +489,7 @@ static int stm32_rng_hw_init(struct STM32PlatformData *platform) return 0; } +#if MBEDTLS_VERSION_NUMBER < 0x04000000 int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) { GlobalContext *global = data; @@ -500,12 +515,14 @@ int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen = written; return 0; } +#endif mbedtls_ms_time_t mbedtls_ms_time(void) { return (mbedtls_ms_time_t) HAL_GetTick(); } +#if MBEDTLS_VERSION_NUMBER < 0x04000000 int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size) { return mbedtls_entropy_func(entropy, buf, size); @@ -561,4 +578,5 @@ void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global) UNUSED(global); } +#endif #endif /* ATOMVM_HAS_MBEDTLS */