/ components / xtensa / expression_with_stack_xtensa.c
expression_with_stack_xtensa.c
 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  
15  #include <esp_expression_with_stack.h>
16  #include <freertos/xtensa_rtos.h>
17  #include <freertos/xtensa_context.h>
18  #include <setjmp.h>
19  #include <string.h>
20  
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  
28  extern void esp_shared_stack_invoke_function(void);
29  
30  static void esp_switch_stack_setup(StackType_t *stack, size_t stack_size)
31  {
32  #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
33      esp_clear_watchpoint(1);
34      uint32_t watchpoint_place = ((uint32_t)stack + 32) & ~0x1f ;
35  #endif    
36      //We need also to tweak current task stackpointer to avoid erroneous
37      //stack overflow indication, so fills the stack with freertos known pattern:
38      memset(stack, 0xa5U, stack_size * sizeof(StackType_t));
39  
40      StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
41      //Then put the fake stack inside of TCB:
42      current_task_stack = current->pxDummy6;
43      current->pxDummy6 = (void *)stack;
44  
45      StackType_t *top_of_stack = stack + stack_size;
46  
47      //Align stack to a 16byte boundary, as required by CPU specific:
48      top_of_stack =  (StackType_t *)(((UBaseType_t)(top_of_stack - 16) & ~0xf));
49  
50  #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
51      esp_set_watchpoint(1, (uint8_t *)watchpoint_place, 32, ESP_WATCHPOINT_STORE);    
52  #endif
53  
54      xtensa_shared_stack = top_of_stack;
55  }
56  
57  
58  void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size_t stack_size, shared_stack_function function)
59  {
60      assert(lock);
61      assert(stack);
62      assert(stack_size > 0 && stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE);
63      assert(function);
64  
65      xSemaphoreTake(lock, portMAX_DELAY);
66      portENTER_CRITICAL(&xtensa_shared_stack_spinlock);
67      xtensa_shared_stack_function_done = false;
68      esp_switch_stack_setup(stack, stack_size);
69      xtensa_shared_stack_callback = function;
70      portEXIT_CRITICAL(&xtensa_shared_stack_spinlock);
71      
72      setjmp(xtensa_shared_stack_env);    
73      if(!xtensa_shared_stack_function_done) {
74          esp_shared_stack_invoke_function();             
75      }
76  
77      portENTER_CRITICAL(&xtensa_shared_stack_spinlock);
78      StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
79  
80      //Restore current task stack:
81      current->pxDummy6 = (StackType_t *)current_task_stack;
82      vPortSetStackWatchpoint(current->pxDummy6);
83      portEXIT_CRITICAL(&xtensa_shared_stack_spinlock);
84  
85      xSemaphoreGive(lock);
86  }