From 8221aac5a9dd6933a79a2c63ecced15c27d2ba6b Mon Sep 17 00:00:00 2001 From: Jimmy Zheng Date: Wed, 7 Aug 2024 09:48:58 +0800 Subject: [PATCH] soc: gd32: gd32vf103: keep the mcause.interrupt by SOC-specific context For Nuclei ECLIC, the interrupt level (mintstatus.MIL) is restored from the previous interrupt level (mcause.MPIL) only if mcause.interrupt is set. This behavior is not defined in the RISC-V CLIC spec. If an ISR causes a context switch and mcause.interrupt is not set in the next context (e.g. the next context is yielded from ecall), interrupts will be masked after MRET because the interrupt level is not restored. Use SOC-specific context to set mcause.interrupt to ensure the interrupt level is restored correctly. Signed-off-by: Jimmy Zheng --- soc/gd/gd32/gd32vf103/CMakeLists.txt | 1 + soc/gd/gd32/gd32vf103/Kconfig | 1 + soc/gd/gd32/gd32vf103/soc_context.h | 18 +++++++++++++ soc/gd/gd32/gd32vf103/soc_irq.S | 40 ++++++++++++++++++++++++++++ soc/gd/gd32/gd32vf103/soc_offsets.h | 16 +++++++++++ 5 files changed, 76 insertions(+) create mode 100644 soc/gd/gd32/gd32vf103/soc_context.h create mode 100644 soc/gd/gd32/gd32vf103/soc_irq.S create mode 100644 soc/gd/gd32/gd32vf103/soc_offsets.h diff --git a/soc/gd/gd32/gd32vf103/CMakeLists.txt b/soc/gd/gd32/gd32vf103/CMakeLists.txt index 6778c0a4f1b3ab..649c118de6700a 100644 --- a/soc/gd/gd32/gd32vf103/CMakeLists.txt +++ b/soc/gd/gd32/gd32vf103/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_sources(entry.S) zephyr_sources(soc.c) +zephyr_sources(soc_irq.S) zephyr_include_directories(.) diff --git a/soc/gd/gd32/gd32vf103/Kconfig b/soc/gd/gd32/gd32vf103/Kconfig index 4ec9057d1967be..2060bb2fe4ab80 100644 --- a/soc/gd/gd32/gd32vf103/Kconfig +++ b/soc/gd/gd32/gd32vf103/Kconfig @@ -13,6 +13,7 @@ config SOC_SERIES_GD32VF103 select RISCV_ISA_EXT_ZICSR select RISCV_ISA_EXT_ZIFENCEI select RISCV_HAS_CLIC + select RISCV_SOC_CONTEXT_SAVE select ATOMIC_OPERATIONS_C select INCLUDE_RESET_VECTOR select GD32_HAS_AFIO_PINMUX diff --git a/soc/gd/gd32/gd32vf103/soc_context.h b/soc/gd/gd32/gd32vf103/soc_context.h new file mode 100644 index 00000000000000..51a082aa0bf2ce --- /dev/null +++ b/soc/gd/gd32/gd32vf103/soc_context.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV_GD32_GD32VF103_SOC_CONTEXT_H +#define SOC_RISCV_GD32_GD32VF103_SOC_CONTEXT_H + +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE + + #define SOC_ESF_MEMBERS + + #define SOC_ESF_INIT + +#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ + +#endif /* SOC_RISCV_GD32_GD32VF103_SOC_CONTEXT_H */ diff --git a/soc/gd/gd32/gd32vf103/soc_irq.S b/soc/gd/gd32/gd32vf103/soc_irq.S new file mode 100644 index 00000000000000..fe0248dad166cb --- /dev/null +++ b/soc/gd/gd32/gd32vf103/soc_irq.S @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* Exports */ +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE +GTEXT(__soc_save_context) +GTEXT(__soc_restore_context) +#endif + +#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE + +SECTION_FUNC(exception.other, __soc_save_context) + + ret + +SECTION_FUNC(exception.other, __soc_restore_context) + + /* + * For Nuclei ECLIC, the interrupt level (mintstatus.MIL) is restored + * from the previous interrupt level (mcause.MPIL) only if + * mcause.interrupt is set when executing MRET. + * Always set the next context's mcause.interrupt to ensure the + * interrupt level is restored correctly after MRET. + */ + addi a0, a0, -__struct_arch_esf_soc_context_OFFSET + lw t0, __struct_arch_esf_mcause_OFFSET(a0) + li t1, 1 << RISCV_MCAUSE_IRQ_POS + or t0, t0, t1 + sw t0, __struct_arch_esf_mcause_OFFSET(a0) + + ret + +#endif /* CONFIG_RISCV_SOC_CONTEXT_SAVE */ diff --git a/soc/gd/gd32/gd32vf103/soc_offsets.h b/soc/gd/gd32/gd32vf103/soc_offsets.h new file mode 100644 index 00000000000000..7322e91b81d7d9 --- /dev/null +++ b/soc/gd/gd32/gd32vf103/soc_offsets.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024 Andes Technology Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_RISCV_GD32_GD32VF103_SOC_OFFSETS_H_ +#define SOC_RISCV_GD32_GD32VF103_SOC_OFFSETS_H_ + +#ifdef CONFIG_RISCV_SOC_OFFSETS + + #define GEN_SOC_OFFSET_SYMS() + +#endif /* CONFIG_RISCV_SOC_OFFSETS */ + +#endif /* SOC_RISCV_GD32_GD32VF103_SOC_OFFSETS_H_*/