1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <esp_expression_with_stack.h>
8 #include <riscv/rvruntime-frames.h>
9 #include <string.h>
10 #include "freertos/FreeRTOS.h"
11 #include "freertos/portmacro.h"
12 
13 static portMUX_TYPE shared_stack_spinlock = portMUX_INITIALIZER_UNLOCKED;
14 static void *current_task_stack = NULL;
15 
16 extern void esp_shared_stack_invoke_function(shared_stack_function function, void *stack);
17 
esp_switch_stack_setup(StackType_t * stack,size_t stack_size)18 static StackType_t *esp_switch_stack_setup(StackType_t *stack, size_t stack_size)
19 {
20     //We need also to tweak current task stackpointer to avoid erroneous
21     //stack overflow indication, so fills the stack with freertos known pattern:
22     memset(stack, 0xa5U, stack_size * sizeof(StackType_t));
23 
24     StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
25     //Then put the fake stack inside of TCB:
26     current_task_stack = current->pxDummy6;
27     current->pxDummy6 = (void *)stack;
28 
29     StackType_t *top_of_stack = stack + stack_size;
30 
31     //Align stack to a 16byte boundary, as required by CPU specific:
32     top_of_stack =  (StackType_t *)(((UBaseType_t)(top_of_stack - 16) & ~0xf));
33     StackType_t *adjusted_top_of_stack = top_of_stack - RV_STK_FRMSZ;
34 
35 #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
36     vPortSetStackWatchpoint(stack);
37 #endif
38     return ((StackType_t *)adjusted_top_of_stack);
39 }
40 
41 
esp_execute_shared_stack_function(SemaphoreHandle_t lock,void * stack,size_t stack_size,shared_stack_function function)42 void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size_t stack_size, shared_stack_function function)
43 {
44     assert(lock);
45     assert(stack);
46     assert(stack_size > 0 && stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE);
47     assert(function);
48 
49     xSemaphoreTake(lock, portMAX_DELAY);
50     portENTER_CRITICAL(&shared_stack_spinlock);
51     stack = esp_switch_stack_setup(stack, stack_size);
52     portEXIT_CRITICAL(&shared_stack_spinlock);
53 
54     esp_shared_stack_invoke_function(function, stack);
55 
56     portENTER_CRITICAL(&shared_stack_spinlock);
57     StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle();
58 
59     //Restore current task stack:
60     current->pxDummy6 = (StackType_t *)current_task_stack;
61 #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
62     vPortSetStackWatchpoint(current->pxDummy6);
63 #endif
64     portEXIT_CRITICAL(&shared_stack_spinlock);
65 
66     xSemaphoreGive(lock);
67 }
68