pussuw edited a comment on pull request #5782:
URL: https://github.com/apache/incubator-nuttx/pull/5782#issuecomment-1076317489


   > > > S-mode can hook ECALL to self, @pussuw could you explain more why we 
need handle differently in S-mode and M-mode?
   > > 
   > > 
   > > S-mode can trap ecall from user mode (U-mode) but not from S-mode. So 
ecall from S-mode to S-mode is not possible.
   > 
   > Ok, I get the key point. So is syscall from S-mode to S-mode only used for 
kernel thread context switch?
   > 
   A context switch can occur in two ways:
   1. A process running thread in privileged mode (either kernel process or 
user process who's privileges are temporary raised e.g. when executing a system 
call from usersace), in this case a context switch occurs via 
`riscv_switchcontext`. In flat mode (M-mode) this is handled via:
   ```
   #define riscv_switchcontext(saveregs, restoreregs) \
     sys_call2(SYS_switch_context, (uintptr_t)saveregs, (uintptr_t)restoreregs)
   ```
   Which uses ecall to enter the trap handler which does all the work. This 
works, because ecall from M-mode to M-mode enters M-mode. 
   
   This cannot be used to switch context in S-mode, because it would raise 
privileges to M-mode (ecall from S-mode) which is not what we want. Instead, 
the assembly routine below is used to do the same work as was done by the trap 
handler previously!
   ```
   riscv_switchcontext:
   
     /* Save old context to arg[0] */
   
     save_ctx   a0                        /* save context */
   
     REGSTORE   x1, REG_EPC(a0)           /* save ra to epc */
     REGSTORE   sp, REG_SP(a0)            /* original SP */
   
     /* Set previous privilege, we are in privileged mode now */
   
     csrr       s0, CSR_STATUS            /* read status register */
     li         s1, STATUS_PPP            /* set previous privilege */
     or         s0, s0, s1
     li         s1, ~STATUS_PIE           /* clear previous interrupt enable */
     and        s0, s0, s1
     REGSTORE   s0, REG_INT_CTX(a0)       /* store status to context */
   
   #ifdef CONFIG_ARCH_FPU
     jal        x1, riscv_savefpu         /* FP registers */
   #endif
   
     /* Load new context from arg[1] */
   
     mv         a0, a1                    /* load from a1 */
     j          riscv_fullcontextrestore  /* restore context */
   ```
   2. The second way a context switch can occur is in the trap handler itself, 
for example if a task is waiting for uart semaphore and the semaphore is posted 
by the uart interrupt handler, this can dispatch a wake up signal to the task, 
and the task that was running prior to taking the trap gets preempted and the 
task that was waiting for the semaphore gets activated instead.
   
   > > Also, we want to use ecall in S-mode to raise privileges to M-mode, to 
access some machine mode services (mhartid,
   > 
   > Yes, but it's still the same ecall instruction. Here is my understanding:
   > 
   >     1. Any syscall(include context switch) issued by U-mode could be 
implemented by ECALL and raise to S-mode
   A user task will never call syscall(SYS_context_switch), or any of the 
reserved SYS_ call numbers, **from user mode**. If a user task calls for a 
context switch, it means its privileges are raised to kernel temporarily. The 
reserved syscalls are reserved for the kernel only and thus will only be 
executed by privileged mode code, i.e. only the kernel does this.
   
   A user task can however call e.g. syscall(SYS__exit, ...), which is executed 
via a proxy function like this:
   ```
   void _exit(int parm1)
   {
     (void)sys_call1((unsigned int)SYS__exit, (uintptr_t)parm1);
     while(1);
   }
   ```
   > 
   >     2. Kernel thread context switch could be implemented by ECALL too, but 
it will be handled in M-mode instead S-mode
   I don't know how to do this, M-mode does not support address translations, 
so when using address environments (the kernel memory is MMU mapped) it will 
become quite difficult.
   > 
   >     3. Some special function(e.g. mhartid) which need the highest 
privilege has to issue ECALL from S-mode to M-mode
   > 
   > 
   Yes, exactly
   > So, I think we can still use the same sys_call0-syscall6 as before, and:
   > 
   >     1. Handle U-mode syscall in S-mode as before
   Yes, this is why we need sys_call0-6, for the userspace
   > 
   >     2. Handle S-mode context switch in M-mode( the code should be same as 
S-mode)
   I don't know how to do this
   > 
   >     3. Extend the reserved syscall id to cover the special need(e.g. 
mhardid)
   Can be done, but I'd like to keep this separate. What riscv_mcall.c 
basically implements is a tiny SBI (comparable to openSBI for example but much 
smaller).
   > 
   > 
   > > mtimer to name a few, see riscv_mcall.c).
   > 
   > Why we can't use S-mode timer instead?
   There is no S-mode timer as far as I know. There is a scounter but this is 
for performance monitoring / profiling as far as I know. What we need is a 
ticker with a compare match event, i.e. mtime and mtimecmp. Such memory mapped 
registers are not available for S-mode.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to