Skip to content

Commit 3804387

Browse files
jimmyzhekartben
authored andcommitted
arch: riscv: handle interrupt level for CLIC
CLIC supports mintstatus.MIL (RO) and mcause.MPIL (RW) for the current interrupt level and the previous interrut level before a trap. Each ISR must execute MRET to set mcause.MPIL back to mintstatus.MIL. This commit introduces CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL to handle mcause.MPIL for interrupt preemption in nested ISR, and uses CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL to ensure ISR always switch out with MRET. e.g. With CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL=n, a context-switch in ISR may skip MRET in this flow: IRQ -> _isr_wrapper -> z_riscv_switch() -> retrun to arch_switch() Signed-off-by: Jimmy Zheng <jimmyzhe@andestech.com>
1 parent e783f69 commit 3804387

File tree

5 files changed

+37
-0
lines changed

5 files changed

+37
-0
lines changed

arch/riscv/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,20 @@ config RISCV_HAS_PLIC
220220
config RISCV_HAS_CLIC
221221
bool
222222
depends on RISCV_PRIVILEGED
223+
select RISCV_ALWAYS_SWITCH_THROUGH_ECALL if MULTITHREADING
224+
select CLIC_SUPPORT_INTERRUPT_LEVEL if !NRFX_CLIC
223225
help
224226
Does the SOC provide support for a Core-Local Interrupt Controller (CLIC).
225227

228+
config CLIC_SUPPORT_INTERRUPT_LEVEL
229+
bool
230+
depends on RISCV_HAS_CLIC
231+
help
232+
For CLIC implementations with extended interrupt level, where
233+
higher-numbered interrupt levels can preempt lower-numbered interrupt
234+
levels. This option handles interrupt level in ISR to ensure proper
235+
nested ISR exits.
236+
226237
config RISCV_SOC_EXCEPTION_FROM_IRQ
227238
bool
228239
help

arch/riscv/core/isr.S

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ SECTION_FUNC(exception.entry, _isr_wrapper)
198198
sr s0, __struct_arch_esf_s0_OFFSET(sp)
199199
get_current_cpu s0
200200

201+
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
202+
/* Save mcause register */
203+
csrr t0, mcause
204+
sr t0, __struct_arch_esf_mcause_OFFSET(sp)
205+
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
206+
201207
/* Save MEPC register */
202208
csrr t0, mepc
203209
sr t0, __struct_arch_esf_mepc_OFFSET(sp)
@@ -737,6 +743,13 @@ fp_trap_exit:
737743
/* Restore MEPC and MSTATUS registers */
738744
lr t0, __struct_arch_esf_mepc_OFFSET(sp)
739745
lr t2, __struct_arch_esf_mstatus_OFFSET(sp)
746+
747+
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
748+
/* Restore MCAUSE register for previous interrupt level. */
749+
lr t1, __struct_arch_esf_mcause_OFFSET(sp)
750+
csrw mcause, t1
751+
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
752+
740753
csrw mepc, t0
741754
csrw mstatus, t2
742755

arch/riscv/core/offsets/offsets.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ GEN_OFFSET_STRUCT(arch_esf, a7);
112112
GEN_OFFSET_STRUCT(arch_esf, mepc);
113113
GEN_OFFSET_STRUCT(arch_esf, mstatus);
114114

115+
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
116+
GEN_OFFSET_STRUCT(arch_esf, mcause);
117+
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
118+
115119
GEN_OFFSET_STRUCT(arch_esf, s0);
116120

117121
#ifdef CONFIG_USERSPACE

arch/riscv/core/thread.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
110110
SOC_ISR_STACKING_ESR_INIT;
111111
#endif
112112

113+
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
114+
/* Clear the previous interrupt level. */
115+
stack_init->mcause = 0;
116+
#endif
117+
113118
thread->callee_saved.sp = (unsigned long)stack_init;
114119

115120
/* where to go when returning from z_riscv_switch() */

include/zephyr/arch/riscv/exception.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ struct arch_esf {
7878
unsigned long a7; /* function argument */
7979
#endif /* !CONFIG_RISCV_ISA_RV32E */
8080

81+
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
82+
unsigned long mcause; /* machine cause register */
83+
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
84+
8185
unsigned long mepc; /* machine exception program counter */
8286
unsigned long mstatus; /* machine status register */
8387

0 commit comments

Comments
 (0)