From 4fdacf39cd9f378c5c636d225e5db3cbe27d7b47 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 26 Nov 2025 15:03:34 +0100 Subject: [PATCH 1/5] extra: Add debug config fragment. Add debug config fragment to easily build debug images. Usage: ./extra/build.sh --debug The build includes extra/debug.conf which enables: - Debug mode with assertions and verbose output - Debug-level logging (level 4) - Stack overflow detection - Thread monitoring - Debug optimizations (-Og) - Enable shell. Signed-off-by: iabdalkader --- extra/build.sh | 5 +++++ extra/debug.conf | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 extra/debug.conf diff --git a/extra/build.sh b/extra/build.sh index 6ff88b925..2b2bac7d5 100755 --- a/extra/build.sh +++ b/extra/build.sh @@ -51,6 +51,11 @@ else args="$*" fi +# Check for debug flag and append +if [ x$2 == x"--debug" ]; then + args="$args -- -DEXTRA_CONF_FILE=../extra/debug.conf" +fi + echo echo "Build target: $target $args" diff --git a/extra/debug.conf b/extra/debug.conf new file mode 100644 index 000000000..6ef7d38de --- /dev/null +++ b/extra/debug.conf @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: Apache-2.0 +# Debug configuration for Arduino Core Zephyr + +# Enable debug mode +CONFIG_DEBUG=y + +# Enable assertions +CONFIG_ASSERT=y +#CONFIG_ASSERT_VERBOSE=y + +# Enable stack overflow detection +CONFIG_STACK_SENTINEL=y +CONFIG_STACK_CANARIES=y + +# Enable thread monitoring +CONFIG_THREAD_MONITOR=y +CONFIG_THREAD_NAME=y + +# Disable compiler optimizations +#CONFIG_DEBUG_OPTIMIZATIONS=y + +# Enable and configure the shell +CONFIG_SHELL=y +#CONFIG_NET_SHELL=y +#CONFIG_NET_L2_WIFI_SHELL=y +CONFIG_SHELL_STACK_SIZE=8192 + +# Enable heap runtime statistics for kernel heap command +CONFIG_SYS_HEAP_RUNTIME_STATS=y From 6af6d0d0a68dc13036ff7ccf35442e250498920d Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 25 Nov 2025 16:07:40 +0100 Subject: [PATCH 2/5] loader: Export the correct sketch log symbols. The created sketch log structures depends on the config: CONFIG_LOG (IMMEDIATE/DEFERRED): creates log_const_sketch struct. CONFIG_LOG_RUNTIME_FILTERING (implied by CONFIG_SHELL): creates log_dynamic_sketch struct. CONFIG_LOG_MODE_IMMEDIATE + CONFIG_SHELL: creates both. Signed-off-by: iabdalkader --- loader/llext_exports.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/loader/llext_exports.c b/loader/llext_exports.c index c9bbc142f..30ccc8665 100644 --- a/loader/llext_exports.c +++ b/loader/llext_exports.c @@ -82,9 +82,14 @@ EXPORT_SYMBOL(usb_enable); EXPORT_SYMBOL(usb_disable); #endif +#if CONFIG_LOG EXPORT_SYMBOL(z_log_msg_runtime_vcreate); +FORCE_EXPORT_SYM(log_const_sketch) +#endif +#if defined(CONFIG_LOG_RUNTIME_FILTERING) FORCE_EXPORT_SYM(log_dynamic_sketch) +#endif #if defined(CONFIG_NETWORKING) FORCE_EXPORT_SYM(net_if_foreach); From 0b9ed75c66dc38d909aa5b582af01aec5ff7c13f Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Thu, 27 Nov 2025 13:32:46 +0100 Subject: [PATCH 3/5] loader: Redirect malloc to kernel heap. Replace the libc's malloc, free etc.. with wrappers that redirect memory allocation Zephyr's kernel heap functions (k_malloc/k_free). Signed-off-by: iabdalkader --- extra/build.sh | 7 +------ loader/CMakeLists.txt | 8 ++++++++ loader/llext_exports.c | 3 --- loader/malloc_wrapper.c | 25 +++++++++++++++++++++++++ platform.txt | 2 +- 5 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 loader/malloc_wrapper.c diff --git a/extra/build.sh b/extra/build.sh index 2b2bac7d5..1b0848f31 100755 --- a/extra/build.sh +++ b/extra/build.sh @@ -104,11 +104,6 @@ extra/gen_provides.py "${BUILD_DIR}/zephyr/zephyr.elf" -LF \ "+kheap_llext_heap" \ "+kheap__system_heap" \ "*sketch_base_addr=_sketch_start" \ - "*sketch_max_size=_sketch_max_size" \ - "malloc=__wrap_malloc" \ - "free=__wrap_free" \ - "realloc=__wrap_realloc" \ - "calloc=__wrap_calloc" \ - "random=__wrap_random" > ${VARIANT_DIR}/syms-static.ld + "*sketch_max_size=_sketch_max_size" > ${VARIANT_DIR}/syms-static.ld cmake -P extra/gen_arduino_files.cmake $variant diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 8688fc866..92021fd54 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -25,4 +25,12 @@ FILE(GLOB app_sources *.c) target_sources(app PRIVATE ${app_sources}) target_compile_definitions(app PUBLIC _XOPEN_SOURCE=700) +# Wrap malloc, free, calloc and realloc +zephyr_ld_options( + -Wl,--wrap=malloc + -Wl,--wrap=free + -Wl,--wrap=calloc + -Wl,--wrap=realloc +) + target_link_libraries(app PUBLIC blobs) diff --git a/loader/llext_exports.c b/loader/llext_exports.c index 30ccc8665..71ecd88a9 100644 --- a/loader/llext_exports.c +++ b/loader/llext_exports.c @@ -276,10 +276,7 @@ FORCE_EXPORT_SYM(__aeabi_idivmod); FORCE_EXPORT_SYM(__aeabi_ldivmod); FORCE_EXPORT_SYM(__aeabi_ul2f); FORCE_EXPORT_SYM(__aeabi_dcmpge); - -#if defined (CONFIG_CPP) FORCE_EXPORT_SYM(__cxa_pure_virtual); -#endif #if defined(CONFIG_BOARD_ARDUINO_UNO_Q) FORCE_EXPORT_SYM(matrixBegin); diff --git a/loader/malloc_wrapper.c b/loader/malloc_wrapper.c new file mode 100644 index 000000000..56ed152d7 --- /dev/null +++ b/loader/malloc_wrapper.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + * + * Wrapper to redirect malloc/free to k_malloc/k_free using ld --wrap + */ + +#include + +void *__wrap_malloc(size_t size) { + return k_malloc(size); +} + +void __wrap_free(void *ptr) { + k_free(ptr); +} + +void *__wrap_calloc(size_t nmemb, size_t size) { + return k_calloc(nmemb, size); +} + +void *__wrap_realloc(void *ptr, size_t size) { + return k_realloc(ptr, size); +} diff --git a/platform.txt b/platform.txt index 888ee4025..fc1565f4a 100644 --- a/platform.txt +++ b/platform.txt @@ -63,7 +63,7 @@ build.combine_command={build.link_command} {build.link_args.build-{build.link_mo # link_args.* are included by any link_command depending on the link_mode build.link_args.dynamic=-e main -build.link_args.static=-lc -lm -lgcc -Wl,--wrap=random -Wl,--wrap=calloc -Wl,--wrap=free -Wl,--wrap=malloc -Wl,--wrap=realloc +build.link_args.static=-lc -lm -lgcc # link_args.check-* are used to check the build. Only LLEXT needs these to emulate a static build (no -r!). build.link_args.check-dynamic="-T{build.variant.path}/syms-dynamic.ld" "-T{build.ldscript.path}/memory-check.ld" "-T{build.ldscript.path}/build-static.ld" From 7498d419781204e3fc579ed0ad44226eddc24360 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Tue, 25 Nov 2025 16:36:07 +0100 Subject: [PATCH 4/5] variants: Disable the shell for production builds. This saves about 70KBs FLASH and ~47KBs RAM. The saved memory is used to increase mbedtls heap to support cert loading, and the remaining added to main heap. Signed-off-by: iabdalkader --- .../arduino_giga_r1_stm32h747xx_m7.conf | 12 ++++-------- .../arduino_portenta_c33_r7fa6m5bh3cfc.conf | 11 ++++------- .../arduino_portenta_h7_stm32h747xx_m7.conf | 12 ++++-------- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf b/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf index c1050099d..76d2e4696 100644 --- a/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf +++ b/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf @@ -11,13 +11,13 @@ CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT=y CONFIG_LLEXT_STORAGE_WRITABLE=n CONFIG_SHARED_MULTI_HEAP=y -CONFIG_HEAP_MEM_POOL_SIZE=24576 -CONFIG_SHELL_STACK_SIZE=32768 +CONFIG_HEAP_MEM_POOL_SIZE=102400 CONFIG_MAIN_STACK_SIZE=32768 CONFIG_LLEXT_HEAP_SIZE=128 -CONFIG_FPU=y +CONFIG_SHELL=n +CONFIG_FPU=y CONFIG_ADC=y CONFIG_DAC=y CONFIG_PWM=y @@ -39,13 +39,12 @@ CONFIG_MBEDTLS=y CONFIG_MBEDTLS_BUILTIN=y CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y CONFIG_MBEDTLS_ENABLE_HEAP=y -CONFIG_MBEDTLS_HEAP_SIZE=60000 +CONFIG_MBEDTLS_HEAP_SIZE=80000 CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=7168 CONFIG_MBEDTLS_HASH_ALL_ENABLED=y CONFIG_MBEDTLS_CMAC=y CONFIG_VIDEO=y -CONFIG_VIDEO_LOG_LEVEL_DBG=y CONFIG_VIDEO_STM32_DCMI=y CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=3 CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=614400 @@ -134,7 +133,4 @@ CONFIG_DNS_SERVER1="8.8.8.8" CONFIG_NET_CONFIG_AUTO_INIT=n CONFIG_NET_CONNECTION_MANAGER=y #CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES=2 - -CONFIG_NET_SHELL=y CONFIG_NET_L2_ETHERNET_MGMT=y -CONFIG_NET_L2_WIFI_SHELL=y diff --git a/variants/arduino_portenta_c33_r7fa6m5bh3cfc/arduino_portenta_c33_r7fa6m5bh3cfc.conf b/variants/arduino_portenta_c33_r7fa6m5bh3cfc/arduino_portenta_c33_r7fa6m5bh3cfc.conf index 8a7a11786..a8c4443fc 100644 --- a/variants/arduino_portenta_c33_r7fa6m5bh3cfc/arduino_portenta_c33_r7fa6m5bh3cfc.conf +++ b/variants/arduino_portenta_c33_r7fa6m5bh3cfc/arduino_portenta_c33_r7fa6m5bh3cfc.conf @@ -18,14 +18,14 @@ CONFIG_USBD_LOG_LEVEL_ERR=y CONFIG_LLEXT_STORAGE_WRITABLE=n CONFIG_FPU=y - CONFIG_USERSPACE=n CONFIG_ARM_MPU=n -CONFIG_SHELL_STACK_SIZE=8192 +CONFIG_SHELL=n + CONFIG_MAIN_STACK_SIZE=32768 CONFIG_LLEXT_HEAP_SIZE=128 -CONFIG_HEAP_MEM_POOL_SIZE=32768 +CONFIG_HEAP_MEM_POOL_SIZE=51200 CONFIG_ISR_STACK_SIZE=8192 CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=8192 CONFIG_IDLE_STACK_SIZE=8192 @@ -34,8 +34,6 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=8192 CONFIG_ADC=y CONFIG_PWM=y -CONFIG_NET_CORE_LOG_LEVEL_DBG=y - CONFIG_NETWORKING=y CONFIG_NET_IPV6=n CONFIG_NET_IPV4=y @@ -74,7 +72,7 @@ CONFIG_MBEDTLS=y CONFIG_MBEDTLS_BUILTIN=y CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y CONFIG_MBEDTLS_ENABLE_HEAP=y -CONFIG_MBEDTLS_HEAP_SIZE=60000 +CONFIG_MBEDTLS_HEAP_SIZE=80000 CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=7168 CONFIG_MBEDTLS_HASH_ALL_ENABLED=y CONFIG_MBEDTLS_CMAC=y @@ -85,7 +83,6 @@ CONFIG_NANOPB=y CONFIG_NET_CONFIG_AUTO_INIT=n CONFIG_NET_CONNECTION_MANAGER=y CONFIG_WIFI_NM_MAX_MANAGED_INTERFACES=2 -CONFIG_NET_L2_WIFI_SHELL=y CONFIG_NET_MGMT_EVENT_QUEUE_SIZE=32 CONFIG_NET_IF_MAX_IPV4_COUNT=3 diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf index a5cc5a0a3..852540950 100644 --- a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf @@ -10,9 +10,10 @@ CONFIG_UART_LINE_CTRL=y CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT=y CONFIG_LLEXT_STORAGE_WRITABLE=n - CONFIG_SHARED_MULTI_HEAP=y -CONFIG_HEAP_MEM_POOL_SIZE=65536 +CONFIG_HEAP_MEM_POOL_SIZE=143360 + +CONFIG_SHELL=n CONFIG_FPU=y CONFIG_ICACHE=y @@ -23,7 +24,6 @@ CONFIG_USERSPACE=n CONFIG_ARM_MPU=y CONFIG_MAX_THREAD_BYTES=4 -CONFIG_SHELL_STACK_SIZE=32768 CONFIG_MAIN_STACK_SIZE=32768 CONFIG_LLEXT_HEAP_SIZE=128 @@ -40,13 +40,10 @@ CONFIG_SDHC_INIT_PRIORITY=75 CONFIG_SDIO_STACK=y CONFIG_CYW4343W=y CONFIG_WIFI=y -CONFIG_NET_L2_WIFI_SHELL=y CONFIG_AIROC_WIFI_CUSTOM=y CONFIG_STM32_MEMMAP=y -CONFIG_NET_CORE_LOG_LEVEL_DBG=y - CONFIG_NETWORKING=y CONFIG_NET_IPV6=n CONFIG_NET_IPV4=y @@ -82,13 +79,12 @@ CONFIG_MBEDTLS=y CONFIG_MBEDTLS_BUILTIN=y CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y CONFIG_MBEDTLS_ENABLE_HEAP=y -CONFIG_MBEDTLS_HEAP_SIZE=60000 +CONFIG_MBEDTLS_HEAP_SIZE=80000 CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=7168 CONFIG_MBEDTLS_HASH_ALL_ENABLED=y CONFIG_MBEDTLS_CMAC=y CONFIG_VIDEO=y -CONFIG_VIDEO_LOG_LEVEL_DBG=y CONFIG_VIDEO_STM32_DCMI=y CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=3 CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=614400 From 5d1e8f5ab6d49cbdbd460f48ce89d5b9ed64f8c6 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Wed, 26 Nov 2025 14:59:44 +0100 Subject: [PATCH 5/5] variants: Disable CPP and libc heap. Signed-off-by: iabdalkader --- loader/fixups.c | 7 +++++++ .../arduino_giga_r1_stm32h747xx_m7.conf | 2 ++ .../arduino_portenta_c33_r7fa6m5bh3cfc.conf | 2 ++ .../arduino_portenta_h7_stm32h747xx_m7.conf | 2 ++ 4 files changed, 13 insertions(+) diff --git a/loader/fixups.c b/loader/fixups.c index ba6be7f3d..42afca2d6 100644 --- a/loader/fixups.c +++ b/loader/fixups.c @@ -1,6 +1,13 @@ #include #include +#ifndef CONFIG_CPP +void __cxa_pure_virtual() { + while (1) + ; +} +#endif + int disable_mpu_rasr_xn(void) { uint32_t index; /* Kept the max index as 8(irrespective of soc) because the sram diff --git a/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf b/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf index 76d2e4696..4397e1885 100644 --- a/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf +++ b/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf @@ -14,7 +14,9 @@ CONFIG_SHARED_MULTI_HEAP=y CONFIG_HEAP_MEM_POOL_SIZE=102400 CONFIG_MAIN_STACK_SIZE=32768 CONFIG_LLEXT_HEAP_SIZE=128 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 +CONFIG_CPP=n CONFIG_SHELL=n CONFIG_FPU=y diff --git a/variants/arduino_portenta_c33_r7fa6m5bh3cfc/arduino_portenta_c33_r7fa6m5bh3cfc.conf b/variants/arduino_portenta_c33_r7fa6m5bh3cfc/arduino_portenta_c33_r7fa6m5bh3cfc.conf index a8c4443fc..e8fa6b274 100644 --- a/variants/arduino_portenta_c33_r7fa6m5bh3cfc/arduino_portenta_c33_r7fa6m5bh3cfc.conf +++ b/variants/arduino_portenta_c33_r7fa6m5bh3cfc/arduino_portenta_c33_r7fa6m5bh3cfc.conf @@ -21,6 +21,7 @@ CONFIG_FPU=y CONFIG_USERSPACE=n CONFIG_ARM_MPU=n +CONFIG_CPP=n CONFIG_SHELL=n CONFIG_MAIN_STACK_SIZE=32768 @@ -30,6 +31,7 @@ CONFIG_ISR_STACK_SIZE=8192 CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=8192 CONFIG_IDLE_STACK_SIZE=8192 CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=8192 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 CONFIG_ADC=y CONFIG_PWM=y diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf index 852540950..9f04a2cb5 100644 --- a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf @@ -12,7 +12,9 @@ CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT=y CONFIG_LLEXT_STORAGE_WRITABLE=n CONFIG_SHARED_MULTI_HEAP=y CONFIG_HEAP_MEM_POOL_SIZE=143360 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 +CONFIG_CPP=n CONFIG_SHELL=n CONFIG_FPU=y