riscv: Introduce RISCV_ALWAYS_SWITCH_THROUGH_ECALL
Some early RISC-V SoCs have a problem when an `mret` instruction is used outside a trap handler. After the latest Zephyr RISC-V huge rework, the arch_switch code is indeed calling `mret` when not in handler mode, breaking some early RISC-V platforms. Optionally restore the old behavior by adding a new CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL symbol. Signed-off-by: Nicolas Pitre <npitre@baylibre.com> Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
d2ac7b4835
commit
7a11d883cc
4 changed files with 27 additions and 2 deletions
|
@ -28,6 +28,16 @@ config RISCV_GP
|
|||
global pointer at program start or earlier than any instruction
|
||||
using GP relative addressing.
|
||||
|
||||
config RISCV_ALWAYS_SWITCH_THROUGH_ECALL
|
||||
bool "Do not use mret outside a trap handler context"
|
||||
depends on !RISCV_PMP
|
||||
help
|
||||
Use mret instruction only when in a trap handler.
|
||||
This is for RISC-V implementations that require every mret to be
|
||||
balanced with an ecall. This is not required by the RISC-V spec
|
||||
and most people should say n here to minimize context switching
|
||||
overhead.
|
||||
|
||||
menu "RISCV Processor Options"
|
||||
|
||||
config INCLUDE_RESET_VECTOR
|
||||
|
|
|
@ -278,6 +278,15 @@ is_kernel_syscall:
|
|||
beq t0, t1, do_irq_offload
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL
|
||||
li t1, RV_ECALL_SCHEDULE
|
||||
bne t0, t1, skip_schedule
|
||||
lr a0, __z_arch_esf_t_a0_OFFSET(sp)
|
||||
lr a1, __z_arch_esf_t_a1_OFFSET(sp)
|
||||
j reschedule
|
||||
skip_schedule:
|
||||
#endif
|
||||
|
||||
/* default fault code is K_ERR_KERNEL_OOPS */
|
||||
li a0, 3
|
||||
j 1f
|
||||
|
@ -483,7 +492,7 @@ irq_done:
|
|||
call z_check_stack_sentinel
|
||||
#endif
|
||||
|
||||
reschedule:
|
||||
check_reschedule:
|
||||
|
||||
/* Get pointer to current thread on this CPU */
|
||||
lr a1, ___cpu_t_current_OFFSET(s0)
|
||||
|
@ -501,6 +510,8 @@ reschedule:
|
|||
addi sp, sp, 16
|
||||
beqz a0, no_reschedule
|
||||
|
||||
reschedule:
|
||||
|
||||
/*
|
||||
* Perform context switch:
|
||||
* a0 = new thread
|
||||
|
|
|
@ -44,8 +44,11 @@ arch_switch(void *switch_to, void **switched_from)
|
|||
struct k_thread *new = switch_to;
|
||||
struct k_thread *old = CONTAINER_OF(switched_from, struct k_thread,
|
||||
switch_handle);
|
||||
|
||||
#ifdef CONFIG_RISCV_ALWAYS_SWITCH_THROUGH_ECALL
|
||||
arch_syscall_invoke2((uintptr_t)new, (uintptr_t)old, RV_ECALL_SCHEDULE);
|
||||
#else
|
||||
z_riscv_switch(new, old);
|
||||
#endif
|
||||
}
|
||||
|
||||
FUNC_NORETURN void z_riscv_fatal_error(unsigned int reason,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
#define RV_ECALL_RUNTIME_EXCEPT 0
|
||||
#define RV_ECALL_IRQ_OFFLOAD 1
|
||||
#define RV_ECALL_SCHEDULE 2
|
||||
|
||||
#ifndef _ASMLANGUAGE
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue