Skip to content

Commit 39a3d54

Browse files
committed
Merge branch 'fix/freertos_port_assert_in_isr_bug_v5.3' into 'release/v5.3'
fix(freertos): Incorrect assert in FreeRTOS port layer when not in ISR context (v5.3) See merge request espressif/esp-idf!32372
2 parents d434587 + d2e4722 commit 39a3d54

File tree

10 files changed

+102
-13
lines changed

10 files changed

+102
-13
lines changed

components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ typedef spinlock_t portMUX_TYPE; /**< Spi
113113

114114
BaseType_t xPortCheckIfInISR(void);
115115

116+
/**
117+
* @brief Assert if in ISR context
118+
*
119+
* - Asserts on xPortCheckIfInISR() internally
120+
*/
121+
void vPortAssertIfInISR(void);
122+
116123
// ------------------ Critical Sections --------------------
117124

118125
#if ( configNUMBER_OF_CORES > 1 )
@@ -187,6 +194,15 @@ void vPortTCBPreDeleteHook( void *pxTCB );
187194
#define portENABLE_INTERRUPTS() vPortClearInterruptMask(1)
188195
#define portRESTORE_INTERRUPTS(x) vPortClearInterruptMask(x)
189196

197+
/**
198+
* @brief Assert if in ISR context
199+
*
200+
* TODO: Enable once ISR safe version of vTaskEnter/ExitCritical() is implemented
201+
* for single-core SMP FreeRTOS Kernel. (IDF-10540)
202+
*/
203+
// #define portASSERT_IF_IN_ISR() vPortAssertIfInISR()
204+
205+
190206
// ------------------ Critical Sections --------------------
191207

192208
#if ( configNUMBER_OF_CORES > 1 )

components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ BaseType_t xPortCheckIfInISR(void)
168168
return uxInterruptNesting;
169169
}
170170

171+
void vPortAssertIfInISR(void)
172+
{
173+
/* Assert if the interrupt nesting count is > 0 */
174+
configASSERT(xPortCheckIfInISR() == 0);
175+
}
176+
171177
// ------------------ Critical Sections --------------------
172178

173179
#if ( configNUMBER_OF_CORES > 1 )
@@ -373,7 +379,7 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u
373379
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
374380
static void vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters)
375381
{
376-
__asm__ volatile(".cfi_undefined ra"); // tell to debugger that it's outermost (inital) frame
382+
__asm__ volatile(".cfi_undefined ra"); // tell to debugger that it's outermost (initial) frame
377383
extern void __attribute__((noreturn)) panic_abort(const char *details);
378384
static char DRAM_ATTR msg[80] = "FreeRTOS: FreeRTOS Task \"\0";
379385
pxCode(pvParameters);
@@ -440,7 +446,7 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
440446
HIGH ADDRESS
441447
|---------------------------| <- pxTopOfStack on entry
442448
| TLS Variables |
443-
| ------------------------- | <- Start of useable stack
449+
| ------------------------- | <- Start of usable stack
444450
| Starting stack frame |
445451
| ------------------------- | <- pxTopOfStack on return (which is the tasks current SP)
446452
| | |

components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ typedef spinlock_t portMUX_TYPE; /**< Spi
9595

9696
BaseType_t xPortCheckIfInISR(void);
9797

98+
/**
99+
* @brief Assert if in ISR context
100+
*
101+
* - Asserts on xPortCheckIfInISR() internally
102+
*/
103+
void vPortAssertIfInISR(void);
104+
98105
// ------------------ Critical Sections --------------------
99106

100107
UBaseType_t uxPortEnterCriticalFromISR( void );
@@ -161,6 +168,14 @@ void vPortTCBPreDeleteHook( void *pxTCB );
161168
#define portSET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK()
162169
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK()
163170

171+
/**
172+
* @brief Assert if in ISR context
173+
*
174+
* TODO: Enable once ISR safe version of vTaskEnter/ExitCritical() is implemented
175+
* for single-core SMP FreeRTOS Kernel. (IDF-10540)
176+
*/
177+
// #define portASSERT_IF_IN_ISR() vPortAssertIfInISR()
178+
164179
/*
165180
Note: XTOS_RESTORE_INTLEVEL() will overwrite entire PS register on XEA2. So we need to set the value of the INTLEVEL field ourselves
166181
*/

components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ BaseType_t xPortEnterCriticalTimeout(portMUX_TYPE *lock, BaseType_t timeout)
139139
void vPortExitCriticalIDF(portMUX_TYPE *lock)
140140
{
141141
/* This function may be called in a nested manner. Therefore, we only need
142-
* to reenable interrupts if this is the last call to exit the critical. We
142+
* to re-enable interrupts if this is the last call to exit the critical. We
143143
* can use the nesting count to determine whether this is the last exit call.
144144
*/
145145
spinlock_release(lock);
@@ -204,6 +204,12 @@ BaseType_t xPortCheckIfInISR(void)
204204
return ret;
205205
}
206206

207+
void vPortAssertIfInISR(void)
208+
{
209+
/* Assert if the interrupt nesting count is > 0 */
210+
configASSERT(xPortCheckIfInISR() == 0);
211+
}
212+
207213
// ------------------ Critical Sections --------------------
208214

209215
#if ( configNUMBER_OF_CORES > 1 )
@@ -614,7 +620,7 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
614620
| Coproc Save Area | (CPSA MUST BE FIRST)
615621
| ------------------------- |
616622
| TLS Variables |
617-
| ------------------------- | <- Start of useable stack
623+
| ------------------------- | <- Start of usable stack
618624
| Starting stack frame |
619625
| ------------------------- | <- pxTopOfStack on return (which is the tasks current SP)
620626
| | |

components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ void vPortClearInterruptMaskFromISR(UBaseType_t prev_int_level);
166166
*/
167167
BaseType_t xPortInIsrContext(void);
168168

169+
/**
170+
* @brief Assert if in ISR context
171+
*
172+
* - Asserts on xPortInIsrContext() internally
173+
*/
174+
void vPortAssertIfInISR(void);
175+
169176
/**
170177
* @brief Check if in ISR context from High priority ISRs
171178
*
@@ -478,6 +485,11 @@ void vPortTCBPreDeleteHook( void *pxTCB );
478485
#define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetInterruptMaskFromISR()
479486
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(prev_level) vPortClearInterruptMaskFromISR(prev_level)
480487

488+
/**
489+
* @brief Assert if in ISR context
490+
*/
491+
#define portASSERT_IF_IN_ISR() vPortAssertIfInISR()
492+
481493
/**
482494
* @brief Used by FreeRTOS functions to call the correct version of critical section API
483495
*/

components/freertos/FreeRTOS-Kernel/portable/riscv/port.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,12 @@ BaseType_t xPortInIsrContext(void)
462462
#endif /* (configNUM_CORES > 1) */
463463
}
464464

465+
void vPortAssertIfInISR(void)
466+
{
467+
/* Assert if the interrupt nesting count is > 0 */
468+
configASSERT(xPortInIsrContext() == 0);
469+
}
470+
465471
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
466472
{
467473
/* Return the interrupt nesting counter for this core */

components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,9 @@ typedef uint32_t TickType_t;
141141
BaseType_t xPortInIsrContext(void);
142142

143143
/**
144-
* @brief Asserts if in ISR context
144+
* @brief Assert if in ISR context
145145
*
146146
* - Asserts on xPortInIsrContext() internally
147-
*
148-
* @note [refactor-todo] Check if this API is still required
149-
* @note [refactor-todo] Check if this should be inlined
150147
*/
151148
void vPortAssertIfInISR(void);
152149

@@ -427,6 +424,9 @@ void vPortTCBPreDeleteHook( void *pxTCB );
427424
#define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetInterruptMaskFromISR()
428425
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(prev_level) vPortClearInterruptMaskFromISR(prev_level)
429426

427+
/**
428+
* @brief Assert if in ISR context
429+
*/
430430
#define portASSERT_IF_IN_ISR() vPortAssertIfInISR()
431431

432432
/**

components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
* SPDX-License-Identifier: MIT
1010
*
11-
* SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD
11+
* SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD
1212
*
1313
* Permission is hereby granted, free of charge, to any person obtaining a copy of
1414
* this software and associated documentation files (the "Software"), to deal in
@@ -395,7 +395,7 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
395395
| Coproc Save Area | (CPSA MUST BE FIRST)
396396
| ------------------------- |
397397
| TLS Variables |
398-
| ------------------------- | <- Start of useable stack
398+
| ------------------------- | <- Start of usable stack
399399
| Starting stack frame |
400400
| ------------------------- | <- pxTopOfStack on return (which is the tasks current SP)
401401
| | |
@@ -449,7 +449,8 @@ BaseType_t xPortInIsrContext(void)
449449

450450
void vPortAssertIfInISR(void)
451451
{
452-
configASSERT(xPortInIsrContext());
452+
/* Assert if the interrupt nesting count is > 0 */
453+
configASSERT(xPortInIsrContext() == 0);
453454
}
454455

455456
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
@@ -489,7 +490,7 @@ BaseType_t __attribute__((optimize("-O3"))) xPortEnterCriticalTimeout(portMUX_TY
489490
void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux)
490491
{
491492
/* This function may be called in a nested manner. Therefore, we only need
492-
* to reenable interrupts if this is the last call to exit the critical. We
493+
* to re-enable interrupts if this is the last call to exit the critical. We
493494
* can use the nesting count to determine whether this is the last exit call.
494495
*/
495496
spinlock_release(mux);

components/freertos/test_apps/freertos/port/test_freertos_isinisrcontext.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -58,3 +58,20 @@ TEST_CASE("xPortInIsrContext test", "[freertos]")
5858
}
5959

6060
#endif
61+
62+
#if !CONFIG_FREERTOS_SMP // TODO: Enable when IDF-10540 is fixed
63+
64+
static void testint_assert(void)
65+
{
66+
esp_rom_printf("INT!\n");
67+
portASSERT_IF_IN_ISR();
68+
}
69+
70+
TEST_CASE("port must assert if in ISR context", "[ignore]")
71+
{
72+
esp_err_t err = esp_register_freertos_tick_hook_for_cpu(testint_assert, xPortGetCoreID());
73+
TEST_ASSERT_EQUAL_HEX32(ESP_OK, err);
74+
vTaskDelay(100 / portTICK_PERIOD_MS);
75+
esp_deregister_freertos_tick_hook_for_cpu(testint_assert, xPortGetCoreID());
76+
}
77+
#endif // !CONFIG_FREERTOS_SMP

components/freertos/test_apps/freertos/pytest_freertos.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,13 @@ def test_task_notify_wait_too_high_index_fails(dut: Dut) -> None:
3939
dut.expect('assert failed: xTaskGenericNotifyWait', timeout=5)
4040
dut.expect('uxIndexToWait < [0-9]+', timeout=5)
4141
dut.expect_exact('Rebooting...')
42+
43+
44+
@pytest.mark.supported_targets
45+
@pytest.mark.generic
46+
@pytest.mark.parametrize('config', ['default'], indirect=True)
47+
def test_port_must_assert_in_isr(dut: Dut) -> None:
48+
dut.expect_exact('Press ENTER to see the list of tests.')
49+
dut.write('\"port must assert if in ISR context\"')
50+
dut.expect('assert failed: vPortAssertIfInISR', timeout=5)
51+
dut.expect_exact('Rebooting...')

0 commit comments

Comments
 (0)