expression_with_stack_xtensa.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <esp_expression_with_stack.h>
  15. #include <freertos/xtensa_rtos.h>
  16. #include <freertos/xtensa_context.h>
  17. #include <setjmp.h>
  18. #include <string.h>
  19. #include "freertos/FreeRTOS.h"
  20. #include "freertos/portmacro.h"
  21. StackType_t *xtensa_shared_stack;
  22. shared_stack_function xtensa_shared_stack_callback;
  23. jmp_buf xtensa_shared_stack_env;
  24. bool xtensa_shared_stack_function_done = false;
  25. static portMUX_TYPE xtensa_shared_stack_spinlock = portMUX_INITIALIZER_UNLOCKED;
  26. static void *current_task_stack = NULL;
  27. extern void esp_shared_stack_invoke_function(void);
  28. static void esp_switch_stack_setup(StackType_t *stack, size_t stack_size)
  29. {
  30. //We need also to tweak current task stackpointer to avoid erroneous
  31. //stack overflow indication, so fills the stack with freertos known pattern:
  32. memset(stack, 0xa5U, stack_size * sizeof(StackType_t));
  33. StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
  34. //Then put the fake stack inside of TCB:
  35. current_task_stack = current->pxDummy6;
  36. current->pxDummy6 = (void *)stack;
  37. StackType_t *top_of_stack = stack + stack_size;
  38. //Align stack to a 16byte boundary, as required by CPU specific:
  39. top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 16) & ~0xf));
  40. #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
  41. vPortSetStackWatchpoint(stack);
  42. #endif
  43. xtensa_shared_stack = top_of_stack;
  44. }
  45. void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size_t stack_size, shared_stack_function function)
  46. {
  47. assert(lock);
  48. assert(stack);
  49. assert(stack_size > 0 && stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE);
  50. assert(function);
  51. xSemaphoreTake(lock, portMAX_DELAY);
  52. portENTER_CRITICAL(&xtensa_shared_stack_spinlock);
  53. xtensa_shared_stack_function_done = false;
  54. esp_switch_stack_setup(stack, stack_size);
  55. xtensa_shared_stack_callback = function;
  56. portEXIT_CRITICAL(&xtensa_shared_stack_spinlock);
  57. setjmp(xtensa_shared_stack_env);
  58. if(!xtensa_shared_stack_function_done) {
  59. esp_shared_stack_invoke_function();
  60. }
  61. portENTER_CRITICAL(&xtensa_shared_stack_spinlock);
  62. StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
  63. //Restore current task stack:
  64. current->pxDummy6 = (StackType_t *)current_task_stack;
  65. vPortSetStackWatchpoint(current->pxDummy6);
  66. portEXIT_CRITICAL(&xtensa_shared_stack_spinlock);
  67. xSemaphoreGive(lock);
  68. }