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>
This commit is contained in:
parent
e783f69ebf
commit
3804387350
5 changed files with 37 additions and 0 deletions
|
@ -220,9 +220,20 @@ config RISCV_HAS_PLIC
|
||||||
config RISCV_HAS_CLIC
|
config RISCV_HAS_CLIC
|
||||||
bool
|
bool
|
||||||
depends on RISCV_PRIVILEGED
|
depends on RISCV_PRIVILEGED
|
||||||
|
select RISCV_ALWAYS_SWITCH_THROUGH_ECALL if MULTITHREADING
|
||||||
|
select CLIC_SUPPORT_INTERRUPT_LEVEL if !NRFX_CLIC
|
||||||
help
|
help
|
||||||
Does the SOC provide support for a Core-Local Interrupt Controller (CLIC).
|
Does the SOC provide support for a Core-Local Interrupt Controller (CLIC).
|
||||||
|
|
||||||
|
config CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||||
|
bool
|
||||||
|
depends on RISCV_HAS_CLIC
|
||||||
|
help
|
||||||
|
For CLIC implementations with extended interrupt level, where
|
||||||
|
higher-numbered interrupt levels can preempt lower-numbered interrupt
|
||||||
|
levels. This option handles interrupt level in ISR to ensure proper
|
||||||
|
nested ISR exits.
|
||||||
|
|
||||||
config RISCV_SOC_EXCEPTION_FROM_IRQ
|
config RISCV_SOC_EXCEPTION_FROM_IRQ
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
|
|
@ -198,6 +198,12 @@ SECTION_FUNC(exception.entry, _isr_wrapper)
|
||||||
sr s0, __struct_arch_esf_s0_OFFSET(sp)
|
sr s0, __struct_arch_esf_s0_OFFSET(sp)
|
||||||
get_current_cpu s0
|
get_current_cpu s0
|
||||||
|
|
||||||
|
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||||
|
/* Save mcause register */
|
||||||
|
csrr t0, mcause
|
||||||
|
sr t0, __struct_arch_esf_mcause_OFFSET(sp)
|
||||||
|
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
|
||||||
|
|
||||||
/* Save MEPC register */
|
/* Save MEPC register */
|
||||||
csrr t0, mepc
|
csrr t0, mepc
|
||||||
sr t0, __struct_arch_esf_mepc_OFFSET(sp)
|
sr t0, __struct_arch_esf_mepc_OFFSET(sp)
|
||||||
|
@ -737,6 +743,13 @@ fp_trap_exit:
|
||||||
/* Restore MEPC and MSTATUS registers */
|
/* Restore MEPC and MSTATUS registers */
|
||||||
lr t0, __struct_arch_esf_mepc_OFFSET(sp)
|
lr t0, __struct_arch_esf_mepc_OFFSET(sp)
|
||||||
lr t2, __struct_arch_esf_mstatus_OFFSET(sp)
|
lr t2, __struct_arch_esf_mstatus_OFFSET(sp)
|
||||||
|
|
||||||
|
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||||
|
/* Restore MCAUSE register for previous interrupt level. */
|
||||||
|
lr t1, __struct_arch_esf_mcause_OFFSET(sp)
|
||||||
|
csrw mcause, t1
|
||||||
|
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
|
||||||
|
|
||||||
csrw mepc, t0
|
csrw mepc, t0
|
||||||
csrw mstatus, t2
|
csrw mstatus, t2
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,10 @@ GEN_OFFSET_STRUCT(arch_esf, a7);
|
||||||
GEN_OFFSET_STRUCT(arch_esf, mepc);
|
GEN_OFFSET_STRUCT(arch_esf, mepc);
|
||||||
GEN_OFFSET_STRUCT(arch_esf, mstatus);
|
GEN_OFFSET_STRUCT(arch_esf, mstatus);
|
||||||
|
|
||||||
|
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||||
|
GEN_OFFSET_STRUCT(arch_esf, mcause);
|
||||||
|
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
|
||||||
|
|
||||||
GEN_OFFSET_STRUCT(arch_esf, s0);
|
GEN_OFFSET_STRUCT(arch_esf, s0);
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
#ifdef CONFIG_USERSPACE
|
||||||
|
|
|
@ -110,6 +110,11 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
|
||||||
SOC_ISR_STACKING_ESR_INIT;
|
SOC_ISR_STACKING_ESR_INIT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||||
|
/* Clear the previous interrupt level. */
|
||||||
|
stack_init->mcause = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
thread->callee_saved.sp = (unsigned long)stack_init;
|
thread->callee_saved.sp = (unsigned long)stack_init;
|
||||||
|
|
||||||
/* where to go when returning from z_riscv_switch() */
|
/* where to go when returning from z_riscv_switch() */
|
||||||
|
|
|
@ -78,6 +78,10 @@ struct arch_esf {
|
||||||
unsigned long a7; /* function argument */
|
unsigned long a7; /* function argument */
|
||||||
#endif /* !CONFIG_RISCV_ISA_RV32E */
|
#endif /* !CONFIG_RISCV_ISA_RV32E */
|
||||||
|
|
||||||
|
#ifdef CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL
|
||||||
|
unsigned long mcause; /* machine cause register */
|
||||||
|
#endif /* CONFIG_CLIC_SUPPORT_INTERRUPT_LEVEL */
|
||||||
|
|
||||||
unsigned long mepc; /* machine exception program counter */
|
unsigned long mepc; /* machine exception program counter */
|
||||||
unsigned long mstatus; /* machine status register */
|
unsigned long mstatus; /* machine status register */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue