From 0427c1f74b86e566fb6f4eb90e6faf07c8c34976 Mon Sep 17 00:00:00 2001 From: Peter M Date: Fri, 30 Jan 2026 13:18:46 +0100 Subject: [PATCH 01/23] otp_crypto: add mbedtls 4 support Port otp_crypto to the PSA Crypto API used by mbedtls 4.x. - Replace deprecated low-level mbedtls APIs with PSA equivalents for hash, HMAC, cipher, and AEAD operations - Guard legacy mbedtls 2/3 code paths with version checks - Update CMake to detect mbedtls 4 and set HAVE_PSA_CRYPTO - Keep ESP32 JIT config outside mbedtls version guards Signed-off-by: Peter M --- .github/workflows/build-and-test-macos.yaml | 2 +- .github/workflows/build-libraries.yaml | 24 +- src/libAtomVM/otp_crypto.c | 356 +++++++++++++++++- src/libAtomVM/otp_ssl.c | 40 +- src/libAtomVM/sys_mbedtls.h | 11 + .../emscripten/src/lib/emscripten_sys.h | 13 +- src/platforms/emscripten/src/lib/sys.c | 11 + .../components/avm_sys/include/esp32_sys.h | 11 + .../esp32/components/avm_sys/platform_nifs.c | 6 + src/platforms/esp32/components/avm_sys/sys.c | 22 +- src/platforms/generic_unix/lib/CMakeLists.txt | 2 +- src/platforms/generic_unix/lib/sys.c | 22 +- src/platforms/rp2/src/lib/rp2_sys.h | 5 + src/platforms/rp2/src/lib/sys.c | 20 +- src/platforms/stm32/src/lib/sys.c | 11 + 15 files changed, 519 insertions(+), 37 deletions(-) diff --git a/.github/workflows/build-and-test-macos.yaml b/.github/workflows/build-and-test-macos.yaml index 6738be264a..b46976ecc7 100644 --- a/.github/workflows/build-and-test-macos.yaml +++ b/.github/workflows/build-and-test-macos.yaml @@ -40,7 +40,7 @@ jobs: matrix: os: ["macos-14", "macos-15", "macos-15-intel", "macos-26"] otp: ["26", "27", "28"] - mbedtls: ["mbedtls@3"] + mbedtls: ["mbedtls@3", "mbedtls@4"] cmake_opts_other: [""] include: diff --git a/.github/workflows/build-libraries.yaml b/.github/workflows/build-libraries.yaml index b18158c7fa..d649106257 100644 --- a/.github/workflows/build-libraries.yaml +++ b/.github/workflows/build-libraries.yaml @@ -19,6 +19,8 @@ jobs: runs-on: "ubuntu-24.04" strategy: fail-fast: false + matrix: + mbedtls: ["default", "mbedtls@4"] steps: - name: "Checkout repo" @@ -42,10 +44,26 @@ jobs: - name: "Install deps" run: | - sudo apt install -y build-essential cmake gperf zlib1g-dev libmbedtls-dev + sudo apt install -y build-essential cmake gperf zlib1g-dev + if [[ "${{ matrix.mbedtls }}" == "default" ]]; then + sudo apt install -y libmbedtls-dev + fi # Get a more recent valgrind sudo snap install valgrind --classic + - name: "Install specific MbedTLS version" + if: matrix.mbedtls == 'mbedtls@4' + run: | + git clone --depth 1 --branch mbedtls-4.0.0 --recurse-submodules https://github.com/Mbed-TLS/mbedtls + cd mbedtls + mkdir build + cd build + cmake -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=On -DCMAKE_INSTALL_PREFIX=/usr/local .. + make -j$(nproc) + sudo make install + sudo ldconfig + echo "MBEDTLS_ROOT_DIR=/usr/local" >> $GITHUB_ENV + # Builder info - name: "System info" run: | @@ -70,7 +88,7 @@ jobs: - name: "Build: run cmake" working-directory: build run: | - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. + cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ${MBEDTLS_ROOT_DIR:+-DMBEDTLS_ROOT_DIR=$MBEDTLS_ROOT_DIR} .. - name: "Build: run make" working-directory: build @@ -130,7 +148,7 @@ jobs: - name: Release uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') && matrix.mbedtls == 'default' with: draft: true fail_on_unmatched_files: true diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index 224c93a432..debe72f0e3 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,6 +42,7 @@ #include #include #include +#endif #if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000) #include #else @@ -51,6 +54,8 @@ #ifdef HAVE_PSA_CRYPTO #include +#endif +#if defined(HAVE_PSA_CRYPTO) || defined(MBEDTLS_PSA_CRYPTO_C) || MBEDTLS_VERSION_NUMBER >= 0x04000000 #include #endif @@ -69,7 +74,6 @@ #include #define AVM_HAVE_MBEDTLS_CT_MEMCMP 1 #endif - // #define ENABLE_TRACE #include "trace.h" @@ -101,6 +105,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 +115,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 +231,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 +277,52 @@ DEFINE_HASH_FOLD_NORET(sha512, ) DEFINE_DO_HASH_NORET_IS_OTHER(sha512, , true) DEFINE_DO_HASH_NORET_IS_OTHER(sha512, , false) +#endif +#endif + +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 +static psa_algorithm_t atom_to_psa_hash_alg(term type, GlobalContext *global) +{ + if (type == globalcontext_make_atom(global, ATOM_STR("\x3", "md5"))) { + return PSA_ALG_MD5; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\x3", "sha"))) { + return PSA_ALG_SHA_1; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha224"))) { + return PSA_ALG_SHA_224; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha256"))) { + return PSA_ALG_SHA_256; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha384"))) { + return PSA_ALG_SHA_384; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha512"))) { + return PSA_ALG_SHA_512; + } + return PSA_ALG_NONE; +} + +static InteropFunctionResult psa_hash_fold_fun(term t, void *accum) +{ + psa_hash_operation_t *operation = (psa_hash_operation_t *) 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, (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 +335,33 @@ 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 + psa_algorithm_t alg = atom_to_psa_hash_alg(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 +409,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 +417,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 +439,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) { @@ -407,6 +490,72 @@ static term handle_iodata(term iodata, const void **data, size_t *len, void **al } } +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 +static psa_algorithm_t atom_to_psa_cipher_alg(term type, GlobalContext *global, psa_key_type_t *key_type, size_t *key_bits) +{ + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_128_ecb"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 128; + return PSA_ALG_ECB_NO_PADDING; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_192_ecb"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 192; + return PSA_ALG_ECB_NO_PADDING; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_256_ecb"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 256; + return PSA_ALG_ECB_NO_PADDING; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_128_cbc"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 128; + return PSA_ALG_CBC_NO_PADDING; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_192_cbc"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 192; + return PSA_ALG_CBC_NO_PADDING; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_256_cbc"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 256; + return PSA_ALG_CBC_NO_PADDING; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xE", "aes_128_cfb128"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 128; + return PSA_ALG_CFB; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xE", "aes_192_cfb128"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 192; + return PSA_ALG_CFB; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xE", "aes_256_cfb128"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 256; + return PSA_ALG_CFB; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_128_ctr"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 128; + return PSA_ALG_CTR; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_192_ctr"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 192; + return PSA_ALG_CTR; + } + if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_256_ctr"))) { + *key_type = PSA_KEY_TYPE_AES; + *key_bits = 256; + return PSA_ALG_CTR; + } + return PSA_ALG_NONE; +} +#else static bool bool_to_mbedtls_operation(term encrypt_flag, mbedtls_operation_t *operation) { switch (encrypt_flag) { @@ -420,6 +569,7 @@ static bool bool_to_mbedtls_operation(term encrypt_flag, mbedtls_operation_t *op return false; } } +#endif static term make_crypto_error_tag( const char *file, int line, const char *message, term tag, Context *ctx) @@ -470,11 +620,21 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) } term cipher_term = argv[0]; + +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + psa_key_type_t key_type; + size_t key_bits; + psa_algorithm_t alg = atom_to_psa_cipher_alg(cipher_term, ctx->global, &key_type, &key_bits); + if (UNLIKELY(alg == PSA_ALG_NONE)) { + RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unknown cipher", ctx)); + } +#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 +668,169 @@ 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; + 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); + 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; + } + + size_t 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); + 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); + free(temp_buf); + secure_free(allocated_key_data, key_len); + secure_free(allocated_iv_data, iv_len); + free(allocated_data_data); + // 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); + free(allocated_data_data); + + int ensure_size = term_binary_heap_size(output_len); + if (UNLIKELY(memory_ensure_free(ctx, ensure_size) != MEMORY_GC_OK)) { + free(temp_buf); + RAISE_ERROR(OUT_OF_MEMORY_ATOM); + } + + term out = term_from_literal_binary(temp_buf, output_len, &ctx->heap, ctx->global); + free(temp_buf); + return out; + +psa_error: + psa_cipher_abort(&operation); + if (key_id != 0) { + psa_destroy_key(key_id); + } + free(temp_buf); + goto raise_error; +#else mbedtls_operation_t operation; mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_NONE; bool padding_has_been_set = false; @@ -625,6 +948,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); + free(allocated_data_data); + RAISE_ERROR(error_atom); +#endif } #ifdef HAVE_PSA_CRYPTO @@ -1369,7 +1701,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; @@ -3113,12 +3449,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; @@ -3231,6 +3561,17 @@ term nif_crypto_strong_rand_bytes(Context *ctx, int argc, term argv[]) RAISE_ERROR(OUT_OF_MEMORY_ATOM); } +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + 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 +3587,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) diff --git a/src/libAtomVM/otp_ssl.c b/src/libAtomVM/otp_ssl.c index b74d2cb8af..56124bf549 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,15 @@ 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 + 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/emscripten_sys.h b/src/platforms/emscripten/src/lib/emscripten_sys.h index 1889b2ab97..f2978e4da2 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 +#include "sys_mbedtls.h" + +#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..2a3a84b205 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); } 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..a11dcfb020 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 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/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/sys.c b/src/platforms/stm32/src/lib/sys.c index 5f60c6eeb0..3babd74f3f 100644 --- a/src/platforms/stm32/src/lib/sys.c +++ b/src/platforms/stm32/src/lib/sys.c @@ -27,6 +27,9 @@ #include #include #include +#if ATOMVM_HAS_MBEDTLS +#include +#endif #ifdef ATOMVM_HAS_MBEDTLS #include @@ -223,6 +226,14 @@ void sys_init_platform(GlobalContext *glb) AVM_LOGE(TAG, "Out of memory!"); AVM_ABORT(); } +#if 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 From 3d724409419a9c83de9fd256d85bc2fe75f51ae7 Mon Sep 17 00:00:00 2001 From: Peter M Date: Tue, 17 Mar 2026 05:10:17 +0100 Subject: [PATCH 02/23] otp_crypto: use PSA PBKDF2 on mbedtls 4 Avoid including mbedtls/pkcs5.h when building against mbedtls 4, where that header is not available. Keep the existing PKCS5-based pbkdf2_hmac implementation for mbedtls 2/3, but switch the mbedtls 4 path to the PSA key derivation API so crypto:pbkdf2_hmac/5 remains available. Also reject zero iterations in PBKDF2 with a clear error message, and update the feature/NIF guards so pbkdf2_hmac stays registered on both legacy and mbedtls 4 builds. Signed-off-by: Peter M --- src/libAtomVM/otp_crypto.c | 84 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 4 deletions(-) diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index debe72f0e3..f37e455eb7 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -59,7 +59,7 @@ #include #endif -#ifdef MBEDTLS_PKCS5_C +#if MBEDTLS_VERSION_NUMBER < 0x04000000 && defined(MBEDTLS_PKCS5_C) #include #include #endif @@ -68,6 +68,10 @@ #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 @@ -301,6 +305,11 @@ static psa_algorithm_t atom_to_psa_hash_alg(term type, GlobalContext *global) if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha512"))) { return PSA_ALG_SHA_512; } +#ifdef PSA_ALG_RIPEMD160 + if (type == globalcontext_make_atom(global, ATOM_STR("\x9", "ripemd160"))) { + return PSA_ALG_RIPEMD160; + } +#endif return PSA_ALG_NONE; } @@ -3427,7 +3436,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 }, @@ -3439,6 +3449,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[]) { @@ -3459,6 +3470,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 = atom_to_psa_hash_alg(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 @@ -3484,6 +3508,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))) { @@ -3498,6 +3527,52 @@ static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) goto cleanup; } +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + psa_status_t status = psa_crypto_init(); + if (UNLIKELY(status != PSA_SUCCESS)) { + result = make_crypto_error(__FILE__, __LINE__, "PSA init failed", ctx); + goto cleanup; + } + + 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( @@ -3522,6 +3597,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; @@ -3762,7 +3838,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 @@ -3875,7 +3951,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; From 37caa0c62e9df0f42632087d69a39e4dda9d1b01 Mon Sep 17 00:00:00 2001 From: Peter M Date: Sat, 21 Mar 2026 14:57:44 +0100 Subject: [PATCH 03/23] otp_crypto: harden PSA crypto lifecycle and memory Improve PSA crypto resource management and memory safety: - Normalize do_psa_init() across all PSA-backed NIFs so every entry point initializes PSA consistently - Destroy PSA key handles immediately after finalization instead of deferring to GC, reducing key material residency time - Abort PSA operations and destroy keys on update failure to avoid dangling handles - Replace free() with secure_free() for all scratch buffers that may contain sensitive data (plaintext, key material) Signed-off-by: Peter M --- src/libAtomVM/otp_crypto.c | 81 ++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index f37e455eb7..a215e47937 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -98,6 +98,15 @@ #define MAX_MD_SIZE 64 +#if defined(HAVE_PSA_CRYPTO) || defined(MBEDTLS_PSA_CRYPTO_C) || MBEDTLS_VERSION_NUMBER >= 0x04000000 +static void do_psa_init(void) +{ + if (UNLIKELY(psa_crypto_init() != PSA_SUCCESS)) { + abort(); + } +} +#endif + enum crypto_algorithm { CryptoInvalidAlgorithm = 0, @@ -345,6 +354,7 @@ static term nif_crypto_hash(Context *ctx, int argc, term argv[]) size_t digest_len = 0; #if MBEDTLS_VERSION_NUMBER >= 0x04000000 + do_psa_init(); psa_algorithm_t alg = atom_to_psa_hash_alg(type, ctx->global); if (alg == PSA_ALG_NONE) { TRACE("crypto:hash unknown algorithm\n"); @@ -631,6 +641,7 @@ 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(); psa_key_type_t key_type; size_t key_bits; psa_algorithm_t alg = atom_to_psa_cipher_alg(cipher_term, ctx->global, &key_type, &key_bits); @@ -785,10 +796,10 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) // No complete blocks to process psa_cipher_abort(&operation); psa_destroy_key(key_id); - free(temp_buf); + secure_free(temp_buf, output_size); secure_free(allocated_key_data, key_len); secure_free(allocated_iv_data, iv_len); - free(allocated_data_data); + 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); @@ -820,16 +831,16 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) secure_free(allocated_key_data, key_len); secure_free(allocated_iv_data, iv_len); - free(allocated_data_data); + 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)) { - free(temp_buf); + 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); - free(temp_buf); + secure_free(temp_buf, output_size); return out; psa_error: @@ -837,7 +848,7 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) if (key_id != 0) { psa_destroy_key(key_id); } - free(temp_buf); + secure_free(temp_buf, output_size); goto raise_error; #else mbedtls_operation_t operation; @@ -963,7 +974,7 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) raise_error: secure_free(allocated_key_data, key_len); secure_free(allocated_iv_data, iv_len); - free(allocated_data_data); + secure_free(allocated_data_data, data_size); RAISE_ERROR(error_atom); #endif } @@ -1053,13 +1064,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. @@ -2153,7 +2157,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); @@ -2321,11 +2328,16 @@ static term nif_crypto_mac_update(Context *ctx, int argc, term argv[]) 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; + 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]; } @@ -2362,6 +2374,8 @@ 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; SMP_MUTEX_UNLOCK(mac_state->mutex); if (UNLIKELY(status != PSA_SUCCESS)) { result = make_crypto_error(__FILE__, __LINE__, "Unexpected error", ctx); @@ -2421,6 +2435,8 @@ 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; SMP_MUTEX_UNLOCK(mac_state->mutex); if (UNLIKELY(status != PSA_SUCCESS)) { result = make_crypto_error(__FILE__, __LINE__, "Unexpected error", ctx); @@ -2649,7 +2665,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); @@ -2989,11 +3008,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; @@ -3004,8 +3028,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); @@ -3059,6 +3083,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) { @@ -3105,7 +3131,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); @@ -3382,7 +3408,7 @@ static term nif_crypto_crypto_one_time_aead(Context *ctx, int argc, term argv[]) cleanup: psa_destroy_key(key_id); - free(maybe_allocated_intext); + secure_free(maybe_allocated_intext, intext_len); free(maybe_allocated_aad); secure_free(out_buf, out_buf_size); @@ -3528,14 +3554,10 @@ static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) } #if MBEDTLS_VERSION_NUMBER >= 0x04000000 + do_psa_init(); psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; - psa_status_t status = psa_crypto_init(); - if (UNLIKELY(status != PSA_SUCCESS)) { - result = make_crypto_error(__FILE__, __LINE__, "PSA init failed", ctx); - goto cleanup; - } - status = psa_key_derivation_setup(&operation, PSA_ALG_PBKDF2_HMAC(hash_alg)); + 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); @@ -3638,6 +3660,7 @@ term nif_crypto_strong_rand_bytes(Context *ctx, int argc, term argv[]) } #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); From 9356570c3221d6e3b012f1a43f930f2e8ca7b77a Mon Sep 17 00:00:00 2001 From: Peter M Date: Sun, 22 Mar 2026 22:59:14 +0100 Subject: [PATCH 04/23] otp_crypto: initialize PSA cleanup sizes before error paths Declare the PSA output buffer size variables before any goto-based cleanup path can skip their initialization. This fixes Clang -Wsometimes-uninitialized failures in crypto_one_time/4-5 and crypto_update/2 when cleanup frees scratch buffers after early exits. Signed-off-by: Peter M --- src/libAtomVM/otp_crypto.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index a215e47937..909156e739 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -692,6 +692,7 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) 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; @@ -751,7 +752,7 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) goto psa_error; } - size_t output_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(key_type, alg, data_size); + 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); } @@ -2975,12 +2976,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); @@ -2994,7 +2996,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 */ } From c4a6e68d824b3bd348377ef44832b8ff4c1bf452 Mon Sep 17 00:00:00 2001 From: Peter M Date: Thu, 26 Mar 2026 16:55:00 +0100 Subject: [PATCH 05/23] otp_crypto: avoid malloc(0) in handle_iodata and one-shot cipher Allocate at least 1 byte when the computed size is zero to avoid undefined malloc(0) behaviour on embedded libc implementations that may legally return NULL for zero-length allocations. This aligns the one-shot cipher and handle_iodata paths with the streaming cipher code that already guards against this case. Signed-off-by: Peter M --- src/libAtomVM/otp_crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index 909156e739..b03394ea92 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -486,7 +486,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; } @@ -756,7 +756,7 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) if (!encrypt) { output_size = PSA_CIPHER_DECRYPT_OUTPUT_SIZE(key_type, alg, data_size); } - temp_buf = malloc(output_size); + temp_buf = malloc(output_size ? output_size : 1); if (IS_NULL_PTR(temp_buf)) { error_atom = OUT_OF_MEMORY_ATOM; goto psa_error; From 42243fc6ee72d966c7cbb7490f8bf584bec3d60e Mon Sep 17 00:00:00 2001 From: Peter M Date: Thu, 26 Mar 2026 17:03:43 +0100 Subject: [PATCH 06/23] otp_crypto: harden PSA security and error handling - Reset key attributes after psa_import_key in one-shot cipher path to match all other PSA import sites - Use secure_free for all crypto-adjacent buffers (sign/verify data, signature buffers, MAC data, AEAD AAD and combined buffers) to prevent sensitive data from lingering in freed memory - Reject AEAD decryption without a tag early with a clear error instead of letting it fail deep in PSA - Add finalized flag to MAC state so repeated mac_final/mac_update calls after finalization raise a clear error instead of a generic PSA failure - Document that ssl:nif_conf_rng is a no-op on mbedtls 4.x where PSA handles randomness internally Signed-off-by: Peter M --- src/libAtomVM/otp_crypto.c | 59 +++++++++++++------ src/libAtomVM/otp_ssl.c | 1 + .../emscripten/src/lib/emscripten_sys.h | 2 +- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index b03394ea92..43079f3c13 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -745,6 +745,7 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) 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); @@ -1727,7 +1728,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); @@ -1782,9 +1783,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); @@ -1904,7 +1905,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); @@ -1951,8 +1952,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); @@ -2005,6 +2006,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; @@ -2072,8 +2075,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); @@ -2112,7 +2113,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); @@ -2147,6 +2148,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 @@ -2317,13 +2319,17 @@ 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)); } @@ -2333,6 +2339,7 @@ static term nif_crypto_mac_update(Context *ctx, int argc, term argv[]) 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)); @@ -2358,6 +2365,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; @@ -2377,6 +2388,7 @@ static term nif_crypto_mac_final(Context *ctx, int argc, term argv[]) 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); @@ -2409,6 +2421,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)); @@ -2438,6 +2454,7 @@ static term nif_crypto_mac_finalN(Context *ctx, int argc, term argv[]) 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); @@ -3214,6 +3231,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; @@ -3289,19 +3310,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); @@ -3369,7 +3390,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; } @@ -3377,7 +3398,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: @@ -3411,7 +3432,7 @@ static term nif_crypto_crypto_one_time_aead(Context *ctx, int argc, term argv[]) cleanup: psa_destroy_key(key_id); secure_free(maybe_allocated_intext, intext_len); - free(maybe_allocated_aad); + secure_free(maybe_allocated_aad, aad_len); secure_free(out_buf, out_buf_size); if (UNLIKELY(!success)) { diff --git a/src/libAtomVM/otp_ssl.c b/src/libAtomVM/otp_ssl.c index 56124bf549..5bdf1a337f 100644 --- a/src/libAtomVM/otp_ssl.c +++ b/src/libAtomVM/otp_ssl.c @@ -521,6 +521,7 @@ static term nif_ssl_conf_rng(Context *ctx, int argc, term argv[]) 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 diff --git a/src/platforms/emscripten/src/lib/emscripten_sys.h b/src/platforms/emscripten/src/lib/emscripten_sys.h index f2978e4da2..68555d7050 100644 --- a/src/platforms/emscripten/src/lib/emscripten_sys.h +++ b/src/platforms/emscripten/src/lib/emscripten_sys.h @@ -33,8 +33,8 @@ #include #include -#include #include "sys_mbedtls.h" +#include #if MBEDTLS_VERSION_NUMBER < 0x04000000 #include From 790b4be314b6feb615301a246eb5b71a6aa61f14 Mon Sep 17 00:00:00 2001 From: Peter M Date: Fri, 27 Mar 2026 08:59:22 +0100 Subject: [PATCH 07/23] Fix esp32 HAVE_PSA_CRYPTO Signed-off-by: Peter M --- src/platforms/esp32/components/avm_sys/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 0d21ace132b3a9224b3e4ef80ca5d2dbbc2727f5 Mon Sep 17 00:00:00 2001 From: Peter M Date: Thu, 26 Mar 2026 22:24:27 +0100 Subject: [PATCH 08/23] Add mbedtls4 CI coverage Signed-off-by: Peter M --- .../workflows/build-and-test-on-freebsd.yaml | 32 +++++++++++- .github/workflows/build-and-test.yaml | 51 +++++++++++++++++-- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test-on-freebsd.yaml b/.github/workflows/build-and-test-on-freebsd.yaml index f22718ecc2..b56311fc5f 100644 --- a/.github/workflows/build-and-test-on-freebsd.yaml +++ b/.github/workflows/build-and-test-on-freebsd.yaml @@ -35,7 +35,7 @@ concurrency: jobs: build-and-test-on-freebsd: runs-on: ubuntu-24.04 - name: Build and test AtomVM on FreeBSD + name: Build and test AtomVM on FreeBSD ${{ matrix.os_release }} (${{ matrix.mbedtls }}) env: ATOMVM_EXAMPLE: "atomvm-example" @@ -44,6 +44,10 @@ jobs: matrix: os_release: ["13.5", "14.3", "15.0"] + mbedtls: ["mbedtls@3"] + include: + - os_release: "14.3" + mbedtls: "mbedtls@4" steps: @@ -60,10 +64,25 @@ jobs: sync: rsync copyback: false + - name: "Use latest pkg repo for MbedTLS 4" + if: matrix.mbedtls == 'mbedtls@4' + shell: freebsd {0} + run: | + mkdir -p /usr/local/etc/pkg/repos + echo 'FreeBSD: { url: "pkg+https://pkg.FreeBSD.org/${ABI}/latest" }' > /usr/local/etc/pkg/repos/FreeBSD.conf + pkg update -f + - name: "Install deps" + if: matrix.mbedtls == 'mbedtls@3' + shell: freebsd {0} + run: | + pkg install -y curl cmake gperf erlang elixir rebar3 ninja mbedtls3 socat + + - name: "Install deps (MbedTLS 4)" + if: matrix.mbedtls == 'mbedtls@4' shell: freebsd {0} run: | - pkg install -y curl cmake gperf erlang elixir rebar3 mbedtls3 ninja socat + pkg install -y curl cmake gperf erlang elixir rebar3 ninja mbedtls4 socat - name: "Add hostname to /etc/hosts for distribution tests" shell: freebsd {0} @@ -102,6 +121,15 @@ jobs: mkdir build - name: "Build: run cmake" + if: matrix.mbedtls == 'mbedtls@3' + shell: freebsd {0} + run: | + cd $GITHUB_WORKSPACE; + cd build + cmake .. -DAVM_WARNINGS_ARE_ERRORS=ON + + - name: "Build: run cmake (MbedTLS 4)" + if: matrix.mbedtls == 'mbedtls@4' shell: freebsd {0} run: | cd $GITHUB_WORKSPACE; diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index f487ea0cf3..f308b95ef4 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -59,6 +59,7 @@ jobs: # 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"] + mbedtls: ["default"] include: ### gcc @@ -159,6 +160,12 @@ jobs: otp: "master" elixir_version: "main" + # Additional mbedtls@4 coverage with the default Linux toolchain + - cc: "cc" + cxx: "c++" + otp: "28" + mbedtls: "mbedtls@4" + # Additional latest & -Os compiler builds - cc: "gcc-14" cxx: "g++-14" @@ -698,13 +705,26 @@ jobs: 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 + if: matrix.container != '' && matrix.mbedtls != 'mbedtls@4' + run: | + sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen valgrind libmbedtls-dev socat + + - name: "Install deps (MbedTLS 4)" + if: matrix.container != '' && matrix.mbedtls == 'mbedtls@4' + run: | + sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen valgrind socat - name: "Install deps" - if: matrix.container == '' + if: matrix.container == '' && matrix.mbedtls != 'mbedtls@4' + run: | + sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen libc6-dbg libmbedtls-dev socat + # Get a more recent valgrind + sudo snap install valgrind --classic + + - name: "Install deps (MbedTLS 4)" + if: matrix.container == '' && matrix.mbedtls == 'mbedtls@4' run: | - sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen libmbedtls-dev libc6-dbg socat + sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen libc6-dbg socat # Get a more recent valgrind sudo snap install valgrind --classic @@ -740,6 +760,19 @@ jobs: https://repo.hex.pm https://cdn.jsdelivr.net/hex + - name: "Install specific MbedTLS version" + if: matrix.mbedtls == 'mbedtls@4' + run: | + git clone --depth 1 --branch mbedtls-4.0.0 --recurse-submodules https://github.com/Mbed-TLS/mbedtls + cd mbedtls + mkdir build + cd build + cmake -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=On -DCMAKE_INSTALL_PREFIX=/usr/local .. + make -j$(nproc) + sudo make install + sudo ldconfig + echo "MBEDTLS_ROOT_DIR=/usr/local" >> $GITHUB_ENV + # Builder info - name: "System info" run: | @@ -777,6 +810,7 @@ jobs: 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" + if: matrix.mbedtls != 'mbedtls@4' working-directory: build run: | cmake ${{ matrix.cmake_opts_fp }} ${{ matrix.cmake_opts_smp }} ${{ matrix.cmake_opts_other || env.DEFAULT_CMAKE_OPTS_OTHER }} .. @@ -784,6 +818,15 @@ jobs: # touch them so we can benefit from the cache and avoid costly beam file rebuild. find . -name '*.beam' -exec touch {} \; + - name: "Build: run cmake (MbedTLS 4)" + if: matrix.mbedtls == 'mbedtls@4' + working-directory: build + run: | + cmake -DMBEDTLS_ROOT_DIR=/usr/local ${{ 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 From 9c96ae2f3ad8d81352f3736db163d81b05da913e Mon Sep 17 00:00:00 2001 From: Peter M Date: Tue, 31 Mar 2026 15:52:18 +0200 Subject: [PATCH 09/23] emscripten: support MbedTLS 4 in build and CI Make the fetched MbedTLS version configurable and extend the wasm jobs to exercise both mbedtls3 and mbedtls4 builds while keeping release artifacts on the mbedtls3 path. Update the Emscripten build to link against MbedTLS::mbedtls, guard the legacy entropy helpers to pre-4.x builds, and switch the PSA feature probes to compile-only checks so they work with fetched and custom MbedTLS targets. Install the Python modules required by the MbedTLS 4 generators in the Emscripten CI container so the tf-psa-crypto build completes. Signed-off-by: Peter M --- .github/workflows/wasm-build.yaml | 60 ++++++++++++++----- CMakeModules/FetchMbedTLS.cmake | 4 +- .../emscripten/src/lib/CMakeLists.txt | 13 ++-- src/platforms/emscripten/src/lib/sys.c | 5 ++ 4 files changed, 63 insertions(+), 19 deletions(-) diff --git a/.github/workflows/wasm-build.yaml b/.github/workflows/wasm-build.yaml index c5b75101a8..efa11e1558 100644 --- a/.github/workflows/wasm-build.yaml +++ b/.github/workflows/wasm-build.yaml @@ -143,18 +143,29 @@ jobs: needs: [compile_tests, compile_tests_jit] runs-on: ubuntu-24.04 container: emscripten/emsdk - strategy: fail-fast: false matrix: - jit: ["", "-DAVM_DISABLE_JIT=OFF"] + include: + - jit: "" + mbedtls_label: "mbedtls3" + mbedtls_git_tag: "v3.6.3.1" + - jit: "" + mbedtls_label: "mbedtls4" + mbedtls_git_tag: "v4.0.0" + - jit: "-DAVM_DISABLE_JIT=OFF" + mbedtls_label: "mbedtls3" + mbedtls_git_tag: "v3.6.3.1" + - jit: "-DAVM_DISABLE_JIT=OFF" + mbedtls_label: "mbedtls4" + mbedtls_git_tag: "v4.0.0" steps: - name: Checkout repo uses: actions/checkout@v4 - name: "Install deps" - run: sudo apt update -y && sudo apt install -y cmake gperf + run: sudo apt update -y && sudo apt install -y cmake gperf python3-jinja2 python3-jsonschema - name: Build shell: bash @@ -163,7 +174,7 @@ jobs: set -euo pipefail mkdir build cd build - emcmake cmake .. ${{ matrix.jit }} + emcmake cmake .. ${{ matrix.jit }} -DAVM_FETCH_MBEDTLS_GIT_TAG=${{ matrix.mbedtls_git_tag }} emmake make -j - name: Download AtomVM and test modules (non-JIT) @@ -210,7 +221,7 @@ jobs: 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 == '' + if: startsWith(github.ref, 'refs/tags/') && matrix.jit == '' && matrix.mbedtls_label == 'mbedtls3' shell: bash working-directory: src/platforms/emscripten/build/src run: | @@ -223,7 +234,7 @@ jobs: - name: "Release (node)" uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') && matrix.jit == '' + if: startsWith(github.ref, 'refs/tags/') && matrix.jit == '' && matrix.mbedtls_label == 'mbedtls3' with: draft: true fail_on_unmatched_files: true @@ -244,15 +255,30 @@ jobs: strategy: fail-fast: false matrix: - jit: ["", "-DAVM_DISABLE_JIT=OFF"] - language: ["javascript-typescript"] + include: + - jit: "" + language: "javascript-typescript" + mbedtls_label: "mbedtls3" + mbedtls_git_tag: "v3.6.3.1" + - jit: "" + language: "javascript-typescript" + mbedtls_label: "mbedtls4" + mbedtls_git_tag: "v4.0.0" + - jit: "-DAVM_DISABLE_JIT=OFF" + language: "javascript-typescript" + mbedtls_label: "mbedtls3" + mbedtls_git_tag: "v3.6.3.1" + - jit: "-DAVM_DISABLE_JIT=OFF" + language: "javascript-typescript" + mbedtls_label: "mbedtls4" + mbedtls_git_tag: "v4.0.0" steps: - name: Checkout repo uses: actions/checkout@v4 - name: "Install deps" - run: sudo apt update -y && sudo apt install -y cmake gperf + run: sudo apt update -y && sudo apt install -y cmake gperf python3-jinja2 python3-jsonschema - name: "Initialize CodeQL" if: matrix.jit == '' @@ -269,7 +295,7 @@ jobs: set -euo pipefail mkdir build cd build - emcmake cmake .. -DAVM_EMSCRIPTEN_ENV=web ${{ matrix.jit }} + emcmake cmake .. -DAVM_EMSCRIPTEN_ENV=web ${{ matrix.jit }} -DAVM_FETCH_MBEDTLS_GIT_TAG=${{ matrix.mbedtls_git_tag }} emmake make -j - name: "Perform CodeQL Analysis" @@ -280,7 +306,7 @@ jobs: if: matrix.jit == '' uses: actions/upload-artifact@v4 with: - name: atomvm-js-web + name: atomvm-js-web-${{ matrix.mbedtls_label }} path: | src/platforms/emscripten/build/**/*.wasm src/platforms/emscripten/build/**/*.mjs @@ -289,6 +315,12 @@ jobs: wasm_test_web: needs: [compile_tests, wasm_build_web] runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + include: + - mbedtls_label: "mbedtls3" + - mbedtls_label: "mbedtls4" steps: - name: Checkout repo uses: actions/checkout@v4 @@ -302,7 +334,7 @@ jobs: - name: Download wasm build for web uses: actions/download-artifact@v4 with: - name: atomvm-js-web + name: atomvm-js-web-${{ matrix.mbedtls_label }} path: src/platforms/emscripten/build - name: Download emscripten test modules @@ -337,7 +369,7 @@ jobs: retention-days: 7 - name: "Rename and write sha256sum (web)" - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') && matrix.mbedtls_label == 'mbedtls3' shell: bash working-directory: src/platforms/emscripten/build/src run: | @@ -350,7 +382,7 @@ jobs: - name: "Release (web)" uses: softprops/action-gh-release@v3.0.0 - if: startsWith(github.ref, 'refs/tags/') + if: startsWith(github.ref, 'refs/tags/') && matrix.mbedtls_label == 'mbedtls3' with: draft: true fail_on_unmatched_files: true 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/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/sys.c b/src/platforms/emscripten/src/lib/sys.c index 2a3a84b205..b44ca0aea3 100644 --- a/src/platforms/emscripten/src/lib/sys.c +++ b/src/platforms/emscripten/src/lib/sys.c @@ -771,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 @@ -837,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 From f66a0943ec414e299990922c1496c82630ddb7d1 Mon Sep 17 00:00:00 2001 From: Peter M Date: Wed, 15 Apr 2026 10:21:44 +0200 Subject: [PATCH 10/23] otp_crypto: address review feedback for mbedtls 4 support - Use psa_hash_algorithm_table instead of atom_to_psa_hash_alg() if-chain - Use psa_cipher_table instead of atom_to_psa_cipher_alg() if-chain - Cast to const uint8_t* in psa_hash_fold_fun - Remove unnecessary void* cast - Widen preprocessor guards for PSA table definitions Signed-off-by: Peter M --- src/libAtomVM/otp_crypto.c | 242 ++++++++++++------------------------- 1 file changed, 77 insertions(+), 165 deletions(-) diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index 43079f3c13..e74ee4eb44 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -55,7 +55,7 @@ #ifdef HAVE_PSA_CRYPTO #include #endif -#if defined(HAVE_PSA_CRYPTO) || defined(MBEDTLS_PSA_CRYPTO_C) || MBEDTLS_VERSION_NUMBER >= 0x04000000 +#if defined(HAVE_PSA_CRYPTO) || MBEDTLS_VERSION_NUMBER >= 0x04000000 #include #endif @@ -98,7 +98,7 @@ #define MAX_MD_SIZE 64 -#if defined(HAVE_PSA_CRYPTO) || defined(MBEDTLS_PSA_CRYPTO_C) || MBEDTLS_VERSION_NUMBER >= 0x04000000 +#if defined(HAVE_PSA_CRYPTO) || MBEDTLS_VERSION_NUMBER >= 0x04000000 static void do_psa_init(void) { if (UNLIKELY(psa_crypto_init() != PSA_SUCCESS)) { @@ -293,38 +293,28 @@ DEFINE_DO_HASH_NORET_IS_OTHER(sha512, , false) #endif #endif -#if MBEDTLS_VERSION_NUMBER >= 0x04000000 -static psa_algorithm_t atom_to_psa_hash_alg(term type, GlobalContext *global) -{ - if (type == globalcontext_make_atom(global, ATOM_STR("\x3", "md5"))) { - return PSA_ALG_MD5; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\x3", "sha"))) { - return PSA_ALG_SHA_1; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha224"))) { - return PSA_ALG_SHA_224; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha256"))) { - return PSA_ALG_SHA_256; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha384"))) { - return PSA_ALG_SHA_384; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\x6", "sha512"))) { - return PSA_ALG_SHA_512; - } -#ifdef PSA_ALG_RIPEMD160 - if (type == globalcontext_make_atom(global, ATOM_STR("\x9", "ripemd160"))) { - return PSA_ALG_RIPEMD160; - } +#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 - return PSA_ALG_NONE; -} +#if MBEDTLS_VERSION_NUMBER >= 0x04000000 static InteropFunctionResult psa_hash_fold_fun(term t, void *accum) { - psa_hash_operation_t *operation = (psa_hash_operation_t *) 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) { @@ -335,7 +325,7 @@ static InteropFunctionResult psa_hash_fold_fun(term t, void *accum) return InteropBadArg; } } else /* term_is_binary(t) */ { - if (UNLIKELY(psa_hash_update(operation, (uint8_t *) term_binary_data(t), term_binary_size(t)) != PSA_SUCCESS)) { + if (UNLIKELY(psa_hash_update(operation, (const uint8_t *) term_binary_data(t), term_binary_size(t)) != PSA_SUCCESS)) { return InteropBadArg; } } @@ -355,7 +345,7 @@ static term nif_crypto_hash(Context *ctx, int argc, term argv[]) #if MBEDTLS_VERSION_NUMBER >= 0x04000000 do_psa_init(); - psa_algorithm_t alg = atom_to_psa_hash_alg(type, ctx->global); + 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); @@ -509,72 +499,7 @@ static term handle_iodata(term iodata, const void **data, size_t *len, void **al } } -#if MBEDTLS_VERSION_NUMBER >= 0x04000000 -static psa_algorithm_t atom_to_psa_cipher_alg(term type, GlobalContext *global, psa_key_type_t *key_type, size_t *key_bits) -{ - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_128_ecb"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 128; - return PSA_ALG_ECB_NO_PADDING; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_192_ecb"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 192; - return PSA_ALG_ECB_NO_PADDING; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_256_ecb"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 256; - return PSA_ALG_ECB_NO_PADDING; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_128_cbc"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 128; - return PSA_ALG_CBC_NO_PADDING; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_192_cbc"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 192; - return PSA_ALG_CBC_NO_PADDING; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_256_cbc"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 256; - return PSA_ALG_CBC_NO_PADDING; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xE", "aes_128_cfb128"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 128; - return PSA_ALG_CFB; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xE", "aes_192_cfb128"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 192; - return PSA_ALG_CFB; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xE", "aes_256_cfb128"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 256; - return PSA_ALG_CFB; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_128_ctr"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 128; - return PSA_ALG_CTR; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_192_ctr"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 192; - return PSA_ALG_CTR; - } - if (type == globalcontext_make_atom(global, ATOM_STR("\xB", "aes_256_ctr"))) { - *key_type = PSA_KEY_TYPE_AES; - *key_bits = 256; - return PSA_ALG_CTR; - } - return PSA_ALG_NONE; -} -#else +#if MBEDTLS_VERSION_NUMBER < 0x04000000 static bool bool_to_mbedtls_operation(term encrypt_flag, mbedtls_operation_t *operation) { switch (encrypt_flag) { @@ -590,6 +515,54 @@ static bool bool_to_mbedtls_operation(term encrypt_flag, mbedtls_operation_t *op } #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) { @@ -642,12 +615,13 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) #if MBEDTLS_VERSION_NUMBER >= 0x04000000 do_psa_init(); - psa_key_type_t key_type; - size_t key_bits; - psa_algorithm_t alg = atom_to_psa_cipher_alg(cipher_term, ctx->global, &key_type, &key_bits); - if (UNLIKELY(alg == PSA_ALG_NONE)) { + 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); @@ -1602,22 +1576,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[]) @@ -2699,52 +2657,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}) @@ -3520,7 +3432,7 @@ static term nif_crypto_pbkdf2_hmac(Context *ctx, int argc, term argv[]) avm_int_t derived_key_len = 0; #if MBEDTLS_VERSION_NUMBER >= 0x04000000 - psa_algorithm_t hash_alg = atom_to_psa_hash_alg(digest_type_term, glb); + 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)); } From c2c2438d48f9762ab1885c8b008dbb0cbbf1d935 Mon Sep 17 00:00:00 2001 From: Peter M Date: Wed, 15 Apr 2026 16:26:45 +0200 Subject: [PATCH 11/23] libAtomVM: fix mbedtls 3.6.1 ECDSA helper gate Signed-off-by: Peter M --- src/libAtomVM/otp_crypto.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index e74ee4eb44..c18b766c46 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -48,9 +48,6 @@ #else #include #endif -#ifdef MBEDTLS_VERSION_C -#include -#endif #ifdef HAVE_PSA_CRYPTO #include @@ -81,7 +78,8 @@ // #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 From d619503919d3fb03a7f1ae5e6bae6421fcfef011 Mon Sep 17 00:00:00 2001 From: Peter M Date: Mon, 11 May 2026 12:03:39 +0200 Subject: [PATCH 12/23] STM32: guard mbedTLS 3 entropy integration Keep the STM32 mbedTLS integration on its existing MbedTLS 3 path while allowing the mbedTLS 4 support series to build around it. The STM32 platform does not enable MbedTLS 4 here; this only hides the legacy entropy and CTR_DRBG context code, hooks, and config disables when building against MbedTLS 4 headers. Signed-off-by: Peter M --- .../stm32/src/lib/mbedtls_stm32_user_config.h | 5 ++++- src/platforms/stm32/src/lib/stm_sys.h | 5 +++++ src/platforms/stm32/src/lib/sys.c | 15 +++++++++++---- 3 files changed, 20 insertions(+), 5 deletions(-) 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 3babd74f3f..9e30ebde32 100644 --- a/src/platforms/stm32/src/lib/sys.c +++ b/src/platforms/stm32/src/lib/sys.c @@ -27,19 +27,18 @@ #include #include #include -#if ATOMVM_HAS_MBEDTLS -#include -#endif #ifdef ATOMVM_HAS_MBEDTLS #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 @@ -226,7 +225,7 @@ void sys_init_platform(GlobalContext *glb) AVM_LOGE(TAG, "Out of memory!"); AVM_ABORT(); } -#if ATOMVM_HAS_MBEDTLS +#ifdef ATOMVM_HAS_MBEDTLS #if MBEDTLS_VERSION_NUMBER >= 0x04000000 psa_status_t status = psa_crypto_init(); if (status != PSA_SUCCESS) { @@ -237,8 +236,10 @@ void sys_init_platform(GlobalContext *glb) 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(); @@ -250,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 @@ -486,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; @@ -511,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); @@ -572,4 +578,5 @@ void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global) UNUSED(global); } +#endif #endif /* ATOMVM_HAS_MBEDTLS */ From 9fd8020f92a43f18a70deb561591ca17865166ba Mon Sep 17 00:00:00 2001 From: Peter M Date: Fri, 6 Mar 2026 05:59:17 +0100 Subject: [PATCH 13/23] ESP32: v6 new sleep_cause api https://docs.espressif.com/projects/esp-idf/en/v6.0-beta1/esp32/migration-guides/release-6.x/6.0/system.html#power-management Signed-off-by: Peter M --- doc/src/programmers-guide.md | 18 ++- libs/avm_esp32/src/esp.erl | 10 ++ .../esp32/components/avm_sys/platform_nifs.c | 145 ++++++++++++++++++ 3 files changed, 171 insertions(+), 2 deletions(-) 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/platforms/esp32/components/avm_sys/platform_nifs.c b/src/platforms/esp32/components/avm_sys/platform_nifs.c index a11dcfb020..fb303da947 100644 --- a/src/platforms/esp32/components/avm_sys/platform_nifs.c +++ b/src/platforms/esp32/components/avm_sys/platform_nifs.c @@ -498,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) { @@ -542,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 @@ -628,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); } @@ -1029,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 = { @@ -1195,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); From b94cd6cdb300f288083165a3483e63d3b429c562 Mon Sep 17 00:00:00 2001 From: Peter M Date: Fri, 6 Mar 2026 07:08:08 +0100 Subject: [PATCH 14/23] ESP_IF_WIFI_STA-> WIFI_IF_STA Signed-off-by: Peter M --- src/platforms/esp32/components/avm_builtins/network_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/esp32/components/avm_builtins/network_driver.c b/src/platforms/esp32/components/avm_builtins/network_driver.c index ad0f3e924b..d37751ba36 100644 --- a/src/platforms/esp32/components/avm_builtins/network_driver.c +++ b/src/platforms/esp32/components/avm_builtins/network_driver.c @@ -1513,7 +1513,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); From 164bd406331fb15f67fee5ae4aeddad880b4ab88 Mon Sep 17 00:00:00 2001 From: Peter M Date: Fri, 27 Mar 2026 15:59:21 +0100 Subject: [PATCH 15/23] Esp32: fix CI esp32c3 esp-idf 6 Signed-off-by: Peter M --- src/platforms/esp32/test/main/test_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/esp32/test/main/test_main.c b/src/platforms/esp32/test/main/test_main.c index 480b164695..41ee734e66 100644 --- a/src/platforms/esp32/test/main/test_main.c +++ b/src/platforms/esp32/test/main/test_main.c @@ -36,7 +36,7 @@ #include // Since IDF v6 it's a separate component -#if ESP_IDF_VERSION_MAJOR >= 6 && CONFIG_ETH_USE_OPENETH +#if ESP_IDF_VERSION_MAJOR >= 6 && CONFIG_ETH_USE_OPENETH && !CONFIG_IDF_TARGET_ESP32C3 #include "esp_eth_phy_dp83848.h" #endif From cdb4378db72c97a78cebb31a12069f00ec3b991e Mon Sep 17 00:00:00 2001 From: Peter M Date: Thu, 7 May 2026 22:10:32 +0200 Subject: [PATCH 16/23] CI: esp-idf v6.0.1 Signed-off-by: Peter M --- .github/workflows/esp32-build.yaml | 1 + .github/workflows/esp32-simtest.yaml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/esp32-build.yaml b/.github/workflows/esp32-build.yaml index 35e32d685e..4eb44940ae 100644 --- a/.github/workflows/esp32-build.yaml +++ b/.github/workflows/esp32-build.yaml @@ -51,6 +51,7 @@ jobs: - 'v5.3.5' - 'v5.4.4' - 'v5.5.4' + - 'v6.0.1' jit: [false] include: diff --git a/.github/workflows/esp32-simtest.yaml b/.github/workflows/esp32-simtest.yaml index e0f2241157..038453a747 100644 --- a/.github/workflows/esp32-simtest.yaml +++ b/.github/workflows/esp32-simtest.yaml @@ -98,6 +98,10 @@ jobs: idf-version: "v5.5.4" - esp-idf-target: "esp32c61" idf-version: "v5.5.4" + - esp-idf-target: "esp32" + idf-version: "v6.0.1" + - esp-idf-target: "esp32s3" + idf-version: "v6.0.1" steps: - name: Checkout repo From 6a7ea47585c93c7337fa6762ddffbb2c9333e0d2 Mon Sep 17 00:00:00 2001 From: Peter M Date: Fri, 8 May 2026 11:44:21 +0200 Subject: [PATCH 17/23] esp32: fix ESP-IDF 6.0 build errors in network_driver Two -Werror failures appear when building against ESP-IDF 6.0: - enum values WIFI_AUTH_DUMMY_1 / WIFI_AUTH_DUMMY_2 are not handled in authmode_to_atom_term's switch statement. Add a default branch so new upstream auth modes do not break the build while keeping the existing explicit cases. - IP_EVENT_AP_STAIPASSIGNED and ip_event_ap_staipassigned_t are deprecated in favor of IP_EVENT_ASSIGNED_IP_TO_CLIENT and ip_event_assigned_ip_to_client_t. Introduce version-gated AVM_IP_EVENT_AP_STAIPASSIGNED / AVM_IP_EVENT_AP_STAIPASSIGNED_T macros (matching the existing ESP_IDF_VERSION_VAL pattern in this file) and use them at the case label, register and unregister sites. The struct rename keeps the same esp_ip4_addr_t ip field, so the existing cast remains valid. Signed-off-by: Peter M --- .../components/avm_builtins/network_driver.c | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/platforms/esp32/components/avm_builtins/network_driver.c b/src/platforms/esp32/components/avm_builtins/network_driver.c index d37751ba36..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"); From ee58e9116722bb5f232fca764b005b1c1266c8f5 Mon Sep 17 00:00:00 2001 From: Peter M Date: Sun, 14 Jun 2026 13:26:05 +0200 Subject: [PATCH 18/23] esp32: add esp_driver_usb_serial_jtag and esp_ringbuf dependencies for ESP-IDF 6.0 --- .../esp32/components/avm_builtins/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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" From e192ba68a724578bb054627cf557063117c87dba Mon Sep 17 00:00:00 2001 From: Peter M Date: Sun, 14 Jun 2026 18:15:28 +0200 Subject: [PATCH 19/23] C3 fix? Signed-off-by: Peter M --- src/platforms/esp32/test/main/idf_component.yml | 10 +++++----- src/platforms/esp32/test/main/test_main.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) 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/esp32/test/main/test_main.c b/src/platforms/esp32/test/main/test_main.c index 41ee734e66..480b164695 100644 --- a/src/platforms/esp32/test/main/test_main.c +++ b/src/platforms/esp32/test/main/test_main.c @@ -36,7 +36,7 @@ #include // Since IDF v6 it's a separate component -#if ESP_IDF_VERSION_MAJOR >= 6 && CONFIG_ETH_USE_OPENETH && !CONFIG_IDF_TARGET_ESP32C3 +#if ESP_IDF_VERSION_MAJOR >= 6 && CONFIG_ETH_USE_OPENETH #include "esp_eth_phy_dp83848.h" #endif From 1199be638df43363c3a586c0c89b228a199f3d83 Mon Sep 17 00:00:00 2001 From: Peter M Date: Sun, 14 Jun 2026 18:15:57 +0200 Subject: [PATCH 20/23] full_sim_test --- .github/workflows/build-and-test-macos.yaml | 293 ----- .../workflows/build-and-test-on-freebsd.yaml | 231 ---- .github/workflows/build-and-test.yaml | 1060 ----------------- .github/workflows/build-docs.yaml | 127 -- .github/workflows/build-libraries.yaml | 167 --- .github/workflows/build-linux-artifacts.yaml | 265 ----- .github/workflows/check-formatting.yaml | 81 -- .github/workflows/codeql-analysis.yaml | 89 -- .github/workflows/esp32-build.yaml | 318 ----- .github/workflows/esp32-mkimage.yaml | 195 --- .github/workflows/pico-build.yaml | 284 ----- .github/workflows/publish-docs.yaml | 148 --- .github/workflows/reuse-lint.yaml | 19 - .github/workflows/run-tests-with-beam.yaml | 187 --- .github/workflows/stm32-build.yaml | 229 ---- .github/workflows/wasm-build.yaml | 393 ------ 16 files changed, 4086 deletions(-) delete mode 100644 .github/workflows/build-and-test-macos.yaml delete mode 100644 .github/workflows/build-and-test-on-freebsd.yaml delete mode 100644 .github/workflows/build-and-test.yaml delete mode 100644 .github/workflows/build-docs.yaml delete mode 100644 .github/workflows/build-libraries.yaml delete mode 100644 .github/workflows/build-linux-artifacts.yaml delete mode 100644 .github/workflows/check-formatting.yaml delete mode 100644 .github/workflows/codeql-analysis.yaml delete mode 100644 .github/workflows/esp32-build.yaml delete mode 100644 .github/workflows/esp32-mkimage.yaml delete mode 100644 .github/workflows/pico-build.yaml delete mode 100644 .github/workflows/publish-docs.yaml delete mode 100644 .github/workflows/reuse-lint.yaml delete mode 100644 .github/workflows/run-tests-with-beam.yaml delete mode 100644 .github/workflows/stm32-build.yaml delete mode 100644 .github/workflows/wasm-build.yaml diff --git a/.github/workflows/build-and-test-macos.yaml b/.github/workflows/build-and-test-macos.yaml deleted file mode 100644 index b46976ecc7..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", "mbedtls@4"] - 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 b56311fc5f..0000000000 --- a/.github/workflows/build-and-test-on-freebsd.yaml +++ /dev/null @@ -1,231 +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 ${{ matrix.os_release }} (${{ matrix.mbedtls }}) - env: - ATOMVM_EXAMPLE: "atomvm-example" - - strategy: - fail-fast: false - - matrix: - os_release: ["13.5", "14.3", "15.0"] - mbedtls: ["mbedtls@3"] - include: - - os_release: "14.3" - mbedtls: "mbedtls@4" - - 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: "Use latest pkg repo for MbedTLS 4" - if: matrix.mbedtls == 'mbedtls@4' - shell: freebsd {0} - run: | - mkdir -p /usr/local/etc/pkg/repos - echo 'FreeBSD: { url: "pkg+https://pkg.FreeBSD.org/${ABI}/latest" }' > /usr/local/etc/pkg/repos/FreeBSD.conf - pkg update -f - - - name: "Install deps" - if: matrix.mbedtls == 'mbedtls@3' - shell: freebsd {0} - run: | - pkg install -y curl cmake gperf erlang elixir rebar3 ninja mbedtls3 socat - - - name: "Install deps (MbedTLS 4)" - if: matrix.mbedtls == 'mbedtls@4' - shell: freebsd {0} - run: | - pkg install -y curl cmake gperf erlang elixir rebar3 ninja mbedtls4 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" - if: matrix.mbedtls == 'mbedtls@3' - shell: freebsd {0} - run: | - cd $GITHUB_WORKSPACE; - cd build - cmake .. -DAVM_WARNINGS_ARE_ERRORS=ON - - - name: "Build: run cmake (MbedTLS 4)" - if: matrix.mbedtls == 'mbedtls@4' - 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 f308b95ef4..0000000000 --- a/.github/workflows/build-and-test.yaml +++ /dev/null @@ -1,1060 +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"] - mbedtls: ["default"] - - 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 mbedtls@4 coverage with the default Linux toolchain - - cc: "cc" - cxx: "c++" - otp: "28" - mbedtls: "mbedtls@4" - - # 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 != '' && matrix.mbedtls != 'mbedtls@4' - run: | - sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen valgrind libmbedtls-dev socat - - - name: "Install deps (MbedTLS 4)" - if: matrix.container != '' && matrix.mbedtls == 'mbedtls@4' - run: | - sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen valgrind socat - - - name: "Install deps" - if: matrix.container == '' && matrix.mbedtls != 'mbedtls@4' - run: | - sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen libc6-dbg libmbedtls-dev socat - # Get a more recent valgrind - sudo snap install valgrind --classic - - - name: "Install deps (MbedTLS 4)" - if: matrix.container == '' && matrix.mbedtls == 'mbedtls@4' - run: | - sudo apt install -y ${{ matrix.compiler_pkgs}} cmake gperf zlib1g-dev doxygen 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 - - - name: "Install specific MbedTLS version" - if: matrix.mbedtls == 'mbedtls@4' - run: | - git clone --depth 1 --branch mbedtls-4.0.0 --recurse-submodules https://github.com/Mbed-TLS/mbedtls - cd mbedtls - mkdir build - cd build - cmake -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=On -DCMAKE_INSTALL_PREFIX=/usr/local .. - make -j$(nproc) - sudo make install - sudo ldconfig - echo "MBEDTLS_ROOT_DIR=/usr/local" >> $GITHUB_ENV - - # 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" - if: matrix.mbedtls != 'mbedtls@4' - 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 cmake (MbedTLS 4)" - if: matrix.mbedtls == 'mbedtls@4' - working-directory: build - run: | - cmake -DMBEDTLS_ROOT_DIR=/usr/local ${{ 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 d649106257..0000000000 --- a/.github/workflows/build-libraries.yaml +++ /dev/null @@ -1,167 +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 - matrix: - mbedtls: ["default", "mbedtls@4"] - - 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 - if [[ "${{ matrix.mbedtls }}" == "default" ]]; then - sudo apt install -y libmbedtls-dev - fi - # Get a more recent valgrind - sudo snap install valgrind --classic - - - name: "Install specific MbedTLS version" - if: matrix.mbedtls == 'mbedtls@4' - run: | - git clone --depth 1 --branch mbedtls-4.0.0 --recurse-submodules https://github.com/Mbed-TLS/mbedtls - cd mbedtls - mkdir build - cd build - cmake -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=On -DCMAKE_INSTALL_PREFIX=/usr/local .. - make -j$(nproc) - sudo make install - sudo ldconfig - echo "MBEDTLS_ROOT_DIR=/usr/local" >> $GITHUB_ENV - - # 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 ${MBEDTLS_ROOT_DIR:+-DMBEDTLS_ROOT_DIR=$MBEDTLS_ROOT_DIR} .. - - - 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/') && matrix.mbedtls == 'default' - 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 4eb44940ae..0000000000 --- a/.github/workflows/esp32-build.yaml +++ /dev/null @@ -1,318 +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' - - 'v6.0.1' - 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/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 efa11e1558..0000000000 --- a/.github/workflows/wasm-build.yaml +++ /dev/null @@ -1,393 +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: - include: - - jit: "" - mbedtls_label: "mbedtls3" - mbedtls_git_tag: "v3.6.3.1" - - jit: "" - mbedtls_label: "mbedtls4" - mbedtls_git_tag: "v4.0.0" - - jit: "-DAVM_DISABLE_JIT=OFF" - mbedtls_label: "mbedtls3" - mbedtls_git_tag: "v3.6.3.1" - - jit: "-DAVM_DISABLE_JIT=OFF" - mbedtls_label: "mbedtls4" - mbedtls_git_tag: "v4.0.0" - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: "Install deps" - run: sudo apt update -y && sudo apt install -y cmake gperf python3-jinja2 python3-jsonschema - - - name: Build - shell: bash - working-directory: ./src/platforms/emscripten/ - run: | - set -euo pipefail - mkdir build - cd build - emcmake cmake .. ${{ matrix.jit }} -DAVM_FETCH_MBEDTLS_GIT_TAG=${{ matrix.mbedtls_git_tag }} - 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 == '' && matrix.mbedtls_label == 'mbedtls3' - 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 == '' && matrix.mbedtls_label == 'mbedtls3' - 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: - include: - - jit: "" - language: "javascript-typescript" - mbedtls_label: "mbedtls3" - mbedtls_git_tag: "v3.6.3.1" - - jit: "" - language: "javascript-typescript" - mbedtls_label: "mbedtls4" - mbedtls_git_tag: "v4.0.0" - - jit: "-DAVM_DISABLE_JIT=OFF" - language: "javascript-typescript" - mbedtls_label: "mbedtls3" - mbedtls_git_tag: "v3.6.3.1" - - jit: "-DAVM_DISABLE_JIT=OFF" - language: "javascript-typescript" - mbedtls_label: "mbedtls4" - mbedtls_git_tag: "v4.0.0" - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: "Install deps" - run: sudo apt update -y && sudo apt install -y cmake gperf python3-jinja2 python3-jsonschema - - - 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 }} -DAVM_FETCH_MBEDTLS_GIT_TAG=${{ matrix.mbedtls_git_tag }} - 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-${{ matrix.mbedtls_label }} - 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 - strategy: - fail-fast: false - matrix: - include: - - mbedtls_label: "mbedtls3" - - mbedtls_label: "mbedtls4" - 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-${{ matrix.mbedtls_label }} - 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/') && matrix.mbedtls_label == 'mbedtls3' - 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/') && matrix.mbedtls_label == 'mbedtls3' - 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 From 1f60e48f7c4dd7b73dc148c9edd0fc2385f6c6b1 Mon Sep 17 00:00:00 2001 From: Peter M Date: Sun, 14 Jun 2026 18:27:43 +0200 Subject: [PATCH 21/23] Update esp32-simtest.yaml --- .github/workflows/esp32-simtest.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/esp32-simtest.yaml b/.github/workflows/esp32-simtest.yaml index 038453a747..cf60860548 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('["v6.0.1"]') }} exclude: - esp-idf-target: "esp32p4" idf-version: "v5.2.7" @@ -95,13 +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" - - esp-idf-target: "esp32c61" - idf-version: "v5.5.4" - - esp-idf-target: "esp32" idf-version: "v6.0.1" - - esp-idf-target: "esp32s3" + - esp-idf-target: "esp32c61" idf-version: "v6.0.1" + # - esp-idf-target: "esp32" + # idf-version: "v6.0.1" + # - esp-idf-target: "esp32s3" + # idf-version: "v6.0.1" steps: - name: Checkout repo From dd79b94b86da38cc49a24fe1d43ff113082fd2c9 Mon Sep 17 00:00:00 2001 From: Peter M Date: Sun, 14 Jun 2026 20:08:59 +0200 Subject: [PATCH 22/23] Update esp32-simtest.yaml --- .github/workflows/esp32-simtest.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/esp32-simtest.yaml b/.github/workflows/esp32-simtest.yaml index cf60860548..0dbe3845bc 100644 --- a/.github/workflows/esp32-simtest.yaml +++ b/.github/workflows/esp32-simtest.yaml @@ -80,7 +80,7 @@ jobs: "esp32c6", "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('["v6.0.1"]') }} + 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" From bf3a988d6df08224f96cce89531f90fe4beadfc0 Mon Sep 17 00:00:00 2001 From: Peter M Date: Sun, 14 Jun 2026 20:17:17 +0200 Subject: [PATCH 23/23] Update esp32-simtest.yaml --- .github/workflows/esp32-simtest.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/esp32-simtest.yaml b/.github/workflows/esp32-simtest.yaml index 0dbe3845bc..b7459ac4ea 100644 --- a/.github/workflows/esp32-simtest.yaml +++ b/.github/workflows/esp32-simtest.yaml @@ -95,9 +95,9 @@ jobs: # CI now uses chip revision 3 that is currently only available since 5.5.2 include: - esp-idf-target: "esp32p4" - idf-version: "v6.0.1" + idf-version: "release-v6.1" - esp-idf-target: "esp32c61" - idf-version: "v6.0.1" + idf-version: "release-v6.1" # - esp-idf-target: "esp32" # idf-version: "v6.0.1" # - esp-idf-target: "esp32s3"