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