diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h index cd2665cd886..40f6275fd91 100644 --- a/arch/risc-v/include/irq.h +++ b/arch/risc-v/include/irq.h @@ -612,6 +612,9 @@ struct xcptcontext /* Integer register save area */ uintreg_t *regs; +#ifndef CONFIG_BUILD_FLAT + uintreg_t *initregs; +#endif #ifdef CONFIG_LIB_SYSCALL /* User integer registers upon system call entry */ diff --git a/arch/risc-v/include/syscall.h b/arch/risc-v/include/syscall.h index 9d220067608..834b2848ddf 100644 --- a/arch/risc-v/include/syscall.h +++ b/arch/risc-v/include/syscall.h @@ -50,7 +50,7 @@ */ #ifndef CONFIG_BUILD_FLAT -# define CONFIG_SYS_RESERVED 8 +# define CONFIG_SYS_RESERVED 6 #else # define CONFIG_SYS_RESERVED 4 #endif @@ -78,37 +78,21 @@ #define SYS_switch_context (2) #ifndef CONFIG_BUILD_FLAT + /* SYS call 4: - * - * void up_task_start(main_t taskentry, int argc, char *argv[]) - * noreturn_function; - */ - -#define SYS_task_start (4) - -/* SYS call 5: - * - * void up_pthread_start(pthread_startroutine_t startup, - * pthread_startroutine_t entrypt, pthread_addr_t arg) - * noreturn_function - */ - -#define SYS_pthread_start (5) - -/* SYS call 6: * * void signal_handler(_sa_sigaction_t sighand, int signo, * siginfo_t *info, void *ucontext); */ -#define SYS_signal_handler (6) +#define SYS_signal_handler (4) -/* SYS call 7: +/* SYS call 5: * * void signal_handler_return(void); */ -#define SYS_signal_handler_return (7) +#define SYS_signal_handler_return (5) #endif /* !CONFIG_BUILD_FLAT */ /**************************************************************************** diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S index 5035a01c7ba..ec585f653af 100644 --- a/arch/risc-v/src/common/riscv_exception_common.S +++ b/arch/risc-v/src/common/riscv_exception_common.S @@ -273,6 +273,42 @@ return_from_exception: ERET +/**************************************************************************** + * Function: riscv_jump_to_user + * + * Description: + * Routine to jump to user space, called when a user process is started and + * the kernel is ready to give control to the user task in user space. + * + * riscv_jump_to_user(entry, a0, a1, a2, sp, regs) + * entry: process entry point + * a0: parameter 0 for process + * a1: parameter 1 for process + * a2: parameter 2 for process + * sp: user stack pointer + * regs: integer register save area to use + * + ****************************************************************************/ + + .section EXCEPTION_SECTION + .global riscv_jump_to_user + +riscv_jump_to_user: + + csrc CSR_STATUS, STATUS_IE + mv sp, a5 + REGSTORE a0, REG_EPC(sp) + REGSTORE a1, REG_A0(sp) + REGSTORE a2, REG_A1(sp) + REGSTORE a3, REG_A2(sp) + REGSTORE a4, REG_SP(sp) + csrr a0, CSR_STATUS + li a1, ~STATUS_PPP + and a0, a0, a1 + REGSTORE a0, REG_INT_CTX(sp) + mv a0, sp + tail return_from_exception + /***************************************************************************** * Name: g_intstackalloc and g_intstacktop ****************************************************************************/ diff --git a/arch/risc-v/src/common/riscv_initialstate.c b/arch/risc-v/src/common/riscv_initialstate.c index f787ed57b71..7eb4aebcad5 100644 --- a/arch/risc-v/src/common/riscv_initialstate.c +++ b/arch/risc-v/src/common/riscv_initialstate.c @@ -169,4 +169,8 @@ void up_initial_state(struct tcb_s *tcb) #ifdef CONFIG_ARCH_RISCV_INTXCPT_EXTENSIONS riscv_initial_extctx_state(tcb); #endif + +#ifndef CONFIG_BUILD_FLAT + tcb->xcp.initregs = tcb->xcp.regs; +#endif } diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h index d9165356a97..7878d762aad 100644 --- a/arch/risc-v/src/common/riscv_internal.h +++ b/arch/risc-v/src/common/riscv_internal.h @@ -434,6 +434,10 @@ uintptr_t riscv_mhartid(void); void *riscv_perform_syscall(uintreg_t *regs); #endif +void riscv_jump_to_user(uintptr_t entry, uintreg_t a0, uintreg_t a1, + uintreg_t a2, uintreg_t sp, + uintreg_t *regs) noreturn_function; + /* Context switching via system calls ***************************************/ /* SYS call 1: diff --git a/arch/risc-v/src/common/riscv_pthread_start.c b/arch/risc-v/src/common/riscv_pthread_start.c index 8dd295a1b8f..4d3056efa0c 100644 --- a/arch/risc-v/src/common/riscv_pthread_start.c +++ b/arch/risc-v/src/common/riscv_pthread_start.c @@ -31,6 +31,8 @@ #include "riscv_internal.h" +#include "sched/sched.h" + #if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__) && \ !defined(CONFIG_DISABLE_PTHREAD) @@ -66,12 +68,26 @@ void up_pthread_start(pthread_trampoline_t startup, pthread_startroutine_t entrypt, pthread_addr_t arg) { - /* Let sys_call3() do all of the work */ + struct tcb_s *rtcb = this_task(); + uintptr_t sp; - sys_call3(SYS_pthread_start, (uintptr_t)startup, (uintptr_t)entrypt, - (uintptr_t)arg); +#ifdef CONFIG_ARCH_KERNEL_STACK + sp = (uintreg_t)rtcb->xcp.ustkptr; +#else + sp = (uintptr_t)rtcb->stack_base_ptr + rtcb->adj_stack_size; +#endif - PANIC(); + /* Set up to return to the user-space _start function in + * unprivileged mode. We need: + * + * A0 = entrypt + * A1 = arg + * EPC = startup + * M/SPP = user mode + */ + + riscv_jump_to_user((uintptr_t)startup, (uintreg_t)entrypt, (uintreg_t)arg, + 0, sp, rtcb->xcp.initregs); } #endif /* !CONFIG_BUILD_FLAT && __KERNEL__ && !CONFIG_DISABLE_PTHREAD */ diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c index ce2a2ad1544..ab6fc22428a 100644 --- a/arch/risc-v/src/common/riscv_swint.c +++ b/arch/risc-v/src/common/riscv_swint.c @@ -212,93 +212,6 @@ int riscv_swint(int irq, void *context, void *arg) } break; - /* R0=SYS_task_start: This a user task start - * - * void up_task_start(main_t taskentry, int argc, - * char *argv[]) noreturn_function; - * - * At this point, the following values are saved in context: - * - * A0 = SYS_task_start - * A1 = taskentry - * A2 = argc - * A3 = argv - */ - -#ifndef CONFIG_BUILD_FLAT - case SYS_task_start: - { - /* Set up to return to the user-space task start-up function in - * unprivileged mode. - */ - -#ifdef CONFIG_ARCH_KERNEL_STACK - /* Set the user stack pointer as we are about to return to user */ - - struct tcb_s *tcb = this_task(); - regs[REG_SP] = (uintptr_t)tcb->xcp.ustkptr; - tcb->xcp.ustkptr = NULL; -#endif - -#if defined (CONFIG_BUILD_PROTECTED) - /* Use the nxtask_startup trampoline function */ - - regs[REG_EPC] = (uintptr_t)USERSPACE->task_startup; - regs[REG_A0] = regs[REG_A1]; /* Task entry */ - regs[REG_A1] = regs[REG_A2]; /* argc */ - regs[REG_A2] = regs[REG_A3]; /* argv */ -#else - /* Start the user task directly */ - - regs[REG_EPC] = (uintptr_t)regs[REG_A1]; - regs[REG_A0] = regs[REG_A2]; /* argc */ - regs[REG_A1] = regs[REG_A3]; /* argv */ -#endif - regs[REG_INT_CTX] &= ~STATUS_PPP; /* User mode */ - } - break; -#endif - - /* R0=SYS_pthread_start: This a user pthread start - * - * void up_pthread_start(pthread_startroutine_t entrypt, - * pthread_addr_t arg) noreturn_function; - * - * At this point, the following values are saved in context: - * - * A0 = SYS_pthread_start - * A1 = entrypt - * A2 = arg - */ - -#if !defined(CONFIG_BUILD_FLAT) && !defined(CONFIG_DISABLE_PTHREAD) - case SYS_pthread_start: - { - /* Set up to return to the user-space pthread start-up function in - * unprivileged mode. - */ - -#ifdef CONFIG_ARCH_KERNEL_STACK - /* Set the user stack pointer as we are about to return to user */ - - struct tcb_s *tcb = this_task(); - regs[REG_SP] = (uintptr_t)tcb->xcp.ustkptr; - tcb->xcp.ustkptr = NULL; -#endif - - regs[REG_EPC] = (uintptr_t)regs[REG_A1]; /* startup */ - - /* Change the parameter ordering to match the expectation of the - * user space pthread_startup: - */ - - regs[REG_A0] = regs[REG_A2]; /* pthread entry */ - regs[REG_A1] = regs[REG_A3]; /* arg */ - regs[REG_INT_CTX] &= ~STATUS_PPP; /* User mode */ - } - break; -#endif - /* R0=SYS_signal_handler: This a user signal handler callback * * void signal_handler(_sa_sigaction_t sighand, int signo, diff --git a/arch/risc-v/src/common/riscv_task_start.c b/arch/risc-v/src/common/riscv_task_start.c index d8cc966f8a9..c664392f27a 100644 --- a/arch/risc-v/src/common/riscv_task_start.c +++ b/arch/risc-v/src/common/riscv_task_start.c @@ -30,6 +30,8 @@ #include "riscv_internal.h" +#include "sched/sched.h" + #ifndef CONFIG_BUILD_FLAT /**************************************************************************** @@ -63,12 +65,32 @@ void up_task_start(main_t taskentry, int argc, char *argv[]) { - /* Let sys_call3() do all of the work */ + struct tcb_s *rtcb = this_task(); + uintptr_t sp; - sys_call3(SYS_task_start, (uintptr_t)taskentry, (uintptr_t)argc, - (uintptr_t)argv); +#ifdef CONFIG_ARCH_KERNEL_STACK + sp = (uintreg_t)rtcb->xcp.ustkptr; +#else + sp = (uintptr_t)rtcb->stack_base_ptr + rtcb->adj_stack_size; +#endif - PANIC(); + /* Set up to return to the user-space _start function in + * unprivileged mode. We need: + * + * A0 = argc + * A1 = argv + * EPC = taskentry + * M/SPP = user mode + */ + +#if defined(CONFIG_BUILD_PROTECTED) + riscv_jump_to_user((uintptr_t)USERSPACE->task_startup, + (uintptr_t)taskentry, (uintreg_t)argc, (uintreg_t)argv, + sp, rtcb->xcp.initregs); +#else + riscv_jump_to_user((uintptr_t)taskentry, (uintreg_t)argc, (uintreg_t)argv, + 0, sp, rtcb->xcp.initregs); +#endif } #endif /* !CONFIG_BUILD_FLAT */