diff --git a/components/esp_common/CMakeLists.txt b/components/esp_common/CMakeLists.txt index c2b6586437..e82222a5f4 100644 --- a/components/esp_common/CMakeLists.txt +++ b/components/esp_common/CMakeLists.txt @@ -7,6 +7,7 @@ if(BOOTLOADER_BUILD) else() # Regular app build set(srcs "src/dbg_stubs.c" + "src/esp_espression_with_stack_asm.S" "src/esp_err_to_name.c" "src/esp_timer.c" "src/ets_timer_legacy.c" diff --git a/components/esp_common/include/esp_expression_with_stack.h b/components/esp_common/include/esp_expression_with_stack.h new file mode 100644 index 0000000000..e2ca47c13f --- /dev/null +++ b/components/esp_common/include/esp_expression_with_stack.h @@ -0,0 +1,35 @@ +#ifndef __ESP_EXPRESSION_WITH_STACK_H +#define __ESP_EXPRESSION_WITH_STACK_H + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +/** + * @brief Executes a 1-line expression with a application alocated stack + * @param lock Mutex object to protect in case of shared stack + * @param stack Pointer to user alocated stack, it must points to its top + * @param expression Expression or function to be executed using the stack + */ +#define EXECUTE_EXPRESSION_WITH_STACK(lock, stack, expression) \ +({ \ + if(lock) { \ + uint32_t backup; \ + xSemaphoreTake(lock, portMAX_DELAY); \ + switch_stack_enter(stack, &backup); \ + { \ + expression; \ + } \ + switch_stack_exit(&backup); \ + xSemaphoreGive(lock); \ + } \ +}) + +/** + * These functions are intended to be use by the macro above, and + * Should never be called directly, otherwise crashes could + * occur + */ +extern void switch_stack_enter(portSTACK_TYPE *stack, uint32_t *backup_stack); +extern void switch_stack_exit(uint32_t *backup_stack); + +#endif \ No newline at end of file diff --git a/components/esp_common/src/esp_espression_with_stack_asm.S b/components/esp_common/src/esp_espression_with_stack_asm.S new file mode 100644 index 0000000000..b27834ad0f --- /dev/null +++ b/components/esp_common/src/esp_espression_with_stack_asm.S @@ -0,0 +1,29 @@ +#include +#include + + .text +/** + * extern void switch_stack_enter(portSTACK_TYPE *stack, portSTACK_TYPE *backup_stack); + */ + .globl switch_stack_enter + .type switch_stack_enter,@function + .align 4 +switch_stack_enter: + entry sp, 0x10 + mov a4, a1 + s32i a4, a3, 0 /* on a3 there is a safe place to save the current stack */ + l32i a4, a2, 0 /* obtains the user allocated stack buffer */ + mov a1, a4 /* sp register now contains caller specified stack */ + retw + +/** + * extern void switch_stack_exit(portSTACK_TYPE *backup_stack); + */ + .globl switch_stack_exit + .type switch_stack_exit,@function + .align 4 +switch_stack_exit: + entry sp, 0x10 + l32i a4, a2, 0 /* recover the original task stack */ + mov a1, a4 /* put it on sp register again */ + retw \ No newline at end of file diff --git a/components/newlib/test/test_shared_stack_printf.c b/components/newlib/test/test_shared_stack_printf.c new file mode 100644 index 0000000000..c072cac732 --- /dev/null +++ b/components/newlib/test/test_shared_stack_printf.c @@ -0,0 +1,33 @@ +#include +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "sdkconfig.h" +#include "soc/rtc.h" +#include "esp_system.h" +#include "test_utils.h" +#include "esp_expression_with_stack.h" +#include + +static portSTACK_TYPE shared_stack[8192]; +static portSTACK_TYPE *ext_stack_top = (portSTACK_TYPE *)&shared_stack[0] + (sizeof(shared_stack) / sizeof(portSTACK_TYPE)); + +//makes sure this is not the task stack... +void check_stack(portSTACK_TYPE *sp) +{ + StaticTask_t *hacked_task = (StaticTask_t *)xTaskGetCurrentTaskHandle(); + portSTACK_TYPE *task_sp = (portSTACK_TYPE *)hacked_task->pxDummy1; + TEST_ASSERT((intptr_t)sp <= (intptr_t)ext_stack_top); + TEST_ASSERT((intptr_t)sp >= (intptr_t)&shared_stack); + + TEST_ASSERT((intptr_t)task_sp < (intptr_t)&shared_stack || + (intptr_t)task_sp >= (intptr_t)&ext_stack_top); +} + +TEST_CASE("test printf using shared buffer stack", "[newlib]") +{ + SemaphoreHandle_t printf_lock = xSemaphoreCreateMutex(); + EXECUTE_EXPRESSION_WITH_STACK(printf_lock, ext_stack_top, printf("Executing this from external stack! \n")); + EXECUTE_EXPRESSION_WITH_STACK(printf_lock, ext_stack_top, check_stack(ext_stack_top)); +}