From 6acfad81c0c0ac4b14b8476dcae347b4ff97f8fc Mon Sep 17 00:00:00 2001 From: Fabian Herb <fabian@herb-clan.de> Date: Wed, 14 Jul 2021 00:05:03 +0200 Subject: [PATCH 1/3] RISC-V: Load xISRStackTop at single spot --- portable/GCC/RISC-V/portASM.S | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/portable/GCC/RISC-V/portASM.S b/portable/GCC/RISC-V/portASM.S index a6b6442b2d8..07ca625d8f6 100644 --- a/portable/GCC/RISC-V/portASM.S +++ b/portable/GCC/RISC-V/portASM.S @@ -162,9 +162,13 @@ freertos_risc_v_trap_handler: csrr a1, mepc test_if_asynchronous: - srli a2, a0, __riscv_xlen - 1 /* MSB of mcause is 1 if handing an asynchronous interrupt - shift to LSB to clear other bits. */ - beq a2, x0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */ + bltz a0, 1f /* MSB is set for async, i.e. it is negative. */ + addi a1, a1, 4 /* Synchronous so updated exception return address to the instruction after the instruction that generated the exeption. */ +1: store_x a1, 0( sp ) /* Asynch so save unmodified exception return address. */ + load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ + bgez a0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */ + handle_asynchronous: @@ -210,7 +214,6 @@ handle_asynchronous: #endif /* __riscv_xlen == 64 */ - load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ jal xTaskIncrementTick beqz a0, processed_source /* Don't switch context if incrementing tick didn't unblock a task. */ jal vTaskSwitchContext @@ -222,18 +225,13 @@ handle_asynchronous: #endif /* portasmHAS_MTIME */ - load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ jal portasmHANDLE_INTERRUPT /* Jump to the interrupt handler if there is no CLINT or if there is a CLINT and it has been determined that an external interrupt is pending. */ j processed_source handle_synchronous: - addi a1, a1, 4 /* Synchronous so updated exception return address to the instruction after the instruction that generated the exeption. */ - store_x a1, 0( sp ) /* Save updated exception return address. */ - test_if_environment_call: li t0, 11 /* 11 == environment call. */ bne a0, t0, is_exception /* Not an M environment call, so some other exception. */ - load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ jal vTaskSwitchContext j processed_source From 0216a64a548c895d0efec8e6930873066500aa95 Mon Sep 17 00:00:00 2001 From: Fabian Herb <fabian@herb-clan.de> Date: Wed, 14 Jul 2021 19:44:23 +0200 Subject: [PATCH 2/3] RISC-V xPortIsInsideInterrupt --- portable/GCC/RISC-V/port.c | 4 ++++ portable/GCC/RISC-V/portASM.S | 14 ++++++++++++++ portable/GCC/RISC-V/portmacro.h | 5 +++++ 3 files changed, 23 insertions(+) diff --git a/portable/GCC/RISC-V/port.c b/portable/GCC/RISC-V/port.c index cde63fdb1cc..1e616b093c1 100644 --- a/portable/GCC/RISC-V/port.c +++ b/portable/GCC/RISC-V/port.c @@ -95,6 +95,10 @@ const size_t uxTimerIncrementsForOneTick = ( size_t ) ( ( configCPU_CLOCK_HZ ) / uint32_t const ullMachineTimerCompareRegisterBase = configMTIMECMP_BASE_ADDRESS; volatile uint64_t * pullMachineTimerCompareRegister = NULL; +/* Counts the number of times the interrupt service routine was entered, but not +exited. Used for xPortIsInsideInterrupt(). */ +uint32_t ulIsrEnterCount = 0; + /* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task stack checking. A problem in the ISR stack will trigger an assert, not call the stack overflow hook function (because the stack overflow hook is specific to a diff --git a/portable/GCC/RISC-V/portASM.S b/portable/GCC/RISC-V/portASM.S index 07ca625d8f6..6062ec3cdf9 100644 --- a/portable/GCC/RISC-V/portASM.S +++ b/portable/GCC/RISC-V/portASM.S @@ -114,6 +114,7 @@ at the top of this file. */ .extern uxTimerIncrementsForOneTick /* size_t type so 32-bit on 32-bit core and 64-bits on 64-bit core. */ .extern xISRStackTop .extern portasmHANDLE_INTERRUPT +.extern ulIsrEnterCount /*-----------------------------------------------------------*/ @@ -166,6 +167,13 @@ test_if_asynchronous: addi a1, a1, 4 /* Synchronous so updated exception return address to the instruction after the instruction that generated the exeption. */ 1: store_x a1, 0( sp ) /* Asynch so save unmodified exception return address. */ + + /* ulIsrEnterCount++: */ + la t0, ulIsrEnterCount /* t0 = &ulIsrEnterCount */ + lw t1, 0(t0) /* t1 = *t0 */ + addi t1, t1, 1 /* t1++ */ + sw t1, 0(t0) /* *t0 = t1 */ + load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ bgez a0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */ @@ -246,6 +254,12 @@ as_yet_unhandled: j as_yet_unhandled processed_source: + /* ulIsrEnterCount--: */ + la t0, ulIsrEnterCount /* t0 = &ulIsrEnterCount */ + lw t1, 0(t0) /* t1 = *t0 */ + addi t1, t1, -1 /* t1-- */ + sw t1, 0(t0) /* *t0 = t1 */ + load_x t1, pxCurrentTCB /* Load pxCurrentTCB. */ load_x sp, 0( t1 ) /* Read sp from first TCB member. */ diff --git a/portable/GCC/RISC-V/portmacro.h b/portable/GCC/RISC-V/portmacro.h index fe93dc28c84..a36a2452931 100644 --- a/portable/GCC/RISC-V/portmacro.h +++ b/portable/GCC/RISC-V/portmacro.h @@ -34,6 +34,8 @@ extern "C" { #endif +#include <stdint.h> + /*----------------------------------------------------------- * Port specific definitions. * @@ -95,6 +97,9 @@ extern void vTaskSwitchContext( void ); #define portYIELD() __asm volatile( "ecall" ); #define portEND_SWITCHING_ISR( xSwitchRequired ) do { if( xSwitchRequired ) vTaskSwitchContext(); } while( 0 ) #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) + +extern uint32_t ulIsrEnterCount; +#define xPortIsInsideInterrupt() (ulIsrEnterCount > 0) /*-----------------------------------------------------------*/ From 71bcfbc17014c24a2c23e2a494aba201cbf23a22 Mon Sep 17 00:00:00 2001 From: Fabian Herb <fabian@herb-clan.de> Date: Thu, 15 Jul 2021 20:11:44 +0200 Subject: [PATCH 3/3] RISC-V interrupt nesting support --- portable/GCC/RISC-V/port.c | 2 +- portable/GCC/RISC-V/portASM.S | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/portable/GCC/RISC-V/port.c b/portable/GCC/RISC-V/port.c index 1e616b093c1..c1ba77afaeb 100644 --- a/portable/GCC/RISC-V/port.c +++ b/portable/GCC/RISC-V/port.c @@ -96,7 +96,7 @@ uint32_t const ullMachineTimerCompareRegisterBase = configMTIMECMP_BASE_ADDRESS; volatile uint64_t * pullMachineTimerCompareRegister = NULL; /* Counts the number of times the interrupt service routine was entered, but not -exited. Used for xPortIsInsideInterrupt(). */ +exited. Used for interrupt nesting and xPortIsInsideInterrupt(). */ uint32_t ulIsrEnterCount = 0; /* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task diff --git a/portable/GCC/RISC-V/portASM.S b/portable/GCC/RISC-V/portASM.S index 6062ec3cdf9..1c7bce70264 100644 --- a/portable/GCC/RISC-V/portASM.S +++ b/portable/GCC/RISC-V/portASM.S @@ -156,9 +156,6 @@ freertos_risc_v_trap_handler: portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to save any registers unique to the RISC-V implementation. */ - load_x t0, pxCurrentTCB /* Load pxCurrentTCB. */ - store_x sp, 0( t0 ) /* Write sp to first TCB member. */ - csrr a0, mcause csrr a1, mepc @@ -171,10 +168,13 @@ test_if_asynchronous: /* ulIsrEnterCount++: */ la t0, ulIsrEnterCount /* t0 = &ulIsrEnterCount */ lw t1, 0(t0) /* t1 = *t0 */ - addi t1, t1, 1 /* t1++ */ - sw t1, 0(t0) /* *t0 = t1 */ - + addi t2, t1, 1 /* t2 = t1 + 1 */ + sw t2, 0(t0) /* *t0 = t2 */ + bnez t1, 2f /* If the interrupt is not nesting: */ + load_x t0, pxCurrentTCB /* Load pxCurrentTCB. */ + store_x sp, 0( t0 ) /* Write sp to first TCB member. */ load_x sp, xISRStackTop /* Switch to ISR stack before function call. */ +2: bgez a0, handle_synchronous /* Branch past interrupt handing if not asynchronous. */ @@ -259,10 +259,10 @@ processed_source: lw t1, 0(t0) /* t1 = *t0 */ addi t1, t1, -1 /* t1-- */ sw t1, 0(t0) /* *t0 = t1 */ - + bnez t1, 1f /* If we are going to exit from ISR on the last (or only) nesting level: */ load_x t1, pxCurrentTCB /* Load pxCurrentTCB. */ load_x sp, 0( t1 ) /* Read sp from first TCB member. */ - +1: /* Load mret with the address of the next instruction in the task to run next. */ load_x t0, 0( sp ) csrw mepc, t0