diff --git a/arch/risc-v/include/rv64gc/irq.h b/arch/risc-v/include/rv64gc/irq.h index 939c43f9108..e4fbf62cf42 100644 --- a/arch/risc-v/include/rv64gc/irq.h +++ b/arch/risc-v/include/rv64gc/irq.h @@ -285,10 +285,13 @@ /* This structure represents the return state from a system call */ -#ifdef CONFIG_BUILD_KERNEL +#ifdef CONFIG_LIB_SYSCALL struct xcpt_syscall_s { uint64_t sysreturn; /* The return PC */ +#ifdef CONFIG_BUILD_PROTECTED + uint64_t int_ctx; /* Interrupt context (i.e. mstatus) */ +#endif }; #endif @@ -316,7 +319,7 @@ struct xcptcontext uint64_t saved_epc; /* Trampoline PC */ uint64_t saved_int_ctx; /* Interrupt context with interrupts disabled. */ -#ifdef CONFIG_BUILD_KERNEL +#ifdef CONFIG_BUILD_PROTECTED /* This is the saved address to use when returning from a user-space * signal handler. */ @@ -324,7 +327,7 @@ struct xcptcontext uint32_t sigreturn; #endif -#ifdef CONFIG_BUILD_KERNEL +#ifdef CONFIG_LIB_SYSCALL /* The following array holds information needed to return from each nested * system call. */ diff --git a/arch/risc-v/include/rv64gc/syscall.h b/arch/risc-v/include/rv64gc/syscall.h index c6481ba4c61..18f69b3a7f9 100644 --- a/arch/risc-v/include/rv64gc/syscall.h +++ b/arch/risc-v/include/rv64gc/syscall.h @@ -56,11 +56,21 @@ #define SYS_syscall 0x00 +/* The SYS_signal_handler_return is executed here... its value is not always + * available in this context and so is assumed to be 7. + */ + +#ifndef SYS_signal_handler_return +# define SYS_signal_handler_return (7) +#elif SYS_signal_handler_return != 7 +# error "SYS_signal_handler_return was assumed to be 7" +#endif + /* Configuration ************************************************************/ /* SYS call 1 and 2 are defined for internal use by the RISC-V port (see - * arch/risc-v/include/rv64gc/syscall.h). In addition, SYS call 3 is the - * return from a SYS call in kernel mode. The first four syscall values must, + * arch/risc-v/include/rv64gc/syscall.h). In addition, SYS call 3 is the + * return from a SYS call in kernel mode. The first four syscall values must, * therefore, be reserved (0 is not used). */ @@ -144,7 +154,20 @@ extern "C" * ****************************************************************************/ -uintptr_t sys_call0(unsigned int nbr); +static inline uintptr_t sys_call0(unsigned int nbr) +{ + register long r0 asm("a0") = (long)(nbr); + + asm volatile + ( + "ecall" + :: "r"(r0) + ); + + asm volatile("nop" : "=r"(r0)); + + return r0; +} /**************************************************************************** * Name: up_syscall1 @@ -154,7 +177,21 @@ uintptr_t sys_call0(unsigned int nbr); * ****************************************************************************/ -uintptr_t sys_call1(unsigned int nbr, uintptr_t parm1); +static inline uintptr_t sys_call1(unsigned int nbr, uintptr_t parm1) +{ + register long r0 asm("a0") = (long)(nbr); + register long r1 asm("a1") = (long)(parm1); + + asm volatile + ( + "ecall" + :: "r"(r0), "r"(r1) + ); + + asm volatile("nop" : "=r"(r0)); + + return r0; +} /**************************************************************************** * Name: up_syscall2 @@ -164,7 +201,23 @@ uintptr_t sys_call1(unsigned int nbr, uintptr_t parm1); * ****************************************************************************/ -uintptr_t sys_call2(unsigned int nbr, uintptr_t parm1, uintptr_t parm2); +static inline uintptr_t sys_call2(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2) +{ + register long r0 asm("a0") = (long)(nbr); + register long r1 asm("a1") = (long)(parm1); + register long r2 asm("a2") = (long)(parm2); + + asm volatile + ( + "ecall" + :: "r"(r0), "r"(r1), "r"(r2) + ); + + asm volatile("nop" : "=r"(r0)); + + return r0; +} /**************************************************************************** * Name: up_syscall3 @@ -174,8 +227,24 @@ uintptr_t sys_call2(unsigned int nbr, uintptr_t parm1, uintptr_t parm2); * ****************************************************************************/ -uintptr_t sys_call3(unsigned int nbr, uintptr_t parm1, uintptr_t parm2, - uintptr_t parm3); +static inline uintptr_t sys_call3(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3) +{ + register long r0 asm("a0") = (long)(nbr); + register long r1 asm("a1") = (long)(parm1); + register long r2 asm("a2") = (long)(parm2); + register long r3 asm("a3") = (long)(parm3); + + asm volatile + ( + "ecall" + :: "r"(r0), "r"(r1), "r"(r2), "r"(r3) + ); + + asm volatile("nop" : "=r"(r0)); + + return r0; +} /**************************************************************************** * Name: up_syscall4 @@ -185,8 +254,26 @@ uintptr_t sys_call3(unsigned int nbr, uintptr_t parm1, uintptr_t parm2, * ****************************************************************************/ -uintptr_t sys_call4(unsigned int nbr, uintptr_t parm1, uintptr_t parm2, - uintptr_t parm3, uintptr_t parm4); +static inline uintptr_t sys_call4(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3, + uintptr_t parm4) +{ + register long r0 asm("a0") = (long)(nbr); + register long r1 asm("a1") = (long)(parm1); + register long r2 asm("a2") = (long)(parm2); + register long r3 asm("a3") = (long)(parm3); + register long r4 asm("a4") = (long)(parm4); + + asm volatile + ( + "ecall" + :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4) + ); + + asm volatile("nop" : "=r"(r0)); + + return r0; +} /**************************************************************************** * Name: up_syscall5 @@ -196,8 +283,59 @@ uintptr_t sys_call4(unsigned int nbr, uintptr_t parm1, uintptr_t parm2, * ****************************************************************************/ -uintptr_t sys_call5(unsigned int nbr, uintptr_t parm1, uintptr_t parm2, - uintptr_t parm3, uintptr_t parm4, uintptr_t parm5); +static inline uintptr_t sys_call5(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3, + uintptr_t parm4, uintptr_t parm5) +{ + register long r0 asm("a0") = (long)(nbr); + register long r1 asm("a1") = (long)(parm1); + register long r2 asm("a2") = (long)(parm2); + register long r3 asm("a3") = (long)(parm3); + register long r4 asm("a4") = (long)(parm4); + register long r5 asm("a5") = (long)(parm5); + + asm volatile + ( + "ecall" + :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5) + ); + + asm volatile("nop" : "=r"(r0)); + + return r0; +} + +/**************************************************************************** + * Name: up_syscall6 + * + * Description: + * System call SYS_ argument and six additional parameters. + * + ****************************************************************************/ + +static inline uintptr_t sys_call6(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3, + uintptr_t parm4, uintptr_t parm5, + uintptr_t parm6) +{ + register long r0 asm("a0") = (long)(nbr); + register long r1 asm("a1") = (long)(parm1); + register long r2 asm("a2") = (long)(parm2); + register long r3 asm("a3") = (long)(parm3); + register long r4 asm("a4") = (long)(parm4); + register long r5 asm("a5") = (long)(parm5); + register long r6 asm("a6") = (long)(parm6); + + asm volatile + ( + "ecall" + :: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5), "r"(r6) + ); + + asm volatile("nop" : "=r"(r0)); + + return r0; +} #undef EXTERN #ifdef __cplusplus diff --git a/arch/risc-v/src/rv64gc/svcall.h b/arch/risc-v/src/rv64gc/svcall.h new file mode 100644 index 00000000000..27d2dc573e7 --- /dev/null +++ b/arch/risc-v/src/rv64gc/svcall.h @@ -0,0 +1,128 @@ +/**************************************************************************** + * arch/risc-v/src/rv64gc/svcall.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_RV64GC_SVCALL_H +#define __ARCH_RISCV_SRC_RV64GC_SVCALL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_LIB_SYSCALL +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* This logic uses three system calls {0,1,2} for context switching and one + * for the syscall return. So a minimum of four syscall values must be + * reserved. If CONFIG_BUILD_PROTECTED is defined, then four more syscall + * values must be reserved. + */ + +#ifdef CONFIG_LIB_SYSCALL +# ifdef CONFIG_BUILD_PROTECTED +# ifndef CONFIG_SYS_RESERVED +# error "CONFIG_SYS_RESERVED must be defined to have the value 8" +# elif CONFIG_SYS_RESERVED != 8 +# error "CONFIG_SYS_RESERVED must have the value 8" +# endif +# else +# ifndef CONFIG_SYS_RESERVED +# error "CONFIG_SYS_RESERVED must be defined to have the value 4" +# elif CONFIG_SYS_RESERVED != 4 +# error "CONFIG_SYS_RESERVED must have the value 4" +# endif +# endif +#endif + +/* RV64GC system calls ******************************************************/ + +/* SYS call 0: + * + * int up_saveusercontext(uint32_t *saveregs); + */ + +#define SYS_save_context (0) + +/* SYS call 1: + * + * void up_fullcontextrestore(uint32_t *restoreregs) noreturn_function; + */ + +#define SYS_restore_context (1) + +/* SYS call 2: + * + * void up_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + */ + +#define SYS_switch_context (2) + +#ifdef CONFIG_LIB_SYSCALL +/* SYS call 3: + * + * void up_syscall_return(void); + */ + +#define SYS_syscall_return (3) + +#ifdef CONFIG_BUILD_PROTECTED +/* SYS call 4: + * + * void up_task_start(main_t taskentry, int argc, FAR char *argv[]) + * noreturn_function; + */ + +#define SYS_task_start (4) + +/* SYS call 5: + * + * void up_pthread_start(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, + * FAR siginfo_t *info, FAR void *ucontext); + */ + +#define SYS_signal_handler (6) + +/* SYS call 7: + * + * void signal_handler_return(void); + */ + +#define SYS_signal_handler_return (7) + +#endif /* CONFIG_BUILD_PROTECTED */ +#endif /* CONFIG_LIB_SYSCALL */ + +#endif /* __ARCH_RISCV_SRC_RV64GC_SVCALL_H */ diff --git a/arch/risc-v/src/rv64gc/up_initialstate.c b/arch/risc-v/src/rv64gc/up_initialstate.c index f7a06a60e85..8fbad33e869 100644 --- a/arch/risc-v/src/rv64gc/up_initialstate.c +++ b/arch/risc-v/src/rv64gc/up_initialstate.c @@ -88,25 +88,6 @@ void up_initial_state(struct tcb_s *tcb) xcp->regs[REG_EPC] = (uintptr_t)tcb->start; - /* If this task is running PIC, then set the PIC base register to the - * address of the allocated D-Space region. - */ - -#ifdef CONFIG_PIC -# warning "Missing logic" -#endif - - /* Set privileged- or unprivileged-mode, depending on how NuttX is - * configured and what kind of thread is being started. - * - * If the kernel build is not selected, then all threads run in - * privileged thread mode. - */ - -#ifdef CONFIG_BUILD_KERNEL -# warning "Missing logic" -#endif - /* Set the initial value of the interrupt context register. * * Since various RISC-V platforms use different interrupt diff --git a/arch/risc-v/src/rv64gc/up_signal_dispatch.c b/arch/risc-v/src/rv64gc/up_signal_dispatch.c new file mode 100644 index 00000000000..a1daacafb96 --- /dev/null +++ b/arch/risc-v/src/rv64gc/up_signal_dispatch.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * arch/risc-v/src/rv64gc/up_signal_dispatch.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "svcall.h" +#include "up_internal.h" + +#if (defined(CONFIG_BUILD_PROTECTED) && defined(__KERNEL__)) || \ + defined(CONFIG_BUILD_KERNEL) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_signal_dispatch + * + * Description: + * In the kernel mode build, this function will be called to execute a + * a signal handler in user-space. When the signal is delivered, a + * kernel-mode stub will first run to perform some housekeeping functions. + * This kernel-mode stub will then be called transfer control to the user + * mode signal handler by calling this function. + * + * Normally the a user-mode signaling handling stub will also execute + * before the ultimate signal handler is called. See + * arch/arm/src/armv[6\7]/up_signal_handler. This function is the + * user-space, signal handler trampoline function. It is called from + * up_signal_dispatch() in user-mode. + * + * Input Parameters: + * sighand - The address user-space signal handling function + * signo, info, and ucontext - Standard arguments to be passed to the + * signal handling function. + * + * Returned Value: + * None. This function does not return in the normal sense. It returns + * via an architecture specific system call made by up_signal_handler(). + * However, this will look like a normal return by the caller of + * up_signal_dispatch. + * + ****************************************************************************/ + +void up_signal_dispatch(_sa_sigaction_t sighand, int signo, + FAR siginfo_t *info, FAR void *ucontext) +{ + /* Let sys_call4() do all of the work */ + + sys_call4(SYS_signal_handler, (uintptr_t)sighand, (uintptr_t)signo, + (uintptr_t)info, (uintptr_t)ucontext); +} + +#endif /* (CONFIG_BUILD_PROTECTED || CONFIG_BUILD_KERNEL) && !CONFIG_DISABLE_PTHREAD */ diff --git a/arch/risc-v/src/rv64gc/up_signal_handler.S b/arch/risc-v/src/rv64gc/up_signal_handler.S new file mode 100644 index 00000000000..231dcc86e37 --- /dev/null +++ b/arch/risc-v/src/rv64gc/up_signal_handler.S @@ -0,0 +1,97 @@ +/**************************************************************************** + * arch/risc-v/src/rv64gc/up_signal_handler.S + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(__KERNEL__) + +/**************************************************************************** + * File info + ****************************************************************************/ + + .file "up_signal_handler.S" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_signal_handler + * + * Description: + * This function is the user-space, signal handler trampoline function. It + * is called from up_signal_dispatch() in user-mode. + * + * Input Parameters: + * a0 = sighand + * The address user-space signal handling function + * a1-a3 = signo, info, and ucontext + * Standard arguments to be passed to the signal handling function. + * + * Returned Value: + * None. This function does not return in the normal sense. It returns + * via the SYS_signal_handler_return (see svcall.h) + * + ****************************************************************************/ + + .text + .globl up_signal_handler + .type up_signal_handler, function + +up_signal_handler: + + /* Save ra on the stack */ + + addi sp, sp, -8 + sd ra, (sp) + + /* Call the signal handler */ + + mv t0, a0 /* t0=sighand */ + mv a0, a1 /* a0=signo */ + mv a1, a2 /* a1=info */ + mv a2, a3 /* a2=ucontext */ + jalr t0 /* Call the signal handler (modifies ra) */ + + /* Restore the register */ + + ld ra, (sp) /* Restore ra in sp */ + addi sp, sp, 8 + + /* Execute the SYS_signal_handler_return SVCall (will not return) */ + + li a0, SYS_signal_handler_return + ecall + nop + + .size up_signal_handler, .-up_signal_handler + .end + +#endif /* CONFIG_BUILD_PROTECTED && !__KERNEL__ */ diff --git a/arch/risc-v/src/rv64gc/up_swint.c b/arch/risc-v/src/rv64gc/up_swint.c index 59663a4c2d7..c45c7bc3f3b 100644 --- a/arch/risc-v/src/rv64gc/up_swint.c +++ b/arch/risc-v/src/rv64gc/up_swint.c @@ -41,15 +41,19 @@ #include #include -#include #include #include -#include - #include +#include +#include + +#ifdef CONFIG_LIB_SYSCALL +# include +#endif #include "signal/signal.h" +#include "svcall.h" #include "up_internal.h" /**************************************************************************** @@ -93,15 +97,38 @@ static void up_registerdump(const uint64_t *regs) * Name: dispatch_syscall * * Description: - * Call the stub function corresponding to the system call. + * Call the stub function corresponding to the system call. NOTE the non- + * standard parameter passing: + * + * A0 = SYS_ call number + * A1 = parm0 + * A2 = parm1 + * A3 = parm2 + * A4 = parm3 + * A5 = parm4 + * A6 = parm5 * ****************************************************************************/ -#ifdef CONFIG_BUILD_KERNEL +#ifdef CONFIG_LIB_SYSCALL static void dispatch_syscall(void) naked_function; static void dispatch_syscall(void) { -# error "Missing logic" + asm volatile + ( + " addi sp, sp, -8\n" /* Create a stack frame to hold ra */ + " sd ra, 0(sp)\n" /* Save ra in the stack frame */ + " la t0, g_stublookup\n" /* t0=The base of the stub lookup table */ + " slli a0, a0, 3\n" /* a0=Offset for the stub lookup table */ + " add t0, t0, a0\n" /* t0=The address in the table */ + " ld t0, 0(t0)\n" /* t0=The address of the stub for this syscall */ + " jalr ra, t0\n" /* Call the stub (modifies ra) */ + " ld ra, 0(sp)\n" /* Restore ra */ + " addi sp, sp, 8\n" /* Destroy the stack frame */ + " mv a2, a0\n" /* a2=Save return value in a0 */ + " li a0, 3\n" /* a0=SYS_syscall_return (3) */ + " ecall" /* Return from the syscall */ + ); } #endif @@ -184,7 +211,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg) } break; - /* A0=SYS_syscall_return: This a switch context command: + /* A0=SYS_syscall_return: This is a SYSCALL return command: * * void up_sycall_return(void); * @@ -196,7 +223,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg) * unprivileged thread mode. */ -#ifdef CONFIG_BUILD_KERNEL +#ifdef CONFIG_LIB_SYSCALL case SYS_syscall_return: { struct tcb_s *rtcb = sched_self(); @@ -210,20 +237,162 @@ int up_swint(int irq, FAR void *context, FAR void *arg) * the original mode. */ - CURRENT_REGS[REG_EPC] = rtcb->xcp.syscall[index].sysreturn; -#error "Missing logic -- need to restore the original mode" - rtcb->xcp.nsyscalls = index; + regs[REG_EPC] = rtcb->xcp.syscall[index].sysreturn; +#ifdef CONFIG_BUILD_PROTECTED + regs[REG_INT_CTX] = rtcb->xcp.syscall[index].int_ctx; +#endif + + /* The return value must be in A0-A1. + * dispatch_syscall() temporarily moved the value for R0 into A2. + */ + + regs[REG_A0] = regs[REG_A2]; + + /* Save the new SYSCALL nesting level */ + + rtcb->xcp.nsyscalls = index; /* Handle any signal actions that were deferred while processing * the system call. */ - rtcb->flags &= ~TCB_FLAG_SYSCALL; + rtcb->flags &= ~TCB_FLAG_SYSCALL; (void)nxsig_unmask_pendingsignal(); } break; #endif + /* R0=SYS_task_start: This a user task start + * + * void up_task_start(main_t taskentry, int argc, + * FAR char *argv[]) noreturn_function; + * + * At this point, the following values are saved in context: + * + * A0 = SYS_task_start + * A1 = taskentry + * A2 = argc + * A3 = argv + */ + +#ifdef CONFIG_BUILD_PROTECTED + case SYS_task_start: + { + /* Set up to return to the user-space task start-up function in + * unprivileged mode. + */ + + regs[REG_EPC] = (uintptr_t)USERSPACE->task_startup & ~1; + + regs[REG_A0] = regs[REG_A1]; /* Task entry */ + regs[REG_A1] = regs[REG_A2]; /* argc */ + regs[REG_A2] = regs[REG_A3]; /* argv */ + + regs[REG_INT_CTX] &= ~MSTATUS_MPPM; /* 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: + * + * R0 = SYS_pthread_start + * R1 = entrypt + * R2 = arg + */ + +#if defined(CONFIG_BUILD_PROTECTED) && !defined(CONFIG_DISABLE_PTHREAD) + case SYS_pthread_start: + { + /* Set up to return to the user-space pthread start-up function in + * unprivileged mode. + */ + + regs[REG_EPC] = (uintptr_t)USERSPACE->pthread_startup & ~1; + + /* Change the parameter ordering to match the expectation of struct + * userpace_s pthread_startup: + */ + + regs[REG_A0] = regs[REG_A1]; /* pthread entry */ + regs[REG_A1] = regs[REG_A2]; /* arg */ + regs[REG_INT_CTX] &= ~MSTATUS_MPPM; /* User mode */ + } + break; +#endif + + /* R0=SYS_signal_handler: This a user signal handler callback + * + * void signal_handler(_sa_sigaction_t sighand, int signo, + * FAR siginfo_t *info, FAR void *ucontext); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_signal_handler + * R1 = sighand + * R2 = signo + * R3 = info + * R4 = ucontext + */ + +#ifdef CONFIG_BUILD_PROTECTED + case SYS_signal_handler: + { + struct tcb_s *rtcb = sched_self(); + + /* Remember the caller's return address */ + + DEBUGASSERT(rtcb->xcp.sigreturn == 0); + rtcb->xcp.sigreturn = regs[REG_EPC]; + + /* Set up to return to the user-space pthread start-up function in + * unprivileged mode. + */ + + regs[REG_EPC] = (uintptr_t)USERSPACE->signal_handler & ~1; + regs[REG_INT_CTX] &= ~MSTATUS_MPPM; /* User mode */ + + /* Change the parameter ordering to match the expectation of struct + * userpace_s signal_handler. + */ + + regs[REG_A0] = regs[REG_A1]; /* sighand */ + regs[REG_A1] = regs[REG_A2]; /* signal */ + regs[REG_A2] = regs[REG_A3]; /* info */ + regs[REG_A3] = regs[REG_A4]; /* ucontext */ + } + break; +#endif + + /* R0=SYS_signal_handler_return: This a user signal handler callback + * + * void signal_handler_return(void); + * + * At this point, the following values are saved in context: + * + * R0 = SYS_signal_handler_return + */ + +#ifdef CONFIG_BUILD_PROTECTED + case SYS_signal_handler_return: + { + struct tcb_s *rtcb = sched_self(); + + /* Set up to return to the kernel-mode signal dispatching logic. */ + + DEBUGASSERT(rtcb->xcp.sigreturn != 0); + regs[REG_EPC] = rtcb->xcp.sigreturn & ~1; + regs[REG_INT_CTX] |= MSTATUS_MPPM; /* Machine mode */ + + rtcb->xcp.sigreturn = 0; + } + break; +#endif + /* This is not an architecture-specify system call. If NuttX is built * as a standalone kernel with a system call interface, then all of the * additional system calls must be handled as in the default case. @@ -231,7 +400,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg) default: { -#ifdef CONFIG_BUILD_KERNEL +#ifdef CONFIG_LIB_SYSCALL FAR struct tcb_s *rtcb = sched_self(); int index = rtcb->xcp.nsyscalls; @@ -247,20 +416,26 @@ int up_swint(int irq, FAR void *context, FAR void *arg) /* Setup to return to dispatch_syscall in privileged mode. */ - rtcb->xcpsyscall[index].sysreturn = regs[REG_EPC]; -#error "Missing logic -- Need to save mode" + rtcb->xcp.syscall[index].sysreturn = regs[REG_EPC]; +#ifdef CONFIG_BUILD_PROTECTED + rtcb->xcp.syscall[index].int_ctx = regs[REG_INT_CTX]; +#endif + rtcb->xcp.nsyscalls = index + 1; - regs[REG_EPC] = (uint32_t)dispatch_syscall; -#error "Missing logic -- Need to set privileged mode" + regs[REG_EPC] = (uintptr_t)dispatch_syscall & ~1; - /* Offset R0 to account for the reserved values */ +#ifdef CONFIG_BUILD_PROTECTED + regs[REG_INT_CTX] |= MSTATUS_MPPM; /* Machine mode */ +#endif - CURRENT_REGS[REG_A0] -= CONFIG_SYS_RESERVED; + /* Offset A0 to account for the reserved values */ + + regs[REG_A0] -= CONFIG_SYS_RESERVED; /* Indicate that we are in a syscall handler. */ - rtcb->flags |= TCB_FLAG_SYSCALL; + rtcb->flags |= TCB_FLAG_SYSCALL; #else svcerr("ERROR: Bad SYS call: %d\n", regs[REG_A0]); #endif diff --git a/arch/risc-v/src/rv64gc/up_syscall.S b/arch/risc-v/src/rv64gc/up_syscall.S deleted file mode 100644 index c28094a4bb8..00000000000 --- a/arch/risc-v/src/rv64gc/up_syscall.S +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** - * arch/riscv/src/rv64gc/up_syscall.S - * - * Copyright (C) 2011, 2015 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Modified for RISC-V: - * - * Copyright (C) 2016 Ken Pettit. All rights reserved. - * Author: Ken Pettit - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -/**************************************************************************** - * Public Symbols - ****************************************************************************/ - - .file "up_syscall0.S" - .global sys_call0 - .global sys_call1 - .global sys_call2 - .global sys_call3 - .global sys_call4 - .global sys_call5 - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_syscall0, up_syscall1, up_syscall2, up_syscall3 - * - * Description: - * up_syscall0 - System call SYS_ argument and no additional parameters. - * up_syscall1 - System call SYS_ argument and one additional parameter. - * up_syscall2 - System call SYS_ argument and two additional parameters. - * up_syscall3 - System call SYS_ argument and three additional parameters. - * up_syscall4 - System call SYS_ argument and four additional parameters. - * up_syscall5 - System call SYS_ argument and five additional parameters. - * - * Assumption: - * All interrupts are disabled except for the software interrupts. - * - ****************************************************************************/ - - .text - -sys_call0: /* a0 holds the syscall number */ -sys_call1: /* a0 holds the syscall number, argument in a1 */ -sys_call2: /* a0 holds the syscall number, arguments in a1 and a2 */ -sys_call3: /* a0 holds the syscall number, arguments in a1, a2, and a3 */ -sys_call4: /* a0 holds the syscall number, arguments in a1, a2, a3 and a4 */ -sys_call5: /* a0 holds the syscall number, arguments in a1, a2, a3, a4 and a5 */ - - /* Issue the ECALL opcode to perform a SW interrupt to the OS */ - - ecall - - /* The actual interrupt may not a occur for a few more cycles. Let's - * put a few nop's here in hope that the SW interrupt occurs during - * the sequence of nops. - */ - - nop - nop - - /* Then return with the result of the software interrupt in v0 */ - - ret - nop