diff --git a/CHANGELOG.md b/CHANGELOG.md index afcb33e02..d36a96fe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,11 +10,14 @@ 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 - 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 65f1896bf..729ca463f 100644 --- a/src/platforms/stm32/src/main.c +++ b/src/platforms/stm32/src/main.c @@ -19,10 +19,13 @@ */ #include +#include #include #include +#include #include +#include #include #include #include @@ -30,6 +33,7 @@ #include #include +#include #include #include #include @@ -61,6 +65,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 +130,31 @@ 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,11 +203,35 @@ int main() ctx->leader = 1; AVM_LOGI(TAG, "Starting: %s...\n", startup_module_name); - context_execute_loop(ctx, mod, "start", 0); - AVM_LOGI(TAG, "Return value: %lx", (long) term_to_int32(ctx->x[0])); + fprintf(stdout, "---\n"); - while (1) - ; + context_execute_loop(ctx, mod, "start", 0); + 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; }