1 /*
2  * SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
7  */
8 /*
9  * FreeRTOS Kernel V10.4.3
10  * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of
13  * this software and associated documentation files (the "Software"), to deal in
14  * the Software without restriction, including without limitation the rights to
15  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
16  * the Software, and to permit persons to whom the Software is furnished to do so,
17  * subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in all
20  * copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
25  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
26  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28  *
29  * http://www.FreeRTOS.org
30  * http://aws.amazon.com/freertos
31  *
32  * 1 tab == 4 spaces!
33  */
34 
35 #ifndef PORTMACRO_H
36 #define PORTMACRO_H
37 
38 #ifndef __ASSEMBLER__
39 
40 #include "sdkconfig.h"
41 #include <stdint.h>
42 #include <stdlib.h>
43 #include <stdbool.h>
44 #include <stdio.h>
45 #include "spinlock.h"
46 #include "soc/interrupt_core0_reg.h"
47 #include "esp_macros.h"
48 #include "esp_attr.h"
49 #include "esp_cpu.h"
50 #include "esp_rom_sys.h"
51 #include "esp_heap_caps.h"
52 #include "esp_system.h"             /* required by esp_get_...() functions in portable.h. [refactor-todo] Update portable.h */
53 #include "esp_newlib.h"
54 #include "rtthread.h"
55 
56 /* [refactor-todo] These includes are not directly used in this file. They are kept into to prevent a breaking change. Remove these. */
57 #include <limits.h>
58 
59 /* [refactor-todo] introduce a port wrapper function to avoid including esp_timer.h into the public header */
60 #if CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
61 #include "esp_timer.h"
62 #endif
63 
64 #ifdef __cplusplus
65 extern "C" {
66 #endif
67 
68 /* --------------------------------------------------- Port Types ------------------------------------------------------
69  * - Port specific types.
70  * - The settings in this file configure FreeRTOS correctly for the given hardware and compiler.
71  * - These settings should not be altered.
72  * - The port types must come first as they are used further down in this file
73  * ------------------------------------------------------------------------------------------------------------------ */
74 
75 #define portCHAR char
76 #define portFLOAT float
77 #define portDOUBLE double
78 #define portLONG long
79 #define portSHORT short
80 #define portSTACK_TYPE rt_ubase_t
81 #define portBASE_TYPE rt_base_t
82 
83 typedef portSTACK_TYPE StackType_t;
84 typedef rt_base_t BaseType_t;
85 typedef rt_ubase_t UBaseType_t;
86 typedef rt_tick_t TickType_t;
87 #define portMAX_DELAY (TickType_t) RT_TICK_MAX
88 
89 struct rt_semaphore_wrapper
90 {
91     struct rt_semaphore sem;
92     rt_uint16_t max_value;
93 };
94 
95 
96 /* ----------------------------------------------- Port Configurations -------------------------------------------------
97  * - Configurations values supplied by each port
98  * - Required by FreeRTOS
99  * ------------------------------------------------------------------------------------------------------------------ */
100 
101 #define portTICK_PERIOD_MS              ((TickType_t) (1000 / configTICK_RATE_HZ))
102 #define portBYTE_ALIGNMENT              RT_ALIGN_SIZE
103 #define portNOP() __asm volatile        (" nop ")
104 
105 
106 /* ---------------------------------------------- Forward Declarations -------------------------------------------------
107  * - Forward declarations of all the port functions and macros need to implement the FreeRTOS porting interface
108  * - These must come before definition/declaration of the FreeRTOS porting interface
109  * ------------------------------------------------------------------------------------------------------------------ */
110 
111 // --------------------- Interrupts ------------------------
112 
113 /**
114  * @brief Checks if the current core is in an ISR context
115  *
116  * - ISR context consist of Low/Mid priority ISR, or time tick ISR
117  * - High priority ISRs aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
118  *
119  * @note [refactor-todo] Check if this should be inlined
120  * @return
121  *  - pdTRUE if in ISR
122  *  - pdFALSE otherwise
123  */
124 BaseType_t xPortInIsrContext(void);
125 
126 /**
127  * @brief Check if in ISR context from High priority ISRs
128  *
129  * - Called from High priority ISR
130  * - Checks if the previous context (before high priority interrupt) was in ISR context (meaning low/med priority)
131  *
132  * @note [refactor-todo] Check if this should be inlined
133  * @return
134  *  - pdTRUE if in previous in ISR context
135  *  - pdFALSE otherwise
136  */
137 BaseType_t xPortInterruptedFromISRContext(void);
138 
139 /* ---------------------- Spinlocks ------------------------
140  - Spinlocks added to match API with SMP FreeRTOS. Single core RISC-V does not need spin locks
141  - Because single core does not have a primitive spinlock data type, we have to implement one here
142  * @note [refactor-todo] Refactor critical section API so that this is no longer required
143  * ------------------------------------------------------ */
144 
145 /**
146  * @brief Spinlock object
147  * Owner:
148  *  - Set to 0 if uninitialized
149  *  - Set to portMUX_FREE_VAL when free
150  *  - Set to CORE_ID_REGVAL_PRO or CORE_ID_REGVAL_AP when locked
151  *  - Any other value indicates corruption
152  * Count:
153  *  - 0 if unlocked
154  *  - Recursive count if locked
155  *
156  * @note Not a true spinlock as single core RISC-V does not have atomic compare and set instruction
157  * @note Keep portMUX_INITIALIZER_UNLOCKED in sync with this struct
158  */
159 typedef struct {
160     uint32_t owner;
161     uint32_t count;
162 } portMUX_TYPE;
163 /**< Spinlock initializer */
164 #define portMUX_INITIALIZER_UNLOCKED {                      \
165             .owner = portMUX_FREE_VAL,                      \
166             .count = 0,                                     \
167         }
168 #define portMUX_FREE_VAL                    SPINLOCK_FREE           /**< Spinlock is free. [refactor-todo] check if this is still required */
169 #define portMUX_NO_TIMEOUT                  SPINLOCK_WAIT_FOREVER   /**< When passed for 'timeout_cycles', spin forever if necessary. [refactor-todo] check if this is still required */
170 #define portMUX_TRY_LOCK                    SPINLOCK_NO_WAIT        /**< Try to acquire the spinlock a single time only. [refactor-todo] check if this is still required */
171 #define portMUX_INITIALIZE(mux)    ({ \
172     (mux)->owner = portMUX_FREE_VAL; \
173     (mux)->count = 0; \
174 })
175 
176 // ------------------ Critical Sections --------------------
177 
178 /**
179  * @brief Enter a critical section
180  *
181  * - Simply disable interrupts
182  * - Can be nested
183  */
184 void vPortEnterCritical(void);
185 
186 /**
187  * @brief Exit a critical section
188  *
189  * - Reenables interrupts
190  * - Can be nested
191  */
192 void vPortExitCritical(void);
193 
194 // ---------------------- Yielding -------------------------
195 
196 /**
197  * @brief Perform a context switch from a task
198  *
199  * @note [refactor-todo] The rest of ESP-IDF should call taskYield() instead
200  */
201 #define vPortYield(void)    rt_thread_yield()
202 
203 /**
204  * @brief Checks if the current core can yield
205  *
206  * - A core cannot yield if its in an ISR or in a critical section
207  *
208  * @note [refactor-todo] See if this can be separated from port macro
209  * @note [refactor-todo] Check if this function should be renamed (due to bool return type)
210  * @return true Core can yield
211  * @return false Core cannot yield
212  */
213 FORCE_INLINE_ATTR bool xPortCanYield(void);
214 
215 // ----------------------- System --------------------------
216 
217 /**
218  * @brief Get the tick rate per second
219  *
220  * @note [refactor-todo] make this inline
221  * @note [refactor-todo] Check if this function should be renamed (due to uint return type)
222  * @return uint32_t Tick rate in Hz
223  */
224 uint32_t xPortGetTickRateHz(void);
225 
226 /**
227  * @brief Set a watchpoint to watch the last 32 bytes of the stack
228  *
229  * Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack watchpoint
230  * around.
231  *
232  * @param pxStackStart Pointer to the start of the stack
233  */
234 void vPortSetStackWatchpoint(void *pxStackStart);
235 
236 /**
237  * @brief Get the current core's ID
238  *
239  * @note Added to be compatible with SMP API
240  * @note [refactor-todo] IDF should call a FreeRTOS like macro instead of port function directly
241  * @return BaseType_t Core ID
242  */
xPortGetCoreID(void)243 FORCE_INLINE_ATTR BaseType_t xPortGetCoreID(void)
244 {
245     return (BaseType_t) esp_cpu_get_core_id();
246 }
247 
248 
249 
250 /* ------------------------------------------- FreeRTOS Porting Interface ----------------------------------------------
251  * - Contains all the mappings of the macros required by FreeRTOS
252  * - Most come after forward declare as porting macros map to declared functions
253  * - Maps to forward declared functions
254  * ------------------------------------------------------------------------------------------------------------------ */
255 
256 // --------------------- Interrupts ------------------------
257 
258 #define portDISABLE_INTERRUPTS()            vPortEnterCritical()
259 #define portENABLE_INTERRUPTS()             vPortExitCritical()
260 #define portSET_INTERRUPT_MASK_FROM_ISR()                       rt_hw_interrupt_disable()
261 #define portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedStatusValue)   rt_hw_interrupt_enable(uxSavedStatusValue)
262 
263 // ------------------ Critical Sections --------------------
264 
265 #define portENTER_CRITICAL(mux)                 {(void)mux;  vPortEnterCritical();}
266 #define portEXIT_CRITICAL(mux)                  {(void)mux;  vPortExitCritical();}
267 #define portTRY_ENTER_CRITICAL(mux, timeout)    ({  \
268     (void)mux; (void)timeout;                       \
269     vPortEnterCritical();                           \
270     BaseType_t ret = pdPASS;                        \
271     ret;                                            \
272 })
273 //In single-core RISC-V, we can use the same critical section API
274 #define portENTER_CRITICAL_ISR(mux)                 portENTER_CRITICAL(mux)
275 #define portEXIT_CRITICAL_ISR(mux)                  portEXIT_CRITICAL(mux)
276 #define portTRY_ENTER_CRITICAL_ISR(mux, timeout)    portTRY_ENTER_CRITICAL(mux, timeout)
277 
278 /* [refactor-todo] on RISC-V, both ISR and non-ISR cases result in the same call. We can redefine this macro */
279 #define portENTER_CRITICAL_SAFE(mux)    ({  \
280     if (xPortInIsrContext()) {              \
281         portENTER_CRITICAL_ISR(mux);        \
282     } else {                                \
283         portENTER_CRITICAL(mux);            \
284     }                                       \
285 })
286 #define portEXIT_CRITICAL_SAFE(mux)     ({  \
287     if (xPortInIsrContext()) {              \
288         portEXIT_CRITICAL_ISR(mux);         \
289     } else {                                \
290         portEXIT_CRITICAL(mux);             \
291     }                                       \
292 })
293 #define portTRY_ENTER_CRITICAL_SAFE(mux, timeout)   portENTER_CRITICAL_SAFE(mux, timeout)
294 
295 // ---------------------- Yielding -------------------------
296 
297 #define portYIELD() rt_thread_yield()
298 #define portYIELD_FROM_ISR_NO_ARG() rt_thread_yield()
299 #define portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken) ({ \
300     if (xHigherPriorityTaskWoken == pdTRUE) { \
301         rt_thread_yield(); \
302     } \
303 })
304 /**
305  * @note    The macro below could be used when passing a single argument, or without any argument,
306  *          it was developed to support both usages of portYIELD inside of an ISR. Any other usage form
307  *          might result in undesired behavior
308  */
309 #if defined(__cplusplus) && (__cplusplus >  201703L)
310 #define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG __VA_OPT__(,) __VA_ARGS__)(__VA_ARGS__)
311 #else
312 #define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG, ##__VA_ARGS__)(__VA_ARGS__)
313 #endif
314 
315 
316 
317 /* --------------------------------------------- Inline Implementations ------------------------------------------------
318  * - Implementation of inline functions of the forward declares
319  * - Should come after forward declare and FreeRTOS Porting interface, as implementation may use both.
320  * - For implementation of non-inlined functions, see port.c, port_common.c, or other assembly files
321  * ------------------------------------------------------------------------------------------------------------------ */
322 
323 // --------------------- Interrupts ------------------------
324 
325 // ---------------------- Yielding -------------------------
326 
xPortCanYield(void)327 FORCE_INLINE_ATTR bool xPortCanYield(void)
328 {
329     rt_base_t level = rt_interrupt_get_nest();
330     return (level == 0);
331 }
332 
333 #define FREERTOS_PRIORITY_TO_RTTHREAD(priority)    ( configMAX_PRIORITIES - 1 - ( priority ) )
334 #define RTTHREAD_PRIORITY_TO_FREERTOS(priority)    ( RT_THREAD_PRIORITY_MAX - 1 - ( priority ) )
335 /* Use this macro to calculate the buffer size when allocating a queue statically
336  * To ensure the buffer can fit the desired number of messages
337  */
338 #define QUEUE_BUFFER_SIZE( uxQueueLength, uxItemSize )  ( ( RT_ALIGN( uxItemSize, RT_ALIGN_SIZE ) + sizeof( void * ) ) * uxQueueLength )
339 
340 BaseType_t rt_err_to_freertos(rt_err_t rt_err);
341 
342 #if CONFIG_APPTRACE_SV_ENABLE
343 extern int xPortSwitchFlag;
344 #define os_task_switch_is_pended(_cpu_) (xPortSwitchFlag)
345 #else
346 #define os_task_switch_is_pended(_cpu_) (false)
347 #endif
348 
349 #ifdef __cplusplus
350 }
351 #endif
352 
353 #endif //__ASSEMBLER__
354 
355 #endif /* PORTMACRO_H */
356