From 3b3dde987caabd09473807e3509a90b98ee7cfbf Mon Sep 17 00:00:00 2001 From: Winford Date: Sat, 14 Oct 2023 19:31:03 -0700 Subject: [PATCH 1/2] Enable `AVM_ABORT()` and use it for `hard_fault_handler` on stm32 - Impliment newlib stubs to support `getpid()` and `kill()` needed for `AVM_ABORT()` to work properly. - Redefine weak linked `hard_fault_handler` defined in libopencm3/cm3/nvic.h to use `AVM_ABORT()` rather than get trapped in the default do nothing `while(1)` loop. Signed-off-by: Winford --- CHANGELOG.md | 2 ++ src/platforms/stm32/src/main.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index afcb33e02..1d5f2e9a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed a bug where guards would raise exceptions instead of just being false - Fixed support for big endian CPUs (such as some MIPS CPUs). +- Fixed STM32 not aborting when `AVM_ABORT()` is used +- Fixed a bug that would leave the STM32 trapped in a loop on hard faults, rather than aborting ### Added diff --git a/src/platforms/stm32/src/main.c b/src/platforms/stm32/src/main.c index 65f1896bf..7bba9dadf 100644 --- a/src/platforms/stm32/src/main.c +++ b/src/platforms/stm32/src/main.c @@ -19,6 +19,7 @@ */ #include +#include #include #include @@ -61,6 +62,8 @@ "\n" int _write(int file, char *ptr, int len); +pid_t _getpid(void); +int _kill(pid_t pid, int sig); static void clock_setup() { @@ -124,6 +127,30 @@ int _write(int file, char *ptr, int len) return -1; } +// newlib stubs to support AVM_ABORT +pid_t _getpid() +{ + return 1; +} + +int _kill(pid_t pid, int sig) +{ + UNUSED(pid); + if (sig == SIGABRT) { + fprintf(stderr, "Aborted\n"); + } else { + fprintf(stderr, "Unknown signal %d\n", sig); + } + errno = EINVAL; + return -1; +} + +// Redefine weak linked while(1) loop from libopencm3/cm3/nvic.h. +void hard_fault_handler() { + fprintf(stderr, "\nHard Fault detected!\n"); + AVM_ABORT(); +} + int main() { // Flash cache must be enabled before system clock is activated @@ -172,6 +199,8 @@ int main() ctx->leader = 1; AVM_LOGI(TAG, "Starting: %s...\n", startup_module_name); + fprintf(stdout, "---\n"); + context_execute_loop(ctx, mod, "start", 0); AVM_LOGI(TAG, "Return value: %lx", (long) term_to_int32(ctx->x[0])); From ce85667856a4ee810e006d23c89e60845a075e22 Mon Sep 17 00:00:00 2001 From: Winford Date: Sat, 14 Oct 2023 19:31:43 -0700 Subject: [PATCH 2/2] Add support for reboot on not ok for stm32 platform Adds the cmake configuration option `AVM_CONFIG_REBOOT_ON_NOT_OK` to allow the automatic rebooting of the device if the user application exits with any return value other than `ok`. Signed-off-by: Winford --- CHANGELOG.md | 1 + doc/src/build-instructions.md | 3 +++ src/platforms/stm32/CMakeLists.txt | 7 +++++- src/platforms/stm32/src/main.c | 36 +++++++++++++++++++++++++----- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d5f2e9a0..d36a96fe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for the OTP `socket` interface. - Enhancd performance of STM32 by enabling flash cache and i-cache with branch prediction. +- Added cmake configuration option `AVM_CONFIG_REBOOT_ON_NOT_OK` for STM32 ## [0.6.0-alpha.1] - 2023-10-09 diff --git a/doc/src/build-instructions.md b/doc/src/build-instructions.md index 865780fea..72441a9a2 100644 --- a/doc/src/build-instructions.md +++ b/doc/src/build-instructions.md @@ -551,6 +551,9 @@ is 8N1 with no flow control. > If building for a different target USART and gpio pins may need to be adjusted in `main.c`. +### Configuring for "deployment" +After your application has been tested (_and debugged_) and is ready to put into active use you may want to tune the build of AtomVM. For instance disabling logging with `-DAVM_LOG_DISABLE=on` as a `cmake` configuration option may result in slightly better performance. This will have no affect on the console output of your application, just disable low level log messages from the AtomVM system. You may also want to enabling automatic reboot in the case that your application ever exits with a return other than `ok`. This can be enabled with the `cmake` option `-DAVM_CONFIG_REBOOT_ON_NOT_OK=on`. + ## Building for Raspberry Pi Pico ### Prerequisites diff --git a/src/platforms/stm32/CMakeLists.txt b/src/platforms/stm32/CMakeLists.txt index 3232756a6..b7c233629 100644 --- a/src/platforms/stm32/CMakeLists.txt +++ b/src/platforms/stm32/CMakeLists.txt @@ -32,6 +32,7 @@ option(AVM_NEWLIB_NANO "Use 'nano' newlib. Saves 46kB, no `long long` support" O option(AVM_LOG_DISABLE "Disable log output" OFF) option(AVM_ENABLE_LOG_COLOR "Use color log output" OFF) option(AVM_ENABLE_LOG_LINES "Include source and line info for all enbled levels" OFF) +option(AVM_CONFIG_REBOOT_ON_NOT_OK "Reboot when application exits with non 'ok' return" OFF) set(AVM_DISABLE_SMP ON FORCE) @@ -40,7 +41,11 @@ if (AVM_NEWLIB_NANO) set(AVM_LOG_DISABLE ON FORCE) endif() -# Configure logging +if (AVM_CONFIG_REBOOT_ON_NOT_OK) + add_compile_definitions(CONFIG_REBOOT_ON_NOT_OK) +endif() + + # Configure logging if (AVM_LOG_DISABLE) add_compile_definitions(AVM_LOG_DISABLE) elseif (AVM_LOG_LEVEL_MAX) diff --git a/src/platforms/stm32/src/main.c b/src/platforms/stm32/src/main.c index 7bba9dadf..729ca463f 100644 --- a/src/platforms/stm32/src/main.c +++ b/src/platforms/stm32/src/main.c @@ -23,7 +23,9 @@ #include #include +#include #include +#include #include #include #include @@ -31,6 +33,7 @@ #include #include +#include #include #include #include @@ -146,7 +149,8 @@ int _kill(pid_t pid, int sig) } // Redefine weak linked while(1) loop from libopencm3/cm3/nvic.h. -void hard_fault_handler() { +void hard_fault_handler() +{ fprintf(stderr, "\nHard Fault detected!\n"); AVM_ABORT(); } @@ -202,10 +206,32 @@ int main() fprintf(stdout, "---\n"); context_execute_loop(ctx, mod, "start", 0); - AVM_LOGI(TAG, "Return value: %lx", (long) term_to_int32(ctx->x[0])); - - while (1) - ; + term ret_value = ctx->x[0]; + char *ret_atom_string = interop_atom_to_string(ctx, ret_value); + if (ret_atom_string != NULL) { + AVM_LOGI(TAG, "Exited with return: %s", ret_atom_string); + } else { + AVM_LOGI(TAG, "Exited with return value: %lx", (long) term_to_int32(ret_value)); + } + free(ret_atom_string); + + bool reboot_on_not_ok = +#if defined(CONFIG_REBOOT_ON_NOT_OK) + CONFIG_REBOOT_ON_NOT_OK ? true : false; +#else + false; +#endif + if (reboot_on_not_ok && ret_value != OK_ATOM) { + AVM_LOGE(TAG, "AtomVM application terminated with non-ok return value. Rebooting ..."); + scb_reset_system(); + } else { + AVM_LOGI(TAG, "AtomVM application terminated. Going to sleep forever ..."); + // Disable all interrupts + cm_disable_interrupts(); + while (1) { + ; + } + } return 0; }