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