From debcc68c41e0a56ac1691b3d80764fd79443c4dc Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 15 Nov 2019 16:07:57 +0800 Subject: [PATCH 01/15] esp_common: added a macro to allow call functions using user allocated stack --- components/esp_common/CMakeLists.txt | 1 + .../include/esp_expression_with_stack.h | 35 +++++++++++++++++++ .../src/esp_espression_with_stack_asm.S | 29 +++++++++++++++ .../newlib/test/test_shared_stack_printf.c | 33 +++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 components/esp_common/include/esp_expression_with_stack.h create mode 100644 components/esp_common/src/esp_espression_with_stack_asm.S create mode 100644 components/newlib/test/test_shared_stack_printf.c diff --git a/components/esp_common/CMakeLists.txt b/components/esp_common/CMakeLists.txt index c2b658643..e82222a5f 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 000000000..e2ca47c13 --- /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 000000000..b27834ad0 --- /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 000000000..c072cac73 --- /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)); +} From 98b76617be96f30fb4ac8e3f1cc2b2e4f19c414b Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 15 Nov 2019 16:45:18 +0800 Subject: [PATCH 02/15] test_shared_stack_printf: moved the test stack inside the heap --- .../newlib/test/test_shared_stack_printf.c | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/components/newlib/test/test_shared_stack_printf.c b/components/newlib/test/test_shared_stack_printf.c index c072cac73..6202b6e36 100644 --- a/components/newlib/test/test_shared_stack_printf.c +++ b/components/newlib/test/test_shared_stack_printf.c @@ -4,30 +4,29 @@ #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) +void check_stack(portSTACK_TYPE *sp, portSTACK_TYPE *base_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_ASSERT((intptr_t)task_sp < (intptr_t)base_sp || + (intptr_t)task_sp >= (intptr_t)sp); } TEST_CASE("test printf using shared buffer stack", "[newlib]") { + portSTACK_TYPE *shared_stack = malloc(8192 * sizeof(portSTACK_TYPE)); + portSTACK_TYPE *ext_stack_top = (portSTACK_TYPE *)&shared_stack[0] + + ((sizeof(8192 * sizeof(portSTACK_TYPE))) / + sizeof(portSTACK_TYPE)); + + TEST_ASSERT(shared_stack != NULL); + 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)); + EXECUTE_EXPRESSION_WITH_STACK(printf_lock, ext_stack_top, check_stack(ext_stack_top, shared_stack)); + free(shared_stack); } From 7b90f34c5a4fe4cb59e0ddbc1a86dedd114ffb1e Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 15 Nov 2019 16:49:25 +0800 Subject: [PATCH 03/15] esp_expression_with_stack: renamed macro and functions to have esp_ prefix --- .../esp_common/include/esp_expression_with_stack.h | 10 +++++----- .../esp_common/src/esp_espression_with_stack_asm.S | 12 ++++++------ components/newlib/test/test_shared_stack_printf.c | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/components/esp_common/include/esp_expression_with_stack.h b/components/esp_common/include/esp_expression_with_stack.h index e2ca47c13..4d337f3fd 100644 --- a/components/esp_common/include/esp_expression_with_stack.h +++ b/components/esp_common/include/esp_expression_with_stack.h @@ -10,16 +10,16 @@ * @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) \ +#define ESP_EXECUTE_EXPRESSION_WITH_STACK(lock, stack, expression) \ ({ \ if(lock) { \ uint32_t backup; \ xSemaphoreTake(lock, portMAX_DELAY); \ - switch_stack_enter(stack, &backup); \ + esp_switch_stack_enter(stack, &backup); \ { \ expression; \ } \ - switch_stack_exit(&backup); \ + esp_switch_stack_exit(&backup); \ xSemaphoreGive(lock); \ } \ }) @@ -29,7 +29,7 @@ * 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); +extern void esp_switch_stack_enter(portSTACK_TYPE *stack, uint32_t *backup_stack); +extern void esp_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 index b27834ad0..78e30b9e4 100644 --- a/components/esp_common/src/esp_espression_with_stack_asm.S +++ b/components/esp_common/src/esp_espression_with_stack_asm.S @@ -5,10 +5,10 @@ /** * extern void switch_stack_enter(portSTACK_TYPE *stack, portSTACK_TYPE *backup_stack); */ - .globl switch_stack_enter - .type switch_stack_enter,@function + .globl esp_switch_stack_enter + .type esp_switch_stack_enter,@function .align 4 -switch_stack_enter: +esp_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 */ @@ -19,10 +19,10 @@ switch_stack_enter: /** * extern void switch_stack_exit(portSTACK_TYPE *backup_stack); */ - .globl switch_stack_exit - .type switch_stack_exit,@function + .globl esp_switch_stack_exit + .type esp_switch_stack_exit,@function .align 4 -switch_stack_exit: +esp_switch_stack_exit: entry sp, 0x10 l32i a4, a2, 0 /* recover the original task stack */ mov a1, a4 /* put it on sp register again */ diff --git a/components/newlib/test/test_shared_stack_printf.c b/components/newlib/test/test_shared_stack_printf.c index 6202b6e36..f5f8aabcb 100644 --- a/components/newlib/test/test_shared_stack_printf.c +++ b/components/newlib/test/test_shared_stack_printf.c @@ -26,7 +26,7 @@ TEST_CASE("test printf using shared buffer stack", "[newlib]") TEST_ASSERT(shared_stack != NULL); 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, shared_stack)); + ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, ext_stack_top, printf("Executing this from external stack! \n")); + ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, ext_stack_top, check_stack(ext_stack_top, shared_stack)); free(shared_stack); } From 11266ef05d8395b8fb69a9b4c8cf19acf7d09533 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 15 Nov 2019 16:56:16 +0800 Subject: [PATCH 04/15] expression_with_stack_xtensa: renamed and moved assembly helpes of esp_expression_wit_stack to xtensa component --- components/esp_common/CMakeLists.txt | 1 - components/xtensa/CMakeLists.txt | 1 + .../expression_with_stack_xtensa.S} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename components/{esp_common/src/esp_espression_with_stack_asm.S => xtensa/expression_with_stack_xtensa.S} (100%) diff --git a/components/esp_common/CMakeLists.txt b/components/esp_common/CMakeLists.txt index e82222a5f..c2b658643 100644 --- a/components/esp_common/CMakeLists.txt +++ b/components/esp_common/CMakeLists.txt @@ -7,7 +7,6 @@ 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/xtensa/CMakeLists.txt b/components/xtensa/CMakeLists.txt index 5c335ffdd..6b4d2429c 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -5,6 +5,7 @@ else() set(priv_requires soc freertos) set(srcs "debug_helpers.c" "debug_helpers_asm.S" + "expression_with_stack_xtensa.S" "eri.c" ) diff --git a/components/esp_common/src/esp_espression_with_stack_asm.S b/components/xtensa/expression_with_stack_xtensa.S similarity index 100% rename from components/esp_common/src/esp_espression_with_stack_asm.S rename to components/xtensa/expression_with_stack_xtensa.S From 002f38c7f526ca2fb278c6a75fa00aedfdef16d2 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 15 Nov 2019 17:14:48 +0800 Subject: [PATCH 05/15] expression_with_stack_xtensa: protected switch stacks function to compile only on window ABI supported platform --- .../include/esp_expression_with_stack.h | 14 ++++++ .../xtensa/expression_with_stack_xtensa.S | 45 ++++++++++++++----- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/components/esp_common/include/esp_expression_with_stack.h b/components/esp_common/include/esp_expression_with_stack.h index 4d337f3fd..d23e7e833 100644 --- a/components/esp_common/include/esp_expression_with_stack.h +++ b/components/esp_common/include/esp_expression_with_stack.h @@ -1,3 +1,17 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef __ESP_EXPRESSION_WITH_STACK_H #define __ESP_EXPRESSION_WITH_STACK_H diff --git a/components/xtensa/expression_with_stack_xtensa.S b/components/xtensa/expression_with_stack_xtensa.S index 78e30b9e4..fdac7fada 100644 --- a/components/xtensa/expression_with_stack_xtensa.S +++ b/components/xtensa/expression_with_stack_xtensa.S @@ -1,5 +1,16 @@ -#include -#include +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. .text /** @@ -9,12 +20,17 @@ .type esp_switch_stack_enter,@function .align 4 esp_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 + + #ifndef __XTENSA_CALL0_ABI__ + 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 + #else + #error "this code is written for Window ABI" + #endif /** * extern void switch_stack_exit(portSTACK_TYPE *backup_stack); @@ -23,7 +39,12 @@ esp_switch_stack_enter: .type esp_switch_stack_exit,@function .align 4 esp_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 + + #ifndef __XTENSA_CALL0_ABI__ + entry sp, 0x10 + l32i a4, a2, 0 /* recover the original task stack */ + mov a1, a4 /* put it on sp register again */ + retw + #else + #error "this code is written for Window ABI" + #endif From dfea4196a276ee7250ae2b56db73dd35d15554f4 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 22 Nov 2019 14:28:15 -0300 Subject: [PATCH 06/15] docs: added esp-expression-with-stack on documentation --- .../include/esp_expression_with_stack.h | 13 ++++- docs/Doxyfile | 2 + .../system/esp_expression_with_stack.rst | 58 +++++++++++++++++++ docs/en/api-reference/system/index.rst | 1 + 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 docs/en/api-reference/system/esp_expression_with_stack.rst diff --git a/components/esp_common/include/esp_expression_with_stack.h b/components/esp_common/include/esp_expression_with_stack.h index d23e7e833..f8cc65136 100644 --- a/components/esp_common/include/esp_expression_with_stack.h +++ b/components/esp_common/include/esp_expression_with_stack.h @@ -39,11 +39,18 @@ }) /** - * These functions are intended to be use by the macro above, and - * Should never be called directly, otherwise crashes could - * occur + * @brief Changes CPU sp-register to use another stack space and save the previous one + * @param stack Caller allocated stack pointer + * @param backup_stack Pointer to a place to save the current stack + * @note Application must not call this function directly */ extern void esp_switch_stack_enter(portSTACK_TYPE *stack, uint32_t *backup_stack); + +/** + * @brief Restores the previous CPU sp-register + * @param backup_stack Pointer to the place where stack was saved + * @note Application must not call this function directly + */ extern void esp_switch_stack_exit(uint32_t *backup_stack); #endif \ No newline at end of file diff --git a/docs/Doxyfile b/docs/Doxyfile index c880f3b68..a56f13cf4 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -223,6 +223,8 @@ INPUT = \ ../../components/esp_common/include/esp_freertos_hooks.h \ ## Inter-Processor Call ../../components/esp_common/include/esp_ipc.h \ + ## Call Function with External stack + ../../components/esp_common/include/esp_expression_with_stack.h \ ## Over The Air Updates (OTA) ../../components/app_update/include/esp_ota_ops.h \ ## ESP HTTPS OTA diff --git a/docs/en/api-reference/system/esp_expression_with_stack.rst b/docs/en/api-reference/system/esp_expression_with_stack.rst new file mode 100644 index 000000000..ed12dc444 --- /dev/null +++ b/docs/en/api-reference/system/esp_expression_with_stack.rst @@ -0,0 +1,58 @@ +Call function with external stack +================================= + +Overview +-------- + +A given function can be executed with a user allocated stack space +which is independent of current task stack, this mechanism can be +used to save stack space wasted by tasks which call a common function +with intensive stack usage such as `printf`. The given function can +be called inside the macro :cpp:func:`ESP_EXECUTE_EXPRESSION_WITH_STACK` +it will redirect the target function to be executed using the space +allocated by the user. + +Usage +----- + +:cpp:func:`ESP_EXECUTE_EXPRESSION_WITH_STACK` takes three arguments, +a mutex object allocated by the caller, which is used to protect if +the same function shares its allocated stack, a pointer to the top +of stack used to that fuction, and the function itself, note the +function is passed extactly in the same way as do when you call +it on a regular way. + +The usage may looks like the code below: + +.. code-block:: c + + //Let's suppose we wanting to call printf using a separated stack space + //allowing app to reduce its stack size. + void app_main() + { + //Allocate a stack buffer, from heap or as a static form: + portSTACK_TYPE *shared_stack = malloc(8192 * sizeof(portSTACK_TYPE)); + + //points to the top of stack, that is it the last word of allocated buffer: + portSTACK_TYPE *ext_stack_top = (portSTACK_TYPE *)&shared_stack[0] + + ((sizeof(8192 * sizeof(portSTACK_TYPE))) / + sizeof(portSTACK_TYPE)); + + //Allocate a mutex to protect its usage: + SemaphoreHandle_t printf_lock = xSemaphoreCreateMutex(); + + //Call the desired function using the macro helper: + ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, + ext_stack_top, + printf("Executing this from external stack! \n")); + free(shared_stack); + } + +.. _esp-call-with-stack-basic_usage: + +API Reference +------------- + +.. include:: /_build/inc/esp_expression_with_stack.inc + + diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 8d0a659e2..13fbaf0fa 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -18,6 +18,7 @@ System API High Resolution Timer Himem (large external SPI RAM) API Inter-Processor Call + Call function with external stack Interrupt Allocation Logging Miscellaneous System APIs From 88dd15c80645debcea34ea72066defc82f0bfe04 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 22 Nov 2019 14:46:05 -0300 Subject: [PATCH 07/15] docs: synchronized the contents of en with cn folders adding the esp-expression-with-stack documentation --- docs/zh_CN/api-reference/system/esp_expression_with_stack.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/zh_CN/api-reference/system/esp_expression_with_stack.rst diff --git a/docs/zh_CN/api-reference/system/esp_expression_with_stack.rst b/docs/zh_CN/api-reference/system/esp_expression_with_stack.rst new file mode 100644 index 000000000..ee9cb17b2 --- /dev/null +++ b/docs/zh_CN/api-reference/system/esp_expression_with_stack.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/system/esp_expression_with_stack.rst \ No newline at end of file From 5e18cd4e13cf948921343335829d99bb9d2a336f Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Tue, 26 Nov 2019 16:31:56 -0300 Subject: [PATCH 08/15] esp_expression_with_stack: added watchpoint on stack parameter before use it --- .../include/esp_expression_with_stack.h | 18 ++++++++++++++---- .../newlib/test/test_shared_stack_printf.c | 4 ++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/components/esp_common/include/esp_expression_with_stack.h b/components/esp_common/include/esp_expression_with_stack.h index f8cc65136..f97137042 100644 --- a/components/esp_common/include/esp_expression_with_stack.h +++ b/components/esp_common/include/esp_expression_with_stack.h @@ -17,22 +17,32 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" +#include "esp_debug_helpers.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 stack Pointer to user alocated stack + * @param stack_size Size of current stack in bytes * @param expression Expression or function to be executed using the stack */ -#define ESP_EXECUTE_EXPRESSION_WITH_STACK(lock, stack, expression) \ +#define ESP_EXECUTE_EXPRESSION_WITH_STACK(lock, stack, stack_size, expression) \ ({ \ - if(lock) { \ + if(lock && stack && stack_size) { \ uint32_t backup; \ + int watchpoint_place=(int)stack; \ + portSTACK_TYPE *top_of_stack = &stack[0] + \ + (sizeof(stack_size * sizeof(portSTACK_TYPE)) / \ + sizeof(portSTACK_TYPE)); \ + watchpoint_place=(watchpoint_place+31)&(~31); \ xSemaphoreTake(lock, portMAX_DELAY); \ - esp_switch_stack_enter(stack, &backup); \ + esp_set_watchpoint(2, (char*)watchpoint_place, 32, ESP_WATCHPOINT_STORE);\ + esp_switch_stack_enter(top_of_stack, &backup); \ { \ expression; \ } \ + esp_clear_watchpoint(2); \ esp_switch_stack_exit(&backup); \ xSemaphoreGive(lock); \ } \ diff --git a/components/newlib/test/test_shared_stack_printf.c b/components/newlib/test/test_shared_stack_printf.c index f5f8aabcb..b99959f71 100644 --- a/components/newlib/test/test_shared_stack_printf.c +++ b/components/newlib/test/test_shared_stack_printf.c @@ -26,7 +26,7 @@ TEST_CASE("test printf using shared buffer stack", "[newlib]") TEST_ASSERT(shared_stack != NULL); SemaphoreHandle_t printf_lock = xSemaphoreCreateMutex(); - ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, ext_stack_top, printf("Executing this from external stack! \n")); - ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, ext_stack_top, check_stack(ext_stack_top, shared_stack)); + ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,printf("Executing printf from external stack! \n")); + ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,check_stack(ext_stack_top, shared_stack)); free(shared_stack); } From 674cb1c21ce111916da00db5045b4736e0262f68 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Wed, 27 Nov 2019 13:52:27 -0300 Subject: [PATCH 09/15] esp_expression_with_stack: added fake stack frame plus some cleanup on main macro --- .../include/esp_expression_with_stack.h | 19 ++++++++------- components/xtensa/CMakeLists.txt | 3 ++- .../xtensa/expression_with_stack_xtensa.c | 24 +++++++++++++++++++ ...a.S => expression_with_stack_xtensa_asm.S} | 6 +++++ 4 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 components/xtensa/expression_with_stack_xtensa.c rename components/xtensa/{expression_with_stack_xtensa.S => expression_with_stack_xtensa_asm.S} (90%) diff --git a/components/esp_common/include/esp_expression_with_stack.h b/components/esp_common/include/esp_expression_with_stack.h index f97137042..afaf43d0f 100644 --- a/components/esp_common/include/esp_expression_with_stack.h +++ b/components/esp_common/include/esp_expression_with_stack.h @@ -31,30 +31,33 @@ ({ \ if(lock && stack && stack_size) { \ uint32_t backup; \ - int watchpoint_place=(int)stack; \ - portSTACK_TYPE *top_of_stack = &stack[0] + \ - (sizeof(stack_size * sizeof(portSTACK_TYPE)) / \ - sizeof(portSTACK_TYPE)); \ - watchpoint_place=(watchpoint_place+31)&(~31); \ xSemaphoreTake(lock, portMAX_DELAY); \ - esp_set_watchpoint(2, (char*)watchpoint_place, 32, ESP_WATCHPOINT_STORE);\ + StackType_t *top_of_stack = esp_switch_stack_setup(stack, stack_size);\ esp_switch_stack_enter(top_of_stack, &backup); \ { \ expression; \ } \ - esp_clear_watchpoint(2); \ esp_switch_stack_exit(&backup); \ xSemaphoreGive(lock); \ } \ }) +/** + * @brief Fill stack frame with CPU-specifics value before use + * @param stack Caller allocated stack pointer + * @param stack_size Size of stack in bytes + * @return New pointer to the top of stack + * @note Application must not call this function directly + */ +StackType_t * esp_switch_stack_setup(StackType_t *stack, size_t stack_size); + /** * @brief Changes CPU sp-register to use another stack space and save the previous one * @param stack Caller allocated stack pointer * @param backup_stack Pointer to a place to save the current stack * @note Application must not call this function directly */ -extern void esp_switch_stack_enter(portSTACK_TYPE *stack, uint32_t *backup_stack); +extern void esp_switch_stack_enter(StackType_t *stack, uint32_t *backup_stack); /** * @brief Restores the previous CPU sp-register diff --git a/components/xtensa/CMakeLists.txt b/components/xtensa/CMakeLists.txt index 6b4d2429c..a360fb2ed 100644 --- a/components/xtensa/CMakeLists.txt +++ b/components/xtensa/CMakeLists.txt @@ -5,7 +5,8 @@ else() set(priv_requires soc freertos) set(srcs "debug_helpers.c" "debug_helpers_asm.S" - "expression_with_stack_xtensa.S" + "expression_with_stack_xtensa_asm.S" + "expression_with_stack_xtensa.c" "eri.c" ) diff --git a/components/xtensa/expression_with_stack_xtensa.c b/components/xtensa/expression_with_stack_xtensa.c new file mode 100644 index 000000000..c24470971 --- /dev/null +++ b/components/xtensa/expression_with_stack_xtensa.c @@ -0,0 +1,24 @@ +#include +#include +#include + +StackType_t * esp_switch_stack_setup(StackType_t *stack, size_t stack_size) +{ + int watchpoint_place = (((int)stack + 31) & ~31); + StackType_t *top_of_stack = (StackType_t *)&stack[0] + + (sizeof(stack_size * sizeof(StackType_t)) / + sizeof(StackType_t)); + + //Align stack to a 16byte boundary, as required by CPU specific: + top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 1) - + ALIGNUP(0x10, sizeof(XtSolFrame) )) & + ~0xf); + + //Fake stack frame to do not break the backtrace + XtSolFrame *frame = (XtSolFrame *)top_of_stack; + frame->a0 = 0; + frame->a1 = (UBaseType_t)top_of_stack; + + esp_set_watchpoint(2, (char*)watchpoint_place, 32, ESP_WATCHPOINT_STORE); + return top_of_stack; +} \ No newline at end of file diff --git a/components/xtensa/expression_with_stack_xtensa.S b/components/xtensa/expression_with_stack_xtensa_asm.S similarity index 90% rename from components/xtensa/expression_with_stack_xtensa.S rename to components/xtensa/expression_with_stack_xtensa_asm.S index fdac7fada..01d5034da 100644 --- a/components/xtensa/expression_with_stack_xtensa.S +++ b/components/xtensa/expression_with_stack_xtensa_asm.S @@ -12,7 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + + .extern esp_clear_watchpoint .text + /** * extern void switch_stack_enter(portSTACK_TYPE *stack, portSTACK_TYPE *backup_stack); */ @@ -42,6 +46,8 @@ esp_switch_stack_exit: #ifndef __XTENSA_CALL0_ABI__ entry sp, 0x10 + movi a6, 2 + call4 esp_clear_watchpoint /* clear the watchpoint before releasing stack */ l32i a4, a2, 0 /* recover the original task stack */ mov a1, a4 /* put it on sp register again */ retw From fab50ccf7c952658e22c401147a482e70fc74edf Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Wed, 27 Nov 2019 14:51:09 -0300 Subject: [PATCH 10/15] expression_with_stack_xtensa: call esp watchpoint function using a callx4 to fix range problem of call4 function --- components/xtensa/expression_with_stack_xtensa_asm.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/xtensa/expression_with_stack_xtensa_asm.S b/components/xtensa/expression_with_stack_xtensa_asm.S index 01d5034da..106eb6f9c 100644 --- a/components/xtensa/expression_with_stack_xtensa_asm.S +++ b/components/xtensa/expression_with_stack_xtensa_asm.S @@ -47,7 +47,8 @@ esp_switch_stack_exit: #ifndef __XTENSA_CALL0_ABI__ entry sp, 0x10 movi a6, 2 - call4 esp_clear_watchpoint /* clear the watchpoint before releasing stack */ + movi a4, esp_clear_watchpoint + callx4 a4 /* clear the watchpoint before releasing stack */ l32i a4, a2, 0 /* recover the original task stack */ mov a1, a4 /* put it on sp register again */ retw From 8bfb8e885eb747d3138907acc3814be18a3dbbba Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Wed, 4 Dec 2019 10:51:56 -0300 Subject: [PATCH 11/15] docs: update on expression with stack api usage regard the stack setup. --- docs/en/api-reference/system/esp_expression_with_stack.rst | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/en/api-reference/system/esp_expression_with_stack.rst b/docs/en/api-reference/system/esp_expression_with_stack.rst index ed12dc444..cf77b2683 100644 --- a/docs/en/api-reference/system/esp_expression_with_stack.rst +++ b/docs/en/api-reference/system/esp_expression_with_stack.rst @@ -33,17 +33,12 @@ The usage may looks like the code below: //Allocate a stack buffer, from heap or as a static form: portSTACK_TYPE *shared_stack = malloc(8192 * sizeof(portSTACK_TYPE)); - //points to the top of stack, that is it the last word of allocated buffer: - portSTACK_TYPE *ext_stack_top = (portSTACK_TYPE *)&shared_stack[0] + - ((sizeof(8192 * sizeof(portSTACK_TYPE))) / - sizeof(portSTACK_TYPE)); - //Allocate a mutex to protect its usage: SemaphoreHandle_t printf_lock = xSemaphoreCreateMutex(); //Call the desired function using the macro helper: ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, - ext_stack_top, + shared_stack, printf("Executing this from external stack! \n")); free(shared_stack); } From e4fb50e6f3f5dff93dd46cad687f8f0877192c13 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Wed, 4 Dec 2019 11:25:02 -0300 Subject: [PATCH 12/15] expression_with_stack_xtensa: fixed stack pointer to avoid its overflow on heap block metadata. --- .../newlib/test/test_shared_stack_printf.c | 17 +++++++---------- .../xtensa/expression_with_stack_xtensa.c | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/components/newlib/test/test_shared_stack_printf.c b/components/newlib/test/test_shared_stack_printf.c index b99959f71..5daa248a2 100644 --- a/components/newlib/test/test_shared_stack_printf.c +++ b/components/newlib/test/test_shared_stack_printf.c @@ -8,25 +8,22 @@ #include "esp_expression_with_stack.h" //makes sure this is not the task stack... -void check_stack(portSTACK_TYPE *sp, portSTACK_TYPE *base_sp) +void another_external_stack_function(void) { - StaticTask_t *hacked_task = (StaticTask_t *)xTaskGetCurrentTaskHandle(); - portSTACK_TYPE *task_sp = (portSTACK_TYPE *)hacked_task->pxDummy1; - TEST_ASSERT((intptr_t)task_sp < (intptr_t)base_sp || - (intptr_t)task_sp >= (intptr_t)sp); + //We can even use Freertos resources inside of this context. + vTaskDelay(100); + printf("Executing this another printf inside a function with external stack"); } TEST_CASE("test printf using shared buffer stack", "[newlib]") { portSTACK_TYPE *shared_stack = malloc(8192 * sizeof(portSTACK_TYPE)); - portSTACK_TYPE *ext_stack_top = (portSTACK_TYPE *)&shared_stack[0] + - ((sizeof(8192 * sizeof(portSTACK_TYPE))) / - sizeof(portSTACK_TYPE)); TEST_ASSERT(shared_stack != NULL); SemaphoreHandle_t printf_lock = xSemaphoreCreateMutex(); - ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,printf("Executing printf from external stack! \n")); - ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,check_stack(ext_stack_top, shared_stack)); + ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,printf("Executing this printf from external stack! \n")); + ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,another_external_stack_function()); + vSemaphoreDelete(printf_lock); free(shared_stack); } diff --git a/components/xtensa/expression_with_stack_xtensa.c b/components/xtensa/expression_with_stack_xtensa.c index c24470971..310d92448 100644 --- a/components/xtensa/expression_with_stack_xtensa.c +++ b/components/xtensa/expression_with_stack_xtensa.c @@ -10,7 +10,7 @@ StackType_t * esp_switch_stack_setup(StackType_t *stack, size_t stack_size) sizeof(StackType_t)); //Align stack to a 16byte boundary, as required by CPU specific: - top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 1) - + top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 31) - ALIGNUP(0x10, sizeof(XtSolFrame) )) & ~0xf); From f0e82311a5243d6424baee2b52f77ceb11ceabae Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 20 Dec 2019 13:23:47 -0300 Subject: [PATCH 13/15] esp_expression_with_stack: fix wrong top of stack calculation plus documentation update --- components/xtensa/expression_with_stack_xtensa.c | 3 +-- docs/en/api-reference/system/esp_expression_with_stack.rst | 5 +++-- docs/en/api-reference/system/index.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/xtensa/expression_with_stack_xtensa.c b/components/xtensa/expression_with_stack_xtensa.c index 310d92448..6f9cf4ca3 100644 --- a/components/xtensa/expression_with_stack_xtensa.c +++ b/components/xtensa/expression_with_stack_xtensa.c @@ -6,8 +6,7 @@ StackType_t * esp_switch_stack_setup(StackType_t *stack, size_t stack_size) { int watchpoint_place = (((int)stack + 31) & ~31); StackType_t *top_of_stack = (StackType_t *)&stack[0] + - (sizeof(stack_size * sizeof(StackType_t)) / - sizeof(StackType_t)); + ((stack_size * sizeof(StackType_t)) / sizeof(StackType_t)); //Align stack to a 16byte boundary, as required by CPU specific: top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 31) - diff --git a/docs/en/api-reference/system/esp_expression_with_stack.rst b/docs/en/api-reference/system/esp_expression_with_stack.rst index cf77b2683..343d2fe0d 100644 --- a/docs/en/api-reference/system/esp_expression_with_stack.rst +++ b/docs/en/api-reference/system/esp_expression_with_stack.rst @@ -19,7 +19,7 @@ Usage a mutex object allocated by the caller, which is used to protect if the same function shares its allocated stack, a pointer to the top of stack used to that fuction, and the function itself, note the -function is passed extactly in the same way as do when you call +function is passed exactly in the same way as do when you call it on a regular way. The usage may looks like the code below: @@ -40,7 +40,8 @@ The usage may looks like the code below: ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack, printf("Executing this from external stack! \n")); - free(shared_stack); + vSemaphoreDelete(printf_lock); + free(shared_stack); } .. _esp-call-with-stack-basic_usage: diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 13fbaf0fa..65f06522c 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -18,7 +18,7 @@ System API High Resolution Timer Himem (large external SPI RAM) API Inter-Processor Call - Call function with external stack + Call function with external stack Interrupt Allocation Logging Miscellaneous System APIs From d1b76d13bb4dfcc46b898a4a2d8decf2298d1194 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 20 Dec 2019 13:27:30 -0300 Subject: [PATCH 14/15] exp_expression_with_stack: added check for null pointer after obtaining a mutex in test --- components/esp_common/include/esp_expression_with_stack.h | 2 +- components/newlib/test/test_shared_stack_printf.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/esp_common/include/esp_expression_with_stack.h b/components/esp_common/include/esp_expression_with_stack.h index afaf43d0f..3aa12a253 100644 --- a/components/esp_common/include/esp_expression_with_stack.h +++ b/components/esp_common/include/esp_expression_with_stack.h @@ -29,7 +29,7 @@ */ #define ESP_EXECUTE_EXPRESSION_WITH_STACK(lock, stack, stack_size, expression) \ ({ \ - if(lock && stack && stack_size) { \ + if (lock && stack && stack_size) { \ uint32_t backup; \ xSemaphoreTake(lock, portMAX_DELAY); \ StackType_t *top_of_stack = esp_switch_stack_setup(stack, stack_size);\ diff --git a/components/newlib/test/test_shared_stack_printf.c b/components/newlib/test/test_shared_stack_printf.c index 5daa248a2..9b020f581 100644 --- a/components/newlib/test/test_shared_stack_printf.c +++ b/components/newlib/test/test_shared_stack_printf.c @@ -22,6 +22,8 @@ TEST_CASE("test printf using shared buffer stack", "[newlib]") TEST_ASSERT(shared_stack != NULL); SemaphoreHandle_t printf_lock = xSemaphoreCreateMutex(); + TEST_ASSERT_NOT_NULL(printf_lock); + ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,printf("Executing this printf from external stack! \n")); ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock, shared_stack,8192,another_external_stack_function()); vSemaphoreDelete(printf_lock); From 785abfeb82fb2c7f8aba4778d981d7c09cb47348 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Fri, 20 Dec 2019 13:30:30 -0300 Subject: [PATCH 15/15] docs: update esp_expresstion_with_stack code snippet to check shared stack and mutex allocation. --- docs/en/api-reference/system/esp_expression_with_stack.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/api-reference/system/esp_expression_with_stack.rst b/docs/en/api-reference/system/esp_expression_with_stack.rst index 343d2fe0d..dd7b994f2 100644 --- a/docs/en/api-reference/system/esp_expression_with_stack.rst +++ b/docs/en/api-reference/system/esp_expression_with_stack.rst @@ -32,9 +32,11 @@ The usage may looks like the code below: { //Allocate a stack buffer, from heap or as a static form: portSTACK_TYPE *shared_stack = malloc(8192 * sizeof(portSTACK_TYPE)); + assert(shared_stack != NULL); //Allocate a mutex to protect its usage: SemaphoreHandle_t printf_lock = xSemaphoreCreateMutex(); + assert(printf_lock != NULL); //Call the desired function using the macro helper: ESP_EXECUTE_EXPRESSION_WITH_STACK(printf_lock,